diff --git a/.clang-format b/.clang-format index 2048b0296d76..0d1ed8776733 100644 --- a/.clang-format +++ b/.clang-format @@ -521,7 +521,6 @@ ForEachMacros: - 'of_property_for_each_u32' - 'pci_bus_for_each_resource' - 'pci_dev_for_each_resource' - - 'pci_doe_for_each_off' - 'pcl_for_each_chunk' - 'pcl_for_each_segment' - 'pcm_for_each_format' diff --git a/.mailmap b/.mailmap index 6686879ce0d5..bf076bbc36b1 100644 --- a/.mailmap +++ b/.mailmap @@ -213,7 +213,10 @@ Jeff Garzik Jeff Layton Jeff Layton Jeff Layton -Jens Axboe +Jens Axboe +Jens Axboe +Jens Axboe +Jens Axboe Jens Osterkamp Jernej Skrabec Jessica Zhang @@ -328,6 +331,7 @@ Maxime Ripard Maxime Ripard Mayuresh Janorkar Michael Buesch +Michal Simek Michel Dänzer Michel Lespinasse Michel Lespinasse @@ -360,6 +364,12 @@ Nicolas Pitre Nicolas Saenz Julienne Nicolas Saenz Julienne Niklas Söderlund +Nikolay Aleksandrov +Nikolay Aleksandrov +Nikolay Aleksandrov +Nikolay Aleksandrov +Nikolay Aleksandrov +Oleksandr Natalenko Oleksij Rempel Oleksij Rempel Oleksij Rempel @@ -375,6 +385,8 @@ Paul E. McKenney Paul E. McKenney Paul E. McKenney Paul E. McKenney +Paul Mackerras +Paul Mackerras Peter A Jonsson Peter Oruba Peter Oruba diff --git a/CREDITS b/CREDITS index b6c93e0a62c3..de7e4dbbc599 100644 --- a/CREDITS +++ b/CREDITS @@ -1706,6 +1706,10 @@ S: Panoramastrasse 18 S: D-69126 Heidelberg S: Germany +N: Neil Horman +M: nhorman@tuxdriver.com +D: SCTP protocol maintainer. + N: Simon Horman M: horms@verge.net.au D: Renesas ARM/ARM64 SoC maintainer @@ -2510,8 +2514,8 @@ D: XF86_8514 D: cfdisk (curses based disk partitioning program) N: Mat Martineau -E: mat@martineau.name -D: MPTCP subsystem co-maintainer 2020-2023 +E: martineau@kernel.org +D: MPTCP subsystem co-maintainer D: Keyctl restricted keyring and Diffie-Hellman UAPI D: Bluetooth L2CAP ERTM mode and AMP S: USA @@ -3475,6 +3479,11 @@ D: several improvements to system programs S: Oldenburg S: Germany +N: Mathieu Poirier +E: mathieu.poirier@linaro.org +D: CoreSight kernel subsystem, Maintainer 2014-2022 +D: Perf tool support for CoreSight + N: Robert Schwebel E: robert@schwebel.de W: https://www.schwebel.de diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index 3becc9a82bdf..534b7a3d59fc 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -136,6 +136,22 @@ Description: The last executed device administrative command's status/error. Also last configuration error overloaded. Writing to it will clear the status. +What: /sys/bus/dsa/devices/dsa/iaa_cap +Date: Sept 14, 2022 +KernelVersion: 6.0.0 +Contact: dmaengine@vger.kernel.org +Description: IAA (IAX) capability mask. Exported to user space for application + consumption. This attribute should only be visible on IAA devices + that are version 2 or later. + +What: /sys/bus/dsa/devices/dsa/event_log_size +Date: Sept 14, 2022 +KernelVersion: 6.4.0 +Contact: dmaengine@vger.kernel.org +Description: The event log size to be configured. Default is 64 entries and + occupies 4k size if the evl entry is 64 bytes. It's visible + only on platforms that support the capability. + What: /sys/bus/dsa/devices/wq./block_on_fault Date: Oct 27, 2020 KernelVersion: 5.11.0 @@ -219,6 +235,16 @@ Contact: dmaengine@vger.kernel.org Description: Indicate whether ATS disable is turned on for the workqueue. 0 indicates ATS is on, and 1 indicates ATS is off for the workqueue. +What: /sys/bus/dsa/devices/wq./prs_disable +Date: Sept 14, 2022 +KernelVersion: 6.4.0 +Contact: dmaengine@vger.kernel.org +Description: Controls whether PRS disable is turned on for the workqueue. + 0 indicates PRS is on, and 1 indicates PRS is off for the + workqueue. This option overrides block_on_fault attribute + if set. It's visible only on platforms that support the + capability. + What: /sys/bus/dsa/devices/wq./occupancy Date May 25, 2021 KernelVersion: 5.14.0 @@ -302,3 +328,28 @@ Description: Allows control of the number of batch descriptors that can be 1 (1/2 of max value), 2 (1/4 of the max value), and 3 (1/8 of the max value). It's visible only on platforms that support the capability. + +What: /sys/bus/dsa/devices/wq./dsa\!wq./file/cr_faults +Date: Sept 14, 2022 +KernelVersion: 6.4.0 +Contact: dmaengine@vger.kernel.org +Description: Show the number of Completion Record (CR) faults this application + has caused. + +What: /sys/bus/dsa/devices/wq./dsa\!wq./file/cr_fault_failures +Date: Sept 14, 2022 +KernelVersion: 6.4.0 +Contact: dmaengine@vger.kernel.org +Description: Show the number of Completion Record (CR) faults failures that this + application has caused. The failure counter is incremented when the + driver cannot fault in the address for the CR. Typically this is caused + by a bad address programmed in the submitted descriptor or a malicious + submitter is using bad CR address on purpose. + +What: /sys/bus/dsa/devices/wq./dsa\!wq./file/pid +Date: Sept 14, 2022 +KernelVersion: 6.4.0 +Contact: dmaengine@vger.kernel.org +Description: Show the process id of the application that opened the file. This is + helpful information for a monitor daemon that wants to kill the + application that opened the file. diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 80b98a4a4d0f..4feb692c4c1d 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -76,7 +76,7 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Default camera terminal descriptors - All attributes read only: + All attributes read only except bmControls, which is read/write: ======================== ==================================== bmControls bitmap specifying which controls are @@ -101,7 +101,7 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Default processing unit descriptors - All attributes read only: + All attributes read only except bmControls, which is read/write: =============== ======================================== iProcessing index of string descriptor diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl new file mode 100644 index 000000000000..fe61d372e3fa --- /dev/null +++ b/Documentation/ABI/testing/debugfs-cxl @@ -0,0 +1,35 @@ +What: /sys/kernel/debug/cxl/memX/inject_poison +Date: April, 2023 +KernelVersion: v6.4 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) When a Device Physical Address (DPA) is written to this + attribute, the memdev driver sends an inject poison command to + the device for the specified address. The DPA must be 64-byte + aligned and the length of the injected poison is 64-bytes. If + successful, the device returns poison when the address is + accessed through the CXL.mem bus. Injecting poison adds the + address to the device's Poison List and the error source is set + to Injected. In addition, the device adds a poison creation + event to its internal Informational Event log, updates the + Event Status register, and if configured, interrupts the host. + It is not an error to inject poison into an address that + already has poison present and no error is returned. The + inject_poison attribute is only visible for devices supporting + the capability. + + +What: /sys/kernel/debug/memX/clear_poison +Date: April, 2023 +KernelVersion: v6.4 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) When a Device Physical Address (DPA) is written to this + attribute, the memdev driver sends a clear poison command to + the device for the specified address. Clearing poison removes + the address from the device's Poison List and writes 0 (zero) + for 64 bytes starting at address. It is not an error to clear + poison from an address that does not have poison set. If the + device cannot clear poison from the address, -ENXIO is returned. + The clear_poison attribute is only visible for devices + supporting the capability. diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx new file mode 100644 index 000000000000..7af477f49998 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -0,0 +1,56 @@ +What: /sys/bus/cdx/rescan +Date: March 2023 +Contact: nipun.gupta@amd.com +Description: + Writing y/1/on to this file will cause rescan of the bus + and devices on the CDX bus. Any new devices are scanned and + added to the list of Linux devices and any devices removed are + also deleted from Linux. + + For example:: + + # echo 1 > /sys/bus/cdx/rescan + +What: /sys/bus/cdx/devices/.../vendor +Date: March 2023 +Contact: nipun.gupta@amd.com +Description: + Vendor ID for this CDX device, in hexadecimal. Vendor ID is + 16 bit identifier which is specific to the device manufacturer. + Combination of Vendor ID and Device ID identifies a device. + +What: /sys/bus/cdx/devices/.../device +Date: March 2023 +Contact: nipun.gupta@amd.com +Description: + Device ID for this CDX device, in hexadecimal. Device ID is + 16 bit identifier to identify a device type within the range + of a device manufacturer. + Combination of Vendor ID and Device ID identifies a device. + +What: /sys/bus/cdx/devices/.../reset +Date: March 2023 +Contact: nipun.gupta@amd.com +Description: + Writing y/1/on to this file resets the CDX device. + On resetting the device, the corresponding driver is notified + twice, once before the device is being reset, and again after + the reset has been complete. + + For example:: + + # echo 1 > /sys/bus/cdx/.../reset + +What: /sys/bus/cdx/devices/.../remove +Date: March 2023 +Contact: tarak.reddy@amd.com +Description: + Writing y/1/on to this file removes the corresponding + device from the CDX bus. If the device is to be reconfigured + reconfigured in the Hardware, the device can be removed, so + that the device driver does not access the device while it is + being reconfigured. + + For example:: + + # echo 1 > /sys/bus/cdx/devices/.../remove diff --git a/Documentation/ABI/testing/sysfs-bus-counter b/Documentation/ABI/testing/sysfs-bus-counter index ff83320b4255..1417c4272c6c 100644 --- a/Documentation/ABI/testing/sysfs-bus-counter +++ b/Documentation/ABI/testing/sysfs-bus-counter @@ -1,3 +1,33 @@ +What: /sys/bus/counter/devices/counterX/cascade_counts_enable +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + Indicates the cascading of Counts on Counter X. + + Valid attribute values are boolean. + +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + Selects the external clock pin for phase counting mode of + Counter X. + + MTCLKA-MTCLKB: + MTCLKA and MTCLKB pins are selected for the external + phase clock. + + MTCLKC-MTCLKD: + MTCLKC and MTCLKD pins are selected for the external + phase clock. + +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select_available +KernelVersion: 6.4 +Contact: linux-iio@vger.kernel.org +Description: + Discrete set of available values for the respective device + configuration are listed in this file. + What: /sys/bus/counter/devices/counterX/countY/count KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org @@ -215,6 +245,8 @@ Contact: linux-iio@vger.kernel.org Description: This attribute indicates the number of overflows of count Y. +What: /sys/bus/counter/devices/counterX/cascade_counts_enable_component_id +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select_component_id What: /sys/bus/counter/devices/counterX/countY/capture_component_id What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id What: /sys/bus/counter/devices/counterX/countY/floor_component_id diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index 3acf2f17a73f..48ac0d911801 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -415,3 +415,17 @@ Description: 1), and checks that the hardware accepts the commit request. Reading this value indicates whether the region is committed or not. + + +What: /sys/bus/cxl/devices/memX/trigger_poison_list +Date: April, 2023 +KernelVersion: v6.4 +Contact: linux-cxl@vger.kernel.org +Description: + (WO) When a boolean 'true' is written to this attribute the + memdev driver retrieves the poison list from the device. The + list consists of addresses that are poisoned, or would result + in poison if accessed, and the source of the poison. This + attribute is only visible for devices supporting the + capability. The retrieved errors are logged as kernel + events when cxl_poison event tracing is enabled. diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6ba34c0d9789..7140e8e7313f 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1807,8 +1807,8 @@ What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw KernelVersion: 4.3 Contact: linux-iio@vger.kernel.org Description: - Raw (unscaled no offset etc.) resistance reading that can be processed - into an ohm value. + Raw (unscaled no offset etc.) resistance reading. + Units after application of scale and offset are ohms. What: /sys/bus/iio/devices/iio:deviceX/heater_enable KernelVersion: 4.1.0 @@ -1894,8 +1894,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw KernelVersion: 4.8 Contact: linux-iio@vger.kernel.org Description: - Raw (unscaled no offset etc.) electric conductivity reading that - can be processed to siemens per meter. + Raw (unscaled no offset etc.) electric conductivity reading. + Units after application of scale and offset are siemens per + meter. What: /sys/bus/iio/devices/iio:deviceX/in_countY_raw KernelVersion: 4.10 @@ -1951,8 +1952,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw KernelVersion: 4.18 Contact: linux-iio@vger.kernel.org Description: - Raw (unscaled) phase difference reading from channel Y - that can be processed to radians. + Raw (unscaled) phase difference reading from channel Y. + Units after application of scale and offset are radians. What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm1_input What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm1_input diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd index 0088aba4caa8..5a775b8f6543 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd +++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd @@ -23,3 +23,55 @@ Description: Reading this attribute gives the state of the DbC. It can be one of the following states: disabled, enabled, initialized, connected, configured and stalled. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idVendor +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_idVendor attribute lets us change the idVendor field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x1d6b (Linux Foundation). + It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idProduct +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_idProduct attribute lets us change the idProduct field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x0010. It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bcdDevice +Date: March 2023 +Contact: Mathias Nyman +Description: + This dbc_bcdDevice attribute lets us change the bcdDevice field + presented in the USB device descriptor by this xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is 0x0010. (device rev 0.10) + It can be any 16-bit integer. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_bInterfaceProtocol +Date: March 2023 +Contact: Mathias Nyman +Description: + This attribute lets us change the bInterfaceProtocol field + presented in the USB Interface descriptor by the xhci debug + device. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB descriptor change while + connected to a USB host. + The default value is 1 (GNU Remote Debug command). + Other permissible value is 0 which is for vendor defined debug + target. diff --git a/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro b/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro index ca93c215ef99..fead760dcf77 100644 --- a/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro +++ b/Documentation/ABI/testing/sysfs-bus-platform-devices-ampere-smpro @@ -234,8 +234,8 @@ Description: For details, see section `5.10 RAS Internal Error Register Definitions, Altra Family Soc BMC Interface Specification`. -What: /sys/bus/platform/devices/smpro-errmon.*/event_[vrd_warn_fault|vrd_hot|dimm_hot] -KernelVersion: 6.1 +What: /sys/bus/platform/devices/smpro-errmon.*/event_[vrd_warn_fault|vrd_hot|dimm_hot|dimm_2x_refresh] +KernelVersion: 6.1 (event_[vrd_warn_fault|vrd_hot|dimm_hot]), 6.4 (event_dimm_2x_refresh) Contact: Quan Nguyen Description: (RO) Contains the detail information in case of VRD/DIMM warning/hot events @@ -258,8 +258,21 @@ Description: +---------------+---------------------------------------------------------------+---------------------+ | DIMM HOT | /sys/bus/platform/devices/smpro-errmon.*/event_dimm_hot | DIMM Hot | +---------------+---------------------------------------------------------------+---------------------+ + | DIMM 2X | /sys/bus/platform/devices/smpro-errmon.*/event_dimm_2x_refresh| DIMM 2x refresh rate| + | REFRESH RATE | | event in high temp | + +---------------+---------------------------------------------------------------+---------------------+ - For more details, see section `5.7 GPI Status Registers, + For more details, see section `5.7 GPI Status Registers and 5.9 Memory Error Register Definitions, + Altra Family Soc BMC Interface Specification`. + +What: /sys/bus/platform/devices/smpro-errmon.*/event_dimm[0-15]_syndrome +KernelVersion: 6.4 +Contact: Quan Nguyen +Description: + (RO) The sysfs returns the 2-byte DIMM failure syndrome data for slot + 0-15 if it failed to initialize. + + For more details, see section `5.11 Boot Stage Register Definitions, Altra Family Soc BMC Interface Specification`. What: /sys/bus/platform/devices/smpro-misc.*/boot_progress diff --git a/Documentation/ABI/testing/sysfs-devices-state_synced b/Documentation/ABI/testing/sysfs-devices-state_synced index 0c922d7d02fc..c64636ddac41 100644 --- a/Documentation/ABI/testing/sysfs-devices-state_synced +++ b/Documentation/ABI/testing/sysfs-devices-state_synced @@ -21,4 +21,9 @@ Description: at the time the kernel starts are not affected or limited in any way by sync_state() callbacks. + Writing "1" to this file will force a call to the device's + sync_state() function if it hasn't been called already. The + sync_state() call happens independent of the state of the + consumer devices. + diff --git a/Documentation/ABI/testing/sysfs-driver-zynqmp-fpga b/Documentation/ABI/testing/sysfs-driver-zynqmp-fpga new file mode 100644 index 000000000000..8f93d27b6d91 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-zynqmp-fpga @@ -0,0 +1,73 @@ +What: /sys/bus/platform/drivers/zynqmp_fpga_manager/firmware:zynqmp-firmware:pcap/status +Date: February 2023 +KernelVersion: 6.4 +Contact: Nava kishore Manne +Description: (RO) Read fpga status. + Read returns a hexadecimal value that tells the current status + of the FPGA device. Each bit position in the status value is + described Below(see ug570 chapter 9). + https://docs.xilinx.com/v/u/en-US/ug570-ultrascale-configuration + + ====================== ============================================== + BIT(0) 0: No CRC error + 1: CRC error + + BIT(1) 0: Decryptor security not set + 1: Decryptor security set + + BIT(2) 0: MMCMs/PLLs are not locked + 1: MMCMs/PLLs are locked + + BIT(3) 0: DCI not matched + 1: DCI matched + + BIT(4) 0: Start-up sequence has not finished + 1: Start-up sequence has finished + + BIT(5) 0: All I/Os are placed in High-Z state + 1: All I/Os behave as configured + + BIT(6) 0: Flip-flops and block RAM are write disabled + 1: Flip-flops and block RAM are write enabled + + BIT(7) 0: GHIGH_B_STATUS asserted + 1: GHIGH_B_STATUS deasserted + + BIT(8) to BIT(10) Status of the mode pins + + BIT(11) 0: Initialization has not finished + 1: Initialization finished + + BIT(12) Value on INIT_B_PIN pin + + BIT(13) 0: Signal not released + 1: Signal released + + BIT(14) Value on DONE_PIN pin. + + BIT(15) 0: No IDCODE_ERROR + 1: IDCODE_ERROR + + BIT(16) 0: No SECURITY_ERROR + 1: SECURITY_ERROR + + BIT(17) System Monitor over-temperature if set + + BIT(18) to BIT(20) Start-up state machine (0 to 7) + Phase 0 = 000 + Phase 1 = 001 + Phase 2 = 011 + Phase 3 = 010 + Phase 4 = 110 + Phase 5 = 111 + Phase 6 = 101 + Phase 7 = 100 + + BIT(25) to BIT(26) Indicates the detected bus width + 00 = x1 + 01 = x8 + 10 = x16 + 11 = x32 + ====================== ============================================== + + The other bits are reserved. diff --git a/Documentation/ABI/testing/sysfs-kernel-iommu_groups b/Documentation/ABI/testing/sysfs-kernel-iommu_groups index b15af6a5bc08..a42d4383d999 100644 --- a/Documentation/ABI/testing/sysfs-kernel-iommu_groups +++ b/Documentation/ABI/testing/sysfs-kernel-iommu_groups @@ -53,7 +53,6 @@ Description: /sys/kernel/iommu_groups//type shows the type of default The default domain type of a group may be modified only when - - The group has only one device. - The device in the group is not bound to any device driver. So, the users must unbind the appropriate driver before changing the default domain type. diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-ksm b/Documentation/ABI/testing/sysfs-kernel-mm-ksm index d244674a9480..6041a025b65a 100644 --- a/Documentation/ABI/testing/sysfs-kernel-mm-ksm +++ b/Documentation/ABI/testing/sysfs-kernel-mm-ksm @@ -51,3 +51,11 @@ Description: Control merging pages across different NUMA nodes. When it is set to 0 only pages from the same node are merged, otherwise pages from all nodes can be merged together (default). + +What: /sys/kernel/mm/ksm/general_profit +Date: April 2023 +KernelVersion: 6.4 +Contact: Linux memory management mailing list +Description: Measure how effective KSM is. + general_profit: how effective is KSM. The formula for the + calculation is in Documentation/admin-guide/mm/ksm.rst. diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst index 7103b62ba6d7..f61c01fc376e 100644 --- a/Documentation/accounting/delay-accounting.rst +++ b/Documentation/accounting/delay-accounting.rst @@ -16,6 +16,7 @@ d) memory reclaim e) thrashing f) direct compact g) write-protect copy +h) IRQ/SOFTIRQ and makes these statistics available to userspace through the taskstats interface. @@ -49,7 +50,7 @@ this structure. See for a description of the fields pertaining to delay accounting. It will generally be in the form of counters returning the cumulative delay seen for cpu, sync block I/O, swapin, memory reclaim, thrash page -cache, direct compact, write-protect copy etc. +cache, direct compact, write-protect copy, IRQ/SOFTIRQ etc. Taking the difference of two successive readings of a given counter (say cpu_delay_total) for a task will give the delay @@ -109,17 +110,19 @@ Get sum of delays, since system boot, for all pids with tgid 5:: CPU count real total virtual total delay total delay average 8 7000000 6872122 3382277 0.423ms IO count delay total delay average - 0 0 0ms + 0 0 0.000ms SWAP count delay total delay average - 0 0 0ms + 0 0 0.000ms RECLAIM count delay total delay average - 0 0 0ms + 0 0 0.000ms THRASHING count delay total delay average - 0 0 0ms + 0 0 0.000ms COMPACT count delay total delay average - 0 0 0ms - WPCOPY count delay total delay average - 0 0 0ms + 0 0 0.000ms + WPCOPY count delay total delay average + 0 0 0.000ms + IRQ count delay total delay average + 0 0 0.000ms Get IO accounting for pid 1, it works only with -p:: diff --git a/Documentation/accounting/psi.rst b/Documentation/accounting/psi.rst index 5e40b3f437f9..df6062eb3abb 100644 --- a/Documentation/accounting/psi.rst +++ b/Documentation/accounting/psi.rst @@ -105,6 +105,10 @@ prevent overly frequent polling. Max limit is chosen as a high enough number after which monitors are most likely not needed and psi averages can be used instead. +Unprivileged users can also create monitors, with the only limitation that the +window size must be a multiple of 2s, in order to prevent excessive resource +usage. + When activated, psi monitor stays active for at least the duration of one tracking window to avoid repeated activations/deactivations when system is bouncing in and out of the stall state. diff --git a/Documentation/admin-guide/blockdev/nbd.rst b/Documentation/admin-guide/blockdev/nbd.rst index d78dfe559dcf..faf2ac4b1509 100644 --- a/Documentation/admin-guide/blockdev/nbd.rst +++ b/Documentation/admin-guide/blockdev/nbd.rst @@ -14,7 +14,7 @@ to borrow disk space from another computer. Unlike NFS, it is possible to put any filesystem on it, etc. For more information, or to download the nbd-client and nbd-server -tools, go to http://nbd.sf.net/. +tools, go to https://github.com/NetworkBlockDevice/nbd. The nbd kernel module need only be installed on the client system, as the nbd-server is completely in userspace. In fact, diff --git a/Documentation/admin-guide/cgroup-v1/cpusets.rst b/Documentation/admin-guide/cgroup-v1/cpusets.rst index 5d844ed4df69..ae646d621a8a 100644 --- a/Documentation/admin-guide/cgroup-v1/cpusets.rst +++ b/Documentation/admin-guide/cgroup-v1/cpusets.rst @@ -719,7 +719,7 @@ There are ways to query or modify cpusets: cat, rmdir commands from the shell, or their equivalent from C. - via the C library libcpuset. - via the C library libcgroup. - (http://sourceforge.net/projects/libcg/) + (https://github.com/libcgroup/libcgroup/) - via the python application cset. (http://code.google.com/p/cpuset/) diff --git a/Documentation/admin-guide/cifs/changes.rst b/Documentation/admin-guide/cifs/changes.rst index 3147bbae9c43..8c42c4de510b 100644 --- a/Documentation/admin-guide/cifs/changes.rst +++ b/Documentation/admin-guide/cifs/changes.rst @@ -5,5 +5,5 @@ Changes See https://wiki.samba.org/index.php/LinuxCIFSKernel for summary information about fixes/improvements to CIFS/SMB2/SMB3 support (changes to cifs.ko module) by kernel version (and cifs internal module version). -This may be easier to read than parsing the output of "git log fs/cifs" -by release. +This may be easier to read than parsing the output of +"git log fs/smb/client" by release. diff --git a/Documentation/admin-guide/cifs/usage.rst b/Documentation/admin-guide/cifs/usage.rst index 2e151cd8c2e4..5f936b4b6018 100644 --- a/Documentation/admin-guide/cifs/usage.rst +++ b/Documentation/admin-guide/cifs/usage.rst @@ -45,7 +45,7 @@ Installation instructions If you have built the CIFS vfs as module (successfully) simply type ``make modules_install`` (or if you prefer, manually copy the file to -the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.ko). +the modules directory e.g. /lib/modules/6.3.0-060300-generic/kernel/fs/smb/client/cifs.ko). If you have built the CIFS vfs into the kernel itself, follow the instructions for your distribution on how to install a new kernel (usually you @@ -66,15 +66,15 @@ If cifs is built as a module, then the size and number of network buffers and maximum number of simultaneous requests to one server can be configured. Changing these from their defaults is not recommended. By executing modinfo:: - modinfo kernel/fs/cifs/cifs.ko + modinfo -on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made +on kernel/fs/smb/client/cifs.ko the list of configuration changes that can be made at module initialization time (by running insmod cifs.ko) can be seen. Recommendations =============== -To improve security the SMB2.1 dialect or later (usually will get SMB3) is now +To improve security the SMB2.1 dialect or later (usually will get SMB3.1.1) is now the new default. To use old dialects (e.g. to mount Windows XP) use "vers=1.0" on mount (or vers=2.0 for Windows Vista). Note that the CIFS (vers=1.0) is much older and less secure than the default dialect SMB3 which includes diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index 86fd88492870..c18d94fa6470 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -172,7 +172,7 @@ variables. Offset of the free_list's member. This value is used to compute the number of free pages. -Each zone has a free_area structure array called free_area[MAX_ORDER]. +Each zone has a free_area structure array called free_area[MAX_ORDER + 1]. The free_list represents a linked list of free page blocks. (list_head, next|prev) @@ -189,8 +189,8 @@ Offsets of the vmap_area's members. They carry vmalloc-specific information. Makedumpfile gets the start address of the vmalloc region from this. -(zone.free_area, MAX_ORDER) ---------------------------- +(zone.free_area, MAX_ORDER + 1) +------------------------------- Free areas descriptor. User-space tools use this value to iterate the free_area ranges. MAX_ORDER is used by the zone buddy allocator. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index bbecbd5797a3..9e5bab29685f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -912,15 +912,14 @@ cs89x0_media= [HW,NET] Format: { rj45 | aui | bnc } - csdlock_debug= [KNL] Enable debug add-ons of cross-CPU function call - handling. When switched on, additional debug data is - printed to the console in case a hanging CPU is - detected, and that CPU is pinged again in order to try - to resolve the hang situation. - 0: disable csdlock debugging (default) - 1: enable basic csdlock debugging (minor impact) - ext: enable extended csdlock debugging (more impact, - but more data) + csdlock_debug= [KNL] Enable or disable debug add-ons of cross-CPU + function call handling. When switched on, + additional debug data is printed to the console + in case a hanging CPU is detected, and that + CPU is pinged again in order to try to resolve + the hang situation. The default value of this + option depends on the CSD_LOCK_WAIT_DEBUG_DEFAULT + Kconfig option. dasd= [HW,NET] See header of drivers/s390/block/dasd_devmap.c. @@ -1602,6 +1601,20 @@ dependencies. This only applies for fw_devlink=on|rpm. Format: + fw_devlink.sync_state = + [KNL] When all devices that could probe have finished + probing, this parameter controls what to do with + devices that haven't yet received their sync_state() + calls. + Format: { strict | timeout } + strict -- Default. Continue waiting on consumers to + probe successfully. + timeout -- Give up waiting on consumers and call + sync_state() on any devices that haven't yet + received their sync_state() calls after + deferred_probe_timeout has expired or by + late_initcall() if !CONFIG_MODULES. + gamecon.map[2|3]= [HW,JOY] Multisystem joystick and NES/SNES/PSX pad support via parallel port (up to 5 devices per port) @@ -3349,6 +3362,12 @@ specified, .async_probe takes precedence for the specific module. + module.enable_dups_trace + [KNL] When CONFIG_MODULE_DEBUG_AUTOLOAD_DUPS is set, + this means that duplicate request_module() calls will + trigger a WARN_ON() instead of a pr_warn(). Note that + if MODULE_DEBUG_AUTOLOAD_DUPS_TRACE is set, WARN_ON()s + will always be issued and this option does nothing. module.sig_enforce [KNL] When CONFIG_MODULE_SIG is set, this means that modules without (valid) signatures will fail to load. @@ -3593,7 +3612,10 @@ emulation library even if a 387 maths coprocessor is present. - no5lvl [X86-64] Disable 5-level paging mode. Forces + no4lvl [RISCV] Disable 4-level and 5-level paging modes. Forces + kernel to use 3-level paging instead. + + no5lvl [X86-64,RISCV] Disable 5-level paging mode. Forces kernel to use 4-level paging instead. noaliencache [MM, NUMA, SLAB] Disables the allocation of alien @@ -3992,7 +4014,7 @@ [KNL] Minimal page reporting order Format: Adjust the minimal page reporting order. The page - reporting is disabled when it exceeds (MAX_ORDER-1). + reporting is disabled when it exceeds MAX_ORDER. panic= [KNL] Kernel behaviour on panic: delay timeout > 0: seconds before rebooting @@ -6150,15 +6172,6 @@ later by a loaded module cannot be set this way. Example: sysctl.vm.swappiness=40 - sysfs.deprecated=0|1 [KNL] - Enable/disable old style sysfs layout for old udev - on older distributions. When this option is enabled - very new udev will not work anymore. When this option - is disabled (or CONFIG_SYSFS_DEPRECATED not compiled) - in older udev will not work anymore. - Default depends on CONFIG_SYSFS_DEPRECATED_V2 set in - the kernel configuration. - sysrq_always_enabled [KNL] Ignore sysrq setting - this boot parameter will diff --git a/Documentation/admin-guide/mm/ksm.rst b/Documentation/admin-guide/mm/ksm.rst index eed51a910c94..7626392fe82c 100644 --- a/Documentation/admin-guide/mm/ksm.rst +++ b/Documentation/admin-guide/mm/ksm.rst @@ -20,7 +20,7 @@ content which can be replaced by a single write-protected page (which is automatically copied if a process later wants to update its content). The amount of pages that KSM daemon scans in a single pass and the time between the passes are configured using :ref:`sysfs -intraface ` +interface ` KSM only merges anonymous (private) pages, never pagecache (file) pages. KSM's merged pages were originally locked into kernel memory, but can now @@ -157,6 +157,8 @@ stable_node_chains_prune_millisecs The effectiveness of KSM and MADV_MERGEABLE is shown in ``/sys/kernel/mm/ksm/``: +general_profit + how effective is KSM. The calculation is explained below. pages_shared how many shared pages are being used pages_sharing @@ -207,7 +209,8 @@ several times, which are unprofitable memory consumed. ksm_rmap_items * sizeof(rmap_item). where ksm_merging_pages is shown under the directory ``/proc//``, - and ksm_rmap_items is shown in ``/proc//ksm_stat``. + and ksm_rmap_items is shown in ``/proc//ksm_stat``. The process profit + is also shown in ``/proc//ksm_stat`` as ksm_process_profit. From the perspective of application, a high ratio of ``ksm_rmap_items`` to ``ksm_merging_pages`` means a bad madvise-applied policy, so developers or diff --git a/Documentation/admin-guide/mm/userfaultfd.rst b/Documentation/admin-guide/mm/userfaultfd.rst index 7dc823b56ca4..7c304e432205 100644 --- a/Documentation/admin-guide/mm/userfaultfd.rst +++ b/Documentation/admin-guide/mm/userfaultfd.rst @@ -219,6 +219,31 @@ former will have ``UFFD_PAGEFAULT_FLAG_WP`` set, the latter you still need to supply a page when ``UFFDIO_REGISTER_MODE_MISSING`` was used. +Userfaultfd write-protect mode currently behave differently on none ptes +(when e.g. page is missing) over different types of memories. + +For anonymous memory, ``ioctl(UFFDIO_WRITEPROTECT)`` will ignore none ptes +(e.g. when pages are missing and not populated). For file-backed memories +like shmem and hugetlbfs, none ptes will be write protected just like a +present pte. In other words, there will be a userfaultfd write fault +message generated when writing to a missing page on file typed memories, +as long as the page range was write-protected before. Such a message will +not be generated on anonymous memories by default. + +If the application wants to be able to write protect none ptes on anonymous +memory, one can pre-populate the memory with e.g. MADV_POPULATE_READ. On +newer kernels, one can also detect the feature UFFD_FEATURE_WP_UNPOPULATED +and set the feature bit in advance to make sure none ptes will also be +write protected even upon anonymous memory. + +When using ``UFFDIO_REGISTER_MODE_WP`` in combination with either +``UFFDIO_REGISTER_MODE_MISSING`` or ``UFFDIO_REGISTER_MODE_MINOR``, when +resolving missing / minor faults with ``UFFDIO_COPY`` or ``UFFDIO_CONTINUE`` +respectively, it may be desirable for the new page / mapping to be +write-protected (so future writes will also result in a WP fault). These ioctls +support a mode flag (``UFFDIO_COPY_MODE_WP`` or ``UFFDIO_CONTINUE_MODE_WP`` +respectively) to configure the mapping this way. + QEMU/KVM ======== diff --git a/Documentation/admin-guide/quickly-build-trimmed-linux.rst b/Documentation/admin-guide/quickly-build-trimmed-linux.rst index ff4f4cc8522b..f08149bc53f8 100644 --- a/Documentation/admin-guide/quickly-build-trimmed-linux.rst +++ b/Documentation/admin-guide/quickly-build-trimmed-linux.rst @@ -215,12 +215,14 @@ again. reduce the compile time enormously, especially if you are running an universal kernel from a commodity Linux distribution. - There is a catch: the make target 'localmodconfig' will disable kernel - features you have not directly or indirectly through some program utilized - since you booted the system. You can reduce or nearly eliminate that risk by - using tricks outlined in the reference section; for quick testing purposes - that risk is often negligible, but it is an aspect you want to keep in mind - in case your kernel behaves oddly. + There is a catch: 'localmodconfig' is likely to disable kernel features you + did not use since you booted your Linux -- like drivers for currently + disconnected peripherals or a virtualization software not haven't used yet. + You can reduce or nearly eliminate that risk with tricks the reference + section outlines; but when building a kernel just for quick testing purposes + it is often negligible if such features are missing. But you should keep that + aspect in mind when using a kernel built with this make target, as it might + be the reason why something you only use occasionally stopped working. [:ref:`details`] @@ -271,6 +273,9 @@ again. does nothing at all; in that case you have to manually install your kernel, as outlined in the reference section. + If you are running a immutable Linux distribution, check its documentation + and the web to find out how to install your own kernel there. + [:ref:`details`] .. _another_sbs: @@ -291,29 +296,29 @@ again. version you care about, as git otherwise might retrieve the entire commit history:: - git fetch --shallow-exclude=v6.1 origin + git fetch --shallow-exclude=v6.0 origin - If you modified the sources (for example by applying a patch), you now need - to discard those modifications; that's because git otherwise will not be able - to switch to the sources of another version due to potential conflicting - changes:: + Now switch to the version you are interested in -- but be aware the command + used here will discard any modifications you performed, as they would + conflict with the sources you want to checkout:: - git reset --hard - - Now checkout the version you are interested in, as explained above:: - - git checkout --detach origin/master + git checkout --force --detach origin/master At this point you might want to patch the sources again or set/modify a build - tag, as explained earlier; afterwards adjust the build configuration to the - new codebase and build your next kernel:: + tag, as explained earlier. Afterwards adjust the build configuration to the + new codebase using olddefconfig, which will now adjust the configuration file + you prepared earlier using localmodconfig (~/linux/.config) for your next + kernel:: # reminder: if you want to apply patches, do it at this point # reminder: you might want to update your build tag at this point make olddefconfig + + Now build your kernel:: + make -j $(nproc --all) - Install the kernel as outlined above:: + Afterwards install the kernel as outlined above:: command -v installkernel && sudo make modules_install install @@ -584,11 +589,11 @@ versions and individual commits at hand at any time:: curl -L \ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/clone.bundle \ -o linux-stable.git.bundle - git clone clone.bundle ~/linux/ + git clone linux-stable.git.bundle ~/linux/ rm linux-stable.git.bundle cd ~/linux/ - git remote set-url origin - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git + git remote set-url origin \ + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git git fetch origin git checkout --detach origin/master diff --git a/Documentation/admin-guide/serial-console.rst b/Documentation/admin-guide/serial-console.rst index 58b32832e50a..8c8b94e54e26 100644 --- a/Documentation/admin-guide/serial-console.rst +++ b/Documentation/admin-guide/serial-console.rst @@ -33,8 +33,11 @@ The format of this option is:: 9600n8. The maximum baudrate is 115200. You can specify multiple console= options on the kernel command line. -Output will appear on all of them. The last device will be used when -you open ``/dev/console``. So, for example:: + +The behavior is well defined when each device type is mentioned only once. +In this case, the output will appear on all requested consoles. And +the last device will be used when you open ``/dev/console``. +So, for example:: console=ttyS1,9600 console=tty0 @@ -42,7 +45,34 @@ defines that opening ``/dev/console`` will get you the current foreground virtual console, and kernel messages will appear on both the VGA console and the 2nd serial port (ttyS1 or COM2) at 9600 baud. -Note that you can only define one console per device type (serial, video). +The behavior is more complicated when the same device type is defined more +times. In this case, there are the following two rules: + +1. The output will appear only on the first device of each defined type. + +2. ``/dev/console`` will be associated with the first registered device. + Where the registration order depends on how kernel initializes various + subsystems. + + This rule is used also when the last console= parameter is not used + for other reasons. For example, because of a typo or because + the hardware is not available. + +The result might be surprising. For example, the following two command +lines have the same result: + + console=ttyS1,9600 console=tty0 console=tty1 + console=tty0 console=ttyS1,9600 console=tty1 + +The kernel messages are printed only on ``tty0`` and ``ttyS1``. And +``/dev/console`` gets associated with ``tty0``. It is because kernel +tries to register graphical consoles before serial ones. It does it +because of the default behavior when no console device is specified, +see below. + +Note that the last ``console=tty1`` parameter still makes a difference. +The kernel command line is used also by systemd. It would use the last +defined ``tty1`` as the login console. If no console device is specified, the first device found capable of acting as a system console will be used. At this time, the system diff --git a/Documentation/admin-guide/xfs.rst b/Documentation/admin-guide/xfs.rst index e2561416391c..3a9c041d7f6c 100644 --- a/Documentation/admin-guide/xfs.rst +++ b/Documentation/admin-guide/xfs.rst @@ -236,13 +236,14 @@ the dates listed above. Deprecated Mount Options ======================== -=========================== ================ +============================ ================ Name Removal Schedule -=========================== ================ +============================ ================ Mounting with V4 filesystem September 2030 +Mounting ascii-ci filesystem September 2030 ikeep/noikeep September 2025 attr2/noattr2 September 2025 -=========================== ================ +============================ ================ Removed Mount Options diff --git a/Documentation/arch/x86/kernel-stacks.rst b/Documentation/arch/x86/kernel-stacks.rst index 6b0bcf027ff1..738671a4070b 100644 --- a/Documentation/arch/x86/kernel-stacks.rst +++ b/Documentation/arch/x86/kernel-stacks.rst @@ -12,7 +12,7 @@ Most of the text from Keith Owens, hacked by AK x86_64 page size (PAGE_SIZE) is 4K. Like all other architectures, x86_64 has a kernel stack for every -active thread. These thread stacks are THREAD_SIZE (2*PAGE_SIZE) big. +active thread. These thread stacks are THREAD_SIZE (4*PAGE_SIZE) big. These stacks contain useful data as long as a thread is alive or a zombie. While the thread is in user space the kernel stack is empty except for the thread_info structure at the bottom. diff --git a/Documentation/arch/x86/sva.rst b/Documentation/arch/x86/sva.rst index 2e9b8b0f9a0f..33cb05005982 100644 --- a/Documentation/arch/x86/sva.rst +++ b/Documentation/arch/x86/sva.rst @@ -107,7 +107,7 @@ process share the same page tables, thus the same MSR value. PASID Life Cycle Management =========================== -PASID is initialized as INVALID_IOASID (-1) when a process is created. +PASID is initialized as IOMMU_PASID_INVALID (-1) when a process is created. Only processes that access SVA-capable devices need to have a PASID allocated. This allocation happens when a process opens/binds an SVA-capable diff --git a/Documentation/arch/x86/xstate.rst b/Documentation/arch/x86/xstate.rst index 5cec7fb558d6..ae5c69e48b11 100644 --- a/Documentation/arch/x86/xstate.rst +++ b/Documentation/arch/x86/xstate.rst @@ -11,6 +11,22 @@ are enabled by XCR0 as well, but the first use of related instruction is trapped by the kernel because by default the required large XSTATE buffers are not allocated automatically. +The purpose for dynamic features +-------------------------------- + +Legacy userspace libraries often have hard-coded, static sizes for +alternate signal stacks, often using MINSIGSTKSZ which is typically 2KB. +That stack must be able to store at *least* the signal frame that the +kernel sets up before jumping into the signal handler. That signal frame +must include an XSAVE buffer defined by the CPU. + +However, that means that the size of signal stacks is dynamic, not static, +because different CPUs have differently-sized XSAVE buffers. A compiled-in +size of 2KB with existing applications is too small for new CPU features +like AMX. Instead of universally requiring larger stack, with the dynamic +enabling, the kernel can enforce userspace applications to have +properly-sized altstacks. + Using dynamically enabled XSTATE features in user space applications -------------------------------------------------------------------- @@ -64,6 +80,61 @@ the handler allocates a larger xstate buffer for the task so the large state can be context switched. In the unlikely cases that the allocation fails, the kernel sends SIGSEGV. +AMX TILE_DATA enabling example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Below is the example of how userspace applications enable +TILE_DATA dynamically: + + 1. The application first needs to query the kernel for AMX + support:: + + #include + #include + #include + #include + + #ifndef ARCH_GET_XCOMP_SUPP + #define ARCH_GET_XCOMP_SUPP 0x1021 + #endif + + #ifndef ARCH_XCOMP_TILECFG + #define ARCH_XCOMP_TILECFG 17 + #endif + + #ifndef ARCH_XCOMP_TILEDATA + #define ARCH_XCOMP_TILEDATA 18 + #endif + + #define MASK_XCOMP_TILE ((1 << ARCH_XCOMP_TILECFG) | \ + (1 << ARCH_XCOMP_TILEDATA)) + + unsigned long features; + long rc; + + ... + + rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); + + if (!rc && (features & MASK_XCOMP_TILE) == MASK_XCOMP_TILE) + printf("AMX is available.\n"); + + 2. After that, determining support for AMX, an application must + explicitly ask permission to use it:: + + #ifndef ARCH_REQ_XCOMP_PERM + #define ARCH_REQ_XCOMP_PERM 0x1023 + #endif + + ... + + rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, ARCH_XCOMP_TILEDATA); + + if (!rc) + printf("AMX is ready for use.\n"); + +Note this example does not include the sigaltstack preparation. + Dynamic features in signal frames --------------------------------- @@ -72,3 +143,32 @@ entry if the feature is in its initial configuration. This differs from non-dynamic features which are always written regardless of their configuration. Signal handlers can examine the XSAVE buffer's XSTATE_BV field to determine if a features was written. + +Dynamic features for virtual machines +------------------------------------- + +The permission for the guest state component needs to be managed separately +from the host, as they are exclusive to each other. A coupled of options +are extended to control the guest permission: + +-ARCH_GET_XCOMP_GUEST_PERM + + arch_prctl(ARCH_GET_XCOMP_GUEST_PERM, &features); + + ARCH_GET_XCOMP_GUEST_PERM is a variant of ARCH_GET_XCOMP_PERM. So it + provides the same semantics and functionality but for the guest + components. + +-ARCH_REQ_XCOMP_GUEST_PERM + + arch_prctl(ARCH_REQ_XCOMP_GUEST_PERM, feature_nr); + + ARCH_REQ_XCOMP_GUEST_PERM is a variant of ARCH_REQ_XCOMP_PERM. It has the + same semantics for the guest permission. While providing a similar + functionality, this comes with a constraint. Permission is frozen when the + first VCPU is created. Any attempt to change permission after that point + is going to be rejected. So, the permission has to be requested before the + first VCPU creation. + +Note that some VMMs may have already established a set of supported state +components. These options are not presumed to support any particular VMM. diff --git a/Documentation/block/index.rst b/Documentation/block/index.rst index 102953166429..9fea696f9daa 100644 --- a/Documentation/block/index.rst +++ b/Documentation/block/index.rst @@ -18,7 +18,6 @@ Block kyber-iosched null_blk pr - request stat switching-sched writeback_cache_control diff --git a/Documentation/block/request.rst b/Documentation/block/request.rst deleted file mode 100644 index 747021e1ffdb..000000000000 --- a/Documentation/block/request.rst +++ /dev/null @@ -1,99 +0,0 @@ -============================ -struct request documentation -============================ - -Jens Axboe 27/05/02 - - -.. FIXME: - No idea about what does mean - seems just some noise, so comment it - - 1.0 - Index - - 2.0 Struct request members classification - - 2.1 struct request members explanation - - 3.0 - - - 2.0 - - - -Short explanation of request members -==================================== - -Classification flags: - - = ==================== - D driver member - B block layer member - I I/O scheduler member - = ==================== - -Unless an entry contains a D classification, a device driver must not access -this member. Some members may contain D classifications, but should only be -access through certain macros or functions (eg ->flags). - - - -=============================== ======= ======================================= -Member Flag Comment -=============================== ======= ======================================= -struct list_head queuelist BI Organization on various internal - queues - -``void *elevator_private`` I I/O scheduler private data - -unsigned char cmd[16] D Driver can use this for setting up - a cdb before execution, see - blk_queue_prep_rq - -unsigned long flags DBI Contains info about data direction, - request type, etc. - -int rq_status D Request status bits - -kdev_t rq_dev DBI Target device - -int errors DB Error counts - -sector_t sector DBI Target location - -unsigned long hard_nr_sectors B Used to keep sector sane - -unsigned long nr_sectors DBI Total number of sectors in request - -unsigned long hard_nr_sectors B Used to keep nr_sectors sane - -unsigned short nr_phys_segments DB Number of physical scatter gather - segments in a request - -unsigned short nr_hw_segments DB Number of hardware scatter gather - segments in a request - -unsigned int current_nr_sectors DB Number of sectors in first segment - of request - -unsigned int hard_cur_sectors B Used to keep current_nr_sectors sane - -int tag DB TCQ tag, if assigned - -``void *special`` D Free to be used by driver - -``char *buffer`` D Map of first segment, also see - section on bouncing SECTION - -``struct completion *waiting`` D Can be used by driver to get signalled - on request completion - -``struct bio *bio`` DBI First bio in request - -``struct bio *biotail`` DBI Last bio in request - -``struct request_queue *q`` DB Request queue this request belongs to - -``struct request_list *rl`` B Request list this request came from -=============================== ======= ======================================= diff --git a/Documentation/bpf/prog_lsm.rst b/Documentation/bpf/prog_lsm.rst index 0dc3fb0d9544..ad2be02f30c2 100644 --- a/Documentation/bpf/prog_lsm.rst +++ b/Documentation/bpf/prog_lsm.rst @@ -18,7 +18,7 @@ LSM hook: .. c:function:: int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); Other LSM hooks which can be instrumented can be found in -``include/linux/lsm_hooks.h``. +``security/security.c``. eBPF programs that use Documentation/bpf/btf.rst do not need to include kernel headers for accessing information from the attached eBPF program's context. diff --git a/Documentation/cdrom/index.rst b/Documentation/cdrom/index.rst index e87a8785bc1a..e9b022d70939 100644 --- a/Documentation/cdrom/index.rst +++ b/Documentation/cdrom/index.rst @@ -1,8 +1,8 @@ .. SPDX-License-Identifier: GPL-2.0 -===== -cdrom -===== +====== +CD-ROM +====== .. toctree:: :maxdepth: 1 diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst index 62f961610773..9b3f3e5f5a95 100644 --- a/Documentation/core-api/kernel-api.rst +++ b/Documentation/core-api/kernel-api.rst @@ -220,12 +220,30 @@ relay interface Module Support ============== -Module Loading --------------- +Kernel module auto-loading +-------------------------- -.. kernel-doc:: kernel/kmod.c +.. kernel-doc:: kernel/module/kmod.c :export: +Module debugging +---------------- + +.. kernel-doc:: kernel/module/stats.c + :doc: module debugging statistics overview + +dup_failed_modules - tracks duplicate failed modules +**************************************************** + +.. kernel-doc:: kernel/module/stats.c + :doc: dup_failed_modules - tracks duplicate failed modules + +module statistics debugfs counters +********************************** + +.. kernel-doc:: kernel/module/stats.c + :doc: module statistics debugfs counters + Inter Module support -------------------- diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index dbe1aacc79d0..dfe7e75a71de 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -575,20 +575,26 @@ The field width is passed by value, the bitmap is passed by reference. Helper macros cpumask_pr_args() and nodemask_pr_args() are available to ease printing cpumask and nodemask. -Flags bitfields such as page flags, gfp_flags ---------------------------------------------- +Flags bitfields such as page flags, page_type, gfp_flags +-------------------------------------------------------- :: %pGp 0x17ffffc0002036(referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff) + %pGt 0xffffff7f(buddy) %pGg GFP_USER|GFP_DMA32|GFP_NOWARN %pGv read|exec|mayread|maywrite|mayexec|denywrite For printing flags bitfields as a collection of symbolic constants that would construct the value. The type of flags is given by the third -character. Currently supported are [p]age flags, [v]ma_flags (both -expect ``unsigned long *``) and [g]fp_flags (expects ``gfp_t *``). The flag -names and print order depends on the particular type. +character. Currently supported are: + + - p - [p]age flags, expects value of type (``unsigned long *``) + - t - page [t]ype, expects value of type (``unsigned int *``) + - v - [v]ma_flags, expects value of type (``unsigned long *``) + - g - [g]fp_flags, expects value of type (``gfp_t *``) + +The flag names and print order depends on the particular type. Note that this format should not be used directly in the :c:func:`TP_printk()` part of a tracepoint. Instead, use the show_*_flags() diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst index d83c9ab49427..6611434e2dd2 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -1,42 +1,50 @@ -kcov: code coverage for fuzzing +KCOV: code coverage for fuzzing =============================== -kcov exposes kernel code coverage information in a form suitable for coverage- -guided fuzzing (randomized testing). Coverage data of a running kernel is -exported via the "kcov" debugfs file. Coverage collection is enabled on a task -basis, and thus it can capture precise coverage of a single system call. +KCOV collects and exposes kernel code coverage information in a form suitable +for coverage-guided fuzzing. Coverage data of a running kernel is exported via +the ``kcov`` debugfs file. Coverage collection is enabled on a task basis, and +thus KCOV can capture precise coverage of a single system call. -Note that kcov does not aim to collect as much coverage as possible. It aims -to collect more or less stable coverage that is function of syscall inputs. -To achieve this goal it does not collect coverage in soft/hard interrupts -and instrumentation of some inherently non-deterministic parts of kernel is -disabled (e.g. scheduler, locking). +Note that KCOV does not aim to collect as much coverage as possible. It aims +to collect more or less stable coverage that is a function of syscall inputs. +To achieve this goal, it does not collect coverage in soft/hard interrupts +(unless remove coverage collection is enabled, see below) and from some +inherently non-deterministic parts of the kernel (e.g. scheduler, locking). -kcov is also able to collect comparison operands from the instrumented code -(this feature currently requires that the kernel is compiled with clang). +Besides collecting code coverage, KCOV can also collect comparison operands. +See the "Comparison operands collection" section for details. + +Besides collecting coverage data from syscall handlers, KCOV can also collect +coverage for annotated parts of the kernel executing in background kernel +tasks or soft interrupts. See the "Remote coverage collection" section for +details. Prerequisites ------------- -Configure the kernel with:: +KCOV relies on compiler instrumentation and requires GCC 6.1.0 or later +or any Clang version supported by the kernel. + +Collecting comparison operands is supported with GCC 8+ or with Clang. + +To enable KCOV, configure the kernel with:: CONFIG_KCOV=y -CONFIG_KCOV requires gcc 6.1.0 or later. - -If the comparison operands need to be collected, set:: +To enable comparison operands collection, set:: CONFIG_KCOV_ENABLE_COMPARISONS=y -Profiling data will only become accessible once debugfs has been mounted:: +Coverage data only becomes accessible once debugfs has been mounted:: mount -t debugfs none /sys/kernel/debug Coverage collection ------------------- -The following program demonstrates coverage collection from within a test -program using kcov: +The following program demonstrates how to use KCOV to collect coverage for a +single syscall from within a test program: .. code-block:: c @@ -84,7 +92,7 @@ program using kcov: perror("ioctl"), exit(1); /* Reset coverage from the tail of the ioctl() call. */ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); - /* That's the target syscal call. */ + /* Call the target syscall call. */ read(-1, NULL, 0); /* Read number of PCs collected. */ n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); @@ -103,7 +111,7 @@ program using kcov: return 0; } -After piping through addr2line output of the program looks as follows:: +After piping through ``addr2line`` the output of the program looks as follows:: SyS_read fs/read_write.c:562 @@ -121,12 +129,13 @@ After piping through addr2line output of the program looks as follows:: fs/read_write.c:562 If a program needs to collect coverage from several threads (independently), -it needs to open /sys/kernel/debug/kcov in each thread separately. +it needs to open ``/sys/kernel/debug/kcov`` in each thread separately. The interface is fine-grained to allow efficient forking of test processes. -That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, -mmaps coverage buffer and then forks child processes in a loop. Child processes -only need to enable coverage (disable happens automatically on thread end). +That is, a parent process opens ``/sys/kernel/debug/kcov``, enables trace mode, +mmaps coverage buffer, and then forks child processes in a loop. The child +processes only need to enable coverage (it gets disabled automatically when +a thread exits). Comparison operands collection ------------------------------ @@ -205,52 +214,78 @@ Comparison operands collection is similar to coverage collection: return 0; } -Note that the kcov modes (coverage collection or comparison operands) are -mutually exclusive. +Note that the KCOV modes (collection of code coverage or comparison operands) +are mutually exclusive. Remote coverage collection -------------------------- -With KCOV_ENABLE coverage is collected only for syscalls that are issued -from the current process. With KCOV_REMOTE_ENABLE it's possible to collect -coverage for arbitrary parts of the kernel code, provided that those parts -are annotated with kcov_remote_start()/kcov_remote_stop(). +Besides collecting coverage data from handlers of syscalls issued from a +userspace process, KCOV can also collect coverage for parts of the kernel +executing in other contexts - so-called "remote" coverage. -This allows to collect coverage from two types of kernel background -threads: the global ones, that are spawned during kernel boot in a limited -number of instances (e.g. one USB hub_event() worker thread is spawned per -USB HCD); and the local ones, that are spawned when a user interacts with -some kernel interface (e.g. vhost workers); as well as from soft -interrupts. +Using KCOV to collect remote coverage requires: -To enable collecting coverage from a global background thread or from a -softirq, a unique global handle must be assigned and passed to the -corresponding kcov_remote_start() call. Then a userspace process can pass -a list of such handles to the KCOV_REMOTE_ENABLE ioctl in the handles -array field of the kcov_remote_arg struct. This will attach the used kcov -device to the code sections, that are referenced by those handles. +1. Modifying kernel code to annotate the code section from where coverage + should be collected with ``kcov_remote_start`` and ``kcov_remote_stop``. -Since there might be many local background threads spawned from different -userspace processes, we can't use a single global handle per annotation. -Instead, the userspace process passes a non-zero handle through the -common_handle field of the kcov_remote_arg struct. This common handle gets -saved to the kcov_handle field in the current task_struct and needs to be -passed to the newly spawned threads via custom annotations. Those threads -should in turn be annotated with kcov_remote_start()/kcov_remote_stop(). +2. Using ``KCOV_REMOTE_ENABLE`` instead of ``KCOV_ENABLE`` in the userspace + process that collects coverage. -Internally kcov stores handles as u64 integers. The top byte of a handle -is used to denote the id of a subsystem that this handle belongs to, and -the lower 4 bytes are used to denote the id of a thread instance within -that subsystem. A reserved value 0 is used as a subsystem id for common -handles as they don't belong to a particular subsystem. The bytes 4-7 are -currently reserved and must be zero. In the future the number of bytes -used for the subsystem or handle ids might be increased. +Both ``kcov_remote_start`` and ``kcov_remote_stop`` annotations and the +``KCOV_REMOTE_ENABLE`` ioctl accept handles that identify particular coverage +collection sections. The way a handle is used depends on the context where the +matching code section executes. -When a particular userspace process collects coverage via a common -handle, kcov will collect coverage for each code section that is annotated -to use the common handle obtained as kcov_handle from the current -task_struct. However non common handles allow to collect coverage -selectively from different subsystems. +KCOV supports collecting remote coverage from the following contexts: + +1. Global kernel background tasks. These are the tasks that are spawned during + kernel boot in a limited number of instances (e.g. one USB ``hub_event`` + worker is spawned per one USB HCD). + +2. Local kernel background tasks. These are spawned when a userspace process + interacts with some kernel interface and are usually killed when the process + exits (e.g. vhost workers). + +3. Soft interrupts. + +For #1 and #3, a unique global handle must be chosen and passed to the +corresponding ``kcov_remote_start`` call. Then a userspace process must pass +this handle to ``KCOV_REMOTE_ENABLE`` in the ``handles`` array field of the +``kcov_remote_arg`` struct. This will attach the used KCOV device to the code +section referenced by this handle. Multiple global handles identifying +different code sections can be passed at once. + +For #2, the userspace process instead must pass a non-zero handle through the +``common_handle`` field of the ``kcov_remote_arg`` struct. This common handle +gets saved to the ``kcov_handle`` field in the current ``task_struct`` and +needs to be passed to the newly spawned local tasks via custom kernel code +modifications. Those tasks should in turn use the passed handle in their +``kcov_remote_start`` and ``kcov_remote_stop`` annotations. + +KCOV follows a predefined format for both global and common handles. Each +handle is a ``u64`` integer. Currently, only the one top and the lower 4 bytes +are used. Bytes 4-7 are reserved and must be zero. + +For global handles, the top byte of the handle denotes the id of a subsystem +this handle belongs to. For example, KCOV uses ``1`` as the USB subsystem id. +The lower 4 bytes of a global handle denote the id of a task instance within +that subsystem. For example, each ``hub_event`` worker uses the USB bus number +as the task instance id. + +For common handles, a reserved value ``0`` is used as a subsystem id, as such +handles don't belong to a particular subsystem. The lower 4 bytes of a common +handle identify a collective instance of all local tasks spawned by the +userspace process that passed a common handle to ``KCOV_REMOTE_ENABLE``. + +In practice, any value can be used for common handle instance id if coverage +is only collected from a single userspace process on the system. However, if +common handles are used by multiple processes, unique instance ids must be +used for each process. One option is to use the process id as the common +handle instance id. + +The following program demonstrates using KCOV to collect coverage from both +local tasks spawned by the process and the global task that handles USB bus #1: .. code-block:: c diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt deleted file mode 100644 index 7f696362a4a1..000000000000 --- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt +++ /dev/null @@ -1,49 +0,0 @@ -Krait Processor Sub-system (KPSS) Application Clock Controller (ACC) - -The KPSS ACC provides clock, power domain, and reset control to a Krait CPU. -There is one ACC register region per CPU within the KPSS remapped region as -well as an alias register region that remaps accesses to the ACC associated -with the CPU accessing the region. - -PROPERTIES - -- compatible: - Usage: required - Value type: - Definition: should be one of: - "qcom,kpss-acc-v1" - "qcom,kpss-acc-v2" - -- reg: - Usage: required - Value type: - Definition: the first element specifies the base address and size of - the register region. An optional second element specifies - the base address and size of the alias register region. - -- clocks: - Usage: required - Value type: - Definition: reference to the pll parents. - -- clock-names: - Usage: required - Value type: - Definition: must be "pll8_vote", "pxo". - -- clock-output-names: - Usage: optional - Value type: - Definition: Name of the output clock. Typically acpuX_aux where X is a - CPU number starting at 0. - -Example: - - clock-controller@2088000 { - compatible = "qcom,kpss-acc-v2"; - reg = <0x02088000 0x1000>, - <0x02008000 0x1000>; - clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; - clock-names = "pll8_vote", "pxo"; - clock-output-names = "acpu0_aux"; - }; diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt deleted file mode 100644 index e628758950e1..000000000000 --- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt +++ /dev/null @@ -1,44 +0,0 @@ -Krait Processor Sub-system (KPSS) Global Clock Controller (GCC) - -PROPERTIES - -- compatible: - Usage: required - Value type: - Definition: should be one of the following. The generic compatible - "qcom,kpss-gcc" should also be included. - "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc" - "qcom,kpss-gcc-apq8064", "qcom,kpss-gcc" - "qcom,kpss-gcc-msm8974", "qcom,kpss-gcc" - "qcom,kpss-gcc-msm8960", "qcom,kpss-gcc" - -- reg: - Usage: required - Value type: - Definition: base address and size of the register region - -- clocks: - Usage: required - Value type: - Definition: reference to the pll parents. - -- clock-names: - Usage: required - Value type: - Definition: must be "pll8_vote", "pxo". - -- clock-output-names: - Usage: required - Value type: - Definition: Name of the output clock. Typically acpu_l2_aux indicating - an L2 cache auxiliary clock. - -Example: - - l2cc: clock-controller@2011000 { - compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc"; - reg = <0x2011000 0x1000>; - clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; - clock-names = "pll8_vote", "pxo"; - clock-output-names = "acpu_l2_aux"; - }; diff --git a/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml index 9b31f864e071..71364c6081ff 100644 --- a/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml +++ b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml @@ -32,7 +32,7 @@ properties: maxItems: 1 iommus: - maxItems: 1 + maxItems: 4 power-domains: maxItems: 1 diff --git a/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml b/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml new file mode 100644 index 000000000000..a8d40c766dcd --- /dev/null +++ b/Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bus/microsoft,vmbus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microsoft Hyper-V VMBus + +maintainers: + - Saurabh Sengar + +description: + VMBus is a software bus that implement the protocols for communication + between the root or host OS and guest OSs (virtual machines). + +properties: + compatible: + const: microsoft,vmbus + + ranges: true + + '#address-cells': + const: 2 + + '#size-cells': + const: 1 + +required: + - compatible + - ranges + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <1>; + bus { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + + vmbus@ff0000000 { + compatible = "microsoft,vmbus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0x0f 0xf0000000 0x0f 0xf0000000 0x10000000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/bus/xlnx,versal-net-cdx.yaml b/Documentation/devicetree/bindings/bus/xlnx,versal-net-cdx.yaml new file mode 100644 index 000000000000..7f62ffbdc245 --- /dev/null +++ b/Documentation/devicetree/bindings/bus/xlnx,versal-net-cdx.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bus/xlnx,versal-net-cdx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AMD CDX bus controller + +description: | + CDX bus controller for AMD devices is implemented to dynamically + detect CDX bus and devices using the firmware. + The CDX bus manages multiple FPGA based hardware devices, which + can support network, crypto or any other specialized type of + devices. These FPGA based devices can be added/modified dynamically + on run-time. + + All devices on the CDX bus will have a unique streamid (for IOMMU) + and a unique device ID (for MSI) corresponding to a requestor ID + (one to one associated with the device). The streamid and deviceid + are used to configure SMMU and GIC-ITS respectively. + + iommu-map property is used to define the set of stream ids + corresponding to each device and the associated IOMMU. + + The MSI writes are accompanied by sideband data (Device ID). + The msi-map property is used to associate the devices with the + device ID as well as the associated ITS controller. + + rproc property (xlnx,rproc) is used to identify the remote processor + with which APU (Application Processor Unit) interacts to find out + the bus and device configuration. + +maintainers: + - Nipun Gupta + - Nikhil Agarwal + +properties: + compatible: + const: xlnx,versal-net-cdx + + iommu-map: true + + msi-map: true + + xlnx,rproc: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the remoteproc_r5 rproc node using which APU interacts + with remote processor. + + ranges: true + + "#address-cells": + enum: [1, 2] + + "#size-cells": + enum: [1, 2] + +required: + - compatible + - iommu-map + - msi-map + - xlnx,rproc + - ranges + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + cdx { + compatible = "xlnx,versal-net-cdx"; + #address-cells = <1>; + #size-cells = <1>; + /* define map for RIDs 250-259 */ + iommu-map = <250 &smmu 250 10>; + /* define msi map for RIDs 250-259 */ + msi-map = <250 &its 250 10>; + xlnx,rproc = <&remoteproc_r5>; + ranges; + }; diff --git a/Documentation/devicetree/bindings/clock/brcm,bcm63268-timer-clocks.yaml b/Documentation/devicetree/bindings/clock/brcm,bcm63268-timer-clocks.yaml new file mode 100644 index 000000000000..199818b2fb6d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/brcm,bcm63268-timer-clocks.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/brcm,bcm63268-timer-clocks.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom BCM63268 Timer Clock and Reset Device Tree Bindings + +maintainers: + - Álvaro Fernández Rojas + +properties: + compatible: + const: brcm,bcm63268-timer-clocks + + reg: + maxItems: 1 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + timer_clk: clock-controller@100000ac { + compatible = "brcm,bcm63268-timer-clocks"; + reg = <0x100000ac 0x4>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml b/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml new file mode 100644 index 000000000000..ff9600474df2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/imx8mp-audiomix.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8MP AudioMIX Block Control Binding + +maintainers: + - Marek Vasut + +description: | + NXP i.MX8M Plus AudioMIX is dedicated clock muxing and gating IP + used to control Audio related clock on the SoC. + +properties: + compatible: + const: fsl,imx8mp-audio-blk-ctrl + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + clocks: + minItems: 7 + maxItems: 7 + + clock-names: + items: + - const: ahb + - const: sai1 + - const: sai2 + - const: sai3 + - const: sai5 + - const: sai6 + - const: sai7 + + '#clock-cells': + const: 1 + description: + The clock consumer should specify the desired clock by having the clock + ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h + for the full list of i.MX8MP IMX8MP_CLK_AUDIOMIX_ clock IDs. + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - '#clock-cells' + +additionalProperties: false + +examples: + # Clock Control Module node: + - | + #include + + clock-controller@30e20000 { + compatible = "fsl,imx8mp-audio-blk-ctrl"; + reg = <0x30e20000 0x10000>; + #clock-cells = <1>; + clocks = <&clk IMX8MP_CLK_AUDIO_ROOT>, + <&clk IMX8MP_CLK_SAI1>, + <&clk IMX8MP_CLK_SAI2>, + <&clk IMX8MP_CLK_SAI3>, + <&clk IMX8MP_CLK_SAI5>, + <&clk IMX8MP_CLK_SAI6>, + <&clk IMX8MP_CLK_SAI7>; + clock-names = "ahb", + "sai1", "sai2", "sai3", + "sai5", "sai6", "sai7"; + power-domains = <&pgc_audio>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/loongson,ls1x-clk.yaml b/Documentation/devicetree/bindings/clock/loongson,ls1x-clk.yaml new file mode 100644 index 000000000000..01561a0f35d5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/loongson,ls1x-clk.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/loongson,ls1x-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-1 Clock Controller + +maintainers: + - Keguang Zhang + +properties: + compatible: + enum: + - loongson,ls1b-clk + - loongson,ls1c-clk + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clkc: clock-controller@1fe78030 { + compatible = "loongson,ls1b-clk"; + reg = <0x1fe78030 0x8>; + + clocks = <&xtal>; + #clock-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml index cfd042ac1e14..d00327d12e1e 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml @@ -16,7 +16,12 @@ description: | properties: compatible: - const: mediatek,mt8186-fhctl + enum: + - mediatek,mt6795-fhctl + - mediatek,mt8173-fhctl + - mediatek,mt8186-fhctl + - mediatek,mt8192-fhctl + - mediatek,mt8195-fhctl reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml new file mode 100644 index 000000000000..d7214d97b2ba --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt8188-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Functional Clock Controller for MT8188 + +maintainers: + - Garmin Chang + +description: | + The clock architecture in MediaTek like below + PLLs --> + dividers --> + muxes + --> + clock gate + + The devices provide clock gate control in different IP blocks. + +properties: + compatible: + enum: + - mediatek,mt8188-adsp-audio26m + - mediatek,mt8188-camsys + - mediatek,mt8188-camsys-rawa + - mediatek,mt8188-camsys-rawb + - mediatek,mt8188-camsys-yuva + - mediatek,mt8188-camsys-yuvb + - mediatek,mt8188-ccusys + - mediatek,mt8188-imgsys + - mediatek,mt8188-imgsys-wpe1 + - mediatek,mt8188-imgsys-wpe2 + - mediatek,mt8188-imgsys-wpe3 + - mediatek,mt8188-imgsys1-dip-nr + - mediatek,mt8188-imgsys1-dip-top + - mediatek,mt8188-imp-iic-wrap-c + - mediatek,mt8188-imp-iic-wrap-en + - mediatek,mt8188-imp-iic-wrap-w + - mediatek,mt8188-ipesys + - mediatek,mt8188-mfgcfg + - mediatek,mt8188-vdecsys + - mediatek,mt8188-vdecsys-soc + - mediatek,mt8188-vencsys + - mediatek,mt8188-vppsys0 + - mediatek,mt8188-vppsys1 + - mediatek,mt8188-wpesys + - mediatek,mt8188-wpesys-vpp0 + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11283000 { + compatible = "mediatek,mt8188-imp-iic-wrap-c"; + reg = <0x11283000 0x1000>; + #clock-cells = <1>; + }; + diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml new file mode 100644 index 000000000000..4cf8d3af9803 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt8188-sys-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek System Clock Controller for MT8188 + +maintainers: + - Garmin Chang + +description: | + The clock architecture in MediaTek like below + PLLs --> + dividers --> + muxes + --> + clock gate + + The apmixedsys provides most of PLLs which generated from SoC 26m. + The topckgen provides dividers and muxes which provide the clock source to other IP blocks. + The infracfg_ao provides clock gate in peripheral and infrastructure IP blocks. + The mcusys provides mux control to select the clock source in AP MCU. + The device nodes also provide the system control capacity for configuration. + +properties: + compatible: + items: + - enum: + - mediatek,mt8188-apmixedsys + - mediatek,mt8188-infracfg-ao + - mediatek,mt8188-pericfg-ao + - mediatek,mt8188-topckgen + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@10000000 { + compatible = "mediatek,mt8188-topckgen", "syscon"; + reg = <0x10000000 0x1000>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml index 64bfd0f5d4d0..659669bf224b 100644 --- a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,ipq5332-a53pll - qcom,ipq6018-a53pll - qcom,ipq8074-a53pll - qcom,msm8916-a53pll diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq4019.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq4019.yaml new file mode 100644 index 000000000000..6ebaef2288fa --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq4019.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq4019.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on IPQ4019 + +maintainers: + - Stephen Boyd + - Taniya Das + - Robert Marko + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on IPQ4019. + + See also:: include/dt-bindings/clock/qcom,gcc-ipq4019.h + +allOf: + - $ref: qcom,gcc.yaml# + +properties: + compatible: + const: qcom,gcc-ipq4019 + + clocks: + items: + - description: board XO clock + - description: sleep clock + + clock-names: + items: + - const: xo + - const: sleep_clk + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + clock-controller@1800000 { + compatible = "qcom,gcc-ipq4019"; + reg = <0x1800000 0x60000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + clocks = <&xo>, <&sleep_clk>; + clock-names = "xo", "sleep_clk"; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8909.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8909.yaml index 6279a59c2e20..b91462587df5 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-msm8909.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-msm8909.yaml @@ -4,20 +4,25 @@ $id: http://devicetree.org/schemas/clock/qcom,gcc-msm8909.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm Global Clock & Reset Controller on MSM8909 +title: Qualcomm Global Clock & Reset Controller on MSM8909, MSM8917 and QM215 maintainers: - Stephan Gerhold description: | Qualcomm global clock control module provides the clocks, resets and power - domains on MSM8909. + domains on MSM8909, MSM8917 or QM215. - See also:: include/dt-bindings/clock/qcom,gcc-msm8909.h + See also:: + include/dt-bindings/clock/qcom,gcc-msm8909.h + include/dt-bindings/clock/qcom,gcc-msm8917.h properties: compatible: - const: qcom,gcc-msm8909 + enum: + - qcom,gcc-msm8909 + - qcom,gcc-msm8917 + - qcom,gcc-qm215 clocks: items: diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml index 2e8acca64af1..ae01e7749534 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml @@ -15,7 +15,6 @@ description: | domains. See also:: - include/dt-bindings/clock/qcom,gcc-ipq4019.h include/dt-bindings/clock/qcom,gcc-ipq6018.h include/dt-bindings/reset/qcom,gcc-ipq6018.h include/dt-bindings/clock/qcom,gcc-msm8953.h @@ -29,7 +28,6 @@ allOf: properties: compatible: enum: - - qcom,gcc-ipq4019 - qcom,gcc-ipq6018 - qcom,gcc-mdm9607 - qcom,gcc-msm8953 diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml index db53eb288995..1e3dc9deded9 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.yaml @@ -15,6 +15,7 @@ description: | See also:: include/dt-bindings/clock/qcom,gpucc-sdm845.h + include/dt-bindings/clock/qcom,gpucc-sa8775p.h include/dt-bindings/clock/qcom,gpucc-sc7180.h include/dt-bindings/clock/qcom,gpucc-sc7280.h include/dt-bindings/clock/qcom,gpucc-sc8280xp.h @@ -27,6 +28,7 @@ properties: compatible: enum: - qcom,sdm845-gpucc + - qcom,sa8775p-gpucc - qcom,sc7180-gpucc - qcom,sc7280-gpucc - qcom,sc8180x-gpucc diff --git a/Documentation/devicetree/bindings/clock/qcom,kpss-acc-v1.yaml b/Documentation/devicetree/bindings/clock/qcom,kpss-acc-v1.yaml new file mode 100644 index 000000000000..a466e4e8aacd --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,kpss-acc-v1.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,kpss-acc-v1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Krait Processor Sub-system (KPSS) Application Clock Controller (ACC) v1 + +maintainers: + - Christian Marangi + +description: + The KPSS ACC provides clock, power domain, and reset control to a Krait CPU. + There is one ACC register region per CPU within the KPSS remapped region as + well as an alias register region that remaps accesses to the ACC associated + with the CPU accessing the region. ACC v1 is currently used as a + clock-controller for enabling the cpu and hanling the aux clocks. + +properties: + compatible: + const: qcom,kpss-acc-v1 + + reg: + items: + - description: Base address and size of the register region + - description: Optional base address and size of the alias register region + minItems: 1 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: pll8_vote + - const: pxo + + clock-output-names: + description: Name of the aux clock. Krait can have at most 4 cpu. + enum: + - acpu0_aux + - acpu1_aux + - acpu2_aux + - acpu3_aux + + '#clock-cells': + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - clock-output-names + - '#clock-cells' + +additionalProperties: false + +examples: + - | + #include + + clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; + clocks = <&gcc PLL8_VOTE>, <&pxo_board>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu0_aux"; + #clock-cells = <0>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/qcom,kpss-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,kpss-gcc.yaml new file mode 100644 index 000000000000..88b7672123a0 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,kpss-gcc.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,kpss-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Krait Processor Sub-system (KPSS) Global Clock Controller (GCC) + +maintainers: + - Christian Marangi + +description: + Krait Processor Sub-system (KPSS) Global Clock Controller (GCC). Used + to control L2 mux (in the current implementation) and provide access + to the kpss-gcc registers. + +properties: + compatible: + items: + - enum: + - qcom,kpss-gcc-ipq8064 + - qcom,kpss-gcc-apq8064 + - qcom,kpss-gcc-msm8974 + - qcom,kpss-gcc-msm8960 + - qcom,kpss-gcc-msm8660 + - qcom,kpss-gcc-mdm9615 + - const: qcom,kpss-gcc + - const: syscon + + reg: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: pll8_vote + - const: pxo + + '#clock-cells': + const: 0 + +required: + - compatible + - reg + +if: + properties: + compatible: + contains: + enum: + - qcom,kpss-gcc-ipq8064 + - qcom,kpss-gcc-apq8064 + - qcom,kpss-gcc-msm8974 + - qcom,kpss-gcc-msm8960 +then: + required: + - clocks + - clock-names + - '#clock-cells' +else: + properties: + clock: false + clock-names: false + '#clock-cells': false + +additionalProperties: false + +examples: + - | + #include + + clock-controller@2011000 { + compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc", "syscon"; + reg = <0x2011000 0x1000>; + clocks = <&gcc PLL8_VOTE>, <&pxo_board>; + clock-names = "pll8_vote", "pxo"; + #clock-cells = <0>; + }; + + - | + clock-controller@2011000 { + compatible = "qcom,kpss-gcc-mdm9615", "qcom,kpss-gcc", "syscon"; + reg = <0x02011000 0x1000>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml index 2a95bf8664f9..3665dd30604a 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml @@ -31,6 +31,7 @@ properties: - qcom,rpmcc-msm8660 - qcom,rpmcc-msm8909 - qcom,rpmcc-msm8916 + - qcom,rpmcc-msm8917 - qcom,rpmcc-msm8936 - qcom,rpmcc-msm8953 - qcom,rpmcc-msm8974 @@ -107,6 +108,7 @@ allOf: - qcom,rpmcc-mdm9607 - qcom,rpmcc-msm8226 - qcom,rpmcc-msm8916 + - qcom,rpmcc-msm8917 - qcom,rpmcc-msm8936 - qcom,rpmcc-msm8953 - qcom,rpmcc-msm8974 diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscc.yaml index 6151fdebbff8..97c6bd96e0cb 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7280-lpasscc.yaml @@ -41,6 +41,12 @@ properties: - const: qdsp6ss - const: top_cc + qcom,adsp-pil-mode: + description: + Indicates if the LPASS would be brought out of reset using + remoteproc peripheral loader. + type: boolean + required: - compatible - reg @@ -60,6 +66,7 @@ examples: reg-names = "qdsp6ss", "top_cc"; clocks = <&gcc GCC_CFG_NOC_LPASS_CLK>; clock-names = "iface"; + qcom,adsp-pil-mode; #clock-cells = <1>; }; ... diff --git a/Documentation/devicetree/bindings/clock/qcom,sm7150-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm7150-gcc.yaml new file mode 100644 index 000000000000..0eb76d9d51c4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm7150-gcc.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm7150-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on SM7150 + +maintainers: + - Bjorn Andersson + - Danila Tikhonov + - David Wronek + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on SM7150 + + See also:: include/dt-bindings/clock/qcom,sm7150-gcc.h + +properties: + compatible: + const: qcom,sm7150-gcc + + clocks: + items: + - description: Board XO source + - description: Board XO Active-Only source + - description: Sleep clock source + +required: + - compatible + - clocks + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,sm7150-gcc"; + reg = <0x00100000 0x001f0000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml index 6b6cec3fba52..3afdebdb52ad 100644 --- a/Documentation/devicetree/bindings/clock/renesas,9series.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,9series.yaml @@ -16,6 +16,11 @@ description: | - 9FGV0241: 0 -- DIF0 1 -- DIF1 + - 9FGV0441: + 0 -- DIF0 + 1 -- DIF1 + 2 -- DIF2 + 3 -- DIF3 maintainers: - Marek Vasut @@ -24,6 +29,7 @@ properties: compatible: enum: - renesas,9fgv0241 + - renesas,9fgv0441 reg: description: I2C device address diff --git a/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.yaml b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.yaml index 95bf485c6cec..99686085f751 100644 --- a/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas RZ/N1D (R9A06G032) System Controller maintainers: - - Gareth Williams + - Fabrizio Castro - Geert Uytterhoeven properties: diff --git a/Documentation/devicetree/bindings/clock/skyworks,si521xx.yaml b/Documentation/devicetree/bindings/clock/skyworks,si521xx.yaml new file mode 100644 index 000000000000..9e35e0e51ce8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/skyworks,si521xx.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/skyworks,si521xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Skyworks Si521xx I2C PCIe clock generators + +description: | + The Skyworks Si521xx are I2C PCIe clock generators providing + from 4 to 9 output clocks. + +maintainers: + - Marek Vasut + +properties: + compatible: + enum: + - skyworks,si52144 + - skyworks,si52146 + - skyworks,si52147 + + reg: + const: 0x6b + + '#clock-cells': + const: 1 + + clocks: + items: + - description: XTal input clock + + skyworks,out-amplitude-microvolt: + enum: [ 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000 ] + description: Output clock signal amplitude + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + clock-generator@6b { + compatible = "skyworks,si52144"; + reg = <0x6b>; + #clock-cells = <1>; + clocks = <&ref25m>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index e6c1ebfe8a32..130e16d025bc 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -82,6 +82,18 @@ properties: Indicates if the DSI controller is driving a panel which needs 2 DSI links. + qcom,master-dsi: + type: boolean + description: | + Indicates if the DSI controller is the master DSI controller when + qcom,dual-dsi-mode enabled. + + qcom,sync-dual-dsi: + type: boolean + description: | + Indicates if the DSI controller needs to sync the other DSI controller + with MIPI DCS commands when qcom,dual-dsi-mode enabled. + assigned-clocks: minItems: 2 maxItems: 4 diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml index 05163d124ec3..ab193bc8bdbb 100644 --- a/Documentation/devicetree/bindings/dma/apple,admac.yaml +++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml @@ -26,6 +26,7 @@ properties: - enum: - apple,t6000-admac - apple,t8103-admac + - apple,t8112-admac - const: apple,admac reg: diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml index fc5de7b6f19e..f61145c91b6d 100644 --- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml @@ -24,6 +24,7 @@ properties: - qcom,sm6350-gpi-dma - items: - enum: + - qcom,qcm2290-gpi-dma - qcom,qdu1000-gpi-dma - qcom,sc7280-gpi-dma - qcom,sm6115-gpi-dma diff --git a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml index f638d3934e71..c284abc6784a 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml @@ -54,6 +54,11 @@ properties: - description: DMA main clock - description: DMA register access clock + clock-names: + items: + - const: main + - const: register + '#dma-cells': const: 1 description: @@ -77,16 +82,23 @@ properties: - description: Reset for DMA ARESETN reset terminal - description: Reset for DMA RST_ASYNC reset terminal + reset-names: + items: + - const: arst + - const: rst_async + required: - compatible - reg - interrupts - interrupt-names - clocks + - clock-names - '#dma-cells' - dma-channels - power-domains - resets + - reset-names additionalProperties: false @@ -124,9 +136,11 @@ examples: "ch12", "ch13", "ch14", "ch15"; clocks = <&cpg CPG_MOD R9A07G044_DMAC_ACLK>, <&cpg CPG_MOD R9A07G044_DMAC_PCLK>; + clock-names = "main", "register"; power-domains = <&cpg>; resets = <&cpg R9A07G044_DMAC_ARESETN>, <&cpg R9A07G044_DMAC_RST_ASYNC>; + reset-names = "arst", "rst_async"; #dma-cells = <1>; dma-channels = <16>; }; diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml index 5c81194e2300..363cf8bd150d 100644 --- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml @@ -20,6 +20,7 @@ properties: enum: - snps,axi-dma-1.01a - intel,kmb-axi-dma + - starfive,jh7110-axi-dma reg: minItems: 1 @@ -58,7 +59,8 @@ properties: maximum: 8 resets: - maxItems: 1 + minItems: 1 + maxItems: 2 snps,dma-masters: description: | @@ -109,6 +111,25 @@ required: - snps,priority - snps,block-size +if: + properties: + compatible: + contains: + enum: + - starfive,jh7110-axi-dma +then: + properties: + resets: + minItems: 2 + items: + - description: AXI reset line + - description: AHB reset line + - description: module reset +else: + properties: + resets: + maxItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml index 97f6ae9b1236..22f6c5e2f7f4 100644 --- a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml +++ b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml @@ -43,7 +43,7 @@ description: | configuration of the legacy peripheral. allOf: - - $ref: "../dma-controller.yaml#" + - $ref: ../dma-controller.yaml# - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# properties: diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml index c0a1408b12ec..23ada8f87526 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml +++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml @@ -15,7 +15,7 @@ maintainers: - Michael Tretter allOf: - - $ref: "../dma-controller.yaml#" + - $ref: ../dma-controller.yaml# properties: "#dma-cells": diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml index 825294e3f0e8..d6cbd95ec26d 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml +++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml @@ -16,7 +16,7 @@ maintainers: - Laurent Pinchart allOf: - - $ref: "../dma-controller.yaml#" + - $ref: ../dma-controller.yaml# properties: "#dma-cells": diff --git a/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml b/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml index 4fb05eb84e2a..164331eb6275 100644 --- a/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml +++ b/Documentation/devicetree/bindings/fpga/lattice,sysconfig.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Lattice Slave SPI sysCONFIG FPGA manager maintainers: - - Ivan Bornyakov + - Vladimir Georgiev description: | Lattice sysCONFIG port, which is used for FPGA configuration, among others, diff --git a/Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml b/Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml index 527532f039ce..a157eecfb5fc 100644 --- a/Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml +++ b/Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip Polarfire FPGA manager. maintainers: - - Ivan Bornyakov + - Vladimir Georgiev description: Device Tree Bindings for Microchip Polarfire FPGA Manager using slave SPI to diff --git a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml index f0ff66c4c74e..3718103e966a 100644 --- a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml +++ b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml @@ -39,6 +39,10 @@ properties: reg: maxItems: 1 + gpio-line-names: + minItems: 1 + maxItems: 16 + gpio-controller: true '#gpio-cells': diff --git a/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.txt b/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.txt deleted file mode 100644 index 1b87b741fa8e..000000000000 --- a/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.txt +++ /dev/null @@ -1,35 +0,0 @@ -Broadcom Kona Family I2C -========================= - -This I2C controller is used in the following Broadcom SoCs: - - BCM11130 - BCM11140 - BCM11351 - BCM28145 - BCM28155 - -Required Properties -------------------- -- compatible: "brcm,bcm11351-i2c", "brcm,kona-i2c" -- reg: Physical base address and length of controller registers -- interrupts: The interrupt number used by the controller -- clocks: clock specifier for the kona i2c external clock -- clock-frequency: The I2C bus frequency in Hz -- #address-cells: Should be <1> -- #size-cells: Should be <0> - -Refer to clocks/clock-bindings.txt for generic clock consumer -properties. - -Example: - -i2c@3e016000 { - compatible = "brcm,bcm11351-i2c","brcm,kona-i2c"; - reg = <0x3e016000 0x80>; - interrupts = ; - clocks = <&bsc1_clk>; - clock-frequency = <400000>; - #address-cells = <1>; - #size-cells = <0>; -}; diff --git a/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.yaml b/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.yaml new file mode 100644 index 000000000000..7a694af90fc6 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/brcm,kona-i2c.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/brcm,kona-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Kona family I2C controller + +maintainers: + - Florian Fainelli + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + items: + - enum: + - brcm,bcm11351-i2c + - brcm,bcm21664-i2c + - brcm,bcm23550-i2c + - const: brcm,kona-i2c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-frequency: + enum: [ 100000, 400000, 1000000, 3400000 ] + +required: + - compatible + - reg + - interrupts + - clocks + - clock-frequency + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c@3e016000 { + compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c"; + reg = <0x3e016000 0x80>; + interrupts = ; + clocks = <&bsc1_clk>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml b/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml index 92e899905ef8..5d1e7885b64a 100644 --- a/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml +++ b/Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas RZ/V2M I2C Bus Interface maintainers: - - Phil Edworthy + - Fabrizio Castro allOf: - $ref: /schemas/i2c/i2c-controller.yaml# diff --git a/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml new file mode 100644 index 000000000000..fcc3dbff9c9a --- /dev/null +++ b/Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i3c/aspeed,ast2600-i3c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED AST2600 i3c controller + +maintainers: + - Jeremy Kerr + +allOf: + - $ref: i3c.yaml# + +properties: + compatible: + const: aspeed,ast2600-i3c + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + + sda-pullup-ohms: + enum: [545, 750, 2000] + default: 2000 + description: | + Value to configure SDA pullup resistor, in Ohms. + + aspeed,global-regs: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to i3c global register syscon node + - description: index of this i3c controller in the global register set + description: | + A (phandle, controller index) reference to the i3c global register set + used for this device. + +required: + - compatible + - reg + - clocks + - interrupts + - aspeed,global-regs + +unevaluatedProperties: false + +examples: + - | + #include + + i3c-master@2000 { + compatible = "aspeed,ast2600-i3c"; + reg = <0x2000 0x1000>; + #address-cells = <3>; + #size-cells = <0>; + clocks = <&syscon 0>; + resets = <&syscon 0>; + aspeed,global-regs = <&i3c_global 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i3c1_default>; + interrupts = ; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml b/Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml index 63369ba388e4..0a192ca192c5 100644 --- a/Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml @@ -39,6 +39,12 @@ properties: power-domains: maxItems: 1 + vref-supply: + description: | + External ADC reference voltage supply on VREFH pad. If VERID[MVI] is + set, there are additional, internal reference voltages selectable. + VREFH1 is always from VREFH pad. + "#io-channel-cells": const: 1 @@ -72,6 +78,7 @@ examples: assigned-clocks = <&clk IMX_SC_R_ADC_0>; assigned-clock-rates = <24000000>; power-domains = <&pd IMX_SC_R_ADC_0>; + vref-supply = <®_1v8>; #io-channel-cells = <1>; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml b/Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml index c115e2e99bd9..36dff3250ea7 100644 --- a/Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml @@ -34,9 +34,11 @@ properties: clock-names: const: fck - power-domains: true + power-domains: + maxItems: 1 - resets: true + resets: + maxItems: 1 "#address-cells": const: 1 @@ -51,6 +53,8 @@ required: - reg - clocks - clock-names + - power-domains + - resets - "#address-cells" - "#size-cells" @@ -86,7 +90,7 @@ patternProperties: of the MAX chips to the GyroADC, while MISO line of each Maxim ADC connects to a shared input pin of the GyroADC. enum: - - adi,7476 + - adi,ad7476 - fujitsu,mb88101a - maxim,max1162 - maxim,max11100 @@ -108,36 +112,30 @@ patternProperties: examples: - | - #include + #include #include - soc { - #address-cells = <2>; - #size-cells = <2>; - adc@e6e54000 { - compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc"; - reg = <0 0xe6e54000 0 64>; - clocks = <&mstp9_clks R8A7791_CLK_GYROADC>; - clock-names = "fck"; - power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + adc@e6e54000 { + compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc"; + reg = <0xe6e54000 64>; + clocks = <&cpg CPG_MOD 901>; + clock-names = "fck"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + resets = <&cpg 901>; - pinctrl-0 = <&adc_pins>; - pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; - #address-cells = <1>; - #size-cells = <0>; + adc@0 { + reg = <0>; + compatible = "maxim,max1162"; + vref-supply = <&vref_max1162>; + }; - adc@0 { - reg = <0>; - compatible = "maxim,max1162"; - vref-supply = <&vref_max1162>; - }; - - adc@1 { - reg = <1>; - compatible = "maxim,max1162"; - vref-supply = <&vref_max1162>; - }; + adc@1 { + reg = <1>; + compatible = "maxim,max1162"; + vref-supply = <&vref_max1162>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml new file mode 100644 index 000000000000..970ccab15e1e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads1100.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI ADS1100/ADS1000 single channel I2C analog to digital converter + +maintainers: + - Mike Looijmans + +description: | + Datasheet at: https://www.ti.com/lit/gpn/ads1100 + +properties: + compatible: + enum: + - ti,ads1100 + - ti,ads1000 + + reg: + maxItems: 1 + + vdd-supply: true + + "#io-channel-cells": + const: 0 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@49 { + compatible = "ti,ads1100"; + reg = <0x49>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml index 9eb3ecc8bbc8..590ea7936ad7 100644 --- a/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml +++ b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml @@ -101,6 +101,15 @@ patternProperties: When not configured as a comparator, the GPO will be treated as an output-only GPIO. + drive-strength-microamp: + description: | + For channels configured as digital input, this configures the sink + current. + minimum: 0 + maximum: 1800 + default: 0 + multipleOf: 120 + required: - reg diff --git a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml index decf022335d8..b39f5217d8ff 100644 --- a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml +++ b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml @@ -46,6 +46,9 @@ properties: - items: - const: st,ism330is - const: st,lsm6dso16is + - items: + - const: st,asm330lhb + - const: st,asm330lhh reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml b/Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml new file mode 100644 index 000000000000..30a109a1bf3b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/rohm,bu27034.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BU27034 ambient light sensor + +maintainers: + - Matti Vaittinen + +description: | + ROHM BU27034 is an ambient light sesnor with 3 channels and 3 photo diodes + capable of detecting a very wide range of illuminance. Typical application + is adjusting LCD and backlight power of TVs and mobile phones. + https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf + +properties: + compatible: + const: rohm,bu27034 + + reg: + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + light-sensor@38 { + compatible = "rohm,bu27034"; + reg = <0x38>; + vdd-supply = <&vdd>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml index 63885af6a74b..6fda887ee9d4 100644 --- a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml @@ -17,6 +17,7 @@ description: | https://www.bosch-sensortec.com/bst/products/all_products/bmp280 https://www.bosch-sensortec.com/bst/products/all_products/bme280 https://www.bosch-sensortec.com/bst/products/all_products/bmp380 + https://www.bosch-sensortec.com/bst/products/all_products/bmp580 properties: compatible: @@ -26,6 +27,7 @@ properties: - bosch,bmp280 - bosch,bme280 - bosch,bmp380 + - bosch,bmp580 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index c6201976378f..1ff3afca9149 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -11,9 +11,6 @@ description: The STMicroelectronics sensor devices are pretty straight-forward what type of sensor it is. Note that whilst this covers many STMicro MEMs sensors, some more complex IMUs need their own bindings. - The STMicroelectronics sensor devices are pretty straight-forward I2C or - SPI devices, all sharing the same device tree descriptions no matter what - type of sensor it is. maintainers: - Denis Ciocca @@ -48,6 +45,9 @@ properties: - st,lsm330d-accel - st,lsm330dl-accel - st,lsm330dlc-accel + - items: + - const: st,iis328dq + - const: st,h3lis331dl-accel - description: Silan Accelerometers enum: - silan,sc7a20 diff --git a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml index f44fc32ce87e..dbb85135fd66 100644 --- a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml @@ -18,6 +18,28 @@ description: | https://www.analog.com/media/en/technical-documentation/data-sheets/29861fa.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ltm2985.pdf +$defs: + sensor-node: + type: object + description: Sensor node common constraints + + properties: + reg: + description: + Channel number. Connects the sensor to the channel with this number + of the device. + minimum: 1 + maximum: 20 + + adi,sensor-type: + description: Type of sensor connected to the device. + $ref: /schemas/types.yaml#/definitions/uint32 + + required: + - reg + - adi,sensor-type + + properties: compatible: oneOf: @@ -64,28 +86,10 @@ properties: const: 0 patternProperties: - "@([0-9a-f]+)$": - type: object - description: Sensor. - - properties: - reg: - description: - Channel number. Connects the sensor to the channel with this number - of the device. - minimum: 1 - maximum: 20 - - adi,sensor-type: - description: Type of sensor connected to the device. - $ref: /schemas/types.yaml#/definitions/uint32 - - required: - - reg - - adi,sensor-type - "^thermocouple@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false + description: Thermocouple sensor. properties: @@ -123,7 +127,7 @@ patternProperties: description: Used for digitizing custom thermocouples. See Page 59 of the datasheet. - $ref: /schemas/types.yaml#/definitions/uint64-matrix + $ref: /schemas/types.yaml#/definitions/int64-matrix minItems: 3 maxItems: 64 items: @@ -141,7 +145,9 @@ patternProperties: - adi,custom-thermocouple "^diode@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false + description: Diode sensor. properties: @@ -184,7 +190,8 @@ patternProperties: default: 0 "^rtd@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false description: RTD sensor. properties: @@ -282,7 +289,8 @@ patternProperties: - adi,custom-rtd "^thermistor@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false description: Thermistor sensor. properties: @@ -383,7 +391,8 @@ patternProperties: - adi,custom-thermistor "^adc@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false description: Direct ADC sensor. properties: @@ -397,7 +406,8 @@ patternProperties: type: boolean "^temp@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false description: Active analog temperature sensor. properties: @@ -426,7 +436,8 @@ patternProperties: - adi,custom-temp "^rsense@": - type: object + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false description: Sense resistor sensor. properties: diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml index c4f1c69f9330..8c6d7735e875 100644 --- a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml @@ -7,9 +7,10 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: TI TMP117 - Digital temperature sensor with integrated NV memory description: | - TI TMP117 - Digital temperature sensor with integrated NV memory that supports - I2C interface. - https://www.ti.com/lit/gpn/tmp1 + TI TMP116/117 - Digital temperature sensor with integrated NV memory that + supports I2C interface. + https://www.ti.com/lit/gpn/tmp116 + https://www.ti.com/lit/gpn/tmp117 maintainers: - Puranjay Mohan @@ -17,6 +18,7 @@ maintainers: properties: compatible: enum: + - ti,tmp116 - ti,tmp117 reg: diff --git a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml index 3486c81699a8..fefaaf46a240 100644 --- a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml +++ b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml @@ -45,7 +45,7 @@ properties: when the keyboard has a custom design for the top row keys. dependencies: - function-row-phsymap: [ 'linux,keymap' ] + function-row-physmap: [ 'linux,keymap' ] google,needs-ghost-filter: [ 'linux,keymap' ] required: diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt deleted file mode 100644 index 8fc0e48c20db..000000000000 --- a/Documentation/devicetree/bindings/input/pwm-beeper.txt +++ /dev/null @@ -1,24 +0,0 @@ -* PWM beeper device tree bindings - -Registers a PWM device as beeper. - -Required properties: -- compatible: should be "pwm-beeper" -- pwms: phandle to the physical PWM device - -Optional properties: -- amp-supply: phandle to a regulator that acts as an amplifier for the beeper -- beeper-hz: bell frequency in Hz - -Example: - -beeper_amp: amplifier { - compatible = "fixed-regulator"; - gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; -}; - -beeper { - compatible = "pwm-beeper"; - pwms = <&pwm0>; - amp-supply = <&beeper_amp>; -}; diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.yaml b/Documentation/devicetree/bindings/input/pwm-beeper.yaml new file mode 100644 index 000000000000..a7611c206989 --- /dev/null +++ b/Documentation/devicetree/bindings/input/pwm-beeper.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/pwm-beeper.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PWM beeper + +maintainers: + - Sascha Hauer + +properties: + compatible: + const: pwm-beeper + + pwms: + maxItems: 1 + + amp-supply: + description: an amplifier for the beeper + + beeper-hz: + description: bell frequency in Hz + minimum: 10 + maximum: 10000 + +required: + - compatible + - pwms + +unevaluatedProperties: false + +examples: + - | + #include + beeper { + compatible = "pwm-beeper"; + pwms = <&pwm0>; + amp-supply = <&beeper_amp>; + beeper-hz = <1000>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml index 12a0d3ecbabb..5d17bdcfdf70 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml @@ -22,14 +22,14 @@ description: | properties: compatible: oneOf: + - const: qcom,msm8998-bwmon # BWMON v4 - items: - enum: - qcom,sc7280-cpu-bwmon - qcom,sc8280xp-cpu-bwmon - - qcom,sdm845-bwmon + - qcom,sdm845-cpu-bwmon - qcom,sm8550-cpu-bwmon - - const: qcom,msm8998-bwmon - - const: qcom,msm8998-bwmon # BWMON v4 + - const: qcom,sdm845-bwmon # BWMON v4, unified register space - items: - enum: - qcom,sc8280xp-llcc-bwmon @@ -49,9 +49,13 @@ properties: type: object reg: - # BWMON v4 (currently described) and BWMON v5 use one register address - # space. BWMON v2 uses two register spaces - not yet described. - maxItems: 1 + # BWMON v5 uses one register address space, v1-v4 use one or two. + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + maxItems: 2 required: - compatible @@ -63,13 +67,36 @@ required: additionalProperties: false +allOf: + - if: + properties: + compatible: + const: qcom,msm8998-bwmon + then: + properties: + reg: + minItems: 2 + + reg-names: + items: + - const: monitor + - const: global + + else: + properties: + reg: + maxItems: 1 + + reg-names: + maxItems: 1 + examples: - | #include #include pmu@1436400 { - compatible = "qcom,sdm845-bwmon", "qcom,msm8998-bwmon"; + compatible = "qcom,sdm845-cpu-bwmon", "qcom,sdm845-bwmon"; reg = <0x01436400 0x600>; interrupts = ; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_LLCC 3>; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml index 576992a6dc5a..9d0a98d77ae9 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml @@ -29,6 +29,7 @@ properties: - enum: - qcom,sc7280-epss-l3 - qcom,sc8280xp-epss-l3 + - qcom,sm6375-cpucp-l3 - qcom,sm8250-epss-l3 - qcom,sm8350-epss-l3 - const: qcom,epss-l3 diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index 92117261e1e1..39e64c7f6360 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -166,6 +166,12 @@ properties: resets: maxItems: 1 + mediatek,broken-save-restore-fw: + type: boolean + description: + Asserts that the firmware on this device has issues saving and restoring + GICR registers when the GIC redistributors are powered off. + dependencies: mbi-ranges: [ msi-controller ] msi-controller: [ mbi-ranges ] diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 807cb511fe18..ba677d401e24 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -53,6 +53,7 @@ properties: - qcom,sm8250-smmu-500 - qcom,sm8350-smmu-500 - qcom,sm8450-smmu-500 + - qcom,sm8550-smmu-500 - const: qcom,smmu-500 - const: arm,mmu-500 @@ -75,9 +76,22 @@ properties: - qcom,sm8350-smmu-500 - qcom,sm8450-smmu-500 - const: arm,mmu-500 - - - description: Qcom Adreno GPUs implementing "arm,smmu-500" + - description: Qcom Adreno GPUs implementing "qcom,smmu-500" and "arm,mmu-500" items: + - enum: + - qcom,sc7280-smmu-500 + - qcom,sm6115-smmu-500 + - qcom,sm6125-smmu-500 + - qcom,sm8150-smmu-500 + - qcom,sm8250-smmu-500 + - qcom,sm8350-smmu-500 + - const: qcom,adreno-smmu + - const: qcom,smmu-500 + - const: arm,mmu-500 + - description: Qcom Adreno GPUs implementing "arm,mmu-500" (legacy binding) + deprecated: true + items: + # Do not add additional SoC to this list. Instead use previous list. - enum: - qcom,sc7280-smmu-500 - qcom,sm8150-smmu-500 @@ -364,6 +378,30 @@ allOf: - description: interface clock required to access smmu's registers through the TCU's programming interface. + - if: + properties: + compatible: + items: + - enum: + - qcom,sm6115-smmu-500 + - qcom,sm6125-smmu-500 + - const: qcom,adreno-smmu + - const: qcom,smmu-500 + - const: arm,mmu-500 + then: + properties: + clock-names: + items: + - const: mem + - const: hlos + - const: iface + + clocks: + items: + - description: GPU memory bus clock + - description: Voter clock required for HLOS SMMU access + - description: Interface clock required for register access + # Disallow clocks for all other platforms with specific compatibles - if: properties: @@ -383,12 +421,11 @@ allOf: - qcom,sdm845-smmu-500 - qcom,sdx55-smmu-500 - qcom,sdx65-smmu-500 - - qcom,sm6115-smmu-500 - - qcom,sm6125-smmu-500 - qcom,sm6350-smmu-500 - qcom,sm6375-smmu-500 - qcom,sm8350-smmu-500 - qcom,sm8450-smmu-500 + - qcom,sm8550-smmu-500 then: properties: clock-names: false diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml index 72308a4c14e7..be90f68c11d1 100644 --- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml +++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml @@ -74,16 +74,16 @@ properties: renesas,ipmmu-main: $ref: /schemas/types.yaml#/definitions/phandle-array items: - - items: + - minItems: 1 + items: - description: phandle to main IPMMU - - description: the interrupt bit number associated with the particular - cache IPMMU device. The interrupt bit number needs to match the main - IPMMU IMSSTR register. Only used by cache IPMMU instances. + - description: + The interrupt bit number associated with the particular cache + IPMMU device. If present, the interrupt bit number needs to match + the main IPMMU IMSSTR register. Only used by cache IPMMU + instances. description: - Reference to the main IPMMU phandle plus 1 cell. The cell is - the interrupt bit number associated with the particular cache IPMMU - device. The interrupt bit number needs to match the main IPMMU IMSSTR - register. Only used by cache IPMMU instances. + Reference to the main IPMMU. required: - compatible @@ -109,6 +109,22 @@ allOf: required: - power-domains + - if: + properties: + compatible: + contains: + const: renesas,rcar-gen4-ipmmu-vmsa + then: + properties: + renesas,ipmmu-main: + items: + - maxItems: 1 + else: + properties: + renesas,ipmmu-main: + items: + - minItems: 2 + examples: - | #include diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 15e3f6645682..11aedf1650a1 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -90,22 +90,51 @@ properties: - heartbeat # LED indicates disk activity - disk-activity + # LED indicates disk read activity - disk-read + # LED indicates disk write activity - disk-write # LED flashes at a fixed, configurable rate - timer # LED alters the brightness for the specified duration with one software # timer (requires "led-pattern" property) - pattern + # LED indicates mic mute state + - audio-micmute + # LED indicates audio mute state + - audio-mute + # LED indicates bluetooth power state + - bluetooth-power + # LED indicates activity of all CPUs + - cpu + # LED indicates camera flash state + - flash + # LED indicated keyboard capslock + - kbd-capslock + # LED indicates MTD memory activity + - mtd + # LED indicates NAND memory activity (deprecated), + # in new implementations use "mtd" + - nand-disk + # No trigger assigned to the LED. This is the default mode + # if trigger is absent + - none + # LED indicates camera torch state + - torch + # LED indicates USB gadget activity - usb-gadget + # LED indicates USB host activity - usb-host + # LED indicates USB port state + - usbport + # LED is triggered by CPU activity - pattern: "^cpu[0-9]*$" - - pattern: "^hci[0-9]+-power$" # LED is triggered by Bluetooth activity - - pattern: "^mmc[0-9]+$" + - pattern: "^hci[0-9]+-power$" # LED is triggered by SD/MMC activity - - pattern: "^phy[0-9]+tx$" + - pattern: "^mmc[0-9]+$" # LED is triggered by WLAN activity + - pattern: "^phy[0-9]+tx$" led-pattern: description: | diff --git a/Documentation/devicetree/bindings/leds/leds-pca9532.txt b/Documentation/devicetree/bindings/leds/leds-pca9532.txt deleted file mode 100644 index f769c52e3643..000000000000 --- a/Documentation/devicetree/bindings/leds/leds-pca9532.txt +++ /dev/null @@ -1,49 +0,0 @@ -*NXP - pca9532 PWM LED Driver - -The PCA9532 family is SMBus I/O expander optimized for dimming LEDs. -The PWM support 256 steps. - -Required properties: - - compatible: - "nxp,pca9530" - "nxp,pca9531" - "nxp,pca9532" - "nxp,pca9533" - - reg - I2C slave address - -Each led is represented as a sub-node of the nxp,pca9530. - -Optional sub-node properties: - - label: see Documentation/devicetree/bindings/leds/common.txt - - type: Output configuration, see dt-bindings/leds/leds-pca9532.h (default NONE) - - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt - - default-state: see Documentation/devicetree/bindings/leds/common.txt - This property is only valid for sub-nodes of type . - -Example: - #include - - leds: pca9530@60 { - compatible = "nxp,pca9530"; - reg = <0x60>; - - red-power { - label = "pca:red:power"; - type = ; - }; - green-power { - label = "pca:green:power"; - type = ; - }; - kernel-booting { - type = ; - default-state = "on"; - }; - sys-stat { - type = ; - default-state = "keep"; // don't touch, was set by U-Boot - }; - }; - -For more product information please see the link below: -http://nxp.com/documents/data_sheet/PCA9532.pdf diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml index 1df837798249..6295c91f43e8 100644 --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -27,6 +27,7 @@ properties: - qcom,pmc8180c-lpg - qcom,pmi8994-lpg - qcom,pmi8998-lpg + - qcom,pmk8550-pwm "#pwm-cells": const: 2 diff --git a/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml new file mode 100644 index 000000000000..edf6f55df685 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/nxp,pca953x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA9532 LED Dimmer + +maintainers: + - Riku Voipio + +description: | + The PCA9532 family is SMBus I/O expander optimized for dimming LEDs. + The PWM support 256 steps. + + For more product information please see the link below: + https://www.nxp.com/docs/en/data-sheet/PCA9532.pdf + +properties: + compatible: + enum: + - nxp,pca9530 + - nxp,pca9531 + - nxp,pca9532 + - nxp,pca9533 + + reg: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + +patternProperties: + "^led-[0-9a-z]+$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + type: + description: | + Output configuration, see include/dt-bindings/leds/leds-pca9532.h + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + minimum: 0 + maximum: 4 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@62 { + compatible = "nxp,pca9533"; + reg = <0x62>; + + led-1 { + label = "pca:red:power"; + type = ; + }; + + led-2 { + label = "pca:green:power"; + type = ; + }; + + led-3 { + type = ; + default-state = "on"; + }; + + led-4 { + type = ; + default-state = "keep"; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml new file mode 100644 index 000000000000..ffacf703d9f9 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/qcom,spmi-flash-led.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Flash LED device inside Qualcomm Technologies, Inc. PMICs + +maintainers: + - Fenglin Wu + +description: | + Flash LED controller is present inside some Qualcomm Technologies, Inc. PMICs. + The flash LED module can have different number of LED channels supported + e.g. 3 or 4. There are some different registers between them but they can + both support maximum current up to 1.5 A per channel and they can also support + ganging 2 channels together to supply maximum current up to 2 A. The current + will be split symmetrically on each channel and they will be enabled and + disabled at the same time. + +properties: + compatible: + items: + - enum: + - qcom,pm6150l-flash-led + - qcom,pm8150c-flash-led + - qcom,pm8150l-flash-led + - qcom,pm8350c-flash-led + - const: qcom,spmi-flash-led + + reg: + maxItems: 1 + +patternProperties: + "^led-[0-3]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + description: + Represents the physical LED components which are connected to the + flash LED channels' output. + + properties: + led-sources: + description: + The HW indices of the flash LED channels that connect to the + physical LED + allOf: + - minItems: 1 + maxItems: 2 + items: + enum: [1, 2, 3, 4] + + led-max-microamp: + anyOf: + - minimum: 5000 + maximum: 500000 + multipleOf: 5000 + - minimum: 10000 + maximum: 1000000 + multipleOf: 10000 + + flash-max-microamp: + anyOf: + - minimum: 12500 + maximum: 1500000 + multipleOf: 12500 + - minimum: 25000 + maximum: 2000000 + multipleOf: 25000 + + flash-max-timeout-us: + minimum: 10000 + maximum: 1280000 + multipleOf: 10000 + + required: + - led-sources + - led-max-microamp + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + spmi { + #address-cells = <1>; + #size-cells = <0>; + led-controller@ee00 { + compatible = "qcom,pm8350c-flash-led", "qcom,spmi-flash-led"; + reg = <0xee00>; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>, <4>; + led-max-microamp = <300000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <0>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>, <3>; + led-max-microamp = <300000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml new file mode 100644 index 000000000000..14700a2e5fea --- /dev/null +++ b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/rohm,bd2606mvv.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD2606MVV LED controller + +maintainers: + - Andreas Kemnade + +description: + The BD2606 MVV is a programmable LED controller connected via I2C that can + drive 6 separate lines. Each of them can be individually switched on and off, + but the brightness setting is shared between pairs of them. + + Datasheet is available at + https://fscdn.rohm.com/en/products/databook/datasheet/ic/power/led_driver/bd2606mvv_1-e.pdf + +properties: + compatible: + const: rohm,bd2606mvv + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + enable-gpios: + maxItems: 1 + description: GPIO pin to enable/disable the device. + +patternProperties: + "^led@[0-6]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 6 + + required: + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@66 { + compatible = "rohm,bd2606mvv"; + reg = <0x66>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0x0>; + color = ; + function = LED_FUNCTION_POWER; + }; + + led@2 { + reg = <0x2>; + color = ; + function = LED_FUNCTION_STATUS; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml index d383b2ab3ce8..cef9d7601398 100644 --- a/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/mediatek,gce-mailbox.yaml @@ -16,14 +16,18 @@ description: properties: compatible: - enum: - - mediatek,mt6779-gce - - mediatek,mt8173-gce - - mediatek,mt8183-gce - - mediatek,mt8186-gce - - mediatek,mt8188-gce - - mediatek,mt8192-gce - - mediatek,mt8195-gce + oneOf: + - enum: + - mediatek,mt6779-gce + - mediatek,mt8173-gce + - mediatek,mt8183-gce + - mediatek,mt8186-gce + - mediatek,mt8188-gce + - mediatek,mt8192-gce + - mediatek,mt8195-gce + - items: + - const: mediatek,mt6795-gce + - const: mediatek,mt8173-gce "#mbox-cells": const: 2 diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml index 7f18fb10435d..32d7bbc98cac 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -19,22 +19,15 @@ properties: - items: - enum: - qcom,ipq5332-apcs-apps-global + - qcom,ipq8074-apcs-apps-global + - qcom,ipq9574-apcs-apps-global - const: qcom,ipq6018-apcs-apps-global - items: - enum: - - qcom,ipq6018-apcs-apps-global - - qcom,ipq8074-apcs-apps-global - - qcom,msm8996-apcs-hmss-global - - qcom,msm8998-apcs-hmss-global - - qcom,qcm2290-apcs-hmss-global - qcom,sc7180-apss-shared - qcom,sc8180x-apss-shared - - qcom,sdm660-apcs-hmss-global - - qcom,sdm845-apss-shared - - qcom,sm4250-apcs-hmss-global - - qcom,sm6125-apcs-hmss-global - - qcom,sm6115-apcs-hmss-global - qcom,sm8150-apss-shared + - const: qcom,sdm845-apss-shared - items: - enum: - qcom,msm8916-apcs-kpss-global @@ -45,6 +38,18 @@ properties: - qcom,qcs404-apcs-apps-global - qcom,sdx55-apcs-gcc - const: syscon + - enum: + - qcom,ipq6018-apcs-apps-global + - qcom,ipq8074-apcs-apps-global + - qcom,msm8996-apcs-hmss-global + - qcom,msm8998-apcs-hmss-global + - qcom,qcm2290-apcs-hmss-global + - qcom,sdm660-apcs-hmss-global + - qcom,sdm845-apss-shared + - qcom,sm4250-apcs-hmss-global + - qcom,sm6115-apcs-hmss-global + - qcom,sm6125-apcs-hmss-global + reg: maxItems: 1 @@ -88,30 +93,31 @@ allOf: items: - const: pll - const: aux + - if: properties: compatible: - enum: - - qcom,sdx55-apcs-gcc + contains: + enum: + - qcom,sdx55-apcs-gcc then: properties: clocks: items: + - description: reference clock - description: primary pll parent of the clock driver - description: auxiliary parent - - description: reference clock clock-names: items: + - const: ref - const: pll - const: aux - - const: ref - if: properties: compatible: contains: enum: - qcom,ipq6018-apcs-apps-global - - qcom,ipq8074-apcs-apps-global then: properties: clocks: @@ -133,14 +139,11 @@ allOf: - qcom,msm8996-apcs-hmss-global - qcom,msm8998-apcs-hmss-global - qcom,qcm2290-apcs-hmss-global - - qcom,sc7180-apss-shared - - qcom,sc8180x-apss-shared - qcom,sdm660-apcs-hmss-global - qcom,sdm845-apss-shared - qcom,sm4250-apcs-hmss-global - qcom,sm6115-apcs-hmss-global - qcom,sm6125-apcs-hmss-global - - qcom,sm8150-apss-shared then: properties: clocks: false @@ -152,7 +155,6 @@ allOf: contains: enum: - qcom,ipq6018-apcs-apps-global - - qcom,ipq8074-apcs-apps-global then: properties: '#clock-cells': diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml index 8b389314c352..e2ffe0a9c26b 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml @@ -49,6 +49,7 @@ properties: properties: data-lanes: + minItems: 1 maxItems: 2 required: diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml index 71595c013dbb..e5448c60e3eb 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegdec.yaml @@ -26,11 +26,6 @@ properties: Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. Ports are according to the HW. - dma-ranges: - maxItems: 1 - description: | - Describes the physical address space of IOMMU maps to memory. - "#address-cells": const: 2 @@ -89,7 +84,6 @@ required: - compatible - power-domains - iommus - - dma-ranges - ranges additionalProperties: false @@ -115,7 +109,6 @@ examples: <&iommu_vpp M4U_PORT_L19_JPGDEC_BSDMA1>, <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>, <&iommu_vpp M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>; - dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml index 95990539f7c0..596186497b68 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mt8195-jpegenc.yaml @@ -26,11 +26,6 @@ properties: Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. Ports are according to the HW. - dma-ranges: - maxItems: 1 - description: | - Describes the physical address space of IOMMU maps to memory. - "#address-cells": const: 2 @@ -89,7 +84,6 @@ required: - compatible - power-domains - iommus - - dma-ranges - ranges additionalProperties: false @@ -113,7 +107,6 @@ examples: <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>, <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>, <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>; - dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-decoder.yaml index aa55ca65d6ed..fad59b486d5d 100644 --- a/Documentation/devicetree/bindings/media/mediatek,vcodec-decoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-decoder.yaml @@ -56,11 +56,6 @@ properties: List of the hardware port in respective IOMMU block for current Socs. Refer to bindings/iommu/mediatek,iommu.yaml. - dma-ranges: - maxItems: 1 - description: | - Describes the physical address space of IOMMU maps to memory. - mediatek,vpu: $ref: /schemas/types.yaml#/definitions/phandle description: diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml index 0f2ea8d9a10c..a2051b31fa29 100644 --- a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml @@ -49,11 +49,6 @@ properties: List of the hardware port in respective IOMMU block for current Socs. Refer to bindings/iommu/mediatek,iommu.yaml. - dma-ranges: - maxItems: 1 - description: | - Describes the physical address space of IOMMU maps to memory. - mediatek,vpu: $ref: /schemas/types.yaml#/definitions/phandle description: diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml index c8412e8ab353..37800e1908cc 100644 --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml @@ -44,11 +44,6 @@ properties: Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. Ports are according to the HW. - dma-ranges: - maxItems: 1 - description: | - Describes the physical address space of IOMMU maps to memory. - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml b/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml index 6d3962a17e49..05dd6b3a1a3c 100644 --- a/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml @@ -8,7 +8,6 @@ title: Arm PL35x Series Static Memory Controller (SMC) maintainers: - Miquel Raynal - - Naga Sureshkumar Relli description: | The PL35x Static Memory Controller is a bus where you can connect two kinds diff --git a/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml index e2046f07a40e..8459d3642205 100644 --- a/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml +++ b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml @@ -36,7 +36,7 @@ properties: clock-controller: # Child node type: object - $ref: "../clock/canaan,k210-clk.yaml" + $ref: ../clock/canaan,k210-clk.yaml description: Clock controller for the SoC clocks. This child node definition should follow the bindings specified in @@ -45,7 +45,7 @@ properties: reset-controller: # Child node type: object - $ref: "../reset/canaan,k210-rst.yaml" + $ref: ../reset/canaan,k210-rst.yaml description: Reset controller for the SoC. This child node definition should follow the bindings specified in @@ -54,7 +54,7 @@ properties: syscon-reboot: # Child node type: object - $ref: "../power/reset/syscon-reboot.yaml" + $ref: ../power/reset/syscon-reboot.yaml description: Reboot method for the SoC. This child node definition should follow the bindings specified in diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index 8caa48f4570e..e1ca4f297c6d 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -65,7 +65,7 @@ properties: ARM Cortex M4 Co-processor. Contains the name of the rpmsg device. Used to match the subnode to the rpmsg device announced by the SCP. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string spi-max-frequency: true @@ -94,23 +94,23 @@ properties: const: 0 typec: - $ref: "/schemas/chrome/google,cros-ec-typec.yaml#" + $ref: /schemas/chrome/google,cros-ec-typec.yaml# ec-pwm: - $ref: "/schemas/pwm/google,cros-ec-pwm.yaml#" + $ref: /schemas/pwm/google,cros-ec-pwm.yaml# deprecated: true pwm: - $ref: "/schemas/pwm/google,cros-ec-pwm.yaml#" + $ref: /schemas/pwm/google,cros-ec-pwm.yaml# kbd-led-backlight: - $ref: "/schemas/chrome/google,cros-kbd-led-backlight.yaml#" + $ref: /schemas/chrome/google,cros-kbd-led-backlight.yaml# keyboard-controller: - $ref: "/schemas/input/google,cros-ec-keyb.yaml#" + $ref: /schemas/input/google,cros-ec-keyb.yaml# proximity: - $ref: "/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml#" + $ref: /schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml# codecs: type: object @@ -126,7 +126,7 @@ properties: patternProperties: "^ec-codec@[a-f0-9]+$": type: object - $ref: "/schemas/sound/google,cros-ec-codec.yaml#" + $ref: /schemas/sound/google,cros-ec-codec.yaml# required: - "#address-cells" @@ -151,15 +151,15 @@ properties: patternProperties: "^i2c-tunnel[0-9]*$": type: object - $ref: "/schemas/i2c/google,cros-ec-i2c-tunnel.yaml#" + $ref: /schemas/i2c/google,cros-ec-i2c-tunnel.yaml# "^regulator@[0-9]+$": type: object - $ref: "/schemas/regulator/google,cros-ec-regulator.yaml#" + $ref: /schemas/regulator/google,cros-ec-regulator.yaml# "^extcon[0-9]*$": type: object - $ref: "/schemas/extcon/extcon-usbc-cros-ec.yaml#" + $ref: /schemas/extcon/extcon-usbc-cros-ec.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml index 22edcb4b212f..bdff5b653453 100644 --- a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml @@ -53,7 +53,7 @@ properties: '^ldo[0-9]+$': type: object - $ref: "/schemas/regulator/regulator.yaml#" + $ref: /schemas/regulator/regulator.yaml# unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/mfd/maxim,max5970.yaml b/Documentation/devicetree/bindings/mfd/maxim,max5970.yaml new file mode 100644 index 000000000000..da67742c5aa9 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max5970.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max5970.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Regulator for MAX5970 Smart Switch from Maxim Integrated + +maintainers: + - Patrick Rudolph + +description: | + The smart switch provides no output regulation, but independent fault protection + and voltage and current sensing. + Programming is done through I2C bus. + + Datasheets: + https://datasheets.maximintegrated.com/en/ds/MAX5970.pdf + https://datasheets.maximintegrated.com/en/ds/MAX5978.pdf + +properties: + compatible: + enum: + - maxim,max5970 + - maxim,max5978 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + leds: + type: object + description: + Properties for four LEDS. + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-3]$": + $ref: /schemas/leds/common.yaml# + type: object + + additionalProperties: false + + vss1-supply: + description: Supply of the first channel. + + vss2-supply: + description: Supply of the second channel. + + regulators: + type: object + description: + Properties for both hot swap control/switch. + + patternProperties: + "^sw[0-1]$": + $ref: /schemas/regulator/regulator.yaml# + type: object + properties: + shunt-resistor-micro-ohms: + description: | + The value of current sense resistor in microohms. + + required: + - shunt-resistor-micro-ohms + + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - regulators + - vss1-supply + +allOf: + - if: + properties: + compatible: + enum: + - maxim,max5970 + then: + required: + - vss2-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + regulator@3a { + compatible = "maxim,max5978"; + reg = <0x3a>; + vss1-supply = <&p3v3>; + + regulators { + sw0_ref_0: sw0 { + shunt-resistor-micro-ohms = <12000>; + }; + }; + + leds { + #address-cells = <1>; + #size-cells = <0>; + led@0 { + reg = <0>; + label = "led0"; + default-state = "on"; + }; + led@1 { + reg = <1>; + label = "led1"; + default-state = "on"; + }; + }; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@3a { + compatible = "maxim,max5970"; + reg = <0x3a>; + vss1-supply = <&p3v3>; + vss2-supply = <&p5v>; + + regulators { + sw0_ref_1: sw0 { + shunt-resistor-micro-ohms = <12000>; + }; + sw1_ref_1: sw1 { + shunt-resistor-micro-ohms = <10000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index adf88245c409..36de335a33aa 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -33,6 +33,7 @@ properties: compatible: items: - enum: + - qcom,pm2250 - qcom,pm6125 - qcom,pm6150 - qcom,pm6150l @@ -78,6 +79,7 @@ properties: - qcom,pmk8350 - qcom,pmk8550 - qcom,pmm8155au + - qcom,pmm8654au - qcom,pmp8074 - qcom,pmr735a - qcom,pmr735b @@ -115,6 +117,7 @@ patternProperties: type: object oneOf: - $ref: /schemas/iio/adc/qcom,spmi-iadc.yaml# + - $ref: /schemas/iio/adc/qcom,spmi-rradc.yaml# - $ref: /schemas/iio/adc/qcom,spmi-vadc.yaml# "^adc-tm@[0-9a-f]+$": @@ -135,6 +138,14 @@ patternProperties: type: object $ref: /schemas/pinctrl/qcom,pmic-gpio.yaml# + "^led-controller@[0-9a-f]+$": + type: object + $ref: /schemas/leds/qcom,spmi-flash-led.yaml# + + "^nvram@[0-9a-f]+$": + type: object + $ref: /schemas/nvmem/qcom,spmi-sdam.yaml# + "pon@[0-9a-f]+$": type: object $ref: /schemas/power/reset/qcom,pon.yaml# @@ -276,12 +287,12 @@ examples: #size-cells = <0>; #io-channel-cells = <1>; - adc-chan@6 { + channel@6 { reg = ; label = "die_temp"; }; - adc-chan@4f { + channel@4f { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index 2eeebe920e6e..fe790af7b4fb 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -25,12 +25,16 @@ properties: - qcom,sc8280xp-tcsr - qcom,sdm630-tcsr - qcom,sdm845-tcsr + - qcom,sdx55-tcsr + - qcom,sdx65-tcsr - qcom,sm8150-tcsr + - qcom,sm8450-tcsr - qcom,tcsr-apq8064 - qcom,tcsr-apq8084 - qcom,tcsr-ipq5332 - qcom,tcsr-ipq6018 - qcom,tcsr-ipq8064 + - qcom,tcsr-ipq9574 - qcom,tcsr-mdm9615 - qcom,tcsr-msm8226 - qcom,tcsr-msm8660 diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml index 9acad9d326eb..9c51c1b19067 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml @@ -49,7 +49,7 @@ patternProperties: "rtc@[0-9a-f]+$": type: object - $ref: "../rtc/qcom-pm8xxx-rtc.yaml" + $ref: ../rtc/qcom-pm8xxx-rtc.yaml required: - compatible diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml index d6d120a78094..05747e012516 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml @@ -46,7 +46,7 @@ properties: rohm,clkout-open-drain: description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 1 diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml index ec3adcd3483d..11089aa89ec6 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml @@ -46,7 +46,7 @@ properties: rohm,clkout-open-drain: description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 1 diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index c828c4f5e4a7..8103154bbb52 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -56,6 +56,7 @@ properties: - microchip,lan966x-cpu-syscon - microchip,sparx5-cpu-syscon - mstar,msc313-pmsleep + - nuvoton,ma35d1-sys - nuvoton,wpcm450-shm - rockchip,px30-qos - rockchip,rk3036-qos @@ -67,6 +68,7 @@ properties: - rockchip,rk3568-qos - rockchip,rk3588-qos - rockchip,rv1126-qos + - starfive,jh7100-sysmain - const: syscon diff --git a/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml b/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml index 76ef4352e13c..0c98d913747b 100644 --- a/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml +++ b/Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml @@ -62,6 +62,12 @@ patternProperties: description: The phy node corresponding to the ethernet MAC. + "^chipid@[0-9a-f]+$": + type: object + $ref: /schemas/hwinfo/ti,k3-socinfo.yaml# + description: + The node corresponding to SoC chip identification. + required: - compatible - reg @@ -99,5 +105,10 @@ examples: reg = <0x4140 0x18>; #clock-cells = <1>; }; + + chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; ... diff --git a/Documentation/devicetree/bindings/mfd/ti,nspire-misc.yaml b/Documentation/devicetree/bindings/mfd/ti,nspire-misc.yaml new file mode 100644 index 000000000000..28cd5164d46f --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ti,nspire-misc.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/ti,nspire-misc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI Nspire MISC hardware block + +maintainers: + - Andrew Davis + +description: + System controller node represents a register region containing a set + of miscellaneous registers. The registers are not cohesive enough to + represent as any specific type of device. Currently there is a reset + controller. + +properties: + compatible: + items: + - enum: + - ti,nspire-misc + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + reboot: + $ref: /schemas/power/reset/syscon-reboot.yaml# + +required: + - compatible + - reg + - reboot + +additionalProperties: false + +examples: + - | + misc: misc@900a0000 { + compatible = "ti,nspire-misc", "syscon", "simple-mfd"; + reg = <0x900a0000 0x1000>; + + reboot { + compatible = "syscon-reboot"; + offset = <0x08>; + value = <0x02>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml b/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml index ea3337dafaf5..7902f3c5d289 100644 --- a/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml +++ b/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml @@ -156,7 +156,7 @@ properties: entry has a value that is out of range for a 16 bit register then the chip default will be used. If present exactly five values must be specified. - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 maxItems: 5 diff --git a/Documentation/devicetree/bindings/mfd/x-powers,ac100.yaml b/Documentation/devicetree/bindings/mfd/x-powers,ac100.yaml index 309606d2d806..f3d8394b27e7 100644 --- a/Documentation/devicetree/bindings/mfd/x-powers,ac100.yaml +++ b/Documentation/devicetree/bindings/mfd/x-powers,ac100.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/mfd/x-powers,ac100.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/mfd/x-powers,ac100.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: X-Powers AC100 diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml index 24d03996b93a..f7f0f2c0421a 100644 --- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml +++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml @@ -47,9 +47,8 @@ allOf: - x-powers,axp209 then: - not: - required: - - x-powers,drive-vbus-en + properties: + x-powers,drive-vbus-en: false - if: not: @@ -59,14 +58,9 @@ allOf: const: x-powers,axp806 then: - allOf: - - not: - required: - - x-powers,self-working-mode - - - not: - required: - - x-powers,master-mode + properties: + x-powers,self-working-mode: false + x-powers,master-mode: false - if: not: @@ -79,6 +73,18 @@ allOf: required: - interrupts + - if: + properties: + compatible: + contains: + enum: + - x-powers,axp313a + - x-powers,axp15060 + + then: + properties: + x-powers,dcdc-freq: false + properties: compatible: oneOf: @@ -88,10 +94,12 @@ properties: - x-powers,axp209 - x-powers,axp221 - x-powers,axp223 + - x-powers,axp313a - x-powers,axp803 - x-powers,axp806 - x-powers,axp809 - x-powers,axp813 + - x-powers,axp15060 - items: - const: x-powers,axp228 - const: x-powers,axp221 @@ -260,7 +268,7 @@ properties: Defines the work frequency of DC-DC in kHz. patternProperties: - "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|drivevbus|dc5ldo)$": + "^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|cpusldo|drivevbus|dc5ldo)$": $ref: /schemas/regulator/regulator.yaml# type: object unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml b/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml index 9efd49c39bd2..6e880a46d7ee 100644 --- a/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml +++ b/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Bootlin %YAML 1.2 --- -$id: "http://devicetree.org/schemas/mfd/xylon,logicvc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/mfd/xylon,logicvc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Xylon LogiCVC multi-function device diff --git a/Documentation/devicetree/bindings/mips/loongson/devices.yaml b/Documentation/devicetree/bindings/mips/loongson/devices.yaml index f13ce386f42c..099e40e1482d 100644 --- a/Documentation/devicetree/bindings/mips/loongson/devices.yaml +++ b/Documentation/devicetree/bindings/mips/loongson/devices.yaml @@ -37,6 +37,18 @@ properties: items: - const: loongson,loongson64v-4core-virtio + - description: LS1B based boards + items: + - enum: + - loongson,lsgz-1b-dev + - const: loongson,ls1b + + - description: LS1C based boards + items: + - enum: + - loongmasses,smartloong-1c + - const: loongson,ls1c + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml index 2fe53cbfbee0..15b63bbb82a2 100644 --- a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml @@ -10,7 +10,7 @@ allOf: - $ref: nand-controller.yaml maintainers: - - Naga Sureshkumar Relli + - Michal Simek properties: compatible: diff --git a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml index f8c0f606f451..7bd7c55a9c15 100644 --- a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml +++ b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml @@ -11,7 +11,6 @@ allOf: maintainers: - Miquel Raynal - - Naga Sureshkumar Relli properties: compatible: diff --git a/Documentation/devicetree/bindings/net/can/st,stm32-bxcan.yaml b/Documentation/devicetree/bindings/net/can/st,stm32-bxcan.yaml index 769fa5c27b76..de1d4298893b 100644 --- a/Documentation/devicetree/bindings/net/can/st,stm32-bxcan.yaml +++ b/Documentation/devicetree/bindings/net/can/st,stm32-bxcan.yaml @@ -21,11 +21,22 @@ properties: st,can-primary: description: - Primary and secondary mode of the bxCAN peripheral is only relevant - if the chip has two CAN peripherals. In that case they share some - of the required logic. + Primary mode of the bxCAN peripheral is only relevant if the chip has + two CAN peripherals in dual CAN configuration. In that case they share + some of the required logic. + Not to be used if the peripheral is in single CAN configuration. To avoid misunderstandings, it should be noted that ST documentation - uses the terms master/slave instead of primary/secondary. + uses the terms master instead of primary. + type: boolean + + st,can-secondary: + description: + Secondary mode of the bxCAN peripheral is only relevant if the chip + has two CAN peripherals in dual CAN configuration. In that case they + share some of the required logic. + Not to be used if the peripheral is in single CAN configuration. + To avoid misunderstandings, it should be noted that ST documentation + uses the terms slave instead of secondary. type: boolean reg: diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml index 14c170c6a86e..296001e7f498 100644 --- a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml @@ -11,7 +11,7 @@ maintainers: - Maxime Ripard allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml new file mode 100644 index 000000000000..e49c2754ff55 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/amlogic,meson-gxbb-efuse.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/amlogic,meson-gxbb-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson GX eFuse + +maintainers: + - Neil Armstrong + +allOf: + - $ref: nvmem.yaml# + +properties: + compatible: + oneOf: + - const: amlogic,meson-gxbb-efuse + - items: + - const: amlogic,meson-gx-efuse + - const: amlogic,meson-gxbb-efuse + + clocks: + maxItems: 1 + + secure-monitor: + description: phandle to the secure-monitor node + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - clocks + - secure-monitor + +unevaluatedProperties: false + +examples: + - | + efuse: efuse { + compatible = "amlogic,meson-gxbb-efuse"; + clocks = <&clk_efuse>; + #address-cells = <1>; + #size-cells = <1>; + secure-monitor = <&sm>; + + sn: sn@14 { + reg = <0x14 0x10>; + }; + + eth_mac: mac@34 { + reg = <0x34 0x10>; + }; + + bid: bid@46 { + reg = <0x46 0x30>; + }; + }; diff --git a/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml b/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml new file mode 100644 index 000000000000..84b3dfd21e09 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/amlogic,meson6-efuse.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/amlogic,meson6-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson6 eFuse + +maintainers: + - Neil Armstrong + - Martin Blumenstingl + +allOf: + - $ref: nvmem.yaml# + +properties: + compatible: + enum: + - amlogic,meson6-efuse + - amlogic,meson8-efuse + - amlogic,meson8b-efuse + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: core + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + efuse: efuse@0 { + compatible = "amlogic,meson6-efuse"; + reg = <0x0 0x2000>; + clocks = <&clk_efuse>; + clock-names = "core"; + #address-cells = <1>; + #size-cells = <1>; + + ethernet_mac_address: mac@1b4 { + reg = <0x1b4 0x6>; + }; + + temperature_calib: calib@1f4 { + reg = <0x1f4 0x4>; + }; + }; diff --git a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt b/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt deleted file mode 100644 index f7b3ed74db54..000000000000 --- a/Documentation/devicetree/bindings/nvmem/amlogic-efuse.txt +++ /dev/null @@ -1,48 +0,0 @@ -= Amlogic Meson GX eFuse device tree bindings = - -Required properties: -- compatible: should be "amlogic,meson-gxbb-efuse" -- clocks: phandle to the efuse peripheral clock provided by the - clock controller. -- secure-monitor: phandle to the secure-monitor node - -= Data cells = -Are child nodes of eFuse, bindings of which as described in -bindings/nvmem/nvmem.txt - -Example: - - efuse: efuse { - compatible = "amlogic,meson-gxbb-efuse"; - clocks = <&clkc CLKID_EFUSE>; - #address-cells = <1>; - #size-cells = <1>; - secure-monitor = <&sm>; - - sn: sn@14 { - reg = <0x14 0x10>; - }; - - eth_mac: eth_mac@34 { - reg = <0x34 0x10>; - }; - - bid: bid@46 { - reg = <0x46 0x30>; - }; - }; - - sm: secure-monitor { - compatible = "amlogic,meson-gxbb-sm"; - }; - -= Data consumers = -Are device nodes which consume nvmem data cells. - -For example: - - eth_mac { - ... - nvmem-cells = <ð_mac>; - nvmem-cell-names = "eth_mac"; - }; diff --git a/Documentation/devicetree/bindings/nvmem/amlogic-meson-mx-efuse.txt b/Documentation/devicetree/bindings/nvmem/amlogic-meson-mx-efuse.txt deleted file mode 100644 index a3c63954a1a4..000000000000 --- a/Documentation/devicetree/bindings/nvmem/amlogic-meson-mx-efuse.txt +++ /dev/null @@ -1,22 +0,0 @@ -Amlogic Meson6/Meson8/Meson8b efuse - -Required Properties: -- compatible: depending on the SoC this should be one of: - - "amlogic,meson6-efuse" - - "amlogic,meson8-efuse" - - "amlogic,meson8b-efuse" -- reg: base address and size of the efuse registers -- clocks: a reference to the efuse core gate clock -- clock-names: must be "core" - -All properties and sub-nodes as well as the consumer bindings -defined in nvmem.txt in this directory are also supported. - - -Example: - efuse: nvmem@0 { - compatible = "amlogic,meson8-efuse"; - reg = <0x0 0x2000>; - clocks = <&clkc CLKID_EFUSE>; - clock-names = "core"; - }; diff --git a/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml b/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml index 5ec8f2bdb3a5..e0860b6b85f3 100644 --- a/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml +++ b/Documentation/devicetree/bindings/nvmem/apple,efuses.yaml @@ -15,7 +15,7 @@ maintainers: - Sven Peter allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml index 25033de3ef6b..36def7128fca 100644 --- a/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml +++ b/Documentation/devicetree/bindings/nvmem/brcm,nvram.yaml @@ -20,7 +20,7 @@ maintainers: - Rafał Miłecki allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml b/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml index 3b4e6e94cb81..70fb2ad25103 100644 --- a/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml +++ b/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml @@ -14,7 +14,7 @@ description: | unique identifier per part. allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/imx-iim.yaml b/Documentation/devicetree/bindings/nvmem/imx-iim.yaml index 7aac1995cfaf..e9d9d8df4811 100644 --- a/Documentation/devicetree/bindings/nvmem/imx-iim.yaml +++ b/Documentation/devicetree/bindings/nvmem/imx-iim.yaml @@ -14,7 +14,7 @@ description: | i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 and i.MX53 SoCs. allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml index d0a239d7e199..9876243ff1e8 100644 --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml @@ -15,7 +15,7 @@ description: | i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN and i.MX8MP SoCs. allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/ingenic,jz4780-efuse.yaml b/Documentation/devicetree/bindings/nvmem/ingenic,jz4780-efuse.yaml index fe2cd7f1afba..e89fd879c968 100644 --- a/Documentation/devicetree/bindings/nvmem/ingenic,jz4780-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/ingenic,jz4780-efuse.yaml @@ -10,7 +10,7 @@ maintainers: - PrasannaKumar Muralidharan allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml b/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml index 5a0e7671aa3f..714a6538cc7c 100644 --- a/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml +++ b/Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml @@ -61,7 +61,7 @@ properties: type: object additionalProperties: false - platforn-name: + platform-name: type: object additionalProperties: false diff --git a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml index 75e0a516e59a..d16d42fb98b6 100644 --- a/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/mediatek,efuse.yaml @@ -15,7 +15,7 @@ maintainers: - Lala Lin allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: $nodename: diff --git a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml index c3c96fd0baac..a296d348adb4 100644 --- a/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml +++ b/Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml @@ -15,7 +15,7 @@ description: | settings, chip identifiers) or user specific data could be stored. allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml index ff317fd7c15b..8938eec22b52 100644 --- a/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/mxs-ocotp.yaml @@ -10,7 +10,7 @@ maintainers: - Anson Huang allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml b/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml index f93bc50c40d7..6c26800f8b79 100644 --- a/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml +++ b/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml @@ -17,7 +17,7 @@ maintainers: - Emmanuel Gil Peyrot allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 2173fe82317d..8d8503dd934b 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -10,7 +10,7 @@ maintainers: - Srinivas Kandagatla allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: @@ -32,6 +32,8 @@ properties: - qcom,sdm670-qfprom - qcom,sdm845-qfprom - qcom,sm6115-qfprom + - qcom,sm6350-qfprom + - qcom,sm6375-qfprom - qcom,sm8150-qfprom - qcom,sm8250-qfprom - const: qcom,qfprom diff --git a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml index e08504ef3b6e..dce0c7d84ce7 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,spmi-sdam.yaml @@ -15,7 +15,7 @@ description: | to/from the PBUS. allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: @@ -42,17 +42,22 @@ unevaluatedProperties: false examples: - | - sdam_1: nvram@b000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "qcom,spmi-sdam"; - reg = <0xb000 0x100>; - ranges = <0 0xb000 0x100>; + pmic { + #address-cells = <1>; + #size-cells = <0>; - /* Data cells */ - restart_reason: restart@50 { - reg = <0x50 0x1>; - bits = <6 2>; - }; - }; + sdam_1: nvram@b000 { + compatible = "qcom,spmi-sdam"; + reg = <0xb000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xb000 0x100>; + + /* Data cells */ + restart_reason: restart@50 { + reg = <0x50 0x1>; + bits = <6 2>; + }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/nvmem/rmem.yaml b/Documentation/devicetree/bindings/nvmem/rmem.yaml index a4a755dcfc43..38a39c9b8c1c 100644 --- a/Documentation/devicetree/bindings/nvmem/rmem.yaml +++ b/Documentation/devicetree/bindings/nvmem/rmem.yaml @@ -10,7 +10,7 @@ maintainers: - Nicolas Saenz Julienne allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml index febee8129aa9..c5403e149080 100644 --- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml @@ -10,7 +10,7 @@ maintainers: - Heiko Stuebner allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml b/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml index dc790d2cd9f0..b8bca0599c45 100644 --- a/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml +++ b/Documentation/devicetree/bindings/nvmem/socionext,uniphier-efuse.yaml @@ -11,7 +11,7 @@ maintainers: - Kunihiko Hayashi allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: "#address-cells": true diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml index 172597cc5c63..a69de3e92282 100644 --- a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml +++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml @@ -16,7 +16,7 @@ maintainers: - Fabrice Gasnier allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml index a7644ebbc2ca..8877c2283e9e 100644 --- a/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml +++ b/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml @@ -11,7 +11,7 @@ maintainers: - Vincent Shih allOf: - - $ref: "nvmem.yaml#" + - $ref: nvmem.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml index cbc5c69fd405..36d97fb87865 100644 --- a/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml +++ b/Documentation/devicetree/bindings/nvmem/u-boot,env.yaml @@ -50,7 +50,11 @@ properties: ethaddr: type: object - description: Ethernet interface's MAC address + description: Ethernet interfaces base MAC address. + properties: + "#nvmem-cell-cells": + description: The first argument is a MAC address offset. + const: 1 additionalProperties: false @@ -72,6 +76,7 @@ examples: reg = <0x40000 0x10000>; mac: ethaddr { + #nvmem-cell-cells = <1>; }; }; }; diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml index 9bff8ecb653c..d91b639ae7ae 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml @@ -17,20 +17,11 @@ description: properties: clocks: minItems: 3 - items: - - description: PCIe bridge clock. - - description: PCIe bus clock. - - description: PCIe PHY clock. - - description: Additional required clock entry for imx6sx-pcie, - imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep. + maxItems: 4 clock-names: minItems: 3 - items: - - const: pcie - - const: pcie_bus - - enum: [ pcie_phy, pcie_aux ] - - enum: [ pcie_inbound_axi, pcie_aux ] + maxItems: 4 num-lanes: const: 1 diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml index f4a328ec1daa..ee155ed5f181 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml @@ -31,6 +31,19 @@ properties: - const: dbi - const: addr_space + clocks: + minItems: 3 + items: + - description: PCIe bridge clock. + - description: PCIe bus clock. + - description: PCIe PHY clock. + - description: Additional required clock entry for imx6sx-pcie, + imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep. + + clock-names: + minItems: 3 + maxItems: 4 + interrupts: items: - description: builtin eDMA interrupter. @@ -49,6 +62,31 @@ required: allOf: - $ref: /schemas/pci/snps,dw-pcie-ep.yaml# - $ref: /schemas/pci/fsl,imx6q-pcie-common.yaml# + - if: + properties: + compatible: + enum: + - fsl,imx8mq-pcie-ep + then: + properties: + clocks: + minItems: 4 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_phy + - const: pcie_aux + else: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_aux + unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml index 2443641754d3..81bbb8728f0f 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml @@ -40,6 +40,19 @@ properties: - const: dbi - const: config + clocks: + minItems: 3 + items: + - description: PCIe bridge clock. + - description: PCIe bus clock. + - description: PCIe PHY clock. + - description: Additional required clock entry for imx6sx-pcie, + imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep. + + clock-names: + minItems: 3 + maxItems: 4 + interrupts: items: - description: builtin MSI controller. @@ -77,6 +90,70 @@ required: allOf: - $ref: /schemas/pci/snps,dw-pcie.yaml# - $ref: /schemas/pci/fsl,imx6q-pcie-common.yaml# + - if: + properties: + compatible: + enum: + - fsl,imx6sx-pcie + then: + properties: + clocks: + minItems: 4 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_phy + - const: pcie_inbound_axi + + - if: + properties: + compatible: + enum: + - fsl,imx8mq-pcie + then: + properties: + clocks: + minItems: 4 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_phy + - const: pcie_aux + + - if: + properties: + compatible: + enum: + - fsl,imx6q-pcie + - fsl,imx6qp-pcie + - fsl,imx7d-pcie + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_phy + + - if: + properties: + compatible: + enum: + - fsl,imx8mm-pcie + - fsl,imx8mp-pcie + then: + properties: + clocks: + maxItems: 3 + clock-names: + items: + - const: pcie + - const: pcie_bus + - const: pcie_aux unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml index 2be72ae1169f..24c88942e59e 100644 --- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml @@ -21,8 +21,12 @@ allOf: properties: compatible: - items: + oneOf: - const: rockchip,rk3568-pcie + - items: + - enum: + - rockchip,rk3588-pcie + - const: rockchip,rk3568-pcie reg: items: diff --git a/Documentation/devicetree/bindings/perf/riscv,pmu.yaml b/Documentation/devicetree/bindings/perf/riscv,pmu.yaml index a55a4d047d3f..c8448de2f2a0 100644 --- a/Documentation/devicetree/bindings/perf/riscv,pmu.yaml +++ b/Documentation/devicetree/bindings/perf/riscv,pmu.yaml @@ -91,7 +91,6 @@ properties: dependencies: "riscv,event-to-mhpmevent": [ "riscv,event-to-mhpmcounters" ] - "riscv,event-to-mhpmcounters": [ "riscv,event-to-mhpmevent" ] required: - compatible diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml index c03b83103e87..cf4eed230565 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Ondrej Jirman %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/allwinner,sun50i-h6-usb3-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/allwinner,sun50i-h6-usb3-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner H6 USB3 PHY diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml index fe9702e7bdd8..6a4fd4929959 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml @@ -45,7 +45,7 @@ properties: maxItems: 1 allwinner,direction: - $ref: '/schemas/types.yaml#/definitions/string' + $ref: /schemas/types.yaml#/definitions/string description: | Direction of the D-PHY: - "rx" for receiving (e.g. when used with MIPI CSI-2); diff --git a/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml index 5eddaed3d853..64795f170f32 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml @@ -2,8 +2,8 @@ # Copyright 2020 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,axg-mipi-dphy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,axg-mipi-dphy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic AXG MIPI D-PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml index 7aa0c05d6ce4..c8c83acfb871 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,g12a-mipi-dphy-analog.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,g12a-mipi-dphy-analog.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic G12A MIPI analog PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml index bb01c6b34dab..0031fb6a4e76 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb2-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,g12a-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic G12A USB2 PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml index 3314711292d6..1a5a12adb72b 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic G12A USB3 + PCIE Combo PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml index a90fa1baadab..009a39808318 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,meson-axg-mipi-pcie-analog.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,meson-axg-mipi-pcie-analog.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic AXG shared MIPI/PCIE analog PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml index 45f3d72b1cca..40fbf8ac3271 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,meson-axg-pcie.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,meson-axg-pcie.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic AXG PCIE PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml index 1f085cdd1c85..6f9fd1c953f0 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,meson8-hdmi-tx-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,meson8-hdmi-tx-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson8, Meson8b and Meson8m2 HDMI TX PHY diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml index 03c4809dbe8d..df68bfe5f407 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/amlogic,meson8b-usb2-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/amlogic,meson8b-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY diff --git a/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml index 0f0bcde9eb88..bd527f566c3b 100644 --- a/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml +++ b/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: BCM63xx USBH PHY diff --git a/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml index 435b971dfd9b..8467c8e6368c 100644 --- a/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml +++ b/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/brcm,sata-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/brcm,sata-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Broadcom SATA3 PHY diff --git a/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml b/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml index 3a07285b5470..c9e65a2facd5 100644 --- a/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml +++ b/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml @@ -2,8 +2,8 @@ # Copyright (c) 2020 NXP %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/cdns,salvo-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/cdns,salvo-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Cadence SALVO PHY diff --git a/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml b/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml index b11d9873854a..405c6b0b88c0 100644 --- a/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml +++ b/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml @@ -19,11 +19,11 @@ properties: const: 0 hisilicon,pericrg-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle of syscon used to control iso refclk. hisilicon,pctrl-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle of syscon used to control usb tcxo. hisilicon,eye-diagram-param: diff --git a/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml index 3c69aca6c7eb..a1a8a84dfc54 100644 --- a/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml +++ b/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml @@ -20,15 +20,15 @@ properties: const: 0 hisilicon,pericrg-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle of syscon used to control iso refclk. hisilicon,pctrl-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle of syscon used to control usb tcxo. hisilicon,sctrl-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle of syscon used to control phy deep sleep. hisilicon,eye-diagram-param: diff --git a/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml b/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml deleted file mode 100644 index 361ffc35b16b..000000000000 --- a/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/phy/intel,phy-thunderbay-emmc.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Intel Thunder Bay eMMC PHY - -maintainers: - - Srikandan Nandhini - -properties: - compatible: - const: intel,thunderbay-emmc-phy - - "#phy-cells": - const: 0 - - reg: - maxItems: 1 - - clocks: - maxItems: 1 - - clock-names: - items: - - const: emmcclk - -required: - - "#phy-cells" - - compatible - - reg - - clocks - -additionalProperties: false - -examples: - - | - mmc_phy@80440800 { - #phy-cells = <0x0>; - compatible = "intel,thunderbay-emmc-phy"; - reg = <0x80440800 0x100>; - clocks = <&emmc>; - clock-names = "emmcclk"; - }; diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml index 632d61c07f40..3aa1a46796dd 100644 --- a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml @@ -2,8 +2,8 @@ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Marvell Armada UTMI/UTMI+ PHY diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml index 43416c216190..9ce7b4c6d208 100644 --- a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml @@ -2,8 +2,8 @@ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Marvell Armada CP110/CP115 UTMI PHY diff --git a/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml index ff255aa4cc10..bd3bd2f8b1cd 100644 --- a/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml +++ b/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Lubomir Rintel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/marvell,mmp3-hsic-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/marvell,mmp3-hsic-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Marvell MMP3 HSIC PHY diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml index 6cfdaadec085..f3a8b0b745d1 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml @@ -28,6 +28,7 @@ properties: - const: mediatek,mt2701-hdmi-phy - const: mediatek,mt2701-hdmi-phy - const: mediatek,mt8173-hdmi-phy + - const: mediatek,mt8195-hdmi-phy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml index c2f4cb0b254a..b35c4d256e40 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Mediatek Mt7621 PCIe PHY diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml index 6a09472740ed..37f028f7a095 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/phy-cadence-sierra.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/phy-cadence-sierra.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Cadence Sierra PHY @@ -61,14 +61,6 @@ properties: - const: pll0_refclk - const: pll1_refclk - assigned-clocks: - minItems: 1 - maxItems: 2 - - assigned-clock-parents: - minItems: 1 - maxItems: 2 - cdns,autoconf: type: boolean description: diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml index 2ad1faadda2a..dfb31314face 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Cadence Torrent SD0801 PHY @@ -44,12 +44,6 @@ properties: - const: refclk - const: phy_en_refclk - assigned-clocks: - maxItems: 3 - - assigned-clock-parents: - maxItems: 3 - reg: minItems: 1 items: diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml index 8d8698412de0..9ae514fa7533 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml @@ -13,6 +13,7 @@ properties: compatible: enum: - rockchip,rk3568-naneng-combphy + - rockchip,rk3588-naneng-combphy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml b/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml index 445b2467f4f6..4790c6238a40 100644 --- a/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml +++ b/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/phy-tegra194-p2u.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/phy-tegra194-p2u.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: NVIDIA Tegra194 & Tegra234 P2U diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 1e104ae76ee6..c4f8e6ffa5c3 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -2,8 +2,8 @@ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom,edp-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom,edp-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm eDP PHY diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml index 7f403e77f320..543c1a2811a5 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml @@ -2,8 +2,8 @@ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm QUSB2 phy controller diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index ef49efbd0a20..a0407fc79563 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -19,6 +19,7 @@ properties: - qcom,sc8280xp-qmp-gen3x1-pcie-phy - qcom,sc8280xp-qmp-gen3x2-pcie-phy - qcom,sc8280xp-qmp-gen3x4-pcie-phy + - qcom,sdx65-qmp-gen4x2-pcie-phy - qcom,sm8350-qmp-gen3x1-pcie-phy - qcom,sm8550-qmp-gen3x2-pcie-phy - qcom,sm8550-qmp-gen4x2-pcie-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index 64ed331880f6..94c0fab065a8 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -16,20 +16,25 @@ description: properties: compatible: enum: + - qcom,sa8775p-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy - qcom,sm6125-qmp-ufs-phy + - qcom,sm7150-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy reg: maxItems: 1 clocks: - maxItems: 2 + minItems: 2 + maxItems: 3 clock-names: + minItems: 2 items: - const: ref - const: ref_aux + - const: qref power-domains: maxItems: 1 @@ -63,6 +68,26 @@ required: - vdda-pll-supply - "#phy-cells" +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,sa8775p-qmp-ufs-phy + then: + properties: + clocks: + maxItems: 3 + clock-names: + maxItems: 3 + else: + properties: + clocks: + maxItems: 2 + clock-names: + maxItems: 2 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml index ca6a0836b53c..6c99e02b2b4f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Synopsys DesignWare Core 28nm High-Speed PHY diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml index 85d405e028b9..a26524b7e7b7 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom,usb-snps-femto-v2.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom,usb-snps-femto-v2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Synopsys Femto High-Speed USB PHY V2 diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml index bd1388d62ce0..6e4254ff1cd7 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom,usb-ss.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom,usb-ss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY diff --git a/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml b/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml index 3e7191b168fb..09c614952fea 100644 --- a/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/qcom-usb-ipq4019-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/qcom-usb-ipq4019-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcom IPQ40xx Dakota HS/SS USB PHY diff --git a/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml index 28e299a9609d..41df8bb08ff7 100644 --- a/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml @@ -21,12 +21,12 @@ properties: maxItems: 1 samsung,pmu-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle for PMU system controller interface, used to control PMU registers bits for PCIe PHY samsung,fsys-sysreg: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle for FSYS sysreg interface, used to control sysreg registers bits for PCIe PHY diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml index c5dbb91ac402..782f975b43ae 100644 --- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml @@ -35,7 +35,7 @@ properties: maxItems: 4 samsung,pmu-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle-array' + $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 items: minItems: 1 diff --git a/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml index 069d422775bb..57914f214e06 100644 --- a/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml @@ -2,8 +2,8 @@ # Copyright (C) Sunplus Co., Ltd. 2021 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/sunplus,sp7021-usb2-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/sunplus,sp7021-usb2-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Sunplus SP7021 USB 2.0 PHY Controller diff --git a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml index 738c92bb7518..854e554eae67 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml @@ -34,11 +34,6 @@ properties: Three input clocks referring to left input reference clock, refclk and right input reference clock. - assigned-clocks: - $ref: "/schemas/types.yaml#/definitions/phandle-array" - assigned-clock-parents: - $ref: "/schemas/types.yaml#/definitions/phandle-array" - '#phy-cells': const: 2 description: diff --git a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml index 6d46f57fa1b4..be41b4547ec6 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/ti,phy-gmii-sel.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/ti,phy-gmii-sel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: CPSW Port's Interface Mode Selection PHY @@ -55,6 +55,7 @@ properties: - ti,am654-phy-gmii-sel - ti,j7200-cpsw5g-phy-gmii-sel - ti,j721e-cpsw9g-phy-gmii-sel + - ti,j784s4-cpsw9g-phy-gmii-sel reg: maxItems: 1 @@ -87,6 +88,7 @@ allOf: - ti,am654-phy-gmii-sel - ti,j7200-cpsw5g-phy-gmii-sel - ti,j721e-cpsw9g-phy-gmii-sel + - ti,j784s4-cpsw9g-phy-gmii-sel then: properties: '#phy-cells': @@ -113,6 +115,7 @@ allOf: contains: enum: - ti,j721e-cpsw9g-phy-gmii-sel + - ti,j784s4-cpsw9g-phy-gmii-sel then: properties: ti,qsgmii-main-ports: @@ -130,6 +133,7 @@ allOf: enum: - ti,j7200-cpsw5g-phy-gmii-sel - ti,j721e-cpsw9g-phy-gmii-sel + - ti,j784s4-cpsw9g-phy-gmii-sel then: properties: ti,qsgmii-main-ports: false diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml index c54b36c104ab..9ea30eaba314 100644 --- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml +++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/ti,phy-j721e-wiz.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/ti,phy-j721e-wiz.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI J721E WIZ (SERDES Wrapper) @@ -54,18 +54,6 @@ properties: ranges: true - assigned-clocks: - minItems: 1 - maxItems: 2 - - assigned-clock-parents: - minItems: 1 - maxItems: 2 - - assigned-clock-rates: - minItems: 1 - maxItems: 2 - typec-dir-gpios: maxItems: 1 description: @@ -101,6 +89,9 @@ properties: "#clock-cells": const: 0 + clock-output-names: + maxItems: 1 + assigned-clocks: maxItems: 1 @@ -134,6 +125,9 @@ patternProperties: "#clock-cells": const: 0 + clock-output-names: + maxItems: 1 + assigned-clocks: maxItems: 1 @@ -162,6 +156,9 @@ patternProperties: "#clock-cells": const: 0 + clock-output-names: + maxItems: 1 + required: - clocks - "#clock-cells" diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml index 237295b2b5a8..79dad3e89aa6 100644 --- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml +++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/phy/ti,tcan104x-can.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/phy/ti,tcan104x-can.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TCAN104x CAN TRANSCEIVER PHY diff --git a/Documentation/devicetree/bindings/pinctrl/actions,s500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/actions,s500-pinctrl.yaml index fb0f69ce9c16..7cb8a747feee 100644 --- a/Documentation/devicetree/bindings/pinctrl/actions,s500-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/actions,s500-pinctrl.yaml @@ -185,7 +185,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml index 1e3c8de6cae1..467016cbb037 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml @@ -142,7 +142,7 @@ allOf: # boards are defining it at the moment so it would generate a lot of # warnings. - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: not: properties: diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-a1.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-a1.yaml new file mode 100644 index 000000000000..99080c9eaac3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-a1.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson-pinctrl-a1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson A1 pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: amlogic,meson-pinctrl-common.yaml# + +properties: + compatible: + enum: + - amlogic,meson-a1-periphs-pinctrl + - amlogic,meson-s4-periphs-pinctrl + +required: + - compatible + +patternProperties: + "^bank@[0-9a-z]+$": + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-gpio + + unevaluatedProperties: false + + properties: + reg: + maxItems: 2 + + reg-names: + items: + - const: mux + - const: gpio + +unevaluatedProperties: + type: object + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-pins + +examples: + - | + periphs_pinctrl: pinctrl { + compatible = "amlogic,meson-a1-periphs-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + bank@400 { + reg = <0x0400 0x003c>, + <0x0480 0x0118>; + reg-names = "mux", "gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&periphs_pinctrl 0 0 62>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-common.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-common.yaml new file mode 100644 index 000000000000..a7b29ef0bab6 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-common.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson-pinctrl-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: pinctrl.yaml# + +properties: + ranges: true + + "#address-cells": + enum: [1, 2] + + "#size-cells": + enum: [1, 2] + +required: + - ranges + - "#address-cells" + - "#size-cells" + +additionalProperties: true + +$defs: + meson-gpio: + type: object + + properties: + gpio-controller: true + + "#gpio-cells": + const: 2 + + gpio-ranges: + maxItems: 1 + + required: + - reg + - reg-names + - gpio-controller + - "#gpio-cells" + - gpio-ranges + + meson-pins: + type: object + additionalProperties: + type: object + allOf: + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-aobus.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-aobus.yaml new file mode 100644 index 000000000000..7c9c94ec5b7b --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-aobus.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson-pinctrl-g12a-aobus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson G12 AOBUS pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: amlogic,meson-pinctrl-common.yaml# + +properties: + compatible: + enum: + - amlogic,meson-g12a-aobus-pinctrl + +required: + - compatible + +patternProperties: + "^bank@[0-9a-z]+$": + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-gpio + + unevaluatedProperties: false + + properties: + reg: + maxItems: 3 + + reg-names: + items: + - const: mux + - const: ds + - const: gpio + +unevaluatedProperties: + type: object + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-pins + +examples: + - | + ao_pinctrl: pinctrl { + compatible = "amlogic,meson-g12a-aobus-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + bank@14 { + reg = <0x14 0x8>, + <0x1c 0x8>, + <0x24 0x14>; + reg-names = "mux", "ds", "gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&ao_pinctrl 0 0 15>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-periphs.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-periphs.yaml new file mode 100644 index 000000000000..4bcb8b60420f --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson-pinctrl-g12a-periphs.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson-pinctrl-g12a-periphs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson G12 PERIPHS pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: amlogic,meson-pinctrl-common.yaml# + +properties: + compatible: + enum: + - amlogic,meson-g12a-periphs-pinctrl + +required: + - compatible + +patternProperties: + "^bank@[0-9a-z]+$": + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-gpio + + unevaluatedProperties: false + + properties: + reg: + maxItems: 5 + + reg-names: + items: + - const: gpio + - const: pull + - const: pull-enable + - const: mux + - const: ds + +unevaluatedProperties: + type: object + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-pins + +examples: + - | + periphs_pinctrl: pinctrl { + compatible = "amlogic,meson-g12a-periphs-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + bank@40 { + reg = <0x40 0x4c>, + <0xe8 0x18>, + <0x120 0x18>, + <0x2c0 0x40>, + <0x340 0x1c>; + reg-names = "gpio", "pull", "pull-enable", "mux", "ds"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&periphs_pinctrl 0 0 86>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-aobus.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-aobus.yaml new file mode 100644 index 000000000000..32d99c9b6afc --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-aobus.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson8-pinctrl-aobus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson8 AOBUS pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: amlogic,meson-pinctrl-common.yaml# + +properties: + compatible: + oneOf: + - enum: + - amlogic,meson8-aobus-pinctrl + - amlogic,meson8b-aobus-pinctrl + - amlogic,meson-gxbb-aobus-pinctrl + - amlogic,meson-gxl-aobus-pinctrl + - amlogic,meson-axg-aobus-pinctrl + - items: + - const: amlogic,meson8m2-aobus-pinctrl + - const: amlogic,meson8-aobus-pinctrl + +required: + - compatible + +patternProperties: + "^bank@[0-9a-z]+$": + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-gpio + + unevaluatedProperties: false + + properties: + reg: + maxItems: 3 + + reg-names: + items: + - const: mux + - const: pull + - const: gpio + +unevaluatedProperties: + type: object + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-pins + +examples: + - | + pinctrl_aobus: pinctrl { + compatible = "amlogic,meson8-aobus-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + bank@14 { + reg = <0x14 0x4>, + <0x2c 0x4>, + <0x24 0x8>; + reg-names = "mux", "pull", "gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aobus 0 0 16>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml new file mode 100644 index 000000000000..d0441051f34a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/amlogic,meson8-pinctrl-cbus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson8 CBUS pinmux controller + +maintainers: + - Neil Armstrong + +allOf: + - $ref: amlogic,meson-pinctrl-common.yaml# + +properties: + compatible: + oneOf: + - enum: + - amlogic,meson8-cbus-pinctrl + - amlogic,meson8b-cbus-pinctrl + - amlogic,meson-gxbb-periphs-pinctrl + - amlogic,meson-gxl-periphs-pinctrl + - amlogic,meson-axg-periphs-pinctrl + - items: + - const: amlogic,meson8m2-cbus-pinctrl + - const: amlogic,meson8-cbus-pinctrl + +required: + - compatible + +patternProperties: + "^bank@[0-9a-z]+$": + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-gpio + + unevaluatedProperties: false + + properties: + reg: + maxItems: 4 + + reg-names: + items: + - const: mux + - const: pull + - const: pull-enable + - const: gpio + +unevaluatedProperties: + type: object + $ref: amlogic,meson-pinctrl-common.yaml#/$defs/meson-pins + +examples: + - | + pinctrl_cbus: pinctrl { + compatible = "amlogic,meson8-cbus-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + bank@80b0 { + reg = <0x80b0 0x28>, + <0x80e8 0x18>, + <0x8120 0x18>, + <0x8030 0x30>; + reg-names = "mux", "pull", "pull-enable", "gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_cbus 0 0 120>; + }; + + cec_ao_a_h_pins: cec_ao_a_h { + mux { + groups = "cec_ao_a_h"; + function = "cec_ao_a_h"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml index 684c03a6bd40..9c07935919ea 100644 --- a/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml @@ -74,7 +74,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml index f4f1ee6b116e..bef85c25cdef 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml @@ -32,7 +32,7 @@ patternProperties: then: patternProperties: "^function|groups$": - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, DDCCLK, DDCDAT, EXTRST, FLACK, FLBUSY, FLWP, GPID, GPID0, GPID2, GPID4, GPID6, GPIE0, @@ -51,7 +51,7 @@ patternProperties: VGAHS, VGAVS, VPI18, VPI24, VPI30, VPO12, VPO24, WDTRST1, WDTRST2] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml index 8168f0088471..14c391f16899 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml @@ -44,7 +44,7 @@ patternProperties: then: patternProperties: "^function|groups$": - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ ACPI, ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, DDCCLK, DDCDAT, ESPI, FWSPICS1, FWSPICS2, GPID0, GPID2, GPID4, GPID6, GPIE0, GPIE2, @@ -65,7 +65,7 @@ patternProperties: VGAVS, VPI24, VPO, WDTRST1, WDTRST2] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml index 62424c42c981..859a1889dc1e 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml @@ -30,7 +30,7 @@ patternProperties: then: properties: function: - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, EMMC, ESPI, ESPIALT, FSI1, FSI2, FWQSPI, FWSPIABR, FWSPID, FWSPIWP, GPIT0, GPIT1, GPIT2, GPIT3, @@ -55,7 +55,7 @@ patternProperties: USB2BD, USB2BH, VB, VGAHS, VGAVS, WDTRST1, WDTRST2, WDTRST3, WDTRST4 ] groups: - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ ADC0, ADC1, ADC10, ADC11, ADC12, ADC13, ADC14, ADC15, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, BMCINT, EMMCG1, EMMCG4, EMMCG8, ESPI, ESPIALT, FSI1, FSI2, FWQSPI, FWSPIABR, FWSPID, FWSPIWP, @@ -84,7 +84,7 @@ patternProperties: WDTRST3, WDTRST4] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6318-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6318-pinctrl.yaml index ab019a1998e8..4478a76171f7 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6318-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6318-pinctrl.yaml @@ -38,7 +38,7 @@ patternProperties: gpio8, gpio9, gpio10, gpio11, gpio12, gpio13, gpio40 ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm63268-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm63268-pinctrl.yaml index 8c9d4668c8c4..73e1caa7c011 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm63268-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm63268-pinctrl.yaml @@ -42,7 +42,7 @@ patternProperties: vdsl_phy_override_3_grp, dsl_gpio8, dsl_gpio9 ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6328-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6328-pinctrl.yaml index a8e22ec02215..2750ba42aeb8 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6328-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6328-pinctrl.yaml @@ -37,7 +37,7 @@ patternProperties: usb_port1 ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6358-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6358-pinctrl.yaml index 35867355a47a..2f6c540498bc 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6358-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6358-pinctrl.yaml @@ -35,7 +35,7 @@ patternProperties: led_grp, spi_cs_grp, utopia_grp, pwm_syn_clk, sys_irq_grp ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6362-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6362-pinctrl.yaml index b584d4b27223..b3044f805753 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6362-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6362-pinctrl.yaml @@ -42,7 +42,7 @@ patternProperties: gpio22, gpio23, gpio24, gpio25, gpio26, gpio27, nand_grp ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6368-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6368-pinctrl.yaml index 229323d9237d..3236871827df 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm6368-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm6368-pinctrl.yaml @@ -43,7 +43,7 @@ patternProperties: gpio31, uart1_grp ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,ns-pinmux.yaml b/Documentation/devicetree/bindings/pinctrl/brcm,ns-pinmux.yaml index 8d1e5b1cdd5f..0a39dd26ee1a 100644 --- a/Documentation/devicetree/bindings/pinctrl/brcm,ns-pinmux.yaml +++ b/Documentation/devicetree/bindings/pinctrl/brcm,ns-pinmux.yaml @@ -53,7 +53,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml index a78cb2796001..7f4f36a58e56 100644 --- a/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml +++ b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml @@ -144,7 +144,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml index 5cd512b7d5ba..5e000b3fadde 100644 --- a/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml +++ b/Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.yaml @@ -173,7 +173,7 @@ properties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml b/Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml index 6bd42e43cdab..bb61a30321a1 100644 --- a/Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml +++ b/Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml @@ -40,8 +40,8 @@ properties: '-pins$': type: object allOf: - - $ref: "pincfg-node.yaml#" - - $ref: "pinmux-node.yaml#" + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# properties: groups: description: diff --git a/Documentation/devicetree/bindings/pinctrl/cypress,cy8c95x0.yaml b/Documentation/devicetree/bindings/pinctrl/cypress,cy8c95x0.yaml index 915cbbcc3555..222d57541b65 100644 --- a/Documentation/devicetree/bindings/pinctrl/cypress,cy8c95x0.yaml +++ b/Documentation/devicetree/bindings/pinctrl/cypress,cy8c95x0.yaml @@ -109,7 +109,7 @@ required: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.yaml index 621038662188..7bd723ab1281 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.yaml @@ -68,7 +68,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8m-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx8m-pinctrl.yaml index 7ae084397258..6068be11dfe2 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx8m-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8m-pinctrl.yaml @@ -65,7 +65,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8ulp-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx8ulp-pinctrl.yaml index 693398d88223..7dcf681271d3 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx8ulp-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8ulp-pinctrl.yaml @@ -57,7 +57,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml index 66baa6082a4f..2f2405102996 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx93-pinctrl.yaml @@ -14,7 +14,7 @@ description: for common binding part and usage. allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml index a4397930e0e8..35723966b70a 100644 --- a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.yaml @@ -119,7 +119,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/intel,lgm-io.yaml b/Documentation/devicetree/bindings/pinctrl/intel,lgm-io.yaml index ca0fef6e535e..1144ca2896e3 100644 --- a/Documentation/devicetree/bindings/pinctrl/intel,lgm-io.yaml +++ b/Documentation/devicetree/bindings/pinctrl/intel,lgm-io.yaml @@ -48,7 +48,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/intel,pinctrl-thunderbay.yaml b/Documentation/devicetree/bindings/pinctrl/intel,pinctrl-thunderbay.yaml deleted file mode 100644 index f001add16814..000000000000 --- a/Documentation/devicetree/bindings/pinctrl/intel,pinctrl-thunderbay.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/pinctrl/intel,pinctrl-thunderbay.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Intel Thunder Bay pin controller - -maintainers: - - Lakshmi Sowjanya D - -description: | - Intel Thunder Bay SoC integrates a pin controller which enables control - of pin directions, input/output values and configuration - for a total of 67 pins. - -properties: - compatible: - const: intel,thunderbay-pinctrl - - reg: - maxItems: 1 - - gpio-controller: true - - '#gpio-cells': - const: 2 - - gpio-ranges: - maxItems: 1 - - interrupts: - description: - Specifies the interrupt lines to be used by the controller. - maxItems: 2 - - interrupt-controller: true - - '#interrupt-cells': - const: 2 - -patternProperties: - '^gpio@[0-9a-f]*$': - type: object - additionalProperties: false - - description: - Child nodes can be specified to contain pin configuration information, - which can then be utilized by pinctrl client devices. - The following properties are supported. - - properties: - pins: - description: | - The name(s) of the pins to be configured in the child node. - Supported pin names are "GPIO0" up to "GPIO66". - - bias-disable: true - - bias-pull-down: true - - bias-pull-up: true - - drive-strength: - description: Drive strength for the pad. - enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] - - bias-bus-hold: - type: boolean - - input-schmitt-enable: - type: boolean - - slew-rate: - description: GPIO slew rate control. - 0 - Slow - 1 - Fast - enum: [0, 1] - -additionalProperties: false - -required: - - compatible - - reg - - gpio-controller - - '#gpio-cells' - - gpio-ranges - - interrupts - - interrupt-controller - - '#interrupt-cells' - -examples: - - | - #include - #include - // Example 1 - pinctrl0: gpio@0 { - compatible = "intel,thunderbay-pinctrl"; - reg = <0x600b0000 0x88>; - gpio-controller; - #gpio-cells = <0x2>; - gpio-ranges = <&pinctrl0 0 0 67>; - interrupts = , - ; - interrupt-controller; - #interrupt-cells = <2>; - }; - - // Example 2 - pinctrl1: gpio@1 { - compatible = "intel,thunderbay-pinctrl"; - reg = <0x600c0000 0x88>; - gpio-controller; - #gpio-cells = <0x2>; - gpio-ranges = <&pinctrl1 0 0 53>; - interrupts = , - ; - interrupt-controller; - #interrupt-cells = <2>; - }; diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt index 4658f105fa09..6bd9bc61becb 100644 --- a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt +++ b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt @@ -1,11 +1,7 @@ Lantiq XWAY pinmux controller Required properties: -- compatible: "lantiq,pinctrl-xway", (DEPRECATED: Use "lantiq,pinctrl-danube") - "lantiq,pinctrl-xr9", (DEPRECATED: Use "lantiq,xrx100-pinctrl" or - "lantiq,xrx200-pinctrl") - "lantiq,pinctrl-ase", (DEPRECATED: Use "lantiq,ase-pinctrl") - "lantiq,-pinctrl", where is: +- compatible: "lantiq,-pinctrl", where is: "ase" (XWAY AMAZON Family) "danube" (XWAY DANUBE Family) "xrx100" (XWAY xRX100 Family) @@ -45,29 +41,6 @@ Required subnode-properties: Valid values for group and function names: -XWAY: (DEPRECATED: Use DANUBE) - mux groups: - exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1, - ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3, - spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, - gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2, - req3 - - functions: - spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu - -XR9: ( DEPRECATED: Use xRX100/xRX200) - mux groups: - exin0, exin1, exin2, exin3, exin4, jtag, ebu a23, ebu a24, ebu a25, - ebu clk, ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, - nand rd, spi, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6, - asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, - clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, - gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2 - - functions: - spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio, gphy - AMAZON: mux groups: exin0, exin1, exin2, jtag, spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, @@ -139,12 +112,6 @@ Optional subnode-properties: 0: none, 1: down, 2: up. - lantiq,open-drain: Boolean, enables open-drain on the defined pin. -Valid values for XWAY pin names: (DEPRECATED: Use DANUBE) - Pinconf pins can be referenced via the names io0-io31. - -Valid values for XR9 pin names: (DEPRECATED: Use xrX100/xRX200) - Pinconf pins can be referenced via the names io0-io55. - Valid values for AMAZON pin names: Pinconf pins can be referenced via the names io0-io31. diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,ac5-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/marvell,ac5-pinctrl.yaml index 491f67e7cc4f..afea9424c7e1 100644 --- a/Documentation/devicetree/bindings/pinctrl/marvell,ac5-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/marvell,ac5-pinctrl.yaml @@ -28,7 +28,7 @@ patternProperties: properties: marvell,function: - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string description: Indicates the function to select. enum: [ dev_init_done, ge, gpio, i2c0, i2c1, int_out, led, nand, pcie, ptp, sdio, @@ -47,7 +47,7 @@ patternProperties: mpp40, mpp41, mpp42, mpp43, mpp44, mpp45 ] allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml index a55c8e4ff26e..bccff08a5ba3 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt65xx-pinctrl.yaml @@ -4,13 +4,13 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT65xx Pin Controller +title: MediaTek MT65xx Pin Controller maintainers: - Sean Wang -description: |+ - The Mediatek's Pin controller is used to control SoC pins. +description: + The MediaTek's MT65xx Pin controller is used to control SoC pins. properties: compatible: @@ -30,7 +30,7 @@ properties: pins-are-numbered: $ref: /schemas/types.yaml#/definitions/flag - description: | + description: Specify the subnodes are using numbered pinmux to specify pins. (UNUSED) deprecated: true @@ -38,10 +38,10 @@ properties: "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. mediatek,pctl-regmap: $ref: /schemas/types.yaml#/definitions/phandle-array @@ -49,7 +49,7 @@ properties: maxItems: 1 minItems: 1 maxItems: 2 - description: | + description: Should be phandles of the syscfg node. interrupt-controller: true @@ -67,7 +67,7 @@ required: - "#gpio-cells" allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# patternProperties: 'pins$': @@ -77,25 +77,25 @@ patternProperties: '(^pins|pins?$)': type: object additionalProperties: false - description: | + description: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer configuration, pullups, drive strength, input enable/disable and input schmitt. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pinmux: description: - integer array, represents gpio pin number and mux setting. + Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are - defined as macros in -pinfunc.h directly. + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. bias-disable: true bias-pull-up: - description: | + description: Besides generic pinconfig options, it can be used as the pull up settings for 2 pull resistors, R0 and R1. User can configure those special pins. Some macros have been defined for this usage, such @@ -117,7 +117,7 @@ patternProperties: input-schmitt-disable: true drive-strength: - description: | + description: Can support some arguments, such as MTK_DRIVE_4mA, MTK_DRIVE_6mA, etc. See dt-bindings/pinctrl/mt65xx.h for valid arguments. diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt6779-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt6779-pinctrl.yaml index a2141eb0854e..7f0e2d6cd6d9 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt6779-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt6779-pinctrl.yaml @@ -4,15 +4,15 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt6779-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT6779 Pin Controller +title: MediaTek MT6779 Pin Controller maintainers: - Andy Teng - Sean Wang description: - The MediaTek pin controller on MT6779 is used to control pin - functions, pull up/down resistance and drive strength options. + The MediaTek pin controller on MT6779 is used to control pin functions, pull + up/down resistance and drive strength options. properties: compatible: @@ -29,22 +29,22 @@ properties: "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. gpio-ranges: minItems: 1 maxItems: 5 - description: | + description: GPIO valid number range. interrupt-controller: true interrupts: maxItems: 1 - description: | + description: Specifies the summary IRQ. "#interrupt-cells": @@ -58,7 +58,7 @@ required: - "#gpio-cells" allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: properties: compatible: @@ -118,19 +118,20 @@ patternProperties: patternProperties: '-pins*$': type: object - description: | + description: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and input schmitt. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + configuration, pullups, drive strength, input enable/disable and input + schmitt. + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pinmux: description: - integer array, represents gpio pin number and mux setting. - Supported pin number and mux varies for different SoCs, and are defined - as macros in boot/dts/-pinfunc.h directly. + Integer array, represents gpio pin number and mux setting. + Supported pin number and mux varies for different SoCs, and are + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. bias-disable: true @@ -159,7 +160,8 @@ patternProperties: mediatek,pull-up-adv: description: | Pull up setings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -170,7 +172,8 @@ patternProperties: mediatek,pull-down-adv: description: | Pull down settings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,pinctrl-mt6795.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt6795-pinctrl.yaml similarity index 85% rename from Documentation/devicetree/bindings/pinctrl/mediatek,pinctrl-mt6795.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt6795-pinctrl.yaml index 9399e0215526..601d86aecdd4 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,pinctrl-mt6795.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt6795-pinctrl.yaml @@ -1,17 +1,17 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/mediatek,pinctrl-mt6795.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt6795-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT6795 Pin Controller +title: MediaTek MT6795 Pin Controller maintainers: - AngeloGioacchino Del Regno - Sean Wang -description: | - The Mediatek's Pin controller is used to control SoC pins. +description: + The MediaTek's MT6795 Pin controller is used to control SoC pins. properties: compatible: @@ -20,10 +20,10 @@ properties: gpio-controller: true '#gpio-cells': - description: | + description: Number of cells in GPIO specifier. Since the generic GPIO binding is used, - the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. const: 2 gpio-ranges: @@ -32,7 +32,7 @@ properties: reg: description: - Physical address base for gpio base and eint registers. + Physical address base for GPIO base and eint registers. minItems: 2 reg-names: @@ -65,8 +65,8 @@ patternProperties: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and - input schmitt. + configuration, pullups, drive strength, input enable/disable and input + schmitt. An example of using macro: pincontroller { /* GPIO0 set as multifunction GPIO0 */ @@ -82,15 +82,14 @@ patternProperties: } }; }; - $ref: "pinmux-node.yaml" + $ref: pinmux-node.yaml properties: pinmux: - description: | + description: Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are - defined as macros in dt-bindings/pinctrl/-pinfunc.h - directly. + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. drive-strength: enum: [2, 4, 6, 8, 10, 12, 14, 16] @@ -100,20 +99,20 @@ patternProperties: - type: boolean - enum: [100, 101, 102, 103] description: mt6795 pull down PUPD/R0/R1 type define value. - description: | - For normal pull down type, it is not necessary to specify R1R0 - values; When pull down type is PUPD/R0/R1, adding R1R0 defines - will set different resistance values. + description: + For normal pull down type, it is not necessary to specify R1R0 + values; When pull down type is PUPD/R0/R1, adding R1R0 defines + will set different resistance values. bias-pull-up: oneOf: - type: boolean - enum: [100, 101, 102, 103] description: mt6795 pull up PUPD/R0/R1 type define value. - description: | - For normal pull up type, it is not necessary to specify R1R0 - values; When pull up type is PUPD/R0/R1, adding R1R0 defines - will set different resistance values. + description: + For normal pull up type, it is not necessary to specify R1R0 + values; When pull up type is PUPD/R0/R1, adding R1R0 defines will + set different resistance values. bias-disable: true @@ -132,7 +131,8 @@ patternProperties: mediatek,pull-up-adv: description: | Pull up setings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -143,7 +143,8 @@ patternProperties: mediatek,pull-down-adv: description: | Pull down settings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -155,7 +156,7 @@ patternProperties: - pinmux allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7620-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7620-pinctrl.yaml new file mode 100644 index 000000000000..591bc0664ec6 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7620-pinctrl.yaml @@ -0,0 +1,298 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt7620-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7620 Pin Controller + +maintainers: + - Arınç ÜNAL + - Sergio Paracuellos + +description: | + MediaTek MT7620 pin controller for MT7620 SoC. + The pin controller can only set the muxing of pin groups. Muxing individual + pins is not supported. There is no pinconf support. + +properties: + compatible: + const: ralink,mt7620-pinctrl + +patternProperties: + '-pins$': + type: object + additionalProperties: false + + patternProperties: + '^(.*-)?pinmux$': + type: object + description: node for pinctrl. + $ref: pinmux-node.yaml# + additionalProperties: false + + properties: + function: + description: + A string containing the name of the function to mux to the group. + enum: [ephy, gpio, gpio i2s, gpio uartf, i2c, i2s uartf, mdio, nand, + pa, pcie refclk, pcie rst, pcm gpio, pcm i2s, pcm uartf, + refclk, rgmii1, rgmii2, sd, spi, spi refclk, uartf, uartlite, + wdt refclk, wdt rst, wled] + + groups: + description: + An array of strings. Each string contains the name of a group. + maxItems: 1 + + required: + - groups + - function + + allOf: + - if: + properties: + function: + const: ephy + then: + properties: + groups: + enum: [ephy] + + - if: + properties: + function: + const: gpio + then: + properties: + groups: + enum: [ephy, i2c, mdio, nd_sd, pa, pcie, rgmii1, rgmii2, spi, + spi refclk, uartf, uartlite, wdt, wled] + + - if: + properties: + function: + const: gpio i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: gpio uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: i2c + then: + properties: + groups: + enum: [i2c] + + - if: + properties: + function: + const: i2s uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: mdio + then: + properties: + groups: + enum: [mdio] + + - if: + properties: + function: + const: nand + then: + properties: + groups: + enum: [nd_sd] + + - if: + properties: + function: + const: pa + then: + properties: + groups: + enum: [pa] + + - if: + properties: + function: + const: pcie refclk + then: + properties: + groups: + enum: [pcie] + + - if: + properties: + function: + const: pcie rst + then: + properties: + groups: + enum: [pcie] + + - if: + properties: + function: + const: pcm gpio + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: refclk + then: + properties: + groups: + enum: [mdio] + + - if: + properties: + function: + const: rgmii1 + then: + properties: + groups: + enum: [rgmii1] + + - if: + properties: + function: + const: rgmii2 + then: + properties: + groups: + enum: [rgmii2] + + - if: + properties: + function: + const: sd + then: + properties: + groups: + enum: [nd_sd] + + - if: + properties: + function: + const: spi + then: + properties: + groups: + enum: [spi] + + - if: + properties: + function: + const: spi refclk + then: + properties: + groups: + enum: [spi refclk] + + - if: + properties: + function: + const: uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: uartlite + then: + properties: + groups: + enum: [uartlite] + + - if: + properties: + function: + const: wdt refclk + then: + properties: + groups: + enum: [wdt] + + - if: + properties: + function: + const: wdt rst + then: + properties: + groups: + enum: [wdt] + + - if: + properties: + function: + const: wled + then: + properties: + groups: + enum: [wled] + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + +additionalProperties: false + +examples: + - | + pinctrl { + compatible = "ralink,mt7620-pinctrl"; + + i2c_pins: i2c0-pins { + pinmux { + groups = "i2c"; + function = "i2c"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,mt7621-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7621-pinctrl.yaml similarity index 96% rename from Documentation/devicetree/bindings/pinctrl/ralink,mt7621-pinctrl.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt7621-pinctrl.yaml index 1b1d37b981d9..e568b9c13727 100644 --- a/Documentation/devicetree/bindings/pinctrl/ralink,mt7621-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7621-pinctrl.yaml @@ -1,17 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/ralink,mt7621-pinctrl.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt7621-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Ralink MT7621 Pin Controller +title: MediaTek MT7621 Pin Controller maintainers: - Arınç ÜNAL - Sergio Paracuellos -description: - Ralink MT7621 pin controller for MT7621 SoC. +description: | + MediaTek MT7621 pin controller for MT7621 SoC. The pin controller can only set the muxing of pin groups. Muxing individual pins is not supported. There is no pinconf support. @@ -22,11 +22,14 @@ properties: patternProperties: '-pins$': type: object + additionalProperties: false + patternProperties: '^(.*-)?pinmux$': type: object description: node for pinctrl. $ref: pinmux-node.yaml# + additionalProperties: false properties: function: @@ -236,12 +239,8 @@ patternProperties: groups: enum: [wdt] - additionalProperties: false - - additionalProperties: false - allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml index ac93eb8f01a6..bd72a326e6e0 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml @@ -4,12 +4,12 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt7622-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT7622 Pin Controller +title: MediaTek MT7622 Pin Controller maintainers: - Sean Wang -description: |+ +description: The MediaTek's MT7622 Pin controller is used to control SoC pins. properties: @@ -29,10 +29,10 @@ properties: "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. interrupt-controller: true @@ -43,7 +43,7 @@ properties: const: 2 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -68,18 +68,18 @@ patternProperties: '^mux(-|$)': type: object additionalProperties: false - description: | + description: pinmux configuration nodes. - $ref: "/schemas/pinctrl/pinmux-node.yaml" + $ref: /schemas/pinctrl/pinmux-node.yaml properties: function: - description: | + description: A string containing the name of the function to mux to the group. enum: [emmc, eth, i2c, i2s, ir, led, flash, pcie, pmic, pwm, sd, spi, tdm, uart, watchdog, wifi] groups: - description: | + description: An array of strings. Each string contains the name of a group. drive-strength: @@ -247,18 +247,18 @@ patternProperties: '^conf(-|$)': type: object additionalProperties: false - description: | + description: pinconf configuration nodes. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: groups: - description: | + description: An array of strings. Each string contains the name of a group. Valid values are the same as the pinmux node. pins: - description: | + description: An array of strings. Each string contains the name of a pin. enum: [GPIO_A, I2S1_IN, I2S1_OUT, I2S_BCLK, I2S_WS, I2S_MCLK, TXD0, RXD0, SPI_WP, SPI_HOLD, SPI_CLK, SPI_MOSI, SPI_MISO, SPI_CS, @@ -315,14 +315,14 @@ patternProperties: enum: [0, 1] mediatek,tdsel: - description: | + description: An integer describing the steps for output level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 15. $ref: /schemas/types.yaml#/definitions/uint32 mediatek,rdsel: - description: | + description: An integer describing the steps for input level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 63. diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,mt7620-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt76x8-pinctrl.yaml similarity index 61% rename from Documentation/devicetree/bindings/pinctrl/ralink,mt7620-pinctrl.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt76x8-pinctrl.yaml index 1e63ea34146a..31849dd5940b 100644 --- a/Documentation/devicetree/bindings/pinctrl/ralink,mt7620-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt76x8-pinctrl.yaml @@ -1,50 +1,46 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/ralink,mt7620-pinctrl.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt76x8-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Ralink MT7620 Pin Controller +title: MediaTek MT76X8 Pin Controller maintainers: - Arınç ÜNAL - Sergio Paracuellos -description: - Ralink MT7620 pin controller for MT7620, MT7628 and MT7688 SoCs. +description: | + MediaTek MT76X8 pin controller for MT7628 and MT7688 SoCs. The pin controller can only set the muxing of pin groups. Muxing individual pins is not supported. There is no pinconf support. properties: compatible: - const: ralink,mt7620-pinctrl + const: ralink,mt76x8-pinctrl patternProperties: '-pins$': type: object + additionalProperties: false + patternProperties: '^(.*-)?pinmux$': type: object description: node for pinctrl. $ref: pinmux-node.yaml# + additionalProperties: false properties: function: description: A string containing the name of the function to mux to the group. - anyOf: - - description: For MT7620 SoC - enum: [ephy, gpio, gpio i2s, gpio uartf, i2c, i2s uartf, mdio, nand, pa, - pcie refclk, pcie rst, pcm gpio, pcm i2s, pcm uartf, refclk, - rgmii1, rgmii2, sd, spi, spi refclk, uartf, uartlite, wdt refclk, - wdt rst, wled] - - - description: For MT7628 and MT7688 SoCs - enum: [antenna, debug, gpio, i2c, i2s, jtag, p0led_an, p0led_kn, - p1led_an, p1led_kn, p2led_an, p2led_kn, p3led_an, p3led_kn, - p4led_an, p4led_kn, pcie, pcm, perst, pwm, pwm0, pwm1, pwm_uart2, - refclk, rsvd, sdxc, sdxc d5 d4, sdxc d6, sdxc d7, spi, spi cs1, - spis, sw_r, uart0, uart1, uart2, utif, wdt, wled_an, wled_kn, -] + enum: [antenna, debug, gpio, i2c, i2s, jtag, p0led_an, p0led_kn, + p1led_an, p1led_kn, p2led_an, p2led_kn, p3led_an, p3led_kn, + p4led_an, p4led_kn, pcie, pcm, perst, pwm, pwm0, pwm1, + pwm_uart2, refclk, rsvd, sdxc, sdxc d5 d4, sdxc d6, sdxc d7, + spi, spi cs1, spis, sw_r, uart0, uart1, uart2, utif, wdt, + wled_an, wled_kn, -] groups: description: @@ -74,15 +70,6 @@ patternProperties: groups: enum: [i2c] - - if: - properties: - function: - const: ephy - then: - properties: - groups: - enum: [ephy] - - if: properties: function: @@ -90,35 +77,11 @@ patternProperties: then: properties: groups: - anyOf: - - description: For MT7620 SoC - enum: [ephy, i2c, mdio, nd_sd, pa, pcie, rgmii1, rgmii2, - spi, spi refclk, uartf, uartlite, wdt, wled] - - - description: For MT7628 and MT7688 SoCs - enum: [gpio, i2c, i2s, p0led_an, p0led_kn, p1led_an, - p1led_kn, p2led_an, p2led_kn, p3led_an, p3led_kn, - p4led_an, p4led_kn, perst, pwm0, pwm1, refclk, - sdmode, spi, spi cs1, spis, uart0, uart1, uart2, - wdt, wled_an, wled_kn] - - - if: - properties: - function: - const: gpio i2s - then: - properties: - groups: - enum: [uartf] - - - if: - properties: - function: - const: gpio uartf - then: - properties: - groups: - enum: [uartf] + enum: [gpio, i2c, i2s, p0led_an, p0led_kn, p1led_an, p1led_kn, + p2led_an, p2led_kn, p3led_an, p3led_kn, p4led_an, + p4led_kn, perst, pwm0, pwm1, refclk, sdmode, spi, + spi cs1, spis, uart0, uart1, uart2, wdt, wled_an, + wled_kn] - if: properties: @@ -138,15 +101,6 @@ patternProperties: groups: enum: [i2s] - - if: - properties: - function: - const: i2s uartf - then: - properties: - groups: - enum: [uartf] - - if: properties: function: @@ -158,24 +112,6 @@ patternProperties: p2led_kn, p3led_an, p3led_kn, p4led_an, p4led_kn, sdmode] - - if: - properties: - function: - const: mdio - then: - properties: - groups: - enum: [mdio] - - - if: - properties: - function: - const: nand - then: - properties: - groups: - enum: [nd_sd] - - if: properties: function: @@ -266,15 +202,6 @@ patternProperties: groups: enum: [p4led_kn] - - if: - properties: - function: - const: pa - then: - properties: - groups: - enum: [pa] - - if: properties: function: @@ -284,24 +211,6 @@ patternProperties: groups: enum: [gpio] - - if: - properties: - function: - const: pcie refclk - then: - properties: - groups: - enum: [pcie] - - - if: - properties: - function: - const: pcie rst - then: - properties: - groups: - enum: [pcie] - - if: properties: function: @@ -311,33 +220,6 @@ patternProperties: groups: enum: [i2s] - - if: - properties: - function: - const: pcm gpio - then: - properties: - groups: - enum: [uartf] - - - if: - properties: - function: - const: pcm i2s - then: - properties: - groups: - enum: [uartf] - - - if: - properties: - function: - const: pcm uartf - then: - properties: - groups: - enum: [uartf] - - if: properties: function: @@ -390,30 +272,7 @@ patternProperties: then: properties: groups: - anyOf: - - description: For MT7620 SoC - enum: [mdio] - - - description: For MT7628 and MT7688 SoCs - enum: [gpio, refclk, spi cs1] - - - if: - properties: - function: - const: rgmii1 - then: - properties: - groups: - enum: [rgmii1] - - - if: - properties: - function: - const: rgmii2 - then: - properties: - groups: - enum: [rgmii2] + enum: [gpio, refclk, spi cs1] - if: properties: @@ -424,15 +283,6 @@ patternProperties: groups: enum: [p0led_an, p0led_kn, wled_an, wled_kn] - - if: - properties: - function: - const: sd - then: - properties: - groups: - enum: [nd_sd] - - if: properties: function: @@ -487,15 +337,6 @@ patternProperties: groups: enum: [spi cs1] - - if: - properties: - function: - const: spi refclk - then: - properties: - groups: - enum: [spi refclk] - - if: properties: function: @@ -541,24 +382,6 @@ patternProperties: groups: enum: [uart2] - - if: - properties: - function: - const: uartf - then: - properties: - groups: - enum: [uartf] - - - if: - properties: - function: - const: uartlite - then: - properties: - groups: - enum: [uartlite] - - if: properties: function: @@ -578,33 +401,6 @@ patternProperties: groups: enum: [wdt] - - if: - properties: - function: - const: wdt refclk - then: - properties: - groups: - enum: [wdt] - - - if: - properties: - function: - const: wdt rst - then: - properties: - groups: - enum: [wdt] - - - if: - properties: - function: - const: wled - then: - properties: - groups: - enum: [wled] - - if: properties: function: @@ -632,12 +428,8 @@ patternProperties: groups: enum: [i2c, spi cs1, uart0] - additionalProperties: false - - additionalProperties: false - allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -647,7 +439,7 @@ additionalProperties: false examples: - | pinctrl { - compatible = "ralink,mt7620-pinctrl"; + compatible = "ralink,mt76x8-pinctrl"; i2c_pins: i2c0-pins { pinmux { diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7981-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7981-pinctrl.yaml index 74c66fbcb2ae..10717cee9058 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7981-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7981-pinctrl.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt7981-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT7981 Pin Controller +title: MediaTek MT7981 Pin Controller maintainers: - Daniel Golle @@ -37,7 +37,7 @@ properties: "#gpio-cells": const: 2 - description: > + description: Number of cells in GPIO specifier. Since the generic GPIO binding is used, the amount of cells must be specified as 2. See the below mentioned gpio binding representation for description of particular cells. @@ -111,7 +111,9 @@ patternProperties: "watchdog1" "watchdog" 13 "udi" "udi" 9, 10, 11, 12, 13 "drv_vbus" "usb" 14 - "emmc_45" "flash" 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 + "emmc_45" "flash" 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25 + "snfi" "flash" 16, 17, 18, 19, 20, 21 "spi0" "spi" 16, 17, 18, 19 "spi0_wp_hold" "spi" 20, 21 @@ -148,7 +150,7 @@ patternProperties: "wf5g_led0" "led" 31 "wf5g_led1" "led" 35 "mt7531_int" "eth" 38 - "ant_sel" "ant" 14, 15, 16, 17, 18, 19, 20, 21, 22 + "ant_sel" "ant" 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 $ref: /schemas/pinctrl/pinmux-node.yaml @@ -256,7 +258,8 @@ patternProperties: then: properties: groups: - enum: [gbe_led0, gbe_led1, wf2g_led0, wf2g_led1, wf5g_led0, wf5g_led1] + enum: [gbe_led0, gbe_led1, wf2g_led0, wf2g_led1, wf5g_led0, + wf5g_led1] - if: properties: function: @@ -275,7 +278,8 @@ patternProperties: properties: groups: items: - enum: [spi1_0, spi0, spi0_wp_hold, spi1_1, spi2, spi2_wp_hold] + enum: [spi1_0, spi0, spi0_wp_hold, spi1_1, spi2, + spi2_wp_hold] maxItems: 4 - if: properties: @@ -332,13 +336,14 @@ patternProperties: JTAG_JTDO, JTAG_JTDI, JTAG_JTMS, JTAG_JTCLK, JTAG_JTRST_N, WO_JTAG_JTDO, WO_JTAG_JTDI, WO_JTAG_JTMS, WO_JTAG_JTCLK, WO_JTAG_JTRST_N, USB_VBUS, PWM0, SPI0_CLK, SPI0_MOSI, - SPI0_MISO, SPI0_CS, SPI0_HOLD, SPI0_WP, SPI1_CLK, SPI1_MOSI, - SPI1_MISO, SPI1_CS, SPI2_CLK, SPI2_MOSI, SPI2_MISO, SPI2_CS, - SPI2_HOLD, SPI2_WP, UART0_RXD, UART0_TXD, PCIE_CLK_REQ, - PCIE_WAKE_N, SMI_MDC, SMI_MDIO, GBE_INT, GBE_RESET, - WF_DIG_RESETB, WF_CBA_RESETB, WF_XO_REQ, WF_TOP_CLK, - WF_TOP_DATA, WF_HB1, WF_HB2, WF_HB3, WF_HB4, WF_HB0, - WF_HB0_B, WF_HB5, WF_HB6, WF_HB7, WF_HB8, WF_HB9, WF_HB10] + SPI0_MISO, SPI0_CS, SPI0_HOLD, SPI0_WP, SPI1_CLK, + SPI1_MOSI, SPI1_MISO, SPI1_CS, SPI2_CLK, SPI2_MOSI, + SPI2_MISO, SPI2_CS, SPI2_HOLD, SPI2_WP, UART0_RXD, + UART0_TXD, PCIE_CLK_REQ, PCIE_WAKE_N, SMI_MDC, SMI_MDIO, + GBE_INT, GBE_RESET, WF_DIG_RESETB, WF_CBA_RESETB, + WF_XO_REQ, WF_TOP_CLK, WF_TOP_DATA, WF_HB1, WF_HB2, WF_HB3, + WF_HB4, WF_HB0, WF_HB0_B, WF_HB5, WF_HB6, WF_HB7, WF_HB8, + WF_HB9, WF_HB10] maxItems: 57 bias-disable: true @@ -348,7 +353,7 @@ patternProperties: - type: boolean description: normal pull up. - enum: [100, 101, 102, 103] - description: > + description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0 defines in dt-bindings/pinctrl/mt65xx.h. @@ -357,7 +362,7 @@ patternProperties: - type: boolean description: normal pull down. - enum: [100, 101, 102, 103] - description: > + description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0 defines in dt-bindings/pinctrl/mt65xx.h. diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml index 216b356cd519..0f615ada290a 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt7986-pinctrl.yaml @@ -4,12 +4,12 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt7986-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT7986 Pin Controller +title: MediaTek MT7986 Pin Controller maintainers: - Sean Wang -description: |+ +description: The MediaTek's MT7986 Pin controller is used to control SoC pins. properties: @@ -37,15 +37,15 @@ properties: "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. gpio-ranges: minItems: 1 maxItems: 5 - description: | + description: GPIO valid number range. interrupt-controller: true @@ -57,7 +57,7 @@ properties: const: 2 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -72,7 +72,7 @@ patternProperties: additionalProperties: false patternProperties: - '.*mux.*': + '^.*mux.*$': type: object additionalProperties: false description: | @@ -81,7 +81,7 @@ patternProperties: The following table shows the effective values of "group", "function" properties and chip pinout pins - groups function pins (in pin#) + groups function pins (in pin#) --------------------------------------------------------------------- "watchdog" "watchdog" 0 "wifi_led" "led" 1, 2 @@ -97,8 +97,9 @@ patternProperties: "pwm1_0" "pwm" 22, "snfi" "flash" 23, 24, 25, 26, 27, 28 "spi1_2" "spi" 29, 30, 31, 32 - "emmc_45" "emmc" 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32 + "emmc_45" "emmc" 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32 + "spi1_1" "spi" 23, 24, 25, 26 "uart1_2_rx_tx" "uart" 29, 30 "uart1_2_cts_rts" "uart" 31, 32 @@ -115,8 +116,9 @@ patternProperties: "pcie_pereset" "pcie" 41 "uart1" "uart" 42, 43, 44, 45 "uart2" "uart" 46, 47, 48, 49 - "emmc_51" "emmc" 50, 51, 52, 53, 54, 55, 56, 57, 57, - 59, 60, 61 + "emmc_51" "emmc" 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61 + "pcm" "audio" 62, 63, 64, 65 "i2s" "audio" 62, 63, 64, 65 "switch_int" "eth" 66 @@ -126,21 +128,20 @@ patternProperties: "wf_dbdc" "wifi" 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85 - $ref: "/schemas/pinctrl/pinmux-node.yaml" + $ref: /schemas/pinctrl/pinmux-node.yaml properties: function: - description: | + description: A string containing the name of the function to mux to the group. There is no "audio", "pcie" functions on mt7986b, you can only use those functions on mt7986a. enum: [audio, emmc, eth, i2c, led, flash, pcie, pwm, spi, uart, watchdog, wifi] groups: - description: | + description: An array of strings. Each string contains the name of a group. - There is no "pcie_pereset", "uart1", "uart2" "emmc_51", "pcm", - and "i2s" groups on mt7986b, you can only use those groups on - mt7986a. + There is no "pcie_pereset", "uart1", "uart2" "emmc_51", "pcm", and + "i2s" groups on mt7986b, you can only use those groups on mt7986a. required: - function - groups @@ -255,32 +256,33 @@ patternProperties: items: enum: [wf_2g, wf_5g, wf_dbdc] maxItems: 3 - '.*conf.*': + '^.*conf.*$': type: object additionalProperties: false - description: | + description: pinconf configuration nodes. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pins: - description: | - An array of strings. Each string contains the name of a pin. - There is no PIN 41 to PIN 65 above on mt7686b, you can only use - those pins on mt7986a. + description: + An array of strings. Each string contains the name of a pin. There + is no PIN 41 to PIN 65 above on mt7686b, you can only use those + pins on mt7986a. items: enum: [SYS_WATCHDOG, WF2G_LED, WF5G_LED, I2C_SCL, I2C_SDA, GPIO_0, GPIO_1, GPIO_2, GPIO_3, GPIO_4, GPIO_5, GPIO_6, GPIO_7, - GPIO_8, GPIO_9, GPIO_10, GPIO_11, GPIO_12, GPIO_13, GPIO_14, - GPIO_15, PWM0, PWM1, SPI0_CLK, SPI0_MOSI, SPI0_MISO, SPI0_CS, - SPI0_HOLD, SPI0_WP, SPI1_CLK, SPI1_MOSI, SPI1_MISO, SPI1_CS, - SPI2_CLK, SPI2_MOSI, SPI2_MISO, SPI2_CS, SPI2_HOLD, SPI2_WP, - UART0_RXD, UART0_TXD, PCIE_PERESET_N, UART1_RXD, UART1_TXD, - UART1_CTS, UART1_RTS, UART2_RXD, UART2_TXD, UART2_CTS, - UART2_RTS, EMMC_DATA_0, EMMC_DATA_1, EMMC_DATA_2, - EMMC_DATA_3, EMMC_DATA_4, EMMC_DATA_5, EMMC_DATA_6, - EMMC_DATA_7, EMMC_CMD, EMMC_CK, EMMC_DSL, EMMC_RSTB, PCM_DTX, - PCM_DRX, PCM_CLK, PCM_FS, MT7531_INT, SMI_MDC, SMI_MDIO, + GPIO_8, GPIO_9, GPIO_10, GPIO_11, GPIO_12, GPIO_13, + GPIO_14, GPIO_15, PWM0, PWM1, SPI0_CLK, SPI0_MOSI, + SPI0_MISO, SPI0_CS, SPI0_HOLD, SPI0_WP, SPI1_CLK, + SPI1_MOSI, SPI1_MISO, SPI1_CS, SPI2_CLK, SPI2_MOSI, + SPI2_MISO, SPI2_CS, SPI2_HOLD, SPI2_WP, UART0_RXD, + UART0_TXD, PCIE_PERESET_N, UART1_RXD, UART1_TXD, UART1_CTS, + UART1_RTS, UART2_RXD, UART2_TXD, UART2_CTS, UART2_RTS, + EMMC_DATA_0, EMMC_DATA_1, EMMC_DATA_2, EMMC_DATA_3, + EMMC_DATA_4, EMMC_DATA_5, EMMC_DATA_6, EMMC_DATA_7, + EMMC_CMD, EMMC_CK, EMMC_DSL, EMMC_RSTB, PCM_DTX, PCM_DRX, + PCM_CLK, PCM_FS, MT7531_INT, SMI_MDC, SMI_MDIO, WF0_DIG_RESETB, WF0_CBA_RESETB, WF0_XO_REQ, WF0_TOP_CLK, WF0_TOP_DATA, WF0_HB1, WF0_HB2, WF0_HB3, WF0_HB4, WF0_HB0, WF0_HB0_B, WF0_HB5, WF0_HB6, WF0_HB7, WF0_HB8, WF0_HB9, @@ -297,7 +299,7 @@ patternProperties: - type: boolean description: normal pull up. - enum: [100, 101, 102, 103] - description: | + description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0 defines in dt-bindings/pinctrl/mt65xx.h. @@ -306,7 +308,7 @@ patternProperties: - type: boolean description: normal pull down. - enum: [100, 101, 102, 103] - description: | + description: PUPD/R1/R0 pull down type. See MTK_PUPD_SET_R1R0 defines in dt-bindings/pinctrl/mt65xx.h. diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml index c30cd0d010dd..ff24cf29eea7 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml @@ -4,12 +4,12 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt8183-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT8183 Pin Controller +title: MediaTek MT8183 Pin Controller maintainers: - Sean Wang -description: |+ +description: The MediaTek's MT8183 Pin controller is used to control SoC pins. properties: @@ -37,15 +37,15 @@ properties: "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. gpio-ranges: minItems: 1 maxItems: 5 - description: | + description: GPIO valid number range. interrupt-controller: true @@ -57,7 +57,7 @@ properties: const: 2 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -74,18 +74,18 @@ patternProperties: '^pins': type: object additionalProperties: false - description: | + description: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer configuration, pullups, drive strength, input enable/disable and input schmitt. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pinmux: description: - integer array, represents gpio pin number and mux setting. + Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are defined as macros in -pinfunc.h directly. @@ -110,8 +110,13 @@ patternProperties: drive-strength: enum: [2, 4, 6, 8, 10, 12, 14, 16] + drive-strength-microamp: + enum: [125, 250, 500, 1000] + mediatek,drive-strength-adv: + deprecated: true description: | + DEPRECATED: Please use drive-strength-microamp instead. 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 @@ -139,7 +144,8 @@ patternProperties: mediatek,pull-up-adv: description: | Pull up setings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -150,7 +156,8 @@ patternProperties: mediatek,pull-down-adv: description: | Pull down settings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -159,14 +166,14 @@ patternProperties: enum: [0, 1, 2, 3] mediatek,tdsel: - description: | + description: An integer describing the steps for output level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 15. $ref: /schemas/types.yaml#/definitions/uint32 mediatek,rdsel: - description: | + description: An integer describing the steps for input level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 63. @@ -215,7 +222,7 @@ examples: pinmux = , ; mediatek,pull-up-adv = <3>; - mediatek,drive-strength-adv = <7>; + drive-strength-microamp = <1000>; }; }; @@ -224,7 +231,6 @@ examples: pinmux = , ; mediatek,pull-down-adv = <2>; - mediatek,drive-strength-adv = <4>; }; }; }; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8186.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8186-pinctrl.yaml similarity index 87% rename from Documentation/devicetree/bindings/pinctrl/pinctrl-mt8186.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt8186-pinctrl.yaml index 26573a793b57..69136ddd0bbc 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8186.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8186-pinctrl.yaml @@ -1,16 +1,16 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/pinctrl-mt8186.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt8186-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT8186 Pin Controller +title: MediaTek MT8186 Pin Controller maintainers: - Sean Wang -description: | - The Mediatek's Pin controller is used to control SoC pins. +description: + The MediaTek's MT8186 Pin controller is used to control SoC pins. properties: compatible: @@ -19,10 +19,10 @@ properties: gpio-controller: true '#gpio-cells': - description: | + description: Number of cells in GPIO specifier. Since the generic GPIO binding is used, - the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. const: 2 gpio-ranges: @@ -31,14 +31,14 @@ properties: gpio-line-names: true reg: - description: | - Physical address base for gpio base registers. There are 8 different GPIO + description: + Physical address base for GPIO base registers. There are 8 different GPIO physical address base in mt8186. maxItems: 8 reg-names: - description: | - Gpio base register names. + description: + GPIO base register names. items: - const: iocfg0 - const: iocfg_lt @@ -60,9 +60,9 @@ properties: mediatek,rsel-resistance-in-si-unit: type: boolean - description: | - Identifying i2c pins pull up/down type which is RSEL. It can support - RSEL define or si unit value(ohm) to set different resistance. + description: + Identifying i2c pins pull up/down type which is RSEL. It can support RSEL + define or si unit value(ohm) to set different resistance. # PIN CONFIGURATION NODES patternProperties: @@ -77,8 +77,8 @@ patternProperties: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and - input schmitt. + configuration, pullups, drive strength, input enable/disable and input + schmitt. An example of using macro: pincontroller { /* GPIO0 set as multifunction GPIO0 */ @@ -94,15 +94,14 @@ patternProperties: } }; }; - $ref: "pinmux-node.yaml" + $ref: pinmux-node.yaml properties: pinmux: - description: | + description: Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are - defined as macros in dt-bindings/pinctrl/-pinfunc.h - directly. + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. drive-strength: enum: [2, 4, 6, 8, 10, 12, 14, 16] @@ -129,10 +128,10 @@ patternProperties: 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". - It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001" - & "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011" - define in mt8186. It can also support resistance value(ohm) - "75000" & "5000" in mt8186. + It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001" & + "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011" define in + mt8186. It can also support resistance value(ohm) "75000" & "5000" + in mt8186. An example of using RSEL define: pincontroller { i2c0_pin { @@ -174,10 +173,10 @@ patternProperties: 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". - It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001" - & "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011" - define in mt8186. It can also support resistance value(ohm) - "1000" & "5000" & "10000" & "75000" in mt8186. + It can support "MTK_PULL_SET_RSEL_000" & "MTK_PULL_SET_RSEL_001" & + "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011" define in + mt8186. It can also support resistance value(ohm) "1000" & "5000" + & "10000" & "75000" in mt8186. An example of using si unit resistance value(ohm): &pio { mediatek,rsel-resistance-in-si-unit; diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8188-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8188-pinctrl.yaml index 7e750f1e643d..e994b0c70dbf 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8188-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8188-pinctrl.yaml @@ -9,7 +9,7 @@ title: MediaTek MT8188 Pin Controller maintainers: - Hui Liu -description: | +description: The MediaTek's MT8188 Pin controller is used to control SoC pins. properties: @@ -19,10 +19,10 @@ properties: gpio-controller: true '#gpio-cells': - description: | - Number of cells in GPIO specifier, should be two. The first cell - is the pin number, the second cell is used to specify optional - parameters which are defined in . + description: + Number of cells in GPIO specifier, should be two. The first cell is the + pin number, the second cell is used to specify optional parameters which + are defined in . const: 2 gpio-ranges: @@ -59,10 +59,11 @@ properties: mediatek,rsel-resistance-in-si-unit: type: boolean - description: | - We provide two methods to select the resistance for I2C when pull up or pull down. - The first is by RSEL definition value, another one is by resistance value(ohm). - This flag is used to identify if the method is resistance(si unit) value. + description: + We provide two methods to select the resistance for I2C when pull up or + pull down. The first is by RSEL definition value, another one is by + resistance value(ohm). This flag is used to identify if the method is + resistance(si unit) value. # PIN CONFIGURATION NODES patternProperties: @@ -73,22 +74,22 @@ patternProperties: patternProperties: '^pins': type: object - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml additionalProperties: false - description: | + description: A pinctrl node should contain at least one subnode representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and - input schmitt. + configuration, pullups, drive strength, input enable/disable and input + schmitt. properties: pinmux: - description: | + description: Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are - defined as macros in dt-bindings/pinctrl/mediatek,-pinfunc.h - directly. + defined as macros in dt-bindings/pinctrl/mediatek,mt8188-pinfunc.h + directly, for this SoC. drive-strength: enum: [2, 4, 6, 8, 10, 12, 14, 16] @@ -106,18 +107,21 @@ patternProperties: - enum: [75000, 5000] description: mt8188 pull down RSEL type si unit value(ohm). description: | - For pull down type is normal, it doesn't need add RSEL & R1R0 define - and resistance value. + For pull down type is normal, it doesn't need add RSEL & R1R0 + define and resistance value. For pull down type is PUPD/R0/R1 type, it can add R1R0 define to set different resistance. It can support "MTK_PUPD_SET_R1R0_00" & - "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" & "MTK_PUPD_SET_R1R0_11" - define in mt8188. - 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". - 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" & "MTK_PULL_SET_RSEL_110" & "MTK_PULL_SET_RSEL_111" - define in mt8188. It can also support resistance value(ohm) "75000" & "5000" in mt8188. + "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" & + "MTK_PUPD_SET_R1R0_11" define in mt8188. + 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". 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" & + "MTK_PULL_SET_RSEL_110" & "MTK_PULL_SET_RSEL_111" define in + mt8188. It can also support resistance value(ohm) "75000" & "5000" + in mt8188. bias-pull-up: oneOf: @@ -131,17 +135,19 @@ patternProperties: description: | For pull up type is normal, it don't need add RSEL & R1R0 define and resistance value. - For pull up type is PUPD/R0/R1 type, it can add R1R0 define to - set different resistance. It can support "MTK_PUPD_SET_R1R0_00" & - "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" & "MTK_PUPD_SET_R1R0_11" - define in mt8188. - 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". - 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" & "MTK_PULL_SET_RSEL_110" & "MTK_PULL_SET_RSEL_111" - define in mt8188. It can also support resistance value(ohm) - "1000" & "1500" & "2000" & "3000" & "4000" & "5000" & "10000" & "75000" in mt8188. + For pull up type is PUPD/R0/R1 type, it can add R1R0 define to set + different resistance. It can support "MTK_PUPD_SET_R1R0_00" & + "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" & + "MTK_PUPD_SET_R1R0_11" define in mt8188. + 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". 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" & + "MTK_PULL_SET_RSEL_110" & "MTK_PULL_SET_RSEL_111" define in + mt8188. It can also support resistance value(ohm) "1000" & "1500" + & "2000" & "3000" & "4000" & "5000" & "10000" & "75000" in mt8188. bias-disable: true diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8192.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8192-pinctrl.yaml similarity index 81% rename from Documentation/devicetree/bindings/pinctrl/pinctrl-mt8192.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt8192-pinctrl.yaml index a09ebbfec574..1686427eb854 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8192.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8192-pinctrl.yaml @@ -1,16 +1,16 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/pinctrl-mt8192.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt8192-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT8192 Pin Controller +title: MediaTek MT8192 Pin Controller maintainers: - Sean Wang -description: | - The Mediatek's Pin controller is used to control SoC pins. +description: + The MediaTek's MT8192 Pin controller is used to control SoC pins. properties: compatible: @@ -19,27 +19,27 @@ properties: gpio-controller: true '#gpio-cells': - description: | + description: Number of cells in GPIO specifier. Since the generic GPIO binding is used, - the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. const: 2 gpio-ranges: - description: gpio valid number range. + description: GPIO valid number range. maxItems: 1 gpio-line-names: true reg: - description: | - Physical address base for gpio base registers. There are 11 GPIO - physical address base in mt8192. + description: + Physical address base for GPIO base registers. There are 11 GPIO physical + address base in mt8192. maxItems: 11 reg-names: - description: | - Gpio base register names. + description: + GPIO base register names. maxItems: 11 interrupt-controller: true @@ -59,25 +59,26 @@ patternProperties: patternProperties: '^pins': type: object - description: | + description: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and - input schmitt. - $ref: "pinmux-node.yaml" + configuration, pullups, drive strength, input enable/disable and input + schmitt. + $ref: pinmux-node.yaml properties: pinmux: - description: | + description: Integer array, represents gpio pin number and mux setting. - Supported pin number and mux varies for different SoCs, and are defined - as macros in dt-bindings/pinctrl/-pinfunc.h directly. + Supported pin number and mux varies for different SoCs, and are + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. drive-strength: - description: | - It can support some arguments, such as MTK_DRIVE_4mA, MTK_DRIVE_6mA, etc. See - dt-bindings/pinctrl/mt65xx.h. It can only support 2/4/6/8/10/12/14/16mA in mt8192. + description: + It can support some arguments, such as MTK_DRIVE_4mA, + MTK_DRIVE_6mA, etc. See 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] drive-strength-microamp: @@ -91,8 +92,8 @@ patternProperties: 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. + description: RSEL pull down type. See MTK_PULL_SET_RSEL_ defines + in dt-bindings/pinctrl/mt65xx.h. bias-pull-up: oneOf: @@ -102,8 +103,8 @@ patternProperties: 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. + description: RSEL pull up type. See MTK_PULL_SET_RSEL_ defines + in dt-bindings/pinctrl/mt65xx.h. bias-disable: true @@ -125,7 +126,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8195-pinctrl.yaml similarity index 89% rename from Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml rename to Documentation/devicetree/bindings/pinctrl/mediatek,mt8195-pinctrl.yaml index 66fe17e9e4d3..33cb71775db9 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8195-pinctrl.yaml @@ -1,16 +1,16 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/pinctrl/pinctrl-mt8195.yaml# +$id: http://devicetree.org/schemas/pinctrl/mediatek,mt8195-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT8195 Pin Controller +title: MediaTek MT8195 Pin Controller maintainers: - Sean Wang -description: | - The Mediatek's Pin controller is used to control SoC pins. +description: + The MediaTek's MT8195 Pin controller is used to control SoC pins. properties: compatible: @@ -19,27 +19,27 @@ properties: gpio-controller: true '#gpio-cells': - description: | + description: Number of cells in GPIO specifier. Since the generic GPIO binding is used, - the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. const: 2 gpio-ranges: - description: gpio valid number range. + description: GPIO valid number range. maxItems: 1 gpio-line-names: true reg: - description: | - Physical address base for gpio base registers. There are 8 GPIO - physical address base in mt8195. + description: + Physical address base for GPIO base registers. There are 8 GPIO physical + address base in mt8195. maxItems: 8 reg-names: - description: | - Gpio base register names. + description: + GPIO base register names. maxItems: 8 interrupt-controller: true @@ -53,9 +53,9 @@ properties: mediatek,rsel-resistance-in-si-unit: type: boolean - description: | - Identifying i2c pins pull up/down type which is RSEL. It can support - RSEL define or si unit value(ohm) to set different resistance. + description: + Identifying i2c pins pull up/down type which is RSEL. It can support RSEL + define or si unit value(ohm) to set different resistance. # PIN CONFIGURATION NODES patternProperties: @@ -70,8 +70,8 @@ patternProperties: A pinctrl node should contain at least one subnodes representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer - configuration, pullups, drive strength, input enable/disable and - input schmitt. + configuration, pullups, drive strength, input enable/disable and input + schmitt. An example of using macro: pincontroller { /* GPIO0 set as multifunction GPIO0 */ @@ -87,15 +87,14 @@ patternProperties: } }; }; - $ref: "pinmux-node.yaml" + $ref: pinmux-node.yaml properties: pinmux: - description: | + description: Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are - defined as macros in dt-bindings/pinctrl/-pinfunc.h - directly. + defined as macros in dt-bindings/pinctrl/-pinfunc.h directly. drive-strength: enum: [2, 4, 6, 8, 10, 12, 14, 16] @@ -174,9 +173,9 @@ patternProperties: & "MTK_PULL_SET_RSEL_010" & "MTK_PULL_SET_RSEL_011" & "MTK_PULL_SET_RSEL_100" & "MTK_PULL_SET_RSEL_101" & "MTK_PULL_SET_RSEL_110" & "MTK_PULL_SET_RSEL_111" - define in mt8195. It can also support resistance value(ohm) - "1000" & "1500" & "2000" & "3000" & "4000" & "5000" & "10000" & - "75000" in mt8195. + define in mt8195. It can also support resistance value(ohm) "1000" + & "1500" & "2000" & "3000" & "4000" & "5000" & "10000" & "75000" + in mt8195. An example of using RSEL define: pincontroller { i2c0-pins { @@ -217,7 +216,7 @@ patternProperties: - pinmux allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8365-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8365-pinctrl.yaml index 4b96884a1afc..61b33b5416f5 100644 --- a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8365-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8365-pinctrl.yaml @@ -4,13 +4,13 @@ $id: http://devicetree.org/schemas/pinctrl/mediatek,mt8365-pinctrl.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Mediatek MT8365 Pin Controller +title: MediaTek MT8365 Pin Controller maintainers: - Zhiyong Tao - Bernhard Rosenkränzer -description: | +description: The MediaTek's MT8365 Pin controller is used to control SoC pins. properties: @@ -26,17 +26,17 @@ properties: maxItems: 1 minItems: 1 maxItems: 2 - description: | + description: Should be phandles of the syscfg node. gpio-controller: true "#gpio-cells": const: 2 - description: | - Number of cells in GPIO specifier. Since the generic GPIO - binding is used, the amount of cells must be specified as 2. See the below - mentioned gpio binding representation for description of particular cells. + description: + Number of cells in GPIO specifier. Since the generic GPIO binding is used, + the amount of cells must be specified as 2. See the below mentioned gpio + binding representation for description of particular cells. interrupt-controller: true @@ -54,7 +54,7 @@ patternProperties: "pins$": type: object additionalProperties: false - description: | + description: A pinctrl node should contain at least one subnode representing the pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer @@ -65,19 +65,42 @@ patternProperties: properties: pinmux: description: - integer array, represents gpio pin number and mux setting. + Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are defined as macros in -pinfunc.h directly. bias-disable: true bias-pull-up: + oneOf: + - type: boolean + - enum: [100, 101, 102, 103] + description: Pull up R1/R0 type define value. description: | - Besides generic pinconfig options, it can be used as the pull up - settings for 2 pull resistors, R0 and R1. User can configure those - special pins. + For pull up type is normal, it don't need add R1/R0 define. + For pull up type is R1/R0 type, it can add value to set different + resistance. Valid arguments are described as below: + 100: (R1, R0) = (0, 0) which means R1 disabled and R0 disabled. + 101: (R1, R0) = (0, 1) which means R1 disabled and R0 enabled. + 102: (R1, R0) = (1, 0) which means R1 enabled and R0 disabled. + 103: (R1, R0) = (1, 1) which means R1 enabled and R0 enabled. - bias-pull-down: true + bias-pull-down: + oneOf: + - type: boolean + - enum: [100, 101, 102, 103] + description: Pull down R1/R0 type define value. + description: | + For pull down type is normal, it don't need add R1/R0 define. + For pull down type is R1/R0 type, it can add value to set + different resistance. Valid arguments are described as below: + 100: (R1, R0) = (0, 0) which means R1 disabled and R0 disabled. + 101: (R1, R0) = (0, 1) which means R1 disabled and R0 enabled. + 102: (R1, R0) = (1, 0) which means R1 enabled and R0 disabled. + 103: (R1, R0) = (1, 1) which means R1 enabled and R0 enabled. + + drive-strength: + enum: [2, 4, 6, 8, 10, 12, 14, 16] input-enable: true @@ -91,8 +114,13 @@ patternProperties: input-schmitt-disable: true + drive-strength-microamp: + enum: [125, 250, 500, 1000] + mediatek,drive-strength-adv: + deprecated: true description: | + DEPRECATED: Please use drive-strength-microamp instead. 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 @@ -118,9 +146,12 @@ patternProperties: enum: [0, 1, 2, 3, 4, 5, 6, 7] mediatek,pull-up-adv: + deprecated: true description: | + DEPRECATED: Please use bias-pull-up instead. Pull up setings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -129,9 +160,12 @@ patternProperties: enum: [0, 1, 2, 3] mediatek,pull-down-adv: + deprecated: true description: | + DEPRECATED: Please use bias-pull-down instead. Pull down settings for 2 pull resistors, R0 and R1. User can - configure those special pins. Valid arguments are described as below: + 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. @@ -140,14 +174,14 @@ patternProperties: enum: [0, 1, 2, 3] mediatek,tdsel: - description: | + description: An integer describing the steps for output level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 15. $ref: /schemas/types.yaml#/definitions/uint32 mediatek,rdsel: - description: | + description: An integer describing the steps for input level shifter duty cycle when asserted (high pulse width adjustment). Valid arguments are from 0 to 63. @@ -189,7 +223,6 @@ examples: pins { pinmux = , ; mediatek,pull-up-adv = <3>; - mediatek,drive-strength-adv = <00>; bias-pull-up; }; }; diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt deleted file mode 100644 index 8146193bd8ac..000000000000 --- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +++ /dev/null @@ -1,94 +0,0 @@ -== Amlogic Meson pinmux controller == - -Required properties for the root node: - - compatible: one of "amlogic,meson8-cbus-pinctrl" - "amlogic,meson8b-cbus-pinctrl" - "amlogic,meson8m2-cbus-pinctrl" - "amlogic,meson8-aobus-pinctrl" - "amlogic,meson8b-aobus-pinctrl" - "amlogic,meson8m2-aobus-pinctrl" - "amlogic,meson-gxbb-periphs-pinctrl" - "amlogic,meson-gxbb-aobus-pinctrl" - "amlogic,meson-gxl-periphs-pinctrl" - "amlogic,meson-gxl-aobus-pinctrl" - "amlogic,meson-axg-periphs-pinctrl" - "amlogic,meson-axg-aobus-pinctrl" - "amlogic,meson-g12a-periphs-pinctrl" - "amlogic,meson-g12a-aobus-pinctrl" - "amlogic,meson-a1-periphs-pinctrl" - "amlogic,meson-s4-periphs-pinctrl" - - reg: address and size of registers controlling irq functionality - -=== GPIO sub-nodes === - -The GPIO bank for the controller is represented as a sub-node and it acts as a -GPIO controller. - -Required properties for sub-nodes are: - - reg: should contain a list of address and size, one tuple for each entry - in reg-names. - - reg-names: an array of strings describing the "reg" entries. - Must contain "mux" and "gpio". - May contain "pull", "pull-enable" and "ds" when appropriate. - - gpio-controller: identifies the node as a gpio controller - - #gpio-cells: must be 2 - -=== Other sub-nodes === - -Child nodes without the "gpio-controller" represent some desired -configuration for a pin or a group. Those nodes can be pinmux nodes or -configuration nodes. - -Required properties for pinmux nodes are: - - groups: a list of pinmux groups. The list of all available groups - depends on the SoC and can be found in driver sources. - - function: the name of a function to activate for the specified set - of groups. The list of all available functions depends on the SoC - and can be found in driver sources. - -Required properties for configuration nodes: - - pins: a list of pin names - -Configuration nodes support the following generic properties, as -described in file pinctrl-bindings.txt: - - "bias-disable" - - "bias-pull-up" - - "bias-pull-down" - - "output-enable" - - "output-disable" - - "output-low" - - "output-high" - -Optional properties : - - drive-strength-microamp: Drive strength for the specified pins in uA. - This property is only valid for G12A and newer. - -=== Example === - - pinctrl: pinctrl@c1109880 { - compatible = "amlogic,meson8-cbus-pinctrl"; - reg = <0xc1109880 0x10>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - gpio: banks@c11080b0 { - reg = <0xc11080b0 0x28>, - <0xc11080e8 0x18>, - <0xc1108120 0x18>, - <0xc1108030 0x30>; - reg-names = "mux", "pull", "pull-enable", "gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - nand { - mux { - groups = "nand_io", "nand_io_ce0", "nand_io_ce1", - "nand_io_rb0", "nand_ale", "nand_cle", - "nand_wen_clk", "nand_ren_clk", "nand_dqs", - "nand_ce2", "nand_ce3"; - function = "nand"; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml index 98d547c34ef3..dbb3e1bd58c1 100644 --- a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml @@ -54,8 +54,8 @@ patternProperties: '-pins$': type: object allOf: - - $ref: "pinmux-node.yaml" - - $ref: "pincfg-node.yaml" + - $ref: pinmux-node.yaml + - $ref: pincfg-node.yaml properties: function: true @@ -78,7 +78,7 @@ required: - gpio-ranges allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml new file mode 100644 index 000000000000..d49aafd8c5f4 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2022 NXP +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/nxp,s32g2-siul2-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP S32G2 pin controller + +maintainers: + - Ghennadi Procopciuc + - Chester Lin + +description: | + S32G2 pinmux is implemented in SIUL2 (System Integration Unit Lite2), + whose memory map is split into two regions: + SIUL2_0 @ 0x4009c000 + SIUL2_1 @ 0x44010000 + + Every SIUL2 region has multiple register types, and here only MSCR and + IMCR registers need to be revealed for kernel to configure pinmux. + + Please note that some register indexes are reserved in S32G2, such as + MSCR102-MSCR111, MSCR123-MSCR143, IMCR84-IMCR118 and IMCR398-IMCR429. + +properties: + compatible: + enum: + - nxp,s32g2-siul2-pinctrl + + reg: + description: | + A list of MSCR/IMCR register regions to be reserved. + - MSCR (Multiplexed Signal Configuration Register) + An MSCR register can configure the associated pin as either a GPIO pin + or a function output pin depends on the selected signal source. + - IMCR (Input Multiplexed Signal Configuration Register) + An IMCR register can configure the associated pin as function input + pin depends on the selected signal source. + items: + - description: MSCR registers group 0 in SIUL2_0 + - description: MSCR registers group 1 in SIUL2_1 + - description: MSCR registers group 2 in SIUL2_1 + - description: IMCR registers group 0 in SIUL2_0 + - description: IMCR registers group 1 in SIUL2_1 + - description: IMCR registers group 2 in SIUL2_1 + +patternProperties: + '-pins$': + type: object + additionalProperties: false + + patternProperties: + '-grp[0-9]$': + type: object + allOf: + - $ref: pinmux-node.yaml# + - $ref: pincfg-node.yaml# + description: | + Pinctrl node's client devices specify pin muxes using subnodes, + which in turn use the standard properties below. + + properties: + bias-disable: true + bias-high-impedance: true + bias-pull-up: true + bias-pull-down: true + drive-open-drain: true + input-enable: true + output-enable: true + + pinmux: + description: | + An integer array for representing pinmux configurations of + a device. Each integer consists of a PIN_ID and a 4-bit + selected signal source(SSS) as IOMUX setting, which is + calculated as: pinmux = (PIN_ID << 4 | SSS) + + slew-rate: + description: Supported slew rate based on Fmax values (MHz) + enum: [83, 133, 150, 166, 208] + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pinctrl@4009c240 { + compatible = "nxp,s32g2-siul2-pinctrl"; + + /* MSCR0-MSCR101 registers on siul2_0 */ + reg = <0x4009c240 0x198>, + /* MSCR112-MSCR122 registers on siul2_1 */ + <0x44010400 0x2c>, + /* MSCR144-MSCR190 registers on siul2_1 */ + <0x44010480 0xbc>, + /* IMCR0-IMCR83 registers on siul2_0 */ + <0x4009ca40 0x150>, + /* IMCR119-IMCR397 registers on siul2_1 */ + <0x44010c1c 0x45c>, + /* IMCR430-IMCR495 registers on siul2_1 */ + <0x440110f8 0x108>; + + llce-can0-pins { + llce-can0-grp0 { + pinmux = <0x2b0>; + input-enable; + slew-rate = <208>; + }; + + llce-can0-grp1 { + pinmux = <0x2c2>; + output-enable; + slew-rate = <208>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml index 300747252a7b..3d3086ae1ba6 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml @@ -56,6 +56,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -92,19 +93,9 @@ $defs: rx1, sdc_data, sdc_clk, sdc_cmd, tsens_max, wci_txd, wci_rxd, wsi_clk, wsi_clk3, wsi_data, wsi_data3, wsis_reset, xfem ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml index 28f1b6a07b70..7c3e5e043f07 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml @@ -43,6 +43,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -89,18 +90,9 @@ $defs: sd_write, sec_mi2s, smb_int, ssbi_wtr0, ssbi_wtr1, uim1, uim2, uim3, uim_batt, wcss_bt, wcss_fm, wcss_wlan, webcam1_rst ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml index 3137db927fc0..e053fbd588b5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -92,19 +93,9 @@ $defs: qdss_tracedata_b, qpic, rx0, rx1, rx2, sd_card, sd_write, tsens_max, wci2a, wci2b, wci2c, wci2d ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml new file mode 100644 index 000000000000..673713debac2 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,ipq9574-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. IPQ9574 TLMM block + +maintainers: + - Bjorn Andersson + - Krzysztof Kozlowski + +description: + Top Level Mode Multiplexer pin controller in Qualcomm IPQ9574 SoC. + +properties: + compatible: + const: qcom,ipq9574-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + "#interrupt-cells": true + gpio-controller: true + "#gpio-cells": true + gpio-ranges: true + wakeup-parent: true + + gpio-reserved-ranges: + minItems: 1 + maxItems: 33 + + gpio-line-names: + maxItems: 65 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-ipq9574-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-ipq9574-tlmm-state" + additionalProperties: false + +$defs: + qcom-ipq9574-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: + pattern: "^gpio([0-9]|[1-5][0-9]|6[0-4])$" + minItems: 1 + maxItems: 8 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + + enum: [ atest_char, atest_char0, atest_char1, atest_char2, atest_char3, + audio_pdm0, audio_pdm1, audio_pri, audio_sec, blsp0_spi, blsp0_uart, + blsp1_i2c, blsp1_spi, blsp1_uart, blsp2_i2c, blsp2_spi, + blsp2_uart, blsp3_i2c, blsp3_spi, blsp3_uart, blsp4_i2c, + blsp4_spi, blsp4_uart, blsp5_i2c, blsp5_uart, cri_trng0, + cri_trng1, cri_trng2, cri_trng3, cxc0, cxc1, dbg_out, dwc_ddrphy, + gcc_plltest, gcc_tlmm, gpio, mac, mdc, mdio, pcie0_clk, pcie0_wake, + pcie1_clk, pcie1_wake, pcie2_clk, pcie2_wake, pcie3_clk, pcie3_wake, + prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, pta, pwm, + 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_traceclk_b, qdss_tracectl_a, qdss_tracectl_b, qdss_tracedata_a, + qdss_tracedata_b, qspi_clk, qspi_cs, qspi_data, + rx0, rx1, sdc_clk, sdc_cmd, sdc_data, sdc_rclk, tsens_max, + wci20, wci21, wsa_swrm ] + + bias-pull-down: true + bias-pull-up: true + bias-disable: true + drive-strength: true + input-enable: true + output-high: true + output-low: true + + required: + - pins + + additionalProperties: false + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + tlmm: pinctrl@1000000 { + compatible = "qcom,ipq9574-tlmm"; + reg = <0x01000000 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 65>; + + uart2-state { + pins = "gpio34", "gpio35"; + function = "blsp2_uart"; + drive-strength = <8>; + bias-pull-down; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml index 96b598bf9a76..2aedb7e7bc8b 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml @@ -54,6 +54,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -105,19 +106,9 @@ $defs: uim1_clk, uim1_data, uim1_present, uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset, uim_batt, wlan_en1, ] - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml index c7c94d742ed2..5885aee95c98 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml @@ -51,6 +51,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -70,19 +71,9 @@ $defs: enum: [ gpio, gsbi2_i2c, gsbi3, gsbi4, gsbi5_i2c, gsbi5_uart, sdc2, ebi2_lcdc, ps_hold, prim_audio, sec_audio, cdc_mclk, ] - bias-disable: true - bias-pull-down: true - bias-pull-up: true - drive-strength: true - output-high: true - output-low: true - input-enable: true - required: - pins - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml index 6cb667fa8665..9efb76509580 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml @@ -48,6 +48,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -71,19 +72,9 @@ $defs: blsp_uart3, blsp_uart4, blsp_uart5, cam_mclk0, cam_mclk1, gp0_clk, gp1_clk, sdc3, wlan ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml index 348d84c3cd21..a05971611780 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -81,20 +82,9 @@ $defs: sdc5, tsif1, tsif2, usb_fs1, usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm, ebi2, ebi2cs ] - - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml index 85082adc1811..5095e86fe9a2 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml @@ -55,6 +55,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -104,19 +105,9 @@ $defs: 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml index 633c9e5ed49e..063d004967bb 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -103,19 +104,9 @@ $defs: uim1, uim2, uim3, uim_batt, wcss_bt, wcss_fm, wcss_wlan, webcam1_rst ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml index ce219827ccc8..798aac9e6e31 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml @@ -45,6 +45,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -106,18 +107,9 @@ $defs: uim_batt, us_emitter, us_euro, wcss_bt, wcss_fm, wcss_wlan, wcss_wlan0, wcss_wlan1, wcss_wlan2, wsa_en, wsa_io, wsa_irq ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml index cf386f644ccb..9172b50f7a98 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -97,19 +98,9 @@ $defs: vfe_camif_timer7_a, vfe_camif_timer7_b, vfe_camif_timer7_c, wlan ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml index afe4a80f0b79..8a3be65c51ed 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -93,14 +94,6 @@ $defs: tsif1, tsif2, hsic, grfc, audio_ref_clk, qua_mi2s, pri_mi2s, spkr_mi2s, ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, hsic_ctl ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins @@ -124,8 +117,6 @@ $defs: output-high: false output-low: false - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml index 5dfcc3eadbb0..ca95de0b87a6 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: Desired pin configuration for a device or its specific state (like sleep or active). $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -93,19 +94,9 @@ $defs: wsa_irq, blsp_i2c8, pa_indicator, modem_tsync, ssbi_wtr1, gsm1_tx, gsm0_tx, sdcard_det, sec_mi2s, ss_switch ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml index 0c4936fc35ef..41525ecfa8e3 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml @@ -55,6 +55,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -103,19 +104,9 @@ $defs: pri_mi2s, sdc4, sec_mi2s, slimbus, spkr_i2s, ter_mi2s, tsif1, tsif2, uim_batt_alarm, uim1, uim2, uim3, uim4 ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml index 047b4584e3c0..59d406b60957 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -122,19 +123,9 @@ $defs: modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3 ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml index c07ee9868046..bd6d7caf499a 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -107,19 +108,9 @@ $defs: vsense_clkout, vsense_data0, vsense_data1, vsense_mode, wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1 ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml index db505fdeac86..eaadd5a9a445 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml @@ -52,12 +52,14 @@ properties: - qcom,pm8994-gpio - qcom,pm8998-gpio - qcom,pma8084-gpio + - qcom,pmi632-gpio - qcom,pmi8950-gpio - qcom,pmi8994-gpio - qcom,pmi8998-gpio - qcom,pmk8350-gpio - qcom,pmk8550-gpio - qcom,pmm8155au-gpio + - qcom,pmm8654au-gpio - qcom,pmp8074-gpio - qcom,pmr735a-gpio - qcom,pmr735b-gpio @@ -173,6 +175,7 @@ allOf: - qcom,pm8350b-gpio - qcom,pm8550ve-gpio - qcom,pm8950-gpio + - qcom,pmi632-gpio then: properties: gpio-line-names: @@ -395,8 +398,8 @@ $defs: qcom-pmic-gpio-state: type: object allOf: - - $ref: "pinmux-node.yaml" - - $ref: "pincfg-node.yaml" + - $ref: pinmux-node.yaml + - $ref: pincfg-node.yaml properties: pins: description: @@ -434,11 +437,13 @@ $defs: - gpio1-gpio22 for pm8994 - gpio1-gpio26 for pm8998 - gpio1-gpio22 for pma8084 + - gpio1-gpio8 for pmi632 - gpio1-gpio2 for pmi8950 - gpio1-gpio10 for pmi8994 - gpio1-gpio4 for pmk8350 - gpio1-gpio6 for pmk8550 - gpio1-gpio10 for pmm8155au + - gpio1-gpio12 for pmm8654au - gpio1-gpio12 for pmp8074 (holes on gpio1 and gpio12) - gpio1-gpio4 for pmr735a - gpio1-gpio4 for pmr735b diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml index 9412b9362328..c91d3e3a094b 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml @@ -82,8 +82,8 @@ $defs: qcom-pmic-mpp-state: type: object allOf: - - $ref: "pinmux-node.yaml" - - $ref: "pincfg-node.yaml" + - $ref: pinmux-node.yaml + - $ref: pincfg-node.yaml properties: pins: description: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml index 6271fd15e0b6..032763649336 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml @@ -85,6 +85,7 @@ $defs: bias-pull-up: true bias-disable: true drive-strength: true + input-enable: true output-high: true output-low: true diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml index 20bc967a17b5..b1b9cd319e50 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml @@ -59,6 +59,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -119,19 +120,9 @@ $defs: spdifrx_opt, spi_lcd, spkr_dac0, wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1, wsa_en ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml index 7e5fb9a6e7d3..237cac4f6ce1 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml @@ -55,6 +55,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -93,19 +94,9 @@ $defs: usb2phy_ac, usb_con_det, usb_dfp_en, usb_phy, vfr_0, vfr_1, vsense_trigger ] - 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 - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml index 70d9106ad83d..e608a4f1bcae 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml @@ -58,6 +58,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -103,19 +104,9 @@ $defs: tgu_ch2, tgu_ch3, tgu_ch4, tgu_ch5, tsense_pwm1, tsense_pwm2, tsense_pwm3, tsense_pwm4, usb2phy_ac, vsense_trigger ] - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml index f33792a1af6c..573e459b1c44 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml @@ -59,6 +59,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -100,19 +101,9 @@ $defs: _V_GPIO, _V_PPS_IN, _V_PPS_OUT, vsense_trigger, wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1 ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml index e51feb4c0700..fa51fa9536f7 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml @@ -50,7 +50,7 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pins: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml index 36502173cb79..368d44ff5468 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml @@ -62,6 +62,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -110,20 +111,9 @@ $defs: uim1_clk, uim1_data, uim1_present, uim1_reset, usb2phy_ac, usb_phy, vfr_0, vfr_1, vsense_trigger ] - bias-pull-down: true - bias-pull-up: true - bias-bus-hold: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml index 0ace55c9868e..b086a5184235 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml @@ -62,6 +62,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -102,19 +103,9 @@ $defs: usb0_phy, usb1_phy, usb2phy_ac, vfr_1, vsense_trigger, wlan1_adc, wlan2_adc, wmss_reset ] - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml index 200b3b6ccd87..a9167dac9ab5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml @@ -20,7 +20,7 @@ properties: reg: items: - description: LPASS LPI TLMM Control and Status registers - - description: LPASS LPI pins SLEW registers + - description: LPASS LPI MCC registers clocks: items: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml index 97b27d6835e9..4ae39fc7894a 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml @@ -104,6 +104,7 @@ $defs: usb1_phy, usb1_sbrx, usb1_sbtx, usb1_usb4, usb2phy_ac, vsense_trigger ] + bias-bus-hold: true bias-disable: true bias-pull-down: true bias-pull-up: true diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml index ea6bd0b44f56..508e0633b253 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml @@ -65,6 +65,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -122,19 +123,9 @@ $defs: vsense_data0, vsense_data1, vsense_mode, 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 - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml index f586b3aa138e..84a15f77e710 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml @@ -58,6 +58,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -94,20 +95,9 @@ $defs: uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset, uim_batt, usb_phy, vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1, wsa_clk, wsa_data, ] - - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml index 23d7c030fec0..d301881ddfa8 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml @@ -61,6 +61,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -102,19 +103,9 @@ $defs: uim_batt, 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 - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml index a40175258495..67af99dd8f14 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml @@ -48,6 +48,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -91,18 +92,9 @@ $defs: uim1_present, uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset, usb2phy_ac, vsense_trigger ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml index 89c5562583d1..2ef793ae4038 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml @@ -47,6 +47,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -111,18 +112,9 @@ $defs: qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, gpio ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml index 29325483cd2b..871df54f69a2 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml @@ -53,6 +53,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -85,18 +86,9 @@ $defs: uim2_present, uim2_reset, usb_phy, vfr_1, vsense_trigger, wlan1_adc0, elan1_adc1 ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml index c9bc4893e8e8..8d77707b02b9 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml @@ -61,6 +61,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -101,19 +102,9 @@ $defs: wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1, wsa_clk, wsa_data ] - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml index d95935fcc8b5..27af379cf791 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml @@ -63,6 +63,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -108,20 +109,9 @@ $defs: uim2_present, uim2_reset, 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml index 66cef48ed59b..6e02ba24825f 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml @@ -55,6 +55,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -109,20 +110,9 @@ $defs: 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml new file mode 100644 index 000000000000..a57d44efe5bd --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm7150-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM7150 TLMM pin controller + +maintainers: + - Bjorn Andersson + - Danila Tikhonov + +description: + Top Level Mode Multiplexer pin controller in Qualcomm SM7150 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,sm7150-tlmm + + reg: + maxItems: 3 + + reg-names: + items: + - const: west + - const: north + - const: south + + interrupts: + maxItems: 1 + + interrupt-controller: true + "#interrupt-cells": true + gpio-controller: true + "#gpio-cells": true + gpio-ranges: true + wakeup-parent: true + + gpio-reserved-ranges: + minItems: 1 + maxItems: 60 + + gpio-line-names: + maxItems: 119 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm7150-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm7150-tlmm-state" + additionalProperties: false + +$defs: + qcom-sm7150-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-8])$" + - enum: [ sdc1_rclk, sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, + sdc2_cmd, sdc2_data, ufs_reset ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + + enum: [ gpio, adsp_ext, agera_pll, aoss_cti, atest_char, atest_tsens, + atest_tsens2, atest_usb1, atest_usb2, cam_mclk, cci_async, + cci_i2c, cci_timer0, cci_timer1, cci_timer2, cci_timer3, + cci_timer4, dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1, ddr_pxi2, + ddr_pxi3, edp_hot, edp_lcd, gcc_gp1, gcc_gp2, gcc_gp3, gp_pdm0, + gp_pdm1, gp_pdm2, gps_tx, jitter_bist, ldo_en, ldo_update, + m_voc, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2, + mdp_vsync3, mss_lte, nav_pps_in, nav_pps_out, pa_indicator, + pci_e, phase_flag, pll_bist, pll_bypassnl, pll_reset, pri_mi2s, + pri_mi2s_ws, prng_rosc, qdss, qdss_cti, qlink_enable, + qlink_request, qua_mi2s, qup00, qup01, qup02, qup03, qup04, + qup10, qup11, qup12, qup13, qup14, qup15, sd_write, sdc40, + sdc41, sdc42, sdc43, sdc4_clk, sdc4_cmd, sec_mi2s, ter_mi2s, + tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tsif1_clk, tsif1_data, + tsif1_en, tsif1_error, tsif1_sync, tsif2_clk, tsif2_data, + tsif2_en, tsif2_error, tsif2_sync, uim1_clk, uim1_data, + uim1_present, uim1_reset, uim2_clk, uim2_data, uim2_present, + uim2_reset, uim_batt, usb_phy, vfr_1, vsense_trigger, + wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1, wsa_clk, + wsa_data ] + + bias-pull-down: true + bias-pull-up: true + bias-disable: true + drive-strength: true + input-enable: true + output-high: true + output-low: true + + required: + - pins + + additionalProperties: false + +required: + - compatible + - reg + - reg-names + +additionalProperties: false + +examples: + - | + #include + + tlmm: pinctrl@3500000 { + compatible = "qcom,sm7150-tlmm"; + reg = <0x03500000 0x300000>, + <0x03900000 0x300000>, + <0x03d00000 0x300000>; + reg-names = "west", "north", "south"; + interrupts = ; + gpio-ranges = <&tlmm 0 0 120>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio44"; + function = "qup12"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio45"; + function = "qup12"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml index 4376a9bd4d70..c6439626464e 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml @@ -60,6 +60,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -81,7 +82,7 @@ $defs: enum: [ adsp_ext, agera_pll, aoss_cti, ddr_pxi2, atest_char, atest_char0, atest_char1, atest_char2, atest_char3, audio_ref, atest_usb1, atest_usb2, atest_usb10, atest_usb11, atest_usb12, - atest_usb13, atest_usb20, atest_usb21, atest_usb22, atest_usb2, + atest_usb13, atest_usb20, atest_usb21, atest_usb22, atest_usb23, btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4, cri_trng, cri_trng0, cri_trng1, dbg_out, ddr_bist, ddr_pxi0, @@ -101,19 +102,9 @@ $defs: usb_phy, vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1, wlan2_adc0, wlan2_adc1, wmss_reset ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml index de9d8854c690..4b4be7efc150 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml @@ -55,7 +55,7 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pins: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml index cf561dff8893..021c54708524 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml @@ -58,6 +58,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -94,19 +95,9 @@ $defs: tsif0_en, tsif0_error, tsif0_sync, tsif1_clk, tsif1_data, tsif1_en, tsif1_error, tsif1_sync, usb2phy_ac, usb_phy, vsense_trigger ] - bias-pull-down: true - bias-pull-up: true - bias-disable: true - drive-strength: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - allOf: - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml index 797242f68b1c..6e8f41ff0a76 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml @@ -62,6 +62,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -104,21 +105,9 @@ $defs: uim0_present, uim0_reset, uim1_clk, uim1_data, uim1_present, uim1_reset, usb2phy_ac, usb_phy, vfr_0, vfr_1, vsense_trigger ] - - bias-disable: true - bias-pull-down: true - bias-pull-up: true - drive-strength: true - input-disable: true - input-enable: true - output-high: true - output-low: true - required: - pins - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml index 8bf51df0b231..1eefa9aa6a86 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml @@ -20,7 +20,7 @@ properties: reg: items: - description: LPASS LPI TLMM Control and Status registers - - description: LPASS LPI pins SLEW registers + - description: LPASS LPI MCC registers clocks: items: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml index 56c8046f1be0..5163fe3f5365 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml @@ -62,6 +62,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -103,19 +104,9 @@ $defs: uim0_reset, uim1_clk, uim1_data, uim1_present, uim1_reset, usb2phy_ac, usb_phy, vfr_0, vfr_1, vsense_trigger ] - 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 - additionalProperties: false - examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml index 8f60a9113e7a..ef9743246849 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml @@ -21,7 +21,7 @@ properties: reg: items: - description: LPASS LPI TLMM Control and Status registers - - description: LPASS LPI pins SLEW registers + - description: LPASS LPI MCC registers clocks: items: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml index a457425ba112..f789c7753a92 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml @@ -54,6 +54,7 @@ $defs: 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 + unevaluatedProperties: false properties: pins: @@ -109,19 +110,9 @@ $defs: uim1_clk, uim1_data, uim1_present, uim1_reset, usb1_hs, usb_phy, vfr_0, vfr_1, vsense_trigger_mirnat ] - 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 - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,tlmm-common.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,tlmm-common.yaml index 90b7d75840c1..aae3dcf6cac8 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,tlmm-common.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,tlmm-common.yaml @@ -52,7 +52,7 @@ properties: information. allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - interrupts diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,rt2880-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ralink,rt2880-pinctrl.yaml index 7fd0df880a76..43b33dbf115b 100644 --- a/Documentation/devicetree/bindings/pinctrl/ralink,rt2880-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ralink,rt2880-pinctrl.yaml @@ -10,7 +10,7 @@ maintainers: - Arınç ÜNAL - Sergio Paracuellos -description: +description: | Ralink RT2880 pin controller for RT2880 SoC. The pin controller can only set the muxing of pin groups. Muxing individual pins is not supported. There is no pinconf support. @@ -22,11 +22,14 @@ properties: patternProperties: '-pins$': type: object + additionalProperties: false + patternProperties: '^(.*-)?pinmux$': type: object description: node for pinctrl. $ref: pinmux-node.yaml# + additionalProperties: false properties: function: @@ -116,12 +119,8 @@ patternProperties: groups: enum: [pci] - additionalProperties: false - - additionalProperties: false - allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,rt305x-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ralink,rt305x-pinctrl.yaml index 4d66ca752a30..95a904273009 100644 --- a/Documentation/devicetree/bindings/pinctrl/ralink,rt305x-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ralink,rt305x-pinctrl.yaml @@ -10,9 +10,8 @@ maintainers: - Arınç ÜNAL - Sergio Paracuellos -description: - Ralink RT305X pin controller for RT3050, RT3052, RT3350, RT3352 and RT5350 - SoCs. +description: | + Ralink RT305X pin controller for RT3050, RT3052, and RT3350 SoCs. The pin controller can only set the muxing of pin groups. Muxing individual pins is not supported. There is no pinconf support. @@ -23,31 +22,22 @@ properties: patternProperties: '-pins$': type: object + additionalProperties: false + patternProperties: '^(.*-)?pinmux$': type: object description: node for pinctrl. $ref: pinmux-node.yaml# + additionalProperties: false properties: function: description: A string containing the name of the function to mux to the group. - anyOf: - - description: For RT3050, RT3052 and RT3350 SoCs - enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, mdio, - pcm gpio, pcm i2s, pcm uartf, rgmii, sdram, spi, uartf, - uartlite] - - - description: For RT3352 SoC - enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, led, - lna, mdio, pa, pcm gpio, pcm i2s, pcm uartf, rgmii, spi, - spi_cs1, uartf, uartlite, wdg_cs1] - - - description: For RT5350 SoC - enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, led, - pcm gpio, pcm i2s, pcm uartf, spi, spi_cs1, uartf, - uartlite, wdg_cs1] + enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, mdio, + pcm gpio, pcm i2s, pcm uartf, rgmii, sdram, spi, uartf, + uartlite] groups: description: @@ -66,17 +56,7 @@ patternProperties: then: properties: groups: - anyOf: - - description: For RT3050, RT3052 and RT3350 SoCs - enum: [i2c, jtag, mdio, rgmii, sdram, spi, uartf, - uartlite] - - - description: For RT3352 SoC - enum: [i2c, jtag, led, lna, mdio, pa, rgmii, spi, spi_cs1, - uartf, uartlite] - - - description: For RT5350 SoC - enum: [i2c, jtag, led, spi, spi_cs1, uartf, uartlite] + enum: [i2c, jtag, mdio, rgmii, sdram, spi, uartf, uartlite] - if: properties: @@ -123,24 +103,6 @@ patternProperties: groups: enum: [jtag] - - if: - properties: - function: - const: led - then: - properties: - groups: - enum: [led] - - - if: - properties: - function: - const: lna - then: - properties: - groups: - enum: [lna] - - if: properties: function: @@ -150,15 +112,6 @@ patternProperties: groups: enum: [mdio] - - if: - properties: - function: - const: pa - then: - properties: - groups: - enum: [pa] - - if: properties: function: @@ -213,15 +166,6 @@ patternProperties: groups: enum: [spi] - - if: - properties: - function: - const: spi_cs1 - then: - properties: - groups: - enum: [spi_cs1] - - if: properties: function: @@ -240,21 +184,8 @@ patternProperties: groups: enum: [uartlite] - - if: - properties: - function: - const: wdg_cs1 - then: - properties: - groups: - enum: [spi_cs1] - - additionalProperties: false - - additionalProperties: false - allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,rt3352-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ralink,rt3352-pinctrl.yaml new file mode 100644 index 000000000000..c9bc6cfd834c --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ralink,rt3352-pinctrl.yaml @@ -0,0 +1,243 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/ralink,rt3352-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ralink RT3352 Pin Controller + +maintainers: + - Arınç ÜNAL + - Sergio Paracuellos + +description: | + Ralink RT3352 pin controller for RT3352 SoC. + The pin controller can only set the muxing of pin groups. Muxing individual + pins is not supported. There is no pinconf support. + +properties: + compatible: + const: ralink,rt3352-pinctrl + +patternProperties: + '-pins$': + type: object + additionalProperties: false + + patternProperties: + '^(.*-)?pinmux$': + type: object + description: node for pinctrl. + $ref: pinmux-node.yaml# + additionalProperties: false + + properties: + function: + description: + A string containing the name of the function to mux to the group. + enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, led, lna, + mdio, pa, pcm gpio, pcm i2s, pcm uartf, rgmii, spi, spi_cs1, + uartf, uartlite, wdg_cs1] + + groups: + description: + An array of strings. Each string contains the name of a group. + maxItems: 1 + + required: + - groups + - function + + allOf: + - if: + properties: + function: + const: gpio + then: + properties: + groups: + enum: [i2c, jtag, led, lna, mdio, pa, rgmii, spi, spi_cs1, + uartf, uartlite] + + - if: + properties: + function: + const: gpio i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: gpio uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: i2c + then: + properties: + groups: + enum: [i2c] + + - if: + properties: + function: + const: i2s uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: jtag + then: + properties: + groups: + enum: [jtag] + + - if: + properties: + function: + const: led + then: + properties: + groups: + enum: [led] + + - if: + properties: + function: + const: lna + then: + properties: + groups: + enum: [lna] + + - if: + properties: + function: + const: mdio + then: + properties: + groups: + enum: [mdio] + + - if: + properties: + function: + const: pa + then: + properties: + groups: + enum: [pa] + + - if: + properties: + function: + const: pcm gpio + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: rgmii + then: + properties: + groups: + enum: [rgmii] + + - if: + properties: + function: + const: spi + then: + properties: + groups: + enum: [spi] + + - if: + properties: + function: + const: spi_cs1 + then: + properties: + groups: + enum: [spi_cs1] + + - if: + properties: + function: + const: uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: uartlite + then: + properties: + groups: + enum: [uartlite] + + - if: + properties: + function: + const: wdg_cs1 + then: + properties: + groups: + enum: [spi_cs1] + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + +additionalProperties: false + +examples: + - | + pinctrl { + compatible = "ralink,rt3352-pinctrl"; + + i2c_pins: i2c0-pins { + pinmux { + groups = "i2c"; + function = "i2c"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,rt3883-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ralink,rt3883-pinctrl.yaml index 008d93181aea..8d14e525b25e 100644 --- a/Documentation/devicetree/bindings/pinctrl/ralink,rt3883-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/ralink,rt3883-pinctrl.yaml @@ -10,7 +10,7 @@ maintainers: - Arınç ÜNAL - Sergio Paracuellos -description: +description: | Ralink RT3883 pin controller for RT3883 SoC. The pin controller can only set the muxing of pin groups. Muxing individual pins is not supported. There is no pinconf support. @@ -22,11 +22,14 @@ properties: patternProperties: '-pins$': type: object + additionalProperties: false + patternProperties: '^(.*-)?pinmux$': type: object description: node for pinctrl. $ref: pinmux-node.yaml# + additionalProperties: false properties: function: @@ -236,12 +239,8 @@ patternProperties: groups: enum: [uartlite] - additionalProperties: false - - additionalProperties: false - allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/ralink,rt5350-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/ralink,rt5350-pinctrl.yaml new file mode 100644 index 000000000000..f248202ce866 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/ralink,rt5350-pinctrl.yaml @@ -0,0 +1,206 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/ralink,rt5350-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ralink RT5350 Pin Controller + +maintainers: + - Arınç ÜNAL + - Sergio Paracuellos + +description: | + Ralink RT5350 pin controller for RT5350 SoC. + The pin controller can only set the muxing of pin groups. Muxing individual + pins is not supported. There is no pinconf support. + +properties: + compatible: + const: ralink,rt5350-pinctrl + +patternProperties: + '-pins$': + type: object + additionalProperties: false + + patternProperties: + '^(.*-)?pinmux$': + type: object + description: node for pinctrl. + $ref: pinmux-node.yaml# + additionalProperties: false + + properties: + function: + description: + A string containing the name of the function to mux to the group. + enum: [gpio, gpio i2s, gpio uartf, i2c, i2s uartf, jtag, led, + pcm gpio, pcm i2s, pcm uartf, spi, spi_cs1, uartf, uartlite, + wdg_cs1] + + groups: + description: + An array of strings. Each string contains the name of a group. + maxItems: 1 + + required: + - groups + - function + + allOf: + - if: + properties: + function: + const: gpio + then: + properties: + groups: + enum: [i2c, jtag, led, spi, spi_cs1, uartf, uartlite] + + - if: + properties: + function: + const: gpio i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: gpio uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: i2c + then: + properties: + groups: + enum: [i2c] + + - if: + properties: + function: + const: i2s uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: jtag + then: + properties: + groups: + enum: [jtag] + + - if: + properties: + function: + const: led + then: + properties: + groups: + enum: [led] + + - if: + properties: + function: + const: pcm gpio + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm i2s + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: pcm uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: spi + then: + properties: + groups: + enum: [spi] + + - if: + properties: + function: + const: spi_cs1 + then: + properties: + groups: + enum: [spi_cs1] + + - if: + properties: + function: + const: uartf + then: + properties: + groups: + enum: [uartf] + + - if: + properties: + function: + const: uartlite + then: + properties: + groups: + enum: [uartlite] + + - if: + properties: + function: + const: wdg_cs1 + then: + properties: + groups: + enum: [spi_cs1] + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + +additionalProperties: false + +examples: + - | + pinctrl { + compatible = "ralink,rt5350-pinctrl"; + + i2c_pins: i2c0-pins { + pinmux { + groups = "i2c"; + function = "i2c"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,pfc.yaml index 4fc758fea7e6..0fc3c0f52c19 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc.yaml @@ -73,7 +73,7 @@ properties: maxItems: 1 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza1-ports.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-ports.yaml index 9083040c996a..83800fcf0ce4 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rza1-ports.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-ports.yaml @@ -32,7 +32,7 @@ properties: maxItems: 1 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml index d761fddc2206..37173a64fed2 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml @@ -73,7 +73,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml index f081acb7ba04..9ce1a07fc015 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml @@ -113,7 +113,7 @@ additionalProperties: $ref: "#/additionalProperties/anyOf/0" allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzn1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzn1-pinctrl.yaml index 70b1788ab594..19d4d2facfb4 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzn1-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzn1-pinctrl.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas RZ/N1 Pin Controller maintainers: - - Gareth Williams + - Fabrizio Castro - Geert Uytterhoeven properties: @@ -32,7 +32,7 @@ properties: The bus clock, sometimes described as pclk, for register accesses. allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml index eac6245db7dc..c87161f2954f 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzv2m-pinctrl.yaml @@ -7,8 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas RZ/V2M combined Pin and GPIO controller maintainers: + - Fabrizio Castro - Geert Uytterhoeven - - Phil Edworthy description: The Renesas RZ/V2M SoC features a combined Pin and GPIO controller. @@ -94,7 +94,7 @@ additionalProperties: $ref: "#/additionalProperties/anyOf/0" allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml index 45b767986a87..10c335efe619 100644 --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml @@ -50,12 +50,12 @@ properties: - rockchip,rv1126-pinctrl rockchip,grf: - $ref: "/schemas/types.yaml#/definitions/phandle" + $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the syscon node for the GRF registers. rockchip,pmu: - $ref: "/schemas/types.yaml#/definitions/phandle" + $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of the syscon node for the PMU registers, as some SoCs carry parts of the iomux controller registers there. @@ -71,7 +71,7 @@ properties: ranges: true allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -81,7 +81,7 @@ patternProperties: "gpio@[0-9a-f]+$": type: object - $ref: "/schemas/gpio/rockchip,gpio-bank.yaml#" + $ref: /schemas/gpio/rockchip,gpio-bank.yaml# deprecated: true unevaluatedProperties: false @@ -117,7 +117,7 @@ additionalProperties: type: object properties: rockchip,pins: - $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + $ref: /schemas/types.yaml#/definitions/uint32-matrix minItems: 1 items: items: diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml index eb2b2692607d..26614621774a 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml @@ -117,7 +117,7 @@ required: - reg allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml b/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml index 0719c03d6f4b..4214d7311f6b 100644 --- a/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml +++ b/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml @@ -62,8 +62,8 @@ patternProperties: - pins allOf: - - $ref: "pincfg-node.yaml#" - - $ref: "pinmux-node.yaml#" + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# - if: properties: pins: @@ -86,7 +86,7 @@ required: - gpio-controller allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# - if: not: properties: diff --git a/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml index bc34e2c872bc..a6f34df82e90 100644 --- a/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml @@ -61,7 +61,7 @@ additionalProperties: unevaluatedProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml index eeb29b4ad4d1..1ab0f8dde477 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -44,7 +44,7 @@ properties: st,syscfg: description: Phandle+args to the syscon node which includes IRQ mux selection. - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array items: - items: - description: syscon node which includes IRQ mux selection @@ -89,7 +89,7 @@ patternProperties: st,bank-name: description: Should be a name string for this bank as specified in the datasheet. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: - GPIOA - GPIOB @@ -108,7 +108,7 @@ patternProperties: description: Should correspond to the EXTI IOport selection (EXTI line used to select GPIOs as interrupts). - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 11 @@ -140,7 +140,7 @@ patternProperties: configuration, pullups, drive, output high/low and output speed. properties: pinmux: - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: /schemas/types.yaml#/definitions/uint32-array description: | Integer array, represents gpio pin number and mux setting. Supported pin number and mux varies for different SoCs, and are @@ -201,7 +201,7 @@ patternProperties: - pinmux allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml index d78c3cd0c295..f3258f2fd3a4 100644 --- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml @@ -111,7 +111,7 @@ patternProperties: pins it needs, and how they should be configured, with regard to muxer configuration, bias, input enable/disable, input schmitt trigger enable/disable, slew-rate and drive strength. - $ref: "/schemas/pinctrl/pincfg-node.yaml" + $ref: /schemas/pinctrl/pincfg-node.yaml properties: pins: @@ -120,14 +120,14 @@ patternProperties: This should be set using either the PAD_GPIO or PAD_FUNC_SHARE macros. Either this or "pinmux" has to be specified, but not both. - $ref: "/schemas/pinctrl/pinmux-node.yaml#/properties/pins" + $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/pins pinmux: description: | The list of GPIOs and their mux settings that properties in the node apply to. This should be set using the GPIOMUX macro. Either this or "pins" has to be specified, but not both. - $ref: "/schemas/pinctrl/pinmux-node.yaml#/properties/pinmux" + $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/pinmux bias-disable: true diff --git a/Documentation/devicetree/bindings/pinctrl/sunplus,sp7021-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/sunplus,sp7021-pinctrl.yaml index 347061eece9e..94b868c7ceb1 100644 --- a/Documentation/devicetree/bindings/pinctrl/sunplus,sp7021-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/sunplus,sp7021-pinctrl.yaml @@ -138,7 +138,7 @@ patternProperties: description: | Define pin-function which is used by pinctrl node's client device. The name should be one of string in the following enumeration. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ SPI_FLASH, SPI_FLASH_4BIT, SPI_NAND, CARD0_EMMC, SD_CARD, UA0, FPGA_IFX, HDMI_TX, LCDIF, USB0_OTG, USB1_OTG ] @@ -146,7 +146,7 @@ patternProperties: description: | Define pin-group in a specified pin-function. The name should be one of string in the following enumeration. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [ SPI_FLASH1, SPI_FLASH2, SPI_FLASH_4BIT1, SPI_FLASH_4BIT2, SPI_NAND, CARD0_EMMC, SD_CARD, UA0, FPGA_IFX, HDMI_TX1, HDMI_TX2, HDMI_TX3, LCDIF, USB0_OTG, USB1_OTG ] @@ -289,7 +289,7 @@ required: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml index 98b4663f9766..19d47fd414bc 100644 --- a/Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml @@ -21,7 +21,7 @@ properties: maxItems: 1 allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible @@ -35,14 +35,14 @@ patternProperties: pinctrl groups available on the machine. Each subnode will list the pins it needs, and how they should be configured, with regard to muxer configuration, pullups, drive strength. - $ref: "pinmux-node.yaml" + $ref: pinmux-node.yaml additionalProperties: false properties: function: description: Function to mux. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [i2c0, i2c1, i2c2, i2c3, i2c4, i2c5, i2c6, i2c7, i2c8, spi0, spi1, spi2, spi3, spi4, spi5, spi6, uart0, uart1, uart2, uart3, pwm, pcmif_out, pcmif_in] @@ -50,7 +50,7 @@ patternProperties: groups: description: Name of the pin group to use for the functions. - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: [i2c0_grp, i2c1_grp, i2c2_grp, i2c3_grp, i2c4_grp, i2c5_grp, i2c6_grp, i2c7_grp, i2c8_grp, spi0_grp, spi0_cs0_grp, spi0_cs1_grp, spi0_cs2_grp, diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml index cfd0cc549a7b..598a042850b8 100644 --- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml @@ -168,7 +168,7 @@ patternProperties: additionalProperties: false allOf: - - $ref: "pinctrl.yaml#" + - $ref: pinctrl.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/power/qcom,kpss-acc-v2.yaml b/Documentation/devicetree/bindings/power/qcom,kpss-acc-v2.yaml new file mode 100644 index 000000000000..202a5d51ee88 --- /dev/null +++ b/Documentation/devicetree/bindings/power/qcom,kpss-acc-v2.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/qcom,kpss-acc-v2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Krait Processor Sub-system (KPSS) Application Clock Controller (ACC) v2 + +maintainers: + - Christian Marangi + +description: + The KPSS ACC provides clock, power manager, and reset control to a Krait CPU. + There is one ACC register region per CPU within the KPSS remapped region as + well as an alias register region that remaps accesses to the ACC associated + with the CPU accessing the region. ACC v2 is currently used as a + power-manager for enabling the cpu. + +properties: + compatible: + const: qcom,kpss-acc-v2 + + reg: + items: + - description: Base address and size of the register region + - description: Optional base address and size of the alias register region + minItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + power-manager@f9088000 { + compatible = "qcom,kpss-acc-v2"; + reg = <0xf9088000 0x1000>, + <0xf9008000 0x1000>; + }; +... diff --git a/Documentation/devicetree/bindings/power/supply/adc-battery.yaml b/Documentation/devicetree/bindings/power/supply/adc-battery.yaml new file mode 100644 index 000000000000..ed9702caedff --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/adc-battery.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/adc-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADC battery + +maintainers: + - Sebastian Reichel + +description: + Basic battery capacity meter, which only reports basic battery data + via ADC channels and optionally indicate that the battery is full by + polling a GPIO line. + + The voltage is expected to be measured between the battery terminals + and mandatory. The optional current/power channel is expected to + monitor the current/power flowing out of the battery. Last but not + least the temperature channel is supposed to measure the battery + temperature. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: adc-battery + + charged-gpios: + description: + GPIO which signals that the battery is fully charged. The GPIO is + often provided by charger ICs, that are not software controllable. + maxItems: 1 + + io-channels: + minItems: 1 + maxItems: 4 + + io-channel-names: + minItems: 1 + items: + - const: voltage + - enum: [ current, power, temperature ] + - enum: [ power, temperature ] + - const: temperature + + monitored-battery: true + +required: + - compatible + - io-channels + - io-channel-names + - monitored-battery + +unevaluatedProperties: false + +examples: + - | + #include + + fuel-gauge { + compatible = "adc-battery"; + charged-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; + io-channels = <&adc 13>, <&adc 37>; + io-channel-names = "voltage", "current"; + + power-supplies = <&charger>; + monitored-battery = <&battery>; + }; diff --git a/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml b/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml new file mode 100644 index 000000000000..142157bff0cd --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/apple,s5l-fpwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple FPWM controller + +maintainers: + - asahi@lists.linux.dev + - Sasha Finkelstein + +description: PWM controller used for keyboard backlight on ARM Macs + +properties: + compatible: + items: + - enum: + - apple,t8103-fpwm + - apple,t6000-fpwm + - apple,t8112-fpwm + - const: apple,s5l-fpwm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + "#pwm-cells": + const: 2 + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + pwm@235044000 { + compatible = "apple,t8103-fpwm", "apple,s5l-fpwm"; + reg = <0x35044000 0x4000>; + power-domains = <&ps_fpwm1>; + clocks = <&clkref>; + #pwm-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml b/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml index dbc974bff9e9..8e176ba7a525 100644 --- a/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml @@ -22,6 +22,7 @@ properties: - mediatek,mt7623-pwm - mediatek,mt7628-pwm - mediatek,mt7629-pwm + - mediatek,mt7986-pwm - mediatek,mt8183-pwm - mediatek,mt8365-pwm - mediatek,mt8516-pwm diff --git a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml new file mode 100644 index 000000000000..527864a4d855 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/pwm-amlogic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic PWM + +maintainers: + - Heiner Kallweit + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + oneOf: + - enum: + - amlogic,meson8b-pwm + - amlogic,meson-gxbb-pwm + - amlogic,meson-gxbb-ao-pwm + - amlogic,meson-axg-ee-pwm + - amlogic,meson-axg-ao-pwm + - amlogic,meson-g12a-ee-pwm + - amlogic,meson-g12a-ao-pwm-ab + - amlogic,meson-g12a-ao-pwm-cd + - amlogic,meson-s4-pwm + - items: + - const: amlogic,meson-gx-pwm + - const: amlogic,meson-gxbb-pwm + - items: + - const: amlogic,meson-gx-ao-pwm + - const: amlogic,meson-gxbb-ao-pwm + - items: + - const: amlogic,meson8-pwm + - const: amlogic,meson8b-pwm + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + oneOf: + - items: + - enum: [clkin0, clkin1] + - items: + - const: clkin0 + - const: clkin1 + + "#pwm-cells": + const: 3 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pwm@8550 { + compatible = "amlogic,meson-gxbb-pwm"; + reg = <0x08550 0x10>; + clocks = <&xtal>, <&xtal>; + clock-names = "clkin0", "clkin1"; + #pwm-cells = <3>; + }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt deleted file mode 100644 index bd02b0a1496f..000000000000 --- a/Documentation/devicetree/bindings/pwm/pwm-meson.txt +++ /dev/null @@ -1,29 +0,0 @@ -Amlogic Meson PWM Controller -============================ - -Required properties: -- compatible: Shall contain "amlogic,meson8b-pwm" - or "amlogic,meson-gxbb-pwm" - or "amlogic,meson-gxbb-ao-pwm" - or "amlogic,meson-axg-ee-pwm" - or "amlogic,meson-axg-ao-pwm" - or "amlogic,meson-g12a-ee-pwm" - or "amlogic,meson-g12a-ao-pwm-ab" - or "amlogic,meson-g12a-ao-pwm-cd" -- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of - the cells format. - -Optional properties: -- clocks: Could contain one or two parents clocks phandle for each of the two - PWM channels. -- clock-names: Could contain at least the "clkin0" and/or "clkin1" names. - -Example: - - pwm_ab: pwm@8550 { - compatible = "amlogic,meson-gxbb-pwm"; - reg = <0x0 0x08550 0x0 0x10>; - #pwm-cells = <3>; - clocks = <&xtal>, <&xtal>; - clock-names = "clkin0", "clkin1"; - } diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml index 14b5b7ea0ce0..3d2934b15e80 100644 --- a/Documentation/devicetree/bindings/riscv/cpus.yaml +++ b/Documentation/devicetree/bindings/riscv/cpus.yaml @@ -66,6 +66,7 @@ properties: - riscv,sv32 - riscv,sv39 - riscv,sv48 + - riscv,sv57 - riscv,none riscv,cbom-block-size: @@ -73,6 +74,11 @@ properties: description: The blocksize in bytes for the Zicbom cache operations. + riscv,cboz-block-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The blocksize in bytes for the Zicboz cache operations. + riscv,isa: description: Identifies the specific RISC-V instruction set architecture @@ -80,6 +86,12 @@ properties: User-Level ISA document, available from https://riscv.org/specifications/ + Due to revisions of the ISA specification, some deviations + have arisen over time. + Notably, riscv,isa was defined prior to the creation of the + Zicsr and Zifencei extensions and thus "i" implies + "zicsr_zifencei". + While the isa strings in ISA specification are case insensitive, letters in the riscv,isa string must be all lowercase to simplify parsing. diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml index dede49431733..054e1e397fc8 100644 --- a/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner A10 RTC allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Chen-Yu Tsai diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml index 04947e166cef..4531eec568a6 100644 --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml @@ -61,7 +61,7 @@ properties: - the Internal Oscillator, at index 2. allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml index 0e5f0fcc26b0..4d2bef15fb7a 100644 --- a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Atmel AT91 RTC allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91sam9260-rtt.yaml b/Documentation/devicetree/bindings/rtc/atmel,at91sam9260-rtt.yaml index b5cd20e89daf..b80b85c394ac 100644 --- a/Documentation/devicetree/bindings/rtc/atmel,at91sam9260-rtt.yaml +++ b/Documentation/devicetree/bindings/rtc/atmel,at91sam9260-rtt.yaml @@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Atmel AT91 RTT allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.yaml b/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.yaml index c6c57636c729..c5e5c5aec74e 100644 --- a/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.yaml +++ b/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.yaml @@ -15,7 +15,7 @@ description: optionally generate RTC alarm interrupts. allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml index 056d42daae06..b1c1a0e21318 100644 --- a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml +++ b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.yaml @@ -38,8 +38,8 @@ properties: clock-names: items: - - const: "PCLK" - - const: "EXTCLK" + - const: PCLK + - const: EXTCLK required: - compatible diff --git a/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml b/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml index dd6eebf06ea6..27a9de10f0af 100644 --- a/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml +++ b/Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip RV-3032 RTC allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml index 585c185d1eb3..af4a31cd0954 100644 --- a/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Mstar MSC313e RTC allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Daniel Palmer diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml index 7a1857f5caa8..4f9b5604acd9 100644 --- a/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml +++ b/Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: NUVOTON NCT3018Y Real Time Clock allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Medad CChien diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml index a1148eb22c24..bcb230027622 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: NXP PCF2127 Real Time Clock allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Alexandre Belloni diff --git a/Documentation/devicetree/bindings/rtc/rtc-mxc.yaml b/Documentation/devicetree/bindings/rtc/rtc-mxc.yaml index 4f263fa6fd0d..a14b52178c4b 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-mxc.yaml +++ b/Documentation/devicetree/bindings/rtc/rtc-mxc.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Real Time Clock of the i.MX SoCs allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Philippe Reynes diff --git a/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.yaml b/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.yaml index 2d1a30663d72..e50131c26dc6 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.yaml +++ b/Documentation/devicetree/bindings/rtc/rtc-mxc_v2.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: i.MX53 Secure Real Time Clock (SRTC) allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# maintainers: - Patrick Bruenn diff --git a/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml b/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml index b04b87ef6f33..a16c355dcd11 100644 --- a/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/sa1100-rtc.yaml @@ -34,8 +34,8 @@ properties: interrupt-names: items: - - const: 'rtc 1Hz' - - const: 'rtc alarm' + - const: rtc 1Hz + - const: rtc alarm required: - compatible diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml index 9e66ed33cda4..4703083d1f11 100644 --- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml @@ -32,7 +32,7 @@ properties: maxItems: 1 st,syscfg: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array items: minItems: 3 maxItems: 3 diff --git a/Documentation/devicetree/bindings/rtc/ti,k3-rtc.yaml b/Documentation/devicetree/bindings/rtc/ti,k3-rtc.yaml index d995ef04a6eb..df5b4f77f6fb 100644 --- a/Documentation/devicetree/bindings/rtc/ti,k3-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/ti,k3-rtc.yaml @@ -13,7 +13,7 @@ description: | This RTC appears in the AM62x family of SoCs. allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index eb75861c28c3..a3603e638c37 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -15,7 +15,7 @@ description: | possibly an interrupt line. allOf: - - $ref: "rtc.yaml#" + - $ref: rtc.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml index eb3488d8f9ee..6a7be42da523 100644 --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml @@ -70,6 +70,7 @@ properties: dsr-gpios: true rng-gpios: true dcd-gpios: true + rs485-rts-active-high: true rts-gpio: true power-domains: true clock-frequency: true diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml index 3cbdde85ed71..01ec45b3b406 100644 --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/amlogic,meson-uart.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/amlogic,meson-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson SoC UART Serial Interface @@ -34,6 +34,11 @@ properties: - amlogic,meson-gx-uart - amlogic,meson-s4-uart - const: amlogic,meson-ao-uart + - description: Always-on power domain UART controller on G12A SoCs + items: + - const: amlogic,meson-g12a-uart + - const: amlogic,meson-gx-uart + - const: amlogic,meson-ao-uart - description: Everything-Else power domain UART controller enum: - amlogic,meson6-uart @@ -41,6 +46,10 @@ properties: - amlogic,meson8b-uart - amlogic,meson-gx-uart - amlogic,meson-s4-uart + - description: Everything-Else power domain UART controller on G12A SoCs + items: + - const: amlogic,meson-g12a-uart + - const: amlogic,meson-gx-uart reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml index 4cbe76e1715b..40414247d61a 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml @@ -49,6 +49,24 @@ properties: reg: maxItems: 1 + clocks: + maxItems: 2 + + clock-names: + items: + - const: ipg + - const: per + + dmas: + items: + - description: DMA controller phandle and request line for RX + - description: DMA controller phandle and request line for TX + + dma-names: + items: + - const: rx + - const: tx + interrupts: maxItems: 1 @@ -86,12 +104,16 @@ properties: required: - compatible - reg + - clocks + - clock-names - interrupts unevaluatedProperties: false examples: - | + #include + aliases { serial0 = &uart1; }; @@ -100,6 +122,11 @@ examples: compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fbc000 0x4000>; interrupts = <31>; + clocks = <&clks IMX5_CLK_UART1_IPG_GATE>, + <&clks IMX5_CLK_UART1_PER_GATE>; + clock-names = "ipg", "per"; + dmas = <&sdma 18 4 1>, <&sdma 19 4 2>; + dma-names = "rx", "tx"; uart-has-rtscts; fsl,dte-mode; }; diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml index ab81722293d3..93062403276b 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml @@ -65,6 +65,9 @@ properties: - const: rx - const: tx + power-domains: + maxItems: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/serial/qcom,serial-geni-qcom.yaml b/Documentation/devicetree/bindings/serial/qcom,serial-geni-qcom.yaml index 05a6999808d1..dd33794b3534 100644 --- a/Documentation/devicetree/bindings/serial/qcom,serial-geni-qcom.yaml +++ b/Documentation/devicetree/bindings/serial/qcom,serial-geni-qcom.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/qcom,serial-geni-qcom.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/qcom,serial-geni-qcom.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Geni based QUP UART interface diff --git a/Documentation/devicetree/bindings/serial/renesas,em-uart.yaml b/Documentation/devicetree/bindings/serial/renesas,em-uart.yaml index 12d0fa34f9f9..3fc2601f1338 100644 --- a/Documentation/devicetree/bindings/serial/renesas,em-uart.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,em-uart.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,em-uart.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,em-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas EMMA Mobile UART Interface diff --git a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml index afedb6edfc34..1c7f1276aed6 100644 --- a/Documentation/devicetree/bindings/serial/renesas,hscif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,hscif.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,hscif.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,hscif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas High Speed Serial Communication Interface with FIFO (HSCIF) diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml index dc445b327e0b..9f7305200c47 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,sci.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,sci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas Serial Communication Interface diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 54e4f41be9b4..99030fc18c45 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,scif.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,scif.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas Serial Communication Interface with FIFO (SCIF) diff --git a/Documentation/devicetree/bindings/serial/renesas,scifa.yaml b/Documentation/devicetree/bindings/serial/renesas,scifa.yaml index 4c3b5e7270da..499507678cdf 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scifa.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scifa.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,scifa.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,scifa.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas Serial Communications Interface with FIFO A (SCIFA) diff --git a/Documentation/devicetree/bindings/serial/renesas,scifb.yaml b/Documentation/devicetree/bindings/serial/renesas,scifb.yaml index 2f7cbbb48960..810d8a991fdd 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scifb.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scifb.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/renesas,scifb.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/renesas,scifb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas Serial Communications Interface with FIFO B (SCIFB) diff --git a/Documentation/devicetree/bindings/serial/serial.yaml b/Documentation/devicetree/bindings/serial/serial.yaml index c9231e501f1f..ea277560a596 100644 --- a/Documentation/devicetree/bindings/serial/serial.yaml +++ b/Documentation/devicetree/bindings/serial/serial.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/serial.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/serial.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Serial Interface Generic diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 2becdfab4f15..3862411c77b5 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -68,12 +68,12 @@ properties: - const: apb_pclk dmas: - minItems: 2 + maxItems: 2 dma-names: items: - - const: rx - const: tx + - const: rx snps,uart-16550-compatible: description: reflects the value of UART_16550_COMPATIBLE configuration diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml index da0e2745b5fc..28ff77aa86c8 100644 --- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Unisoc Inc. %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/sprd-uart.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/sprd-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Spreadtrum serial UART diff --git a/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml index ea1e637661c7..7d0a4bcb88e9 100644 --- a/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml @@ -2,8 +2,8 @@ # Copyright (C) Sunplus Co., Ltd. 2021 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Sunplus SoC SP7021 UART Controller diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml index a5bb561bfcfb..31a3024ea789 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/tas2562.yaml @@ -55,7 +55,9 @@ properties: description: TDM TX current sense time slot. '#sound-dai-cells': - const: 1 + # The codec has a single DAI, the #sound-dai-cells=<1>; case is left in for backward + # compatibility but is deprecated. + enum: [0, 1] required: - compatible @@ -72,7 +74,7 @@ examples: codec: codec@4c { compatible = "ti,tas2562"; reg = <0x4c>; - #sound-dai-cells = <1>; + #sound-dai-cells = <0>; interrupt-parent = <&gpio1>; interrupts = <14>; shutdown-gpios = <&gpio1 15 0>; diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/tas2770.yaml index 26088adb9dc2..8908bf1122e9 100644 --- a/Documentation/devicetree/bindings/sound/tas2770.yaml +++ b/Documentation/devicetree/bindings/sound/tas2770.yaml @@ -57,7 +57,9 @@ properties: - 1 # Falling edge '#sound-dai-cells': - const: 1 + # The codec has a single DAI, the #sound-dai-cells=<1>; case is left in for backward + # compatibility but is deprecated. + enum: [0, 1] required: - compatible @@ -74,7 +76,7 @@ examples: codec: codec@41 { compatible = "ti,tas2770"; reg = <0x41>; - #sound-dai-cells = <1>; + #sound-dai-cells = <0>; interrupt-parent = <&gpio1>; interrupts = <14>; reset-gpio = <&gpio1 15 0>; diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/tas27xx.yaml index 8cba01316855..a876545ec87d 100644 --- a/Documentation/devicetree/bindings/sound/tas27xx.yaml +++ b/Documentation/devicetree/bindings/sound/tas27xx.yaml @@ -50,7 +50,9 @@ properties: description: TDM TX voltage sense time slot. '#sound-dai-cells': - const: 1 + # The codec has a single DAI, the #sound-dai-cells=<1>; case is left in for backward + # compatibility but is deprecated. + enum: [0, 1] required: - compatible @@ -67,7 +69,7 @@ examples: codec: codec@38 { compatible = "ti,tas2764"; reg = <0x38>; - #sound-dai-cells = <1>; + #sound-dai-cells = <0>; interrupt-parent = <&gpio1>; interrupts = <14>; reset-gpios = <&gpio1 15 0>; diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index f59125bc79d1..0b4e21bde5bc 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -8,7 +8,7 @@ Required properties: "ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256 "ti,tas2505" TAS2505, TAS2521 - reg: I2C slave address - - supply-*: Required supply regulators are: + - *-supply: Required supply regulators are: "iov" - digital IO power supply "ldoin" - LDO power supply "dv" - Digital core power supply diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml index fe599e443eaf..3aecea77869f 100644 --- a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml @@ -12,10 +12,16 @@ maintainers: properties: compatible: - enum: - - fsl,imx6q-tempmon - - fsl,imx6sx-tempmon - - fsl,imx7d-tempmon + oneOf: + - enum: + - fsl,imx6q-tempmon + - fsl,imx6sx-tempmon + - fsl,imx7d-tempmon + - items: + - enum: + - fsl,imx6sll-tempmon + - fsl,imx6ul-tempmon + - const: fsl,imx6sx-tempmon interrupts: description: | diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml index 8273ac55b63f..01253d58bf9f 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -124,8 +124,8 @@ examples: #size-cells = <0>; #io-channel-cells = <1>; - /* Other propreties are omitted */ - adc-chan@4c { + /* Other properties are omitted */ + channel@4c { reg = ; }; }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml index 52ec18cf1eda..3c81def03c84 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml @@ -178,10 +178,11 @@ examples: #io-channel-cells = <1>; /* Other properties are omitted */ - conn-therm@4f { + channel@4f { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; + label = "conn_therm"; }; }; @@ -217,16 +218,18 @@ examples: #io-channel-cells = <1>; /* Other properties are omitted */ - xo-therm@44 { + channel@44 { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; + label = "xo_therm"; }; - conn-therm@147 { + channel@147 { reg = ; qcom,ratiometric; qcom,hw-settle-time = <200>; + label = "conn_therm"; }; }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 926e9c51c93c..d1ec963a6834 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -326,7 +326,7 @@ examples: - | #include // Example 1 (new calbiration data: for pre v1 IP): - thermal-sensor@900000 { + thermal-sensor@4a9000 { compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1"; reg = <0x4a9000 0x1000>, /* TM */ <0x4a8000 0x1000>; /* SROT */ @@ -356,7 +356,7 @@ examples: - | #include // Example 1 (legacy: for pre v1 IP): - tsens1: thermal-sensor@900000 { + tsens1: thermal-sensor@4a9000 { compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1"; reg = <0x4a9000 0x1000>, /* TM */ <0x4a8000 0x1000>; /* SROT */ diff --git a/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml b/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml new file mode 100644 index 000000000000..bffdab0b0185 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/renesas,rz-mtu3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a) + +maintainers: + - Biju Das + +description: | + This hardware block consists of eight 16-bit timer channels and one + 32- bit timer channel. It supports the following specifications: + - Pulse input/output: 28 lines max. + - Pulse input 3 lines + - Count clock 11 clocks for each channel (14 clocks for MTU0, 12 clocks + for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2 combination + (when LWA = 1)) + - Operating frequency Up to 100 MHz + - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8] + - Waveform output on compare match + - Input capture function (noise filter setting available) + - Counter-clearing operation + - Simultaneous writing to multiple timer counters (TCNT) + (excluding MTU8). + - Simultaneous clearing on compare match or input capture + (excluding MTU8). + - Simultaneous input and output to registers in synchronization with + counter operations (excluding MTU8). + - Up to 12-phase PWM output in combination with synchronous operation + (excluding MTU8) + - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8] + - Buffer operation specifiable + - [MTU1, MTU2] + - Phase counting mode can be specified independently + - 32-bit phase counting mode can be specified for interlocked operation + of MTU1 and MTU2 (when TMDR3.LWA = 1) + - Cascade connection operation available + - [MTU3, MTU4, MTU6, and MTU7] + - Through interlocked operation of MTU3/4 and MTU6/7, the positive and + negative signals in six phases (12 phases in total) can be output in + complementary PWM and reset-synchronized PWM operation. + - In complementary PWM mode, values can be transferred from buffer + registers to temporary registers at crests and troughs of the timer- + counter values or when the buffer registers (TGRD registers in MTU4 + and MTU7) are written to. + - Double-buffering selectable in complementary PWM mode. + - [MTU3 and MTU4] + - Through interlocking with MTU0, a mode for driving AC synchronous + motors (brushless DC motors) by using complementary PWM output and + reset-synchronized PWM output is settable and allows the selection + of two types of waveform output (chopping or level). + - [MTU5] + - Capable of operation as a dead-time compensation counter. + - [MTU0/MTU5, MTU1, MTU2, and MTU8] + - 32-bit phase counting mode specifiable by combining MTU1 and MTU2 and + through interlocked operation with MTU0/MTU5 and MTU8. + - Interrupt-skipping function + - In complementary PWM mode, interrupts on crests and troughs of counter + values and triggers to start conversion by the A/D converter can be + skipped. + - Interrupt sources: 43 sources. + - Buffer operation: + - Automatic transfer of register data (transfer from the buffer + register to the timer register). + - Trigger generation + - A/D converter start triggers can be generated + - A/D converter start request delaying function enables A/D converter + to be started with any desired timing and to be synchronized with + PWM output. + - Low power consumption function + - The MTU3a can be placed in the module-stop state. + + There are two phase counting modes. 16-bit phase counting mode in which + MTU1 and MTU2 operate independently, and cascade connection 32-bit phase + counting mode in which MTU1 and MTU2 are cascaded. + + In phase counting mode, the phase difference between two external input + clocks is detected and the corresponding TCNT is incremented or + decremented. + The below counters are supported + count0 - MTU1 16-bit phase counting + count1 - MTU2 16-bit phase counting + count2 - MTU1+ MTU2 32-bit phase counting + + The module supports PWM mode{1,2}, Reset-synchronized PWM mode and + complementary PWM mode{1,2,3}. + + In complementary PWM mode, six positive-phase and six negative-phase PWM + waveforms (12 phases in total) with dead time can be output by + combining MTU{3,4} and MTU{6,7}. + + The below pwm channels are supported in pwm mode 1. + pwm0 - MTU0.MTIOC0A PWM mode 1 + pwm1 - MTU0.MTIOC0C PWM mode 1 + pwm2 - MTU1.MTIOC1A PWM mode 1 + pwm3 - MTU2.MTIOC2A PWM mode 1 + pwm4 - MTU3.MTIOC3A PWM mode 1 + pwm5 - MTU3.MTIOC3C PWM mode 1 + pwm6 - MTU4.MTIOC4A PWM mode 1 + pwm7 - MTU4.MTIOC4C PWM mode 1 + pwm8 - MTU6.MTIOC6A PWM mode 1 + pwm9 - MTU6.MTIOC6C PWM mode 1 + pwm10 - MTU7.MTIOC7A PWM mode 1 + pwm11 - MTU7.MTIOC7C PWM mode 1 + +properties: + compatible: + items: + - enum: + - renesas,r9a07g044-mtu3 # RZ/G2{L,LC} + - renesas,r9a07g054-mtu3 # RZ/V2L + - const: renesas,rz-mtu3 + + reg: + maxItems: 1 + + interrupts: + items: + - description: MTU0.TGRA input capture/compare match + - description: MTU0.TGRB input capture/compare match + - description: MTU0.TGRC input capture/compare match + - description: MTU0.TGRD input capture/compare match + - description: MTU0.TCNT overflow + - description: MTU0.TGRE compare match + - description: MTU0.TGRF compare match + - description: MTU1.TGRA input capture/compare match + - description: MTU1.TGRB input capture/compare match + - description: MTU1.TCNT overflow + - description: MTU1.TCNT underflow + - description: MTU2.TGRA input capture/compare match + - description: MTU2.TGRB input capture/compare match + - description: MTU2.TCNT overflow + - description: MTU2.TCNT underflow + - description: MTU3.TGRA input capture/compare match + - description: MTU3.TGRB input capture/compare match + - description: MTU3.TGRC input capture/compare match + - description: MTU3.TGRD input capture/compare match + - description: MTU3.TCNT overflow + - description: MTU4.TGRA input capture/compare match + - description: MTU4.TGRB input capture/compare match + - description: MTU4.TGRC input capture/compare match + - description: MTU4.TGRD input capture/compare match + - description: MTU4.TCNT overflow/underflow + - description: MTU5.TGRU input capture/compare match + - description: MTU5.TGRV input capture/compare match + - description: MTU5.TGRW input capture/compare match + - description: MTU6.TGRA input capture/compare match + - description: MTU6.TGRB input capture/compare match + - description: MTU6.TGRC input capture/compare match + - description: MTU6.TGRD input capture/compare match + - description: MTU6.TCNT overflow + - description: MTU7.TGRA input capture/compare match + - description: MTU7.TGRB input capture/compare match + - description: MTU7.TGRC input capture/compare match + - description: MTU7.TGRD input capture/compare match + - description: MTU7.TCNT overflow/underflow + - description: MTU8.TGRA input capture/compare match + - description: MTU8.TGRB input capture/compare match + - description: MTU8.TGRC input capture/compare match + - description: MTU8.TGRD input capture/compare match + - description: MTU8.TCNT overflow + - description: MTU8.TCNT underflow + + interrupt-names: + items: + - const: tgia0 + - const: tgib0 + - const: tgic0 + - const: tgid0 + - const: tgiv0 + - const: tgie0 + - const: tgif0 + - const: tgia1 + - const: tgib1 + - const: tgiv1 + - const: tgiu1 + - const: tgia2 + - const: tgib2 + - const: tgiv2 + - const: tgiu2 + - const: tgia3 + - const: tgib3 + - const: tgic3 + - const: tgid3 + - const: tgiv3 + - const: tgia4 + - const: tgib4 + - const: tgic4 + - const: tgid4 + - const: tgiv4 + - const: tgiu5 + - const: tgiv5 + - const: tgiw5 + - const: tgia6 + - const: tgib6 + - const: tgic6 + - const: tgid6 + - const: tgiv6 + - const: tgia7 + - const: tgib7 + - const: tgic7 + - const: tgid7 + - const: tgiv7 + - const: tgia8 + - const: tgib8 + - const: tgic8 + - const: tgid8 + - const: tgiv8 + - const: tgiu8 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + "#pwm-cells": + const: 2 + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include + #include + + mtu3: timer@10001200 { + compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3"; + reg = <0x10001200 0xb00>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0", + "tgif0", + "tgia1", "tgib1", "tgiv1", "tgiu1", + "tgia2", "tgib2", "tgiv2", "tgiu2", + "tgia3", "tgib3", "tgic3", "tgid3", "tgiv3", + "tgia4", "tgib4", "tgic4", "tgid4", "tgiv4", + "tgiu5", "tgiv5", "tgiw5", + "tgia6", "tgib6", "tgic6", "tgid6", "tgiv6", + "tgia7", "tgib7", "tgic7", "tgid7", "tgiv7", + "tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8"; + clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>; + power-domains = <&cpg>; + resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>; + #pwm-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml index 65e59836a660..19e56b7577a0 100644 --- a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml +++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.yaml @@ -23,8 +23,8 @@ properties: - rockchip,rk3188-timer - rockchip,rk3228-timer - rockchip,rk3229-timer - - rockchip,rk3288-timer - rockchip,rk3368-timer + - rockchip,rk3588-timer - rockchip,px30-timer - const: rockchip,rk3288-timer reg: diff --git a/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml b/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml index c31e207d1652..456797967adc 100644 --- a/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml +++ b/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/timestamp/nvidia,tegra194-hte.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Tegra194 on chip generic hardware timestamping engine (HTE) +title: Tegra on chip generic hardware timestamping engine (HTE) provider maintainers: - Dipen Patel @@ -23,6 +23,8 @@ properties: enum: - nvidia,tegra194-gte-aon - nvidia,tegra194-gte-lic + - nvidia,tegra234-gte-aon + - nvidia,tegra234-gte-lic reg: maxItems: 1 @@ -40,12 +42,20 @@ properties: nvidia,slices: $ref: /schemas/types.yaml#/definitions/uint32 + deprecated: true description: HTE lines are arranged in 32 bit slice where each bit represents different line/signal that it can enable/configure for the timestamp. It is u32 - property and depends on the HTE instance in the chip. The value 3 is for - GPIO GTE and 11 for IRQ GTE. - enum: [3, 11] + property and the value depends on the HTE instance in the chip. The AON + GTE instances for both Tegra194 and Tegra234 has 3 slices. The Tegra194 + LIC instance has 11 slices and Tegra234 LIC has 17 slices. + enum: [3, 11, 17] + + nvidia,gpio-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle to AON gpio controller instance. This is required to handle + namespace conversion between GPIO and GTE. '#timestamp-cells': description: @@ -59,9 +69,53 @@ required: - compatible - reg - interrupts - - nvidia,slices - "#timestamp-cells" +allOf: + - if: + properties: + compatible: + contains: + enum: + - nvidia,tegra194-gte-aon + - nvidia,tegra234-gte-aon + then: + properties: + nvidia,slices: + const: 3 + + - if: + properties: + compatible: + contains: + enum: + - nvidia,tegra194-gte-lic + then: + properties: + nvidia,slices: + const: 11 + + - if: + properties: + compatible: + contains: + enum: + - nvidia,tegra234-gte-lic + then: + properties: + nvidia,slices: + const: 17 + + - if: + properties: + compatible: + contains: + enum: + - nvidia,tegra234-gte-aon + then: + required: + - nvidia,gpio-controller + additionalProperties: false examples: @@ -71,7 +125,6 @@ examples: reg = <0xc1e0000 0x10000>; interrupts = <0 13 0x4>; nvidia,int-threshold = <1>; - nvidia,slices = <3>; #timestamp-cells = <1>; }; @@ -81,7 +134,6 @@ examples: reg = <0x3aa0000 0x10000>; interrupts = <0 11 0x4>; nvidia,int-threshold = <1>; - nvidia,slices = <11>; #timestamp-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml index f38a2be07eda..da757c1155d4 100644 --- a/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml +++ b/Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/amlogic,meson-g12a-usb-ctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson G12A DWC3 USB SoC Controller Glue diff --git a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml index ad075407d85e..1536cbec6334 100644 --- a/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Broadcom STB USB EHCI Controller allOf: - - $ref: "usb-hcd.yaml" + - $ref: usb-hcd.yaml maintainers: - Al Cooper diff --git a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml index cae46c4982ad..69a93a0722f0 100644 --- a/Documentation/devicetree/bindings/usb/cdns,usb3.yaml +++ b/Documentation/devicetree/bindings/usb/cdns,usb3.yaml @@ -64,7 +64,7 @@ properties: description: size of memory intended as internal memory for endpoints buffers expressed in KB - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint16 cdns,phyrst-a-enable: description: Enable resetting of PHY if Rx fail is detected diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt deleted file mode 100644 index 72ceea575d58..000000000000 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ /dev/null @@ -1,159 +0,0 @@ -* USB2 ChipIdea USB controller for ci13xxx - -Required properties: -- compatible: should be one of: - "fsl,imx23-usb" - "fsl,imx27-usb" - "fsl,imx28-usb" - "fsl,imx6q-usb" - "fsl,imx6sl-usb" - "fsl,imx6sx-usb" - "fsl,imx6ul-usb" - "fsl,imx7d-usb" - "fsl,imx7ulp-usb" - "fsl,imx8mm-usb" - "lsi,zevio-usb" - "qcom,ci-hdrc" - "chipidea,usb2" - "xlnx,zynq-usb-2.20a" - "nvidia,tegra20-udc" - "nvidia,tegra30-udc" - "nvidia,tegra114-udc" - "nvidia,tegra124-udc" -- reg: base address and length of the registers -- interrupts: interrupt for the USB controller - -Recommended properies: -- phy_type: the type of the phy connected to the core. Should be one - of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this - property the PORTSC register won't be touched. -- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" - -Deprecated properties: -- usb-phy: phandle for the PHY device. Use "phys" instead. -- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead. - -Optional properties: -- clocks: reference to the USB clock -- phys: reference to the USB PHY -- phy-names: should be "usb-phy" -- vbus-supply: reference to the VBUS regulator -- maximum-speed: limit the maximum connection speed to "full-speed". -- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts -- itc-setting: interrupt threshold control register control, the setting - should be aligned with ITC bits at register USBCMD. -- ahb-burst-config: it is vendor dependent, the required value should be - aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This - property is used to change AHB burst configuration, check the chipidea - spec for meaning of each value. If this property is not existed, it - will use the reset value. -- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword - (4 bytes), This register represents the maximum length of a the burst - in 32-bit words while moving data from system memory to the USB - bus, the value of this property will only take effect if property - "ahb-burst-config" is set to 0, if this property is missing the reset - default of the hardware implementation will be used. -- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword - (4 bytes), This register represents the maximum length of a the burst - in 32-bit words while moving data from the USB bus to system memory, - the value of this property will only take effect if property - "ahb-burst-config" is set to 0, if this property is missing the reset - default of the hardware implementation will be used. -- extcon: phandles to external connector devices. First phandle should point to - external connector, which provide "USB" cable events, the second should point - to external connector device, which provide "USB-HOST" cable events. If one - of the external connector devices is not required, empty <0> phandle should - be specified. -- phy-clkgate-delay-us: the delay time (us) between putting the PHY into - low power mode and gating the PHY clock. -- non-zero-ttctrl-ttha: after setting this property, the value of register - ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default - value. It needs to be very carefully for setting this property, it is - recommended that consult with your IC engineer before setting this value. - On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this - property only affects siTD. - If this property is not set, the max packet size is 1023 bytes, and if - the total of packet size for pervious transactions are more than 256 bytes, - it can't accept any transactions within this frame. The use case is single - transaction, but higher frame rate. - If this property is set, the max packet size is 188 bytes, it can handle - more transactions than above case, it can accept transactions until it - considers the left room size within frame is less than 188 bytes, software - needs to make sure it does not send more than 90% - maximum_periodic_data_per_frame. The use case is multiple transactions, but - less frame rate. -- mux-controls: The mux control for toggling host/device output of this - controller. It's expected that a mux state of 0 indicates device mode and a - mux state of 1 indicates host mode. -- mux-control-names: Shall be "usb_switch" if mux-controls is specified. -- pinctrl-names: Names for optional pin modes in "default", "host", "device". - In case of HSIC-mode, "idle" and "active" pin modes are mandatory. In this - case, the "idle" state needs to pull down the data and strobe pin - and the "active" state needs to pull up the strobe pin. -- pinctrl-n: alternate pin modes - -i.mx specific properties -- fsl,usbmisc: phandler of non-core register device, with one - argument that indicate usb controller index -- disable-over-current: disable over current detect -- over-current-active-low: over current signal polarity is active low. -- over-current-active-high: over current signal polarity is active high. - It's recommended to specify the over current polarity. -- power-active-high: power signal polarity is active high -- external-vbus-divider: enables off-chip resistor divider for Vbus -- samsung,picophy-pre-emp-curr-control: HS Transmitter Pre-Emphasis Current - Control. This signal controls the amount of current sourced to the - USB_OTG*_DP and USB_OTG*_DN pins after a J-to-K or K-to-J transition. - The range is from 0x0 to 0x3, the default value is 0x1. - Details can refer to TXPREEMPAMPTUNE0 bits of USBNC_n_PHY_CFG1. -- samsung,picophy-dc-vol-level-adjust: HS DC Voltage Level Adjustment. - Adjust the high-speed transmitter DC level voltage. - The range is from 0x0 to 0xf, the default value is 0x3. - Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. - -Example: - - usb@f7ed0000 { - compatible = "chipidea,usb2"; - reg = <0xf7ed0000 0x10000>; - interrupts = ; - clocks = <&chip CLKID_USB0>; - phys = <&usb_phy0>; - phy-names = "usb-phy"; - vbus-supply = <®_usb0_vbus>; - itc-setting = <0x4>; /* 4 micro-frames */ - /* Incremental burst of unspecified length */ - ahb-burst-config = <0x0>; - tx-burst-size-dword = <0x10>; /* 64 bytes */ - rx-burst-size-dword = <0x10>; - extcon = <0>, <&usb_id>; - phy-clkgate-delay-us = <400>; - mux-controls = <&usb_switch>; - mux-control-names = "usb_switch"; - }; - -Example for HSIC: - - usb@2184400 { - compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; - reg = <0x02184400 0x200>; - interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clks IMX6QDL_CLK_USBOH3>; - fsl,usbphy = <&usbphynop1>; - fsl,usbmisc = <&usbmisc 2>; - phy_type = "hsic"; - dr_mode = "host"; - ahb-burst-config = <0x0>; - tx-burst-size-dword = <0x10>; - rx-burst-size-dword = <0x10>; - pinctrl-names = "idle", "active"; - pinctrl-0 = <&pinctrl_usbh2_idle>; - pinctrl-1 = <&pinctrl_usbh2_active>; - #address-cells = <1>; - #size-cells = <0>; - - usbnet: ethernet@1 { - compatible = "usb424,9730"; - reg = <1>; - }; - }; diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml new file mode 100644 index 000000000000..b26d26c2b023 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml @@ -0,0 +1,448 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ci-hdrc-usb2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: USB2 ChipIdea USB controller + +maintainers: + - Xu Yang + - Peng Fan + +properties: + compatible: + oneOf: + - enum: + - chipidea,usb2 + - lsi,zevio-usb + - nvidia,tegra20-ehci + - nvidia,tegra20-udc + - nvidia,tegra30-ehci + - nvidia,tegra30-udc + - nvidia,tegra114-udc + - nvidia,tegra124-udc + - qcom,ci-hdrc + - items: + - enum: + - nvidia,tegra114-ehci + - nvidia,tegra124-ehci + - nvidia,tegra210-ehci + - const: nvidia,tegra30-ehci + - items: + - enum: + - fsl,imx23-usb + - fsl,imx25-usb + - fsl,imx28-usb + - fsl,imx50-usb + - fsl,imx51-usb + - fsl,imx53-usb + - fsl,imx6q-usb + - fsl,imx6sl-usb + - fsl,imx6sx-usb + - fsl,imx6ul-usb + - fsl,imx7d-usb + - fsl,vf610-usb + - const: fsl,imx27-usb + - items: + - const: fsl,imx8dxl-usb + - const: fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - items: + - enum: + - fsl,imx8mm-usb + - fsl,imx8mn-usb + - const: fsl,imx7d-usb + - const: fsl,imx27-usb + - items: + - enum: + - fsl,imx6sll-usb + - fsl,imx7ulp-usb + - const: fsl,imx6ul-usb + - const: fsl,imx27-usb + - items: + - const: xlnx,zynq-usb-2.20a + - const: chipidea,usb2 + + reg: + minItems: 1 + maxItems: 2 + + interrupts: + minItems: 1 + maxItems: 2 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + dr_mode: true + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + maxItems: 1 + + "#reset-cells": + const: 1 + + phy_type: true + + itc-setting: + description: + interrupt threshold control register control, the setting should be + aligned with ITC bits at register USBCMD. + $ref: /schemas/types.yaml#/definitions/uint32 + + ahb-burst-config: + description: + it is vendor dependent, the required value should be aligned with + AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This property is + used to change AHB burst configuration, check the chipidea spec for + meaning of each value. If this property is not existed, it will use + the reset value. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x7 + + tx-burst-size-dword: + description: + it is vendor dependent, the tx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit + words while moving data from system memory to the USB bus, the value + of this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + rx-burst-size-dword: + description: + it is vendor dependent, the rx burst size in dword (4 bytes), This + register represents the maximum length of a the burst in 32-bit words + while moving data from the USB bus to system memory, the value of + this property will only take effect if property "ahb-burst-config" + is set to 0, if this property is missing the reset default of the + hardware implementation will be used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x20 + + extcon: + description: + Phandles to external connector devices. First phandle should point + to external connector, which provide "USB" cable events, the second + should point to external connector device, which provide "USB-HOST" + cable events. If one of the external connector devices is not + required, empty <0> phandle should be specified. + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + items: + - description: vbus extcon + - description: id extcon + + phy-clkgate-delay-us: + description: + The delay time (us) between putting the PHY into low power mode and + gating the PHY clock. + + non-zero-ttctrl-ttha: + description: + After setting this property, the value of register ttctrl.ttha + will be 0x7f; if not, the value will be 0x0, this is the default + value. It needs to be very carefully for setting this property, it + is recommended that consult with your IC engineer before setting + this value. On the most of chipidea platforms, the "usage_tt" flag + at RTL is 0, so this property only affects siTD. + + If this property is not set, the max packet size is 1023 bytes, and + if the total of packet size for pervious transactions are more than + 256 bytes, it can't accept any transactions within this frame. The + use case is single transaction, but higher frame rate. + + If this property is set, the max packet size is 188 bytes, it can + handle more transactions than above case, it can accept transactions + until it considers the left room size within frame is less than 188 + bytes, software needs to make sure it does not send more than 90% + maximum_periodic_data_per_frame. The use case is multiple + transactions, but less frame rate. + type: boolean + + mux-controls: + description: + The mux control for toggling host/device output of this controller. + It's expected that a mux state of 0 indicates device mode and a mux + state of 1 indicates host mode. + maxItems: 1 + + mux-control-names: + const: usb_switch + + operating-points-v2: + description: A phandle to the OPP table containing the performance states. + $ref: /schemas/types.yaml#/definitions/phandle + + pinctrl-names: + description: + Names for optional pin modes in "default", "host", "device". + In case of HSIC-mode, "idle" and "active" pin modes are mandatory. + In this case, the "idle" state needs to pull down the data and + strobe pin and the "active" state needs to pull up the strobe pin. + oneOf: + - items: + - const: idle + - const: active + - items: + - const: default + - enum: + - host + - device + - items: + - const: default + + pinctrl-0: + maxItems: 1 + + pinctrl-1: + maxItems: 1 + + phys: + maxItems: 1 + + phy-names: + const: usb-phy + + phy-select: + description: + Phandler of TCSR node with two argument that indicate register + offset, and phy index + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - description: phandle to TCSR node + - description: register offset + - description: phy index + + vbus-supply: + description: reference to the VBUS regulator. + + fsl,usbmisc: + description: + Phandler of non-core register device, with one argument that + indicate usb controller index + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to usbmisc node + - description: index of usb controller + + fsl,anatop: + description: phandle for the anatop node. + $ref: /schemas/types.yaml#/definitions/phandle + + disable-over-current: + type: boolean + description: disable over current detect + + over-current-active-low: + type: boolean + description: over current signal polarity is active low + + over-current-active-high: + type: boolean + description: + Over current signal polarity is active high. It's recommended to + specify the over current polarity. + + power-active-high: + type: boolean + description: power signal polarity is active high + + external-vbus-divider: + type: boolean + description: enables off-chip resistor divider for Vbus + + samsung,picophy-pre-emp-curr-control: + description: + HS Transmitter Pre-Emphasis Current Control. This signal controls + the amount of current sourced to the USB_OTG*_DP and USB_OTG*_DN + pins after a J-to-K or K-to-J transition. The range is from 0x0 to + 0x3, the default value is 0x1. Details can refer to TXPREEMPAMPTUNE0 + bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0x3 + + samsung,picophy-dc-vol-level-adjust: + description: + HS DC Voltage Level Adjustment. Adjust the high-speed transmitter DC + level voltage. The range is from 0x0 to 0xf, the default value is + 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0xf + + usb-phy: + description: phandle for the PHY device. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + fsl,usbphy: + description: phandle of usb phy that connects to the port. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + nvidia,phy: + description: phandle of usb phy that connects to the port. Use "phys" instead. + $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + + nvidia,needs-double-reset: + description: Indicates double reset or not. + type: boolean + deprecated: true + + port: + description: + Any connector to the data bus of this controller should be modelled + using the OF graph bindings specified, if the "usb-role-switch" + property is used. + $ref: /schemas/graph.yaml#/properties/port + + reset-gpios: + maxItems: 1 + + ulpi: + type: object + additionalProperties: false + patternProperties: + "^phy(-[0-9])?$": + description: The phy child node for Qcom chips. + type: object + $ref: /schemas/phy/qcom,usb-hs-phy.yaml + +dependencies: + port: [ usb-role-switch ] + mux-controls: [ mux-control-names ] + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: usb-hcd.yaml# + - $ref: usb-drd.yaml# + - if: + properties: + phy_type: + const: hsic + required: + - phy_type + then: + properties: + pinctrl-names: + items: + - const: idle + - const: active + else: + properties: + pinctrl-names: + minItems: 1 + maxItems: 2 + oneOf: + - items: + - const: default + - enum: + - host + - device + - items: + - const: default + - if: + properties: + compatible: + contains: + enum: + - chipidea,usb2 + - lsi,zevio-usb + - nvidia,tegra20-udc + - nvidia,tegra30-udc + - nvidia,tegra114-udc + - nvidia,tegra124-udc + - qcom,ci-hdrc + - xlnx,zynq-usb-2.20a + then: + properties: + fsl,usbmisc: false + disable-over-current: false + over-current-active-low: false + over-current-active-high: false + power-active-high: false + external-vbus-divider: false + samsung,picophy-pre-emp-curr-control: false + samsung,picophy-dc-vol-level-adjust: false + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb@f7ed0000 { + compatible = "chipidea,usb2"; + reg = <0xf7ed0000 0x10000>; + interrupts = ; + clocks = <&chip CLKID_USB0>; + phys = <&usb_phy0>; + phy-names = "usb-phy"; + vbus-supply = <®_usb0_vbus>; + itc-setting = <0x4>; /* 4 micro-frames */ + /* Incremental burst of unspecified length */ + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; /* 64 bytes */ + rx-burst-size-dword = <0x10>; + extcon = <0>, <&usb_id>; + phy-clkgate-delay-us = <400>; + mux-controls = <&usb_switch>; + mux-control-names = "usb_switch"; + }; + + # Example for HSIC: + - | + #include + #include + + usb@2184400 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; + interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_USBOH3>; + fsl,usbphy = <&usbphynop1>; + fsl,usbmisc = <&usbmisc 2>; + phy_type = "hsic"; + dr_mode = "host"; + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; + rx-burst-size-dword = <0x10>; + pinctrl-names = "idle", "active"; + pinctrl-0 = <&pinctrl_usbh2_idle>; + pinctrl-1 = <&pinctrl_usbh2_active>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet@1 { + compatible = "usb424,9730"; + reg = <1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index 371ba93f3ce5..d3506090f8b1 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -75,11 +75,14 @@ properties: maxItems: 1 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 clock-names: items: - const: otg + - const: utmi + minItems: 1 disable-over-current: type: boolean diff --git a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml index 51120fe90322..f6e7a5c1ff0b 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml +++ b/Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/fcs,fsa4480.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/fcs,fsa4480.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: ON Semiconductor Analog Audio Switch diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml new file mode 100644 index 000000000000..50569d3ee767 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/fsl,imx8mq-dwc3.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/fsl,imx8mq-dwc3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP iMX8MQ Soc USB Controller + +maintainers: + - Li Jun + - Peng Fan + +select: + properties: + compatible: + contains: + enum: + - fsl,imx8mq-dwc3 + required: + - compatible + +properties: + compatible: + items: + - const: fsl,imx8mq-dwc3 + - const: snps,dwc3 + +allOf: + - $ref: snps,dwc3.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + usb_dwc3_1: usb@38200000 { + compatible = "fsl,imx8mq-dwc3", "snps,dwc3"; + reg = <0x38200000 0x10000>; + clocks = <&clk IMX8MQ_CLK_USB2_CTRL_ROOT>, + <&clk IMX8MQ_CLK_USB_CORE_REF>, + <&clk IMX8MQ_CLK_32K>; + clock-names = "bus_early", "ref", "suspend"; + interrupts = ; + phys = <&usb3_phy1>, <&usb3_phy1>; + phy-names = "usb2-phy", "usb3-phy"; + }; diff --git a/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml new file mode 100644 index 000000000000..2d3589d284b2 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/fsl,usbmisc.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/fsl,usbmisc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX wrapper module for Chipidea USB2 controller + +maintainers: + - Xu Yang + - Peng Fan + +properties: + compatible: + oneOf: + - enum: + - fsl,imx25-usbmisc + - fsl,imx27-usbmisc + - fsl,imx35-usbmisc + - fsl,imx51-usbmisc + - fsl,imx53-usbmisc + - fsl,imx6q-usbmisc + - fsl,vf610-usbmisc + - items: + - enum: + - fsl,imx6ul-usbmisc + - fsl,imx6sl-usbmisc + - fsl,imx6sx-usbmisc + - fsl,imx7d-usbmisc + - const: fsl,imx6q-usbmisc + - items: + - enum: + - fsl,imx7ulp-usbmisc + - fsl,imx8mm-usbmisc + - fsl,imx8mn-usbmisc + - const: fsl,imx7d-usbmisc + - const: fsl,imx6q-usbmisc + - items: + - const: fsl,imx6sll-usbmisc + - const: fsl,imx6ul-usbmisc + - const: fsl,imx6q-usbmisc + + clocks: + maxItems: 1 + + reg: + maxItems: 1 + + '#index-cells': + const: 1 + description: Cells used to describe usb controller index. + deprecated: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + usbmisc@2184800 { + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; + #index-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index 050cfd5acdaa..9445764bd8de 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -10,7 +10,7 @@ maintainers: - Greg Kroah-Hartman allOf: - - $ref: "usb-hcd.yaml" + - $ref: usb-hcd.yaml - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml index a9ba7257b884..d06d1e7d8876 100644 --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml @@ -148,7 +148,7 @@ allOf: properties: transceiver: false -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml index db841589fc33..594ebb3ee432 100644 --- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml @@ -10,7 +10,7 @@ maintainers: - Mathias Nyman allOf: - - $ref: "usb-xhci.yaml#" + - $ref: usb-xhci.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml index bf4b1d016e1f..f196beb826d8 100644 --- a/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml +++ b/Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/gpio-sbu-mux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: GPIO-based SBU mux diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml index 3cb631ea7079..276bf7554215 100644 --- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml +++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/maxim,max33359.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/maxim,max33359.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim TCPCI Type-C PD controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml index 6cad7ae2c70d..053264e60583 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6360-tcpc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/mediatek,mt6360-tcpc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Mediatek MT6360 Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml index 72f56cc88457..747d0f16d9b6 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index c119caa9ad16..e9644e333d78 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -11,7 +11,7 @@ maintainers: - Chunfeng Yun allOf: - - $ref: "usb-xhci.yaml" + - $ref: usb-xhci.yaml description: | There are two scenarios: @@ -77,6 +77,7 @@ properties: - description: Mcu bus clock for register access - description: DMA bus clock for data transfer - description: controller clock + - description: frame count clock clock-names: minItems: 1 @@ -86,14 +87,7 @@ properties: - const: mcu_ck - const: dma_ck - const: xhci_ck - - assigned-clocks: - minItems: 1 - maxItems: 5 - - assigned-clock-parents: - minItems: 1 - maxItems: 5 + - const: frmcnt_ck phys: description: diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml index d2655173e108..478214ab045e 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -11,7 +11,7 @@ maintainers: - Chunfeng Yun allOf: - - $ref: "usb-drd.yaml" + - $ref: usb-drd.yaml description: | The DRD controller has a glue layer IPPC (IP Port Control), and its host is @@ -66,6 +66,8 @@ properties: - description: Reference clock used by low power mode etc - description: Mcu bus clock for register access - description: DMA bus clock for data transfer + - description: DRD controller clock + - description: Frame count clock clock-names: minItems: 1 @@ -74,6 +76,8 @@ properties: - const: ref_ck - const: mcu_ck - const: dma_ck + - const: xhci_ck + - const: frmcnt_ck phys: description: @@ -204,9 +208,9 @@ patternProperties: example if the host mode is enabled. dependencies: - connector: [ 'usb-role-switch' ] - port: [ 'usb-role-switch' ] - role-switch-default-mode: [ 'usb-role-switch' ] + connector: [ usb-role-switch ] + port: [ usb-role-switch ] + role-switch-default-mode: [ usb-role-switch ] wakeup-source: [ 'mediatek,syscon-wakeup' ] required: diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml index f16ab30a95d2..a39d38db7714 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,musb.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,musb.yaml @@ -68,8 +68,8 @@ properties: type: object dependencies: - usb-role-switch: [ 'connector' ] - connector: [ 'usb-role-switch' ] + usb-role-switch: [ connector ] + connector: [ usb-role-switch ] required: - compatible diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml index e638f77658fc..e2270ce0c56b 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/nvidia,tegra-xudc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: NVIDIA Tegra XUSB device mode controller (XUDC) diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml new file mode 100644 index 000000000000..28eb25ecba74 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PTN5110 Typec Port Cotroller + +maintainers: + - Li Jun + +properties: + compatible: + const: nxp,ptn5110 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - connector + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tcpci@50 { + compatible = "nxp,ptn5110"; + reg = <0x50>; + interrupt-parent = <&gpio3>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 3e401014e3bc..d84281926f10 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -21,6 +21,7 @@ properties: - qcom,msm8994-dwc3 - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 + - qcom,qcm2290-dwc3 - qcom,qcs404-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 @@ -301,6 +302,7 @@ allOf: compatible: contains: enum: + - qcom,qcm2290-dwc3 - qcom,sm6115-dwc3 - qcom,sm6125-dwc3 - qcom,sm8150-dwc3 diff --git a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml index 623d04a88a81..9309f003cd07 100644 --- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml +++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml @@ -26,7 +26,7 @@ properties: phandle to the regulator that provides power to the hub. peer-hub: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: phandle to the peer hub on the controller. diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml index dd864b25a148..8da4d2ad1a91 100644 --- a/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml +++ b/Documentation/devicetree/bindings/usb/richtek,rt1711h.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/richtek,rt1711h.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/richtek,rt1711h.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Richtek RT1711H Type-C Port Switch and Power Delivery controller diff --git a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml index 8b9bd2cc58e9..4ced2f68e2a9 100644 --- a/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml +++ b/Documentation/devicetree/bindings/usb/richtek,rt1719.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/richtek,rt1719.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/richtek,rt1719.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Richtek RT1719 sink-only Type-C PD controller diff --git a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml index a09f4528aea3..6156dc26e65c 100644 --- a/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml +++ b/Documentation/devicetree/bindings/usb/smsc,usb3503.yaml @@ -14,6 +14,7 @@ properties: enum: - smsc,usb3503 - smsc,usb3503a + - smsc,usb3803 reg: maxItems: 1 @@ -33,6 +34,12 @@ properties: description: > GPIO for reset + bypass-gpios: + maxItems: 1 + description: > + GPIO for bypass. + Control signal to select between HUB MODE and BYPASS MODE. + disabled-ports: $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 1 @@ -46,9 +53,10 @@ properties: initial-mode: $ref: /schemas/types.yaml#/definitions/uint32 - enum: [1, 2] description: > - Specifies initial mode. 1 for Hub mode, 2 for standby mode. + Specifies initial mode. 1 for Hub mode, 2 for standby mode and 3 for bypass mode. + In bypass mode the downstream port 3 is connected to the upstream port with low + switch resistance R_on. clocks: maxItems: 1 @@ -71,6 +79,29 @@ properties: required: - compatible +allOf: + - if: + not: + properties: + compatible: + enum: + - smsc,usb3803 + then: + properties: + bypass-gpios: false + + - if: + required: + - bypass-gpios + then: + properties: + initial-mode: + enum: [1, 2, 3] + else: + properties: + initial-mode: + enum: [1, 2] + additionalProperties: false examples: @@ -92,6 +123,25 @@ examples: }; }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@8 { + compatible = "smsc,usb3803"; + reg = <0x08>; + connect-gpios = <&gpx3 0 1>; + disabled-ports = <2 3>; + intn-gpios = <&gpx3 4 1>; + reset-gpios = <&gpx3 5 1>; + bypass-gpios = <&gpx3 6 1>; + initial-mode = <3>; + clocks = <&clks 80>; + clock-names = "refclk"; + }; + }; + - | #include diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index be36956af53b..4f7625955ccc 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -70,6 +70,10 @@ properties: dma-coherent: true + extcon: + maxItems: 1 + deprecated: true + iommus: maxItems: 1 @@ -232,6 +236,11 @@ properties: When set, all SuperSpeed bus instances in park mode are disabled. type: boolean + snps,parkmode-disable-hs-quirk: + description: + When set, all HighSpeed bus instances in park mode are disabled. + type: boolean + snps,dis_metastability_quirk: description: When set, disable metastability workaround. CAUTION! Use only if you are @@ -256,6 +265,14 @@ properties: of resume. This option is to support certain legacy ULPI PHYs. type: boolean + snps,ulpi-ext-vbus-drv: + description: + Some ULPI USB PHY does not support internal VBUS supply, and driving + the CPEN pin, requires the configuration of the ulpi DRVVBUSEXTERNAL + bit. When set, the xhci host will configure the USB2 PHY drives VBUS + with an external supply. + type: boolean + snps,is-utmi-l1-suspend: description: True when DWC3 asserts output signal utmi_l1_suspend_n, false when @@ -270,7 +287,7 @@ properties: description: High-Speed PHY interface selection between UTMI+ and ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3. - $ref: /schemas/types.yaml#/definitions/uint8 + $ref: /schemas/types.yaml#/definitions/string enum: [utmi, ulpi] snps,quirk-frame-length-adjustment: @@ -365,6 +382,22 @@ properties: This port is used with the 'usb-role-switch' property to connect the dwc3 to type C connector. + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Those ports should be used with any connector to the data bus of this + controller using the OF graph bindings specified if the "usb-role-switch" + property is used. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: High Speed (HS) data bus. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Super Speed (SS) data bus. + wakeup-source: $ref: /schemas/types.yaml#/definitions/flag description: diff --git a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml index f6840cd5750d..acda2f47fbc9 100644 --- a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml +++ b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/st,stusb160x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/st,stusb160x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: STMicroelectronics STUSB160x Type-C controller diff --git a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml index f81ba3e90297..95ff9791baea 100644 --- a/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml +++ b/Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/ti,j721e-usb.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/ti,j721e-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI wrapper module for the Cadence USBSS-DRD controller @@ -53,12 +53,6 @@ properties: VBUS pin of the SoC via a 1/3 voltage divider. type: boolean - assigned-clocks: - maxItems: 1 - - assigned-clock-parents: - maxItems: 1 - '#address-cells': const: 2 diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml index c1f0194ad0d5..9252d893f694 100644 --- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml @@ -34,14 +34,6 @@ properties: minItems: 1 maxItems: 2 - assigned-clocks: - minItems: 1 - maxItems: 2 - - assigned-clock-parents: - minItems: 1 - maxItems: 2 - power-domains: maxItems: 1 description: Should contain a phandle to a PM domain provider node diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml index 7dfa34d11b0e..5497a60cddbc 100644 --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/usb/ti,tps6598x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/usb/ti,tps6598x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments 6598x Type-C Port Switch and Power Delivery controller @@ -35,8 +35,6 @@ properties: required: - compatible - reg - - interrupts - - interrupt-names additionalProperties: true diff --git a/Documentation/devicetree/bindings/usb/typec-tcpci.txt b/Documentation/devicetree/bindings/usb/typec-tcpci.txt deleted file mode 100644 index 2082522b1c32..000000000000 --- a/Documentation/devicetree/bindings/usb/typec-tcpci.txt +++ /dev/null @@ -1,49 +0,0 @@ -TCPCI(Typec port cotroller interface) binding ---------------------------------------------- - -Required properties: -- compatible: should be set one of following: - - "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110. - -- reg: the i2c slave address of typec port controller device. -- interrupt-parent: the phandle to the interrupt controller which provides - the interrupt. -- interrupts: interrupt specification for tcpci alert. - -Required sub-node: -- connector: The "usb-c-connector" attached to the tcpci chip, the bindings - of connector node are specified in - Documentation/devicetree/bindings/connector/usb-connector.yaml - -Example: - -ptn5110@50 { - compatible = "nxp,ptn5110"; - reg = <0x50>; - interrupt-parent = <&gpio3>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - - usb_con: connector { - compatible = "usb-c-connector"; - label = "USB-C"; - data-role = "dual"; - power-role = "dual"; - try-power-role = "sink"; - source-pdos = ; - sink-pdos = ; - op-sink-microwatt = <10000000>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@1 { - reg = <1>; - usb_con_ss: endpoint { - remote-endpoint = <&usb3_data_ss>; - }; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml index 7a771125ec76..da890ee60ce6 100644 --- a/Documentation/devicetree/bindings/usb/usb-device.yaml +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml @@ -76,7 +76,6 @@ patternProperties: maxItems: 1 required: - - compatible - reg additionalProperties: true diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml index 921b986adc47..6734f4d3aa78 100644 --- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml +++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml @@ -27,6 +27,9 @@ properties: vcc-supply: description: phandle to the regulator that provides power to the PHY. + power-domains: + maxItems: 1 + reset-gpios: maxItems: 1 diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml index f2139a9f35fb..180a261c3e8f 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml @@ -10,7 +10,7 @@ maintainers: - Mathias Nyman allOf: - - $ref: "usb-hcd.yaml#" + - $ref: usb-hcd.yaml# properties: usb2-lpm-disable: diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt deleted file mode 100644 index 29b8f65ff849..000000000000 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ /dev/null @@ -1,19 +0,0 @@ -* Freescale i.MX non-core registers - -Required properties: -- #index-cells: Cells used to describe usb controller index. Should be <1> -- compatible: Should be one of below: - "fsl,imx6q-usbmisc" for imx6q - "fsl,vf610-usbmisc" for Vybrid vf610 - "fsl,imx6sx-usbmisc" for imx6sx - "fsl,imx7d-usbmisc" for imx7d - "fsl,imx7ulp-usbmisc" for imx7ulp - "fsl,imx8mm-usbmisc" for imx8mm -- reg: Should contain registers location and length - -Examples: -usbmisc@2184800 { - #index-cells = <1>; - compatible = "fsl,imx6q-usbmisc"; - reg = <0x02184800 0x200>; -}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 72c0f5dcef43..82d39ab0231b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -777,6 +777,8 @@ patternProperties: description: Lontium Semiconductor Corporation "^loongson,.*": description: Loongson Technology Corporation Limited + "^loongmasses,.*": + description: Nanjing Loongmasses Ltd. "^lsi,.*": description: LSI Corp. (LSI Logic) "^lwn,.*": diff --git a/Documentation/devicetree/bindings/w1/maxim,ds2482.yaml b/Documentation/devicetree/bindings/w1/maxim,ds2482.yaml new file mode 100644 index 000000000000..422becc6e1fa --- /dev/null +++ b/Documentation/devicetree/bindings/w1/maxim,ds2482.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/w1/maxim,ds2482.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim One wire bus master controller + +maintainers: + - Stefan Wahren + +description: | + I2C to 1-wire bridges + + https://www.analog.com/media/en/technical-documentation/data-sheets/ds2482-100.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/DS2482-800.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/DS2484.pdf + +properties: + compatible: + enum: + - maxim,ds2482 + - maxim,ds2484 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: + type: object + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + onewire@18 { + compatible = "maxim,ds2484"; + reg = <0x18>; + }; + }; diff --git a/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml b/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml new file mode 100644 index 000000000000..fea84f5b7e6d --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/alphascale,asm9260-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Alphascale asm9260 Watchdog timer + +allOf: + - $ref: watchdog.yaml# + +maintainers: + - Oleksij Rempel + +properties: + compatible: + const: alphascale,asm9260-wdt + + reg: + maxItems: 1 + + clocks: + items: + - description: source clock, used for tick counter + - description: ahb gate + + clock-names: + items: + - const: mod + - const: ahb + + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + items: + - const: wdt_rst + + alphascale,mode: + description: | + Specifies the reset mode of operation. If set to sw, then reset is handled + via interrupt request, if set to debug, then it does nothing and logs. + $ref: /schemas/types.yaml#/definitions/string + enum: [hw, sw, debug] + default: hw + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + watchdog0: watchdog@80048000 { + compatible = "alphascale,asm9260-wdt"; + reg = <0x80048000 0x10>; + clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>; + clock-names = "mod", "ahb"; + interrupts = <55>; + timeout-sec = <30>; + alphascale,mode = "hw"; + }; diff --git a/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt b/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt deleted file mode 100644 index 75b265a04047..000000000000 --- a/Documentation/devicetree/bindings/watchdog/alphascale-asm9260.txt +++ /dev/null @@ -1,35 +0,0 @@ -Alphascale asm9260 Watchdog timer - -Required properties: - -- compatible : should be "alphascale,asm9260-wdt". -- reg : Specifies base physical address and size of the registers. -- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt -- clock-names : should be set to - "mod" - source for tick counter. - "ahb" - ahb gate. -- resets : phandle pointing to the system reset controller with - line index for the watchdog. -- reset-names : should be set to "wdt_rst". - -Optional properties: -- timeout-sec : shall contain the default watchdog timeout in seconds, - if unset, the default timeout is 30 seconds. -- alphascale,mode : three modes are supported - "hw" - hw reset (default). - "sw" - sw reset. - "debug" - no action is taken. - -Example: - -watchdog0: watchdog@80048000 { - compatible = "alphascale,asm9260-wdt"; - reg = <0x80048000 0x10>; - clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>; - clock-names = "mod", "ahb"; - interrupts = <55>; - resets = <&rst WDT_RESET>; - reset-names = "wdt_rst"; - timeout-sec = <30>; - alphascale,mode = "hw"; -}; diff --git a/Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml b/Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml index 497d60408ea0..f5cc7aa1b93b 100644 --- a/Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/amlogic,meson-gxbb-wdt.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/watchdog/amlogic,meson-gxbb-wdt.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/watchdog/amlogic,meson-gxbb-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Meson GXBB SoCs Watchdog timer @@ -36,7 +36,7 @@ unevaluatedProperties: false examples: - | watchdog@98d0 { - compatible = "amlogic,meson-gxbb-wdt"; - reg = <0x98d0 0x10>; - clocks = <&xtal>; + compatible = "amlogic,meson-gxbb-wdt"; + reg = <0x98d0 0x10>; + clocks = <&xtal>; }; diff --git a/Documentation/devicetree/bindings/watchdog/arm,sbsa-gwdt.yaml b/Documentation/devicetree/bindings/watchdog/arm,sbsa-gwdt.yaml index 6bfa46353c4e..aa804f96acba 100644 --- a/Documentation/devicetree/bindings/watchdog/arm,sbsa-gwdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm,sbsa-gwdt.yaml @@ -40,7 +40,6 @@ unevaluatedProperties: false examples: - | - watchdog@2a440000 { compatible = "arm,sbsa-gwdt"; reg = <0x2a440000 0x1000>, diff --git a/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml b/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml index a69cac8ec208..7aea255b301b 100644 --- a/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm,sp805.yaml @@ -43,7 +43,6 @@ properties: Clocks driving the watchdog timer hardware. The first clock is used for the actual watchdog counter. The second clock drives the register interface. - minItems: 2 maxItems: 2 clock-names: diff --git a/Documentation/devicetree/bindings/watchdog/arm,twd-wdt.yaml b/Documentation/devicetree/bindings/watchdog/arm,twd-wdt.yaml index bb8901854222..9646ac72051e 100644 --- a/Documentation/devicetree/bindings/watchdog/arm,twd-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm,twd-wdt.yaml @@ -44,7 +44,7 @@ examples: #include watchdog@2c000620 { - compatible = "arm,arm11mp-twd-wdt"; - reg = <0x2c000620 0x20>; - interrupts = ; + compatible = "arm,arm11mp-twd-wdt"; + reg = <0x2c000620 0x20>; + interrupts = ; }; diff --git a/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml index fa05d6252982..b5573852ef5a 100644 --- a/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - arm,smc-wdt + arm,smc-id: $ref: /schemas/types.yaml#/definitions/uint32 description: | @@ -30,9 +31,9 @@ unevaluatedProperties: false examples: - | watchdog { - compatible = "arm,smc-wdt"; - arm,smc-id = <0x82003D06>; - timeout-sec = <15>; + compatible = "arm,smc-wdt"; + arm,smc-id = <0x82003D06>; + timeout-sec = <15>; }; ... diff --git a/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml index b28f7b57c36b..816f85ee2c77 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/atmel,sama5d4-wdt.yaml @@ -65,13 +65,13 @@ examples: #include watchdog@fc068640 { - compatible = "atmel,sama5d4-wdt"; - reg = <0xfc068640 0x10>; - interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; - timeout-sec = <10>; - atmel,watchdog-type = "hardware"; - atmel,dbg-halt; - atmel,idle-halt; + compatible = "atmel,sama5d4-wdt"; + reg = <0xfc068640 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; + timeout-sec = <10>; + atmel,watchdog-type = "hardware"; + atmel,dbg-halt; + atmel,idle-halt; }; ... diff --git a/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml b/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml index 428004e7f0c3..526ff908d134 100644 --- a/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml @@ -37,7 +37,7 @@ required: examples: - | watchdog@f040a7e8 { - compatible = "brcm,bcm7038-wdt"; - reg = <0xf040a7e8 0x16>; - clocks = <&upg_fixed>; + compatible = "brcm,bcm7038-wdt"; + reg = <0xf040a7e8 0x16>; + clocks = <&upg_fixed>; }; diff --git a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml index 6e135f48b3ba..726dc872ad02 100644 --- a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml +++ b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml @@ -52,16 +52,16 @@ examples: - | #include watchdog@41000000 { - compatible = "faraday,ftwdt010"; - reg = <0x41000000 0x1000>; - interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; - timeout-sec = <5>; + compatible = "faraday,ftwdt010"; + reg = <0x41000000 0x1000>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + timeout-sec = <5>; }; - | watchdog: watchdog@98500000 { - compatible = "moxa,moxart-watchdog", "faraday,ftwdt010"; - reg = <0x98500000 0x10>; - clocks = <&clk_apb>; - clock-names = "PCLK"; + compatible = "moxa,moxart-watchdog", "faraday,ftwdt010"; + reg = <0x98500000 0x10>; + clocks = <&clk_apb>; + clock-names = "PCLK"; }; ... diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml index d3790f1a96a2..4b7ed1355701 100644 --- a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml @@ -30,15 +30,13 @@ properties: clocks: maxItems: 1 - timeout-sec: true - required: - compatible - interrupts - reg - clocks -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.yaml b/Documentation/devicetree/bindings/watchdog/gpio-wdt.yaml deleted file mode 100644 index 155dc7965e9b..000000000000 --- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/watchdog/gpio-wdt.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: GPIO controlled watchdog - -maintainers: - - Robert Marko - -properties: - compatible: - const: linux,wdt-gpio - - gpios: - maxItems: 1 - description: GPIO connected to the WDT reset pin - - hw_algo: - $ref: /schemas/types.yaml#/definitions/string - description: Algorithm used by the driver - oneOf: - - description: - Either a high-to-low or a low-to-high transition clears the WDT counter. - The watchdog timer is disabled when GPIO is left floating or connected - to a three-state buffer. - const: toggle - - description: - Low or high level starts counting WDT timeout, the opposite level - disables the WDT. - Active level is determined by the GPIO flags. - const: level - - hw_margin_ms: - $ref: /schemas/types.yaml#/definitions/uint32 - description: Maximum time to reset watchdog circuit (in milliseconds) - minimum: 2 - maximum: 65535 - - always-running: - type: boolean - description: - If the watchdog timer cannot be disabled, add this flag to have the driver - keep toggling the signal without a client. - It will only cease to toggle the signal when the device is open and the - timeout elapsed. - -required: - - compatible - - gpios - - hw_algo - - hw_margin_ms - -unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/watchdog/linux,wdt-gpio.yaml b/Documentation/devicetree/bindings/watchdog/linux,wdt-gpio.yaml index 50af79af6416..499f1b7e03f9 100644 --- a/Documentation/devicetree/bindings/watchdog/linux,wdt-gpio.yaml +++ b/Documentation/devicetree/bindings/watchdog/linux,wdt-gpio.yaml @@ -8,6 +8,7 @@ title: GPIO-controlled Watchdog maintainers: - Guenter Roeck + - Robert Marko properties: compatible: @@ -19,11 +20,23 @@ properties: hw_algo: description: The algorithm used by the driver. - enum: [ level, toggle ] + oneOf: + - description: + Either a high-to-low or a low-to-high transition clears the WDT counter. + The watchdog timer is disabled when GPIO is left floating or connected + to a three-state buffer. + const: toggle + - description: + Low or high level starts counting WDT timeout, the opposite level + disables the WDT. + Active level is determined by the GPIO flags. + const: level hw_margin_ms: description: Maximum time to reset watchdog circuit (milliseconds). $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 2 + maximum: 65535 always-running: type: boolean @@ -42,7 +55,7 @@ required: allOf: - $ref: watchdog.yaml# -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mt7621-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mt7621-wdt.yaml index a668d0c2f14b..18160869c378 100644 --- a/Documentation/devicetree/bindings/watchdog/mediatek,mt7621-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/mediatek,mt7621-wdt.yaml @@ -34,7 +34,7 @@ additionalProperties: false examples: - | watchdog@100 { - compatible = "mediatek,mt7621-wdt"; - reg = <0x100 0x100>; - mediatek,sysctl = <&sysc>; + compatible = "mediatek,mt7621-wdt"; + reg = <0x100 0x100>; + mediatek,sysctl = <&sysc>; }; diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml index 55b34461df1b..cc502838bc39 100644 --- a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml @@ -22,6 +22,7 @@ properties: - enum: - mediatek,mt2712-wdt - mediatek,mt6589-wdt + - mediatek,mt6735-wdt - mediatek,mt6795-wdt - mediatek,mt7986-wdt - mediatek,mt8183-wdt @@ -38,6 +39,7 @@ properties: - mediatek,mt7623-wdt - mediatek,mt7629-wdt - mediatek,mt8173-wdt + - mediatek,mt8365-wdt - mediatek,mt8516-wdt - const: mediatek,mt6589-wdt diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 6448b633c970..6d0fe6abd06a 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -18,7 +18,10 @@ properties: - items: - enum: - qcom,kpss-wdt-ipq4019 + - qcom,apss-wdt-ipq5332 + - qcom,apss-wdt-ipq9574 - qcom,apss-wdt-msm8994 + - qcom,apss-wdt-qcm2290 - qcom,apss-wdt-qcs404 - qcom,apss-wdt-sa8775p - qcom,apss-wdt-sc7180 @@ -28,6 +31,7 @@ properties: - qcom,apss-wdt-sdm845 - qcom,apss-wdt-sdx55 - qcom,apss-wdt-sdx65 + - qcom,apss-wdt-sm6115 - qcom,apss-wdt-sm6350 - qcom,apss-wdt-sm8150 - qcom,apss-wdt-sm8250 @@ -113,26 +117,26 @@ examples: #include watchdog@17c10000 { - compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; - reg = <0x17c10000 0x1000>; - clocks = <&sleep_clk>; - interrupts = ; - timeout-sec = <10>; + compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; + reg = <0x17c10000 0x1000>; + clocks = <&sleep_clk>; + interrupts = ; + timeout-sec = <10>; }; - | #include watchdog@200a000 { - compatible = "qcom,kpss-wdt-ipq8064", "qcom,kpss-timer", "qcom,msm-timer"; - interrupts = , - , - , - , - ; - reg = <0x0200a000 0x100>; - clock-frequency = <25000000>; - clocks = <&sleep_clk>; - clock-names = "sleep"; - cpu-offset = <0x80000>; + compatible = "qcom,kpss-wdt-ipq8064", "qcom,kpss-timer", "qcom,msm-timer"; + interrupts = , + , + , + , + ; + reg = <0x0200a000 0x100>; + clock-frequency = <25000000>; + clocks = <&sleep_clk>; + clock-names = "sleep"; + cpu-offset = <0x80000>; }; diff --git a/Documentation/devicetree/bindings/watchdog/ralink,rt2880-wdt.yaml b/Documentation/devicetree/bindings/watchdog/ralink,rt2880-wdt.yaml new file mode 100644 index 000000000000..51e00de947e9 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/ralink,rt2880-wdt.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/ralink,rt2880-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ralink Watchdog Timers + +maintainers: + - Sergio Paracuellos + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: ralink,rt2880-wdt + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + watchdog@100 { + compatible = "ralink,rt2880-wdt"; + reg = <0x120 0x10>; + clocks = <&clkref>; + resets = <&rstctrl 8>; + interrupt-parent = <&intc>; + interrupts = <1>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml b/Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml index 099245fe7b10..1f5390a67cdb 100644 --- a/Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml @@ -67,12 +67,10 @@ required: - reg - clocks - interrupts + - interrupt-names unevaluatedProperties: false -dependencies: - interrupts: [ interrupt-names ] - examples: - | watchdog: watchdog@3150 { diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml index 50c5c48ee6fb..951a7d54135a 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml @@ -177,11 +177,11 @@ examples: #include #include wdt0: watchdog@e6020000 { - compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt"; - reg = <0xe6020000 0x0c>; - interrupts = ; - clocks = <&cpg CPG_MOD 402>; - power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; - resets = <&cpg 402>; - timeout-sec = <60>; + compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt"; + reg = <0xe6020000 0x0c>; + interrupts = ; + clocks = <&cpg CPG_MOD 402>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 402>; + timeout-sec = <60>; }; diff --git a/Documentation/devicetree/bindings/watchdog/rt2880-wdt.txt b/Documentation/devicetree/bindings/watchdog/rt2880-wdt.txt deleted file mode 100644 index 05b95bfa2a89..000000000000 --- a/Documentation/devicetree/bindings/watchdog/rt2880-wdt.txt +++ /dev/null @@ -1,18 +0,0 @@ -Ralink Watchdog Timers - -Required properties: -- compatible: must be "ralink,rt2880-wdt" -- reg: physical base address of the controller and length of the register range - -Optional properties: -- interrupts: Specify the INTC interrupt number - -Example: - - watchdog@120 { - compatible = "ralink,rt2880-wdt"; - reg = <0x120 0x10>; - - interrupt-parent = <&intc>; - interrupts = <1>; - }; diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index 39139586611b..76eceeddd150 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -83,25 +83,25 @@ required: examples: - | watchdog@ffd02000 { - compatible = "snps,dw-wdt"; - reg = <0xffd02000 0x1000>; - interrupts = <0 171 4>; - clocks = <&per_base_clk>; - resets = <&wdt_rst>; + compatible = "snps,dw-wdt"; + reg = <0xffd02000 0x1000>; + interrupts = <0 171 4>; + clocks = <&per_base_clk>; + resets = <&wdt_rst>; }; - | watchdog@ffd02000 { - compatible = "snps,dw-wdt"; - reg = <0xffd02000 0x1000>; - interrupts = <0 171 4>; - clocks = <&per_base_clk>; - clock-names = "tclk"; - snps,watchdog-tops = <0x000000FF 0x000001FF 0x000003FF - 0x000007FF 0x0000FFFF 0x0001FFFF - 0x0003FFFF 0x0007FFFF 0x000FFFFF - 0x001FFFFF 0x003FFFFF 0x007FFFFF - 0x00FFFFFF 0x01FFFFFF 0x03FFFFFF - 0x07FFFFFF>; + compatible = "snps,dw-wdt"; + reg = <0xffd02000 0x1000>; + interrupts = <0 171 4>; + clocks = <&per_base_clk>; + clock-names = "tclk"; + snps,watchdog-tops = <0x000000FF 0x000001FF 0x000003FF + 0x000007FF 0x0000FFFF 0x0001FFFF + 0x0003FFFF 0x0007FFFF 0x000FFFFF + 0x001FFFFF 0x003FFFFF 0x007FFFFF + 0x00FFFFFF 0x01FFFFFF 0x03FFFFFF + 0x07FFFFFF>; }; ... diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.yaml b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.yaml index 2cb1a2ed0f7b..6b13bfc11e11 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.yaml +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.yaml @@ -48,11 +48,11 @@ examples: - | #include watchdog@5a002000 { - compatible = "st,stm32mp1-iwdg"; - reg = <0x5a002000 0x400>; - clocks = <&rcc IWDG2>, <&rcc CK_LSI>; - clock-names = "pclk", "lsi"; - timeout-sec = <32>; + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + timeout-sec = <32>; }; ... diff --git a/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml b/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml new file mode 100644 index 000000000000..68f3f6fd08a6 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/starfive,jh7100-wdt.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/starfive,jh7100-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive Watchdog for JH7100 and JH7110 SoC + +maintainers: + - Xingyu Wu + - Samin Guo + +description: + The JH7100 and JH7110 watchdog both are 32 bit counters. JH7100 watchdog + has only one timeout phase and reboots. And JH7110 watchdog has two + timeout phases. At the first phase, the signal of watchdog interrupt + output(WDOGINT) will rise when counter is 0. The counter will reload + the timeout value. And then, if counter decreases to 0 again and WDOGINT + isn't cleared, the watchdog will reset the system unless the watchdog + reset is disabled. + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + enum: + - starfive,jh7100-wdt + - starfive,jh7110-wdt + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: APB clock + - description: Core clock + + clock-names: + items: + - const: apb + - const: core + + resets: + items: + - description: APB reset + - description: Core reset + +required: + - compatible + - reg + - clocks + - clock-names + - resets + +unevaluatedProperties: false + +examples: + - | + watchdog@12480000 { + compatible = "starfive,jh7100-wdt"; + reg = <0x12480000 0x10000>; + clocks = <&clk 171>, + <&clk 172>; + clock-names = "apb", "core"; + resets = <&rst 99>, + <&rst 100>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml b/Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml index eba083822d1f..51d03d5b08ad 100644 --- a/Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml @@ -24,14 +24,12 @@ properties: clocks: maxItems: 1 - timeout-sec: true - required: - compatible - reg - clocks -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml b/Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml index 493a1c954707..8444c56dd602 100644 --- a/Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml @@ -58,11 +58,11 @@ unevaluatedProperties: false examples: - | watchdog@40100000 { - compatible = "xlnx,xps-timebase-wdt-1.00.a"; - reg = <0x40100000 0x1000>; - clock-frequency = <50000000>; - clocks = <&clkc 15>; - xlnx,wdt-enable-once = <0x0>; - xlnx,wdt-interval = <0x1b>; + compatible = "xlnx,xps-timebase-wdt-1.00.a"; + reg = <0x40100000 0x1000>; + clock-frequency = <50000000>; + clocks = <&clkc 15>; + xlnx,wdt-enable-once = <0x0>; + xlnx,wdt-interval = <0x1b>; }; ... diff --git a/Documentation/driver-api/driver-model/bus.rst b/Documentation/driver-api/driver-model/bus.rst index 016b15a6e8ea..9709ab62a468 100644 --- a/Documentation/driver-api/driver-model/bus.rst +++ b/Documentation/driver-api/driver-model/bus.rst @@ -125,8 +125,8 @@ Exporting Attributes struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(const struct bus_type *, char * buf); + ssize_t (*store)(const struct bus_type *, const char * buf, size_t count); }; Bus drivers can export attributes using the BUS_ATTR_RW macro that works diff --git a/Documentation/driver-api/firmware/fw_upload.rst b/Documentation/driver-api/firmware/fw_upload.rst index 76922591e446..edf1d0c5e7c3 100644 --- a/Documentation/driver-api/firmware/fw_upload.rst +++ b/Documentation/driver-api/firmware/fw_upload.rst @@ -57,7 +57,8 @@ function calls firmware_upload_unregister() such as:: len = (truncate) ? truncate - fw_name : strlen(fw_name); sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL); - fwl = firmware_upload_register(sec->dev, sec->fw_name, &m10bmc_ops, sec); + fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name, + &m10bmc_ops, sec); if (IS_ERR(fwl)) { dev_err(sec->dev, "Firmware Upload driver failed to start\n"); kfree(sec->fw_name); diff --git a/Documentation/driver-api/hte/index.rst b/Documentation/driver-api/hte/index.rst index 9f43301c05dc..29011de9a4b8 100644 --- a/Documentation/driver-api/hte/index.rst +++ b/Documentation/driver-api/hte/index.rst @@ -18,5 +18,5 @@ HTE Tegra Provider .. toctree:: :maxdepth: 1 - tegra194-hte + tegra-hte diff --git a/Documentation/driver-api/hte/tegra194-hte.rst b/Documentation/driver-api/hte/tegra-hte.rst similarity index 50% rename from Documentation/driver-api/hte/tegra194-hte.rst rename to Documentation/driver-api/hte/tegra-hte.rst index f2d617265546..85e654772782 100644 --- a/Documentation/driver-api/hte/tegra194-hte.rst +++ b/Documentation/driver-api/hte/tegra-hte.rst @@ -5,25 +5,25 @@ HTE Kernel provider driver Description ----------- -The Nvidia tegra194 HTE provider driver implements two GTE -(Generic Timestamping Engine) instances: 1) GPIO GTE and 2) LIC -(Legacy Interrupt Controller) IRQ GTE. Both GTE instances get the -timestamp from the system counter TSC which has 31.25MHz clock rate, and the -driver converts clock tick rate to nanoseconds before storing it as timestamp -value. +The Nvidia tegra HTE provider also known as GTE (Generic Timestamping Engine) +driver implements two GTE instances: 1) GPIO GTE and 2) LIC +(Legacy Interrupt Controller) IRQ GTE. Both GTE instances get the timestamp +from the system counter TSC which has 31.25MHz clock rate, and the driver +converts clock tick rate to nanoseconds before storing it as timestamp value. GPIO GTE -------- This GTE instance timestamps GPIO in real time. For that to happen GPIO -needs to be configured as input. The always on (AON) GPIO controller instance -supports timestamping GPIOs in real time and it has 39 GPIO lines. The GPIO GTE -and AON GPIO controller are tightly coupled as it requires very specific bits -to be set in GPIO config register before GPIO GTE can be used, for that GPIOLIB -adds two optional APIs as below. The GPIO GTE code supports both kernel -and userspace consumers. The kernel space consumers can directly talk to HTE -subsystem while userspace consumers timestamp requests go through GPIOLIB CDEV -framework to HTE subsystem. +needs to be configured as input. Only the always on (AON) GPIO controller +instance supports timestamping GPIOs in real time as it is tightly coupled with +the GPIO GTE. To support this, GPIOLIB adds two optional APIs as mentioned +below. The GPIO GTE code supports both kernel and userspace consumers. The +kernel space consumers can directly talk to HTE subsystem while userspace +consumers timestamp requests go through GPIOLIB CDEV framework to HTE +subsystem. The hte devicetree binding described at +``Documentation/devicetree/bindings/timestamp`` provides an example of how a +consumer can request an GPIO line. See gpiod_enable_hw_timestamp_ns() and gpiod_disable_hw_timestamp_ns(). @@ -34,9 +34,8 @@ returns the timestamp in nanoseconds. LIC (Legacy Interrupt Controller) IRQ GTE ----------------------------------------- -This GTE instance timestamps LIC IRQ lines in real time. There are 352 IRQ -lines which this instance can add timestamps to in real time. The hte -devicetree binding described at ``Documentation/devicetree/bindings/timestamp`` +This GTE instance timestamps LIC IRQ lines in real time. The hte devicetree +binding described at ``Documentation/devicetree/bindings/timestamp`` provides an example of how a consumer can request an IRQ line. Since it is a one-to-one mapping with IRQ GTE provider, consumers can simply specify the IRQ number that they are interested in. There is no userspace consumer support for diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst index e3366322d46c..de221e91c8e3 100644 --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst @@ -185,3 +185,18 @@ ex:: ===================== See Documentation/devicetree/bindings/nvmem/nvmem.txt + +8. NVMEM layouts +================ + +NVMEM layouts are yet another mechanism to create cells. With the device +tree binding it is possible to specify simple cells by using an offset +and a length. Sometimes, the cells doesn't have a static offset, but +the content is still well defined, e.g. tag-length-values. In this case, +the NVMEM device content has to be first parsed and the cells need to +be added accordingly. Layouts let you read the content of the NVMEM device +and let you add cells dynamically. + +Another use case for layouts is the post processing of cells. With layouts, +it is possible to associate a custom post processing hook to a cell. It +even possible to add this hook to cells not created by the layout itself. diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index 8c71a2055d27..3fdc95f7a1d1 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -35,12 +35,9 @@ consumers to providers, as given in the following example:: Using PWMs ---------- -Legacy users can request a PWM device using pwm_request() and free it -after usage with pwm_free(). - -New users should use the pwm_get() function and pass to it the consumer -device or a consumer name. pwm_put() is used to free the PWM device. Managed -variants of the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. +Consumers use the pwm_get() function and pass to it the consumer device or a +consumer name. pwm_put() is used to free the PWM device. Managed variants of +the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. After being requested, a PWM has to be configured using:: @@ -165,8 +162,8 @@ consumers should implement it as described in the "Using PWMs" section. Locking ------- -The PWM core list manipulations are protected by a mutex, so pwm_request() -and pwm_free() may not be called from an atomic context. Currently the +The PWM core list manipulations are protected by a mutex, so pwm_get() +and pwm_put() may not be called from an atomic context. Currently the PWM core does not enforce any locking to pwm_enable(), pwm_disable() and pwm_config(), so the calling context is currently driver specific. This is an issue derived from the former barebone API and should be fixed soon. diff --git a/Documentation/driver-api/tty/n_gsm.rst b/Documentation/driver-api/tty/n_gsm.rst index 9447b8a3b8e2..120317ec990f 100644 --- a/Documentation/driver-api/tty/n_gsm.rst +++ b/Documentation/driver-api/tty/n_gsm.rst @@ -29,6 +29,8 @@ Config Initiator #. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl. +#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults. + #. Obtain base gsmtty number for the used serial port. Major parts of the initialization program @@ -45,6 +47,7 @@ Config Initiator int ldisc = N_GSM0710; struct gsm_config c; struct gsm_config_ext ce; + struct gsm_dlci_config dc; struct termios configuration; uint32_t first; @@ -81,6 +84,13 @@ Config Initiator c.mtu = 127; /* set the new configuration */ ioctl(fd, GSMIOC_SETCONF, &c); + /* get DLC 1 configuration */ + dc.channel = 1; + ioctl(fd, GSMIOC_GETCONF_DLCI, &dc); + /* the first user channel gets a higher priority */ + dc.priority = 1; + /* set the new DLC 1 specific configuration */ + ioctl(fd, GSMIOC_SETCONF_DLCI, &dc); /* get first gsmtty device node */ ioctl(fd, GSMIOC_GETFIRST, &first); printf("first muxed line: /dev/gsmtty%i\n", first); @@ -120,6 +130,8 @@ Config Requester #. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl. +#. Configure DLCs using ``GSMIOC_GETCONF_DLCI``/``GSMIOC_SETCONF_DLCI`` ioctl for non-defaults. + #. Obtain base gsmtty number for the used serial port:: #include @@ -132,6 +144,7 @@ Config Requester int ldisc = N_GSM0710; struct gsm_config c; struct gsm_config_ext ce; + struct gsm_dlci_config dc; struct termios configuration; uint32_t first; @@ -161,6 +174,13 @@ Config Requester c.mtu = 127; /* set the new configuration */ ioctl(fd, GSMIOC_SETCONF, &c); + /* get DLC 1 configuration */ + dc.channel = 1; + ioctl(fd, GSMIOC_GETCONF_DLCI, &dc); + /* the first user channel gets a higher priority */ + dc.priority = 1; + /* set the new DLC 1 specific configuration */ + ioctl(fd, GSMIOC_SETCONF_DLCI, &dc); /* get first gsmtty device node */ ioctl(fd, GSMIOC_GETFIRST, &first); printf("first muxed line: /dev/gsmtty%i\n", first); diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt index 1e51614c136e..23260ca44946 100644 --- a/Documentation/features/sched/membarrier-sync-core/arch-support.txt +++ b/Documentation/features/sched/membarrier-sync-core/arch-support.txt @@ -5,7 +5,7 @@ # # Architecture requirements # -# * arm/arm64/powerpc +# * arm/arm64/powerpc/s390 # # Rely on implicit context synchronization as a result of exception return # when returning from IPI handler, and when returning to user-space. @@ -45,7 +45,7 @@ | parisc: | TODO | | powerpc: | ok | | riscv: | TODO | - | s390: | TODO | + | s390: | ok | | sh: | TODO | | sparc: | TODO | | um: | TODO | diff --git a/Documentation/filesystems/9p.rst b/Documentation/filesystems/9p.rst index 7b5964bc8865..1b5f0cc3e4ca 100644 --- a/Documentation/filesystems/9p.rst +++ b/Documentation/filesystems/9p.rst @@ -78,19 +78,39 @@ Options offering several exported file systems. cache=mode specifies a caching policy. By default, no caches are used. + The mode can be specified as a bitmask or by using one of the + prexisting common 'shortcuts'. + The bitmask is described below: (unspecified bits are reserved) - none - default no cache policy, metadata and data - alike are synchronous. - loose - no attempts are made at consistency, - intended for exclusive, read-only mounts - fscache - use FS-Cache for a persistent, read-only - cache backend. - mmap - minimal cache that is only used for read-write - mmap. Northing else is cached, like cache=none + ========== ==================================================== + 0b00000000 all caches disabled, mmap disabled + 0b00000001 file caches enabled + 0b00000010 meta-data caches enabled + 0b00000100 writeback behavior (as opposed to writethrough) + 0b00001000 loose caches (no explicit consistency with server) + 0b10000000 fscache enabled for persistent caching + ========== ==================================================== + + The current shortcuts and their associated bitmask are: + + ========= ==================================================== + none 0b00000000 (no caching) + readahead 0b00000001 (only read-ahead file caching) + mmap 0b00000101 (read-ahead + writeback file cache) + loose 0b00001111 (non-coherent file and meta-data caches) + fscache 0b10001111 (persistent loose cache) + ========= ==================================================== + + NOTE: only these shortcuts are tested modes of operation at the + moment, so using other combinations of bit-patterns is not + known to work. Work on better cache support is in progress. + + IMPORTANT: loose caches (and by extension at the moment fscache) + do not necessarily validate cached values on the server. In other + words changes on the server are not guaranteed to be reflected + on the client system. Only use this mode of operation if you + have an exclusive mount and the server will modify the filesystem + underneath you. debug=n specifies debug level. The debug level is a bitmask. @@ -137,6 +157,12 @@ Options This can be used to share devices/named pipes/sockets between hosts. This functionality will be expanded in later versions. + directio bypass page cache on all read/write operations + + ignoreqv ignore qid.version==0 as a marker to ignore cache + + noxattr do not offer xattr functions on this mount. + access there are four access modes. user if a user tries to access a file on v9fs diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index bee63d42e5ec..eb252fc972aa 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -72,7 +72,6 @@ Documentation for filesystem implementations. befs bfs btrfs - cifs/index ceph coda configfs @@ -111,6 +110,7 @@ Documentation for filesystem implementations. ramfs-rootfs-initramfs relay romfs + smb/index spufs/index squashfs sysfs @@ -123,4 +123,5 @@ Documentation for filesystem implementations. vfat xfs-delayed-logging-design xfs-self-describing-metadata + xfs-online-fsck-design zonefs diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index 7de7a7272a5e..aa1a233b0fa8 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -645,7 +645,7 @@ ops mmap_lock PageLocked(page) open: yes close: yes fault: yes can return with page locked -map_pages: yes +map_pages: read page_mkwrite: yes can return with page locked pfn_mkwrite: yes access: yes @@ -661,7 +661,7 @@ locked. The VM will unlock the page. ->map_pages() is called when VM asks to map easy accessible pages. Filesystem should find and map pages associated with offsets from "start_pgoff" -till "end_pgoff". ->map_pages() is called with page table locked and must +till "end_pgoff". ->map_pages() is called with the RCU lock held and must not block. If it's not possible to reach a page without blocking, filesystem should skip it. Filesystem should use do_set_pte() to setup page table entry. Pointer to entry associated with the page is passed in diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index 5aa102bd72c2..f0cf05cad2ba 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -61,17 +61,6 @@ this table marked with no it means default is without **no**. directories, fmask applies only to files and dmask only to directories. * - fmask= - * - noacsrules - - "No access rules" mount option sets access rights for files/folders to - 777 and owner/group to root. This mount option absorbs all other - permissions. - - - Permissions change for files/folders will be reported as successful, - but they will remain 777. - - - Owner/group change will be reported as successful, butthey will stay - as root. - * - nohidden - Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute will not be shown under Linux. diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 59db0bed35e1..7897a7dafcbc 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -179,6 +179,7 @@ read the file /proc/PID/status:: Gid: 100 100 100 100 FDSize: 256 Groups: 100 14 16 + Kthread: 0 VmPeak: 5004 kB VmSize: 5004 kB VmLck: 0 kB @@ -256,6 +257,7 @@ It's slow but very precise. NSpid descendant namespace process ID hierarchy NSpgid descendant namespace process group ID hierarchy NSsid descendant namespace session ID hierarchy + Kthread kernel thread flag, 1 is yes, 0 is no VmPeak peak virtual memory size VmSize total program size VmLck locked memory size @@ -996,6 +998,7 @@ Example output. You may not have all of these fields. VmallocUsed: 40444 kB VmallocChunk: 0 kB Percpu: 29312 kB + EarlyMemtestBad: 0 kB HardwareCorrupted: 0 kB AnonHugePages: 4149248 kB ShmemHugePages: 0 kB @@ -1146,6 +1149,13 @@ VmallocChunk Percpu Memory allocated to the percpu allocator used to back percpu allocations. This stat excludes the cost of metadata. +EarlyMemtestBad + The amount of RAM/memory in kB, that was identified as corrupted + by early memtest. If memtest was not run, this field will not + be displayed at all. Size is never rounded down to 0 kB. + That means if 0 kB is reported, you can safely assume + there was at least one pass of memtest and none of the passes + found a single faulty byte of RAM. HardwareCorrupted The amount of RAM/memory in KB, the kernel identifies as corrupted. diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.rst b/Documentation/filesystems/ramfs-rootfs-initramfs.rst index 164960631925..447f767c6462 100644 --- a/Documentation/filesystems/ramfs-rootfs-initramfs.rst +++ b/Documentation/filesystems/ramfs-rootfs-initramfs.rst @@ -6,8 +6,7 @@ Ramfs, rootfs and initramfs October 17, 2005 -Rob Landley -============================= +:Author: Rob Landley What is ramfs? -------------- diff --git a/Documentation/filesystems/sharedsubtree.rst b/Documentation/filesystems/sharedsubtree.rst index d83395354250..1cf56489ed48 100644 --- a/Documentation/filesystems/sharedsubtree.rst +++ b/Documentation/filesystems/sharedsubtree.rst @@ -147,6 +147,7 @@ replicas continue to be exactly same. 3) Setting mount states +----------------------- The mount command (util-linux package) can be used to set mount states:: @@ -612,6 +613,7 @@ replicas continue to be exactly same. 6) Quiz +------- A. What is the result of the following command sequence? @@ -673,6 +675,7 @@ replicas continue to be exactly same. /mnt/1/test be? 7) FAQ +------ Q1. Why is bind mount needed? How is it different from symbolic links? symbolic links can get stale if the destination mount gets @@ -841,6 +844,7 @@ replicas continue to be exactly same. tmp usr tmp usr tmp usr 8) Implementation +----------------- 8A) Datastructure diff --git a/Documentation/filesystems/cifs/cifsroot.rst b/Documentation/filesystems/smb/cifsroot.rst similarity index 97% rename from Documentation/filesystems/cifs/cifsroot.rst rename to Documentation/filesystems/smb/cifsroot.rst index 4930bb443134..bf2d9db3acb9 100644 --- a/Documentation/filesystems/cifs/cifsroot.rst +++ b/Documentation/filesystems/smb/cifsroot.rst @@ -59,7 +59,7 @@ the root file system via SMB protocol. Enables the kernel to mount the root file system via SMB that are located in the and specified in this option. -The default mount options are set in fs/cifs/cifsroot.c. +The default mount options are set in fs/smb/client/cifsroot.c. server-ip IPv4 address of the server. diff --git a/Documentation/filesystems/cifs/index.rst b/Documentation/filesystems/smb/index.rst similarity index 100% rename from Documentation/filesystems/cifs/index.rst rename to Documentation/filesystems/smb/index.rst diff --git a/Documentation/filesystems/cifs/ksmbd.rst b/Documentation/filesystems/smb/ksmbd.rst similarity index 100% rename from Documentation/filesystems/cifs/ksmbd.rst rename to Documentation/filesystems/smb/ksmbd.rst diff --git a/Documentation/filesystems/sysfs.rst b/Documentation/filesystems/sysfs.rst index f8187d466b97..c32993bc83c7 100644 --- a/Documentation/filesystems/sysfs.rst +++ b/Documentation/filesystems/sysfs.rst @@ -373,8 +373,8 @@ Structure:: struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(const struct bus_type *, char * buf); + ssize_t (*store)(const struct bus_type *, const char * buf, size_t count); }; Declaring:: diff --git a/Documentation/filesystems/tmpfs.rst b/Documentation/filesystems/tmpfs.rst index 0408c245785e..f18f46be5c0c 100644 --- a/Documentation/filesystems/tmpfs.rst +++ b/Documentation/filesystems/tmpfs.rst @@ -13,17 +13,29 @@ everything stored therein is lost. tmpfs puts everything into the kernel internal caches and grows and shrinks to accommodate the files it contains and is able to swap -unneeded pages out to swap space. It has maximum size limits which can -be adjusted on the fly via 'mount -o remount ...' +unneeded pages out to swap space, if swap was enabled for the tmpfs +mount. tmpfs also supports THP. -If you compare it to ramfs (which was the template to create tmpfs) -you gain swapping and limit checking. Another similar thing is the RAM -disk (/dev/ram*), which simulates a fixed size hard disk in physical -RAM, where you have to create an ordinary filesystem on top. Ramdisks -cannot swap and you do not have the possibility to resize them. +tmpfs extends ramfs with a few userspace configurable options listed and +explained further below, some of which can be reconfigured dynamically on the +fly using a remount ('mount -o remount ...') of the filesystem. A tmpfs +filesystem can be resized but it cannot be resized to a size below its current +usage. tmpfs also supports POSIX ACLs, and extended attributes for the +trusted.* and security.* namespaces. ramfs does not use swap and you cannot +modify any parameter for a ramfs filesystem. The size limit of a ramfs +filesystem is how much memory you have available, and so care must be taken if +used so to not run out of memory. -Since tmpfs lives completely in the page cache and on swap, all tmpfs -pages will be shown as "Shmem" in /proc/meminfo and "Shared" in +An alternative to tmpfs and ramfs is to use brd to create RAM disks +(/dev/ram*), which allows you to simulate a block device disk in physical RAM. +To write data you would just then need to create an regular filesystem on top +this ramdisk. As with ramfs, brd ramdisks cannot swap. brd ramdisks are also +configured in size at initialization and you cannot dynamically resize them. +Contrary to brd ramdisks, tmpfs has its own filesystem, it does not rely on the +block layer at all. + +Since tmpfs lives completely in the page cache and optionally on swap, +all tmpfs pages will be shown as "Shmem" in /proc/meminfo and "Shared" in free(1). Notice that these counters also include shared memory (shmem, see ipcs(1)). The most reliable way to get the count is using df(1) and du(1). @@ -72,6 +84,8 @@ nr_inodes The maximum number of inodes for this instance. The default is half of the number of your physical RAM pages, or (on a machine with highmem) the number of lowmem RAM pages, whichever is the lower. +noswap Disables swap. Remounts must respect the original settings. + By default swap is enabled. ========= ============================================================ These parameters accept a suffix k, m or g for kilo, mega and giga and @@ -85,6 +99,36 @@ mount with such options, since it allows any user with write access to use up all the memory on the machine; but enhances the scalability of that instance in a system with many CPUs making intensive use of it. +tmpfs also supports Transparent Huge Pages which requires a kernel +configured with CONFIG_TRANSPARENT_HUGEPAGE and with huge supported for +your system (has_transparent_hugepage(), which is architecture specific). +The mount options for this are: + +====== ============================================================ +huge=0 never: disables huge pages for the mount +huge=1 always: enables huge pages for the mount +huge=2 within_size: only allocate huge pages if the page will be + fully within i_size, also respect fadvise()/madvise() hints. +huge=3 advise: only allocate huge pages if requested with + fadvise()/madvise() +====== ============================================================ + +There is a sysfs file which you can also use to control system wide THP +configuration for all tmpfs mounts, the file is: + +/sys/kernel/mm/transparent_hugepage/shmem_enabled + +This sysfs file is placed on top of THP sysfs directory and so is registered +by THP code. It is however only used to control all tmpfs mounts with one +single knob. Since it controls all tmpfs mounts it should only be used either +for emergency or testing purposes. The values you can set for shmem_enabled are: + +== ============================================================ +-1 deny: disables huge on shm_mnt and all mounts, for + emergency use +-2 force: enables huge on shm_mnt and all mounts, w/o needing + option, for testing +== ============================================================ tmpfs has a mount option to set the NUMA memory allocation policy for all files in that instance (if CONFIG_NUMA is enabled) - which can be diff --git a/Documentation/filesystems/xfs-online-fsck-design.rst b/Documentation/filesystems/xfs-online-fsck-design.rst new file mode 100644 index 000000000000..791ab264b77e --- /dev/null +++ b/Documentation/filesystems/xfs-online-fsck-design.rst @@ -0,0 +1,5315 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. _xfs_online_fsck_design: + +.. + Mapping of heading styles within this document: + Heading 1 uses "====" above and below + Heading 2 uses "====" + Heading 3 uses "----" + Heading 4 uses "````" + Heading 5 uses "^^^^" + Heading 6 uses "~~~~" + Heading 7 uses "...." + + Sections are manually numbered because apparently that's what everyone + does in the kernel. + +====================== +XFS Online Fsck Design +====================== + +This document captures the design of the online filesystem check feature for +XFS. +The purpose of this document is threefold: + +- To help kernel distributors understand exactly what the XFS online fsck + feature is, and issues about which they should be aware. + +- To help people reading the code to familiarize themselves with the relevant + concepts and design points before they start digging into the code. + +- To help developers maintaining the system by capturing the reasons + supporting higher level decision making. + +As the online fsck code is merged, the links in this document to topic branches +will be replaced with links to code. + +This document is licensed under the terms of the GNU Public License, v2. +The primary author is Darrick J. Wong. + +This design document is split into seven parts. +Part 1 defines what fsck tools are and the motivations for writing a new one. +Parts 2 and 3 present a high level overview of how online fsck process works +and how it is tested to ensure correct functionality. +Part 4 discusses the user interface and the intended usage modes of the new +program. +Parts 5 and 6 show off the high level components and how they fit together, and +then present case studies of how each repair function actually works. +Part 7 sums up what has been discussed so far and speculates about what else +might be built atop online fsck. + +.. contents:: Table of Contents + :local: + +1. What is a Filesystem Check? +============================== + +A Unix filesystem has four main responsibilities: + +- Provide a hierarchy of names through which application programs can associate + arbitrary blobs of data for any length of time, + +- Virtualize physical storage media across those names, and + +- Retrieve the named data blobs at any time. + +- Examine resource usage. + +Metadata directly supporting these functions (e.g. files, directories, space +mappings) are sometimes called primary metadata. +Secondary metadata (e.g. reverse mapping and directory parent pointers) support +operations internal to the filesystem, such as internal consistency checking +and reorganization. +Summary metadata, as the name implies, condense information contained in +primary metadata for performance reasons. + +The filesystem check (fsck) tool examines all the metadata in a filesystem +to look for errors. +In addition to looking for obvious metadata corruptions, fsck also +cross-references different types of metadata records with each other to look +for inconsistencies. +People do not like losing data, so most fsck tools also contains some ability +to correct any problems found. +As a word of caution -- the primary goal of most Linux fsck tools is to restore +the filesystem metadata to a consistent state, not to maximize the data +recovered. +That precedent will not be challenged here. + +Filesystems of the 20th century generally lacked any redundancy in the ondisk +format, which means that fsck can only respond to errors by erasing files until +errors are no longer detected. +More recent filesystem designs contain enough redundancy in their metadata that +it is now possible to regenerate data structures when non-catastrophic errors +occur; this capability aids both strategies. + ++--------------------------------------------------------------------------+ +| **Note**: | ++--------------------------------------------------------------------------+ +| System administrators avoid data loss by increasing the number of | +| separate storage systems through the creation of backups; and they avoid | +| downtime by increasing the redundancy of each storage system through the | +| creation of RAID arrays. | +| fsck tools address only the first problem. | ++--------------------------------------------------------------------------+ + +TLDR; Show Me the Code! +----------------------- + +Code is posted to the kernel.org git trees as follows: +`kernel changes `_, +`userspace changes `_, and +`QA test changes `_. +Each kernel patchset adding an online repair function will use the same branch +name across the kernel, xfsprogs, and fstests git repos. + +Existing Tools +-------------- + +The online fsck tool described here will be the third tool in the history of +XFS (on Linux) to check and repair filesystems. +Two programs precede it: + +The first program, ``xfs_check``, was created as part of the XFS debugger +(``xfs_db``) and can only be used with unmounted filesystems. +It walks all metadata in the filesystem looking for inconsistencies in the +metadata, though it lacks any ability to repair what it finds. +Due to its high memory requirements and inability to repair things, this +program is now deprecated and will not be discussed further. + +The second program, ``xfs_repair``, was created to be faster and more robust +than the first program. +Like its predecessor, it can only be used with unmounted filesystems. +It uses extent-based in-memory data structures to reduce memory consumption, +and tries to schedule readahead IO appropriately to reduce I/O waiting time +while it scans the metadata of the entire filesystem. +The most important feature of this tool is its ability to respond to +inconsistencies in file metadata and directory tree by erasing things as needed +to eliminate problems. +Space usage metadata are rebuilt from the observed file metadata. + +Problem Statement +----------------- + +The current XFS tools leave several problems unsolved: + +1. **User programs** suddenly **lose access** to the filesystem when unexpected + shutdowns occur as a result of silent corruptions in the metadata. + These occur **unpredictably** and often without warning. + +2. **Users** experience a **total loss of service** during the recovery period + after an **unexpected shutdown** occurs. + +3. **Users** experience a **total loss of service** if the filesystem is taken + offline to **look for problems** proactively. + +4. **Data owners** cannot **check the integrity** of their stored data without + reading all of it. + This may expose them to substantial billing costs when a linear media scan + performed by the storage system administrator might suffice. + +5. **System administrators** cannot **schedule** a maintenance window to deal + with corruptions if they **lack the means** to assess filesystem health + while the filesystem is online. + +6. **Fleet monitoring tools** cannot **automate periodic checks** of filesystem + health when doing so requires **manual intervention** and downtime. + +7. **Users** can be tricked into **doing things they do not desire** when + malicious actors **exploit quirks of Unicode** to place misleading names + in directories. + +Given this definition of the problems to be solved and the actors who would +benefit, the proposed solution is a third fsck tool that acts on a running +filesystem. + +This new third program has three components: an in-kernel facility to check +metadata, an in-kernel facility to repair metadata, and a userspace driver +program to drive fsck activity on a live filesystem. +``xfs_scrub`` is the name of the driver program. +The rest of this document presents the goals and use cases of the new fsck +tool, describes its major design points in connection to those goals, and +discusses the similarities and differences with existing tools. + ++--------------------------------------------------------------------------+ +| **Note**: | ++--------------------------------------------------------------------------+ +| Throughout this document, the existing offline fsck tool can also be | +| referred to by its current name "``xfs_repair``". | +| The userspace driver program for the new online fsck tool can be | +| referred to as "``xfs_scrub``". | +| The kernel portion of online fsck that validates metadata is called | +| "online scrub", and portion of the kernel that fixes metadata is called | +| "online repair". | ++--------------------------------------------------------------------------+ + +The naming hierarchy is broken up into objects known as directories and files +and the physical space is split into pieces known as allocation groups. +Sharding enables better performance on highly parallel systems and helps to +contain the damage when corruptions occur. +The division of the filesystem into principal objects (allocation groups and +inodes) means that there are ample opportunities to perform targeted checks and +repairs on a subset of the filesystem. + +While this is going on, other parts continue processing IO requests. +Even if a piece of filesystem metadata can only be regenerated by scanning the +entire system, the scan can still be done in the background while other file +operations continue. + +In summary, online fsck takes advantage of resource sharding and redundant +metadata to enable targeted checking and repair operations while the system +is running. +This capability will be coupled to automatic system management so that +autonomous self-healing of XFS maximizes service availability. + +2. Theory of Operation +====================== + +Because it is necessary for online fsck to lock and scan live metadata objects, +online fsck consists of three separate code components. +The first is the userspace driver program ``xfs_scrub``, which is responsible +for identifying individual metadata items, scheduling work items for them, +reacting to the outcomes appropriately, and reporting results to the system +administrator. +The second and third are in the kernel, which implements functions to check +and repair each type of online fsck work item. + ++------------------------------------------------------------------+ +| **Note**: | ++------------------------------------------------------------------+ +| For brevity, this document shortens the phrase "online fsck work | +| item" to "scrub item". | ++------------------------------------------------------------------+ + +Scrub item types are delineated in a manner consistent with the Unix design +philosophy, which is to say that each item should handle one aspect of a +metadata structure, and handle it well. + +Scope +----- + +In principle, online fsck should be able to check and to repair everything that +the offline fsck program can handle. +However, online fsck cannot be running 100% of the time, which means that +latent errors may creep in after a scrub completes. +If these errors cause the next mount to fail, offline fsck is the only +solution. +This limitation means that maintenance of the offline fsck tool will continue. +A second limitation of online fsck is that it must follow the same resource +sharing and lock acquisition rules as the regular filesystem. +This means that scrub cannot take *any* shortcuts to save time, because doing +so could lead to concurrency problems. +In other words, online fsck is not a complete replacement for offline fsck, and +a complete run of online fsck may take longer than online fsck. +However, both of these limitations are acceptable tradeoffs to satisfy the +different motivations of online fsck, which are to **minimize system downtime** +and to **increase predictability of operation**. + +.. _scrubphases: + +Phases of Work +-------------- + +The userspace driver program ``xfs_scrub`` splits the work of checking and +repairing an entire filesystem into seven phases. +Each phase concentrates on checking specific types of scrub items and depends +on the success of all previous phases. +The seven phases are as follows: + +1. Collect geometry information about the mounted filesystem and computer, + discover the online fsck capabilities of the kernel, and open the + underlying storage devices. + +2. Check allocation group metadata, all realtime volume metadata, and all quota + files. + Each metadata structure is scheduled as a separate scrub item. + If corruption is found in the inode header or inode btree and ``xfs_scrub`` + is permitted to perform repairs, then those scrub items are repaired to + prepare for phase 3. + Repairs are implemented by using the information in the scrub item to + resubmit the kernel scrub call with the repair flag enabled; this is + discussed in the next section. + Optimizations and all other repairs are deferred to phase 4. + +3. Check all metadata of every file in the filesystem. + Each metadata structure is also scheduled as a separate scrub item. + If repairs are needed and ``xfs_scrub`` is permitted to perform repairs, + and there were no problems detected during phase 2, then those scrub items + are repaired immediately. + Optimizations, deferred repairs, and unsuccessful repairs are deferred to + phase 4. + +4. All remaining repairs and scheduled optimizations are performed during this + phase, if the caller permits them. + Before starting repairs, the summary counters are checked and any necessary + repairs are performed so that subsequent repairs will not fail the resource + reservation step due to wildly incorrect summary counters. + Unsuccesful repairs are requeued as long as forward progress on repairs is + made somewhere in the filesystem. + Free space in the filesystem is trimmed at the end of phase 4 if the + filesystem is clean. + +5. By the start of this phase, all primary and secondary filesystem metadata + must be correct. + Summary counters such as the free space counts and quota resource counts + are checked and corrected. + Directory entry names and extended attribute names are checked for + suspicious entries such as control characters or confusing Unicode sequences + appearing in names. + +6. If the caller asks for a media scan, read all allocated and written data + file extents in the filesystem. + The ability to use hardware-assisted data file integrity checking is new + to online fsck; neither of the previous tools have this capability. + If media errors occur, they will be mapped to the owning files and reported. + +7. Re-check the summary counters and presents the caller with a summary of + space usage and file counts. + +This allocation of responsibilities will be :ref:`revisited ` +later in this document. + +Steps for Each Scrub Item +------------------------- + +The kernel scrub code uses a three-step strategy for checking and repairing +the one aspect of a metadata object represented by a scrub item: + +1. The scrub item of interest is checked for corruptions; opportunities for + optimization; and for values that are directly controlled by the system + administrator but look suspicious. + If the item is not corrupt or does not need optimization, resource are + released and the positive scan results are returned to userspace. + If the item is corrupt or could be optimized but the caller does not permit + this, resources are released and the negative scan results are returned to + userspace. + Otherwise, the kernel moves on to the second step. + +2. The repair function is called to rebuild the data structure. + Repair functions generally choose rebuild a structure from other metadata + rather than try to salvage the existing structure. + If the repair fails, the scan results from the first step are returned to + userspace. + Otherwise, the kernel moves on to the third step. + +3. In the third step, the kernel runs the same checks over the new metadata + item to assess the efficacy of the repairs. + The results of the reassessment are returned to userspace. + +Classification of Metadata +-------------------------- + +Each type of metadata object (and therefore each type of scrub item) is +classified as follows: + +Primary Metadata +```````````````` + +Metadata structures in this category should be most familiar to filesystem +users either because they are directly created by the user or they index +objects created by the user +Most filesystem objects fall into this class: + +- Free space and reference count information + +- Inode records and indexes + +- Storage mapping information for file data + +- Directories + +- Extended attributes + +- Symbolic links + +- Quota limits + +Scrub obeys the same rules as regular filesystem accesses for resource and lock +acquisition. + +Primary metadata objects are the simplest for scrub to process. +The principal filesystem object (either an allocation group or an inode) that +owns the item being scrubbed is locked to guard against concurrent updates. +The check function examines every record associated with the type for obvious +errors and cross-references healthy records against other metadata to look for +inconsistencies. +Repairs for this class of scrub item are simple, since the repair function +starts by holding all the resources acquired in the previous step. +The repair function scans available metadata as needed to record all the +observations needed to complete the structure. +Next, it stages the observations in a new ondisk structure and commits it +atomically to complete the repair. +Finally, the storage from the old data structure are carefully reaped. + +Because ``xfs_scrub`` locks a primary object for the duration of the repair, +this is effectively an offline repair operation performed on a subset of the +filesystem. +This minimizes the complexity of the repair code because it is not necessary to +handle concurrent updates from other threads, nor is it necessary to access +any other part of the filesystem. +As a result, indexed structures can be rebuilt very quickly, and programs +trying to access the damaged structure will be blocked until repairs complete. +The only infrastructure needed by the repair code are the staging area for +observations and a means to write new structures to disk. +Despite these limitations, the advantage that online repair holds is clear: +targeted work on individual shards of the filesystem avoids total loss of +service. + +This mechanism is described in section 2.1 ("Off-Line Algorithm") of +V. Srinivasan and M. J. Carey, `"Performance of On-Line Index Construction +Algorithms" `_, +*Extending Database Technology*, pp. 293-309, 1992. + +Most primary metadata repair functions stage their intermediate results in an +in-memory array prior to formatting the new ondisk structure, which is very +similar to the list-based algorithm discussed in section 2.3 ("List-Based +Algorithms") of Srinivasan. +However, any data structure builder that maintains a resource lock for the +duration of the repair is *always* an offline algorithm. + +.. _secondary_metadata: + +Secondary Metadata +`````````````````` + +Metadata structures in this category reflect records found in primary metadata, +but are only needed for online fsck or for reorganization of the filesystem. + +Secondary metadata include: + +- Reverse mapping information + +- Directory parent pointers + +This class of metadata is difficult for scrub to process because scrub attaches +to the secondary object but needs to check primary metadata, which runs counter +to the usual order of resource acquisition. +Frequently, this means that full filesystems scans are necessary to rebuild the +metadata. +Check functions can be limited in scope to reduce runtime. +Repairs, however, require a full scan of primary metadata, which can take a +long time to complete. +Under these conditions, ``xfs_scrub`` cannot lock resources for the entire +duration of the repair. + +Instead, repair functions set up an in-memory staging structure to store +observations. +Depending on the requirements of the specific repair function, the staging +index will either have the same format as the ondisk structure or a design +specific to that repair function. +The next step is to release all locks and start the filesystem scan. +When the repair scanner needs to record an observation, the staging data are +locked long enough to apply the update. +While the filesystem scan is in progress, the repair function hooks the +filesystem so that it can apply pending filesystem updates to the staging +information. +Once the scan is done, the owning object is re-locked, the live data is used to +write a new ondisk structure, and the repairs are committed atomically. +The hooks are disabled and the staging staging area is freed. +Finally, the storage from the old data structure are carefully reaped. + +Introducing concurrency helps online repair avoid various locking problems, but +comes at a high cost to code complexity. +Live filesystem code has to be hooked so that the repair function can observe +updates in progress. +The staging area has to become a fully functional parallel structure so that +updates can be merged from the hooks. +Finally, the hook, the filesystem scan, and the inode locking model must be +sufficiently well integrated that a hook event can decide if a given update +should be applied to the staging structure. + +In theory, the scrub implementation could apply these same techniques for +primary metadata, but doing so would make it massively more complex and less +performant. +Programs attempting to access the damaged structures are not blocked from +operation, which may cause application failure or an unplanned filesystem +shutdown. + +Inspiration for the secondary metadata repair strategy was drawn from section +2.4 of Srinivasan above, and sections 2 ("NSF: Inded Build Without Side-File") +and 3.1.1 ("Duplicate Key Insert Problem") in C. Mohan, `"Algorithms for +Creating Indexes for Very Large Tables Without Quiescing Updates" +`_, 1992. + +The sidecar index mentioned above bears some resemblance to the side file +method mentioned in Srinivasan and Mohan. +Their method consists of an index builder that extracts relevant record data to +build the new structure as quickly as possible; and an auxiliary structure that +captures all updates that would be committed to the index by other threads were +the new index already online. +After the index building scan finishes, the updates recorded in the side file +are applied to the new index. +To avoid conflicts between the index builder and other writer threads, the +builder maintains a publicly visible cursor that tracks the progress of the +scan through the record space. +To avoid duplication of work between the side file and the index builder, side +file updates are elided when the record ID for the update is greater than the +cursor position within the record ID space. + +To minimize changes to the rest of the codebase, XFS online repair keeps the +replacement index hidden until it's completely ready to go. +In other words, there is no attempt to expose the keyspace of the new index +while repair is running. +The complexity of such an approach would be very high and perhaps more +appropriate to building *new* indices. + +**Future Work Question**: Can the full scan and live update code used to +facilitate a repair also be used to implement a comprehensive check? + +*Answer*: In theory, yes. Check would be much stronger if each scrub function +employed these live scans to build a shadow copy of the metadata and then +compared the shadow records to the ondisk records. +However, doing that is a fair amount more work than what the checking functions +do now. +The live scans and hooks were developed much later. +That in turn increases the runtime of those scrub functions. + +Summary Information +``````````````````` + +Metadata structures in this last category summarize the contents of primary +metadata records. +These are often used to speed up resource usage queries, and are many times +smaller than the primary metadata which they represent. + +Examples of summary information include: + +- Summary counts of free space and inodes + +- File link counts from directories + +- Quota resource usage counts + +Check and repair require full filesystem scans, but resource and lock +acquisition follow the same paths as regular filesystem accesses. + +The superblock summary counters have special requirements due to the underlying +implementation of the incore counters, and will be treated separately. +Check and repair of the other types of summary counters (quota resource counts +and file link counts) employ the same filesystem scanning and hooking +techniques as outlined above, but because the underlying data are sets of +integer counters, the staging data need not be a fully functional mirror of the +ondisk structure. + +Inspiration for quota and file link count repair strategies were drawn from +sections 2.12 ("Online Index Operations") through 2.14 ("Incremental View +Maintenace") of G. Graefe, `"Concurrent Queries and Updates in Summary Views +and Their Indexes" +`_, 2011. + +Since quotas are non-negative integer counts of resource usage, online +quotacheck can use the incremental view deltas described in section 2.14 to +track pending changes to the block and inode usage counts in each transaction, +and commit those changes to a dquot side file when the transaction commits. +Delta tracking is necessary for dquots because the index builder scans inodes, +whereas the data structure being rebuilt is an index of dquots. +Link count checking combines the view deltas and commit step into one because +it sets attributes of the objects being scanned instead of writing them to a +separate data structure. +Each online fsck function will be discussed as case studies later in this +document. + +Risk Management +--------------- + +During the development of online fsck, several risk factors were identified +that may make the feature unsuitable for certain distributors and users. +Steps can be taken to mitigate or eliminate those risks, though at a cost to +functionality. + +- **Decreased performance**: Adding metadata indices to the filesystem + increases the time cost of persisting changes to disk, and the reverse space + mapping and directory parent pointers are no exception. + System administrators who require the maximum performance can disable the + reverse mapping features at format time, though this choice dramatically + reduces the ability of online fsck to find inconsistencies and repair them. + +- **Incorrect repairs**: As with all software, there might be defects in the + software that result in incorrect repairs being written to the filesystem. + Systematic fuzz testing (detailed in the next section) is employed by the + authors to find bugs early, but it might not catch everything. + The kernel build system provides Kconfig options (``CONFIG_XFS_ONLINE_SCRUB`` + and ``CONFIG_XFS_ONLINE_REPAIR``) to enable distributors to choose not to + accept this risk. + The xfsprogs build system has a configure option (``--enable-scrub=no``) that + disables building of the ``xfs_scrub`` binary, though this is not a risk + mitigation if the kernel functionality remains enabled. + +- **Inability to repair**: Sometimes, a filesystem is too badly damaged to be + repairable. + If the keyspaces of several metadata indices overlap in some manner but a + coherent narrative cannot be formed from records collected, then the repair + fails. + To reduce the chance that a repair will fail with a dirty transaction and + render the filesystem unusable, the online repair functions have been + designed to stage and validate all new records before committing the new + structure. + +- **Misbehavior**: Online fsck requires many privileges -- raw IO to block + devices, opening files by handle, ignoring Unix discretionary access control, + and the ability to perform administrative changes. + Running this automatically in the background scares people, so the systemd + background service is configured to run with only the privileges required. + Obviously, this cannot address certain problems like the kernel crashing or + deadlocking, but it should be sufficient to prevent the scrub process from + escaping and reconfiguring the system. + The cron job does not have this protection. + +- **Fuzz Kiddiez**: There are many people now who seem to think that running + automated fuzz testing of ondisk artifacts to find mischevious behavior and + spraying exploit code onto the public mailing list for instant zero-day + disclosure is somehow of some social benefit. + In the view of this author, the benefit is realized only when the fuzz + operators help to **fix** the flaws, but this opinion apparently is not + widely shared among security "researchers". + The XFS maintainers' continuing ability to manage these events presents an + ongoing risk to the stability of the development process. + Automated testing should front-load some of the risk while the feature is + considered EXPERIMENTAL. + +Many of these risks are inherent to software programming. +Despite this, it is hoped that this new functionality will prove useful in +reducing unexpected downtime. + +3. Testing Plan +=============== + +As stated before, fsck tools have three main goals: + +1. Detect inconsistencies in the metadata; + +2. Eliminate those inconsistencies; and + +3. Minimize further loss of data. + +Demonstrations of correct operation are necessary to build users' confidence +that the software behaves within expectations. +Unfortunately, it was not really feasible to perform regular exhaustive testing +of every aspect of a fsck tool until the introduction of low-cost virtual +machines with high-IOPS storage. +With ample hardware availability in mind, the testing strategy for the online +fsck project involves differential analysis against the existing fsck tools and +systematic testing of every attribute of every type of metadata object. +Testing can be split into four major categories, as discussed below. + +Integrated Testing with fstests +------------------------------- + +The primary goal of any free software QA effort is to make testing as +inexpensive and widespread as possible to maximize the scaling advantages of +community. +In other words, testing should maximize the breadth of filesystem configuration +scenarios and hardware setups. +This improves code quality by enabling the authors of online fsck to find and +fix bugs early, and helps developers of new features to find integration +issues earlier in their development effort. + +The Linux filesystem community shares a common QA testing suite, +`fstests `_, for +functional and regression testing. +Even before development work began on online fsck, fstests (when run on XFS) +would run both the ``xfs_check`` and ``xfs_repair -n`` commands on the test and +scratch filesystems between each test. +This provides a level of assurance that the kernel and the fsck tools stay in +alignment about what constitutes consistent metadata. +During development of the online checking code, fstests was modified to run +``xfs_scrub -n`` between each test to ensure that the new checking code +produces the same results as the two existing fsck tools. + +To start development of online repair, fstests was modified to run +``xfs_repair`` to rebuild the filesystem's metadata indices between tests. +This ensures that offline repair does not crash, leave a corrupt filesystem +after it exists, or trigger complaints from the online check. +This also established a baseline for what can and cannot be repaired offline. +To complete the first phase of development of online repair, fstests was +modified to be able to run ``xfs_scrub`` in a "force rebuild" mode. +This enables a comparison of the effectiveness of online repair as compared to +the existing offline repair tools. + +General Fuzz Testing of Metadata Blocks +--------------------------------------- + +XFS benefits greatly from having a very robust debugging tool, ``xfs_db``. + +Before development of online fsck even began, a set of fstests were created +to test the rather common fault that entire metadata blocks get corrupted. +This required the creation of fstests library code that can create a filesystem +containing every possible type of metadata object. +Next, individual test cases were created to create a test filesystem, identify +a single block of a specific type of metadata object, trash it with the +existing ``blocktrash`` command in ``xfs_db``, and test the reaction of a +particular metadata validation strategy. + +This earlier test suite enabled XFS developers to test the ability of the +in-kernel validation functions and the ability of the offline fsck tool to +detect and eliminate the inconsistent metadata. +This part of the test suite was extended to cover online fsck in exactly the +same manner. + +In other words, for a given fstests filesystem configuration: + +* For each metadata object existing on the filesystem: + + * Write garbage to it + + * Test the reactions of: + + 1. The kernel verifiers to stop obviously bad metadata + 2. Offline repair (``xfs_repair``) to detect and fix + 3. Online repair (``xfs_scrub``) to detect and fix + +Targeted Fuzz Testing of Metadata Records +----------------------------------------- + +The testing plan for online fsck includes extending the existing fs testing +infrastructure to provide a much more powerful facility: targeted fuzz testing +of every metadata field of every metadata object in the filesystem. +``xfs_db`` can modify every field of every metadata structure in every +block in the filesystem to simulate the effects of memory corruption and +software bugs. +Given that fstests already contains the ability to create a filesystem +containing every metadata format known to the filesystem, ``xfs_db`` can be +used to perform exhaustive fuzz testing! + +For a given fstests filesystem configuration: + +* For each metadata object existing on the filesystem... + + * For each record inside that metadata object... + + * For each field inside that record... + + * For each conceivable type of transformation that can be applied to a bit field... + + 1. Clear all bits + 2. Set all bits + 3. Toggle the most significant bit + 4. Toggle the middle bit + 5. Toggle the least significant bit + 6. Add a small quantity + 7. Subtract a small quantity + 8. Randomize the contents + + * ...test the reactions of: + + 1. The kernel verifiers to stop obviously bad metadata + 2. Offline checking (``xfs_repair -n``) + 3. Offline repair (``xfs_repair``) + 4. Online checking (``xfs_scrub -n``) + 5. Online repair (``xfs_scrub``) + 6. Both repair tools (``xfs_scrub`` and then ``xfs_repair`` if online repair doesn't succeed) + +This is quite the combinatoric explosion! + +Fortunately, having this much test coverage makes it easy for XFS developers to +check the responses of XFS' fsck tools. +Since the introduction of the fuzz testing framework, these tests have been +used to discover incorrect repair code and missing functionality for entire +classes of metadata objects in ``xfs_repair``. +The enhanced testing was used to finalize the deprecation of ``xfs_check`` by +confirming that ``xfs_repair`` could detect at least as many corruptions as +the older tool. + +These tests have been very valuable for ``xfs_scrub`` in the same ways -- they +allow the online fsck developers to compare online fsck against offline fsck, +and they enable XFS developers to find deficiencies in the code base. + +Proposed patchsets include +`general fuzzer improvements +`_, +`fuzzing baselines +`_, +and `improvements in fuzz testing comprehensiveness +`_. + +Stress Testing +-------------- + +A unique requirement to online fsck is the ability to operate on a filesystem +concurrently with regular workloads. +Although it is of course impossible to run ``xfs_scrub`` with *zero* observable +impact on the running system, the online repair code should never introduce +inconsistencies into the filesystem metadata, and regular workloads should +never notice resource starvation. +To verify that these conditions are being met, fstests has been enhanced in +the following ways: + +* For each scrub item type, create a test to exercise checking that item type + while running ``fsstress``. +* For each scrub item type, create a test to exercise repairing that item type + while running ``fsstress``. +* Race ``fsstress`` and ``xfs_scrub -n`` to ensure that checking the whole + filesystem doesn't cause problems. +* Race ``fsstress`` and ``xfs_scrub`` in force-rebuild mode to ensure that + force-repairing the whole filesystem doesn't cause problems. +* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while + freezing and thawing the filesystem. +* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while + remounting the filesystem read-only and read-write. +* The same, but running ``fsx`` instead of ``fsstress``. (Not done yet?) + +Success is defined by the ability to run all of these tests without observing +any unexpected filesystem shutdowns due to corrupted metadata, kernel hang +check warnings, or any other sort of mischief. + +Proposed patchsets include `general stress testing +`_ +and the `evolution of existing per-function stress testing +`_. + +4. User Interface +================= + +The primary user of online fsck is the system administrator, just like offline +repair. +Online fsck presents two modes of operation to administrators: +A foreground CLI process for online fsck on demand, and a background service +that performs autonomous checking and repair. + +Checking on Demand +------------------ + +For administrators who want the absolute freshest information about the +metadata in a filesystem, ``xfs_scrub`` can be run as a foreground process on +a command line. +The program checks every piece of metadata in the filesystem while the +administrator waits for the results to be reported, just like the existing +``xfs_repair`` tool. +Both tools share a ``-n`` option to perform a read-only scan, and a ``-v`` +option to increase the verbosity of the information reported. + +A new feature of ``xfs_scrub`` is the ``-x`` option, which employs the error +correction capabilities of the hardware to check data file contents. +The media scan is not enabled by default because it may dramatically increase +program runtime and consume a lot of bandwidth on older storage hardware. + +The output of a foreground invocation is captured in the system log. + +The ``xfs_scrub_all`` program walks the list of mounted filesystems and +initiates ``xfs_scrub`` for each of them in parallel. +It serializes scans for any filesystems that resolve to the same top level +kernel block device to prevent resource overconsumption. + +Background Service +------------------ + +To reduce the workload of system administrators, the ``xfs_scrub`` package +provides a suite of `systemd `_ timers and services that +run online fsck automatically on weekends by default. +The background service configures scrub to run with as little privilege as +possible, the lowest CPU and IO priority, and in a CPU-constrained single +threaded mode. +This can be tuned by the systemd administrator at any time to suit the latency +and throughput requirements of customer workloads. + +The output of the background service is also captured in the system log. +If desired, reports of failures (either due to inconsistencies or mere runtime +errors) can be emailed automatically by setting the ``EMAIL_ADDR`` environment +variable in the following service files: + +* ``xfs_scrub_fail@.service`` +* ``xfs_scrub_media_fail@.service`` +* ``xfs_scrub_all_fail.service`` + +The decision to enable the background scan is left to the system administrator. +This can be done by enabling either of the following services: + +* ``xfs_scrub_all.timer`` on systemd systems +* ``xfs_scrub_all.cron`` on non-systemd systems + +This automatic weekly scan is configured out of the box to perform an +additional media scan of all file data once per month. +This is less foolproof than, say, storing file data block checksums, but much +more performant if application software provides its own integrity checking, +redundancy can be provided elsewhere above the filesystem, or the storage +device's integrity guarantees are deemed sufficient. + +The systemd unit file definitions have been subjected to a security audit +(as of systemd 249) to ensure that the xfs_scrub processes have as little +access to the rest of the system as possible. +This was performed via ``systemd-analyze security``, after which privileges +were restricted to the minimum required, sandboxing was set up to the maximal +extent possible with sandboxing and system call filtering; and access to the +filesystem tree was restricted to the minimum needed to start the program and +access the filesystem being scanned. +The service definition files restrict CPU usage to 80% of one CPU core, and +apply as nice of a priority to IO and CPU scheduling as possible. +This measure was taken to minimize delays in the rest of the filesystem. +No such hardening has been performed for the cron job. + +Proposed patchset: +`Enabling the xfs_scrub background service +`_. + +Health Reporting +---------------- + +XFS caches a summary of each filesystem's health status in memory. +The information is updated whenever ``xfs_scrub`` is run, or whenever +inconsistencies are detected in the filesystem metadata during regular +operations. +System administrators should use the ``health`` command of ``xfs_spaceman`` to +download this information into a human-readable format. +If problems have been observed, the administrator can schedule a reduced +service window to run the online repair tool to correct the problem. +Failing that, the administrator can decide to schedule a maintenance window to +run the traditional offline repair tool to correct the problem. + +**Future Work Question**: Should the health reporting integrate with the new +inotify fs error notification system? +Would it be helpful for sysadmins to have a daemon to listen for corruption +notifications and initiate a repair? + +*Answer*: These questions remain unanswered, but should be a part of the +conversation with early adopters and potential downstream users of XFS. + +Proposed patchsets include +`wiring up health reports to correction returns +`_ +and +`preservation of sickness info during memory reclaim +`_. + +5. Kernel Algorithms and Data Structures +======================================== + +This section discusses the key algorithms and data structures of the kernel +code that provide the ability to check and repair metadata while the system +is running. +The first chapters in this section reveal the pieces that provide the +foundation for checking metadata. +The remainder of this section presents the mechanisms through which XFS +regenerates itself. + +Self Describing Metadata +------------------------ + +Starting with XFS version 5 in 2012, XFS updated the format of nearly every +ondisk block header to record a magic number, a checksum, a universally +"unique" identifier (UUID), an owner code, the ondisk address of the block, +and a log sequence number. +When loading a block buffer from disk, the magic number, UUID, owner, and +ondisk address confirm that the retrieved block matches the specific owner of +the current filesystem, and that the information contained in the block is +supposed to be found at the ondisk address. +The first three components enable checking tools to disregard alleged metadata +that doesn't belong to the filesystem, and the fourth component enables the +filesystem to detect lost writes. + +Whenever a file system operation modifies a block, the change is submitted +to the log as part of a transaction. +The log then processes these transactions marking them done once they are +safely persisted to storage. +The logging code maintains the checksum and the log sequence number of the last +transactional update. +Checksums are useful for detecting torn writes and other discrepancies that can +be introduced between the computer and its storage devices. +Sequence number tracking enables log recovery to avoid applying out of date +log updates to the filesystem. + +These two features improve overall runtime resiliency by providing a means for +the filesystem to detect obvious corruption when reading metadata blocks from +disk, but these buffer verifiers cannot provide any consistency checking +between metadata structures. + +For more information, please see the documentation for +Documentation/filesystems/xfs-self-describing-metadata.rst + +Reverse Mapping +--------------- + +The original design of XFS (circa 1993) is an improvement upon 1980s Unix +filesystem design. +In those days, storage density was expensive, CPU time was scarce, and +excessive seek time could kill performance. +For performance reasons, filesystem authors were reluctant to add redundancy to +the filesystem, even at the cost of data integrity. +Filesystems designers in the early 21st century choose different strategies to +increase internal redundancy -- either storing nearly identical copies of +metadata, or more space-efficient encoding techniques. + +For XFS, a different redundancy strategy was chosen to modernize the design: +a secondary space usage index that maps allocated disk extents back to their +owners. +By adding a new index, the filesystem retains most of its ability to scale +well to heavily threaded workloads involving large datasets, since the primary +file metadata (the directory tree, the file block map, and the allocation +groups) remain unchanged. +Like any system that improves redundancy, the reverse-mapping feature increases +overhead costs for space mapping activities. +However, it has two critical advantages: first, the reverse index is key to +enabling online fsck and other requested functionality such as free space +defragmentation, better media failure reporting, and filesystem shrinking. +Second, the different ondisk storage format of the reverse mapping btree +defeats device-level deduplication because the filesystem requires real +redundancy. + ++--------------------------------------------------------------------------+ +| **Sidebar**: | ++--------------------------------------------------------------------------+ +| A criticism of adding the secondary index is that it does nothing to | +| improve the robustness of user data storage itself. | +| This is a valid point, but adding a new index for file data block | +| checksums increases write amplification by turning data overwrites into | +| copy-writes, which age the filesystem prematurely. | +| In keeping with thirty years of precedent, users who want file data | +| integrity can supply as powerful a solution as they require. | +| As for metadata, the complexity of adding a new secondary index of space | +| usage is much less than adding volume management and storage device | +| mirroring to XFS itself. | +| Perfection of RAID and volume management are best left to existing | +| layers in the kernel. | ++--------------------------------------------------------------------------+ + +The information captured in a reverse space mapping record is as follows: + +.. code-block:: c + + struct xfs_rmap_irec { + xfs_agblock_t rm_startblock; /* extent start block */ + xfs_extlen_t rm_blockcount; /* extent length */ + uint64_t rm_owner; /* extent owner */ + uint64_t rm_offset; /* offset within the owner */ + unsigned int rm_flags; /* state flags */ + }; + +The first two fields capture the location and size of the physical space, +in units of filesystem blocks. +The owner field tells scrub which metadata structure or file inode have been +assigned this space. +For space allocated to files, the offset field tells scrub where the space was +mapped within the file fork. +Finally, the flags field provides extra information about the space usage -- +is this an attribute fork extent? A file mapping btree extent? Or an +unwritten data extent? + +Online filesystem checking judges the consistency of each primary metadata +record by comparing its information against all other space indices. +The reverse mapping index plays a key role in the consistency checking process +because it contains a centralized alternate copy of all space allocation +information. +Program runtime and ease of resource acquisition are the only real limits to +what online checking can consult. +For example, a file data extent mapping can be checked against: + +* The absence of an entry in the free space information. +* The absence of an entry in the inode index. +* The absence of an entry in the reference count data if the file is not + marked as having shared extents. +* The correspondence of an entry in the reverse mapping information. + +There are several observations to make about reverse mapping indices: + +1. Reverse mappings can provide a positive affirmation of correctness if any of + the above primary metadata are in doubt. + The checking code for most primary metadata follows a path similar to the + one outlined above. + +2. Proving the consistency of secondary metadata with the primary metadata is + difficult because that requires a full scan of all primary space metadata, + which is very time intensive. + For example, checking a reverse mapping record for a file extent mapping + btree block requires locking the file and searching the entire btree to + confirm the block. + Instead, scrub relies on rigorous cross-referencing during the primary space + mapping structure checks. + +3. Consistency scans must use non-blocking lock acquisition primitives if the + required locking order is not the same order used by regular filesystem + operations. + For example, if the filesystem normally takes a file ILOCK before taking + the AGF buffer lock but scrub wants to take a file ILOCK while holding + an AGF buffer lock, scrub cannot block on that second acquisition. + This means that forward progress during this part of a scan of the reverse + mapping data cannot be guaranteed if system load is heavy. + +In summary, reverse mappings play a key role in reconstruction of primary +metadata. +The details of how these records are staged, written to disk, and committed +into the filesystem are covered in subsequent sections. + +Checking and Cross-Referencing +------------------------------ + +The first step of checking a metadata structure is to examine every record +contained within the structure and its relationship with the rest of the +system. +XFS contains multiple layers of checking to try to prevent inconsistent +metadata from wreaking havoc on the system. +Each of these layers contributes information that helps the kernel to make +three decisions about the health of a metadata structure: + +- Is a part of this structure obviously corrupt (``XFS_SCRUB_OFLAG_CORRUPT``) ? +- Is this structure inconsistent with the rest of the system + (``XFS_SCRUB_OFLAG_XCORRUPT``) ? +- Is there so much damage around the filesystem that cross-referencing is not + possible (``XFS_SCRUB_OFLAG_XFAIL``) ? +- Can the structure be optimized to improve performance or reduce the size of + metadata (``XFS_SCRUB_OFLAG_PREEN``) ? +- Does the structure contain data that is not inconsistent but deserves review + by the system administrator (``XFS_SCRUB_OFLAG_WARNING``) ? + +The following sections describe how the metadata scrubbing process works. + +Metadata Buffer Verification +```````````````````````````` + +The lowest layer of metadata protection in XFS are the metadata verifiers built +into the buffer cache. +These functions perform inexpensive internal consistency checking of the block +itself, and answer these questions: + +- Does the block belong to this filesystem? + +- Does the block belong to the structure that asked for the read? + This assumes that metadata blocks only have one owner, which is always true + in XFS. + +- Is the type of data stored in the block within a reasonable range of what + scrub is expecting? + +- Does the physical location of the block match the location it was read from? + +- Does the block checksum match the data? + +The scope of the protections here are very limited -- verifiers can only +establish that the filesystem code is reasonably free of gross corruption bugs +and that the storage system is reasonably competent at retrieval. +Corruption problems observed at runtime cause the generation of health reports, +failed system calls, and in the extreme case, filesystem shutdowns if the +corrupt metadata force the cancellation of a dirty transaction. + +Every online fsck scrubbing function is expected to read every ondisk metadata +block of a structure in the course of checking the structure. +Corruption problems observed during a check are immediately reported to +userspace as corruption; during a cross-reference, they are reported as a +failure to cross-reference once the full examination is complete. +Reads satisfied by a buffer already in cache (and hence already verified) +bypass these checks. + +Internal Consistency Checks +``````````````````````````` + +After the buffer cache, the next level of metadata protection is the internal +record verification code built into the filesystem. +These checks are split between the buffer verifiers, the in-filesystem users of +the buffer cache, and the scrub code itself, depending on the amount of higher +level context required. +The scope of checking is still internal to the block. +These higher level checking functions answer these questions: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- If the block contains records, do the records fit within the block? + +- If the block tracks internal free space information, is it consistent with + the record areas? + +- Are the records contained inside the block free of obvious corruptions? + +Record checks in this category are more rigorous and more time-intensive. +For example, block pointers and inumbers are checked to ensure that they point +within the dynamically allocated parts of an allocation group and within +the filesystem. +Names are checked for invalid characters, and flags are checked for invalid +combinations. +Other record attributes are checked for sensible values. +Btree records spanning an interval of the btree keyspace are checked for +correct order and lack of mergeability (except for file fork mappings). +For performance reasons, regular code may skip some of these checks unless +debugging is enabled or a write is about to occur. +Scrub functions, of course, must check all possible problems. + +Validation of Userspace-Controlled Record Attributes +```````````````````````````````````````````````````` + +Various pieces of filesystem metadata are directly controlled by userspace. +Because of this nature, validation work cannot be more precise than checking +that a value is within the possible range. +These fields include: + +- Superblock fields controlled by mount options +- Filesystem labels +- File timestamps +- File permissions +- File size +- File flags +- Names present in directory entries, extended attribute keys, and filesystem + labels +- Extended attribute key namespaces +- Extended attribute values +- File data block contents +- Quota limits +- Quota timer expiration (if resource usage exceeds the soft limit) + +Cross-Referencing Space Metadata +```````````````````````````````` + +After internal block checks, the next higher level of checking is +cross-referencing records between metadata structures. +For regular runtime code, the cost of these checks is considered to be +prohibitively expensive, but as scrub is dedicated to rooting out +inconsistencies, it must pursue all avenues of inquiry. +The exact set of cross-referencing is highly dependent on the context of the +data structure being checked. + +The XFS btree code has keyspace scanning functions that online fsck uses to +cross reference one structure with another. +Specifically, scrub can scan the key space of an index to determine if that +keyspace is fully, sparsely, or not at all mapped to records. +For the reverse mapping btree, it is possible to mask parts of the key for the +purposes of performing a keyspace scan so that scrub can decide if the rmap +btree contains records mapping a certain extent of physical space without the +sparsenses of the rest of the rmap keyspace getting in the way. + +Btree blocks undergo the following checks before cross-referencing: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- Do the records fit within the block? + +- Are the records contained inside the block free of obvious corruptions? + +- Are the name hashes in the correct order? + +- Do node pointers within the btree point to valid block addresses for the type + of btree? + +- Do child pointers point towards the leaves? + +- Do sibling pointers point across the same level? + +- For each node block record, does the record key accurate reflect the contents + of the child block? + +Space allocation records are cross-referenced as follows: + +1. Any space mentioned by any metadata structure are cross-referenced as + follows: + + - Does the reverse mapping index list only the appropriate owner as the + owner of each block? + + - Are none of the blocks claimed as free space? + + - If these aren't file data blocks, are none of the blocks claimed as space + shared by different owners? + +2. Btree blocks are cross-referenced as follows: + + - Everything in class 1 above. + + - If there's a parent node block, do the keys listed for this block match the + keyspace of this block? + + - Do the sibling pointers point to valid blocks? Of the same level? + + - Do the child pointers point to valid blocks? Of the next level down? + +3. Free space btree records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Does the reverse mapping index list no owners of this space? + + - Is this space not claimed by the inode index for inodes? + + - Is it not mentioned by the reference count index? + + - Is there a matching record in the other free space btree? + +4. Inode btree records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Is there a matching record in free inode btree? + + - Do cleared bits in the holemask correspond with inode clusters? + + - Do set bits in the freemask correspond with inode records with zero link + count? + +5. Inode records are cross-referenced as follows: + + - Everything in class 1. + + - Do all the fields that summarize information about the file forks actually + match those forks? + + - Does each inode with zero link count correspond to a record in the free + inode btree? + +6. File fork space mapping records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Is this space not mentioned by the inode btrees? + + - If this is a CoW fork mapping, does it correspond to a CoW entry in the + reference count btree? + +7. Reference count records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Within the space subkeyspace of the rmap btree (that is to say, all + records mapped to a particular space extent and ignoring the owner info), + are there the same number of reverse mapping records for each block as the + reference count record claims? + +Proposed patchsets are the series to find gaps in +`refcount btree +`_, +`inode btree +`_, and +`rmap btree +`_ records; +to find +`mergeable records +`_; +and to +`improve cross referencing with rmap +`_ +before starting a repair. + +Checking Extended Attributes +```````````````````````````` + +Extended attributes implement a key-value store that enable fragments of data +to be attached to any file. +Both the kernel and userspace can access the keys and values, subject to +namespace and privilege restrictions. +Most typically these fragments are metadata about the file -- origins, security +contexts, user-supplied labels, indexing information, etc. + +Names can be as long as 255 bytes and can exist in several different +namespaces. +Values can be as large as 64KB. +A file's extended attributes are stored in blocks mapped by the attr fork. +The mappings point to leaf blocks, remote value blocks, or dabtree blocks. +Block 0 in the attribute fork is always the top of the structure, but otherwise +each of the three types of blocks can be found at any offset in the attr fork. +Leaf blocks contain attribute key records that point to the name and the value. +Names are always stored elsewhere in the same leaf block. +Values that are less than 3/4 the size of a filesystem block are also stored +elsewhere in the same leaf block. +Remote value blocks contain values that are too large to fit inside a leaf. +If the leaf information exceeds a single filesystem block, a dabtree (also +rooted at block 0) is created to map hashes of the attribute names to leaf +blocks in the attr fork. + +Checking an extended attribute structure is not so straightfoward due to the +lack of separation between attr blocks and index blocks. +Scrub must read each block mapped by the attr fork and ignore the non-leaf +blocks: + +1. Walk the dabtree in the attr fork (if present) to ensure that there are no + irregularities in the blocks or dabtree mappings that do not point to + attr leaf blocks. + +2. Walk the blocks of the attr fork looking for leaf blocks. + For each entry inside a leaf: + + a. Validate that the name does not contain invalid characters. + + b. Read the attr value. + This performs a named lookup of the attr name to ensure the correctness + of the dabtree. + If the value is stored in a remote block, this also validates the + integrity of the remote value block. + +Checking and Cross-Referencing Directories +`````````````````````````````````````````` + +The filesystem directory tree is a directed acylic graph structure, with files +constituting the nodes, and directory entries (dirents) constituting the edges. +Directories are a special type of file containing a set of mappings from a +255-byte sequence (name) to an inumber. +These are called directory entries, or dirents for short. +Each directory file must have exactly one directory pointing to the file. +A root directory points to itself. +Directory entries point to files of any type. +Each non-directory file may have multiple directories point to it. + +In XFS, directories are implemented as a file containing up to three 32GB +partitions. +The first partition contains directory entry data blocks. +Each data block contains variable-sized records associating a user-provided +name with an inumber and, optionally, a file type. +If the directory entry data grows beyond one block, the second partition (which +exists as post-EOF extents) is populated with a block containing free space +information and an index that maps hashes of the dirent names to directory data +blocks in the first partition. +This makes directory name lookups very fast. +If this second partition grows beyond one block, the third partition is +populated with a linear array of free space information for faster +expansions. +If the free space has been separated and the second partition grows again +beyond one block, then a dabtree is used to map hashes of dirent names to +directory data blocks. + +Checking a directory is pretty straightfoward: + +1. Walk the dabtree in the second partition (if present) to ensure that there + are no irregularities in the blocks or dabtree mappings that do not point to + dirent blocks. + +2. Walk the blocks of the first partition looking for directory entries. + Each dirent is checked as follows: + + a. Does the name contain no invalid characters? + + b. Does the inumber correspond to an actual, allocated inode? + + c. Does the child inode have a nonzero link count? + + d. If a file type is included in the dirent, does it match the type of the + inode? + + e. If the child is a subdirectory, does the child's dotdot pointer point + back to the parent? + + f. If the directory has a second partition, perform a named lookup of the + dirent name to ensure the correctness of the dabtree. + +3. Walk the free space list in the third partition (if present) to ensure that + the free spaces it describes are really unused. + +Checking operations involving :ref:`parents ` and +:ref:`file link counts ` are discussed in more detail in later +sections. + +Checking Directory/Attribute Btrees +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As stated in previous sections, the directory/attribute btree (dabtree) index +maps user-provided names to improve lookup times by avoiding linear scans. +Internally, it maps a 32-bit hash of the name to a block offset within the +appropriate file fork. + +The internal structure of a dabtree closely resembles the btrees that record +fixed-size metadata records -- each dabtree block contains a magic number, a +checksum, sibling pointers, a UUID, a tree level, and a log sequence number. +The format of leaf and node records are the same -- each entry points to the +next level down in the hierarchy, with dabtree node records pointing to dabtree +leaf blocks, and dabtree leaf records pointing to non-dabtree blocks elsewhere +in the fork. + +Checking and cross-referencing the dabtree is very similar to what is done for +space btrees: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- Do the records fit within the block? + +- Are the records contained inside the block free of obvious corruptions? + +- Are the name hashes in the correct order? + +- Do node pointers within the dabtree point to valid fork offsets for dabtree + blocks? + +- Do leaf pointers within the dabtree point to valid fork offsets for directory + or attr leaf blocks? + +- Do child pointers point towards the leaves? + +- Do sibling pointers point across the same level? + +- For each dabtree node record, does the record key accurate reflect the + contents of the child dabtree block? + +- For each dabtree leaf record, does the record key accurate reflect the + contents of the directory or attr block? + +Cross-Referencing Summary Counters +`````````````````````````````````` + +XFS maintains three classes of summary counters: available resources, quota +resource usage, and file link counts. + +In theory, the amount of available resources (data blocks, inodes, realtime +extents) can be found by walking the entire filesystem. +This would make for very slow reporting, so a transactional filesystem can +maintain summaries of this information in the superblock. +Cross-referencing these values against the filesystem metadata should be a +simple matter of walking the free space and inode metadata in each AG and the +realtime bitmap, but there are complications that will be discussed in +:ref:`more detail ` later. + +:ref:`Quota usage ` and :ref:`file link count ` +checking are sufficiently complicated to warrant separate sections. + +Post-Repair Reverification +`````````````````````````` + +After performing a repair, the checking code is run a second time to validate +the new structure, and the results of the health assessment are recorded +internally and returned to the calling process. +This step is critical for enabling system administrator to monitor the status +of the filesystem and the progress of any repairs. +For developers, it is a useful means to judge the efficacy of error detection +and correction in the online and offline checking tools. + +Eventual Consistency vs. Online Fsck +------------------------------------ + +Complex operations can make modifications to multiple per-AG data structures +with a chain of transactions. +These chains, once committed to the log, are restarted during log recovery if +the system crashes while processing the chain. +Because the AG header buffers are unlocked between transactions within a chain, +online checking must coordinate with chained operations that are in progress to +avoid incorrectly detecting inconsistencies due to pending chains. +Furthermore, online repair must not run when operations are pending because +the metadata are temporarily inconsistent with each other, and rebuilding is +not possible. + +Only online fsck has this requirement of total consistency of AG metadata, and +should be relatively rare as compared to filesystem change operations. +Online fsck coordinates with transaction chains as follows: + +* For each AG, maintain a count of intent items targetting that AG. + The count should be bumped whenever a new item is added to the chain. + The count should be dropped when the filesystem has locked the AG header + buffers and finished the work. + +* When online fsck wants to examine an AG, it should lock the AG header + buffers to quiesce all transaction chains that want to modify that AG. + If the count is zero, proceed with the checking operation. + If it is nonzero, cycle the buffer locks to allow the chain to make forward + progress. + +This may lead to online fsck taking a long time to complete, but regular +filesystem updates take precedence over background checking activity. +Details about the discovery of this situation are presented in the +:ref:`next section `, and details about the solution +are presented :ref:`after that`. + +.. _chain_coordination: + +Discovery of the Problem +```````````````````````` + +Midway through the development of online scrubbing, the fsstress tests +uncovered a misinteraction between online fsck and compound transaction chains +created by other writer threads that resulted in false reports of metadata +inconsistency. +The root cause of these reports is the eventual consistency model introduced by +the expansion of deferred work items and compound transaction chains when +reverse mapping and reflink were introduced. + +Originally, transaction chains were added to XFS to avoid deadlocks when +unmapping space from files. +Deadlock avoidance rules require that AGs only be locked in increasing order, +which makes it impossible (say) to use a single transaction to free a space +extent in AG 7 and then try to free a now superfluous block mapping btree block +in AG 3. +To avoid these kinds of deadlocks, XFS creates Extent Freeing Intent (EFI) log +items to commit to freeing some space in one transaction while deferring the +actual metadata updates to a fresh transaction. +The transaction sequence looks like this: + +1. The first transaction contains a physical update to the file's block mapping + structures to remove the mapping from the btree blocks. + It then attaches to the in-memory transaction an action item to schedule + deferred freeing of space. + Concretely, each transaction maintains a list of ``struct + xfs_defer_pending`` objects, each of which maintains a list of ``struct + xfs_extent_free_item`` objects. + Returning to the example above, the action item tracks the freeing of both + the unmapped space from AG 7 and the block mapping btree (BMBT) block from + AG 3. + Deferred frees recorded in this manner are committed in the log by creating + an EFI log item from the ``struct xfs_extent_free_item`` object and + attaching the log item to the transaction. + When the log is persisted to disk, the EFI item is written into the ondisk + transaction record. + EFIs can list up to 16 extents to free, all sorted in AG order. + +2. The second transaction contains a physical update to the free space btrees + of AG 3 to release the former BMBT block and a second physical update to the + free space btrees of AG 7 to release the unmapped file space. + Observe that the the physical updates are resequenced in the correct order + when possible. + Attached to the transaction is a an extent free done (EFD) log item. + The EFD contains a pointer to the EFI logged in transaction #1 so that log + recovery can tell if the EFI needs to be replayed. + +If the system goes down after transaction #1 is written back to the filesystem +but before #2 is committed, a scan of the filesystem metadata would show +inconsistent filesystem metadata because there would not appear to be any owner +of the unmapped space. +Happily, log recovery corrects this inconsistency for us -- when recovery finds +an intent log item but does not find a corresponding intent done item, it will +reconstruct the incore state of the intent item and finish it. +In the example above, the log must replay both frees described in the recovered +EFI to complete the recovery phase. + +There are subtleties to XFS' transaction chaining strategy to consider: + +* Log items must be added to a transaction in the correct order to prevent + conflicts with principal objects that are not held by the transaction. + In other words, all per-AG metadata updates for an unmapped block must be + completed before the last update to free the extent, and extents should not + be reallocated until that last update commits to the log. + +* AG header buffers are released between each transaction in a chain. + This means that other threads can observe an AG in an intermediate state, + but as long as the first subtlety is handled, this should not affect the + correctness of filesystem operations. + +* Unmounting the filesystem flushes all pending work to disk, which means that + offline fsck never sees the temporary inconsistencies caused by deferred + work item processing. + +In this manner, XFS employs a form of eventual consistency to avoid deadlocks +and increase parallelism. + +During the design phase of the reverse mapping and reflink features, it was +decided that it was impractical to cram all the reverse mapping updates for a +single filesystem change into a single transaction because a single file +mapping operation can explode into many small updates: + +* The block mapping update itself +* A reverse mapping update for the block mapping update +* Fixing the freelist +* A reverse mapping update for the freelist fix + +* A shape change to the block mapping btree +* A reverse mapping update for the btree update +* Fixing the freelist (again) +* A reverse mapping update for the freelist fix + +* An update to the reference counting information +* A reverse mapping update for the refcount update +* Fixing the freelist (a third time) +* A reverse mapping update for the freelist fix + +* Freeing any space that was unmapped and not owned by any other file +* Fixing the freelist (a fourth time) +* A reverse mapping update for the freelist fix + +* Freeing the space used by the block mapping btree +* Fixing the freelist (a fifth time) +* A reverse mapping update for the freelist fix + +Free list fixups are not usually needed more than once per AG per transaction +chain, but it is theoretically possible if space is very tight. +For copy-on-write updates this is even worse, because this must be done once to +remove the space from a staging area and again to map it into the file! + +To deal with this explosion in a calm manner, XFS expands its use of deferred +work items to cover most reverse mapping updates and all refcount updates. +This reduces the worst case size of transaction reservations by breaking the +work into a long chain of small updates, which increases the degree of eventual +consistency in the system. +Again, this generally isn't a problem because XFS orders its deferred work +items carefully to avoid resource reuse conflicts between unsuspecting threads. + +However, online fsck changes the rules -- remember that although physical +updates to per-AG structures are coordinated by locking the buffers for AG +headers, buffer locks are dropped between transactions. +Once scrub acquires resources and takes locks for a data structure, it must do +all the validation work without releasing the lock. +If the main lock for a space btree is an AG header buffer lock, scrub may have +interrupted another thread that is midway through finishing a chain. +For example, if a thread performing a copy-on-write has completed a reverse +mapping update but not the corresponding refcount update, the two AG btrees +will appear inconsistent to scrub and an observation of corruption will be +recorded. This observation will not be correct. +If a repair is attempted in this state, the results will be catastrophic! + +Several other solutions to this problem were evaluated upon discovery of this +flaw and rejected: + +1. Add a higher level lock to allocation groups and require writer threads to + acquire the higher level lock in AG order before making any changes. + This would be very difficult to implement in practice because it is + difficult to determine which locks need to be obtained, and in what order, + without simulating the entire operation. + Performing a dry run of a file operation to discover necessary locks would + make the filesystem very slow. + +2. Make the deferred work coordinator code aware of consecutive intent items + targeting the same AG and have it hold the AG header buffers locked across + the transaction roll between updates. + This would introduce a lot of complexity into the coordinator since it is + only loosely coupled with the actual deferred work items. + It would also fail to solve the problem because deferred work items can + generate new deferred subtasks, but all subtasks must be complete before + work can start on a new sibling task. + +3. Teach online fsck to walk all transactions waiting for whichever lock(s) + protect the data structure being scrubbed to look for pending operations. + The checking and repair operations must factor these pending operations into + the evaluations being performed. + This solution is a nonstarter because it is *extremely* invasive to the main + filesystem. + +.. _intent_drains: + +Intent Drains +````````````` + +Online fsck uses an atomic intent item counter and lock cycling to coordinate +with transaction chains. +There are two key properties to the drain mechanism. +First, the counter is incremented when a deferred work item is *queued* to a +transaction, and it is decremented after the associated intent done log item is +*committed* to another transaction. +The second property is that deferred work can be added to a transaction without +holding an AG header lock, but per-AG work items cannot be marked done without +locking that AG header buffer to log the physical updates and the intent done +log item. +The first property enables scrub to yield to running transaction chains, which +is an explicit deprioritization of online fsck to benefit file operations. +The second property of the drain is key to the correct coordination of scrub, +since scrub will always be able to decide if a conflict is possible. + +For regular filesystem code, the drain works as follows: + +1. Call the appropriate subsystem function to add a deferred work item to a + transaction. + +2. The function calls ``xfs_defer_drain_bump`` to increase the counter. + +3. When the deferred item manager wants to finish the deferred work item, it + calls ``->finish_item`` to complete it. + +4. The ``->finish_item`` implementation logs some changes and calls + ``xfs_defer_drain_drop`` to decrease the sloppy counter and wake up any threads + waiting on the drain. + +5. The subtransaction commits, which unlocks the resource associated with the + intent item. + +For scrub, the drain works as follows: + +1. Lock the resource(s) associated with the metadata being scrubbed. + For example, a scan of the refcount btree would lock the AGI and AGF header + buffers. + +2. If the counter is zero (``xfs_defer_drain_busy`` returns false), there are no + chains in progress and the operation may proceed. + +3. Otherwise, release the resources grabbed in step 1. + +4. Wait for the intent counter to reach zero (``xfs_defer_drain_intents``), then go + back to step 1 unless a signal has been caught. + +To avoid polling in step 4, the drain provides a waitqueue for scrub threads to +be woken up whenever the intent count drops to zero. + +The proposed patchset is the +`scrub intent drain series +`_. + +.. _jump_labels: + +Static Keys (aka Jump Label Patching) +````````````````````````````````````` + +Online fsck for XFS separates the regular filesystem from the checking and +repair code as much as possible. +However, there are a few parts of online fsck (such as the intent drains, and +later, live update hooks) where it is useful for the online fsck code to know +what's going on in the rest of the filesystem. +Since it is not expected that online fsck will be constantly running in the +background, it is very important to minimize the runtime overhead imposed by +these hooks when online fsck is compiled into the kernel but not actively +running on behalf of userspace. +Taking locks in the hot path of a writer thread to access a data structure only +to find that no further action is necessary is expensive -- on the author's +computer, this have an overhead of 40-50ns per access. +Fortunately, the kernel supports dynamic code patching, which enables XFS to +replace a static branch to hook code with ``nop`` sleds when online fsck isn't +running. +This sled has an overhead of however long it takes the instruction decoder to +skip past the sled, which seems to be on the order of less than 1ns and +does not access memory outside of instruction fetching. + +When online fsck enables the static key, the sled is replaced with an +unconditional branch to call the hook code. +The switchover is quite expensive (~22000ns) but is paid entirely by the +program that invoked online fsck, and can be amortized if multiple threads +enter online fsck at the same time, or if multiple filesystems are being +checked at the same time. +Changing the branch direction requires taking the CPU hotplug lock, and since +CPU initialization requires memory allocation, online fsck must be careful not +to change a static key while holding any locks or resources that could be +accessed in the memory reclaim paths. +To minimize contention on the CPU hotplug lock, care should be taken not to +enable or disable static keys unnecessarily. + +Because static keys are intended to minimize hook overhead for regular +filesystem operations when xfs_scrub is not running, the intended usage +patterns are as follows: + +- The hooked part of XFS should declare a static-scoped static key that + defaults to false. + The ``DEFINE_STATIC_KEY_FALSE`` macro takes care of this. + The static key itself should be declared as a ``static`` variable. + +- When deciding to invoke code that's only used by scrub, the regular + filesystem should call the ``static_branch_unlikely`` predicate to avoid the + scrub-only hook code if the static key is not enabled. + +- The regular filesystem should export helper functions that call + ``static_branch_inc`` to enable and ``static_branch_dec`` to disable the + static key. + Wrapper functions make it easy to compile out the relevant code if the kernel + distributor turns off online fsck at build time. + +- Scrub functions wanting to turn on scrub-only XFS functionality should call + the ``xchk_fsgates_enable`` from the setup function to enable a specific + hook. + This must be done before obtaining any resources that are used by memory + reclaim. + Callers had better be sure they really need the functionality gated by the + static key; the ``TRY_HARDER`` flag is useful here. + +Online scrub has resource acquisition helpers (e.g. ``xchk_perag_lock``) to +handle locking AGI and AGF buffers for all scrubber functions. +If it detects a conflict between scrub and the running transactions, it will +try to wait for intents to complete. +If the caller of the helper has not enabled the static key, the helper will +return -EDEADLOCK, which should result in the scrub being restarted with the +``TRY_HARDER`` flag set. +The scrub setup function should detect that flag, enable the static key, and +try the scrub again. +Scrub teardown disables all static keys obtained by ``xchk_fsgates_enable``. + +For more information, please see the kernel documentation of +Documentation/staging/static-keys.rst. + +.. _xfile: + +Pageable Kernel Memory +---------------------- + +Some online checking functions work by scanning the filesystem to build a +shadow copy of an ondisk metadata structure in memory and comparing the two +copies. +For online repair to rebuild a metadata structure, it must compute the record +set that will be stored in the new structure before it can persist that new +structure to disk. +Ideally, repairs complete with a single atomic commit that introduces +a new data structure. +To meet these goals, the kernel needs to collect a large amount of information +in a place that doesn't require the correct operation of the filesystem. + +Kernel memory isn't suitable because: + +* Allocating a contiguous region of memory to create a C array is very + difficult, especially on 32-bit systems. + +* Linked lists of records introduce double pointer overhead which is very high + and eliminate the possibility of indexed lookups. + +* Kernel memory is pinned, which can drive the system into OOM conditions. + +* The system might not have sufficient memory to stage all the information. + +At any given time, online fsck does not need to keep the entire record set in +memory, which means that individual records can be paged out if necessary. +Continued development of online fsck demonstrated that the ability to perform +indexed data storage would also be very useful. +Fortunately, the Linux kernel already has a facility for byte-addressable and +pageable storage: tmpfs. +In-kernel graphics drivers (most notably i915) take advantage of tmpfs files +to store intermediate data that doesn't need to be in memory at all times, so +that usage precedent is already established. +Hence, the ``xfile`` was born! + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| The first edition of online repair inserted records into a new btree as | +| it found them, which failed because filesystem could shut down with a | +| built data structure, which would be live after recovery finished. | +| | +| The second edition solved the half-rebuilt structure problem by storing | +| everything in memory, but frequently ran the system out of memory. | +| | +| The third edition solved the OOM problem by using linked lists, but the | +| memory overhead of the list pointers was extreme. | ++--------------------------------------------------------------------------+ + +xfile Access Models +``````````````````` + +A survey of the intended uses of xfiles suggested these use cases: + +1. Arrays of fixed-sized records (space management btrees, directory and + extended attribute entries) + +2. Sparse arrays of fixed-sized records (quotas and link counts) + +3. Large binary objects (BLOBs) of variable sizes (directory and extended + attribute names and values) + +4. Staging btrees in memory (reverse mapping btrees) + +5. Arbitrary contents (realtime space management) + +To support the first four use cases, high level data structures wrap the xfile +to share functionality between online fsck functions. +The rest of this section discusses the interfaces that the xfile presents to +four of those five higher level data structures. +The fifth use case is discussed in the :ref:`realtime summary ` case +study. + +The most general storage interface supported by the xfile enables the reading +and writing of arbitrary quantities of data at arbitrary offsets in the xfile. +This capability is provided by ``xfile_pread`` and ``xfile_pwrite`` functions, +which behave similarly to their userspace counterparts. +XFS is very record-based, which suggests that the ability to load and store +complete records is important. +To support these cases, a pair of ``xfile_obj_load`` and ``xfile_obj_store`` +functions are provided to read and persist objects into an xfile. +They are internally the same as pread and pwrite, except that they treat any +error as an out of memory error. +For online repair, squashing error conditions in this manner is an acceptable +behavior because the only reaction is to abort the operation back to userspace. +All five xfile usecases can be serviced by these four functions. + +However, no discussion of file access idioms is complete without answering the +question, "But what about mmap?" +It is convenient to access storage directly with pointers, just like userspace +code does with regular memory. +Online fsck must not drive the system into OOM conditions, which means that +xfiles must be responsive to memory reclamation. +tmpfs can only push a pagecache folio to the swap cache if the folio is neither +pinned nor locked, which means the xfile must not pin too many folios. + +Short term direct access to xfile contents is done by locking the pagecache +folio and mapping it into kernel address space. +Programmatic access (e.g. pread and pwrite) uses this mechanism. +Folio locks are not supposed to be held for long periods of time, so long +term direct access to xfile contents is done by bumping the folio refcount, +mapping it into kernel address space, and dropping the folio lock. +These long term users *must* be responsive to memory reclaim by hooking into +the shrinker infrastructure to know when to release folios. + +The ``xfile_get_page`` and ``xfile_put_page`` functions are provided to +retrieve the (locked) folio that backs part of an xfile and to release it. +The only code to use these folio lease functions are the xfarray +:ref:`sorting` algorithms and the :ref:`in-memory +btrees`. + +xfile Access Coordination +````````````````````````` + +For security reasons, xfiles must be owned privately by the kernel. +They are marked ``S_PRIVATE`` to prevent interference from the security system, +must never be mapped into process file descriptor tables, and their pages must +never be mapped into userspace processes. + +To avoid locking recursion issues with the VFS, all accesses to the shmfs file +are performed by manipulating the page cache directly. +xfile writers call the ``->write_begin`` and ``->write_end`` functions of the +xfile's address space to grab writable pages, copy the caller's buffer into the +page, and release the pages. +xfile readers call ``shmem_read_mapping_page_gfp`` to grab pages directly +before copying the contents into the caller's buffer. +In other words, xfiles ignore the VFS read and write code paths to avoid +having to create a dummy ``struct kiocb`` and to avoid taking inode and +freeze locks. +tmpfs cannot be frozen, and xfiles must not be exposed to userspace. + +If an xfile is shared between threads to stage repairs, the caller must provide +its own locks to coordinate access. +For example, if a scrub function stores scan results in an xfile and needs +other threads to provide updates to the scanned data, the scrub function must +provide a lock for all threads to share. + +.. _xfarray: + +Arrays of Fixed-Sized Records +````````````````````````````` + +In XFS, each type of indexed space metadata (free space, inodes, reference +counts, file fork space, and reverse mappings) consists of a set of fixed-size +records indexed with a classic B+ tree. +Directories have a set of fixed-size dirent records that point to the names, +and extended attributes have a set of fixed-size attribute keys that point to +names and values. +Quota counters and file link counters index records with numbers. +During a repair, scrub needs to stage new records during the gathering step and +retrieve them during the btree building step. + +Although this requirement can be satisfied by calling the read and write +methods of the xfile directly, it is simpler for callers for there to be a +higher level abstraction to take care of computing array offsets, to provide +iterator functions, and to deal with sparse records and sorting. +The ``xfarray`` abstraction presents a linear array for fixed-size records atop +the byte-accessible xfile. + +.. _xfarray_access_patterns: + +Array Access Patterns +^^^^^^^^^^^^^^^^^^^^^ + +Array access patterns in online fsck tend to fall into three categories. +Iteration of records is assumed to be necessary for all cases and will be +covered in the next section. + +The first type of caller handles records that are indexed by position. +Gaps may exist between records, and a record may be updated multiple times +during the collection step. +In other words, these callers want a sparse linearly addressed table file. +The typical use case are quota records or file link count records. +Access to array elements is performed programmatically via ``xfarray_load`` and +``xfarray_store`` functions, which wrap the similarly-named xfile functions to +provide loading and storing of array elements at arbitrary array indices. +Gaps are defined to be null records, and null records are defined to be a +sequence of all zero bytes. +Null records are detected by calling ``xfarray_element_is_null``. +They are created either by calling ``xfarray_unset`` to null out an existing +record or by never storing anything to an array index. + +The second type of caller handles records that are not indexed by position +and do not require multiple updates to a record. +The typical use case here is rebuilding space btrees and key/value btrees. +These callers can add records to the array without caring about array indices +via the ``xfarray_append`` function, which stores a record at the end of the +array. +For callers that require records to be presentable in a specific order (e.g. +rebuilding btree data), the ``xfarray_sort`` function can arrange the sorted +records; this function will be covered later. + +The third type of caller is a bag, which is useful for counting records. +The typical use case here is constructing space extent reference counts from +reverse mapping information. +Records can be put in the bag in any order, they can be removed from the bag +at any time, and uniqueness of records is left to callers. +The ``xfarray_store_anywhere`` function is used to insert a record in any +null record slot in the bag; and the ``xfarray_unset`` function removes a +record from the bag. + +The proposed patchset is the +`big in-memory array +`_. + +Iterating Array Elements +^^^^^^^^^^^^^^^^^^^^^^^^ + +Most users of the xfarray require the ability to iterate the records stored in +the array. +Callers can probe every possible array index with the following: + +.. code-block:: c + + xfarray_idx_t i; + foreach_xfarray_idx(array, i) { + xfarray_load(array, i, &rec); + + /* do something with rec */ + } + +All users of this idiom must be prepared to handle null records or must already +know that there aren't any. + +For xfarray users that want to iterate a sparse array, the ``xfarray_iter`` +function ignores indices in the xfarray that have never been written to by +calling ``xfile_seek_data`` (which internally uses ``SEEK_DATA``) to skip areas +of the array that are not populated with memory pages. +Once it finds a page, it will skip the zeroed areas of the page. + +.. code-block:: c + + xfarray_idx_t i = XFARRAY_CURSOR_INIT; + while ((ret = xfarray_iter(array, &i, &rec)) == 1) { + /* do something with rec */ + } + +.. _xfarray_sort: + +Sorting Array Elements +^^^^^^^^^^^^^^^^^^^^^^ + +During the fourth demonstration of online repair, a community reviewer remarked +that for performance reasons, online repair ought to load batches of records +into btree record blocks instead of inserting records into a new btree one at a +time. +The btree insertion code in XFS is responsible for maintaining correct ordering +of the records, so naturally the xfarray must also support sorting the record +set prior to bulk loading. + +Case Study: Sorting xfarrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The sorting algorithm used in the xfarray is actually a combination of adaptive +quicksort and a heapsort subalgorithm in the spirit of +`Sedgewick `_ and +`pdqsort `_, with customizations for the Linux +kernel. +To sort records in a reasonably short amount of time, ``xfarray`` takes +advantage of the binary subpartitioning offered by quicksort, but it also uses +heapsort to hedge aginst performance collapse if the chosen quicksort pivots +are poor. +Both algorithms are (in general) O(n * lg(n)), but there is a wide performance +gulf between the two implementations. + +The Linux kernel already contains a reasonably fast implementation of heapsort. +It only operates on regular C arrays, which limits the scope of its usefulness. +There are two key places where the xfarray uses it: + +* Sorting any record subset backed by a single xfile page. + +* Loading a small number of xfarray records from potentially disparate parts + of the xfarray into a memory buffer, and sorting the buffer. + +In other words, ``xfarray`` uses heapsort to constrain the nested recursion of +quicksort, thereby mitigating quicksort's worst runtime behavior. + +Choosing a quicksort pivot is a tricky business. +A good pivot splits the set to sort in half, leading to the divide and conquer +behavior that is crucial to O(n * lg(n)) performance. +A poor pivot barely splits the subset at all, leading to O(n\ :sup:`2`) +runtime. +The xfarray sort routine tries to avoid picking a bad pivot by sampling nine +records into a memory buffer and using the kernel heapsort to identify the +median of the nine. + +Most modern quicksort implementations employ Tukey's "ninther" to select a +pivot from a classic C array. +Typical ninther implementations pick three unique triads of records, sort each +of the triads, and then sort the middle value of each triad to determine the +ninther value. +As stated previously, however, xfile accesses are not entirely cheap. +It turned out to be much more performant to read the nine elements into a +memory buffer, run the kernel's in-memory heapsort on the buffer, and choose +the 4th element of that buffer as the pivot. +Tukey's ninthers are described in J. W. Tukey, `The ninther, a technique for +low-effort robust (resistant) location in large samples`, in *Contributions to +Survey Sampling and Applied Statistics*, edited by H. David, (Academic Press, +1978), pp. 251–257. + +The partitioning of quicksort is fairly textbook -- rearrange the record +subset around the pivot, then set up the current and next stack frames to +sort with the larger and the smaller halves of the pivot, respectively. +This keeps the stack space requirements to log2(record count). + +As a final performance optimization, the hi and lo scanning phase of quicksort +keeps examined xfile pages mapped in the kernel for as long as possible to +reduce map/unmap cycles. +Surprisingly, this reduces overall sort runtime by nearly half again after +accounting for the application of heapsort directly onto xfile pages. + +.. _xfblob: + +Blob Storage +```````````` + +Extended attributes and directories add an additional requirement for staging +records: arbitrary byte sequences of finite length. +Each directory entry record needs to store entry name, +and each extended attribute needs to store both the attribute name and value. +The names, keys, and values can consume a large amount of memory, so the +``xfblob`` abstraction was created to simplify management of these blobs +atop an xfile. + +Blob arrays provide ``xfblob_load`` and ``xfblob_store`` functions to retrieve +and persist objects. +The store function returns a magic cookie for every object that it persists. +Later, callers provide this cookie to the ``xblob_load`` to recall the object. +The ``xfblob_free`` function frees a specific blob, and the ``xfblob_truncate`` +function frees them all because compaction is not needed. + +The details of repairing directories and extended attributes will be discussed +in a subsequent section about atomic extent swapping. +However, it should be noted that these repair functions only use blob storage +to cache a small number of entries before adding them to a temporary ondisk +file, which is why compaction is not required. + +The proposed patchset is at the start of the +`extended attribute repair +`_ series. + +.. _xfbtree: + +In-Memory B+Trees +````````````````` + +The chapter about :ref:`secondary metadata` mentioned that +checking and repairing of secondary metadata commonly requires coordination +between a live metadata scan of the filesystem and writer threads that are +updating that metadata. +Keeping the scan data up to date requires requires the ability to propagate +metadata updates from the filesystem into the data being collected by the scan. +This *can* be done by appending concurrent updates into a separate log file and +applying them before writing the new metadata to disk, but this leads to +unbounded memory consumption if the rest of the system is very busy. +Another option is to skip the side-log and commit live updates from the +filesystem directly into the scan data, which trades more overhead for a lower +maximum memory requirement. +In both cases, the data structure holding the scan results must support indexed +access to perform well. + +Given that indexed lookups of scan data is required for both strategies, online +fsck employs the second strategy of committing live updates directly into +scan data. +Because xfarrays are not indexed and do not enforce record ordering, they +are not suitable for this task. +Conveniently, however, XFS has a library to create and maintain ordered reverse +mapping records: the existing rmap btree code! +If only there was a means to create one in memory. + +Recall that the :ref:`xfile ` abstraction represents memory pages as a +regular file, which means that the kernel can create byte or block addressable +virtual address spaces at will. +The XFS buffer cache specializes in abstracting IO to block-oriented address +spaces, which means that adaptation of the buffer cache to interface with +xfiles enables reuse of the entire btree library. +Btrees built atop an xfile are collectively known as ``xfbtrees``. +The next few sections describe how they actually work. + +The proposed patchset is the +`in-memory btree +`_ +series. + +Using xfiles as a Buffer Cache Target +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Two modifications are necessary to support xfiles as a buffer cache target. +The first is to make it possible for the ``struct xfs_buftarg`` structure to +host the ``struct xfs_buf`` rhashtable, because normally those are held by a +per-AG structure. +The second change is to modify the buffer ``ioapply`` function to "read" cached +pages from the xfile and "write" cached pages back to the xfile. +Multiple access to individual buffers is controlled by the ``xfs_buf`` lock, +since the xfile does not provide any locking on its own. +With this adaptation in place, users of the xfile-backed buffer cache use +exactly the same APIs as users of the disk-backed buffer cache. +The separation between xfile and buffer cache implies higher memory usage since +they do not share pages, but this property could some day enable transactional +updates to an in-memory btree. +Today, however, it simply eliminates the need for new code. + +Space Management with an xfbtree +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Space management for an xfile is very simple -- each btree block is one memory +page in size. +These blocks use the same header format as an on-disk btree, but the in-memory +block verifiers ignore the checksums, assuming that xfile memory is no more +corruption-prone than regular DRAM. +Reusing existing code here is more important than absolute memory efficiency. + +The very first block of an xfile backing an xfbtree contains a header block. +The header describes the owner, height, and the block number of the root +xfbtree block. + +To allocate a btree block, use ``xfile_seek_data`` to find a gap in the file. +If there are no gaps, create one by extending the length of the xfile. +Preallocate space for the block with ``xfile_prealloc``, and hand back the +location. +To free an xfbtree block, use ``xfile_discard`` (which internally uses +``FALLOC_FL_PUNCH_HOLE``) to remove the memory page from the xfile. + +Populating an xfbtree +^^^^^^^^^^^^^^^^^^^^^ + +An online fsck function that wants to create an xfbtree should proceed as +follows: + +1. Call ``xfile_create`` to create an xfile. + +2. Call ``xfs_alloc_memory_buftarg`` to create a buffer cache target structure + pointing to the xfile. + +3. Pass the buffer cache target, buffer ops, and other information to + ``xfbtree_create`` to write an initial tree header and root block to the + xfile. + Each btree type should define a wrapper that passes necessary arguments to + the creation function. + For example, rmap btrees define ``xfs_rmapbt_mem_create`` to take care of + all the necessary details for callers. + A ``struct xfbtree`` object will be returned. + +4. Pass the xfbtree object to the btree cursor creation function for the + btree type. + Following the example above, ``xfs_rmapbt_mem_cursor`` takes care of this + for callers. + +5. Pass the btree cursor to the regular btree functions to make queries against + and to update the in-memory btree. + For example, a btree cursor for an rmap xfbtree can be passed to the + ``xfs_rmap_*`` functions just like any other btree cursor. + See the :ref:`next section` for information on dealing with + xfbtree updates that are logged to a transaction. + +6. When finished, delete the btree cursor, destroy the xfbtree object, free the + buffer target, and the destroy the xfile to release all resources. + +.. _xfbtree_commit: + +Committing Logged xfbtree Buffers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Although it is a clever hack to reuse the rmap btree code to handle the staging +structure, the ephemeral nature of the in-memory btree block storage presents +some challenges of its own. +The XFS transaction manager must not commit buffer log items for buffers backed +by an xfile because the log format does not understand updates for devices +other than the data device. +An ephemeral xfbtree probably will not exist by the time the AIL checkpoints +log transactions back into the filesystem, and certainly won't exist during +log recovery. +For these reasons, any code updating an xfbtree in transaction context must +remove the buffer log items from the transaction and write the updates into the +backing xfile before committing or cancelling the transaction. + +The ``xfbtree_trans_commit`` and ``xfbtree_trans_cancel`` functions implement +this functionality as follows: + +1. Find each buffer log item whose buffer targets the xfile. + +2. Record the dirty/ordered status of the log item. + +3. Detach the log item from the buffer. + +4. Queue the buffer to a special delwri list. + +5. Clear the transaction dirty flag if the only dirty log items were the ones + that were detached in step 3. + +6. Submit the delwri list to commit the changes to the xfile, if the updates + are being committed. + +After removing xfile logged buffers from the transaction in this manner, the +transaction can be committed or cancelled. + +Bulk Loading of Ondisk B+Trees +------------------------------ + +As mentioned previously, early iterations of online repair built new btree +structures by creating a new btree and adding observations individually. +Loading a btree one record at a time had a slight advantage of not requiring +the incore records to be sorted prior to commit, but was very slow and leaked +blocks if the system went down during a repair. +Loading records one at a time also meant that repair could not control the +loading factor of the blocks in the new btree. + +Fortunately, the venerable ``xfs_repair`` tool had a more efficient means for +rebuilding a btree index from a collection of records -- bulk btree loading. +This was implemented rather inefficiently code-wise, since ``xfs_repair`` +had separate copy-pasted implementations for each btree type. + +To prepare for online fsck, each of the four bulk loaders were studied, notes +were taken, and the four were refactored into a single generic btree bulk +loading mechanism. +Those notes in turn have been refreshed and are presented below. + +Geometry Computation +```````````````````` + +The zeroth step of bulk loading is to assemble the entire record set that will +be stored in the new btree, and sort the records. +Next, call ``xfs_btree_bload_compute_geometry`` to compute the shape of the +btree from the record set, the type of btree, and any load factor preferences. +This information is required for resource reservation. + +First, the geometry computation computes the minimum and maximum records that +will fit in a leaf block from the size of a btree block and the size of the +block header. +Roughly speaking, the maximum number of records is:: + + maxrecs = (block_size - header_size) / record_size + +The XFS design specifies that btree blocks should be merged when possible, +which means the minimum number of records is half of maxrecs:: + + minrecs = maxrecs / 2 + +The next variable to determine is the desired loading factor. +This must be at least minrecs and no more than maxrecs. +Choosing minrecs is undesirable because it wastes half the block. +Choosing maxrecs is also undesirable because adding a single record to each +newly rebuilt leaf block will cause a tree split, which causes a noticeable +drop in performance immediately afterwards. +The default loading factor was chosen to be 75% of maxrecs, which provides a +reasonably compact structure without any immediate split penalties:: + + default_load_factor = (maxrecs + minrecs) / 2 + +If space is tight, the loading factor will be set to maxrecs to try to avoid +running out of space:: + + leaf_load_factor = enough space ? default_load_factor : maxrecs + +Load factor is computed for btree node blocks using the combined size of the +btree key and pointer as the record size:: + + maxrecs = (block_size - header_size) / (key_size + ptr_size) + minrecs = maxrecs / 2 + node_load_factor = enough space ? default_load_factor : maxrecs + +Once that's done, the number of leaf blocks required to store the record set +can be computed as:: + + leaf_blocks = ceil(record_count / leaf_load_factor) + +The number of node blocks needed to point to the next level down in the tree +is computed as:: + + n_blocks = (n == 0 ? leaf_blocks : node_blocks[n]) + node_blocks[n + 1] = ceil(n_blocks / node_load_factor) + +The entire computation is performed recursively until the current level only +needs one block. +The resulting geometry is as follows: + +- For AG-rooted btrees, this level is the root level, so the height of the new + tree is ``level + 1`` and the space needed is the summation of the number of + blocks on each level. + +- For inode-rooted btrees where the records in the top level do not fit in the + inode fork area, the height is ``level + 2``, the space needed is the + summation of the number of blocks on each level, and the inode fork points to + the root block. + +- For inode-rooted btrees where the records in the top level can be stored in + the inode fork area, then the root block can be stored in the inode, the + height is ``level + 1``, and the space needed is one less than the summation + of the number of blocks on each level. + This only becomes relevant when non-bmap btrees gain the ability to root in + an inode, which is a future patchset and only included here for completeness. + +.. _newbt: + +Reserving New B+Tree Blocks +``````````````````````````` + +Once repair knows the number of blocks needed for the new btree, it allocates +those blocks using the free space information. +Each reserved extent is tracked separately by the btree builder state data. +To improve crash resilience, the reservation code also logs an Extent Freeing +Intent (EFI) item in the same transaction as each space allocation and attaches +its in-memory ``struct xfs_extent_free_item`` object to the space reservation. +If the system goes down, log recovery will use the unfinished EFIs to free the +unused space, the free space, leaving the filesystem unchanged. + +Each time the btree builder claims a block for the btree from a reserved +extent, it updates the in-memory reservation to reflect the claimed space. +Block reservation tries to allocate as much contiguous space as possible to +reduce the number of EFIs in play. + +While repair is writing these new btree blocks, the EFIs created for the space +reservations pin the tail of the ondisk log. +It's possible that other parts of the system will remain busy and push the head +of the log towards the pinned tail. +To avoid livelocking the filesystem, the EFIs must not pin the tail of the log +for too long. +To alleviate this problem, the dynamic relogging capability of the deferred ops +mechanism is reused here to commit a transaction at the log head containing an +EFD for the old EFI and new EFI at the head. +This enables the log to release the old EFI to keep the log moving forwards. + +EFIs have a role to play during the commit and reaping phases; please see the +next section and the section about :ref:`reaping` for more details. + +Proposed patchsets are the +`bitmap rework +`_ +and the +`preparation for bulk loading btrees +`_. + + +Writing the New Tree +```````````````````` + +This part is pretty simple -- the btree builder (``xfs_btree_bulkload``) claims +a block from the reserved list, writes the new btree block header, fills the +rest of the block with records, and adds the new leaf block to a list of +written blocks:: + + ┌────┐ + │leaf│ + │RRR │ + └────┘ + +Sibling pointers are set every time a new block is added to the level:: + + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +When it finishes writing the record leaf blocks, it moves on to the node +blocks +To fill a node block, it walks each block in the next level down in the tree +to compute the relevant keys and write them into the parent node:: + + ┌────┐ ┌────┐ + │node│──────→│node│ + │PP │←──────│PP │ + └────┘ └────┘ + ↙ ↘ ↙ ↘ + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +When it reaches the root level, it is ready to commit the new btree!:: + + ┌─────────┐ + │ root │ + │ PP │ + └─────────┘ + ↙ ↘ + ┌────┐ ┌────┐ + │node│──────→│node│ + │PP │←──────│PP │ + └────┘ └────┘ + ↙ ↘ ↙ ↘ + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +The first step to commit the new btree is to persist the btree blocks to disk +synchronously. +This is a little complicated because a new btree block could have been freed +in the recent past, so the builder must use ``xfs_buf_delwri_queue_here`` to +remove the (stale) buffer from the AIL list before it can write the new blocks +to disk. +Blocks are queued for IO using a delwri list and written in one large batch +with ``xfs_buf_delwri_submit``. + +Once the new blocks have been persisted to disk, control returns to the +individual repair function that called the bulk loader. +The repair function must log the location of the new root in a transaction, +clean up the space reservations that were made for the new btree, and reap the +old metadata blocks: + +1. Commit the location of the new btree root. + +2. For each incore reservation: + + a. Log Extent Freeing Done (EFD) items for all the space that was consumed + by the btree builder. The new EFDs must point to the EFIs attached to + the reservation to prevent log recovery from freeing the new blocks. + + b. For unclaimed portions of incore reservations, create a regular deferred + extent free work item to be free the unused space later in the + transaction chain. + + c. The EFDs and EFIs logged in steps 2a and 2b must not overrun the + reservation of the committing transaction. + If the btree loading code suspects this might be about to happen, it must + call ``xrep_defer_finish`` to clear out the deferred work and obtain a + fresh transaction. + +3. Clear out the deferred work a second time to finish the commit and clean + the repair transaction. + +The transaction rolling in steps 2c and 3 represent a weakness in the repair +algorithm, because a log flush and a crash before the end of the reap step can +result in space leaking. +Online repair functions minimize the chances of this occuring by using very +large transactions, which each can accomodate many thousands of block freeing +instructions. +Repair moves on to reaping the old blocks, which will be presented in a +subsequent :ref:`section` after a few case studies of bulk loading. + +Case Study: Rebuilding the Inode Index +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The high level process to rebuild the inode index btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_inobt_rec`` + records from the inode chunk information and a bitmap of the old inode btree + blocks. + +2. Append the records to an xfarray in inode order. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the inode btree. + If the free space inode btree is enabled, call it again to estimate the + geometry of the finobt. + +4. Allocate the number of blocks computed in the previous step. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + If the free space inode btree is enabled, call it again to load the finobt. + +6. Commit the location of the new btree root block(s) to the AGI. + +7. Reap the old btree blocks using the bitmap created in step 1. + +Details are as follows. + +The inode btree maps inumbers to the ondisk location of the associated +inode records, which means that the inode btrees can be rebuilt from the +reverse mapping information. +Reverse mapping records with an owner of ``XFS_RMAP_OWN_INOBT`` marks the +location of the old inode btree blocks. +Each reverse mapping record with an owner of ``XFS_RMAP_OWN_INODES`` marks the +location of at least one inode cluster buffer. +A cluster is the smallest number of ondisk inodes that can be allocated or +freed in a single transaction; it is never smaller than 1 fs block or 4 inodes. + +For the space represented by each inode cluster, ensure that there are no +records in the free space btrees nor any records in the reference count btree. +If there are, the space metadata inconsistencies are reason enough to abort the +operation. +Otherwise, read each cluster buffer to check that its contents appear to be +ondisk inodes and to decide if the file is allocated +(``xfs_dinode.i_mode != 0``) or free (``xfs_dinode.i_mode == 0``). +Accumulate the results of successive inode cluster buffer reads until there is +enough information to fill a single inode chunk record, which is 64 consecutive +numbers in the inumber keyspace. +If the chunk is sparse, the chunk record may include holes. + +Once the repair function accumulates one chunk's worth of data, it calls +``xfarray_append`` to add the inode btree record to the xfarray. +This xfarray is walked twice during the btree creation step -- once to populate +the inode btree with all inode chunk records, and a second time to populate the +free inode btree with records for chunks that have free non-sparse inodes. +The number of records for the inode btree is the number of xfarray records, +but the record count for the free inode btree has to be computed as inode chunk +records are stored in the xfarray. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding the Space Reference Counts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Reverse mapping records are used to rebuild the reference count information. +Reference counts are required for correct operation of copy on write for shared +file data. +Imagine the reverse mapping entries as rectangles representing extents of +physical blocks, and that the rectangles can be laid down to allow them to +overlap each other. +From the diagram below, it is apparent that a reference count record must start +or end wherever the height of the stack changes. +In other words, the record emission stimulus is level-triggered:: + + █ ███ + ██ █████ ████ ███ ██████ + ██ ████ ███████████ ████ █████████ + ████████████████████████████████ ███████████ + ^ ^ ^^ ^^ ^ ^^ ^^^ ^^^^ ^ ^^ ^ ^ ^ + 2 1 23 21 3 43 234 2123 1 01 2 3 0 + +The ondisk reference count btree does not store the refcount == 0 cases because +the free space btree already records which blocks are free. +Extents being used to stage copy-on-write operations should be the only records +with refcount == 1. +Single-owner file blocks aren't recorded in either the free space or the +reference count btrees. + +The high level process to rebuild the reference count btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_refcount_irec`` + records for any space having more than one reverse mapping and add them to + the xfarray. + Any records owned by ``XFS_RMAP_OWN_COW`` are also added to the xfarray + because these are extents allocated to stage a copy on write operation and + are tracked in the refcount btree. + + Use any records owned by ``XFS_RMAP_OWN_REFC`` to create a bitmap of old + refcount btree blocks. + +2. Sort the records in physical extent order, putting the CoW staging extents + at the end of the xfarray. + This matches the sorting order of records in the refcount btree. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the new tree. + +4. Allocate the number of blocks computed in the previous step. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + +6. Commit the location of new btree root block to the AGF. + +7. Reap the old btree blocks using the bitmap created in step 1. + +Details are as follows; the same algorithm is used by ``xfs_repair`` to +generate refcount information from reverse mapping records. + +- Until the reverse mapping btree runs out of records: + + - Retrieve the next record from the btree and put it in a bag. + + - Collect all records with the same starting block from the btree and put + them in the bag. + + - While the bag isn't empty: + + - Among the mappings in the bag, compute the lowest block number where the + reference count changes. + This position will be either the starting block number of the next + unprocessed reverse mapping or the next block after the shortest mapping + in the bag. + + - Remove all mappings from the bag that end at this position. + + - Collect all reverse mappings that start at this position from the btree + and put them in the bag. + + - If the size of the bag changed and is greater than one, create a new + refcount record associating the block number range that we just walked to + the size of the bag. + +The bag-like structure in this case is a type 2 xfarray as discussed in the +:ref:`xfarray access patterns` section. +Reverse mappings are added to the bag using ``xfarray_store_anywhere`` and +removed via ``xfarray_unset``. +Bag members are examined through ``xfarray_iter`` loops. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding File Fork Mapping Indices +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The high level process to rebuild a data/attr fork mapping btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_bmbt_rec`` + records from the reverse mapping records for that inode and fork. + Append these records to an xfarray. + Compute the bitmap of the old bmap btree blocks from the ``BMBT_BLOCK`` + records. + +2. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the new tree. + +3. Sort the records in file offset order. + +4. If the extent records would fit in the inode fork immediate area, commit the + records to that immediate area and skip to step 8. + +5. Allocate the number of blocks computed in the previous step. + +6. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + +7. Commit the new btree root block to the inode fork immediate area. + +8. Reap the old btree blocks using the bitmap created in step 1. + +There are some complications here: +First, it's possible to move the fork offset to adjust the sizes of the +immediate areas if the data and attr forks are not both in BMBT format. +Second, if there are sufficiently few fork mappings, it may be possible to use +EXTENTS format instead of BMBT, which may require a conversion. +Third, the incore extent map must be reloaded carefully to avoid disturbing +any delayed allocation extents. + +The proposed patchset is the +`file mapping repair +`_ +series. + +.. _reaping: + +Reaping Old Metadata Blocks +--------------------------- + +Whenever online fsck builds a new data structure to replace one that is +suspect, there is a question of how to find and dispose of the blocks that +belonged to the old structure. +The laziest method of course is not to deal with them at all, but this slowly +leads to service degradations as space leaks out of the filesystem. +Hopefully, someone will schedule a rebuild of the free space information to +plug all those leaks. +Offline repair rebuilds all space metadata after recording the usage of +the files and directories that it decides not to clear, hence it can build new +structures in the discovered free space and avoid the question of reaping. + +As part of a repair, online fsck relies heavily on the reverse mapping records +to find space that is owned by the corresponding rmap owner yet truly free. +Cross referencing rmap records with other rmap records is necessary because +there may be other data structures that also think they own some of those +blocks (e.g. crosslinked trees). +Permitting the block allocator to hand them out again will not push the system +towards consistency. + +For space metadata, the process of finding extents to dispose of generally +follows this format: + +1. Create a bitmap of space used by data structures that must be preserved. + The space reservations used to create the new metadata can be used here if + the same rmap owner code is used to denote all of the objects being rebuilt. + +2. Survey the reverse mapping data to create a bitmap of space owned by the + same ``XFS_RMAP_OWN_*`` number for the metadata that is being preserved. + +3. Use the bitmap disunion operator to subtract (1) from (2). + The remaining set bits represent candidate extents that could be freed. + The process moves on to step 4 below. + +Repairs for file-based metadata such as extended attributes, directories, +symbolic links, quota files and realtime bitmaps are performed by building a +new structure attached to a temporary file and swapping the forks. +Afterward, the mappings in the old file fork are the candidate blocks for +disposal. + +The process for disposing of old extents is as follows: + +4. For each candidate extent, count the number of reverse mapping records for + the first block in that extent that do not have the same rmap owner for the + data structure being repaired. + + - If zero, the block has a single owner and can be freed. + + - If not, the block is part of a crosslinked structure and must not be + freed. + +5. Starting with the next block in the extent, figure out how many more blocks + have the same zero/nonzero other owner status as that first block. + +6. If the region is crosslinked, delete the reverse mapping entry for the + structure being repaired and move on to the next region. + +7. If the region is to be freed, mark any corresponding buffers in the buffer + cache as stale to prevent log writeback. + +8. Free the region and move on. + +However, there is one complication to this procedure. +Transactions are of finite size, so the reaping process must be careful to roll +the transactions to avoid overruns. +Overruns come from two sources: + +a. EFIs logged on behalf of space that is no longer occupied + +b. Log items for buffer invalidations + +This is also a window in which a crash during the reaping process can leak +blocks. +As stated earlier, online repair functions use very large transactions to +minimize the chances of this occurring. + +The proposed patchset is the +`preparation for bulk loading btrees +`_ +series. + +Case Study: Reaping After a Regular Btree Repair +```````````````````````````````````````````````` + +Old reference count and inode btrees are the easiest to reap because they have +rmap records with special owner codes: ``XFS_RMAP_OWN_REFC`` for the refcount +btree, and ``XFS_RMAP_OWN_INOBT`` for the inode and free inode btrees. +Creating a list of extents to reap the old btree blocks is quite simple, +conceptually: + +1. Lock the relevant AGI/AGF header buffers to prevent allocation and frees. + +2. For each reverse mapping record with an rmap owner corresponding to the + metadata structure being rebuilt, set the corresponding range in a bitmap. + +3. Walk the current data structures that have the same rmap owner. + For each block visited, clear that range in the above bitmap. + +4. Each set bit in the bitmap represents a block that could be a block from the + old data structures and hence is a candidate for reaping. + In other words, ``(rmap_records_owned_by & ~blocks_reachable_by_walk)`` + are the blocks that might be freeable. + +If it is possible to maintain the AGF lock throughout the repair (which is the +common case), then step 2 can be performed at the same time as the reverse +mapping record walk that creates the records for the new btree. + +Case Study: Rebuilding the Free Space Indices +````````````````````````````````````````````` + +The high level process to rebuild the free space indices is: + +1. Walk the reverse mapping records to generate ``struct xfs_alloc_rec_incore`` + records from the gaps in the reverse mapping btree. + +2. Append the records to an xfarray. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for each new tree. + +4. Allocate the number of blocks computed in the previous step from the free + space information collected. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks for the free space by length index. + Call it again for the free space by block number index. + +6. Commit the locations of the new btree root blocks to the AGF. + +7. Reap the old btree blocks by looking for space that is not recorded by the + reverse mapping btree, the new free space btrees, or the AGFL. + +Repairing the free space btrees has three key complications over a regular +btree repair: + +First, free space is not explicitly tracked in the reverse mapping records. +Hence, the new free space records must be inferred from gaps in the physical +space component of the keyspace of the reverse mapping btree. + +Second, free space repairs cannot use the common btree reservation code because +new blocks are reserved out of the free space btrees. +This is impossible when repairing the free space btrees themselves. +However, repair holds the AGF buffer lock for the duration of the free space +index reconstruction, so it can use the collected free space information to +supply the blocks for the new free space btrees. +It is not necessary to back each reserved extent with an EFI because the new +free space btrees are constructed in what the ondisk filesystem thinks is +unowned space. +However, if reserving blocks for the new btrees from the collected free space +information changes the number of free space records, repair must re-estimate +the new free space btree geometry with the new record count until the +reservation is sufficient. +As part of committing the new btrees, repair must ensure that reverse mappings +are created for the reserved blocks and that unused reserved blocks are +inserted into the free space btrees. +Deferrred rmap and freeing operations are used to ensure that this transition +is atomic, similar to the other btree repair functions. + +Third, finding the blocks to reap after the repair is not overly +straightforward. +Blocks for the free space btrees and the reverse mapping btrees are supplied by +the AGFL. +Blocks put onto the AGFL have reverse mapping records with the owner +``XFS_RMAP_OWN_AG``. +This ownership is retained when blocks move from the AGFL into the free space +btrees or the reverse mapping btrees. +When repair walks reverse mapping records to synthesize free space records, it +creates a bitmap (``ag_owner_bitmap``) of all the space claimed by +``XFS_RMAP_OWN_AG`` records. +The repair context maintains a second bitmap corresponding to the rmap btree +blocks and the AGFL blocks (``rmap_agfl_bitmap``). +When the walk is complete, the bitmap disunion operation ``(ag_owner_bitmap & +~rmap_agfl_bitmap)`` computes the extents that are used by the old free space +btrees. +These blocks can then be reaped using the methods outlined above. + +The proposed patchset is the +`AG btree repair +`_ +series. + +.. _rmap_reap: + +Case Study: Reaping After Repairing Reverse Mapping Btrees +`````````````````````````````````````````````````````````` + +Old reverse mapping btrees are less difficult to reap after a repair. +As mentioned in the previous section, blocks on the AGFL, the two free space +btree blocks, and the reverse mapping btree blocks all have reverse mapping +records with ``XFS_RMAP_OWN_AG`` as the owner. +The full process of gathering reverse mapping records and building a new btree +are described in the case study of +:ref:`live rebuilds of rmap data `, but a crucial point from that +discussion is that the new rmap btree will not contain any records for the old +rmap btree, nor will the old btree blocks be tracked in the free space btrees. +The list of candidate reaping blocks is computed by setting the bits +corresponding to the gaps in the new rmap btree records, and then clearing the +bits corresponding to extents in the free space btrees and the current AGFL +blocks. +The result ``(new_rmapbt_gaps & ~(agfl | bnobt_records))`` are reaped using the +methods outlined above. + +The rest of the process of rebuildng the reverse mapping btree is discussed +in a separate :ref:`case study`. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding the AGFL +``````````````````````````````` + +The allocation group free block list (AGFL) is repaired as follows: + +1. Create a bitmap for all the space that the reverse mapping data claims is + owned by ``XFS_RMAP_OWN_AG``. + +2. Subtract the space used by the two free space btrees and the rmap btree. + +3. Subtract any space that the reverse mapping data claims is owned by any + other owner, to avoid re-adding crosslinked blocks to the AGFL. + +4. Once the AGFL is full, reap any blocks leftover. + +5. The next operation to fix the freelist will right-size the list. + +See `fs/xfs/scrub/agheader_repair.c `_ for more details. + +Inode Record Repairs +-------------------- + +Inode records must be handled carefully, because they have both ondisk records +("dinodes") and an in-memory ("cached") representation. +There is a very high potential for cache coherency issues if online fsck is not +careful to access the ondisk metadata *only* when the ondisk metadata is so +badly damaged that the filesystem cannot load the in-memory representation. +When online fsck wants to open a damaged file for scrubbing, it must use +specialized resource acquisition functions that return either the in-memory +representation *or* a lock on whichever object is necessary to prevent any +update to the ondisk location. + +The only repairs that should be made to the ondisk inode buffers are whatever +is necessary to get the in-core structure loaded. +This means fixing whatever is caught by the inode cluster buffer and inode fork +verifiers, and retrying the ``iget`` operation. +If the second ``iget`` fails, the repair has failed. + +Once the in-memory representation is loaded, repair can lock the inode and can +subject it to comprehensive checks, repairs, and optimizations. +Most inode attributes are easy to check and constrain, or are user-controlled +arbitrary bit patterns; these are both easy to fix. +Dealing with the data and attr fork extent counts and the file block counts is +more complicated, because computing the correct value requires traversing the +forks, or if that fails, leaving the fields invalid and waiting for the fork +fsck functions to run. + +The proposed patchset is the +`inode +`_ +repair series. + +Quota Record Repairs +-------------------- + +Similar to inodes, quota records ("dquots") also have both ondisk records and +an in-memory representation, and hence are subject to the same cache coherency +issues. +Somewhat confusingly, both are known as dquots in the XFS codebase. + +The only repairs that should be made to the ondisk quota record buffers are +whatever is necessary to get the in-core structure loaded. +Once the in-memory representation is loaded, the only attributes needing +checking are obviously bad limits and timer values. + +Quota usage counters are checked, repaired, and discussed separately in the +section about :ref:`live quotacheck `. + +The proposed patchset is the +`quota +`_ +repair series. + +.. _fscounters: + +Freezing to Fix Summary Counters +-------------------------------- + +Filesystem summary counters track availability of filesystem resources such +as free blocks, free inodes, and allocated inodes. +This information could be compiled by walking the free space and inode indexes, +but this is a slow process, so XFS maintains a copy in the ondisk superblock +that should reflect the ondisk metadata, at least when the filesystem has been +unmounted cleanly. +For performance reasons, XFS also maintains incore copies of those counters, +which are key to enabling resource reservations for active transactions. +Writer threads reserve the worst-case quantities of resources from the +incore counter and give back whatever they don't use at commit time. +It is therefore only necessary to serialize on the superblock when the +superblock is being committed to disk. + +The lazy superblock counter feature introduced in XFS v5 took this even further +by training log recovery to recompute the summary counters from the AG headers, +which eliminated the need for most transactions even to touch the superblock. +The only time XFS commits the summary counters is at filesystem unmount. +To reduce contention even further, the incore counter is implemented as a +percpu counter, which means that each CPU is allocated a batch of blocks from a +global incore counter and can satisfy small allocations from the local batch. + +The high-performance nature of the summary counters makes it difficult for +online fsck to check them, since there is no way to quiesce a percpu counter +while the system is running. +Although online fsck can read the filesystem metadata to compute the correct +values of the summary counters, there's no way to hold the value of a percpu +counter stable, so it's quite possible that the counter will be out of date by +the time the walk is complete. +Earlier versions of online scrub would return to userspace with an incomplete +scan flag, but this is not a satisfying outcome for a system administrator. +For repairs, the in-memory counters must be stabilized while walking the +filesystem metadata to get an accurate reading and install it in the percpu +counter. + +To satisfy this requirement, online fsck must prevent other programs in the +system from initiating new writes to the filesystem, it must disable background +garbage collection threads, and it must wait for existing writer programs to +exit the kernel. +Once that has been established, scrub can walk the AG free space indexes, the +inode btrees, and the realtime bitmap to compute the correct value of all +four summary counters. +This is very similar to a filesystem freeze, though not all of the pieces are +necessary: + +- The final freeze state is set one higher than ``SB_FREEZE_COMPLETE`` to + prevent other threads from thawing the filesystem, or other scrub threads + from initiating another fscounters freeze. + +- It does not quiesce the log. + +With this code in place, it is now possible to pause the filesystem for just +long enough to check and correct the summary counters. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| The initial implementation used the actual VFS filesystem freeze | +| mechanism to quiesce filesystem activity. | +| With the filesystem frozen, it is possible to resolve the counter values | +| with exact precision, but there are many problems with calling the VFS | +| methods directly: | +| | +| - Other programs can unfreeze the filesystem without our knowledge. | +| This leads to incorrect scan results and incorrect repairs. | +| | +| - Adding an extra lock to prevent others from thawing the filesystem | +| required the addition of a ``->freeze_super`` function to wrap | +| ``freeze_fs()``. | +| This in turn caused other subtle problems because it turns out that | +| the VFS ``freeze_super`` and ``thaw_super`` functions can drop the | +| last reference to the VFS superblock, and any subsequent access | +| becomes a UAF bug! | +| This can happen if the filesystem is unmounted while the underlying | +| block device has frozen the filesystem. | +| This problem could be solved by grabbing extra references to the | +| superblock, but it felt suboptimal given the other inadequacies of | +| this approach. | +| | +| - The log need not be quiesced to check the summary counters, but a VFS | +| freeze initiates one anyway. | +| This adds unnecessary runtime to live fscounter fsck operations. | +| | +| - Quiescing the log means that XFS flushes the (possibly incorrect) | +| counters to disk as part of cleaning the log. | +| | +| - A bug in the VFS meant that freeze could complete even when | +| sync_filesystem fails to flush the filesystem and returns an error. | +| This bug was fixed in Linux 5.17. | ++--------------------------------------------------------------------------+ + +The proposed patchset is the +`summary counter cleanup +`_ +series. + +Full Filesystem Scans +--------------------- + +Certain types of metadata can only be checked by walking every file in the +entire filesystem to record observations and comparing the observations against +what's recorded on disk. +Like every other type of online repair, repairs are made by writing those +observations to disk in a replacement structure and committing it atomically. +However, it is not practical to shut down the entire filesystem to examine +hundreds of billions of files because the downtime would be excessive. +Therefore, online fsck must build the infrastructure to manage a live scan of +all the files in the filesystem. +There are two questions that need to be solved to perform a live walk: + +- How does scrub manage the scan while it is collecting data? + +- How does the scan keep abreast of changes being made to the system by other + threads? + +.. _iscan: + +Coordinated Inode Scans +``````````````````````` + +In the original Unix filesystems of the 1970s, each directory entry contained +an index number (*inumber*) which was used as an index into on ondisk array +(*itable*) of fixed-size records (*inodes*) describing a file's attributes and +its data block mapping. +This system is described by J. Lions, `"inode (5659)" +`_ in *Lions' Commentary on +UNIX, 6th Edition*, (Dept. of Computer Science, the University of New South +Wales, November 1977), pp. 18-2; and later by D. Ritchie and K. Thompson, +`"Implementation of the File System" +`_, from *The UNIX +Time-Sharing System*, (The Bell System Technical Journal, July 1978), pp. +1913-4. + +XFS retains most of this design, except now inumbers are search keys over all +the space in the data section filesystem. +They form a continuous keyspace that can be expressed as a 64-bit integer, +though the inodes themselves are sparsely distributed within the keyspace. +Scans proceed in a linear fashion across the inumber keyspace, starting from +``0x0`` and ending at ``0xFFFFFFFFFFFFFFFF``. +Naturally, a scan through a keyspace requires a scan cursor object to track the +scan progress. +Because this keyspace is sparse, this cursor contains two parts. +The first part of this scan cursor object tracks the inode that will be +examined next; call this the examination cursor. +Somewhat less obviously, the scan cursor object must also track which parts of +the keyspace have already been visited, which is critical for deciding if a +concurrent filesystem update needs to be incorporated into the scan data. +Call this the visited inode cursor. + +Advancing the scan cursor is a multi-step process encapsulated in +``xchk_iscan_iter``: + +1. Lock the AGI buffer of the AG containing the inode pointed to by the visited + inode cursor. + This guarantee that inodes in this AG cannot be allocated or freed while + advancing the cursor. + +2. Use the per-AG inode btree to look up the next inumber after the one that + was just visited, since it may not be keyspace adjacent. + +3. If there are no more inodes left in this AG: + + a. Move the examination cursor to the point of the inumber keyspace that + corresponds to the start of the next AG. + + b. Adjust the visited inode cursor to indicate that it has "visited" the + last possible inode in the current AG's inode keyspace. + XFS inumbers are segmented, so the cursor needs to be marked as having + visited the entire keyspace up to just before the start of the next AG's + inode keyspace. + + c. Unlock the AGI and return to step 1 if there are unexamined AGs in the + filesystem. + + d. If there are no more AGs to examine, set both cursors to the end of the + inumber keyspace. + The scan is now complete. + +4. Otherwise, there is at least one more inode to scan in this AG: + + a. Move the examination cursor ahead to the next inode marked as allocated + by the inode btree. + + b. Adjust the visited inode cursor to point to the inode just prior to where + the examination cursor is now. + Because the scanner holds the AGI buffer lock, no inodes could have been + created in the part of the inode keyspace that the visited inode cursor + just advanced. + +5. Get the incore inode for the inumber of the examination cursor. + By maintaining the AGI buffer lock until this point, the scanner knows that + it was safe to advance the examination cursor across the entire keyspace, + and that it has stabilized this next inode so that it cannot disappear from + the filesystem until the scan releases the incore inode. + +6. Drop the AGI lock and return the incore inode to the caller. + +Online fsck functions scan all files in the filesystem as follows: + +1. Start a scan by calling ``xchk_iscan_start``. + +2. Advance the scan cursor (``xchk_iscan_iter``) to get the next inode. + If one is provided: + + a. Lock the inode to prevent updates during the scan. + + b. Scan the inode. + + c. While still holding the inode lock, adjust the visited inode cursor + (``xchk_iscan_mark_visited``) to point to this inode. + + d. Unlock and release the inode. + +8. Call ``xchk_iscan_teardown`` to complete the scan. + +There are subtleties with the inode cache that complicate grabbing the incore +inode for the caller. +Obviously, it is an absolute requirement that the inode metadata be consistent +enough to load it into the inode cache. +Second, if the incore inode is stuck in some intermediate state, the scan +coordinator must release the AGI and push the main filesystem to get the inode +back into a loadable state. + +The proposed patches are the +`inode scanner +`_ +series. +The first user of the new functionality is the +`online quotacheck +`_ +series. + +Inode Management +```````````````` + +In regular filesystem code, references to allocated XFS incore inodes are +always obtained (``xfs_iget``) outside of transaction context because the +creation of the incore context for an existing file does not require metadata +updates. +However, it is important to note that references to incore inodes obtained as +part of file creation must be performed in transaction context because the +filesystem must ensure the atomicity of the ondisk inode btree index updates +and the initialization of the actual ondisk inode. + +References to incore inodes are always released (``xfs_irele``) outside of +transaction context because there are a handful of activities that might +require ondisk updates: + +- The VFS may decide to kick off writeback as part of a ``DONTCACHE`` inode + release. + +- Speculative preallocations need to be unreserved. + +- An unlinked file may have lost its last reference, in which case the entire + file must be inactivated, which involves releasing all of its resources in + the ondisk metadata and freeing the inode. + +These activities are collectively called inode inactivation. +Inactivation has two parts -- the VFS part, which initiates writeback on all +dirty file pages, and the XFS part, which cleans up XFS-specific information +and frees the inode if it was unlinked. +If the inode is unlinked (or unconnected after a file handle operation), the +kernel drops the inode into the inactivation machinery immediately. + +During normal operation, resource acquisition for an update follows this order +to avoid deadlocks: + +1. Inode reference (``iget``). + +2. Filesystem freeze protection, if repairing (``mnt_want_write_file``). + +3. Inode ``IOLOCK`` (VFS ``i_rwsem``) lock to control file IO. + +4. Inode ``MMAPLOCK`` (page cache ``invalidate_lock``) lock for operations that + can update page cache mappings. + +5. Log feature enablement. + +6. Transaction log space grant. + +7. Space on the data and realtime devices for the transaction. + +8. Incore dquot references, if a file is being repaired. + Note that they are not locked, merely acquired. + +9. Inode ``ILOCK`` for file metadata updates. + +10. AG header buffer locks / Realtime metadata inode ILOCK. + +11. Realtime metadata buffer locks, if applicable. + +12. Extent mapping btree blocks, if applicable. + +Resources are often released in the reverse order, though this is not required. +However, online fsck differs from regular XFS operations because it may examine +an object that normally is acquired in a later stage of the locking order, and +then decide to cross-reference the object with an object that is acquired +earlier in the order. +The next few sections detail the specific ways in which online fsck takes care +to avoid deadlocks. + +iget and irele During a Scrub +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An inode scan performed on behalf of a scrub operation runs in transaction +context, and possibly with resources already locked and bound to it. +This isn't much of a problem for ``iget`` since it can operate in the context +of an existing transaction, as long as all of the bound resources are acquired +before the inode reference in the regular filesystem. + +When the VFS ``iput`` function is given a linked inode with no other +references, it normally puts the inode on an LRU list in the hope that it can +save time if another process re-opens the file before the system runs out +of memory and frees it. +Filesystem callers can short-circuit the LRU process by setting a ``DONTCACHE`` +flag on the inode to cause the kernel to try to drop the inode into the +inactivation machinery immediately. + +In the past, inactivation was always done from the process that dropped the +inode, which was a problem for scrub because scrub may already hold a +transaction, and XFS does not support nesting transactions. +On the other hand, if there is no scrub transaction, it is desirable to drop +otherwise unused inodes immediately to avoid polluting caches. +To capture these nuances, the online fsck code has a separate ``xchk_irele`` +function to set or clear the ``DONTCACHE`` flag to get the required release +behavior. + +Proposed patchsets include fixing +`scrub iget usage +`_ and +`dir iget usage +`_. + +.. _ilocking: + +Locking Inodes +^^^^^^^^^^^^^^ + +In regular filesystem code, the VFS and XFS will acquire multiple IOLOCK locks +in a well-known order: parent → child when updating the directory tree, and +in numerical order of the addresses of their ``struct inode`` object otherwise. +For regular files, the MMAPLOCK can be acquired after the IOLOCK to stop page +faults. +If two MMAPLOCKs must be acquired, they are acquired in numerical order of +the addresses of their ``struct address_space`` objects. +Due to the structure of existing filesystem code, IOLOCKs and MMAPLOCKs must be +acquired before transactions are allocated. +If two ILOCKs must be acquired, they are acquired in inumber order. + +Inode lock acquisition must be done carefully during a coordinated inode scan. +Online fsck cannot abide these conventions, because for a directory tree +scanner, the scrub process holds the IOLOCK of the file being scanned and it +needs to take the IOLOCK of the file at the other end of the directory link. +If the directory tree is corrupt because it contains a cycle, ``xfs_scrub`` +cannot use the regular inode locking functions and avoid becoming trapped in an +ABBA deadlock. + +Solving both of these problems is straightforward -- any time online fsck +needs to take a second lock of the same class, it uses trylock to avoid an ABBA +deadlock. +If the trylock fails, scrub drops all inode locks and use trylock loops to +(re)acquire all necessary resources. +Trylock loops enable scrub to check for pending fatal signals, which is how +scrub avoids deadlocking the filesystem or becoming an unresponsive process. +However, trylock loops means that online fsck must be prepared to measure the +resource being scrubbed before and after the lock cycle to detect changes and +react accordingly. + +.. _dirparent: + +Case Study: Finding a Directory Parent +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Consider the directory parent pointer repair code as an example. +Online fsck must verify that the dotdot dirent of a directory points up to a +parent directory, and that the parent directory contains exactly one dirent +pointing down to the child directory. +Fully validating this relationship (and repairing it if possible) requires a +walk of every directory on the filesystem while holding the child locked, and +while updates to the directory tree are being made. +The coordinated inode scan provides a way to walk the filesystem without the +possibility of missing an inode. +The child directory is kept locked to prevent updates to the dotdot dirent, but +if the scanner fails to lock a parent, it can drop and relock both the child +and the prospective parent. +If the dotdot entry changes while the directory is unlocked, then a move or +rename operation must have changed the child's parentage, and the scan can +exit early. + +The proposed patchset is the +`directory repair +`_ +series. + +.. _fshooks: + +Filesystem Hooks +````````````````` + +The second piece of support that online fsck functions need during a full +filesystem scan is the ability to stay informed about updates being made by +other threads in the filesystem, since comparisons against the past are useless +in a dynamic environment. +Two pieces of Linux kernel infrastructure enable online fsck to monitor regular +filesystem operations: filesystem hooks and :ref:`static keys`. + +Filesystem hooks convey information about an ongoing filesystem operation to +a downstream consumer. +In this case, the downstream consumer is always an online fsck function. +Because multiple fsck functions can run in parallel, online fsck uses the Linux +notifier call chain facility to dispatch updates to any number of interested +fsck processes. +Call chains are a dynamic list, which means that they can be configured at +run time. +Because these hooks are private to the XFS module, the information passed along +contains exactly what the checking function needs to update its observations. + +The current implementation of XFS hooks uses SRCU notifier chains to reduce the +impact to highly threaded workloads. +Regular blocking notifier chains use a rwsem and seem to have a much lower +overhead for single-threaded applications. +However, it may turn out that the combination of blocking chains and static +keys are a more performant combination; more study is needed here. + +The following pieces are necessary to hook a certain point in the filesystem: + +- A ``struct xfs_hooks`` object must be embedded in a convenient place such as + a well-known incore filesystem object. + +- Each hook must define an action code and a structure containing more context + about the action. + +- Hook providers should provide appropriate wrapper functions and structs + around the ``xfs_hooks`` and ``xfs_hook`` objects to take advantage of type + checking to ensure correct usage. + +- A callsite in the regular filesystem code must be chosen to call + ``xfs_hooks_call`` with the action code and data structure. + This place should be adjacent to (and not earlier than) the place where + the filesystem update is committed to the transaction. + In general, when the filesystem calls a hook chain, it should be able to + handle sleeping and should not be vulnerable to memory reclaim or locking + recursion. + However, the exact requirements are very dependent on the context of the hook + caller and the callee. + +- The online fsck function should define a structure to hold scan data, a lock + to coordinate access to the scan data, and a ``struct xfs_hook`` object. + The scanner function and the regular filesystem code must acquire resources + in the same order; see the next section for details. + +- The online fsck code must contain a C function to catch the hook action code + and data structure. + If the object being updated has already been visited by the scan, then the + hook information must be applied to the scan data. + +- Prior to unlocking inodes to start the scan, online fsck must call + ``xfs_hooks_setup`` to initialize the ``struct xfs_hook``, and + ``xfs_hooks_add`` to enable the hook. + +- Online fsck must call ``xfs_hooks_del`` to disable the hook once the scan is + complete. + +The number of hooks should be kept to a minimum to reduce complexity. +Static keys are used to reduce the overhead of filesystem hooks to nearly +zero when online fsck is not running. + +.. _liveupdate: + +Live Updates During a Scan +`````````````````````````` + +The code paths of the online fsck scanning code and the :ref:`hooked` +filesystem code look like this:: + + other program + ↓ + inode lock ←────────────────────┐ + ↓ │ + AG header lock │ + ↓ │ + filesystem function │ + ↓ │ + notifier call chain │ same + ↓ ├─── inode + scrub hook function │ lock + ↓ │ + scan data mutex ←──┐ same │ + ↓ ├─── scan │ + update scan data │ lock │ + ↑ │ │ + scan data mutex ←──┘ │ + ↑ │ + inode lock ←────────────────────┘ + ↑ + scrub function + ↑ + inode scanner + ↑ + xfs_scrub + +These rules must be followed to ensure correct interactions between the +checking code and the code making an update to the filesystem: + +- Prior to invoking the notifier call chain, the filesystem function being + hooked must acquire the same lock that the scrub scanning function acquires + to scan the inode. + +- The scanning function and the scrub hook function must coordinate access to + the scan data by acquiring a lock on the scan data. + +- Scrub hook function must not add the live update information to the scan + observations unless the inode being updated has already been scanned. + The scan coordinator has a helper predicate (``xchk_iscan_want_live_update``) + for this. + +- Scrub hook functions must not change the caller's state, including the + transaction that it is running. + They must not acquire any resources that might conflict with the filesystem + function being hooked. + +- The hook function can abort the inode scan to avoid breaking the other rules. + +The inode scan APIs are pretty simple: + +- ``xchk_iscan_start`` starts a scan + +- ``xchk_iscan_iter`` grabs a reference to the next inode in the scan or + returns zero if there is nothing left to scan + +- ``xchk_iscan_want_live_update`` to decide if an inode has already been + visited in the scan. + This is critical for hook functions to decide if they need to update the + in-memory scan information. + +- ``xchk_iscan_mark_visited`` to mark an inode as having been visited in the + scan + +- ``xchk_iscan_teardown`` to finish the scan + +This functionality is also a part of the +`inode scanner +`_ +series. + +.. _quotacheck: + +Case Study: Quota Counter Checking +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is useful to compare the mount time quotacheck code to the online repair +quotacheck code. +Mount time quotacheck does not have to contend with concurrent operations, so +it does the following: + +1. Make sure the ondisk dquots are in good enough shape that all the incore + dquots will actually load, and zero the resource usage counters in the + ondisk buffer. + +2. Walk every inode in the filesystem. + Add each file's resource usage to the incore dquot. + +3. Walk each incore dquot. + If the incore dquot is not being flushed, add the ondisk buffer backing the + incore dquot to a delayed write (delwri) list. + +4. Write the buffer list to disk. + +Like most online fsck functions, online quotacheck can't write to regular +filesystem objects until the newly collected metadata reflect all filesystem +state. +Therefore, online quotacheck records file resource usage to a shadow dquot +index implemented with a sparse ``xfarray``, and only writes to the real dquots +once the scan is complete. +Handling transactional updates is tricky because quota resource usage updates +are handled in phases to minimize contention on dquots: + +1. The inodes involved are joined and locked to a transaction. + +2. For each dquot attached to the file: + + a. The dquot is locked. + + b. A quota reservation is added to the dquot's resource usage. + The reservation is recorded in the transaction. + + c. The dquot is unlocked. + +3. Changes in actual quota usage are tracked in the transaction. + +4. At transaction commit time, each dquot is examined again: + + a. The dquot is locked again. + + b. Quota usage changes are logged and unused reservation is given back to + the dquot. + + c. The dquot is unlocked. + +For online quotacheck, hooks are placed in steps 2 and 4. +The step 2 hook creates a shadow version of the transaction dquot context +(``dqtrx``) that operates in a similar manner to the regular code. +The step 4 hook commits the shadow ``dqtrx`` changes to the shadow dquots. +Notice that both hooks are called with the inode locked, which is how the +live update coordinates with the inode scanner. + +The quotacheck scan looks like this: + +1. Set up a coordinated inode scan. + +2. For each inode returned by the inode scan iterator: + + a. Grab and lock the inode. + + b. Determine that inode's resource usage (data blocks, inode counts, + realtime blocks) and add that to the shadow dquots for the user, group, + and project ids associated with the inode. + + c. Unlock and release the inode. + +3. For each dquot in the system: + + a. Grab and lock the dquot. + + b. Check the dquot against the shadow dquots created by the scan and updated + by the live hooks. + +Live updates are key to being able to walk every quota record without +needing to hold any locks for a long duration. +If repairs are desired, the real and shadow dquots are locked and their +resource counts are set to the values in the shadow dquot. + +The proposed patchset is the +`online quotacheck +`_ +series. + +.. _nlinks: + +Case Study: File Link Count Checking +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +File link count checking also uses live update hooks. +The coordinated inode scanner is used to visit all directories on the +filesystem, and per-file link count records are stored in a sparse ``xfarray`` +indexed by inumber. +During the scanning phase, each entry in a directory generates observation +data as follows: + +1. If the entry is a dotdot (``'..'``) entry of the root directory, the + directory's parent link count is bumped because the root directory's dotdot + entry is self referential. + +2. If the entry is a dotdot entry of a subdirectory, the parent's backref + count is bumped. + +3. If the entry is neither a dot nor a dotdot entry, the target file's parent + count is bumped. + +4. If the target is a subdirectory, the parent's child link count is bumped. + +A crucial point to understand about how the link count inode scanner interacts +with the live update hooks is that the scan cursor tracks which *parent* +directories have been scanned. +In other words, the live updates ignore any update about ``A → B`` when A has +not been scanned, even if B has been scanned. +Furthermore, a subdirectory A with a dotdot entry pointing back to B is +accounted as a backref counter in the shadow data for A, since child dotdot +entries affect the parent's link count. +Live update hooks are carefully placed in all parts of the filesystem that +create, change, or remove directory entries, since those operations involve +bumplink and droplink. + +For any file, the correct link count is the number of parents plus the number +of child subdirectories. +Non-directories never have children of any kind. +The backref information is used to detect inconsistencies in the number of +links pointing to child subdirectories and the number of dotdot entries +pointing back. + +After the scan completes, the link count of each file can be checked by locking +both the inode and the shadow data, and comparing the link counts. +A second coordinated inode scan cursor is used for comparisons. +Live updates are key to being able to walk every inode without needing to hold +any locks between inodes. +If repairs are desired, the inode's link count is set to the value in the +shadow information. +If no parents are found, the file must be :ref:`reparented ` to the +orphanage to prevent the file from being lost forever. + +The proposed patchset is the +`file link count repair +`_ +series. + +.. _rmap_repair: + +Case Study: Rebuilding Reverse Mapping Records +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Most repair functions follow the same pattern: lock filesystem resources, +walk the surviving ondisk metadata looking for replacement metadata records, +and use an :ref:`in-memory array ` to store the gathered observations. +The primary advantage of this approach is the simplicity and modularity of the +repair code -- code and data are entirely contained within the scrub module, +do not require hooks in the main filesystem, and are usually the most efficient +in memory use. +A secondary advantage of this repair approach is atomicity -- once the kernel +decides a structure is corrupt, no other threads can access the metadata until +the kernel finishes repairing and revalidating the metadata. + +For repairs going on within a shard of the filesystem, these advantages +outweigh the delays inherent in locking the shard while repairing parts of the +shard. +Unfortunately, repairs to the reverse mapping btree cannot use the "standard" +btree repair strategy because it must scan every space mapping of every fork of +every file in the filesystem, and the filesystem cannot stop. +Therefore, rmap repair foregoes atomicity between scrub and repair. +It combines a :ref:`coordinated inode scanner `, :ref:`live update hooks +`, and an :ref:`in-memory rmap btree ` to complete the +scan for reverse mapping records. + +1. Set up an xfbtree to stage rmap records. + +2. While holding the locks on the AGI and AGF buffers acquired during the + scrub, generate reverse mappings for all AG metadata: inodes, btrees, CoW + staging extents, and the internal log. + +3. Set up an inode scanner. + +4. Hook into rmap updates for the AG being repaired so that the live scan data + can receive updates to the rmap btree from the rest of the filesystem during + the file scan. + +5. For each space mapping found in either fork of each file scanned, + decide if the mapping matches the AG of interest. + If so: + + a. Create a btree cursor for the in-memory btree. + + b. Use the rmap code to add the record to the in-memory btree. + + c. Use the :ref:`special commit function ` to write the + xfbtree changes to the xfile. + +6. For each live update received via the hook, decide if the owner has already + been scanned. + If so, apply the live update into the scan data: + + a. Create a btree cursor for the in-memory btree. + + b. Replay the operation into the in-memory btree. + + c. Use the :ref:`special commit function ` to write the + xfbtree changes to the xfile. + This is performed with an empty transaction to avoid changing the + caller's state. + +7. When the inode scan finishes, create a new scrub transaction and relock the + two AG headers. + +8. Compute the new btree geometry using the number of rmap records in the + shadow btree, like all other btree rebuilding functions. + +9. Allocate the number of blocks computed in the previous step. + +10. Perform the usual btree bulk loading and commit to install the new rmap + btree. + +11. Reap the old rmap btree blocks as discussed in the case study about how + to :ref:`reap after rmap btree repair `. + +12. Free the xfbtree now that it not needed. + +The proposed patchset is the +`rmap repair +`_ +series. + +Staging Repairs with Temporary Files on Disk +-------------------------------------------- + +XFS stores a substantial amount of metadata in file forks: directories, +extended attributes, symbolic link targets, free space bitmaps and summary +information for the realtime volume, and quota records. +File forks map 64-bit logical file fork space extents to physical storage space +extents, similar to how a memory management unit maps 64-bit virtual addresses +to physical memory addresses. +Therefore, file-based tree structures (such as directories and extended +attributes) use blocks mapped in the file fork offset address space that point +to other blocks mapped within that same address space, and file-based linear +structures (such as bitmaps and quota records) compute array element offsets in +the file fork offset address space. + +Because file forks can consume as much space as the entire filesystem, repairs +cannot be staged in memory, even when a paging scheme is available. +Therefore, online repair of file-based metadata createas a temporary file in +the XFS filesystem, writes a new structure at the correct offsets into the +temporary file, and atomically swaps the fork mappings (and hence the fork +contents) to commit the repair. +Once the repair is complete, the old fork can be reaped as necessary; if the +system goes down during the reap, the iunlink code will delete the blocks +during log recovery. + +**Note**: All space usage and inode indices in the filesystem *must* be +consistent to use a temporary file safely! +This dependency is the reason why online repair can only use pageable kernel +memory to stage ondisk space usage information. + +Swapping metadata extents with a temporary file requires the owner field of the +block headers to match the file being repaired and not the temporary file. The +directory, extended attribute, and symbolic link functions were all modified to +allow callers to specify owner numbers explicitly. + +There is a downside to the reaping process -- if the system crashes during the +reap phase and the fork extents are crosslinked, the iunlink processing will +fail because freeing space will find the extra reverse mappings and abort. + +Temporary files created for repair are similar to ``O_TMPFILE`` files created +by userspace. +They are not linked into a directory and the entire file will be reaped when +the last reference to the file is lost. +The key differences are that these files must have no access permission outside +the kernel at all, they must be specially marked to prevent them from being +opened by handle, and they must never be linked into the directory tree. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| In the initial iteration of file metadata repair, the damaged metadata | +| blocks would be scanned for salvageable data; the extents in the file | +| fork would be reaped; and then a new structure would be built in its | +| place. | +| This strategy did not survive the introduction of the atomic repair | +| requirement expressed earlier in this document. | +| | +| The second iteration explored building a second structure at a high | +| offset in the fork from the salvage data, reaping the old extents, and | +| using a ``COLLAPSE_RANGE`` operation to slide the new extents into | +| place. | +| | +| This had many drawbacks: | +| | +| - Array structures are linearly addressed, and the regular filesystem | +| codebase does not have the concept of a linear offset that could be | +| applied to the record offset computation to build an alternate copy. | +| | +| - Extended attributes are allowed to use the entire attr fork offset | +| address space. | +| | +| - Even if repair could build an alternate copy of a data structure in a | +| different part of the fork address space, the atomic repair commit | +| requirement means that online repair would have to be able to perform | +| a log assisted ``COLLAPSE_RANGE`` operation to ensure that the old | +| structure was completely replaced. | +| | +| - A crash after construction of the secondary tree but before the range | +| collapse would leave unreachable blocks in the file fork. | +| This would likely confuse things further. | +| | +| - Reaping blocks after a repair is not a simple operation, and | +| initiating a reap operation from a restarted range collapse operation | +| during log recovery is daunting. | +| | +| - Directory entry blocks and quota records record the file fork offset | +| in the header area of each block. | +| An atomic range collapse operation would have to rewrite this part of | +| each block header. | +| Rewriting a single field in block headers is not a huge problem, but | +| it's something to be aware of. | +| | +| - Each block in a directory or extended attributes btree index contains | +| sibling and child block pointers. | +| Were the atomic commit to use a range collapse operation, each block | +| would have to be rewritten very carefully to preserve the graph | +| structure. | +| Doing this as part of a range collapse means rewriting a large number | +| of blocks repeatedly, which is not conducive to quick repairs. | +| | +| This lead to the introduction of temporary file staging. | ++--------------------------------------------------------------------------+ + +Using a Temporary File +`````````````````````` + +Online repair code should use the ``xrep_tempfile_create`` function to create a +temporary file inside the filesystem. +This allocates an inode, marks the in-core inode private, and attaches it to +the scrub context. +These files are hidden from userspace, may not be added to the directory tree, +and must be kept private. + +Temporary files only use two inode locks: the IOLOCK and the ILOCK. +The MMAPLOCK is not needed here, because there must not be page faults from +userspace for data fork blocks. +The usage patterns of these two locks are the same as for any other XFS file -- +access to file data are controlled via the IOLOCK, and access to file metadata +are controlled via the ILOCK. +Locking helpers are provided so that the temporary file and its lock state can +be cleaned up by the scrub context. +To comply with the nested locking strategy laid out in the :ref:`inode +locking` section, it is recommended that scrub functions use the +xrep_tempfile_ilock*_nowait lock helpers. + +Data can be written to a temporary file by two means: + +1. ``xrep_tempfile_copyin`` can be used to set the contents of a regular + temporary file from an xfile. + +2. The regular directory, symbolic link, and extended attribute functions can + be used to write to the temporary file. + +Once a good copy of a data file has been constructed in a temporary file, it +must be conveyed to the file being repaired, which is the topic of the next +section. + +The proposed patches are in the +`repair temporary files +`_ +series. + +Atomic Extent Swapping +---------------------- + +Once repair builds a temporary file with a new data structure written into +it, it must commit the new changes into the existing file. +It is not possible to swap the inumbers of two files, so instead the new +metadata must replace the old. +This suggests the need for the ability to swap extents, but the existing extent +swapping code used by the file defragmenting tool ``xfs_fsr`` is not sufficient +for online repair because: + +a. When the reverse-mapping btree is enabled, the swap code must keep the + reverse mapping information up to date with every exchange of mappings. + Therefore, it can only exchange one mapping per transaction, and each + transaction is independent. + +b. Reverse-mapping is critical for the operation of online fsck, so the old + defragmentation code (which swapped entire extent forks in a single + operation) is not useful here. + +c. Defragmentation is assumed to occur between two files with identical + contents. + For this use case, an incomplete exchange will not result in a user-visible + change in file contents, even if the operation is interrupted. + +d. Online repair needs to swap the contents of two files that are by definition + *not* identical. + For directory and xattr repairs, the user-visible contents might be the + same, but the contents of individual blocks may be very different. + +e. Old blocks in the file may be cross-linked with another structure and must + not reappear if the system goes down mid-repair. + +These problems are overcome by creating a new deferred operation and a new type +of log intent item to track the progress of an operation to exchange two file +ranges. +The new deferred operation type chains together the same transactions used by +the reverse-mapping extent swap code. +The new log item records the progress of the exchange to ensure that once an +exchange begins, it will always run to completion, even there are +interruptions. +The new ``XFS_SB_FEAT_INCOMPAT_LOG_ATOMIC_SWAP`` log-incompatible feature flag +in the superblock protects these new log item records from being replayed on +old kernels. + +The proposed patchset is the +`atomic extent swap +`_ +series. + ++--------------------------------------------------------------------------+ +| **Sidebar: Using Log-Incompatible Feature Flags** | ++--------------------------------------------------------------------------+ +| Starting with XFS v5, the superblock contains a | +| ``sb_features_log_incompat`` field to indicate that the log contains | +| records that might not readable by all kernels that could mount this | +| filesystem. | +| In short, log incompat features protect the log contents against kernels | +| that will not understand the contents. | +| Unlike the other superblock feature bits, log incompat bits are | +| ephemeral because an empty (clean) log does not need protection. | +| The log cleans itself after its contents have been committed into the | +| filesystem, either as part of an unmount or because the system is | +| otherwise idle. | +| Because upper level code can be working on a transaction at the same | +| time that the log cleans itself, it is necessary for upper level code to | +| communicate to the log when it is going to use a log incompatible | +| feature. | +| | +| The log coordinates access to incompatible features through the use of | +| one ``struct rw_semaphore`` for each feature. | +| The log cleaning code tries to take this rwsem in exclusive mode to | +| clear the bit; if the lock attempt fails, the feature bit remains set. | +| Filesystem code signals its intention to use a log incompat feature in a | +| transaction by calling ``xlog_use_incompat_feat``, which takes the rwsem | +| in shared mode. | +| The code supporting a log incompat feature should create wrapper | +| functions to obtain the log feature and call | +| ``xfs_add_incompat_log_feature`` to set the feature bits in the primary | +| superblock. | +| The superblock update is performed transactionally, so the wrapper to | +| obtain log assistance must be called just prior to the creation of the | +| transaction that uses the functionality. | +| For a file operation, this step must happen after taking the IOLOCK | +| and the MMAPLOCK, but before allocating the transaction. | +| When the transaction is complete, the ``xlog_drop_incompat_feat`` | +| function is called to release the feature. | +| The feature bit will not be cleared from the superblock until the log | +| becomes clean. | +| | +| Log-assisted extended attribute updates and atomic extent swaps both use | +| log incompat features and provide convenience wrappers around the | +| functionality. | ++--------------------------------------------------------------------------+ + +Mechanics of an Atomic Extent Swap +`````````````````````````````````` + +Swapping entire file forks is a complex task. +The goal is to exchange all file fork mappings between two file fork offset +ranges. +There are likely to be many extent mappings in each fork, and the edges of +the mappings aren't necessarily aligned. +Furthermore, there may be other updates that need to happen after the swap, +such as exchanging file sizes, inode flags, or conversion of fork data to local +format. +This is roughly the format of the new deferred extent swap work item: + +.. code-block:: c + + struct xfs_swapext_intent { + /* Inodes participating in the operation. */ + struct xfs_inode *sxi_ip1; + struct xfs_inode *sxi_ip2; + + /* File offset range information. */ + xfs_fileoff_t sxi_startoff1; + xfs_fileoff_t sxi_startoff2; + xfs_filblks_t sxi_blockcount; + + /* Set these file sizes after the operation, unless negative. */ + xfs_fsize_t sxi_isize1; + xfs_fsize_t sxi_isize2; + + /* XFS_SWAP_EXT_* log operation flags */ + uint64_t sxi_flags; + }; + +The new log intent item contains enough information to track two logical fork +offset ranges: ``(inode1, startoff1, blockcount)`` and ``(inode2, startoff2, +blockcount)``. +Each step of a swap operation exchanges the largest file range mapping possible +from one file to the other. +After each step in the swap operation, the two startoff fields are incremented +and the blockcount field is decremented to reflect the progress made. +The flags field captures behavioral parameters such as swapping the attr fork +instead of the data fork and other work to be done after the extent swap. +The two isize fields are used to swap the file size at the end of the operation +if the file data fork is the target of the swap operation. + +When the extent swap is initiated, the sequence of operations is as follows: + +1. Create a deferred work item for the extent swap. + At the start, it should contain the entirety of the file ranges to be + swapped. + +2. Call ``xfs_defer_finish`` to process the exchange. + This is encapsulated in ``xrep_tempswap_contents`` for scrub operations. + This will log an extent swap intent item to the transaction for the deferred + extent swap work item. + +3. Until ``sxi_blockcount`` of the deferred extent swap work item is zero, + + a. Read the block maps of both file ranges starting at ``sxi_startoff1`` and + ``sxi_startoff2``, respectively, and compute the longest extent that can + be swapped in a single step. + This is the minimum of the two ``br_blockcount`` s in the mappings. + Keep advancing through the file forks until at least one of the mappings + contains written blocks. + Mutual holes, unwritten extents, and extent mappings to the same physical + space are not exchanged. + + For the next few steps, this document will refer to the mapping that came + from file 1 as "map1", and the mapping that came from file 2 as "map2". + + b. Create a deferred block mapping update to unmap map1 from file 1. + + c. Create a deferred block mapping update to unmap map2 from file 2. + + d. Create a deferred block mapping update to map map1 into file 2. + + e. Create a deferred block mapping update to map map2 into file 1. + + f. Log the block, quota, and extent count updates for both files. + + g. Extend the ondisk size of either file if necessary. + + h. Log an extent swap done log item for the extent swap intent log item + that was read at the start of step 3. + + i. Compute the amount of file range that has just been covered. + This quantity is ``(map1.br_startoff + map1.br_blockcount - + sxi_startoff1)``, because step 3a could have skipped holes. + + j. Increase the starting offsets of ``sxi_startoff1`` and ``sxi_startoff2`` + by the number of blocks computed in the previous step, and decrease + ``sxi_blockcount`` by the same quantity. + This advances the cursor. + + k. Log a new extent swap intent log item reflecting the advanced state of + the work item. + + l. Return the proper error code (EAGAIN) to the deferred operation manager + to inform it that there is more work to be done. + The operation manager completes the deferred work in steps 3b-3e before + moving back to the start of step 3. + +4. Perform any post-processing. + This will be discussed in more detail in subsequent sections. + +If the filesystem goes down in the middle of an operation, log recovery will +find the most recent unfinished extent swap log intent item and restart from +there. +This is how extent swapping guarantees that an outside observer will either see +the old broken structure or the new one, and never a mismash of both. + +Preparation for Extent Swapping +``````````````````````````````` + +There are a few things that need to be taken care of before initiating an +atomic extent swap operation. +First, regular files require the page cache to be flushed to disk before the +operation begins, and directio writes to be quiesced. +Like any filesystem operation, extent swapping must determine the maximum +amount of disk space and quota that can be consumed on behalf of both files in +the operation, and reserve that quantity of resources to avoid an unrecoverable +out of space failure once it starts dirtying metadata. +The preparation step scans the ranges of both files to estimate: + +- Data device blocks needed to handle the repeated updates to the fork + mappings. +- Change in data and realtime block counts for both files. +- Increase in quota usage for both files, if the two files do not share the + same set of quota ids. +- The number of extent mappings that will be added to each file. +- Whether or not there are partially written realtime extents. + User programs must never be able to access a realtime file extent that maps + to different extents on the realtime volume, which could happen if the + operation fails to run to completion. + +The need for precise estimation increases the run time of the swap operation, +but it is very important to maintain correct accounting. +The filesystem must not run completely out of free space, nor can the extent +swap ever add more extent mappings to a fork than it can support. +Regular users are required to abide the quota limits, though metadata repairs +may exceed quota to resolve inconsistent metadata elsewhere. + +Special Features for Swapping Metadata File Extents +``````````````````````````````````````````````````` + +Extended attributes, symbolic links, and directories can set the fork format to +"local" and treat the fork as a literal area for data storage. +Metadata repairs must take extra steps to support these cases: + +- If both forks are in local format and the fork areas are large enough, the + swap is performed by copying the incore fork contents, logging both forks, + and committing. + The atomic extent swap mechanism is not necessary, since this can be done + with a single transaction. + +- If both forks map blocks, then the regular atomic extent swap is used. + +- Otherwise, only one fork is in local format. + The contents of the local format fork are converted to a block to perform the + swap. + The conversion to block format must be done in the same transaction that + logs the initial extent swap intent log item. + The regular atomic extent swap is used to exchange the mappings. + Special flags are set on the swap operation so that the transaction can be + rolled one more time to convert the second file's fork back to local format + so that the second file will be ready to go as soon as the ILOCK is dropped. + +Extended attributes and directories stamp the owning inode into every block, +but the buffer verifiers do not actually check the inode number! +Although there is no verification, it is still important to maintain +referential integrity, so prior to performing the extent swap, online repair +builds every block in the new data structure with the owner field of the file +being repaired. + +After a successful swap operation, the repair operation must reap the old fork +blocks by processing each fork mapping through the standard :ref:`file extent +reaping ` mechanism that is done post-repair. +If the filesystem should go down during the reap part of the repair, the +iunlink processing at the end of recovery will free both the temporary file and +whatever blocks were not reaped. +However, this iunlink processing omits the cross-link detection of online +repair, and is not completely foolproof. + +Swapping Temporary File Extents +``````````````````````````````` + +To repair a metadata file, online repair proceeds as follows: + +1. Create a temporary repair file. + +2. Use the staging data to write out new contents into the temporary repair + file. + The same fork must be written to as is being repaired. + +3. Commit the scrub transaction, since the swap estimation step must be + completed before transaction reservations are made. + +4. Call ``xrep_tempswap_trans_alloc`` to allocate a new scrub transaction with + the appropriate resource reservations, locks, and fill out a ``struct + xfs_swapext_req`` with the details of the swap operation. + +5. Call ``xrep_tempswap_contents`` to swap the contents. + +6. Commit the transaction to complete the repair. + +.. _rtsummary: + +Case Study: Repairing the Realtime Summary File +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the "realtime" section of an XFS filesystem, free space is tracked via a +bitmap, similar to Unix FFS. +Each bit in the bitmap represents one realtime extent, which is a multiple of +the filesystem block size between 4KiB and 1GiB in size. +The realtime summary file indexes the number of free extents of a given size to +the offset of the block within the realtime free space bitmap where those free +extents begin. +In other words, the summary file helps the allocator find free extents by +length, similar to what the free space by count (cntbt) btree does for the data +section. + +The summary file itself is a flat file (with no block headers or checksums!) +partitioned into ``log2(total rt extents)`` sections containing enough 32-bit +counters to match the number of blocks in the rt bitmap. +Each counter records the number of free extents that start in that bitmap block +and can satisfy a power-of-two allocation request. + +To check the summary file against the bitmap: + +1. Take the ILOCK of both the realtime bitmap and summary files. + +2. For each free space extent recorded in the bitmap: + + a. Compute the position in the summary file that contains a counter that + represents this free extent. + + b. Read the counter from the xfile. + + c. Increment it, and write it back to the xfile. + +3. Compare the contents of the xfile against the ondisk file. + +To repair the summary file, write the xfile contents into the temporary file +and use atomic extent swap to commit the new contents. +The temporary file is then reaped. + +The proposed patchset is the +`realtime summary repair +`_ +series. + +Case Study: Salvaging Extended Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In XFS, extended attributes are implemented as a namespaced name-value store. +Values are limited in size to 64KiB, but there is no limit in the number of +names. +The attribute fork is unpartitioned, which means that the root of the attribute +structure is always in logical block zero, but attribute leaf blocks, dabtree +index blocks, and remote value blocks are intermixed. +Attribute leaf blocks contain variable-sized records that associate +user-provided names with the user-provided values. +Values larger than a block are allocated separate extents and written there. +If the leaf information expands beyond a single block, a directory/attribute +btree (``dabtree``) is created to map hashes of attribute names to entries +for fast lookup. + +Salvaging extended attributes is done as follows: + +1. Walk the attr fork mappings of the file being repaired to find the attribute + leaf blocks. + When one is found, + + a. Walk the attr leaf block to find candidate keys. + When one is found, + + 1. Check the name for problems, and ignore the name if there are. + + 2. Retrieve the value. + If that succeeds, add the name and value to the staging xfarray and + xfblob. + +2. If the memory usage of the xfarray and xfblob exceed a certain amount of + memory or there are no more attr fork blocks to examine, unlock the file and + add the staged extended attributes to the temporary file. + +3. Use atomic extent swapping to exchange the new and old extended attribute + structures. + The old attribute blocks are now attached to the temporary file. + +4. Reap the temporary file. + +The proposed patchset is the +`extended attribute repair +`_ +series. + +Fixing Directories +------------------ + +Fixing directories is difficult with currently available filesystem features, +since directory entries are not redundant. +The offline repair tool scans all inodes to find files with nonzero link count, +and then it scans all directories to establish parentage of those linked files. +Damaged files and directories are zapped, and files with no parent are +moved to the ``/lost+found`` directory. +It does not try to salvage anything. + +The best that online repair can do at this time is to read directory data +blocks and salvage any dirents that look plausible, correct link counts, and +move orphans back into the directory tree. +The salvage process is discussed in the case study at the end of this section. +The :ref:`file link count fsck ` code takes care of fixing link counts +and moving orphans to the ``/lost+found`` directory. + +Case Study: Salvaging Directories +````````````````````````````````` + +Unlike extended attributes, directory blocks are all the same size, so +salvaging directories is straightforward: + +1. Find the parent of the directory. + If the dotdot entry is not unreadable, try to confirm that the alleged + parent has a child entry pointing back to the directory being repaired. + Otherwise, walk the filesystem to find it. + +2. Walk the first partition of data fork of the directory to find the directory + entry data blocks. + When one is found, + + a. Walk the directory data block to find candidate entries. + When an entry is found: + + i. Check the name for problems, and ignore the name if there are. + + ii. Retrieve the inumber and grab the inode. + If that succeeds, add the name, inode number, and file type to the + staging xfarray and xblob. + +3. If the memory usage of the xfarray and xfblob exceed a certain amount of + memory or there are no more directory data blocks to examine, unlock the + directory and add the staged dirents into the temporary directory. + Truncate the staging files. + +4. Use atomic extent swapping to exchange the new and old directory structures. + The old directory blocks are now attached to the temporary file. + +5. Reap the temporary file. + +**Future Work Question**: Should repair revalidate the dentry cache when +rebuilding a directory? + +*Answer*: Yes, it should. + +In theory it is necessary to scan all dentry cache entries for a directory to +ensure that one of the following apply: + +1. The cached dentry reflects an ondisk dirent in the new directory. + +2. The cached dentry no longer has a corresponding ondisk dirent in the new + directory and the dentry can be purged from the cache. + +3. The cached dentry no longer has an ondisk dirent but the dentry cannot be + purged. + This is the problem case. + +Unfortunately, the current dentry cache design doesn't provide a means to walk +every child dentry of a specific directory, which makes this a hard problem. +There is no known solution. + +The proposed patchset is the +`directory repair +`_ +series. + +Parent Pointers +``````````````` + +A parent pointer is a piece of file metadata that enables a user to locate the +file's parent directory without having to traverse the directory tree from the +root. +Without them, reconstruction of directory trees is hindered in much the same +way that the historic lack of reverse space mapping information once hindered +reconstruction of filesystem space metadata. +The parent pointer feature, however, makes total directory reconstruction +possible. + +XFS parent pointers include the dirent name and location of the entry within +the parent directory. +In other words, child files use extended attributes to store pointers to +parents in the form ``(parent_inum, parent_gen, dirent_pos) → (dirent_name)``. +The directory checking process can be strengthened to ensure that the target of +each dirent also contains a parent pointer pointing back to the dirent. +Likewise, each parent pointer can be checked by ensuring that the target of +each parent pointer is a directory and that it contains a dirent matching +the parent pointer. +Both online and offline repair can use this strategy. + +**Note**: The ondisk format of parent pointers is not yet finalized. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| Directory parent pointers were first proposed as an XFS feature more | +| than a decade ago by SGI. | +| Each link from a parent directory to a child file is mirrored with an | +| extended attribute in the child that could be used to identify the | +| parent directory. | +| Unfortunately, this early implementation had major shortcomings and was | +| never merged into Linux XFS: | +| | +| 1. The XFS codebase of the late 2000s did not have the infrastructure to | +| enforce strong referential integrity in the directory tree. | +| It did not guarantee that a change in a forward link would always be | +| followed up with the corresponding change to the reverse links. | +| | +| 2. Referential integrity was not integrated into offline repair. | +| Checking and repairs were performed on mounted filesystems without | +| taking any kernel or inode locks to coordinate access. | +| It is not clear how this actually worked properly. | +| | +| 3. The extended attribute did not record the name of the directory entry | +| in the parent, so the SGI parent pointer implementation cannot be | +| used to reconnect the directory tree. | +| | +| 4. Extended attribute forks only support 65,536 extents, which means | +| that parent pointer attribute creation is likely to fail at some | +| point before the maximum file link count is achieved. | +| | +| The original parent pointer design was too unstable for something like | +| a file system repair to depend on. | +| Allison Henderson, Chandan Babu, and Catherine Hoang are working on a | +| second implementation that solves all shortcomings of the first. | +| During 2022, Allison introduced log intent items to track physical | +| manipulations of the extended attribute structures. | +| This solves the referential integrity problem by making it possible to | +| commit a dirent update and a parent pointer update in the same | +| transaction. | +| Chandan increased the maximum extent counts of both data and attribute | +| forks, thereby ensuring that the extended attribute structure can grow | +| to handle the maximum hardlink count of any file. | ++--------------------------------------------------------------------------+ + +Case Study: Repairing Directories with Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Directory rebuilding uses a :ref:`coordinated inode scan ` and +a :ref:`directory entry live update hook ` as follows: + +1. Set up a temporary directory for generating the new directory structure, + an xfblob for storing entry names, and an xfarray for stashing directory + updates. + +2. Set up an inode scanner and hook into the directory entry code to receive + updates on directory operations. + +3. For each parent pointer found in each file scanned, decide if the parent + pointer references the directory of interest. + If so: + + a. Stash an addname entry for this dirent in the xfarray for later. + + b. When finished scanning that file, flush the stashed updates to the + temporary directory. + +4. For each live directory update received via the hook, decide if the child + has already been scanned. + If so: + + a. Stash an addname or removename entry for this dirent update in the + xfarray for later. + We cannot write directly to the temporary directory because hook + functions are not allowed to modify filesystem metadata. + Instead, we stash updates in the xfarray and rely on the scanner thread + to apply the stashed updates to the temporary directory. + +5. When the scan is complete, atomically swap the contents of the temporary + directory and the directory being repaired. + The temporary directory now contains the damaged directory structure. + +6. Reap the temporary directory. + +7. Update the dirent position field of parent pointers as necessary. + This may require the queuing of a substantial number of xattr log intent + items. + +The proposed patchset is the +`parent pointers directory repair +`_ +series. + +**Unresolved Question**: How will repair ensure that the ``dirent_pos`` fields +match in the reconstructed directory? + +*Answer*: There are a few ways to solve this problem: + +1. The field could be designated advisory, since the other three values are + sufficient to find the entry in the parent. + However, this makes indexed key lookup impossible while repairs are ongoing. + +2. We could allow creating directory entries at specified offsets, which solves + the referential integrity problem but runs the risk that dirent creation + will fail due to conflicts with the free space in the directory. + + These conflicts could be resolved by appending the directory entry and + amending the xattr code to support updating an xattr key and reindexing the + dabtree, though this would have to be performed with the parent directory + still locked. + +3. Same as above, but remove the old parent pointer entry and add a new one + atomically. + +4. Change the ondisk xattr format to ``(parent_inum, name) → (parent_gen)``, + which would provide the attr name uniqueness that we require, without + forcing repair code to update the dirent position. + Unfortunately, this requires changes to the xattr code to support attr + names as long as 263 bytes. + +5. Change the ondisk xattr format to ``(parent_inum, hash(name)) → + (name, parent_gen)``. + If the hash is sufficiently resistant to collisions (e.g. sha256) then + this should provide the attr name uniqueness that we require. + Names shorter than 247 bytes could be stored directly. + +Discussion is ongoing under the `parent pointers patch deluge +`_. + +Case Study: Repairing Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Online reconstruction of a file's parent pointer information works similarly to +directory reconstruction: + +1. Set up a temporary file for generating a new extended attribute structure, + an `xfblob` for storing parent pointer names, and an xfarray for + stashing parent pointer updates. + +2. Set up an inode scanner and hook into the directory entry code to receive + updates on directory operations. + +3. For each directory entry found in each directory scanned, decide if the + dirent references the file of interest. + If so: + + a. Stash an addpptr entry for this parent pointer in the xfblob and xfarray + for later. + + b. When finished scanning the directory, flush the stashed updates to the + temporary directory. + +4. For each live directory update received via the hook, decide if the parent + has already been scanned. + If so: + + a. Stash an addpptr or removepptr entry for this dirent update in the + xfarray for later. + We cannot write parent pointers directly to the temporary file because + hook functions are not allowed to modify filesystem metadata. + Instead, we stash updates in the xfarray and rely on the scanner thread + to apply the stashed parent pointer updates to the temporary file. + +5. Copy all non-parent pointer extended attributes to the temporary file. + +6. When the scan is complete, atomically swap the attribute fork of the + temporary file and the file being repaired. + The temporary file now contains the damaged extended attribute structure. + +7. Reap the temporary file. + +The proposed patchset is the +`parent pointers repair +`_ +series. + +Digression: Offline Checking of Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Examining parent pointers in offline repair works differently because corrupt +files are erased long before directory tree connectivity checks are performed. +Parent pointer checks are therefore a second pass to be added to the existing +connectivity checks: + +1. After the set of surviving files has been established (i.e. phase 6), + walk the surviving directories of each AG in the filesystem. + This is already performed as part of the connectivity checks. + +2. For each directory entry found, record the name in an xfblob, and store + ``(child_ag_inum, parent_inum, parent_gen, dirent_pos)`` tuples in a + per-AG in-memory slab. + +3. For each AG in the filesystem, + + a. Sort the per-AG tuples in order of child_ag_inum, parent_inum, and + dirent_pos. + + b. For each inode in the AG, + + 1. Scan the inode for parent pointers. + Record the names in a per-file xfblob, and store ``(parent_inum, + parent_gen, dirent_pos)`` tuples in a per-file slab. + + 2. Sort the per-file tuples in order of parent_inum, and dirent_pos. + + 3. Position one slab cursor at the start of the inode's records in the + per-AG tuple slab. + This should be trivial since the per-AG tuples are in child inumber + order. + + 4. Position a second slab cursor at the start of the per-file tuple slab. + + 5. Iterate the two cursors in lockstep, comparing the parent_ino and + dirent_pos fields of the records under each cursor. + + a. Tuples in the per-AG list but not the per-file list are missing and + need to be written to the inode. + + b. Tuples in the per-file list but not the per-AG list are dangling + and need to be removed from the inode. + + c. For tuples in both lists, update the parent_gen and name components + of the parent pointer if necessary. + +4. Move on to examining link counts, as we do today. + +The proposed patchset is the +`offline parent pointers repair +`_ +series. + +Rebuilding directories from parent pointers in offline repair is very +challenging because it currently uses a single-pass scan of the filesystem +during phase 3 to decide which files are corrupt enough to be zapped. +This scan would have to be converted into a multi-pass scan: + +1. The first pass of the scan zaps corrupt inodes, forks, and attributes + much as it does now. + Corrupt directories are noted but not zapped. + +2. The next pass records parent pointers pointing to the directories noted + as being corrupt in the first pass. + This second pass may have to happen after the phase 4 scan for duplicate + blocks, if phase 4 is also capable of zapping directories. + +3. The third pass resets corrupt directories to an empty shortform directory. + Free space metadata has not been ensured yet, so repair cannot yet use the + directory building code in libxfs. + +4. At the start of phase 6, space metadata have been rebuilt. + Use the parent pointer information recorded during step 2 to reconstruct + the dirents and add them to the now-empty directories. + +This code has not yet been constructed. + +.. _orphanage: + +The Orphanage +------------- + +Filesystems present files as a directed, and hopefully acyclic, graph. +In other words, a tree. +The root of the filesystem is a directory, and each entry in a directory points +downwards either to more subdirectories or to non-directory files. +Unfortunately, a disruption in the directory graph pointers result in a +disconnected graph, which makes files impossible to access via regular path +resolution. + +Without parent pointers, the directory parent pointer online scrub code can +detect a dotdot entry pointing to a parent directory that doesn't have a link +back to the child directory and the file link count checker can detect a file +that isn't pointed to by any directory in the filesystem. +If such a file has a positive link count, the file is an orphan. + +With parent pointers, directories can be rebuilt by scanning parent pointers +and parent pointers can be rebuilt by scanning directories. +This should reduce the incidence of files ending up in ``/lost+found``. + +When orphans are found, they should be reconnected to the directory tree. +Offline fsck solves the problem by creating a directory ``/lost+found`` to +serve as an orphanage, and linking orphan files into the orphanage by using the +inumber as the name. +Reparenting a file to the orphanage does not reset any of its permissions or +ACLs. + +This process is more involved in the kernel than it is in userspace. +The directory and file link count repair setup functions must use the regular +VFS mechanisms to create the orphanage directory with all the necessary +security attributes and dentry cache entries, just like a regular directory +tree modification. + +Orphaned files are adopted by the orphanage as follows: + +1. Call ``xrep_orphanage_try_create`` at the start of the scrub setup function + to try to ensure that the lost and found directory actually exists. + This also attaches the orphanage directory to the scrub context. + +2. If the decision is made to reconnect a file, take the IOLOCK of both the + orphanage and the file being reattached. + The ``xrep_orphanage_iolock_two`` function follows the inode locking + strategy discussed earlier. + +3. Call ``xrep_orphanage_compute_blkres`` and ``xrep_orphanage_compute_name`` + to compute the new name in the orphanage and the block reservation required. + +4. Use ``xrep_orphanage_adoption_prep`` to reserve resources to the repair + transaction. + +5. Call ``xrep_orphanage_adopt`` to reparent the orphaned file into the lost + and found, and update the kernel dentry cache. + +The proposed patches are in the +`orphanage adoption +`_ +series. + +6. Userspace Algorithms and Data Structures +=========================================== + +This section discusses the key algorithms and data structures of the userspace +program, ``xfs_scrub``, that provide the ability to drive metadata checks and +repairs in the kernel, verify file data, and look for other potential problems. + +.. _scrubcheck: + +Checking Metadata +----------------- + +Recall the :ref:`phases of fsck work` outlined earlier. +That structure follows naturally from the data dependencies designed into the +filesystem from its beginnings in 1993. +In XFS, there are several groups of metadata dependencies: + +a. Filesystem summary counts depend on consistency within the inode indices, + the allocation group space btrees, and the realtime volume space + information. + +b. Quota resource counts depend on consistency within the quota file data + forks, inode indices, inode records, and the forks of every file on the + system. + +c. The naming hierarchy depends on consistency within the directory and + extended attribute structures. + This includes file link counts. + +d. Directories, extended attributes, and file data depend on consistency within + the file forks that map directory and extended attribute data to physical + storage media. + +e. The file forks depends on consistency within inode records and the space + metadata indices of the allocation groups and the realtime volume. + This includes quota and realtime metadata files. + +f. Inode records depends on consistency within the inode metadata indices. + +g. Realtime space metadata depend on the inode records and data forks of the + realtime metadata inodes. + +h. The allocation group metadata indices (free space, inodes, reference count, + and reverse mapping btrees) depend on consistency within the AG headers and + between all the AG metadata btrees. + +i. ``xfs_scrub`` depends on the filesystem being mounted and kernel support + for online fsck functionality. + +Therefore, a metadata dependency graph is a convenient way to schedule checking +operations in the ``xfs_scrub`` program: + +- Phase 1 checks that the provided path maps to an XFS filesystem and detect + the kernel's scrubbing abilities, which validates group (i). + +- Phase 2 scrubs groups (g) and (h) in parallel using a threaded workqueue. + +- Phase 3 scans inodes in parallel. + For each inode, groups (f), (e), and (d) are checked, in that order. + +- Phase 4 repairs everything in groups (i) through (d) so that phases 5 and 6 + may run reliably. + +- Phase 5 starts by checking groups (b) and (c) in parallel before moving on + to checking names. + +- Phase 6 depends on groups (i) through (b) to find file data blocks to verify, + to read them, and to report which blocks of which files are affected. + +- Phase 7 checks group (a), having validated everything else. + +Notice that the data dependencies between groups are enforced by the structure +of the program flow. + +Parallel Inode Scans +-------------------- + +An XFS filesystem can easily contain hundreds of millions of inodes. +Given that XFS targets installations with large high-performance storage, +it is desirable to scrub inodes in parallel to minimize runtime, particularly +if the program has been invoked manually from a command line. +This requires careful scheduling to keep the threads as evenly loaded as +possible. + +Early iterations of the ``xfs_scrub`` inode scanner naïvely created a single +workqueue and scheduled a single workqueue item per AG. +Each workqueue item walked the inode btree (with ``XFS_IOC_INUMBERS``) to find +inode chunks and then called bulkstat (``XFS_IOC_BULKSTAT``) to gather enough +information to construct file handles. +The file handle was then passed to a function to generate scrub items for each +metadata object of each inode. +This simple algorithm leads to thread balancing problems in phase 3 if the +filesystem contains one AG with a few large sparse files and the rest of the +AGs contain many smaller files. +The inode scan dispatch function was not sufficiently granular; it should have +been dispatching at the level of individual inodes, or, to constrain memory +consumption, inode btree records. + +Thanks to Dave Chinner, bounded workqueues in userspace enable ``xfs_scrub`` to +avoid this problem with ease by adding a second workqueue. +Just like before, the first workqueue is seeded with one workqueue item per AG, +and it uses INUMBERS to find inode btree chunks. +The second workqueue, however, is configured with an upper bound on the number +of items that can be waiting to be run. +Each inode btree chunk found by the first workqueue's workers are queued to the +second workqueue, and it is this second workqueue that queries BULKSTAT, +creates a file handle, and passes it to a function to generate scrub items for +each metadata object of each inode. +If the second workqueue is too full, the workqueue add function blocks the +first workqueue's workers until the backlog eases. +This doesn't completely solve the balancing problem, but reduces it enough to +move on to more pressing issues. + +The proposed patchsets are the scrub +`performance tweaks +`_ +and the +`inode scan rebalance +`_ +series. + +.. _scrubrepair: + +Scheduling Repairs +------------------ + +During phase 2, corruptions and inconsistencies reported in any AGI header or +inode btree are repaired immediately, because phase 3 relies on proper +functioning of the inode indices to find inodes to scan. +Failed repairs are rescheduled to phase 4. +Problems reported in any other space metadata are deferred to phase 4. +Optimization opportunities are always deferred to phase 4, no matter their +origin. + +During phase 3, corruptions and inconsistencies reported in any part of a +file's metadata are repaired immediately if all space metadata were validated +during phase 2. +Repairs that fail or cannot be repaired immediately are scheduled for phase 4. + +In the original design of ``xfs_scrub``, it was thought that repairs would be +so infrequent that the ``struct xfs_scrub_metadata`` objects used to +communicate with the kernel could also be used as the primary object to +schedule repairs. +With recent increases in the number of optimizations possible for a given +filesystem object, it became much more memory-efficient to track all eligible +repairs for a given filesystem object with a single repair item. +Each repair item represents a single lockable object -- AGs, metadata files, +individual inodes, or a class of summary information. + +Phase 4 is responsible for scheduling a lot of repair work in as quick a +manner as is practical. +The :ref:`data dependencies ` outlined earlier still apply, which +means that ``xfs_scrub`` must try to complete the repair work scheduled by +phase 2 before trying repair work scheduled by phase 3. +The repair process is as follows: + +1. Start a round of repair with a workqueue and enough workers to keep the CPUs + as busy as the user desires. + + a. For each repair item queued by phase 2, + + i. Ask the kernel to repair everything listed in the repair item for a + given filesystem object. + + ii. Make a note if the kernel made any progress in reducing the number + of repairs needed for this object. + + iii. If the object no longer requires repairs, revalidate all metadata + associated with this object. + If the revalidation succeeds, drop the repair item. + If not, requeue the item for more repairs. + + b. If any repairs were made, jump back to 1a to retry all the phase 2 items. + + c. For each repair item queued by phase 3, + + i. Ask the kernel to repair everything listed in the repair item for a + given filesystem object. + + ii. Make a note if the kernel made any progress in reducing the number + of repairs needed for this object. + + iii. If the object no longer requires repairs, revalidate all metadata + associated with this object. + If the revalidation succeeds, drop the repair item. + If not, requeue the item for more repairs. + + d. If any repairs were made, jump back to 1c to retry all the phase 3 items. + +2. If step 1 made any repair progress of any kind, jump back to step 1 to start + another round of repair. + +3. If there are items left to repair, run them all serially one more time. + Complain if the repairs were not successful, since this is the last chance + to repair anything. + +Corruptions and inconsistencies encountered during phases 5 and 7 are repaired +immediately. +Corrupt file data blocks reported by phase 6 cannot be recovered by the +filesystem. + +The proposed patchsets are the +`repair warning improvements +`_, +refactoring of the +`repair data dependency +`_ +and +`object tracking +`_, +and the +`repair scheduling +`_ +improvement series. + +Checking Names for Confusable Unicode Sequences +----------------------------------------------- + +If ``xfs_scrub`` succeeds in validating the filesystem metadata by the end of +phase 4, it moves on to phase 5, which checks for suspicious looking names in +the filesystem. +These names consist of the filesystem label, names in directory entries, and +the names of extended attributes. +Like most Unix filesystems, XFS imposes the sparest of constraints on the +contents of a name: + +- Slashes and null bytes are not allowed in directory entries. + +- Null bytes are not allowed in userspace-visible extended attributes. + +- Null bytes are not allowed in the filesystem label. + +Directory entries and attribute keys store the length of the name explicitly +ondisk, which means that nulls are not name terminators. +For this section, the term "naming domain" refers to any place where names are +presented together -- all the names in a directory, or all the attributes of a +file. + +Although the Unix naming constraints are very permissive, the reality of most +modern-day Linux systems is that programs work with Unicode character code +points to support international languages. +These programs typically encode those code points in UTF-8 when interfacing +with the C library because the kernel expects null-terminated names. +In the common case, therefore, names found in an XFS filesystem are actually +UTF-8 encoded Unicode data. + +To maximize its expressiveness, the Unicode standard defines separate control +points for various characters that render similarly or identically in writing +systems around the world. +For example, the character "Cyrillic Small Letter A" U+0430 "а" often renders +identically to "Latin Small Letter A" U+0061 "a". + +The standard also permits characters to be constructed in multiple ways -- +either by using a defined code point, or by combining one code point with +various combining marks. +For example, the character "Angstrom Sign U+212B "Å" can also be expressed +as "Latin Capital Letter A" U+0041 "A" followed by "Combining Ring Above" +U+030A "◌̊". +Both sequences render identically. + +Like the standards that preceded it, Unicode also defines various control +characters to alter the presentation of text. +For example, the character "Right-to-Left Override" U+202E can trick some +programs into rendering "moo\\xe2\\x80\\xaegnp.txt" as "mootxt.png". +A second category of rendering problems involves whitespace characters. +If the character "Zero Width Space" U+200B is encountered in a file name, the +name will render identically to a name that does not have the zero width +space. + +If two names within a naming domain have different byte sequences but render +identically, a user may be confused by it. +The kernel, in its indifference to upper level encoding schemes, permits this. +Most filesystem drivers persist the byte sequence names that are given to them +by the VFS. + +Techniques for detecting confusable names are explained in great detail in +sections 4 and 5 of the +`Unicode Security Mechanisms `_ +document. +When ``xfs_scrub`` detects UTF-8 encoding in use on a system, it uses the +Unicode normalization form NFD in conjunction with the confusable name +detection component of +`libicu `_ +to identify names with a directory or within a file's extended attributes that +could be confused for each other. +Names are also checked for control characters, non-rendering characters, and +mixing of bidirectional characters. +All of these potential issues are reported to the system administrator during +phase 5. + +Media Verification of File Data Extents +--------------------------------------- + +The system administrator can elect to initiate a media scan of all file data +blocks. +This scan after validation of all filesystem metadata (except for the summary +counters) as phase 6. +The scan starts by calling ``FS_IOC_GETFSMAP`` to scan the filesystem space map +to find areas that are allocated to file data fork extents. +Gaps betweeen data fork extents that are smaller than 64k are treated as if +they were data fork extents to reduce the command setup overhead. +When the space map scan accumulates a region larger than 32MB, a media +verification request is sent to the disk as a directio read of the raw block +device. + +If the verification read fails, ``xfs_scrub`` retries with single-block reads +to narrow down the failure to the specific region of the media and recorded. +When it has finished issuing verification requests, it again uses the space +mapping ioctl to map the recorded media errors back to metadata structures +and report what has been lost. +For media errors in blocks owned by files, parent pointers can be used to +construct file paths from inode numbers for user-friendly reporting. + +7. Conclusion and Future Work +============================= + +It is hoped that the reader of this document has followed the designs laid out +in this document and now has some familiarity with how XFS performs online +rebuilding of its metadata indices, and how filesystem users can interact with +that functionality. +Although the scope of this work is daunting, it is hoped that this guide will +make it easier for code readers to understand what has been built, for whom it +has been built, and why. +Please feel free to contact the XFS mailing list with questions. + +FIEXCHANGE_RANGE +---------------- + +As discussed earlier, a second frontend to the atomic extent swap mechanism is +a new ioctl call that userspace programs can use to commit updates to files +atomically. +This frontend has been out for review for several years now, though the +necessary refinements to online repair and lack of customer demand mean that +the proposal has not been pushed very hard. + +Extent Swapping with Regular User Files +``````````````````````````````````````` + +As mentioned earlier, XFS has long had the ability to swap extents between +files, which is used almost exclusively by ``xfs_fsr`` to defragment files. +The earliest form of this was the fork swap mechanism, where the entire +contents of data forks could be exchanged between two files by exchanging the +raw bytes in each inode fork's immediate area. +When XFS v5 came along with self-describing metadata, this old mechanism grew +some log support to continue rewriting the owner fields of BMBT blocks during +log recovery. +When the reverse mapping btree was later added to XFS, the only way to maintain +the consistency of the fork mappings with the reverse mapping index was to +develop an iterative mechanism that used deferred bmap and rmap operations to +swap mappings one at a time. +This mechanism is identical to steps 2-3 from the procedure above except for +the new tracking items, because the atomic extent swap mechanism is an +iteration of an existing mechanism and not something totally novel. +For the narrow case of file defragmentation, the file contents must be +identical, so the recovery guarantees are not much of a gain. + +Atomic extent swapping is much more flexible than the existing swapext +implementations because it can guarantee that the caller never sees a mix of +old and new contents even after a crash, and it can operate on two arbitrary +file fork ranges. +The extra flexibility enables several new use cases: + +- **Atomic commit of file writes**: A userspace process opens a file that it + wants to update. + Next, it opens a temporary file and calls the file clone operation to reflink + the first file's contents into the temporary file. + Writes to the original file should instead be written to the temporary file. + Finally, the process calls the atomic extent swap system call + (``FIEXCHANGE_RANGE``) to exchange the file contents, thereby committing all + of the updates to the original file, or none of them. + +.. _swapext_if_unchanged: + +- **Transactional file updates**: The same mechanism as above, but the caller + only wants the commit to occur if the original file's contents have not + changed. + To make this happen, the calling process snapshots the file modification and + change timestamps of the original file before reflinking its data to the + temporary file. + When the program is ready to commit the changes, it passes the timestamps + into the kernel as arguments to the atomic extent swap system call. + The kernel only commits the changes if the provided timestamps match the + original file. + +- **Emulation of atomic block device writes**: Export a block device with a + logical sector size matching the filesystem block size to force all writes + to be aligned to the filesystem block size. + Stage all writes to a temporary file, and when that is complete, call the + atomic extent swap system call with a flag to indicate that holes in the + temporary file should be ignored. + This emulates an atomic device write in software, and can support arbitrary + scattered writes. + +Vectorized Scrub +---------------- + +As it turns out, the :ref:`refactoring ` of repair items mentioned +earlier was a catalyst for enabling a vectorized scrub system call. +Since 2018, the cost of making a kernel call has increased considerably on some +systems to mitigate the effects of speculative execution attacks. +This incentivizes program authors to make as few system calls as possible to +reduce the number of times an execution path crosses a security boundary. + +With vectorized scrub, userspace pushes to the kernel the identity of a +filesystem object, a list of scrub types to run against that object, and a +simple representation of the data dependencies between the selected scrub +types. +The kernel executes as much of the caller's plan as it can until it hits a +dependency that cannot be satisfied due to a corruption, and tells userspace +how much was accomplished. +It is hoped that ``io_uring`` will pick up enough of this functionality that +online fsck can use that instead of adding a separate vectored scrub system +call to XFS. + +The relevant patchsets are the +`kernel vectorized scrub +`_ +and +`userspace vectorized scrub +`_ +series. + +Quality of Service Targets for Scrub +------------------------------------ + +One serious shortcoming of the online fsck code is that the amount of time that +it can spend in the kernel holding resource locks is basically unbounded. +Userspace is allowed to send a fatal signal to the process which will cause +``xfs_scrub`` to exit when it reaches a good stopping point, but there's no way +for userspace to provide a time budget to the kernel. +Given that the scrub codebase has helpers to detect fatal signals, it shouldn't +be too much work to allow userspace to specify a timeout for a scrub/repair +operation and abort the operation if it exceeds budget. +However, most repair functions have the property that once they begin to touch +ondisk metadata, the operation cannot be cancelled cleanly, after which a QoS +timeout is no longer useful. + +Defragmenting Free Space +------------------------ + +Over the years, many XFS users have requested the creation of a program to +clear a portion of the physical storage underlying a filesystem so that it +becomes a contiguous chunk of free space. +Call this free space defragmenter ``clearspace`` for short. + +The first piece the ``clearspace`` program needs is the ability to read the +reverse mapping index from userspace. +This already exists in the form of the ``FS_IOC_GETFSMAP`` ioctl. +The second piece it needs is a new fallocate mode +(``FALLOC_FL_MAP_FREE_SPACE``) that allocates the free space in a region and +maps it to a file. +Call this file the "space collector" file. +The third piece is the ability to force an online repair. + +To clear all the metadata out of a portion of physical storage, clearspace +uses the new fallocate map-freespace call to map any free space in that region +to the space collector file. +Next, clearspace finds all metadata blocks in that region by way of +``GETFSMAP`` and issues forced repair requests on the data structure. +This often results in the metadata being rebuilt somewhere that is not being +cleared. +After each relocation, clearspace calls the "map free space" function again to +collect any newly freed space in the region being cleared. + +To clear all the file data out of a portion of the physical storage, clearspace +uses the FSMAP information to find relevant file data blocks. +Having identified a good target, it uses the ``FICLONERANGE`` call on that part +of the file to try to share the physical space with a dummy file. +Cloning the extent means that the original owners cannot overwrite the +contents; any changes will be written somewhere else via copy-on-write. +Clearspace makes its own copy of the frozen extent in an area that is not being +cleared, and uses ``FIEDEUPRANGE`` (or the :ref:`atomic extent swap +` feature) to change the target file's data extent +mapping away from the area being cleared. +When all other mappings have been moved, clearspace reflinks the space into the +space collector file so that it becomes unavailable. + +There are further optimizations that could apply to the above algorithm. +To clear a piece of physical storage that has a high sharing factor, it is +strongly desirable to retain this sharing factor. +In fact, these extents should be moved first to maximize sharing factor after +the operation completes. +To make this work smoothly, clearspace needs a new ioctl +(``FS_IOC_GETREFCOUNTS``) to report reference count information to userspace. +With the refcount information exposed, clearspace can quickly find the longest, +most shared data extents in the filesystem, and target them first. + +**Future Work Question**: How might the filesystem move inode chunks? + +*Answer*: To move inode chunks, Dave Chinner constructed a prototype program +that creates a new file with the old contents and then locklessly runs around +the filesystem updating directory entries. +The operation cannot complete if the filesystem goes down. +That problem isn't totally insurmountable: create an inode remapping table +hidden behind a jump label, and a log item that tracks the kernel walking the +filesystem to update directory entries. +The trouble is, the kernel can't do anything about open files, since it cannot +revoke them. + +**Future Work Question**: Can static keys be used to minimize the cost of +supporting ``revoke()`` on XFS files? + +*Answer*: Yes. +Until the first revocation, the bailout code need not be in the call path at +all. + +The relevant patchsets are the +`kernel freespace defrag +`_ +and +`userspace freespace defrag +`_ +series. + +Shrinking Filesystems +--------------------- + +Removing the end of the filesystem ought to be a simple matter of evacuating +the data and metadata at the end of the filesystem, and handing the freed space +to the shrink code. +That requires an evacuation of the space at end of the filesystem, which is a +use of free space defragmentation! diff --git a/Documentation/filesystems/xfs-self-describing-metadata.rst b/Documentation/filesystems/xfs-self-describing-metadata.rst index b79dbf36dc94..a10c4ae6955e 100644 --- a/Documentation/filesystems/xfs-self-describing-metadata.rst +++ b/Documentation/filesystems/xfs-self-describing-metadata.rst @@ -1,4 +1,5 @@ .. SPDX-License-Identifier: GPL-2.0 +.. _xfs_self_describing_metadata: ============================ XFS Self Describing Metadata diff --git a/Documentation/fpga/index.rst b/Documentation/fpga/index.rst index f80f95667ca2..43c968871d99 100644 --- a/Documentation/fpga/index.rst +++ b/Documentation/fpga/index.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 ==== -fpga +FPGA ==== .. toctree:: diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst index 5202186728b4..2a22ddb1b848 100644 --- a/Documentation/kbuild/kbuild.rst +++ b/Documentation/kbuild/kbuild.rst @@ -160,7 +160,7 @@ directory name found in the arch/ directory. But some architectures such as x86 and sparc have aliases. - x86: i386 for 32 bit, x86_64 for 64 bit -- sh: sh for 32 bit, sh64 for 64 bit +- parisc: parisc64 for 64 bit - sparc: sparc32 for 32 bit, sparc64 for 64 bit CROSS_COMPILE diff --git a/Documentation/leds/index.rst b/Documentation/leds/index.rst index b9ca081fac71..ce57254cb871 100644 --- a/Documentation/leds/index.rst +++ b/Documentation/leds/index.rst @@ -25,5 +25,6 @@ LEDs leds-lp5562 leds-lp55xx leds-mlxcpld + leds-mt6370-rgb leds-sc27xx leds-qcom-lpg diff --git a/Documentation/leds/leds-mt6370-rgb.rst b/Documentation/leds/leds-mt6370-rgb.rst new file mode 100644 index 000000000000..152a2e592172 --- /dev/null +++ b/Documentation/leds/leds-mt6370-rgb.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================================= +The device for Mediatek MT6370 RGB LED +========================================= + +Description +----------- + +The MT6370 integrates a four-channel RGB LED driver, designed to provide a +variety of lighting effect for mobile device applications. The RGB LED devices +includes a smart LED string controller and it can drive 3 channels of LEDs with +a sink current up to 24mA and a CHG_VIN power good indicator LED with sink +current up to 6mA. It provides three operation modes for RGB LEDs: +PWM Dimming mode, breath pattern mode, and constant current mode. The device +can increase or decrease the brightness of the RGB LED via an I2C interface. + +The breath pattern for a channel can be programmed using the "pattern" trigger, +using the hw_pattern attribute. + +/sys/class/leds//hw_pattern +-------------------------------- + +Specify a hardware breath pattern for a MT6370 RGB LED. + +The breath pattern is a series of timing pairs, with the hold-time expressed in +milliseconds. And the brightness is controlled by +'/sys/class/leds//brightness'. The pattern doesn't include the brightness +setting. Hardware pattern only controls the timing for each pattern stage +depending on the current brightness setting. + +Pattern diagram:: + + "0 Tr1 0 Tr2 0 Tf1 0 Tf2 0 Ton 0 Toff" --> '0' for dummy brightness code + + ^ + | ============ + | / \ / + Icurr | / \ / + | / \ / + | / \ / .....repeat + | / \ / + | --- --- --- + |--- --- --- + +----------------------------------============------------> Time + < Tr1>< Ton >< Toff >< Tr1> + +Timing description: + + * Tr1: First rising time for 0% - 30% load. + * Tr2: Second rising time for 31% - 100% load. + * Ton: On time for 100% load. + * Tf1: First falling time for 100% - 31% load. + * Tf2: Second falling time for 30% to 0% load. + * Toff: Off time for 0% load. + + * Tr1/Tr2/Tf1/Tf2/Ton: 125ms to 3125ms, 200ms per step. + * Toff: 250ms to 6250ms, 400ms per step. + +Pattern example:: + + "0 125 0 125 0 125 0 125 0 625 0 1050" + +This Will configure Tr1/Tr2/Tf1/Tf2 to 125m, Ton to 625ms, and Toff to 1050ms. diff --git a/Documentation/leds/ledtrig-oneshot.rst b/Documentation/leds/ledtrig-oneshot.rst index 69fa3ea1d554..e044d69e9c0f 100644 --- a/Documentation/leds/ledtrig-oneshot.rst +++ b/Documentation/leds/ledtrig-oneshot.rst @@ -5,7 +5,7 @@ One-shot LED Trigger This is a LED trigger useful for signaling the user of an event where there are no clear trap points to put standard led-on and led-off settings. Using this trigger, the application needs only to signal the trigger when an event has -happened, than the trigger turns the LED on and than keeps it off for a +happened, then the trigger turns the LED on and then keeps it off for a specified amount of time. This trigger is meant to be usable both for sporadic and dense events. In the diff --git a/Documentation/livepatch/reliable-stacktrace.rst b/Documentation/livepatch/reliable-stacktrace.rst index 67459d2ca2af..d56bb706172f 100644 --- a/Documentation/livepatch/reliable-stacktrace.rst +++ b/Documentation/livepatch/reliable-stacktrace.rst @@ -183,7 +183,7 @@ trampoline or return trampoline. For example, considering the x86_64 .. code-block:: none SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED subq $24, %rsp /* Save the return values */ diff --git a/Documentation/locking/index.rst b/Documentation/locking/index.rst index 7003bd5aeff4..6a9ea96c8bcb 100644 --- a/Documentation/locking/index.rst +++ b/Documentation/locking/index.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 ======= -locking +Locking ======= .. toctree:: diff --git a/Documentation/mm/active_mm.rst b/Documentation/mm/active_mm.rst index 45d89f8fb3a8..d096fc091e23 100644 --- a/Documentation/mm/active_mm.rst +++ b/Documentation/mm/active_mm.rst @@ -2,6 +2,12 @@ Active MM ========= +Note, the mm_count refcount may no longer include the "lazy" users +(running tasks with ->active_mm == mm && ->mm == NULL) on kernels +with CONFIG_MMU_LAZY_TLB_REFCOUNT=n. Taking and releasing these lazy +references must be done with mmgrab_lazy_tlb() and mmdrop_lazy_tlb() +helpers, which abstract this config option. + :: List: linux-kernel diff --git a/Documentation/mm/arch_pgtable_helpers.rst b/Documentation/mm/arch_pgtable_helpers.rst index 30d9a09f01f4..af3891f895b0 100644 --- a/Documentation/mm/arch_pgtable_helpers.rst +++ b/Documentation/mm/arch_pgtable_helpers.rst @@ -214,7 +214,7 @@ HugeTLB Page Table Helpers +---------------------------+--------------------------------------------------+ | pte_huge | Tests a HugeTLB | +---------------------------+--------------------------------------------------+ -| pte_mkhuge | Creates a HugeTLB | +| arch_make_huge_pte | Creates a HugeTLB | +---------------------------+--------------------------------------------------+ | huge_pte_dirty | Tests a dirty HugeTLB | +---------------------------+--------------------------------------------------+ diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst index 5f1f6ecbb79b..52ed5092022f 100644 --- a/Documentation/mm/multigen_lru.rst +++ b/Documentation/mm/multigen_lru.rst @@ -103,7 +103,8 @@ moving across tiers only involves atomic operations on ``folio->flags`` and therefore has a negligible cost. A feedback loop modeled after the PID controller monitors refaults over all the tiers from anon and file types and decides which tiers from which types to -evict or protect. +evict or protect. The desired effect is to balance refault percentages +between anon and file types proportional to the swappiness level. There are two conceptually independent procedures: the aging and the eviction. They form a closed-loop system, i.e., the page reclaim. @@ -156,6 +157,27 @@ This time-based approach has the following advantages: and memory sizes. 2. It is more reliable because it is directly wired to the OOM killer. +``mm_struct`` list +------------------ +An ``mm_struct`` list is maintained for each memcg, and an +``mm_struct`` follows its owner task to the new memcg when this task +is migrated. + +A page table walker iterates ``lruvec_memcg()->mm_list`` and calls +``walk_page_range()`` with each ``mm_struct`` on this list to scan +PTEs. When multiple page table walkers iterate the same list, each of +them gets a unique ``mm_struct``, and therefore they can run in +parallel. + +Page table walkers ignore any misplaced pages, e.g., if an +``mm_struct`` was migrated, pages left in the previous memcg will be +ignored when the current memcg is under reclaim. Similarly, page table +walkers will ignore pages from nodes other than the one under reclaim. + +This infrastructure also tracks the usage of ``mm_struct`` between +context switches so that page table walkers can skip processes that +have been sleeping since the last iteration. + Rmap/PT walk feedback --------------------- Searching the rmap for PTEs mapping each page on an LRU list (to test @@ -170,7 +192,7 @@ promotes hot pages. If the scan was done cacheline efficiently, it adds the PMD entry pointing to the PTE table to the Bloom filter. This forms a feedback loop between the eviction and the aging. -Bloom Filters +Bloom filters ------------- Bloom filters are a space and memory efficient data structure for set membership test, i.e., test if an element is not in the set or may be @@ -186,6 +208,18 @@ is false positive, the cost is an additional scan of a range of PTEs, which may yield hot pages anyway. Parameters of the filter itself can control the false positive rate in the limit. +PID controller +-------------- +A feedback loop modeled after the Proportional-Integral-Derivative +(PID) controller monitors refaults over anon and file types and +decides which type to evict when both types are available from the +same generation. + +The PID controller uses generations rather than the wall clock as the +time domain because a CPU can scan pages at different rates under +varying memory pressure. It calculates a moving average for each new +generation to avoid being permanently locked in a suboptimal state. + Memcg LRU --------- An memcg LRU is a per-node LRU of memcgs. It is also an LRU of LRUs, @@ -223,9 +257,9 @@ parts: * Generations * Rmap walks -* Page table walks -* Bloom filters -* PID controller +* Page table walks via ``mm_struct`` list +* Bloom filters for rmap/PT walk feedback +* PID controller for refault feedback The aging and the eviction form a producer-consumer model; specifically, the latter drives the former by the sliding window over diff --git a/Documentation/mm/page_table_check.rst b/Documentation/mm/page_table_check.rst index cfd8f4117cf3..c12838ce6b8d 100644 --- a/Documentation/mm/page_table_check.rst +++ b/Documentation/mm/page_table_check.rst @@ -52,3 +52,22 @@ Build kernel with: Optionally, build kernel with PAGE_TABLE_CHECK_ENFORCED in order to have page table support without extra kernel parameter. + +Implementation notes +==================== + +We specifically decided not to use VMA information in order to avoid relying on +MM states (except for limited "struct page" info). The page table check is a +separate from Linux-MM state machine that verifies that the user accessible +pages are not falsely shared. + +PAGE_TABLE_CHECK depends on EXCLUSIVE_SYSTEM_RAM. The reason is that without +EXCLUSIVE_SYSTEM_RAM, users are allowed to map arbitrary physical memory +regions into the userspace via /dev/mem. At the same time, pages may change +their properties (e.g., from anonymous pages to named pages) while they are +still being mapped in the userspace, leading to "corruption" detected by the +page table check. + +Even with EXCLUSIVE_SYSTEM_RAM, I/O pages may be still allowed to be mapped via +/dev/mem. However, these pages are always considered as named pages, so they +won't break the logic used in the page table check. diff --git a/Documentation/mm/unevictable-lru.rst b/Documentation/mm/unevictable-lru.rst index 92ac5dca420c..d5ac8511eb67 100644 --- a/Documentation/mm/unevictable-lru.rst +++ b/Documentation/mm/unevictable-lru.rst @@ -42,6 +42,8 @@ The unevictable list addresses the following classes of unevictable pages: * Those owned by ramfs. + * Those owned by tmpfs with the noswap mount option. + * Those mapped into SHM_LOCK'd shared memory regions. * Those mapped into VM_LOCKED [mlock()ed] VMAs. diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 129f413ea349..3abc576ff797 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -60,22 +60,6 @@ attribute-sets: type: nest nested-attributes: bitset-bits - - - name: u64-array - attributes: - - - name: u64 - type: nest - multi-attr: true - nested-attributes: u64 - - - name: s32-array - attributes: - - - name: s32 - type: nest - multi-attr: true - nested-attributes: s32 - name: string attributes: @@ -705,16 +689,16 @@ attribute-sets: type: u8 - name: corrected - type: nest - nested-attributes: u64-array + type: binary + sub-type: u64 - name: uncorr - type: nest - nested-attributes: u64-array + type: binary + sub-type: u64 - name: corr-bits - type: nest - nested-attributes: u64-array + type: binary + sub-type: u64 - name: fec attributes: @@ -827,8 +811,8 @@ attribute-sets: type: u32 - name: index - type: nest - nested-attributes: s32-array + type: binary + sub-type: s32 - name: module attributes: diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml index 614f1a585511..6d89e30f5fd5 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -68,6 +68,9 @@ attribute-sets: type: nest nested-attributes: x509 multi-attr: true + - + name: peername + type: string - name: done attributes: @@ -105,6 +108,7 @@ operations: - auth-mode - peer-identity - certificate + - peername - name: done doc: Handler reports handshake completion diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index adc4bf4f3c50..28925e19622d 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -776,10 +776,11 @@ peer_notif_delay Specify the delay, in milliseconds, between each peer notification (gratuitous ARP and unsolicited IPv6 Neighbor Advertisement) when they are issued after a failover event. - This delay should be a multiple of the link monitor interval - (arp_interval or miimon, whichever is active). The default - value is 0 which means to match the value of the link monitor - interval. + This delay should be a multiple of the MII link monitor interval + (miimon). + + The valid range is 0 - 300000. The default value is 0, which means + to match the value of the MII link monitor interval. prio Slave priority. A higher number means higher priority. diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst index 3a7a714cc08f..3354ca3608ee 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst @@ -40,6 +40,7 @@ flow_steering_mode: Device flow steering mode --------------------------------------------- The flow steering mode parameter controls the flow steering mode of the driver. Two modes are supported: + 1. 'dmfs' - Device managed flow steering. 2. 'smfs' - Software/Driver managed flow steering. @@ -99,6 +100,7 @@ between representors and stacked devices. By default metadata is enabled on the supported devices in E-switch. Metadata is applicable only for E-switch in switchdev mode and users may disable it when NONE of the below use cases will be in use: + 1. HCA is in Dual/multi-port RoCE mode. 2. VF/SF representor bonding (Usually used for Live migration) 3. Stacked devices @@ -180,7 +182,8 @@ User commands examples: $ devlink health diagnose pci/0000:82:00.0 reporter tx -NOTE: This command has valid output only when interface is up, otherwise the command has empty output. +.. note:: + This command has valid output only when interface is up, otherwise the command has empty output. - Show number of tx errors indicated, number of recover flows ended successfully, is autorecover enabled and graceful period from last recover:: @@ -232,8 +235,9 @@ User commands examples: $ devlink health dump show pci/0000:82:00.0 reporter fw -NOTE: This command can run only on the PF which has fw tracer ownership, -running it on other PF or any VF will return "Operation not permitted". +.. note:: + This command can run only on the PF which has fw tracer ownership, + running it on other PF or any VF will return "Operation not permitted". fw fatal reporter ----------------- @@ -256,7 +260,8 @@ User commands examples: $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal -NOTE: This command can run only on PF. +.. note:: + This command can run only on PF. vnic reporter ------------- @@ -265,28 +270,37 @@ It is responsible for querying the vnic diagnostic counters from fw and displayi them in realtime. Description of the vnic counters: -total_q_under_processor_handle: number of queues in an error state due to -an async error or errored command. -send_queue_priority_update_flow: number of QP/SQ priority/SL update -events. -cq_overrun: number of times CQ entered an error state due to an -overflow. -async_eq_overrun: number of times an EQ mapped to async events was -overrun. -comp_eq_overrun: number of times an EQ mapped to completion events was -overrun. -quota_exceeded_command: number of commands issued and failed due to quota -exceeded. -invalid_command: number of commands issued and failed dues to any reason -other than quota exceeded. -nic_receive_steering_discard: number of packets that completed RX flow -steering but were discarded due to a mismatch in flow table. + +- total_q_under_processor_handle + number of queues in an error state due to + an async error or errored command. +- send_queue_priority_update_flow + number of QP/SQ priority/SL update events. +- cq_overrun + number of times CQ entered an error state due to an overflow. +- async_eq_overrun + number of times an EQ mapped to async events was overrun. + comp_eq_overrun number of times an EQ mapped to completion events was + overrun. +- quota_exceeded_command + number of commands issued and failed due to quota exceeded. +- invalid_command + number of commands issued and failed dues to any reason other than quota + exceeded. +- nic_receive_steering_discard + number of packets that completed RX flow + steering but were discarded due to a mismatch in flow table. User commands examples: -- Diagnose PF/VF vnic counters + +- Diagnose PF/VF vnic counters:: + $ devlink health diagnose pci/0000:82:00.1 reporter vnic + - Diagnose representor vnic counters (performed by supplying devlink port of the - representor, which can be obtained via devlink port command) + representor, which can be obtained via devlink port command):: + $ devlink health diagnose pci/0000:82:00.1/65537 reporter vnic -NOTE: This command can run over all interfaces such as PF/VF and representor ports. +.. note:: + This command can run over all interfaces such as PF/VF and representor ports. diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index a164ff074356..5b75c3f7a137 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -116,8 +116,8 @@ Contents: udplite vrf vxlan - x25-iface x25 + x25-iface xfrm_device xfrm_proc xfrm_sync diff --git a/Documentation/networking/tls-handshake.rst b/Documentation/networking/tls-handshake.rst index a2817a88e905..6f5ea1646a47 100644 --- a/Documentation/networking/tls-handshake.rst +++ b/Documentation/networking/tls-handshake.rst @@ -53,6 +53,7 @@ fills in a structure that contains the parameters of the request: struct socket *ta_sock; tls_done_func_t ta_done; void *ta_data; + const char *ta_peername; unsigned int ta_timeout_ms; key_serial_t ta_keyring; key_serial_t ta_my_cert; @@ -71,6 +72,10 @@ instantiated a struct file in sock->file. has completed. Further explanation of this function is in the "Handshake Completion" sesction below. +The consumer can provide a NUL-terminated hostname in the @ta_peername +field that is sent as part of ClientHello. If no peername is provided, +the DNS hostname associated with the server's IP address is used instead. + The consumer can fill in the @ta_timeout_ms field to force the servicing handshake agent to exit after a number of milliseconds. This enables the socket to be fully closed once both the kernel and the handshake agent diff --git a/Documentation/networking/x25-iface.rst b/Documentation/networking/x25-iface.rst index f34e9ec64937..285cefcfce87 100644 --- a/Documentation/networking/x25-iface.rst +++ b/Documentation/networking/x25-iface.rst @@ -1,8 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 -============================- X.25 Device Driver Interface -============================- +============================ Version 1.1 diff --git a/Documentation/pcmcia/index.rst b/Documentation/pcmcia/index.rst index 7ae1f62fca14..8067236c51ab 100644 --- a/Documentation/pcmcia/index.rst +++ b/Documentation/pcmcia/index.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 ====== -pcmcia +PCMCIA ====== .. toctree:: diff --git a/Documentation/power/regulator/consumer.rst b/Documentation/power/regulator/consumer.rst index 0cd8cc1275a7..85c2bf5ac07e 100644 --- a/Documentation/power/regulator/consumer.rst +++ b/Documentation/power/regulator/consumer.rst @@ -41,7 +41,7 @@ A consumer can enable its power supply by calling:: int regulator_enable(regulator); NOTE: - The supply may already be enabled before regulator_enabled() is called. + The supply may already be enabled before regulator_enable() is called. This may happen if the consumer shares the regulator or the regulator has been previously enabled by bootloader or kernel board initialization code. diff --git a/Documentation/process/5.Posting.rst b/Documentation/process/5.Posting.rst index 7a670a075ab6..de4edd42d5c0 100644 --- a/Documentation/process/5.Posting.rst +++ b/Documentation/process/5.Posting.rst @@ -207,8 +207,8 @@ the patch:: Fixes: 1f2e3d4c5b6a ("The first line of the commit specified by the first 12 characters of its SHA-1 ID") Another tag is used for linking web pages with additional backgrounds or -details, for example a report about a bug fixed by the patch or a document -with a specification implemented by the patch:: +details, for example an earlier discussion which leads to the patch or a +document with a specification implemented by the patch:: Link: https://example.com/somewhere.html optional-other-stuff @@ -217,7 +217,17 @@ latest public review posting of the patch; often this is automatically done by tools like b4 or a git hook like the one described in 'Documentation/maintainer/configure-git.rst'. -A third kind of tag is used to document who was involved in the development of +If the URL points to a public bug report being fixed by the patch, use the +"Closes:" tag instead:: + + Closes: https://example.com/issues/1234 optional-other-stuff + +Some bug trackers have the ability to close issues automatically when a +commit with such a tag is applied. Some bots monitoring mailing lists can +also track such tags and take certain actions. Private bug trackers and +invalid URLs are forbidden. + +Another kind of tag is used to document who was involved in the development of the patch. Each of these uses this format:: tag: Full Name optional-other-stuff @@ -251,8 +261,10 @@ The tags in common use are: - Reported-by: names a user who reported a problem which is fixed by this patch; this tag is used to give credit to the (often underappreciated) people who test our code and let us know when things do not work - correctly. Note, this tag should be followed by a Link: tag pointing to the - report, unless the report is not available on the web. + correctly. Note, this tag should be followed by a Closes: tag pointing to + the report, unless the report is not available on the web. The Link: tag + can be used instead of Closes: if the patch fixes a part of the issue(s) + being reported. - Cc: the named person received a copy of the patch and had the opportunity to comment on it. diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index 64b5948fc1d4..7029c3c084ee 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -72,7 +72,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst index f73ac9e175a8..83614cec9328 100644 --- a/Documentation/process/maintainer-netdev.rst +++ b/Documentation/process/maintainer-netdev.rst @@ -127,13 +127,32 @@ the value of ``Message-ID`` to the URL above. Updating patch status ~~~~~~~~~~~~~~~~~~~~~ -It may be tempting to help the maintainers and update the state of your -own patches when you post a new version or spot a bug. Please **do not** -do that. -Interfering with the patch status on patchwork will only cause confusion. Leave -it to the maintainer to figure out what is the most recent and current -version that should be applied. If there is any doubt, the maintainer -will reply and ask what should be done. +Contributors and reviewers do not have the permissions to update patch +state directly in patchwork. Patchwork doesn't expose much information +about the history of the state of patches, therefore having multiple +people update the state leads to confusion. + +Instead of delegating patchwork permissions netdev uses a simple mail +bot which looks for special commands/lines within the emails sent to +the mailing list. For example to mark a series as Changes Requested +one needs to send the following line anywhere in the email thread:: + + pw-bot: changes-requested + +As a result the bot will set the entire series to Changes Requested. +This may be useful when author discovers a bug in their own series +and wants to prevent it from getting applied. + +The use of the bot is entirely optional, if in doubt ignore its existence +completely. Maintainers will classify and update the state of the patches +themselves. No email should ever be sent to the list with the main purpose +of communicating with the bot, the bot commands should be seen as metadata. + +The use of the bot is restricted to authors of the patches (the ``From:`` +header on patch submission and command must match!), maintainers themselves +and a handful of senior reviewers. Bot records its activity here: + + https://patchwork.hopto.org/pw-bot.html Review timelines ~~~~~~~~~~~~~~~~ diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index 7a5619fecb38..486875fd73c0 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -113,11 +113,9 @@ there is no collision with your six-character ID now, that condition may change five years from now. If related discussions or any other background information behind the change -can be found on the web, add 'Link:' tags pointing to it. In case your patch -fixes a bug, for example, add a tag with a URL referencing the report in the -mailing list archives or a bug tracker; if the patch is a result of some -earlier mailing list discussion or something documented on the web, point to -it. +can be found on the web, add 'Link:' tags pointing to it. If the patch is a +result of some earlier mailing list discussions or something documented on the +web, point to it. When linking to mailing list archives, preferably use the lore.kernel.org message archiver service. To create the link URL, use the contents of the @@ -134,6 +132,16 @@ resources. In addition to giving a URL to a mailing list archive or bug, summarize the relevant points of the discussion that led to the patch as submitted. +In case your patch fixes a bug, use the 'Closes:' tag with a URL referencing +the report in the mailing list archives or a public bug tracker. For example:: + + Closes: https://example.com/issues/1234 + +Some bug trackers have the ability to close issues automatically when a +commit with such a tag is applied. Some bots monitoring mailing lists can +also track such tags and take certain actions. Private bug trackers and +invalid URLs are forbidden. + If your patch fixes a bug in a specific commit, e.g. you found an issue using ``git bisect``, please use the 'Fixes:' tag with the first 12 characters of the SHA-1 ID, and the one line summary. Do not split the tag across multiple @@ -495,9 +503,11 @@ Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: The Reported-by tag gives credit to people who find bugs and report them and it hopefully inspires them to help us again in the future. The tag is intended for bugs; please do not use it to credit feature requests. The tag should be -followed by a Link: tag pointing to the report, unless the report is not -available on the web. Please note that if the bug was reported in private, then -ask for permission first before using the Reported-by tag. +followed by a Closes: tag pointing to the report, unless the report is not +available on the web. The Link: tag can be used instead of Closes: if the patch +fixes a part of the issue(s) being reported. Please note that if the bug was +reported in private, then ask for permission first before using the Reported-by +tag. A Tested-by: tag indicates that the patch has been successfully tested (in some environment) by the person named. This tag informs maintainers that diff --git a/Documentation/riscv/hwprobe.rst b/Documentation/riscv/hwprobe.rst new file mode 100644 index 000000000000..9f0dd62dcb5d --- /dev/null +++ b/Documentation/riscv/hwprobe.rst @@ -0,0 +1,86 @@ +.. SPDX-License-Identifier: GPL-2.0 + +RISC-V Hardware Probing Interface +--------------------------------- + +The RISC-V hardware probing interface is based around a single syscall, which +is defined in :: + + struct riscv_hwprobe { + __s64 key; + __u64 value; + }; + + long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, cpu_set_t *cpus, + unsigned int flags); + +The arguments are split into three groups: an array of key-value pairs, a CPU +set, and some flags. The key-value pairs are supplied with a count. Userspace +must prepopulate the key field for each element, and the kernel will fill in the +value if the key is recognized. If a key is unknown to the kernel, its key field +will be cleared to -1, and its value set to 0. The CPU set is defined by +CPU_SET(3). For value-like keys (eg. vendor/arch/impl), the returned value will +be only be valid if all CPUs in the given set have the same value. Otherwise -1 +will be returned. For boolean-like keys, the value returned will be a logical +AND of the values for the specified CPUs. Usermode can supply NULL for cpus and +0 for cpu_count as a shortcut for all online CPUs. There are currently no flags, +this value must be zero for future compatibility. + +On success 0 is returned, on failure a negative error code is returned. + +The following keys are defined: + +* :c:macro:`RISCV_HWPROBE_KEY_MVENDORID`: Contains the value of ``mvendorid``, + as defined by the RISC-V privileged architecture specification. + +* :c:macro:`RISCV_HWPROBE_KEY_MARCHID`: Contains the value of ``marchid``, as + defined by the RISC-V privileged architecture specification. + +* :c:macro:`RISCV_HWPROBE_KEY_MIMPLID`: Contains the value of ``mimplid``, as + defined by the RISC-V privileged architecture specification. + +* :c:macro:`RISCV_HWPROBE_KEY_BASE_BEHAVIOR`: A bitmask containing the base + user-visible behavior that this kernel supports. The following base user ABIs + are defined: + + * :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: Support for rv32ima or + rv64ima, as defined by version 2.2 of the user ISA and version 1.10 of the + privileged ISA, with the following known exceptions (more exceptions may be + added, but only if it can be demonstrated that the user ABI is not broken): + + * The :fence.i: instruction cannot be directly executed by userspace + programs (it may still be executed in userspace via a + kernel-controlled mechanism such as the vDSO). + +* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing the extensions + that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: + base system behavior. + + * :c:macro:`RISCV_HWPROBE_IMA_FD`: The F and D extensions are supported, as + defined by commit cd20cee ("FMIN/FMAX now implement + minimumNumber/maximumNumber, not minNum/maxNum") of the RISC-V ISA manual. + + * :c:macro:`RISCV_HWPROBE_IMA_C`: The C extension is supported, as defined + by version 2.2 of the RISC-V ISA manual. + +* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance + information about the selected set of processors. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNKNOWN`: The performance of misaligned + accesses is unknown. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_EMULATED`: Misaligned accesses are + emulated via software, either in or below the kernel. These accesses are + always extremely slow. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_SLOW`: Misaligned accesses are supported + in hardware, but are slower than the cooresponding aligned accesses + sequences. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_FAST`: Misaligned accesses are supported + in hardware and are faster than the cooresponding aligned accesses + sequences. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNSUPPORTED`: Misaligned accesses are + not supported at all and will generate a misaligned address fault. diff --git a/Documentation/riscv/index.rst b/Documentation/riscv/index.rst index 2e5b18fbb145..175a91db0200 100644 --- a/Documentation/riscv/index.rst +++ b/Documentation/riscv/index.rst @@ -7,6 +7,7 @@ RISC-V architecture boot-image-header vm-layout + hwprobe patch-acceptance uabi diff --git a/Documentation/s390/vfio-ap.rst b/Documentation/s390/vfio-ap.rst index d46e98c7c1ec..bb3f4c4e2885 100644 --- a/Documentation/s390/vfio-ap.rst +++ b/Documentation/s390/vfio-ap.rst @@ -551,7 +551,6 @@ These are the steps: * IOMMU_SUPPORT * S390 * ZCRYPT - * S390_AP_IOMMU * VFIO * KVM diff --git a/Documentation/scheduler/sched-arch.rst b/Documentation/scheduler/sched-arch.rst index 0eaec669790a..505cd27f9a92 100644 --- a/Documentation/scheduler/sched-arch.rst +++ b/Documentation/scheduler/sched-arch.rst @@ -70,7 +70,5 @@ Possible arch problems I found (and either tried to fix or didn't): ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a) -sh64 - Is sleeping racy vs interrupts? (See #4a) - sparc - IRQs on at this point(?), change local_irq_save to _disable. - TODO: needs secondary CPUs to disable preempt (See #1) diff --git a/Documentation/security/lsm-development.rst b/Documentation/security/lsm-development.rst index ac53e5065f79..5895e529da7f 100644 --- a/Documentation/security/lsm-development.rst +++ b/Documentation/security/lsm-development.rst @@ -11,7 +11,7 @@ that end users and distros can make a more informed decision about which LSMs suit their requirements. For extensive documentation on the available LSM hook interfaces, please -see ``include/linux/lsm_hooks.h`` and associated structures: +see ``security/security.c`` and associated structures: -.. kernel-doc:: include/linux/lsm_hooks.h - :internal: +.. kernel-doc:: security/security.c + :export: diff --git a/Documentation/security/lsm.rst b/Documentation/security/lsm.rst index 6a2a2e973080..c20c7c72e2d6 100644 --- a/Documentation/security/lsm.rst +++ b/Documentation/security/lsm.rst @@ -98,7 +98,7 @@ associate these values with real security attributes. LSM hooks are maintained in lists. A list is maintained for each hook, and the hooks are called in the order specified by CONFIG_LSM. Detailed documentation for each hook is -included in the `include/linux/lsm_hooks.h` header file. +included in the `security/security.c` source file. The LSM framework provides for a close approximation of general security module stacking. It defines diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index af71c68f1e4e..829c672d9fe6 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -133,6 +133,19 @@ enable enable card; Default: enabled, for PCI and ISA PnP cards +These options are used for either specifying the order of instances or +controlling enabling and disabling of each one of the devices if there +are multiple devices bound with the same driver. For example, there are +many machines which have two HD-audio controllers (one for HDMI/DP +audio and another for onboard analog). In most cases, the second one is +in primary usage, and people would like to assign it as the first +appearing card. They can do it by specifying "index=1,0" module +parameter, which will swap the assignment slots. + +Today, with the sound backend like PulseAudio and PipeWire which +supports dynamic configuration, it's of little use, but that was a +help for static configuration in the past. + Module snd-adlib ---------------- diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index c0f97b5e4249..4335c98b3d82 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3994,21 +3994,21 @@ Driver with A Single Source File Suppose you have a file xyz.c. Add the following two lines:: - snd-xyz-objs := xyz.o - obj-$(CONFIG_SND_XYZ) += snd-xyz.o + snd-xyz-objs := xyz.o + obj-$(CONFIG_SND_XYZ) += snd-xyz.o 2. Create the Kconfig entry Add the new entry of Kconfig for your xyz driver:: - config SND_XYZ - tristate "Foobar XYZ" - depends on SND - select SND_PCM - help - Say Y here to include support for Foobar XYZ soundcard. - To compile this driver as a module, choose M here: - the module will be called snd-xyz. + config SND_XYZ + tristate "Foobar XYZ" + depends on SND + select SND_PCM + help + Say Y here to include support for Foobar XYZ soundcard. + To compile this driver as a module, choose M here: + the module will be called snd-xyz. The line ``select SND_PCM`` specifies that the driver xyz supports PCM. In addition to SND_PCM, the following components are supported for @@ -4032,7 +4032,7 @@ located in the new subdirectory, sound/pci/xyz. 1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile`` as below:: - obj-$(CONFIG_SND) += sound/pci/xyz/ + obj-$(CONFIG_SND) += sound/pci/xyz/ 2. Under the directory ``sound/pci/xyz``, create a Makefile:: diff --git a/Documentation/staging/crc32.rst b/Documentation/staging/crc32.rst index 8a6860f33b4e..7542220967cb 100644 --- a/Documentation/staging/crc32.rst +++ b/Documentation/staging/crc32.rst @@ -1,5 +1,5 @@ ================================= -brief tutorial on CRC computation +Brief tutorial on CRC computation ================================= A CRC is a long-division remainder. You add the CRC to the message, diff --git a/Documentation/timers/hrtimers.rst b/Documentation/timers/hrtimers.rst index 7ac448908d1f..f88ff8bae89c 100644 --- a/Documentation/timers/hrtimers.rst +++ b/Documentation/timers/hrtimers.rst @@ -123,17 +123,12 @@ equivalent to timer_delete() and timer_delete_sync()] - so there's no direct potential for code sharing either. Basic data types: every time value, absolute or relative, is in a -special nanosecond-resolution type: ktime_t. The kernel-internal -representation of ktime_t values and operations is implemented via -macros and inline functions, and can be switched between a "hybrid -union" type and a plain "scalar" 64bit nanoseconds representation (at -compile time). The hybrid union type optimizes time conversions on 32bit -CPUs. This build-time-selectable ktime_t storage format was implemented -to avoid the performance impact of 64-bit multiplications and divisions -on 32bit CPUs. Such operations are frequently necessary to convert -between the storage formats provided by kernel and userspace interfaces -and the internal time format. (See include/linux/ktime.h for further -details.) +special nanosecond-resolution 64bit type: ktime_t. +(Originally, the kernel-internal representation of ktime_t values and +operations was implemented via macros and inline functions, and could be +switched between a "hybrid union" type and a plain "scalar" 64bit +nanoseconds representation (at compile time). This was abandoned in the +context of the Y2038 work.) hrtimers - rounding of timer values ----------------------------------- @@ -148,7 +143,7 @@ a given clock has - be it low-res, high-res, or artificially-low-res. hrtimers - testing and verification ----------------------------------- -We used the high-resolution clock subsystem ontop of hrtimers to verify +We used the high-resolution clock subsystem on top of hrtimers to verify the hrtimer implementation details in praxis, and we also ran the posix timer tests in order to ensure specification compliance. We also ran tests on low-resolution clocks. diff --git a/Documentation/timers/index.rst b/Documentation/timers/index.rst index df510ad0c989..983f91f8f023 100644 --- a/Documentation/timers/index.rst +++ b/Documentation/timers/index.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 ====== -timers +Timers ====== .. toctree:: diff --git a/Documentation/tools/rtla/common_timerlat_aa.rst b/Documentation/tools/rtla/common_timerlat_aa.rst index 077029e6b289..795b9fbcbc6d 100644 --- a/Documentation/tools/rtla/common_timerlat_aa.rst +++ b/Documentation/tools/rtla/common_timerlat_aa.rst @@ -5,3 +5,10 @@ **--no-aa** disable auto-analysis, reducing rtla timerlat cpu usage + +**--aa-only** *us* + + Set stop tracing conditions and run without collecting and displaying statistics. + Print the auto-analysis if the system hits the stop tracing condition. This option + is useful to reduce rtla timerlat CPU, enabling the debug without the overhead of + collecting the statistics. diff --git a/Documentation/trace/fprobe.rst b/Documentation/trace/fprobe.rst index b64bec1ce144..40dd2fbce861 100644 --- a/Documentation/trace/fprobe.rst +++ b/Documentation/trace/fprobe.rst @@ -87,14 +87,16 @@ returns as same as unregister_ftrace_function(). The fprobe entry/exit handler ============================= -The prototype of the entry/exit callback function is as follows: +The prototype of the entry/exit callback function are as follows: .. code-block:: c - void callback_func(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs); + int entry_callback(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs, void *entry_data); -Note that both entry and exit callbacks have same ptototype. The @entry_ip is -saved at function entry and passed to exit handler. + void exit_callback(struct fprobe *fp, unsigned long entry_ip, struct pt_regs *regs, void *entry_data); + +Note that the @entry_ip is saved at function entry and passed to exit handler. +If the entry callback function returns !0, the corresponding exit callback will be cancelled. @fp This is the address of `fprobe` data structure related to this handler. @@ -113,6 +115,12 @@ saved at function entry and passed to exit handler. to use @entry_ip. On the other hand, in the exit_handler, the instruction pointer of @regs is set to the currect return address. +@entry_data + This is a local storage to share the data between entry and exit handlers. + This storage is NULL by default. If the user specify `exit_handler` field + and `entry_data_size` field when registering the fprobe, the storage is + allocated and passed to both `entry_handler` and `exit_handler`. + Share the callbacks with kprobes ================================ diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index e8bca5fea7cc..027437b745a0 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -350,6 +350,19 @@ of ftrace. Here is a list of some of the key files: an 'I' will be displayed on the same line as the function that can be overridden. + If a non ftrace trampoline is attached (BPF) a 'D' will be displayed. + Note, normal ftrace trampolines can also be attached, but only one + "direct" trampoline can be attached to a given function at a time. + + Some architectures can not call direct trampolines, but instead have + the ftrace ops function located above the function entry point. In + such cases an 'O' will be displayed. + + If a function had either the "ip modify" or a "direct" call attached to + it in the past, a 'M' will be shown. This flag is never cleared. It is + used to know if a function was every modified by the ftrace infrastructure, + and can be used for debugging. + If the architecture supports it, it will also show what callback is being directly called by the function. If the count is greater than 1 it most likely will be ftrace_ops_list_func(). @@ -359,6 +372,18 @@ of ftrace. Here is a list of some of the key files: its address will be printed as well as the function that the trampoline calls. + touched_functions: + + This file contains all the functions that ever had a function callback + to it via the ftrace infrastructure. It has the same format as + enabled_functions but shows all functions that have every been + traced. + + To see any function that has every been modified by "ip modify" or a + direct trampoline, one can perform the following command: + + grep ' M ' /sys/kernel/tracing/touched_functions + function_profile_enabled: When set it will enable all functions with either the function @@ -1027,6 +1052,7 @@ To see what is available, simply cat the file:: nohex nobin noblock + nofields trace_printk annotate nouserstacktrace @@ -1110,6 +1136,11 @@ Here are the available options: block When set, reading trace_pipe will not block when polled. + fields + Print the fields as described by their types. This is a better + option than using hex, bin or raw, as it gives a better parsing + of the content of the event. + trace_printk Can disable trace_printk() from writing into the buffer. diff --git a/Documentation/trace/histogram.rst b/Documentation/trace/histogram.rst index 479c9eac6335..3c9b263de9c2 100644 --- a/Documentation/trace/histogram.rst +++ b/Documentation/trace/histogram.rst @@ -35,7 +35,7 @@ Documentation written by Tom Zanussi in place of an explicit value field - this is simply a count of event hits. If 'values' isn't specified, an implicit 'hitcount' value will be automatically created and used as the only value. - Keys can be any field, or the special string 'stacktrace', which + Keys can be any field, or the special string 'common_stacktrace', which will use the event's kernel stacktrace as the key. The keywords 'keys' or 'key' can be used to specify keys, and the keywords 'values', 'vals', or 'val' can be used to specify values. Compound @@ -54,7 +54,7 @@ Documentation written by Tom Zanussi 'compatible' if the fields named in the trigger share the same number and type of fields and those fields also have the same names. Note that any two events always share the compatible 'hitcount' and - 'stacktrace' fields and can therefore be combined using those + 'common_stacktrace' fields and can therefore be combined using those fields, however pointless that may be. 'hist' triggers add a 'hist' file to each event's subdirectory. @@ -547,9 +547,9 @@ Extended error information the hist trigger display symbolic call_sites, we can have the hist trigger additionally display the complete set of kernel stack traces that led to each call_site. To do that, we simply use the special - value 'stacktrace' for the key parameter:: + value 'common_stacktrace' for the key parameter:: - # echo 'hist:keys=stacktrace:values=bytes_req,bytes_alloc:sort=bytes_alloc' > \ + # echo 'hist:keys=common_stacktrace:values=bytes_req,bytes_alloc:sort=bytes_alloc' > \ /sys/kernel/tracing/events/kmem/kmalloc/trigger The above trigger will use the kernel stack trace in effect when an @@ -561,9 +561,9 @@ Extended error information every callpath to a kmalloc for a kernel compile):: # cat /sys/kernel/tracing/events/kmem/kmalloc/hist - # trigger info: hist:keys=stacktrace:vals=bytes_req,bytes_alloc:sort=bytes_alloc:size=2048 [active] + # trigger info: hist:keys=common_stacktrace:vals=bytes_req,bytes_alloc:sort=bytes_alloc:size=2048 [active] - { stacktrace: + { common_stacktrace: __kmalloc_track_caller+0x10b/0x1a0 kmemdup+0x20/0x50 hidraw_report_event+0x8a/0x120 [hid] @@ -581,7 +581,7 @@ Extended error information cpu_startup_entry+0x315/0x3e0 rest_init+0x7c/0x80 } hitcount: 3 bytes_req: 21 bytes_alloc: 24 - { stacktrace: + { common_stacktrace: __kmalloc_track_caller+0x10b/0x1a0 kmemdup+0x20/0x50 hidraw_report_event+0x8a/0x120 [hid] @@ -596,7 +596,7 @@ Extended error information do_IRQ+0x5a/0xf0 ret_from_intr+0x0/0x30 } hitcount: 3 bytes_req: 21 bytes_alloc: 24 - { stacktrace: + { common_stacktrace: kmem_cache_alloc_trace+0xeb/0x150 aa_alloc_task_context+0x27/0x40 apparmor_cred_prepare+0x1f/0x50 @@ -608,7 +608,7 @@ Extended error information . . . - { stacktrace: + { common_stacktrace: __kmalloc+0x11b/0x1b0 i915_gem_execbuffer2+0x6c/0x2c0 [i915] drm_ioctl+0x349/0x670 [drm] @@ -616,7 +616,7 @@ Extended error information SyS_ioctl+0x81/0xa0 system_call_fastpath+0x12/0x6a } hitcount: 17726 bytes_req: 13944120 bytes_alloc: 19593808 - { stacktrace: + { common_stacktrace: __kmalloc+0x11b/0x1b0 load_elf_phdrs+0x76/0xa0 load_elf_binary+0x102/0x1650 @@ -625,7 +625,7 @@ Extended error information SyS_execve+0x3a/0x50 return_from_execve+0x0/0x23 } hitcount: 33348 bytes_req: 17152128 bytes_alloc: 20226048 - { stacktrace: + { common_stacktrace: kmem_cache_alloc_trace+0xeb/0x150 apparmor_file_alloc_security+0x27/0x40 security_file_alloc+0x16/0x20 @@ -636,7 +636,7 @@ Extended error information SyS_open+0x1e/0x20 system_call_fastpath+0x12/0x6a } hitcount: 4766422 bytes_req: 9532844 bytes_alloc: 38131376 - { stacktrace: + { common_stacktrace: __kmalloc+0x11b/0x1b0 seq_buf_alloc+0x1b/0x50 seq_read+0x2cc/0x370 @@ -1026,7 +1026,7 @@ Extended error information First we set up an initially paused stacktrace trigger on the netif_receive_skb event:: - # echo 'hist:key=stacktrace:vals=len:pause' > \ + # echo 'hist:key=common_stacktrace:vals=len:pause' > \ /sys/kernel/tracing/events/net/netif_receive_skb/trigger Next, we set up an 'enable_hist' trigger on the sched_process_exec @@ -1060,9 +1060,9 @@ Extended error information $ wget https://www.kernel.org/pub/linux/kernel/v3.x/patch-3.19.xz # cat /sys/kernel/tracing/events/net/netif_receive_skb/hist - # trigger info: hist:keys=stacktrace:vals=len:sort=hitcount:size=2048 [paused] + # trigger info: hist:keys=common_stacktrace:vals=len:sort=hitcount:size=2048 [paused] - { stacktrace: + { common_stacktrace: __netif_receive_skb_core+0x46d/0x990 __netif_receive_skb+0x18/0x60 netif_receive_skb_internal+0x23/0x90 @@ -1079,7 +1079,7 @@ Extended error information kthread+0xd2/0xf0 ret_from_fork+0x42/0x70 } hitcount: 85 len: 28884 - { stacktrace: + { common_stacktrace: __netif_receive_skb_core+0x46d/0x990 __netif_receive_skb+0x18/0x60 netif_receive_skb_internal+0x23/0x90 @@ -1097,7 +1097,7 @@ Extended error information irq_thread+0x11f/0x150 kthread+0xd2/0xf0 } hitcount: 98 len: 664329 - { stacktrace: + { common_stacktrace: __netif_receive_skb_core+0x46d/0x990 __netif_receive_skb+0x18/0x60 process_backlog+0xa8/0x150 @@ -1115,7 +1115,7 @@ Extended error information inet_sendmsg+0x64/0xa0 sock_sendmsg+0x3d/0x50 } hitcount: 115 len: 13030 - { stacktrace: + { common_stacktrace: __netif_receive_skb_core+0x46d/0x990 __netif_receive_skb+0x18/0x60 netif_receive_skb_internal+0x23/0x90 @@ -1142,14 +1142,14 @@ Extended error information into the histogram. In order to avoid having to set everything up again, we can just clear the histogram first:: - # echo 'hist:key=stacktrace:vals=len:clear' >> \ + # echo 'hist:key=common_stacktrace:vals=len:clear' >> \ /sys/kernel/tracing/events/net/netif_receive_skb/trigger Just to verify that it is in fact cleared, here's what we now see in the hist file:: # cat /sys/kernel/tracing/events/net/netif_receive_skb/hist - # trigger info: hist:keys=stacktrace:vals=len:sort=hitcount:size=2048 [paused] + # trigger info: hist:keys=common_stacktrace:vals=len:sort=hitcount:size=2048 [paused] Totals: Hits: 0 @@ -1485,12 +1485,12 @@ Extended error information And here's an example that shows how to combine histogram data from any two events even if they don't share any 'compatible' fields - other than 'hitcount' and 'stacktrace'. These commands create a + other than 'hitcount' and 'common_stacktrace'. These commands create a couple of triggers named 'bar' using those fields:: - # echo 'hist:name=bar:key=stacktrace:val=hitcount' > \ + # echo 'hist:name=bar:key=common_stacktrace:val=hitcount' > \ /sys/kernel/tracing/events/sched/sched_process_fork/trigger - # echo 'hist:name=bar:key=stacktrace:val=hitcount' > \ + # echo 'hist:name=bar:key=common_stacktrace:val=hitcount' > \ /sys/kernel/tracing/events/net/netif_rx/trigger And displaying the output of either shows some interesting if @@ -1501,16 +1501,16 @@ Extended error information # event histogram # - # trigger info: hist:name=bar:keys=stacktrace:vals=hitcount:sort=hitcount:size=2048 [active] + # trigger info: hist:name=bar:keys=common_stacktrace:vals=hitcount:sort=hitcount:size=2048 [active] # - { stacktrace: + { common_stacktrace: kernel_clone+0x18e/0x330 kernel_thread+0x29/0x30 kthreadd+0x154/0x1b0 ret_from_fork+0x3f/0x70 } hitcount: 1 - { stacktrace: + { common_stacktrace: netif_rx_internal+0xb2/0xd0 netif_rx_ni+0x20/0x70 dev_loopback_xmit+0xaa/0xd0 @@ -1528,7 +1528,7 @@ Extended error information call_cpuidle+0x3b/0x60 cpu_startup_entry+0x22d/0x310 } hitcount: 1 - { stacktrace: + { common_stacktrace: netif_rx_internal+0xb2/0xd0 netif_rx_ni+0x20/0x70 dev_loopback_xmit+0xaa/0xd0 @@ -1543,7 +1543,7 @@ Extended error information SyS_sendto+0xe/0x10 entry_SYSCALL_64_fastpath+0x12/0x6a } hitcount: 2 - { stacktrace: + { common_stacktrace: netif_rx_internal+0xb2/0xd0 netif_rx+0x1c/0x60 loopback_xmit+0x6c/0xb0 @@ -1561,7 +1561,7 @@ Extended error information sock_sendmsg+0x38/0x50 ___sys_sendmsg+0x14e/0x270 } hitcount: 76 - { stacktrace: + { common_stacktrace: netif_rx_internal+0xb2/0xd0 netif_rx+0x1c/0x60 loopback_xmit+0x6c/0xb0 @@ -1579,7 +1579,7 @@ Extended error information sock_sendmsg+0x38/0x50 ___sys_sendmsg+0x269/0x270 } hitcount: 77 - { stacktrace: + { common_stacktrace: netif_rx_internal+0xb2/0xd0 netif_rx+0x1c/0x60 loopback_xmit+0x6c/0xb0 @@ -1597,7 +1597,7 @@ Extended error information sock_sendmsg+0x38/0x50 SYSC_sendto+0xef/0x170 } hitcount: 88 - { stacktrace: + { common_stacktrace: kernel_clone+0x18e/0x330 SyS_clone+0x19/0x20 entry_SYSCALL_64_fastpath+0x12/0x6a @@ -1949,7 +1949,7 @@ uninterruptible state:: # cd /sys/kernel/tracing # echo 's:block_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events - # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 2' >> events/sched/sched_switch/trigger + # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=common_stacktrace if prev_state == 2' >> events/sched/sched_switch/trigger # echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(block_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger # echo 1 > events/synthetic/block_lat/enable # cat trace diff --git a/Documentation/trace/user_events.rst b/Documentation/trace/user_events.rst index 422802ef4025..f79987e16cf4 100644 --- a/Documentation/trace/user_events.rst +++ b/Documentation/trace/user_events.rst @@ -20,11 +20,10 @@ dynamic_events is the same as the ioctl with the u: prefix applied. Typically programs will register a set of events that they wish to expose to tools that can read trace_events (such as ftrace and perf). The registration -process gives back two ints to the program for each event. The first int is -the status bit. This describes which bit in little-endian format in the -/sys/kernel/tracing/user_events_status file represents this event. The -second int is the write index which describes the data when a write() or -writev() is called on the /sys/kernel/tracing/user_events_data file. +process tells the kernel which address and bit to reflect if any tool has +enabled the event and data should be written. The registration will give back +a write index which describes the data when a write() or writev() is called +on the /sys/kernel/tracing/user_events_data file. The structures referenced in this document are contained within the /include/uapi/linux/user_events.h file in the source tree. @@ -41,23 +40,64 @@ DIAG_IOCSREG. This command takes a packed struct user_reg as an argument:: struct user_reg { - u32 size; - u64 name_args; - u32 status_bit; - u32 write_index; - }; + /* Input: Size of the user_reg structure being used */ + __u32 size; -The struct user_reg requires two inputs, the first is the size of the structure -to ensure forward and backward compatibility. The second is the command string -to issue for registering. Upon success two outputs are set, the status bit -and the write index. + /* Input: Bit in enable address to use */ + __u8 enable_bit; + + /* Input: Enable size in bytes at address */ + __u8 enable_size; + + /* Input: Flags for future use, set to 0 */ + __u16 flags; + + /* Input: Address to update when enabled */ + __u64 enable_addr; + + /* Input: Pointer to string with event name, description and flags */ + __u64 name_args; + + /* Output: Index of the event to use when writing data */ + __u32 write_index; + } __attribute__((__packed__)); + +The struct user_reg requires all the above inputs to be set appropriately. + ++ size: This must be set to sizeof(struct user_reg). + ++ enable_bit: The bit to reflect the event status at the address specified by + enable_addr. + ++ enable_size: The size of the value specified by enable_addr. + This must be 4 (32-bit) or 8 (64-bit). 64-bit values are only allowed to be + used on 64-bit kernels, however, 32-bit can be used on all kernels. + ++ flags: The flags to use, if any. For the initial version this must be 0. + Callers should first attempt to use flags and retry without flags to ensure + support for lower versions of the kernel. If a flag is not supported -EINVAL + is returned. + ++ enable_addr: The address of the value to use to reflect event status. This + must be naturally aligned and write accessible within the user program. + ++ name_args: The name and arguments to describe the event, see command format + for details. + +Upon successful registration the following is set. + ++ write_index: The index to use for this file descriptor that represents this + event when writing out data. The index is unique to this instance of the file + descriptor that was used for the registration. See writing data for details. User based events show up under tracefs like any other event under the subsystem named "user_events". This means tools that wish to attach to the events need to use /sys/kernel/tracing/events/user_events/[name]/enable or perf record -e user_events:[name] when attaching/recording. -**NOTE:** *The write_index returned is only valid for the FD that was used* +**NOTE:** The event subsystem name by default is "user_events". Callers should +not assume it will always be "user_events". Operators reserve the right in the +future to change the subsystem name per-process to accomodate event isolation. Command Format ^^^^^^^^^^^^^^ @@ -94,7 +134,7 @@ Would be represented by the following field:: struct mytype myname 20 Deleting ------------ +-------- Deleting an event from within a user process is done via ioctl() out to the /sys/kernel/tracing/user_events_data file. The command to issue is DIAG_IOCSDEL. @@ -104,92 +144,79 @@ its name. Delete will only succeed if there are no references left to the event (in both user and kernel space). User programs should use a separate file to request deletes than the one used for registration due to this. +Unregistering +------------- +If after registering an event it is no longer wanted to be updated then it can +be disabled via ioctl() out to the /sys/kernel/tracing/user_events_data file. +The command to issue is DIAG_IOCSUNREG. This is different than deleting, where +deleting actually removes the event from the system. Unregistering simply tells +the kernel your process is no longer interested in updates to the event. + +This command takes a packed struct user_unreg as an argument:: + + struct user_unreg { + /* Input: Size of the user_unreg structure being used */ + __u32 size; + + /* Input: Bit to unregister */ + __u8 disable_bit; + + /* Input: Reserved, set to 0 */ + __u8 __reserved; + + /* Input: Reserved, set to 0 */ + __u16 __reserved2; + + /* Input: Address to unregister */ + __u64 disable_addr; + } __attribute__((__packed__)); + +The struct user_unreg requires all the above inputs to be set appropriately. + ++ size: This must be set to sizeof(struct user_unreg). + ++ disable_bit: This must be set to the bit to disable (same bit that was + previously registered via enable_bit). + ++ disable_addr: This must be set to the address to disable (same address that was + previously registered via enable_addr). + +**NOTE:** Events are automatically unregistered when execve() is invoked. During +fork() the registered events will be retained and must be unregistered manually +in each process if wanted. + Status ------ When tools attach/record user based events the status of the event is updated in realtime. This allows user programs to only incur the cost of the write() or writev() calls when something is actively attached to the event. -User programs call mmap() on /sys/kernel/tracing/user_events_status to -check the status for each event that is registered. The bit to check in the -file is given back after the register ioctl() via user_reg.status_bit. The bit -is always in little-endian format. Programs can check if the bit is set either -using a byte-wise index with a mask or a long-wise index with a little-endian -mask. - -Currently the size of user_events_status is a single page, however, custom -kernel configurations can change this size to allow more user based events. In -all cases the size of the file is a multiple of a page size. - -For example, if the register ioctl() gives back a status_bit of 3 you would -check byte 0 (3 / 8) of the returned mmap data and then AND the result with 8 -(1 << (3 % 8)) to see if anything is attached to that event. - -A byte-wise index check is performed as follows:: - - int index, mask; - char *status_page; - - index = status_bit / 8; - mask = 1 << (status_bit % 8); - - ... - - if (status_page[index] & mask) { - /* Enabled */ - } - -A long-wise index check is performed as follows:: - - #include - #include - - #if __BITS_PER_LONG == 64 - #define endian_swap(x) htole64(x) - #else - #define endian_swap(x) htole32(x) - #endif - - long index, mask, *status_page; - - index = status_bit / __BITS_PER_LONG; - mask = 1L << (status_bit % __BITS_PER_LONG); - mask = endian_swap(mask); - - ... - - if (status_page[index] & mask) { - /* Enabled */ - } +The kernel will update the specified bit that was registered for the event as +tools attach/detach from the event. User programs simply check if the bit is set +to see if something is attached or not. Administrators can easily check the status of all registered events by reading the user_events_status file directly via a terminal. The output is as follows:: - Byte:Name [# Comments] + Name [# Comments] ... Active: ActiveCount Busy: BusyCount - Max: MaxCount For example, on a system that has a single event the output looks like this:: - 1:test + test Active: 1 Busy: 0 - Max: 32768 If a user enables the user event via ftrace, the output would change to this:: - 1:test # Used by ftrace + test # Used by ftrace Active: 1 Busy: 1 - Max: 32768 - -**NOTE:** *A status bit of 0 will never be returned. This allows user programs -to have a bit that can be used on error cases.* Writing Data ------------ @@ -217,7 +244,7 @@ For example, if I have a struct like this:: int src; int dst; int flags; - }; + } __attribute__((__packed__)); It's advised for user programs to do the following:: diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst index a9e781d2e323..4c21cf60f775 100644 --- a/Documentation/translations/it_IT/kernel-hacking/locking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst @@ -1030,7 +1030,7 @@ alle corse critiche, dovreste usare timer_delete_sync() (``include/linux/timer.h``) per gestire questo caso. Prima di rilasciare un temporizzatore dovreste chiamare la funzione -timer_shutdown() o timer_shutdown_sync() di modo che non venga più ricarmato. +timer_shutdown() o timer_shutdown_sync() di modo che non venga più riarmato. Ogni successivo tentativo di riarmare il temporizzatore verrà silenziosamente ignorato. diff --git a/Documentation/translations/it_IT/process/deprecated.rst b/Documentation/translations/it_IT/process/deprecated.rst index 57b501f0dfa4..ba0ed7dc154c 100644 --- a/Documentation/translations/it_IT/process/deprecated.rst +++ b/Documentation/translations/it_IT/process/deprecated.rst @@ -386,7 +386,7 @@ combinazione con struct_size() e flex_array_size():: Ci sono due casi speciali dove è necessario usare la macro DECLARE_FLEX_ARRAY() (da notare che la stessa macro è chiamata __DECLARE_FLEX_ARRAY() nei file di intestazione UAPI). Uno è quando l'array flessibile è l'unico elemento di una -struttura, e l'altro è quando è parti un unione. Per motivi non tecnici, entrambi +struttura, e l'altro quando è parte di un unione. Per motivi non tecnici, entrambi i casi d'uso non sono permessi dalla specifica C99. Per esempio, per convertire il seguente codice:: diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 02eb7eb2448e..ae92ab633c16 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -78,7 +78,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` diff --git a/Documentation/translations/it_IT/process/submitting-patches.rst b/Documentation/translations/it_IT/process/submitting-patches.rst index 447b18792e61..f91c8092844f 100644 --- a/Documentation/translations/it_IT/process/submitting-patches.rst +++ b/Documentation/translations/it_IT/process/submitting-patches.rst @@ -532,7 +532,7 @@ manutentori che qualche verifica è stata fatta, fornisce un mezzo per trovare persone che possano verificare il codice in futuro, e garantisce che queste stesse persone ricevano credito per il loro lavoro. -Reviewd-by:, invece, indica che la patch è stata revisionata ed è stata +Reviewed-by:, invece, indica che la patch è stata revisionata ed è stata considerata accettabile in accordo con la dichiarazione dei revisori: Dichiarazione di svista dei revisori @@ -563,13 +563,13 @@ una modifica che si ritiene appropriata e senza alcun problema tecnico importante. Qualsiasi revisore interessato (quelli che lo hanno fatto) possono offrire il proprio Reviewed-by per la patch. Questa etichetta serve a dare credito ai revisori e a informare i manutentori sul livello di revisione -che è stato fatto sulla patch. L'etichetta Reviewd-by, quando fornita da +che è stato fatto sulla patch. L'etichetta Reviewed-by, quando fornita da revisori conosciuti per la loro conoscenza sulla materia in oggetto e per la loro serietà nella revisione, accrescerà le probabilità che la vostra patch venga integrate nel kernel. Quando si riceve una email sulla lista di discussione da un tester o -un revisore, le etichette Tested-by o Reviewd-by devono essere +un revisore, le etichette Tested-by o Reviewed-by devono essere aggiunte dall'autore quando invierà nuovamente la patch. Tuttavia, se la patch è cambiata in modo significativo, queste etichette potrebbero non avere più senso e quindi andrebbero rimosse. Solitamente si tiene traccia diff --git a/Documentation/translations/ja_JP/SubmittingPatches b/Documentation/translations/ja_JP/SubmittingPatches index 04deb77b20c6..5334db471744 100644 --- a/Documentation/translations/ja_JP/SubmittingPatches +++ b/Documentation/translations/ja_JP/SubmittingPatches @@ -450,7 +450,7 @@ Reviewed-by: タグは、それとは異なり、下記のレビューア宣言 状況においてその宣言した目的や機能が正しく実現することに関して、 いかなる保証もしない(特にどこかで明示しない限り)。 -Reviewd-by タグはそのパッチがカーネルに対して適切な修正であって、深刻な技術的 +Reviewed-by タグはそのパッチがカーネルに対して適切な修正であって、深刻な技術的 問題を残していないという意見の宣言です。興味のあるレビューアは誰でも(レビュー 作業を終えたら)パッチに対して Reviewed-by タグを提示できます。このタグは レビューアの寄与をクレジットする働き、レビューの進捗の度合いをメンテナに diff --git a/Documentation/translations/sp_SP/process/adding-syscalls.rst b/Documentation/translations/sp_SP/process/adding-syscalls.rst new file mode 100644 index 000000000000..f21504c612b2 --- /dev/null +++ b/Documentation/translations/sp_SP/process/adding-syscalls.rst @@ -0,0 +1,632 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/adding-syscalls.rst ` +:Translator: Mauricio Fuentes + +.. _sp_addsyscalls: + +Agregando una Nueva Llamada del Sistema +======================================= + +Este documento describe qué involucra agregar una nueva llamada del sistema +al kernel Linux, más allá de la presentación y consejos normales en +:ref:`Documentation/process/submitting-patches.rst ` que +también puede encontrar traducido a este idioma. + +Alternativas a Llamadas del Sistema +----------------------------------- + +La primera cosa a considerar cuando se agrega una llamada al sistema es si +alguna alternativa es adecuada en su lugar. Aunque las llamadas al sistema +son los puntos de interacción entre el userspace y el kernel más obvios y +tradicionales, existen otras posibilidades -- elija la que mejor se adecúe +a su interfaz. + + - Si se puede hacer que la operación se parezca a un objeto filesystem, + podría tener más sentido crear un nuevo sistema de ficheros o + dispositivo. Esto también hará más fácil encapsular la nueva + funcionalidad en un módulo del kernel en vez de requerir que sea + construido junto al kernel principal. + + - Si la nueva funcionalidad involucra operaciones donde el kernel + notifica al userspace que algo ha pasado, entonces retornar un nuevo + descriptor de archivo para el objeto relevante permite al userspace + usar ``poll``/``select``/``epoll`` para recibir esta notificación. + + - Sin embargo, operaciones que no mapean a operaciones similares a + :manpage:`read(2)`/:manpage:`write(2)` tienen que ser implementadas + como solicitudes :manpage:`ioctl(2)`, las cuales pueden llevar a un + API algo opaca. + + - Si sólo está exponiendo información del runtime, un nuevo nodo en sysfs + (mire ``Documentation/filesystems/sysfs.rst``) o el filesystem ``/proc`` + podría ser más adecuado. Sin embargo, acceder a estos mecanismos + requiere que el filesystem relevante esté montado, lo que podría no ser + siempre el caso (e.g. en un ambiente namespaced/sandboxed/chrooted). + Evite agregar cualquier API a debugfs, ya que no se considera una + interfaz (interface) de 'producción' para el userspace. + + - Si la operación es específica a un archivo o descriptor de archivo + específico, entonces la opción de comando adicional :manpage:`fcntl(2)` + podría ser más apropiada. Sin embargo, :manpage:`fcntl(2)` es una + llamada al sistema multiplexada que esconde mucha complejidad, así que + esta opción es mejor cuando la nueva funcion es analogamente cercana a + la funcionalidad existente :manpage:`fcntl(2)`, o la nueva funcionalidad + es muy simple (por ejemplo, definir/obtener un flag simple relacionado a + un descriptor de archivo). + + - Si la operación es específica a un proceso o tarea particular, entonces + un comando adicional :manpage:`prctl(2)` podría ser más apropiado. Tal + como con :manpage:`fcntl(2)`, esta llamada al sistema es un multiplexor + complicado así que está reservado para comandos análogamente cercanos + del existente ``prctl()`` u obtener/definir un flag simple relacionado a + un proceso. + +Diseñando el API: Planeando para extensiones +-------------------------------------------- + +Una nueva llamada del sistema forma parte del API del kernel, y tiene que +ser soportada indefinidamente. Como tal, es una muy buena idea discutir +explícitamente el interface en las listas de correo del kernel, y es +importante planear para futuras extensiones del interface. + +(La tabla syscall está poblada con ejemplos históricos donde esto no se +hizo, junto con los correspondientes seguimientos de los system calls -- +``eventfd``/``eventfd2``, ``dup2``/``dup3``, ``inotify_init``/``inotify_init1``, +``pipe``/``pipe2``, ``renameat``/``renameat2`` -- así que aprenda de la +historia del kernel y planee extensiones desde el inicio.) + +Para llamadas al sistema más simples que sólo toman un par de argumentos, +la forma preferida de permitir futuras extensiones es incluir un argumento +flag a la llamada al sistema. Para asegurarse que el userspace pueda usar +de forma segura estos flags entre versiones del kernel, revise si los flags +contienen cualquier flag desconocido, y rechace la llamada al sistema (con +``EINVAL``) si ocurre:: + + if (flags & ~(THING_FLAG1 | THINGFLAG2 | THING_FLAG3)) + return -EINVAL; + +(Si no hay valores de flags usados aún, revise que los argumentos del flag +sean cero.) + +Para llamadas al sistema más sofisticadas que involucran un gran número de +argumentos, es preferible encapsular la mayoría de los argumentos en una +estructura que sea pasada a través de un puntero. Tal estructura puede +hacer frente a futuras extensiones mediante la inclusión de un argumento de +tamaño en la estructura:: + + struct xyzzy_params { + u32 size; /* userspace define p->size = sizeof(struct xyzzy_params) */ + u32 param_1; + u64 param_2; + u64 param_3; + }; + +Siempre que cualquier campo añadido subsecuente, digamos ``param_4``, sea +diseñado de forma tal que un valor cero, devuelva el comportamiento previo, +entonces permite versiones no coincidentes en ambos sentidos: + + - Para hacer frente a programas del userspace más modernos, haciendo + llamadas a un kernel más antiguo, el código del kernel debe revisar que + cualquier memoria más allá del tamaño de la estructura sea cero (revisar + de manera efectiva que ``param_4 == 0``). + - Para hacer frente a programas antiguos del userspace haciendo llamadas a + un kernel más nuevo, el código del kernel puede extender con ceros, una + instancia más pequeña de la estructura (definiendo efectivamente + ``param_4 == 0``). + +Revise :manpage:`perf_event_open(2)` y la función ``perf_copy_attr()`` (en +``kernel/events/code.c``) para un ejemplo de esta aproximación. + + +Diseñando el API: Otras consideraciones +--------------------------------------- + +Si su nueva llamada al sistema permite al userspace hacer referencia a un +objeto del kernel, esta debería usar un descriptor de archivo como el +manipulador de ese objeto -- no invente un nuevo tipo de objeto manipulador +userspace cuando el kernel ya tiene mecanismos y semánticas bien definidas +para usar los descriptores de archivos. + +Si su nueva llamada a sistema :manpage:`xyzzy(2)` retorna un nuevo +descriptor de archivo, entonces el argumento flag debe incluir un valor que +sea equivalente a definir ``O_CLOEXEC`` en el nuevo FD. Esto hace posible +al userspace acortar la brecha de tiempo entre ``xyzzy()`` y la llamada a +``fcntl(fd, F_SETFD, FD_CLOEXEC)``, donde un ``fork()`` inesperado y +``execve()`` en otro hilo podrían filtrar un descriptor al programa +ejecutado. (Sin embargo, resista la tentación de reusar el valor actual de +la constante ``O_CLOEXEC``, ya que es específica de la arquitectura y es +parte de un espacio numerado de flags ``O_*`` que está bastante lleno.) + +Si su llamada de sistema retorna un nuevo descriptor de archivo, debería +considerar también que significa usar la familia de llamadas de sistema +:manpage:`poll(2)` en ese descriptor de archivo. Hacer un descriptor de +archivo listo para leer o escribir es la forma normal para que el kernel +indique al espacio de usuario que un evento ha ocurrido en el +correspondiente objeto del kernel. + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra algún nombre +de archivo como argumento:: + + int sys_xyzzy(const char __user *path, ..., unsigned int flags); + +debería considerar también si una versión :manpage:`xyzzyat(2)` es mas +apropiada:: + + int sys_xyzzyat(int dfd, const char __user *path, ..., unsigned int flags); + +Esto permite más flexibilidad en como el userspace especifica el archivo en +cuestión; en particular esto permite al userspace pedir la funcionalidad a +un descriptor de archivo ya abierto usando el flag ``AT_EMPTY_PATH``, +efectivamente dando una operación :manpage:`fxyzzy(3)` gratis:: + + - xyzzyat(AT_FDCWD, path, ..., 0) es equivalente a xyzzy(path, ...) + - xyzzyat(fd, "", ..., AT_EMPTY_PATH) es equivalente a fxyzzy(fd, ...) + +(Para más detalles sobre la explicación racional de las llamadas \*at(), +revise el man page :manpage:`openat(2)`; para un ejemplo de AT_EMPTY_PATH, +mire el man page :manpage:`fstatat(2)` manpage.) + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` involucra un parámetro +describiendo un describiendo un movimiento dentro de un archivo, ponga de +tipo ``loff_t`` para que movimientos de 64-bit puedan ser soportados +incluso en arquitecturas de 32-bit. + +Si su nueva llamada de sistema :manpage:`xyzzy` involucra una +funcionalidad privilegiada, esta necesita ser gobernada por la capability +bit linux apropiada (revisado con una llamada a ``capable()``), como se +describe en el man page :manpage:`capabilities(7)`. Elija una parte de +capability linux que govierne las funcionalidades relacionadas, pero trate +de evitar combinar muchas funciones sólo relacionadas vagamente bajo la +misma sección, ya que va en contra de los propósitos de las capabilities de +dividir el poder del usuario root. En particular, evite agregar nuevos usos +de la capacidad ya demasiado general de la capabilities ``CAP_SYS_ADMIN``. + +Si su nueva llamada de sistema :manpage:`xyzzy(2)` manipula un proceso que +no es el proceso invocado, este debería ser restringido (usando una llamada +a ``ptrace_may_access()``) de forma que el único proceso con los mismos +permisos del proceso objetivo, o con las capacidades (capabilities) +necesarias, pueda manipulador el proceso objetivo. + +Finalmente, debe ser conciente de que algunas arquitecturas no-x86 tienen +un manejo más sencillo si los parámetros que son explícitamente 64-bit +caigan en argumentos enumerados impares (i.e. parámetros 1,3,5), para +permitir el uso de pares contiguos de registros 32-bits. (Este cuidado no +aplica si el argumento es parte de una estructura que se pasa a través de +un puntero.) + +Proponiendo el API +------------------ + +Para hacer una nueva llamada al sistema fácil de revisar, es mejor dividir +el patchset (conjunto de parches) en trozos separados. Estos deberían +incluir al menos los siguientes items como commits distintos (cada uno de +los cuales se describirá más abajo): + + - La implementación central de la llamada al sistema, junto con + prototipos, numeración genérica, cambios Kconfig e implementaciones de + rutinas de respaldo (fallback stub) + - Conectar la nueva llamada a sistema a una arquitectura particular, + usualmente x86 (incluyendo todas las x86_64, x86_32 y x32). + - Una demostración del use de la nueva llamada a sistema en el userspace + vía un selftest en ``tools/testing/selftest/``. + - Un borrador de man-page para la nueva llamada a sistema, ya sea como + texto plano en la carta de presentación, o como un parche (separado) + para el repositorio man-pages. + +Nuevas propuestas de llamadas de sistema, como cualquier cambio al API del +kernel, debería siempre ser copiado a linux-api@vger.kernel.org. + + +Implementation de Llamada de Sistema Generica +--------------------------------------------- + +La entrada principal a su nueva llamada de sistema :manpage:`xyzzy(2)` será +llamada ``sys_xyzzy()``, pero incluya este punto de entrada con la macro +``SYSCALL_DEFINEn()`` apropiada en vez de explicitamente. El 'n' indica el +numero de argumentos de la llamada de sistema, y la macro toma el nombre de +la llamada de sistema seguida por el par (tipo, nombre) para los parámetros +como argumentos. Usar esta macro permite a la metadata de la nueva llamada +de sistema estar disponible para otras herramientas. + +El nuevo punto de entrada también necesita un prototipo de función +correspondiente en ``include/linux/syscalls.h``, marcado como asmlinkage +para calzar en la manera en que las llamadas de sistema son invocadas:: + + asmlinkage long sys_xyzzy(...); + +Algunas arquitecturas (e.g. x86) tienen sus propias tablas de syscall +específicas para la arquitectura, pero muchas otras arquitecturas comparten +una tabla de syscall genéricas. Agrega su nueva llamada de sistema a la +lista genérica agregando una entrada a la lista en +``include/uapi/asm-generic/unistd.h``:: + + #define __NR_xyzzy 292 + __SYSCALL(__NR_xyzzy, sys_xyzzy ) + +También actualice el conteo de __NR_syscalls para reflejar la llamada de +sistema adicional, y note que si multiples llamadas de sistema nuevas son +añadidas en la misma ventana unida, su nueva llamada de sistema podría +tener que ser ajustada para resolver conflictos. + +El archivo ``kernel/sys_ni.c`` provee una implementación fallback stub +(rutina de respaldo) para cada llamada de sistema, retornando ``-ENOSYS``. +Incluya su nueva llamada a sistema aquí también:: + + COND_SYSCALL(xyzzy); + +Su nueva funcionalidad del kernel, y la llamada de sistema que la controla, +debería normalmente ser opcional, así que incluya una opción ``CONFIG`` +(tipicamente en ``init/Kconfig``) para ella. Como es usual para opciones +``CONFIG`` nuevas: + + - Incluya una descripción para la nueva funcionalidad y llamada al sistema + controlada por la opción. + - Haga la opción dependiendo de EXPERT si esta debe estar escondida de los + usuarios normales. + - Haga que cualquier nuevo archivo fuente que implemente la función + dependa de la opción CONFIG en el Makefile (e.g. + ``obj-$(CONFIG_XYZZY_SYSCALL) += xyzzy.o``). + - Revise dos veces que el kernel se siga compilando con la nueva opción + CONFIG apagada. + +Para resumir, necesita un commit que incluya: + + - una opción ``CONFIG`` para la nueva función, normalmente en ``init/Kconfig`` + - ``SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada + - El correspondiente prototipo en ``include/linux/syscalls.h`` + - Una entrada genérica en ``include/uapi/asm-generic/unistd.h`` + - fallback stub en ``kernel/sys_ni.c`` + + +Implementación de Llamada de Sistema x86 +---------------------------------------- + +Para conectar su nueva llamada de sistema a plataformas x86, necesita +actualizar las tablas maestras syscall. Asumiendo que su nueva llamada de +sistema ni es especial de alguna manera (revise abajo), esto involucra una +entrada "común" (para x86_64 y x86_32) en +arch/x86/entry/syscalls/syscall_64.tbl:: + + 333 common xyzz sys_xyzzy + +y una entrada "i386" en ``arch/x86/entry/syscalls/syscall_32.tbl``:: + + 380 i386 xyzz sys_xyzzy + +De nuevo, estos número son propensos de ser cambiados si hay conflictos en +la ventana de integración relevante. + + +Compatibilidad de Llamadas de Sistema (Genérica) +------------------------------------------------ + +Para la mayoría de llamadas al sistema la misma implementación 64-bit puede +ser invocada incluso cuando el programa de userspace es en si mismo 32-bit; +incluso si los parámetros de la llamada de sistema incluyen un puntero +explícito, esto es manipulado de forma transparente. + +Sin embargo, existe un par de situaciones donde se necesita una capa de +compatibilidad para lidiar con las diferencias de tamaño entre 32-bit y +64-bit. + +La primera es si el kernel 64-bit también soporta programas del userspace +32-bit, y por lo tanto necesita analizar areas de memoria del (``__user``) +que podrían tener valores tanto 32-bit como 64-bit. En particular esto se +necesita siempre que un argumento de la llamada a sistema es: + + - un puntero a un puntero + - un puntero a un struc conteniendo un puntero (por ejemplo + ``struct iovec __user *``) + - un puntero a un type entero de tamaño entero variable (``time_t``, + ``off_t``, ``long``, ...) + - un puntero a un struct conteniendo un type entero de tamaño variable. + +La segunda situación que requiere una capa de compatibilidad es cuando uno +de los argumentos de la llamada a sistema tiene un argumento que es +explícitamente 64-bit incluso sobre arquitectura 32-bit, por ejemplo +``loff_t`` o ``__u64``. En este caso, el valor que llega a un kernel 64-bit +desde una aplicación de 32-bit se separará en dos valores de 32-bit, los +que luego necesitan ser reensamblados en la capa de compatibilidad. + +(Note que un argumento de una llamada a sistema que sea un puntero a un +type explicitamente de 64-bit **no** necesita una capa de compatibilidad; +por ejemplo, los argumentos de :manpage:`splice(2)`) del tipo +``loff_t __user *`` no significan la necesidad de una llamada a sistema +``compat_``.) + +La versión compatible de la llamada de sistema se llama +``compat_sys_xyzzy()``, y se agrega con la macro +``COMPAT_SYSCALL_DEFINEn``, de manera análoga a SYSCALL_DEFINEn. Esta +versión de la implementación se ejecuta como parte de un kernel de 64-bit, +pero espera recibir parametros con valores 32-bit y hace lo que tenga que +hacer para tratar con ellos. (Típicamente, la versión ``compat_sys_`` +convierte los valores a versiones de 64 bits y llama a la versión ``sys_`` +o ambas llaman a una función de implementación interna común.) + +El punto de entrada compat también necesita un prototipo de función +correspondiente, en ``include/linux/compat.h``, marcado como asmlinkage +para igualar la forma en que las llamadas al sistema son invocadas:: + + asmlinkage long compat_sys_xyzzy(...); + +Si la nueva llamada al sistema involucra una estructura que que se dispone +de forma distinta en sistema de 32-bit y 64-bit, digamos +``struct xyzzy_args``, entonces el archivo de cabecera +include/linux/compat.h también debería incluir una versión compatible de la +estructura (``struct compat_xyzzy_args``) donde cada campo de tamaño +variable tiene el tipo ``compat_`` apropiado que corresponde al tipo en +``struct xyzzy_args``. La rutina ``compat_sys_xyzzy()`` puede entonces usar +esta estructura ``compat_`` para analizar los argumentos de una invocación +de 32-bit. + +Por ejemplo, si hay campos:: + + struct xyzzy_args { + const char __user *ptr; + __kernel_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +en struct xyzzy_args, entonces struct compat_xyzzy_args debe tener:: + + struct compat_xyzzy_args { + compat_uptr_t ptr; + compat_long_t varying_val; + u64 fixed_val; + /* ... */ + }; + +la lista genérica de llamadas al sistema también necesita ajustes para +permitir la versión compat; la entrada en +``include/uapi/asm-generic/unistd.h`` debería usar ``__SC_COMP`` en vez de +``__SYSCALL``:: + + #define __NR_xyzzy 292 + __SC_COMP(__NR_xyzzy, sys_xyzzy, compat_sys_xyzzy) + +Para resumir, necesita: + + - una ``COMPAT_SYSCALL_DEFINEn(xyzzy, ...)`` para el punto de entrada de compat. + - el prototipo correspondiente en ``include/linux/compat.h`` + - (en caso de ser necesario) un struct de mapeo de 32-bit en ``include/linux/compat.h`` + - una instancia de ``__SC_COMP`` no ``__SYSCALL`` en ``include/uapi/asm-generic/unistd.h`` + +Compatibilidad de Llamadas de Sistema (x86) +------------------------------------------- + +Para conectar la arquitectura x86 de una llamada al sistema con una versión +de compatibilidad, las entradas en las tablas de syscall deben ser +ajustadas. + +Primero, la entrada en ``arch/x86/entry/syscalls/syscall_32.tbl`` recibe +una columna extra para indicar que un programa del userspace de 32-bit +corriendo en un kernel de 64-bit debe llegar al punto de entrada compat:: + + 380 i386 xyzzy sys_xyzzy __ia32_compat_sys_xyzzy + +Segundo, tienes que averiguar qué debería pasar para la versión x32 ABI de +la nueva llamada al sistema. Aquí hay una elección: el diseño de los +argumentos debería coincidir con la versión de 64-bit o la versión de +32-bit. + +Si hay involucrado un puntero-a-puntero, la decisión es fácil: x32 es +ILP32, por lo que el diseño debe coincidir con la versión 32-bit, y la +entrada en ``arch/x86/entry/syscalls/syscall_64.tbl`` se divide para que +progamas 32-bit lleguen al envoltorio de compatibilidad:: + + 333 64 xyzzy sys_xyzzy + ... + 555 x32 xyzzy __x32_compat_sys_xyzzy + +Si no hay punteros involucrados, entonces es preferible reutilizar el system +call 64-bit para el x32 ABI (y consecuentemente la entrada en +arch/x86/entry/syscalls/syscall_64.tbl no se cambia). + +En cualquier caso, debes revisar que lo tipos involucrados en su diseño de +argumentos de hecho asigne exactamente de x32 (-mx32) a 32-bit(-m32) o +equivalentes 64-bit (-m64). + + +Llamadas de Sistema Retornando a Otros Lugares +---------------------------------------------- + +Para la mayoría de las llamadas al sistema, una vez que se la llamada al +sistema se ha completado el programa de usuario continúa exactamente donde +quedó -- en la siguiente instrucción, con el stack igual y la mayoría de +los registros igual que antes de la llamada al sistema, y con el mismo +espacio en la memoria virtual. + +Sin embargo, unas pocas llamadas al sistema hacen las cosas diferente. +Estas podrían retornar a una ubicación distinta (``rt_sigreturn``) o +cambiar el espacio de memoria (``fork``/``vfork``/``clone``) o incluso de +arquitectura (``execve``/``execveat``) del programa. + +Para permitir esto, la implementación del kernel de la llamada al sistema +podría necesitar guardar y restaurar registros adicionales al stak del +kernel, brindandole control completo de donde y cómo la ejecución continúa +después de la llamada a sistema. + +Esto es arch-specific, pero típicamente involucra definir puntos de entrada +assembly que guardan/restauran registros adicionales e invocan el punto de +entrada real de la llamada a sistema. + +Para x86_64, esto es implementado como un punto de entrada ``stub_xyzzy`` +en ``arch/x86/entry/entry_64.S``, y la entrada en la tabla syscall +(``arch/x86/entry/syscalls/syscall_32.tbl``) es ajustada para calzar:: + + 333 common xyzzy stub_xyzzy + +El equivalente para programas 32-bit corriendo en un kernel 64-bit es +normalmente llamado ``stub32_xyzzy`` e implementado en +``arch/x86/entry/entry_64_compat.S``, con el correspondiente ajuste en la +tabla syscall en ``arch/x86/syscalls/syscall_32.tbl``:: + + 380 i386 xyzzy sys_xyzzy stub32_xyzzy + +Si la llamada a sistema necesita una capa de compatibilidad (como en la +sección anterior) entonces la versión ``stub32_`` necesita llamar a la +versión ``compat_sys_`` de la llamada a sistema, en vez de la versión +nativa de 64-bit. También, si la implementación de la versión x32 ABI no es +comun con la versión x86_64, entonces su tabla syscall también necesitará +invocar un stub que llame a la versión ``compat_sys_`` + +Para completar, también es agradable configurar un mapeo de modo que el +user-mode linux todavía funcione -- su tabla syscall referenciará +stub_xyzzy, pero el UML construido no incluye una implementación +``arch/x86/entry/entry_64.S``. Arreglar esto es tan simple como agregar un +#define a ``arch/x86/um/sys_call_table_64.c``:: + + #define stub_xyzzy sys_xyzzy + + +Otros detalles +-------------- + +La mayoría del kernel trata las llamadas a sistema de manera genérica, pero +está la excepción ocasional que pueda requerir actualización para su +llamada a sistema particular. + +El subsistema de auditoría es un caso especial; este incluye funciones +(arch-specific) que clasifican algunos tipos especiales de llamadas al +sistema -- específicamente file open (``open``/``openat``), program +execution (``execve`` /``execveat``) o operaciones multiplexores de socket +(``socketcall``). Si su nueva llamada de sistema es análoga a alguna de +estas, entonces el sistema auditor debe ser actualizado. + +Más generalmente, si existe una llamada al sistema que sea análoga a su +nueva llamada al sistema, entonces vale la pena hacer un grep a todo el +kernel de la llamada a sistema existente, para revisar que no exista otro +caso especial. + + +Testing +------- + +Una nueva llamada al sistema debe obviamente ser probada; también es útil +proveer a los revisores con una demostración de cómo los programas del +userspace usarán la llamada al sistema. Una buena forma de combinar estos +objetivos es incluir un simple programa self-test en un nuevo directorio +bajo ``tools/testing/selftests/``. + +Para una nueva llamada al sistema, obviamente no habrá una función +envoltorio libc por lo que el test necesitará ser invocado usando +``syscall()``; también, si la llamada al sistema involucra una nueva +estructura userspace-visible, el encabezado correspondiente necesitará ser +instalado para compilar el test. + +Asegure que selftest corra satisfactoriamente en todas las arquitecturas +soportadas. Por ejemplo, revise si funciona cuando es compilado como un +x86_64 (-m64), x86_32 (-m32) y x32 (-mx32) programa ABI. + +Para pruebas más amplias y exhautivas de la nueva funcionalidad, también +debería considerar agregar tests al Linus Test Project, o al proyecto +xfstests para cambios filesystem-related + + - https://linux-test-project.github.io/ + - git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git + + +Man Page +-------- + +Todas las llamada al sistema nueva deben venir con un man page completo, +idealmente usando groff markup, pero texto plano también funciona. Si se +usa groff, es útil incluir una versión ASCII pre-renderizada del man-page +en el cover del email para el patchset, para la conveniencia de los +revisores. + +El man page debe ser cc'do a linux-man@vger.kernel.org +Para más detalles, revise https://www.kernel.org/doc/man-pages/patches.html + + +No invoque las llamadas de sistemas en el kernel +------------------------------------------------ + +Las llamadas al sistema son, cómo se declaró más arriba, puntos de +interacción entre el userspace y el kernel. Por lo tanto, las funciones de +llamada al sistema como ``sys_xyzzy()`` o ``compat_sys_xyzzy()`` deberían +ser llamadas sólo desde el userspace vía la tabla de syscall, pero no de +otro lugar en el kernel. Si la funcionalidad syscall es útil para ser usada +dentro del kernel, necesita ser compartida entre syscalls nuevas o +antiguas, o necesita ser compartida entre una syscall y su variante de +compatibilidad, esta debería ser implementada mediante una función "helper" +(como ``ksys_xyzzy()``). Esta función del kernel puede ahora ser llamada +dentro del syscall stub (``sys_xyzzy()``), la syscall stub de +compatibilidad (``compat_sys_xyzzy()``), y/o otro código del kernel. + +Al menos en 64-bit x86, será un requerimiento duro desde la v4.17 en +adelante no invocar funciones de llamada al sistema (system call) en el +kernel. Este usa una convención de llamada diferente para llamadas al +sistema donde ``struct pt_regs`` es decodificado on-the-fly en un +envoltorio syscall que luego entrega el procesamiento al syscall real. Esto +significa que sólo aquellos parámetros que son realmente necesarios para +una syscall específica son pasados durante la entrada del syscall, en vez +de llenar en seis registros de CPU con contenido random del userspace todo +el tiempo (los cuales podrían causar serios problemas bajando la cadena de +llamadas). + +Más aún, reglas sobre cómo se debería acceder a la data pueden diferir +entre la data del kernel y la data de usuario. Esta es otra razón por la +cual llamar a ``sys_xyzzy()`` es generalmente una mala idea. + +Excepciones a esta regla están permitidas solamente en overrides +específicos de arquitectura, envoltorios de compatibilidad específicos de +arquitectura, u otro código en arch/. + + +Referencias y fuentes +--------------------- + + - Artículo LWN de Michael Kerrisk sobre el uso de argumentos flags en llamadas al + sistema: + https://lwn.net/Articles/585415/ + - Artículo LWN de Michael Kerrisk sobre cómo manejar flags desconocidos en una + llamada al sistema: https://lwn.net/Articles/588444/ + - Artículo LWN de Jake Edge describiendo restricciones en argumentos en + 64-bit system call: https://lwn.net/Articles/311630/ + - Par de artículos LWN de David Drysdale que describen la ruta de implementación + de llamadas al sistema en detalle para v3.14: + + - https://lwn.net/Articles/604287/ + - https://lwn.net/Articles/604515/ + + - Requerimientos arquitectura-específicos para llamadas al sistema son discutidos en el + :manpage:`syscall(2)` man-page: + http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES + - Recopilación de emails de Linus Torvalds discutiendo problemas con ``ioctl()``: + https://yarchive.net/comp/linux/ioctl.html + - "How to not invent kernel interfaces", Arnd Bergmann, + https://www.ukuug.org/events/linux2007/2007/papers/Bergmann.pdf + - Artículo LWN de Michael Kerrisk sobre evitar nuevos usos de CAP_SYS_ADMIN: + https://lwn.net/Articles/486306/ + - Recomendaciones de Andrew Morton que toda la información relacionada a una nueva + llamada al sistema debe venir en el mismo hilo de correos: + https://lore.kernel.org/r/20140724144747.3041b208832bbdf9fbce5d96@linux-foundation.org + - Recomendaciones de Michael Kerrisk que una nueva llamada al sistema debe venir + con un man-page: https://lore.kernel.org/r/CAKgNAkgMA39AfoSoA5Pe1r9N+ZzfYQNvNPvcRN7tOvRb8+v06Q@mail.gmail.com + - Sugerencias de Thomas Gleixner que conexiones x86 deben ir en commits + separados: https://lore.kernel.org/r/alpine.DEB.2.11.1411191249560.3909@nanos + - Sugerencias de Greg Kroah-Hartman que es bueno para las nueva llamadas al sistema + que vengan con man-page y selftest: https://lore.kernel.org/r/20140320025530.GA25469@kroah.com + - Discusión de Michael Kerrisk de nuevas system call vs. extensiones :manpage:`prctl(2)`: + https://lore.kernel.org/r/CAHO5Pa3F2MjfTtfNxa8LbnkeeU8=YJ+9tDqxZpw7Gz59E-4AUg@mail.gmail.com + - Sugerencias de Ingo Molnar que llamadas al sistema que involucran múltiples + argumentos deben encapsular estos argumentos en una estructura, la cual incluye + un campo de tamaño para futura extensibilidad: https://lore.kernel.org/r/20150730083831.GA22182@gmail.com + - Enumerando rarezas por la (re-)utilización de O_* numbering space flags: + + - commit 75069f2b5bfb ("vfs: renumber FMODE_NONOTIFY and add to uniqueness + check") + - commit 12ed2e36c98a ("fanotify: FMODE_NONOTIFY and __O_SYNC in sparc + conflict") + - commit bb458c644a59 ("Safer ABI for O_TMPFILE") + + - Discusión de Matthew Wilcox sobre las restricciones en argumentos 64-bit: + https://lore.kernel.org/r/20081212152929.GM26095@parisc-linux.org + - Recomendaciones de Greg Kroah-Hartman sobre flags desconocidos deben ser + vigilados: https://lore.kernel.org/r/20140717193330.GB4703@kroah.com + - Recomendaciones de Linus Torvalds que las llamadas al sistema x32 deben favorecer + compatibilidad con versiones 64-bit sobre versiones 32-bit: + https://lore.kernel.org/r/CA+55aFxfmwfB7jbbrXxa=K7VBYPfAvmu3XOkGrLbB1UFjX1+Ew@mail.gmail.com diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst index 3b0c32593726..0bdeb1eb4403 100644 --- a/Documentation/translations/sp_SP/process/index.rst +++ b/Documentation/translations/sp_SP/process/index.rst @@ -19,3 +19,4 @@ magic-number programming-language deprecated + adding-syscalls diff --git a/Documentation/translations/sp_SP/process/magic-number.rst b/Documentation/translations/sp_SP/process/magic-number.rst index 2b62cec34e8e..7c7dfb4ba80b 100644 --- a/Documentation/translations/sp_SP/process/magic-number.rst +++ b/Documentation/translations/sp_SP/process/magic-number.rst @@ -77,7 +77,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` diff --git a/Documentation/translations/zh_CN/accounting/delay-accounting.rst b/Documentation/translations/zh_CN/accounting/delay-accounting.rst index a01dc3d5b0db..7b8693ccf80a 100644 --- a/Documentation/translations/zh_CN/accounting/delay-accounting.rst +++ b/Documentation/translations/zh_CN/accounting/delay-accounting.rst @@ -92,15 +92,15 @@ getdelays命令的一般格式:: CPU count real total virtual total delay total delay average 8 7000000 6872122 3382277 0.423ms IO count delay total delay average - 0 0 0ms + 0 0 0.000ms SWAP count delay total delay average - 0 0 0ms + 0 0 0.000ms RECLAIM count delay total delay average - 0 0 0ms + 0 0 0.000ms THRASHING count delay total delay average - 0 0 0ms + 0 0 0.000ms COMPACT count delay total delay average - 0 0 0ms + 0 0 0.000ms WPCOPY count delay total delay average 0 0 0ms diff --git a/Documentation/translations/zh_CN/core-api/kernel-api.rst b/Documentation/translations/zh_CN/core-api/kernel-api.rst index a4b373c48c0c..a1ea7081077c 100644 --- a/Documentation/translations/zh_CN/core-api/kernel-api.rst +++ b/Documentation/translations/zh_CN/core-api/kernel-api.rst @@ -226,7 +226,7 @@ kernel/relay.c 该API在以下内核代码中: -kernel/kmod.c +kernel/module/kmod.c 模块接口支持 ------------ diff --git a/Documentation/translations/zh_CN/filesystems/sysfs.txt b/Documentation/translations/zh_CN/filesystems/sysfs.txt index 046cc1d52058..547062759e60 100644 --- a/Documentation/translations/zh_CN/filesystems/sysfs.txt +++ b/Documentation/translations/zh_CN/filesystems/sysfs.txt @@ -329,8 +329,8 @@ void device_remove_file(struct device *dev, const struct device_attribute * attr struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(const struct bus_type *, char * buf); + ssize_t (*store)(const struct bus_type *, const char * buf, size_t count); }; 声明: diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 0617ce125e12..4a92ebb619ee 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -25,7 +25,7 @@ Linux 魔术数 ... }; -当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,‪这些情况可以被快速地,安全地避免。 +当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,这些情况可以被快速地,安全地避免。 Theodore Ts'o 31 Mar 94 @@ -61,7 +61,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` diff --git a/Documentation/translations/zh_CN/scheduler/sched-arch.rst b/Documentation/translations/zh_CN/scheduler/sched-arch.rst index 754a15c6b60f..ce3f39d9b3cb 100644 --- a/Documentation/translations/zh_CN/scheduler/sched-arch.rst +++ b/Documentation/translations/zh_CN/scheduler/sched-arch.rst @@ -70,7 +70,5 @@ arch/x86/kernel/process.c有轮询和睡眠空闲函数的例子。 ia64 - safe_halt的调用与中断相比,是否很荒谬? (它睡眠了吗) (参考 #4a) -sh64 - 睡眠与中断相比,是否很荒谬? (参考 #4a) - sparc - 在这一点上,IRQ是开着的(?),把local_irq_save改为_disable。 - 待办事项: 需要第二个CPU来禁用抢占 (参考 #1) diff --git a/Documentation/translations/zh_TW/filesystems/sysfs.txt b/Documentation/translations/zh_TW/filesystems/sysfs.txt index acd677f19d4f..280824cc7e5d 100644 --- a/Documentation/translations/zh_TW/filesystems/sysfs.txt +++ b/Documentation/translations/zh_TW/filesystems/sysfs.txt @@ -332,8 +332,8 @@ void device_remove_file(struct device *dev, const struct device_attribute * attr struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(const struct bus_type *, char * buf); + ssize_t (*store)(const struct bus_type *, const char * buf, size_t count); }; 聲明: diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst index f3f7082e17c6..c9e3db12c3f9 100644 --- a/Documentation/translations/zh_TW/process/magic-number.rst +++ b/Documentation/translations/zh_TW/process/magic-number.rst @@ -28,7 +28,7 @@ Linux 魔術數 ... }; -當你以後給內核添加增強功能的時候,請遵守這條規則!這樣就會節省數不清的調試時間,特別是一些古怪的情況,例如,數組超出範圍並且重新寫了超出部分。遵守這個規則,‪這些情況可以被快速地,安全地避免。 +當你以後給內核添加增強功能的時候,請遵守這條規則!這樣就會節省數不清的調試時間,特別是一些古怪的情況,例如,數組超出範圍並且重新寫了超出部分。遵守這個規則,這些情況可以被快速地,安全地避免。 Theodore Ts'o 31 Mar 94 @@ -64,7 +64,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/ APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h`` -MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h`` KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h`` diff --git a/Documentation/usb/gadget_uvc.rst b/Documentation/usb/gadget_uvc.rst index 6d22faceb1a0..62bd81ba3dd1 100644 --- a/Documentation/usb/gadget_uvc.rst +++ b/Documentation/usb/gadget_uvc.rst @@ -275,6 +275,34 @@ out with 0x00, for example: bNrInPins and baSourceID function in the same way. +Configuring Supported Controls for Camera Terminal and Processing Unit +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Camera Terminal and Processing Units in the UVC chain also have bmControls +attributes which function similarly to the same field in an Extension Unit. +Unlike XUs however, the meaning of the bitflag for these units is defined in +the UVC specification; you should consult the "Camera Terminal Descriptor" and +"Processing Unit Descriptor" sections for an enumeration of the flags. + +.. code-block:: bash + + # Set the Processing Unit's bmControls, flagging Brightness, Contrast + # and Hue as available controls: + echo 0x05 > $FUNCTION/control/processing/default/bmControls + + # Set the Camera Terminal's bmControls, flagging Focus Absolute and + # Focus Relative as available controls: + echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls + +If you do not set these fields then by default the Auto-Exposure Mode control +for the Camera Terminal and the Brightness control for the Processing Unit will +be flagged as available; if they are not supported you should set the field to +0x00. + +Note that the size of the bmControls field for a Camera Terminal or Processing +Unit is fixed by the UVC specification, and so the bControlSize attribute is +read-only here. + Custom Strings Support ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 0a1882e296ae..4f7b23faebb9 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -222,7 +222,6 @@ Code Seq# Include File Comments 'b' 00-FF conflict! bit3 vme host bridge 'b' 00-0F linux/dma-buf.h conflict! -'c' all linux/cm4000_cs.h conflict! 'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/coda.h conflict! 'c' 00-1F linux/chio.h conflict! @@ -364,7 +363,7 @@ Code Seq# Include File Comments 0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver 0xCD 01 linux/reiserfs_fs.h 0xCE 01-02 uapi/linux/cxl_mem.h Compute Express Link Memory Devices -0xCF 02 fs/cifs/ioctl.c +0xCF 02 fs/smb/client/cifs_ioctl.h 0xDB 00-0F drivers/char/mwave/mwavepub.h 0xDD 00-3F ZFCP device driver see drivers/s390/scsi/ diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 841e9d1987bd..add067793b90 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5645,7 +5645,8 @@ with the KVM_XEN_VCPU_GET_ATTR ioctl. }; Copies Memory Tagging Extension (MTE) tags to/from guest tag memory. The -``guest_ipa`` and ``length`` fields must be ``PAGE_SIZE`` aligned. The ``addr`` +``guest_ipa`` and ``length`` fields must be ``PAGE_SIZE`` aligned. +``length`` must not be bigger than 2^31 - PAGE_SIZE bytes. The ``addr`` field must point to a buffer which the tags will be copied to or from. ``flags`` specifies the direction of copy, either ``KVM_ARM_TAGS_TO_GUEST`` or @@ -6029,6 +6030,44 @@ delivery must be provided via the "reg_aen" struct. The "pad" and "reserved" fields may be used for future extensions and should be set to 0s by userspace. +4.138 KVM_ARM_SET_COUNTER_OFFSET +-------------------------------- + +:Capability: KVM_CAP_COUNTER_OFFSET +:Architectures: arm64 +:Type: vm ioctl +:Parameters: struct kvm_arm_counter_offset (in) +:Returns: 0 on success, < 0 on error + +This capability indicates that userspace is able to apply a single VM-wide +offset to both the virtual and physical counters as viewed by the guest +using the KVM_ARM_SET_CNT_OFFSET ioctl and the following data structure: + +:: + + struct kvm_arm_counter_offset { + __u64 counter_offset; + __u64 reserved; + }; + +The offset describes a number of counter cycles that are subtracted from +both virtual and physical counter views (similar to the effects of the +CNTVOFF_EL2 and CNTPOFF_EL2 system registers, but only global). The offset +always applies to all vcpus (already created or created after this ioctl) +for this VM. + +It is userspace's responsibility to compute the offset based, for example, +on previous values of the guest counters. + +Any value other than 0 for the "reserved" field may result in an error +(-EINVAL) being returned. This ioctl can also return -EBUSY if any vcpu +ioctl is issued concurrently. + +Note that using this ioctl results in KVM ignoring subsequent userspace +writes to the CNTVCT_EL0 and CNTPCT_EL0 registers using the SET_ONE_REG +interface. No error will be returned, but the resulting offset will not be +applied. + 5. The kvm_run structure ======================== @@ -6218,15 +6257,40 @@ to the byte array. __u64 nr; __u64 args[6]; __u64 ret; - __u32 longmode; - __u32 pad; + __u64 flags; } hypercall; -Unused. This was once used for 'hypercall to userspace'. To implement -such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390). + +It is strongly recommended that userspace use ``KVM_EXIT_IO`` (x86) or +``KVM_EXIT_MMIO`` (all except s390) to implement functionality that +requires a guest to interact with host userpace. .. note:: KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO. +For arm64: +---------- + +SMCCC exits can be enabled depending on the configuration of the SMCCC +filter. See the Documentation/virt/kvm/devices/vm.rst +``KVM_ARM_SMCCC_FILTER`` for more details. + +``nr`` contains the function ID of the guest's SMCCC call. Userspace is +expected to use the ``KVM_GET_ONE_REG`` ioctl to retrieve the call +parameters from the vCPU's GPRs. + +Definition of ``flags``: + - ``KVM_HYPERCALL_EXIT_SMC``: Indicates that the guest used the SMC + conduit to initiate the SMCCC call. If this bit is 0 then the guest + used the HVC conduit for the SMCCC call. + + - ``KVM_HYPERCALL_EXIT_16BIT``: Indicates that the guest used a 16bit + instruction to initiate the SMCCC call. If this bit is 0 then the + guest used a 32bit instruction. An AArch64 guest always has this + bit set to 0. + +At the point of exit, PC points to the instruction immediately following +the trapping instruction. + :: /* KVM_EXIT_TPR_ACCESS */ @@ -7266,6 +7330,7 @@ and injected exceptions. will clear DR6.RTM. 7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 +-------------------------------------- :Architectures: x86, arm64, mips :Parameters: args[0] whether feature should be enabled or not diff --git a/Documentation/virt/kvm/devices/vfio.rst b/Documentation/virt/kvm/devices/vfio.rst index 2d20dc561069..08b544212638 100644 --- a/Documentation/virt/kvm/devices/vfio.rst +++ b/Documentation/virt/kvm/devices/vfio.rst @@ -39,3 +39,8 @@ KVM_DEV_VFIO_GROUP attributes: - @groupfd is a file descriptor for a VFIO group; - @tablefd is a file descriptor for a TCE table allocated via KVM_CREATE_SPAPR_TCE. + +The GROUP_ADD operation above should be invoked prior to accessing the +device file descriptor via VFIO_GROUP_GET_DEVICE_FD in order to support +drivers which require a kvm pointer to be set in their .open_device() +callback. diff --git a/Documentation/virt/kvm/devices/vm.rst b/Documentation/virt/kvm/devices/vm.rst index 147efec626e5..9d726e60ec47 100644 --- a/Documentation/virt/kvm/devices/vm.rst +++ b/Documentation/virt/kvm/devices/vm.rst @@ -321,3 +321,82 @@ Allows userspace to query the status of migration mode. if it is enabled :Returns: -EFAULT if the given address is not accessible from kernel space; 0 in case of success. + +6. GROUP: KVM_ARM_VM_SMCCC_CTRL +=============================== + +:Architectures: arm64 + +6.1. ATTRIBUTE: KVM_ARM_VM_SMCCC_FILTER (w/o) +--------------------------------------------- + +:Parameters: Pointer to a ``struct kvm_smccc_filter`` + +:Returns: + + ====== =========================================== + EEXIST Range intersects with a previously inserted + or reserved range + EBUSY A vCPU in the VM has already run + EINVAL Invalid filter configuration + ENOMEM Failed to allocate memory for the in-kernel + representation of the SMCCC filter + ====== =========================================== + +Requests the installation of an SMCCC call filter described as follows:: + + enum kvm_smccc_filter_action { + KVM_SMCCC_FILTER_HANDLE = 0, + KVM_SMCCC_FILTER_DENY, + KVM_SMCCC_FILTER_FWD_TO_USER, + }; + + struct kvm_smccc_filter { + __u32 base; + __u32 nr_functions; + __u8 action; + __u8 pad[15]; + }; + +The filter is defined as a set of non-overlapping ranges. Each +range defines an action to be applied to SMCCC calls within the range. +Userspace can insert multiple ranges into the filter by using +successive calls to this attribute. + +The default configuration of KVM is such that all implemented SMCCC +calls are allowed. Thus, the SMCCC filter can be defined sparsely +by userspace, only describing ranges that modify the default behavior. + +The range expressed by ``struct kvm_smccc_filter`` is +[``base``, ``base + nr_functions``). The range is not allowed to wrap, +i.e. userspace cannot rely on ``base + nr_functions`` overflowing. + +The SMCCC filter applies to both SMC and HVC calls initiated by the +guest. The SMCCC filter gates the in-kernel emulation of SMCCC calls +and as such takes effect before other interfaces that interact with +SMCCC calls (e.g. hypercall bitmap registers). + +Actions: + + - ``KVM_SMCCC_FILTER_HANDLE``: Allows the guest SMCCC call to be + handled in-kernel. It is strongly recommended that userspace *not* + explicitly describe the allowed SMCCC call ranges. + + - ``KVM_SMCCC_FILTER_DENY``: Rejects the guest SMCCC call in-kernel + and returns to the guest. + + - ``KVM_SMCCC_FILTER_FWD_TO_USER``: The guest SMCCC call is forwarded + to userspace with an exit reason of ``KVM_EXIT_HYPERCALL``. + +The ``pad`` field is reserved for future use and must be zero. KVM may +return ``-EINVAL`` if the field is nonzero. + +KVM reserves the 'Arm Architecture Calls' range of function IDs and +will reject attempts to define a filter for any portion of these ranges: + + =========== =============== + Start End (inclusive) + =========== =============== + 0x8000_0000 0x8000_FFFF + 0xC000_0000 0xC000_FFFF + =========== =============== diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst index 14c4e9fa501d..8c77554e4896 100644 --- a/Documentation/virt/kvm/locking.rst +++ b/Documentation/virt/kvm/locking.rst @@ -21,7 +21,7 @@ The acquisition orders for mutexes are as follows: - kvm->mn_active_invalidate_count ensures that pairs of invalidate_range_start() and invalidate_range_end() callbacks use the same memslots array. kvm->slots_lock and kvm->slots_arch_lock - are taken on the waiting side in install_new_memslots, so MMU notifiers + are taken on the waiting side when modifying memslots, so MMU notifiers must not take either kvm->slots_lock or kvm->slots_arch_lock. For SRCU: diff --git a/MAINTAINERS b/MAINTAINERS index eb555b57cec1..0dab9737ec16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -273,8 +273,8 @@ ABI/API L: linux-api@vger.kernel.org F: include/linux/syscalls.h F: kernel/sys_ni.c -X: include/uapi/ X: arch/*/include/uapi/ +X: include/uapi/ ABIT UGURU 1,2 HARDWARE MONITOR DRIVER M: Hans de Goede @@ -406,12 +406,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/acpi/arm64 -ACPI SERIAL MULTI INSTANTIATE DRIVER -M: Hans de Goede -L: platform-driver-x86@vger.kernel.org -S: Maintained -F: drivers/platform/x86/serial-multi-instantiate.c - ACPI PCC(Platform Communication Channel) MAILBOX DRIVER M: Sudeep Holla L: linux-acpi@vger.kernel.org @@ -430,6 +424,12 @@ B: https://bugzilla.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm F: drivers/acpi/pmic/ +ACPI SERIAL MULTI INSTANTIATE DRIVER +M: Hans de Goede +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/serial-multi-instantiate.c + ACPI THERMAL DRIVER M: Rafael J. Wysocki R: Zhang Rui @@ -823,6 +823,13 @@ L: linux-crypto@vger.kernel.org S: Maintained F: drivers/crypto/allwinner/ +ALLWINNER DMIC DRIVERS +M: Ban Tao +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml +F: sound/soc/sunxi/sun50i-dmic.c + ALLWINNER HARDWARE SPINLOCK SUPPORT M: Wilken Gottwalt S: Maintained @@ -844,13 +851,6 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/staging/media/sunxi/cedrus/ -ALLWINNER DMIC DRIVERS -M: Ban Tao -L: alsa-devel@alsa-project.org (moderated for non-subscribers) -S: Maintained -F: Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml -F: sound/soc/sunxi/sun50i-dmic.c - ALPHA PORT M: Richard Henderson M: Ivan Kokshaysky @@ -956,7 +956,8 @@ F: Documentation/networking/device_drivers/ethernet/amazon/ena.rst F: drivers/net/ethernet/amazon/ AMAZON RDMA EFA DRIVER -M: Gal Pressman +M: Michael Margolin +R: Gal Pressman R: Yossi Leybovich L: linux-rdma@vger.kernel.org S: Supported @@ -964,6 +965,14 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/ F: drivers/infiniband/hw/efa/ F: include/uapi/rdma/efa-abi.h +AMD CDX BUS DRIVER +M: Nipun Gupta +M: Nikhil Agarwal +S: Maintained +F: Documentation/devicetree/bindings/bus/xlnx,versal-net-cdx.yaml +F: drivers/cdx/* +F: include/linux/cdx/* + AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER M: Tom Lendacky M: John Allen @@ -1018,6 +1027,16 @@ F: drivers/char/hw_random/geode-rng.c F: drivers/crypto/geode* F: drivers/video/fbdev/geode/ +AMD HSMP DRIVER +M: Naveen Krishna Chatradhi +R: Carlos Bilbao +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: Documentation/arch/x86/amd_hsmp.rst +F: arch/x86/include/asm/amd_hsmp.h +F: arch/x86/include/uapi/asm/amd_hsmp.h +F: drivers/platform/x86/amd/hsmp.c + AMD IOMMU (AMD-VI) M: Joerg Roedel R: Suravee Suthikulpanit @@ -1041,6 +1060,13 @@ F: drivers/gpu/drm/amd/include/vi_structs.h F: include/uapi/linux/kfd_ioctl.h F: include/uapi/linux/kfd_sysfs.h +AMD MP2 I2C DRIVER +M: Elie Morisse +M: Shyam Sundar S K +L: linux-i2c@vger.kernel.org +S: Maintained +F: drivers/i2c/busses/i2c-amd-mp2* + AMD PDS CORE DRIVER M: Shannon Nelson M: Brett Creeley @@ -1050,18 +1076,6 @@ F: Documentation/networking/device_drivers/ethernet/amd/pds_core.rst F: drivers/net/ethernet/amd/pds_core/ F: include/linux/pds/ -AMD SPI DRIVER -M: Sanjay R Mehta -S: Maintained -F: drivers/spi/spi-amd.c - -AMD MP2 I2C DRIVER -M: Elie Morisse -M: Shyam Sundar S K -L: linux-i2c@vger.kernel.org -S: Maintained -F: drivers/i2c/busses/i2c-amd-mp2* - AMD PMC DRIVER M: Shyam Sundar S K L: platform-driver-x86@vger.kernel.org @@ -1075,16 +1089,6 @@ S: Maintained F: Documentation/ABI/testing/sysfs-amd-pmf F: drivers/platform/x86/amd/pmf/ -AMD HSMP DRIVER -M: Naveen Krishna Chatradhi -R: Carlos Bilbao -L: platform-driver-x86@vger.kernel.org -S: Maintained -F: Documentation/arch/x86/amd_hsmp.rst -F: arch/x86/include/asm/amd_hsmp.h -F: arch/x86/include/uapi/asm/amd_hsmp.h -F: drivers/platform/x86/amd/hsmp.c - AMD POWERPLAY AND SWSMU M: Evan Quan L: amd-gfx@lists.freedesktop.org @@ -1113,13 +1117,6 @@ M: Tom Lendacky S: Supported F: arch/arm64/boot/dts/amd/ -AMD XGBE DRIVER -M: "Shyam Sundar S K" -L: netdev@vger.kernel.org -S: Supported -F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi -F: drivers/net/ethernet/amd/xgbe/ - AMD SENSOR FUSION HUB DRIVER M: Basavaraj Natikar L: linux-input@vger.kernel.org @@ -1127,6 +1124,18 @@ S: Maintained F: Documentation/hid/amd-sfh* F: drivers/hid/amd-sfh-hid/ +AMD SPI DRIVER +M: Sanjay R Mehta +S: Maintained +F: drivers/spi/spi-amd.c + +AMD XGBE DRIVER +M: "Shyam Sundar S K" +L: netdev@vger.kernel.org +S: Supported +F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi +F: drivers/net/ethernet/amd/xgbe/ + AMLOGIC DDR PMU DRIVER M: Jiucheng Xu L: linux-amlogic@lists.infradead.org @@ -1161,6 +1170,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: drivers/net/amt.c +ANALOG DEVICES INC AD3552R DRIVER +M: Nuno Sá +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +F: drivers/iio/dac/ad3552r.c + ANALOG DEVICES INC AD4130 DRIVER M: Cosmin Tanislav L: linux-iio@vger.kernel.org @@ -1186,14 +1203,6 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml F: drivers/iio/adc/ad7292.c -ANALOG DEVICES INC AD3552R DRIVER -M: Nuno Sá -L: linux-iio@vger.kernel.org -S: Supported -W: https://ez.analog.com/linux-software-drivers -F: Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml -F: drivers/iio/dac/ad3552r.c - ANALOG DEVICES INC AD7293 DRIVER M: Antoniu Miclaus L: linux-iio@vger.kernel.org @@ -1202,23 +1211,6 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml F: drivers/iio/dac/ad7293.c -ANALOG DEVICES INC AD7768-1 DRIVER -M: Michael Hennerich -L: linux-iio@vger.kernel.org -S: Supported -W: https://ez.analog.com/linux-software-drivers -F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml -F: drivers/iio/adc/ad7768-1.c - -ANALOG DEVICES INC AD7780 DRIVER -M: Michael Hennerich -M: Renato Lui Geh -L: linux-iio@vger.kernel.org -S: Supported -W: https://ez.analog.com/linux-software-drivers -F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml -F: drivers/iio/adc/ad7780.c - ANALOG DEVICES INC AD74115 DRIVER M: Cosmin Tanislav L: linux-iio@vger.kernel.org @@ -1236,6 +1228,23 @@ F: Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml F: drivers/iio/addac/ad74413r.c F: include/dt-bindings/iio/addac/adi,ad74413r.h +ANALOG DEVICES INC AD7768-1 DRIVER +M: Michael Hennerich +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml +F: drivers/iio/adc/ad7768-1.c + +ANALOG DEVICES INC AD7780 DRIVER +M: Michael Hennerich +M: Renato Lui Geh +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml +F: drivers/iio/adc/ad7780.c + ANALOG DEVICES INC ADA4250 DRIVER M: Antoniu Miclaus L: linux-iio@vger.kernel.org @@ -1286,10 +1295,10 @@ F: drivers/iio/imu/adis16460.c ANALOG DEVICES INC ADIS16475 DRIVER M: Nuno Sa L: linux-iio@vger.kernel.org -W: https://ez.analog.com/linux-software-drivers S: Supported -F: drivers/iio/imu/adis16475.c +W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +F: drivers/iio/imu/adis16475.c ANALOG DEVICES INC ADM1177 DRIVER M: Michael Hennerich @@ -1307,14 +1316,6 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/frequency/adi,admv1013.yaml F: drivers/iio/frequency/admv1013.c -ANALOG DEVICES INC ADMV8818 DRIVER -M: Antoniu Miclaus -L: linux-iio@vger.kernel.org -S: Supported -W: https://ez.analog.com/linux-software-drivers -F: Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml -F: drivers/iio/filter/admv8818.c - ANALOG DEVICES INC ADMV1014 DRIVER M: Antoniu Miclaus L: linux-iio@vger.kernel.org @@ -1323,6 +1324,14 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/frequency/adi,admv1014.yaml F: drivers/iio/frequency/admv1014.c +ANALOG DEVICES INC ADMV8818 DRIVER +M: Antoniu Miclaus +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/filter/adi,admv8818.yaml +F: drivers/iio/filter/admv8818.c + ANALOG DEVICES INC ADP5061 DRIVER M: Michael Hennerich L: linux-pm@vger.kernel.org @@ -1343,8 +1352,8 @@ M: Lars-Peter Clausen L: linux-media@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers -F: drivers/media/i2c/adv7180.c F: Documentation/devicetree/bindings/media/i2c/adv7180.yaml +F: drivers/media/i2c/adv7180.c ANALOG DEVICES INC ADV748X DRIVER M: Kieran Bingham @@ -1363,8 +1372,8 @@ ANALOG DEVICES INC ADV7604 DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -F: drivers/media/i2c/adv7604* F: Documentation/devicetree/bindings/media/i2c/adv7604.yaml +F: drivers/media/i2c/adv7604* ANALOG DEVICES INC ADV7842 DRIVER M: Hans Verkuil @@ -1376,8 +1385,8 @@ ANALOG DEVICES INC ADXRS290 DRIVER M: Nishant Malpani L: linux-iio@vger.kernel.org S: Supported -F: drivers/iio/gyro/adxrs290.c F: Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml +F: drivers/iio/gyro/adxrs290.c ANALOG DEVICES INC ASOC CODEC DRIVERS M: Lars-Peter Clausen @@ -1431,11 +1440,6 @@ S: Supported F: drivers/clk/analogbits/* F: include/linux/clk/analogbits* -ANDROID CONFIG FRAGMENTS -M: Rob Herring -S: Supported -F: kernel/configs/android* - ANDROID DRIVERS M: Greg Kroah-Hartman M: Arve Hjønnevåg @@ -1597,7 +1601,7 @@ F: drivers/media/i2c/ar0521.c ARASAN NAND CONTROLLER DRIVER M: Miquel Raynal -M: Naga Sureshkumar Relli +R: Michal Simek L: linux-mtd@lists.infradead.org S: Maintained F: Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml @@ -1622,6 +1626,17 @@ S: Maintained F: drivers/net/arcnet/ F: include/uapi/linux/if_arcnet.h +ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS) +M: Arnd Bergmann +M: Olof Johansson +M: soc@kernel.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +C: irc://irc.libera.chat/armlinux +T: git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git +F: arch/arm/boot/dts/Makefile +F: arch/arm64/boot/dts/Makefile + ARM ARCHITECTED TIMER DRIVER M: Mark Rutland M: Marc Zyngier @@ -1663,10 +1678,7 @@ F: drivers/power/reset/arm-versatile-reboot.c F: drivers/soc/versatile/ ARM KOMEDA DRM-KMS DRIVER -M: James (Qian) Wang M: Liviu Dudau -M: Mihail Atanassov -L: Mali DP Maintainers S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/arm,komeda.yaml @@ -1687,8 +1699,6 @@ F: include/uapi/drm/panfrost_drm.h ARM MALI-DP DRM DRIVER M: Liviu Dudau -M: Brian Starkey -L: Mali DP Maintainers S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/arm,malidp.yaml @@ -1735,22 +1745,6 @@ S: Odd Fixes F: drivers/amba/ F: include/linux/amba/bus.h -ARM PRIMECELL PL35X NAND CONTROLLER DRIVER -M: Miquel Raynal -M: Naga Sureshkumar Relli -L: linux-mtd@lists.infradead.org -S: Maintained -F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml -F: drivers/mtd/nand/raw/pl35x-nand-controller.c - -ARM PRIMECELL PL35X SMC DRIVER -M: Miquel Raynal -M: Naga Sureshkumar Relli -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml -F: drivers/memory/pl353-smc.c - ARM PRIMECELL CLCD PL110 DRIVER M: Russell King S: Odd Fixes @@ -1768,6 +1762,22 @@ S: Odd Fixes F: drivers/mmc/host/mmci.* F: include/linux/amba/mmci.h +ARM PRIMECELL PL35X NAND CONTROLLER DRIVER +M: Miquel Raynal +R: Michal Simek +L: linux-mtd@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml +F: drivers/mtd/nand/raw/pl35x-nand-controller.c + +ARM PRIMECELL PL35X SMC DRIVER +M: Miquel Raynal +R: Michal Simek +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml +F: drivers/memory/pl353-smc.c + ARM PRIMECELL SSP PL022 SPI DRIVER M: Linus Walleij L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -1804,17 +1814,6 @@ F: Documentation/devicetree/bindings/iommu/arm,smmu* F: drivers/iommu/arm/ F: drivers/iommu/io-pgtable-arm* -ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS) -M: Arnd Bergmann -M: Olof Johansson -M: soc@kernel.org -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -C: irc://irc.libera.chat/armlinux -T: git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git -F: arch/arm/boot/dts/Makefile -F: arch/arm64/boot/dts/Makefile - ARM SUB-ARCHITECTURES L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -1866,9 +1865,9 @@ M: Chen-Yu Tsai M: Jernej Skrabec M: Samuel Holland L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-sunxi@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git -L: linux-sunxi@lists.linux.dev F: arch/arm/mach-sunxi/ F: arch/arm64/boot/dts/allwinner/ F: drivers/clk/sunxi-ng/ @@ -1931,6 +1930,15 @@ F: arch/arm/mach-alpine/ F: arch/arm64/boot/dts/amazon/ F: drivers/*/*alpine* +ARM/APPLE MACHINE SOUND DRIVERS +M: Martin Povišer +L: asahi@lists.linux.dev +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/sound/apple,* +F: sound/soc/apple/* +F: sound/soc/codecs/cs42l83-i2c.c + ARM/APPLE MACHINE SUPPORT M: Hector Martin M: Sven Peter @@ -1958,6 +1966,7 @@ F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml F: Documentation/devicetree/bindings/pci/apple,pcie.yaml F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml F: Documentation/devicetree/bindings/power/apple* +F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml F: arch/arm64/boot/dts/apple/ F: drivers/bluetooth/hci_bcm4377.c @@ -1973,6 +1982,7 @@ F: drivers/mailbox/apple-mailbox.c F: drivers/nvme/host/apple.c F: drivers/nvmem/apple-efuses.c F: drivers/pinctrl/pinctrl-apple-gpio.c +F: drivers/pwm/pwm-apple.c F: drivers/soc/apple/* F: drivers/watchdog/apple_wdt.c F: include/dt-bindings/interrupt-controller/apple-aic.h @@ -1980,15 +1990,6 @@ F: include/dt-bindings/pinctrl/apple.h F: include/linux/apple-mailbox.h F: include/linux/soc/apple/* -ARM/APPLE MACHINE SOUND DRIVERS -M: Martin Povišer -L: asahi@lists.linux.dev -L: alsa-devel@alsa-project.org (moderated for non-subscribers) -S: Maintained -F: Documentation/devicetree/bindings/sound/apple,* -F: sound/soc/apple/* -F: sound/soc/codecs/cs42l83-i2c.c - ARM/ARTPEC MACHINE SUPPORT M: Jesper Nilsson M: Lars Persson @@ -2095,7 +2096,6 @@ F: arch/arm/boot/dts/cx92755* N: digicolor ARM/CORESIGHT FRAMEWORK AND DRIVERS -M: Mathieu Poirier M: Suzuki K Poulose R: Mike Leach R: Leo Yan @@ -2105,19 +2105,19 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git F: Documentation/ABI/testing/sysfs-bus-coresight-devices-* F: Documentation/devicetree/bindings/arm/arm,coresight-*.yaml -F: Documentation/devicetree/bindings/arm/qcom,coresight-*.yaml F: Documentation/devicetree/bindings/arm/arm,embedded-trace-extension.yaml F: Documentation/devicetree/bindings/arm/arm,trace-buffer-extension.yaml +F: Documentation/devicetree/bindings/arm/qcom,coresight-*.yaml F: Documentation/trace/coresight/* F: drivers/hwtracing/coresight/* F: include/dt-bindings/arm/coresight-cti-dt.h F: include/linux/coresight* F: samples/coresight/* -F: tools/perf/tests/shell/coresight/* F: tools/perf/arch/arm/util/auxtrace.c F: tools/perf/arch/arm/util/cs-etm.c F: tools/perf/arch/arm/util/cs-etm.h F: tools/perf/arch/arm/util/pmu.c +F: tools/perf/tests/shell/coresight/* F: tools/perf/util/cs-etm-decoder/* F: tools/perf/util/cs-etm.* @@ -2152,9 +2152,9 @@ F: Documentation/devicetree/bindings/leds/cznic,turris-omnia-leds.yaml F: Documentation/devicetree/bindings/watchdog/armada-37xx-wdt.txt F: drivers/bus/moxtet.c F: drivers/firmware/turris-mox-rwtm.c +F: drivers/gpio/gpio-moxtet.c F: drivers/leds/leds-turris-omnia.c F: drivers/mailbox/armada-37xx-rwtm-mailbox.c -F: drivers/gpio/gpio-moxtet.c F: drivers/watchdog/armada_37xx_wdt.c F: include/dt-bindings/bus/moxtet.h F: include/linux/armada-37xx-rwtm-mailbox.h @@ -2184,10 +2184,10 @@ R: NXP Linux Team L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git -X: drivers/media/i2c/ F: arch/arm64/boot/dts/freescale/ X: arch/arm64/boot/dts/freescale/fsl-* X: arch/arm64/boot/dts/freescale/qoriq-* +X: drivers/media/i2c/ N: imx N: mxs @@ -2241,12 +2241,12 @@ ARM/HPE GXP ARCHITECTURE M: Jean-Marie Verdun M: Nick Hawkins S: Maintained -F: Documentation/hwmon/gxp-fan-ctrl.rst F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml F: Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml F: Documentation/devicetree/bindings/i2c/hpe,gxp-i2c.yaml F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml +F: Documentation/hwmon/gxp-fan-ctrl.rst F: arch/arm/boot/dts/hpe-bmc* F: arch/arm/boot/dts/hpe-gxp* F: arch/arm/mach-hpe/ @@ -2271,9 +2271,9 @@ M: Krzysztof Halasa L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml -F: Documentation/devicetree/bindings/memory-controllers/intel,ixp4xx-expansion* F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt F: Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml +F: Documentation/devicetree/bindings/memory-controllers/intel,ixp4xx-expansion* F: Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml F: arch/arm/boot/dts/intel-ixp* F: arch/arm/mach-ixp4xx/ @@ -2430,6 +2430,15 @@ X: drivers/net/wireless/atmel/ N: at91 N: atmel +ARM/MICROCHIP (ARM64) SoC support +M: Conor Dooley +M: Nicolas Ferre +M: Claudiu Beznea +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Supported +T: git https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git +F: arch/arm64/boot/dts/microchip/ + ARM/Microchip Sparx5 SoC support M: Lars Povlsen M: Steen Hegelund @@ -2437,19 +2446,11 @@ M: Daniel Machon M: UNGLinuxDriver@microchip.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported -T: git git://github.com/microchip-ung/linux-upstream.git -F: arch/arm64/boot/dts/microchip/ +F: arch/arm64/boot/dts/microchip/sparx* F: drivers/net/ethernet/microchip/vcap/ F: drivers/pinctrl/pinctrl-microchip-sgpio.c N: sparx5 -Microchip Timer Counter Block (TCB) Capture Driver -M: Kamel Bouhara -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -L: linux-iio@vger.kernel.org -S: Maintained -F: drivers/counter/microchip-tcb-capture.c - ARM/MILBEAUT ARCHITECTURE M: Taichi Sugaya M: Takao Orito @@ -2521,8 +2522,8 @@ F: Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml F: arch/arm/boot/dts/nuvoton-npcm* F: arch/arm/mach-npcm/ F: arch/arm64/boot/dts/nuvoton/ -F: drivers/*/*npcm* F: drivers/*/*/*npcm* +F: drivers/*/*npcm* F: drivers/rtc/rtc-nct3018y.c F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h F: include/dt-bindings/clock/nuvoton,npcm845-clk.h @@ -2565,6 +2566,12 @@ F: arch/arm/mach-oxnas/ F: drivers/power/reset/oxnas-restart.c N: oxnas +ARM/QUALCOMM CHROMEBOOK SUPPORT +R: cros-qcom-dts-watchers@chromium.org +F: arch/arm64/boot/dts/qcom/sc7180* +F: arch/arm64/boot/dts/qcom/sc7280* +F: arch/arm64/boot/dts/qcom/sdm845-cheza* + ARM/QUALCOMM SUPPORT M: Andy Gross M: Bjorn Andersson @@ -2598,22 +2605,16 @@ F: drivers/pci/controller/dwc/pcie-qcom.c F: drivers/phy/qualcomm/ F: drivers/power/*/msm* F: drivers/reset/reset-qcom-* -F: drivers/ufs/host/ufs-qcom* F: drivers/spi/spi-geni-qcom.c F: drivers/spi/spi-qcom-qspi.c F: drivers/spi/spi-qup.c F: drivers/tty/serial/msm_serial.c +F: drivers/ufs/host/ufs-qcom* F: drivers/usb/dwc3/dwc3-qcom.c F: include/dt-bindings/*/qcom* F: include/linux/*/qcom* F: include/linux/soc/qcom/ -ARM/QUALCOMM CHROMEBOOK SUPPORT -R: cros-qcom-dts-watchers@chromium.org -F: arch/arm64/boot/dts/qcom/sc7180* -F: arch/arm64/boot/dts/qcom/sc7280* -F: arch/arm64/boot/dts/qcom/sdm845-cheza* - ARM/RDA MICRO ARCHITECTURE M: Manivannan Sadhasivam L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2705,9 +2706,9 @@ R: Alim Akhtar L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org S: Maintained -C: irc://irc.libera.chat/linux-exynos Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/ B: mailto:linux-samsung-soc@vger.kernel.org +C: irc://irc.libera.chat/linux-exynos T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git F: Documentation/arm/samsung/ F: Documentation/devicetree/bindings/arm/samsung/ @@ -2807,8 +2808,8 @@ M: Patrice Chotard L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://www.stlinux.com -F: Documentation/devicetree/bindings/spi/st,ssc-spi.yaml F: Documentation/devicetree/bindings/i2c/st,sti-i2c.yaml +F: Documentation/devicetree/bindings/spi/st,ssc-spi.yaml F: arch/arm/boot/dts/sti* F: arch/arm/mach-sti/ F: drivers/ata/ahci_st.c @@ -2860,6 +2861,7 @@ F: Documentation/devicetree/bindings/reset/sunplus,reset.yaml F: arch/arm/boot/dts/sunplus-sp7021*.dts* F: arch/arm/configs/sp7021_*defconfig F: arch/arm/mach-sunplus/ +F: drivers/clk/clk-sp7021.c F: drivers/irqchip/irq-sp7021-intc.c F: drivers/reset/reset-sunplus.c F: include/dt-bindings/clock/sunplus,sp7021-clkc.h @@ -2954,15 +2956,15 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git F: Documentation/devicetree/bindings/arm/toshiba.yaml F: Documentation/devicetree/bindings/clock/toshiba,tmpv770x-pipllct.yaml F: Documentation/devicetree/bindings/clock/toshiba,tmpv770x-pismu.yaml -F: Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml F: Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml +F: Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml F: Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml F: Documentation/devicetree/bindings/pinctrl/toshiba,visconti-pinctrl.yaml F: Documentation/devicetree/bindings/watchdog/toshiba,visconti-wdt.yaml F: arch/arm64/boot/dts/toshiba/ F: drivers/clk/visconti/ -F: drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c F: drivers/gpio/gpio-visconti.c +F: drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c F: drivers/pci/controller/dwc/pcie-visconti.c F: drivers/pinctrl/visconti/ F: drivers/watchdog/visconti_wdt.c @@ -3034,7 +3036,7 @@ F: drivers/video/fbdev/wm8505fb* F: drivers/video/fbdev/wmt_ge_rops.* ARM/ZYNQ ARCHITECTURE -M: Michal Simek +M: Michal Simek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported W: http://wiki.xilinx.com @@ -3107,6 +3109,13 @@ S: Maintained F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml F: drivers/net/ethernet/asix/ax88796c_* +ASPEED CRYPTO DRIVER +M: Neal Liu +L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/crypto/aspeed,* +F: drivers/crypto/aspeed/ + ASPEED PECI CONTROLLER M: Iwona Winiarska L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) @@ -3151,6 +3160,13 @@ S: Maintained F: Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml F: drivers/spi/spi-aspeed-smc.c +ASPEED USB UDC DRIVER +M: Neal Liu +L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml +F: drivers/usb/gadget/udc/aspeed_udc.c + ASPEED VIDEO ENGINE DRIVER M: Eddie James L: linux-media@vger.kernel.org @@ -3159,19 +3175,11 @@ S: Maintained F: Documentation/devicetree/bindings/media/aspeed-video.txt F: drivers/media/platform/aspeed/ -ASPEED USB UDC DRIVER -M: Neal Liu -L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) +ASUS EC HARDWARE MONITOR DRIVER +M: Eugene Shalygin +L: linux-hwmon@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml -F: drivers/usb/gadget/udc/aspeed_udc.c - -ASPEED CRYPTO DRIVER -M: Neal Liu -L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) -S: Maintained -F: Documentation/devicetree/bindings/crypto/aspeed,* -F: drivers/crypto/aspeed/ +F: drivers/hwmon/asus-ec-sensors.c ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary @@ -3189,6 +3197,12 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git F: drivers/platform/x86/asus-tf103c-dock.c +ASUS WIRELESS RADIO CONTROL DRIVER +M: João Paulo Rechi Vita +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/asus-wireless.c + ASUS WMI HARDWARE MONITOR DRIVER M: Ed Brindley M: Denis Pauk @@ -3196,18 +3210,6 @@ L: linux-hwmon@vger.kernel.org S: Maintained F: drivers/hwmon/asus_wmi_sensors.c -ASUS EC HARDWARE MONITOR DRIVER -M: Eugene Shalygin -L: linux-hwmon@vger.kernel.org -S: Maintained -F: drivers/hwmon/asus-ec-sensors.c - -ASUS WIRELESS RADIO CONTROL DRIVER -M: João Paulo Rechi Vita -L: platform-driver-x86@vger.kernel.org -S: Maintained -F: drivers/platform/x86/asus-wireless.c - ASYMMETRIC KEYS M: David Howells L: keyrings@vger.kernel.org @@ -3347,10 +3349,10 @@ R: Boqun Feng R: Mark Rutland L: linux-kernel@vger.kernel.org S: Maintained +F: Documentation/atomic_*.txt F: arch/*/include/asm/atomic*.h F: include/*/atomic*.h F: include/linux/refcount.h -F: Documentation/atomic_*.txt F: scripts/atomic/ ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER @@ -3543,7 +3545,7 @@ F: Documentation/filesystems/befs.rst F: fs/befs/ BFQ I/O SCHEDULER -M: Paolo Valente +M: Paolo Valente M: Jens Axboe L: linux-block@vger.kernel.org S: Maintained @@ -3644,50 +3646,6 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* -BPF [GENERAL] (Safe Dynamic Programs and Tools) -M: Alexei Starovoitov -M: Daniel Borkmann -M: Andrii Nakryiko -R: Martin KaFai Lau -R: Song Liu -R: Yonghong Song -R: John Fastabend -R: KP Singh -R: Stanislav Fomichev -R: Hao Luo -R: Jiri Olsa -L: bpf@vger.kernel.org -S: Supported -W: https://bpf.io/ -Q: https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173 -T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git -F: Documentation/bpf/ -F: Documentation/networking/filter.rst -F: Documentation/userspace-api/ebpf/ -F: arch/*/net/* -F: include/linux/bpf* -F: include/linux/btf* -F: include/linux/filter.h -F: include/trace/events/xdp.h -F: include/uapi/linux/bpf* -F: include/uapi/linux/btf* -F: include/uapi/linux/filter.h -F: kernel/bpf/ -F: kernel/trace/bpf_trace.c -F: lib/test_bpf.c -F: net/bpf/ -F: net/core/filter.c -F: net/sched/act_bpf.c -F: net/sched/cls_bpf.c -F: samples/bpf/ -F: scripts/bpf_doc.py -F: scripts/pahole-flags.sh -F: scripts/pahole-version.sh -F: tools/bpf/ -F: tools/lib/bpf/ -F: tools/testing/selftests/bpf/ - BPF JIT for ARM M: Shubham Bansal L: bpf@vger.kernel.org @@ -3766,79 +3724,79 @@ S: Supported F: arch/x86/net/ X: arch/x86/net/bpf_jit_comp32.c +BPF [BTF] +M: Martin KaFai Lau +L: bpf@vger.kernel.org +S: Maintained +F: include/linux/btf* +F: kernel/bpf/btf.c + BPF [CORE] M: Alexei Starovoitov M: Daniel Borkmann R: John Fastabend L: bpf@vger.kernel.org S: Maintained -F: kernel/bpf/verifier.c -F: kernel/bpf/tnum.c -F: kernel/bpf/core.c -F: kernel/bpf/syscall.c -F: kernel/bpf/dispatcher.c -F: kernel/bpf/trampoline.c F: include/linux/bpf* F: include/linux/filter.h F: include/linux/tnum.h +F: kernel/bpf/core.c +F: kernel/bpf/dispatcher.c +F: kernel/bpf/syscall.c +F: kernel/bpf/tnum.c +F: kernel/bpf/trampoline.c +F: kernel/bpf/verifier.c -BPF [BTF] -M: Martin KaFai Lau +BPF [DOCUMENTATION] (Related to Standardization) +R: David Vernet L: bpf@vger.kernel.org +L: bpf@ietf.org S: Maintained -F: kernel/bpf/btf.c -F: include/linux/btf* +F: Documentation/bpf/instruction-set.rst -BPF [TRACING] -M: Song Liu +BPF [GENERAL] (Safe Dynamic Programs and Tools) +M: Alexei Starovoitov +M: Daniel Borkmann +M: Andrii Nakryiko +R: Martin KaFai Lau +R: Song Liu +R: Yonghong Song +R: John Fastabend +R: KP Singh +R: Stanislav Fomichev +R: Hao Luo R: Jiri Olsa L: bpf@vger.kernel.org -S: Maintained +S: Supported +W: https://bpf.io/ +Q: https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173 +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git +F: Documentation/bpf/ +F: Documentation/networking/filter.rst +F: Documentation/userspace-api/ebpf/ +F: arch/*/net/* +F: include/linux/bpf* +F: include/linux/btf* +F: include/linux/filter.h +F: include/trace/events/xdp.h +F: include/uapi/linux/bpf* +F: include/uapi/linux/btf* +F: include/uapi/linux/filter.h +F: kernel/bpf/ F: kernel/trace/bpf_trace.c -F: kernel/bpf/stackmap.c - -BPF [NETWORKING] (tc BPF, sock_addr) -M: Martin KaFai Lau -M: Daniel Borkmann -R: John Fastabend -L: bpf@vger.kernel.org -L: netdev@vger.kernel.org -S: Maintained +F: lib/test_bpf.c +F: net/bpf/ F: net/core/filter.c F: net/sched/act_bpf.c F: net/sched/cls_bpf.c - -BPF [NETWORKING] (struct_ops, reuseport) -M: Martin KaFai Lau -L: bpf@vger.kernel.org -L: netdev@vger.kernel.org -S: Maintained -F: kernel/bpf/bpf_struct* - -BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF) -M: KP Singh -R: Florent Revest -R: Brendan Jackman -L: bpf@vger.kernel.org -S: Maintained -F: Documentation/bpf/prog_lsm.rst -F: include/linux/bpf_lsm.h -F: kernel/bpf/bpf_lsm.c -F: security/bpf/ - -BPF [STORAGE & CGROUPS] -M: Martin KaFai Lau -L: bpf@vger.kernel.org -S: Maintained -F: kernel/bpf/cgroup.c -F: kernel/bpf/*storage.c -F: kernel/bpf/bpf_lru* - -BPF [RINGBUF] -M: Andrii Nakryiko -L: bpf@vger.kernel.org -S: Maintained -F: kernel/bpf/ringbuf.c +F: samples/bpf/ +F: scripts/bpf_doc.py +F: scripts/pahole-flags.sh +F: scripts/pahole-version.sh +F: tools/bpf/ +F: tools/lib/bpf/ +F: tools/testing/selftests/bpf/ BPF [ITERATOR] M: Yonghong Song @@ -3865,12 +3823,45 @@ L: bpf@vger.kernel.org S: Maintained F: tools/lib/bpf/ -BPF [TOOLING] (bpftool) -M: Quentin Monnet +BPF [MISC] +L: bpf@vger.kernel.org +S: Odd Fixes +K: (?:\b|_)bpf(?:\b|_) + +BPF [NETWORKING] (struct_ops, reuseport) +M: Martin KaFai Lau +L: bpf@vger.kernel.org +L: netdev@vger.kernel.org +S: Maintained +F: kernel/bpf/bpf_struct* + +BPF [NETWORKING] (tc BPF, sock_addr) +M: Martin KaFai Lau +M: Daniel Borkmann +R: John Fastabend +L: bpf@vger.kernel.org +L: netdev@vger.kernel.org +S: Maintained +F: net/core/filter.c +F: net/sched/act_bpf.c +F: net/sched/cls_bpf.c + +BPF [RINGBUF] +M: Andrii Nakryiko L: bpf@vger.kernel.org S: Maintained -F: kernel/bpf/disasm.* -F: tools/bpf/bpftool/ +F: kernel/bpf/ringbuf.c + +BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF) +M: KP Singh +R: Florent Revest +R: Brendan Jackman +L: bpf@vger.kernel.org +S: Maintained +F: Documentation/bpf/prog_lsm.rst +F: include/linux/bpf_lsm.h +F: kernel/bpf/bpf_lsm.c +F: security/bpf/ BPF [SELFTESTS] (Test Runners & Infrastructure) M: Andrii Nakryiko @@ -3879,17 +3870,28 @@ L: bpf@vger.kernel.org S: Maintained F: tools/testing/selftests/bpf/ -BPF [DOCUMENTATION] (Related to Standardization) -R: David Vernet +BPF [STORAGE & CGROUPS] +M: Martin KaFai Lau L: bpf@vger.kernel.org -L: bpf@ietf.org S: Maintained -F: Documentation/bpf/instruction-set.rst +F: kernel/bpf/*storage.c +F: kernel/bpf/bpf_lru* +F: kernel/bpf/cgroup.c -BPF [MISC] +BPF [TOOLING] (bpftool) +M: Quentin Monnet L: bpf@vger.kernel.org -S: Odd Fixes -K: (?:\b|_)bpf(?:\b|_) +S: Maintained +F: kernel/bpf/disasm.* +F: tools/bpf/bpftool/ + +BPF [TRACING] +M: Song Liu +R: Jiri Olsa +L: bpf@vger.kernel.org +S: Maintained +F: kernel/bpf/stackmap.c +F: kernel/trace/bpf_trace.c BROADCOM B44 10/100 ETHERNET DRIVER M: Michael Chan @@ -3908,34 +3910,6 @@ F: drivers/net/dsa/bcm_sf2* F: include/linux/dsa/brcm.h F: include/linux/platform_data/b53.h -BROADCOM BCMBCA ARM ARCHITECTURE -M: William Zhang -M: Anand Gore -M: Kursad Oney -M: Florian Fainelli -M: Rafał Miłecki -R: Broadcom internal kernel review list -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -T: git https://github.com/broadcom/stblinux.git -F: Documentation/devicetree/bindings/arm/bcm/brcm,bcmbca.yaml -F: arch/arm64/boot/dts/broadcom/bcmbca/* -N: bcmbca -N: bcm[9]?47622 -N: bcm[9]?4912 -N: bcm[9]?63138 -N: bcm[9]?63146 -N: bcm[9]?63148 -N: bcm[9]?63158 -N: bcm[9]?63178 -N: bcm[9]?6756 -N: bcm[9]?6813 -N: bcm[9]?6846 -N: bcm[9]?6855 -N: bcm[9]?6856 -N: bcm[9]?6858 -N: bcm[9]?6878 - BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE M: Florian Fainelli R: Broadcom internal kernel review list @@ -4033,11 +4007,39 @@ N: brcmstb N: bcm7038 N: bcm7120 +BROADCOM BCMBCA ARM ARCHITECTURE +M: William Zhang +M: Anand Gore +M: Kursad Oney +M: Florian Fainelli +M: Rafał Miłecki +R: Broadcom internal kernel review list +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +T: git https://github.com/broadcom/stblinux.git +F: Documentation/devicetree/bindings/arm/bcm/brcm,bcmbca.yaml +F: arch/arm64/boot/dts/broadcom/bcmbca/* +N: bcmbca +N: bcm[9]?47622 +N: bcm[9]?4912 +N: bcm[9]?63138 +N: bcm[9]?63146 +N: bcm[9]?63148 +N: bcm[9]?63158 +N: bcm[9]?63178 +N: bcm[9]?6756 +N: bcm[9]?6813 +N: bcm[9]?6846 +N: bcm[9]?6855 +N: bcm[9]?6856 +N: bcm[9]?6858 +N: bcm[9]?6878 + BROADCOM BDC DRIVER M: Justin Chen M: Al Cooper -L: linux-usb@vger.kernel.org R: Broadcom internal kernel review list +L: linux-usb@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/usb/brcm,bdc.yaml F: drivers/usb/gadget/udc/bdc/ @@ -4059,10 +4061,10 @@ F: arch/mips/bmips/* F: arch/mips/boot/dts/brcm/bcm*.dts* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* -F: drivers/soc/bcm/bcm63xx F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb* +F: drivers/soc/bcm/bcm63xx F: include/linux/bcm963xx_nvram.h F: include/linux/bcm963xx_tag.h @@ -4344,9 +4346,9 @@ M: Florian Fainelli R: Broadcom internal kernel review list L: netdev@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/net/brcm,systemport.yaml F: drivers/net/ethernet/broadcom/bcmsysport.* F: drivers/net/ethernet/broadcom/unimac.h -F: Documentation/devicetree/bindings/net/brcm,systemport.yaml BROADCOM TG3 GIGABIT ETHERNET DRIVER M: Siva Reddy Kallam @@ -4478,29 +4480,6 @@ W: https://github.com/Cascoda/ca8210-linux.git F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt F: drivers/net/ieee802154/ca8210.c -CANAAN/KENDRYTE K210 SOC FPIOA DRIVER -M: Damien Le Moal -L: linux-riscv@lists.infradead.org -L: linux-gpio@vger.kernel.org (pinctrl driver) -F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml -F: drivers/pinctrl/pinctrl-k210.c - -CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER -M: Damien Le Moal -L: linux-kernel@vger.kernel.org -L: linux-riscv@lists.infradead.org -S: Maintained -F: Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml -F: drivers/reset/reset-k210.c - -CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER -M: Damien Le Moal -L: linux-riscv@lists.infradead.org -S: Maintained -F: Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml -F: drivers/soc/canaan/ -F: include/soc/canaan/ - CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS M: David Howells L: linux-cachefs@redhat.com (moderated for non-subscribers) @@ -4622,6 +4601,29 @@ F: Documentation/networking/j1939.rst F: include/uapi/linux/can/j1939.h F: net/can/j1939/ +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER +M: Damien Le Moal +L: linux-riscv@lists.infradead.org +L: linux-gpio@vger.kernel.org (pinctrl driver) +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml +F: drivers/pinctrl/pinctrl-k210.c + +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER +M: Damien Le Moal +L: linux-kernel@vger.kernel.org +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml +F: drivers/reset/reset-k210.c + +CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER +M: Damien Le Moal +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml +F: drivers/soc/canaan/ +F: include/soc/canaan/ + CAPABILITIES M: Serge Hallyn L: linux-security-module@vger.kernel.org @@ -4681,8 +4683,8 @@ F: arch/arm64/boot/dts/cavium/thunder2-99xx* CBS/ETF/TAPRIO QDISCS M: Vinicius Costa Gomes -S: Maintained L: netdev@vger.kernel.org +S: Maintained F: net/sched/sch_cbs.c F: net/sched/sch_etf.c F: net/sched/sch_taprio.c @@ -4705,10 +4707,10 @@ CCTRNG ARM TRUSTZONE CRYPTOCELL TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER M: Hadar Gat L: linux-crypto@vger.kernel.org S: Supported +W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family +F: Documentation/devicetree/bindings/rng/arm-cctrng.yaml F: drivers/char/hw_random/cctrng.c F: drivers/char/hw_random/cctrng.h -F: Documentation/devicetree/bindings/rng/arm-cctrng.yaml -W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family CEC FRAMEWORK M: Hans Verkuil @@ -4868,13 +4870,6 @@ S: Maintained F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml F: sound/soc/codecs/cros_ec_codec.* -CHROMEOS EC UART DRIVER -M: Bhanu Prakash Maiya -R: Benson Leung -R: Tzung-Bi Shih -S: Maintained -F: drivers/platform/chrome/cros_ec_uart.c - CHROMEOS EC SUBDRIVERS M: Benson Leung R: Guenter Roeck @@ -4884,13 +4879,12 @@ F: drivers/power/supply/cros_usbpd-charger.c N: cros_ec N: cros-ec -CHROMEOS EC USB TYPE-C DRIVER -M: Prashant Malani -L: chrome-platform@lists.linux.dev +CHROMEOS EC UART DRIVER +M: Bhanu Prakash Maiya +R: Benson Leung +R: Tzung-Bi Shih S: Maintained -F: drivers/platform/chrome/cros_ec_typec.* -F: drivers/platform/chrome/cros_typec_switch.c -F: drivers/platform/chrome/cros_typec_vdm.* +F: drivers/platform/chrome/cros_ec_uart.c CHROMEOS EC USB PD NOTIFY DRIVER M: Prashant Malani @@ -4899,6 +4893,14 @@ S: Maintained F: drivers/platform/chrome/cros_usbpd_notify.c F: include/linux/platform_data/cros_usbpd_notify.h +CHROMEOS EC USB TYPE-C DRIVER +M: Prashant Malani +L: chrome-platform@lists.linux.dev +S: Maintained +F: drivers/platform/chrome/cros_ec_typec.* +F: drivers/platform/chrome/cros_typec_switch.c +F: drivers/platform/chrome/cros_typec_vdm.* + CHROMEOS HPS DRIVER M: Dan Callaghan R: Sami Kyöstilä @@ -4916,7 +4918,6 @@ F: drivers/media/cec/i2c/ch7322.c CIRRUS LOGIC AUDIO CODEC DRIVERS M: James Schulman M: David Rhodes -M: Lucas Tanure M: Richard Fitzgerald L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: patches@opensource.cirrus.com @@ -5016,6 +5017,18 @@ M: Nelson Escobar S: Supported F: drivers/infiniband/hw/usnic/ +CLANG CONTROL FLOW INTEGRITY SUPPORT +M: Sami Tolvanen +M: Kees Cook +R: Nathan Chancellor +R: Nick Desaulniers +L: llvm@lists.linux.dev +S: Supported +B: https://github.com/ClangBuiltLinux/linux/issues +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening +F: include/linux/cfi.h +F: kernel/cfi.c + CLANG-FORMAT FILE M: Miguel Ojeda S: Maintained @@ -5036,18 +5049,6 @@ F: scripts/Makefile.clang F: scripts/clang-tools/ K: \b(?i:clang|llvm)\b -CLANG CONTROL FLOW INTEGRITY SUPPORT -M: Sami Tolvanen -M: Kees Cook -R: Nathan Chancellor -R: Nick Desaulniers -L: llvm@lists.linux.dev -S: Supported -B: https://github.com/ClangBuiltLinux/linux/issues -T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening -F: include/linux/cfi.h -F: kernel/cfi.c - CLK API M: Russell King L: linux-clk@vger.kernel.org @@ -5138,7 +5139,7 @@ X: drivers/clk/clkdev.c COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) M: Steve French -R: Paulo Alcantara (DFS, global name space) +R: Paulo Alcantara (DFS, global name space) R: Ronnie Sahlberg (directory leases, sparse files) R: Shyam Prasad N (multichannel) R: Tom Talpey (RDMA, smbdirect) @@ -5148,8 +5149,8 @@ S: Supported W: https://wiki.samba.org/index.php/LinuxCIFS T: git git://git.samba.org/sfrench/cifs-2.6.git F: Documentation/admin-guide/cifs/ -F: fs/cifs/ -F: fs/smbfs_common/ +F: fs/smb/client/ +F: fs/smb/common/ F: include/uapi/linux/cifs COMPACTPCI HOTPLUG CORE @@ -5218,8 +5219,8 @@ CONTEXT TRACKING M: Frederic Weisbecker M: "Paul E. McKenney" S: Maintained -F: kernel/context_tracking.c F: include/linux/context_tracking* +F: kernel/context_tracking.c CONTROL GROUP (CGROUP) M: Tejun Heo @@ -5380,8 +5381,8 @@ F: drivers/cpuidle/cpuidle-big_little.c CPUIDLE DRIVER - ARM EXYNOS M: Daniel Lezcano -R: Krzysztof Kozlowski M: Kukjin Kim +R: Krzysztof Kozlowski L: linux-pm@vger.kernel.org L: linux-samsung-soc@vger.kernel.org S: Supported @@ -5402,8 +5403,8 @@ M: Ulf Hansson L: linux-pm@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported -F: drivers/cpuidle/cpuidle-psci.h F: drivers/cpuidle/cpuidle-psci-domain.c +F: drivers/cpuidle/cpuidle-psci.h CPUIDLE DRIVER - DT IDLE PM DOMAIN M: Ulf Hansson @@ -5547,13 +5548,6 @@ S: Supported W: http://www.chelsio.com F: drivers/crypto/chelsio -CXGB4 INLINE CRYPTO DRIVER -M: Ayush Sawal -L: netdev@vger.kernel.org -S: Supported -W: http://www.chelsio.com -F: drivers/net/ethernet/chelsio/inline_crypto/ - CXGB4 ETHERNET DRIVER (CXGB4) M: Raju Rangoju L: netdev@vger.kernel.org @@ -5561,6 +5555,13 @@ S: Supported W: http://www.chelsio.com F: drivers/net/ethernet/chelsio/cxgb4/ +CXGB4 INLINE CRYPTO DRIVER +M: Ayush Sawal +L: netdev@vger.kernel.org +S: Supported +W: http://www.chelsio.com +F: drivers/net/ethernet/chelsio/inline_crypto/ + CXGB4 ISCSI DRIVER (CXGB4I) M: Varun Prakash L: linux-scsi@vger.kernel.org @@ -5616,16 +5617,6 @@ CYCLADES PC300 DRIVER S: Orphan F: drivers/net/wan/pc300* -CYPRESS_FIRMWARE MEDIA DRIVER -M: Antti Palosaari -L: linux-media@vger.kernel.org -S: Maintained -W: https://linuxtv.org -W: http://palosaari.fi/linux/ -Q: http://patchwork.linuxtv.org/project/linux-media/list/ -T: git git://linuxtv.org/anttip/media_tree.git -F: drivers/media/common/cypress_firmware* - CYPRESS CY8C95X0 PINCTRL DRIVER M: Patrick Rudolph L: linux-gpio@vger.kernel.org @@ -5645,6 +5636,16 @@ S: Maintained F: Documentation/devicetree/bindings/input/cypress-sf.yaml F: drivers/input/keyboard/cypress-sf.c +CYPRESS_FIRMWARE MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +S: Maintained +W: https://linuxtv.org +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +F: drivers/media/common/cypress_firmware* + CYTTSP TOUCHSCREEN DRIVER M: Linus Walleij L: linux-input@vger.kernel.org @@ -5811,11 +5812,6 @@ S: Maintained F: Documentation/driver-api/dcdbas.rst F: drivers/platform/x86/dell/dcdbas.* -DELL WMI DESCRIPTOR DRIVER -L: Dell.Client.Kernel@dell.com -S: Maintained -F: drivers/platform/x86/dell/dell-wmi-descriptor.c - DELL WMI DDV DRIVER M: Armin Wolf S: Maintained @@ -5823,19 +5819,10 @@ F: Documentation/ABI/testing/debugfs-dell-wmi-ddv F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv F: drivers/platform/x86/dell/dell-wmi-ddv.c -DELL WMI SYSMAN DRIVER -M: Prasanth Ksr +DELL WMI DESCRIPTOR DRIVER L: Dell.Client.Kernel@dell.com -L: platform-driver-x86@vger.kernel.org S: Maintained -F: Documentation/ABI/testing/sysfs-class-firmware-attributes -F: drivers/platform/x86/dell/dell-wmi-sysman/ - -DELL WMI NOTIFICATIONS DRIVER -M: Matthew Garrett -M: Pali Rohár -S: Maintained -F: drivers/platform/x86/dell/dell-wmi-base.c +F: drivers/platform/x86/dell/dell-wmi-descriptor.c DELL WMI HARDWARE PRIVACY SUPPORT M: Perry Yuan @@ -5844,13 +5831,19 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/dell/dell-wmi-privacy.c -DELTA ST MEDIA DRIVER -M: Hugues Fruchet -L: linux-media@vger.kernel.org -S: Supported -W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git -F: drivers/media/platform/st/sti/delta +DELL WMI NOTIFICATIONS DRIVER +M: Matthew Garrett +M: Pali Rohár +S: Maintained +F: drivers/platform/x86/dell/dell-wmi-base.c + +DELL WMI SYSMAN DRIVER +M: Prasanth Ksr +L: Dell.Client.Kernel@dell.com +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-class-firmware-attributes +F: drivers/platform/x86/dell/dell-wmi-sysman/ DELTA AHE-50DC FAN CONTROL MODULE DRIVER M: Zev Weiss @@ -5874,6 +5867,14 @@ F: Documentation/devicetree/bindings/reset/delta,tn48m-reset.yaml F: drivers/gpio/gpio-tn48m.c F: include/dt-bindings/reset/delta,tn48m-reset.h +DELTA ST MEDIA DRIVER +M: Hugues Fruchet +L: linux-media@vger.kernel.org +S: Supported +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +F: drivers/media/platform/st/sti/delta + DENALI NAND DRIVER L: linux-mtd@lists.infradead.org S: Orphan @@ -5886,13 +5887,6 @@ S: Maintained F: drivers/dma/dw-edma/ F: include/linux/dma/edma.h -DESIGNWARE XDATA IP DRIVER -M: Gustavo Pimentel -L: linux-pci@vger.kernel.org -S: Maintained -F: Documentation/misc-devices/dw-xdata-pcie.rst -F: drivers/misc/dw-xdata-pcie.c - DESIGNWARE USB2 DRD IP DRIVER M: Minas Harutyunyan L: linux-usb@vger.kernel.org @@ -5906,6 +5900,13 @@ L: linux-usb@vger.kernel.org S: Maintained F: drivers/usb/dwc3/ +DESIGNWARE XDATA IP DRIVER +M: Gustavo Pimentel +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/misc-devices/dw-xdata-pcie.rst +F: drivers/misc/dw-xdata-pcie.c + DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER M: Andreas Klinger L: linux-iio@vger.kernel.org @@ -6014,9 +6015,9 @@ W: http://www.dialog-semiconductor.com/products F: Documentation/devicetree/bindings/input/da90??-onkey.txt F: Documentation/devicetree/bindings/input/dlg,da72??.txt F: Documentation/devicetree/bindings/mfd/da90*.txt -F: Documentation/devicetree/bindings/mfd/da90*.yaml -F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml +F: Documentation/devicetree/bindings/mfd/dlg,da90*.yaml F: Documentation/devicetree/bindings/regulator/da92*.txt +F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml F: Documentation/devicetree/bindings/regulator/slg51000.txt F: Documentation/devicetree/bindings/sound/da[79]*.txt F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt @@ -6135,6 +6136,12 @@ F: include/linux/dma/ F: include/linux/dmaengine.h F: include/linux/of_dma.h +DMA MAPPING BENCHMARK +M: Xiang Chen +L: iommu@lists.linux.dev +F: kernel/dma/map_benchmark.c +F: tools/testing/selftests/dma/ + DMA MAPPING HELPERS M: Christoph Hellwig M: Marek Szyprowski @@ -6145,17 +6152,11 @@ W: http://git.infradead.org/users/hch/dma-mapping.git T: git git://git.infradead.org/users/hch/dma-mapping.git F: include/asm-generic/dma-mapping.h F: include/linux/dma-direct.h -F: include/linux/dma-mapping.h F: include/linux/dma-map-ops.h +F: include/linux/dma-mapping.h F: include/linux/swiotlb.h F: kernel/dma/ -DMA MAPPING BENCHMARK -M: Xiang Chen -L: iommu@lists.linux.dev -F: kernel/dma/map_benchmark.c -F: tools/testing/selftests/dma/ - DMA-BUF HEAPS FRAMEWORK M: Sumit Semwal R: Benjamin Gaignard @@ -6213,6 +6214,7 @@ X: Documentation/devicetree/ X: Documentation/driver-api/media/ X: Documentation/firmware-guide/acpi/ X: Documentation/i2c/ +X: Documentation/netlink/ X: Documentation/power/ X: Documentation/spi/ X: Documentation/userspace-api/media/ @@ -6333,7 +6335,9 @@ F: drivers/base/ F: fs/debugfs/ F: fs/sysfs/ F: include/linux/debugfs.h +F: include/linux/fwnode.h F: include/linux/kobj* +F: include/linux/property.h F: lib/kobj* DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS) @@ -6343,6 +6347,25 @@ S: Maintained F: drivers/soc/ti/smartreflex.c F: include/linux/power/smartreflex.h +DRM ACCEL DRIVERS FOR INTEL VPU +M: Jacek Lawrynowicz +M: Stanislaw Gruszka +L: dri-devel@lists.freedesktop.org +S: Supported +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/accel/ivpu/ +F: include/uapi/drm/ivpu_accel.h + +DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK +M: Oded Gabbay +L: dri-devel@lists.freedesktop.org +S: Maintained +C: irc://irc.oftc.net/dri-devel +T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git +F: Documentation/accel/ +F: drivers/accel/ +F: include/drm/drm_accel.h + DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE M: Maxime Ripard M: Chen-Yu Tsai @@ -6425,6 +6448,21 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +DRM DRIVER FOR FIRMWARE FRAMEBUFFERS +M: Thomas Zimmermann +M: Javier Martinez Canillas +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/gpu/drm/drm_aperture.c +F: drivers/gpu/drm/tiny/ofdrm.c +F: drivers/gpu/drm/tiny/simpledrm.c +F: drivers/video/aperture.c +F: drivers/video/nomodeset.c +F: include/drm/drm_aperture.h +F: include/linux/aperture.h +F: include/video/nomodeset.h + DRM DRIVER FOR GENERIC EDP PANELS R: Douglas Anderson F: Documentation/devicetree/bindings/display/panel/panel-edp.yaml @@ -6459,6 +6497,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/himax,hx8357d.txt F: drivers/gpu/drm/tiny/hx8357d.c +DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE +M: Deepak Rawat +L: linux-hyperv@vger.kernel.org +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/gpu/drm/hyperv + DRM DRIVER FOR ILITEK ILI9225 PANELS M: David Lechner S: Maintained @@ -6488,11 +6534,11 @@ F: drivers/gpu/drm/logicvc/ DRM DRIVER FOR LVDS PANELS M: Laurent Pinchart L: dri-devel@lists.freedesktop.org -T: git git://anongit.freedesktop.org/drm/drm-misc S: Maintained -F: drivers/gpu/drm/panel/panel-lvds.c +T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/lvds.yaml F: Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +F: drivers/gpu/drm/panel/panel-lvds.c DRM DRIVER FOR MANTIX MLAF057WE51 PANELS M: Guido Günther @@ -6601,13 +6647,6 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/repaper.txt F: drivers/gpu/drm/tiny/repaper.c -DRM DRIVER FOR SOLOMON SSD130X OLED DISPLAYS -M: Javier Martinez Canillas -S: Maintained -T: git git://anongit.freedesktop.org/drm/drm-misc -F: Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml -F: drivers/gpu/drm/solomon/ssd130x* - DRM DRIVER FOR QEMU'S CIRRUS DEVICE M: Dave Airlie M: Gerd Hoffmann @@ -6656,29 +6695,6 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/samsung,s6d27a1.yaml F: drivers/gpu/drm/panel/panel-samsung-s6d27a1.c -DRM DRIVER FOR SITRONIX ST7703 PANELS -M: Guido Günther -R: Purism Kernel Team -R: Ondrej Jirman -S: Maintained -F: Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml -F: drivers/gpu/drm/panel/panel-sitronix-st7703.c - -DRM DRIVER FOR FIRMWARE FRAMEBUFFERS -M: Thomas Zimmermann -M: Javier Martinez Canillas -L: dri-devel@lists.freedesktop.org -S: Maintained -T: git git://anongit.freedesktop.org/drm/drm-misc -F: drivers/gpu/drm/drm_aperture.c -F: drivers/gpu/drm/tiny/ofdrm.c -F: drivers/gpu/drm/tiny/simpledrm.c -F: drivers/video/aperture.c -F: drivers/video/nomodeset.c -F: include/drm/drm_aperture.h -F: include/linux/aperture.h -F: include/video/nomodeset.h - DRM DRIVER FOR SITRONIX ST7586 PANELS M: David Lechner S: Maintained @@ -6692,6 +6708,14 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml F: drivers/gpu/drm/panel/panel-sitronix-st7701.c +DRM DRIVER FOR SITRONIX ST7703 PANELS +M: Guido Günther +R: Purism Kernel Team +R: Ondrej Jirman +S: Maintained +F: Documentation/devicetree/bindings/display/panel/rocktech,jh057n00900.yaml +F: drivers/gpu/drm/panel/panel-sitronix-st7703.c + DRM DRIVER FOR SITRONIX ST7735R PANELS M: David Lechner S: Maintained @@ -6699,6 +6723,13 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/sitronix,st7735r.yaml F: drivers/gpu/drm/tiny/st7735r.c +DRM DRIVER FOR SOLOMON SSD130X OLED DISPLAYS +M: Javier Martinez Canillas +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml +F: drivers/gpu/drm/solomon/ssd130x* + DRM DRIVER FOR ST-ERICSSON MCDE M: Linus Walleij S: Maintained @@ -6797,25 +6828,6 @@ F: include/drm/drm* F: include/linux/vga* F: include/uapi/drm/drm* -DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK -M: Oded Gabbay -L: dri-devel@lists.freedesktop.org -S: Maintained -C: irc://irc.oftc.net/dri-devel -T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git -F: Documentation/accel/ -F: drivers/accel/ -F: include/drm/drm_accel.h - -DRM ACCEL DRIVERS FOR INTEL VPU -M: Jacek Lawrynowicz -M: Stanislaw Gruszka -L: dri-devel@lists.freedesktop.org -S: Supported -T: git git://anongit.freedesktop.org/drm/drm-misc -F: drivers/accel/ivpu/ -F: include/uapi/drm/ivpu_accel.h - DRM DRIVERS FOR ALLWINNER A10 M: Maxime Ripard M: Chen-Yu Tsai @@ -6919,14 +6931,6 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/hisilicon/ F: drivers/gpu/drm/hisilicon/ -DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE -M: Deepak Rawat -L: linux-hyperv@vger.kernel.org -L: dri-devel@lists.freedesktop.org -S: Maintained -T: git git://anongit.freedesktop.org/drm/drm-misc -F: drivers/gpu/drm/hyperv - DRM DRIVERS FOR LIMA M: Qiang Yu L: dri-devel@lists.freedesktop.org @@ -7078,6 +7082,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/xlnx/ F: drivers/gpu/drm/xlnx/ +DRM GPU SCHEDULER +M: Luben Tuikov +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/gpu/drm/scheduler/ +F: include/drm/gpu_scheduler.h + DRM PANEL DRIVERS M: Neil Armstrong R: Sam Ravnborg @@ -7106,14 +7118,6 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/ttm/ F: include/drm/ttm/ -DRM GPU SCHEDULER -M: Luben Tuikov -L: dri-devel@lists.freedesktop.org -S: Maintained -T: git git://anongit.freedesktop.org/drm/drm-misc -F: drivers/gpu/drm/scheduler/ -F: include/drm/gpu_scheduler.h - DSBR100 USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org @@ -7241,10 +7245,10 @@ F: drivers/media/usb/dvb-usb-v2/usb_urb.c DYNAMIC DEBUG M: Jason Baron +M: Jim Cromie S: Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c -M: Jim Cromie F: lib/test_dynamic_debug.c DYNAMIC INTERRUPT MODERATION @@ -7254,6 +7258,15 @@ F: Documentation/networking/net_dim.rst F: include/linux/dim.h F: lib/dim/ +DYNAMIC THERMAL POWER MANAGEMENT (DTPM) +M: Daniel Lezcano +L: linux-pm@vger.kernel.org +S: Supported +B: https://bugzilla.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm +F: drivers/powercap/dtpm* +F: include/linux/dtpm.h + DZ DECSTATION DZ11 SERIAL DRIVER M: "Maciej W. Rozycki" S: Maintained @@ -7560,12 +7573,6 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/em28xx* F: drivers/media/usb/em28xx/ -EMBEDDED LINUX -M: Olivia Mackall -M: David Woodhouse -L: linux-embedded@vger.kernel.org -S: Maintained - EMMC CMDQ HOST CONTROLLER INTERFACE (CQHCI) DRIVER M: Adrian Hunter M: Ritesh Harjani @@ -7598,14 +7605,6 @@ W: http://www.broadcom.com F: drivers/infiniband/hw/ocrdma/ F: include/uapi/rdma/ocrdma-abi.h -EMULEX/BROADCOM LPFC FC/FCOE SCSI DRIVER -M: James Smart -M: Dick Kennedy -L: linux-scsi@vger.kernel.org -S: Supported -W: http://www.broadcom.com -F: drivers/scsi/lpfc/ - EMULEX/BROADCOM EFCT FC/FCOE SCSI TARGET DRIVER M: James Smart M: Ram Vegesna @@ -7615,6 +7614,14 @@ S: Supported W: http://www.broadcom.com F: drivers/scsi/elx/ +EMULEX/BROADCOM LPFC FC/FCOE SCSI DRIVER +M: James Smart +M: Dick Kennedy +L: linux-scsi@vger.kernel.org +S: Supported +W: http://www.broadcom.com +F: drivers/scsi/lpfc/ + ENE CB710 FLASH CARD READER DRIVER M: Michał Mirosław S: Maintained @@ -7706,8 +7713,8 @@ F: drivers/net/mdio/of_mdio.c F: drivers/net/pcs/ F: drivers/net/phy/ F: include/dt-bindings/net/qca-ar803x.h -F: include/linux/linkmode.h F: include/linux/*mdio*.h +F: include/linux/linkmode.h F: include/linux/mdio/*.h F: include/linux/mii.h F: include/linux/of_net.h @@ -7770,8 +7777,8 @@ M: Mimi Zohar L: linux-integrity@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git -F: security/integrity/evm/ F: security/integrity/ +F: security/integrity/evm/ EXTENSIBLE FIRMWARE INTERFACE (EFI) M: Ard Biesheuvel @@ -7802,8 +7809,8 @@ EXTRA BOOT CONFIG M: Masami Hiramatsu L: linux-kernel@vger.kernel.org L: linux-trace-kernel@vger.kernel.org -Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ S: Maintained +Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git F: Documentation/admin-guide/bootconfig.rst F: fs/proc/bootconfig.c @@ -7990,10 +7997,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master F: drivers/target/sbp/ FIREWIRE SUBSYSTEM -M: Stefan Richter +M: Takashi Sakamoto +M: Takashi Sakamoto L: linux1394-devel@lists.sourceforge.net S: Maintained -W: http://ieee1394.wiki.kernel.org/ +W: http://ieee1394.docs.kernel.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git F: drivers/firewire/ F: include/linux/firewire.h @@ -8089,21 +8097,6 @@ F: Documentation/fpga/ F: drivers/fpga/ F: include/linux/fpga/ -INTEL MAX10 BMC SECURE UPDATES -M: Russ Weight -L: linux-fpga@vger.kernel.org -S: Maintained -F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update -F: drivers/fpga/intel-m10-bmc-sec-update.c - -MICROCHIP POLARFIRE FPGA DRIVERS -M: Conor Dooley -R: Ivan Bornyakov -L: linux-fpga@vger.kernel.org -S: Supported -F: Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml -F: drivers/fpga/microchip-spi.c - FPU EMULATOR M: Bill Metzenthen S: Maintained @@ -8112,9 +8105,9 @@ F: arch/x86/math-emu/ FRAMEBUFFER CORE M: Daniel Vetter -F: drivers/video/fbdev/core/ S: Odd Fixes T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/video/fbdev/core/ FRAMEBUFFER LAYER M: Helge Deller @@ -8169,6 +8162,7 @@ F: include/linux/spi/spi-fsl-dspi.h FREESCALE ENETC ETHERNET DRIVERS M: Claudiu Manoil +M: Vladimir Oltean L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/freescale/enetc/ @@ -8491,15 +8485,15 @@ M: Masami Hiramatsu R: Mark Rutland L: linux-kernel@vger.kernel.org L: linux-trace-kernel@vger.kernel.org -Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ S: Maintained +Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git F: Documentation/trace/ftrace* -F: kernel/trace/ftrace* -F: kernel/trace/fgraph.c F: arch/*/*/*/*ftrace* F: arch/*/*/*ftrace* F: include/*/ftrace.h +F: kernel/trace/fgraph.c +F: kernel/trace/ftrace* F: samples/ftrace FUNGIBLE ETHERNET DRIVERS @@ -8540,10 +8534,10 @@ GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER M: Tim Harvey S: Maintained F: Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml -F: drivers/mfd/gateworks-gsc.c -F: include/linux/mfd/gsc.h F: Documentation/hwmon/gsc-hwmon.rst F: drivers/hwmon/gsc-hwmon.c +F: drivers/mfd/gateworks-gsc.c +F: include/linux/mfd/gsc.h F: include/linux/platform_data/gsc_hwmon.h GCC PLUGINS @@ -8671,8 +8665,8 @@ R: Andy Shevchenko S: Maintained F: lib/string.c F: lib/string_helpers.c -F: lib/test_string.c F: lib/test-string_helpers.c +F: lib/test_string.c GENERIC UIO DRIVER FOR PCI DEVICES M: "Michael S. Tsirkin" @@ -9155,12 +9149,11 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/hid/hid-logitech-* -HID++ LOGITECH DRIVERS -R: Filipe Laíns -R: Bastien Nocera +HID PHOENIX RC FLIGHT CONTROLLER +M: Marcus Folkesson L: linux-input@vger.kernel.org S: Maintained -F: drivers/hid/hid-logitech-hidpp.c +F: drivers/hid/hid-pxrc.c HID PLAYSTATION DRIVER M: Roderick Colenbrander @@ -9168,12 +9161,6 @@ L: linux-input@vger.kernel.org S: Supported F: drivers/hid/hid-playstation.c -HID PHOENIX RC FLIGHT CONTROLLER -M: Marcus Folkesson -L: linux-input@vger.kernel.org -S: Maintained -F: drivers/hid/hid-pxrc.c - HID SENSOR HUB DRIVERS M: Jiri Kosina M: Jonathan Cameron @@ -9200,6 +9187,13 @@ S: Maintained F: drivers/hid/wacom.h F: drivers/hid/wacom_* +HID++ LOGITECH DRIVERS +R: Filipe Laíns +R: Bastien Nocera +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-logitech-hidpp.c + HIGH-RESOLUTION TIMERS, CLOCKEVENTS M: Thomas Gleixner L: linux-kernel@vger.kernel.org @@ -9224,6 +9218,12 @@ W: http://www.highpoint-tech.com F: Documentation/scsi/hptiop.rst F: drivers/scsi/hptiop.c +HIKEY960 ONBOARD USB GPIO HUB DRIVER +M: John Stultz +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/misc/hisi_hikey_usb.c + HIMAX HX83112B TOUCHSCREEN SUPPORT M: Job Noorman L: linux-input@vger.kernel.org @@ -9272,6 +9272,12 @@ F: drivers/crypto/hisilicon/hpre/hpre.h F: drivers/crypto/hisilicon/hpre/hpre_crypto.c F: drivers/crypto/hisilicon/hpre/hpre_main.c +HISILICON HNS3 PMU DRIVER +M: Guangbin Huang +S: Supported +F: Documentation/admin-guide/perf/hns3-pmu.rst +F: drivers/perf/hisilicon/hns3_pmu.c + HISILICON I2C CONTROLLER DRIVER M: Yicong Yang L: linux-i2c@vger.kernel.org @@ -9304,12 +9310,6 @@ W: http://www.hisilicon.com F: Documentation/devicetree/bindings/net/hisilicon*.txt F: drivers/net/ethernet/hisilicon/ -HIKEY960 ONBOARD USB GPIO HUB DRIVER -M: John Stultz -L: linux-kernel@vger.kernel.org -S: Maintained -F: drivers/misc/hisi_hikey_usb.c - HISILICON PMU DRIVER M: Shaokun Zhang M: Jonathan Cameron @@ -9319,12 +9319,6 @@ F: Documentation/admin-guide/perf/hisi-pcie-pmu.rst F: Documentation/admin-guide/perf/hisi-pmu.rst F: drivers/perf/hisilicon -HISILICON HNS3 PMU DRIVER -M: Guangbin Huang -S: Supported -F: Documentation/admin-guide/perf/hns3-pmu.rst -F: drivers/perf/hisilicon/hns3_pmu.c - HISILICON PTT DRIVER M: Yicong Yang M: Jonathan Cameron @@ -9348,17 +9342,9 @@ F: drivers/crypto/hisilicon/qm.c F: drivers/crypto/hisilicon/sgl.c F: include/linux/hisi_acc_qm.h -HISILICON ZIP Controller DRIVER -M: Yang Shen -M: Zhou Wang -L: linux-crypto@vger.kernel.org -S: Maintained -F: Documentation/ABI/testing/debugfs-hisi-zip -F: drivers/crypto/hisilicon/zip/ - HISILICON ROCE DRIVER M: Haoyue Xu -M: Wenpeng Liang +M: Junxian Huang L: linux-rdma@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt @@ -9414,6 +9400,14 @@ S: Maintained W: http://www.hisilicon.com F: drivers/spi/spi-hisi-sfc-v3xx.c +HISILICON ZIP Controller DRIVER +M: Yang Shen +M: Zhou Wang +L: linux-crypto@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/debugfs-hisi-zip +F: drivers/crypto/hisilicon/zip/ + HMM - Heterogeneous Memory Management M: Jérôme Glisse L: linux-mm@kvack.org @@ -9489,7 +9483,10 @@ F: drivers/input/touchscreen/htcpen.c HTE SUBSYSTEM M: Dipen Patel +L: timestamp@lists.linux.dev S: Maintained +Q: https://patchwork.kernel.org/project/timestamp/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pateldipen1984/linux.git F: Documentation/devicetree/bindings/timestamp/ F: Documentation/driver-api/hte/ F: drivers/hte/ @@ -9583,8 +9580,9 @@ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git F: Documentation/ABI/stable/sysfs-bus-vmbus F: Documentation/ABI/testing/debugfs-hyperv -F: Documentation/virt/hyperv +F: Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml F: Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst +F: Documentation/virt/hyperv F: arch/arm64/hyperv F: arch/arm64/include/asm/hyperv-tlfs.h F: arch/arm64/include/asm/mshyperv.h @@ -9766,6 +9764,12 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/i2c-stub.c +I3C DRIVER FOR ASPEED AST2600 +M: Jeremy Kerr +S: Maintained +F: Documentation/devicetree/bindings/i3c/aspeed,ast2600-i3c.yaml +F: drivers/i3c/master/ast2600-i3c-master.c + I3C DRIVER FOR CADENCE I3C MASTER IP M: Przemysław Gaj S: Maintained @@ -9855,6 +9859,11 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/ibm/ibmvnic.* +IBM Power VFIO Support +M: Timothy Pearson +S: Supported +F: drivers/vfio/vfio_iommu_spapr_tce.c + IBM Power Virtual Ethernet Device Driver M: Nick Child L: netdev@vger.kernel.org @@ -9967,6 +9976,10 @@ F: include/net/nl802154.h F: net/ieee802154/ F: net/mac802154/ +IFCVF VIRTIO DATA PATH ACCELERATOR +R: Zhu Lingshan +F: drivers/vdpa/ifcvf/ + IFE PROTOCOL M: Yotam Gigi M: Jamal Hadi Salim @@ -10002,6 +10015,13 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector F: Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml F: drivers/iio/adc/envelope-detector.c +IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS +M: Matti Vaittinen +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/light/gain-time-scale-helper.c +F: drivers/iio/light/gain-time-scale-helper.h + IIO MULTIPLEXER M: Peter Rosin L: linux-iio@vger.kernel.org @@ -10095,7 +10115,7 @@ S: Maintained F: Documentation/process/kernel-docs.rst INDUSTRY PACK SUBSYSTEM (IPACK) -M: Samuel Iglesias Gonsalvez +M: Vaibhav Gupta M: Jens Taprogge M: Greg Kroah-Hartman L: industrypack-devel@lists.sourceforge.net @@ -10224,8 +10244,8 @@ M: Dmitry Kasatkin L: linux-integrity@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git -F: security/integrity/ima/ F: security/integrity/ +F: security/integrity/ima/ INTEL 810/815 FRAMEBUFFER DRIVER M: Antonino Daplas @@ -10379,14 +10399,6 @@ S: Supported Q: https://patchwork.kernel.org/project/linux-dmaengine/list/ F: drivers/dma/ioat* -INTEL IDXD DRIVER -M: Fenghua Yu -M: Dave Jiang -L: dmaengine@vger.kernel.org -S: Supported -F: drivers/dma/idxd/* -F: include/uapi/linux/idxd.h - INTEL IDLE DRIVER M: Jacob Pan M: Len Brown @@ -10396,6 +10408,14 @@ B: https://bugzilla.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git F: drivers/idle/intel_idle.c +INTEL IDXD DRIVER +M: Fenghua Yu +M: Dave Jiang +L: dmaengine@vger.kernel.org +S: Supported +F: drivers/dma/idxd/* +F: include/uapi/linux/idxd.h + INTEL IN FIELD SCAN (IFS) DEVICE M: Jithu Joseph R: Ashok Raj @@ -10442,18 +10462,18 @@ F: Documentation/admin-guide/media/ipu3_rcb.svg F: Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst F: drivers/staging/media/ipu3/ -INTEL IXP4XX CRYPTO SUPPORT -M: Corentin Labbe -L: linux-crypto@vger.kernel.org -S: Maintained -F: drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c - INTEL ISHTP ECLITE DRIVER M: Sumesh K Naduvalath L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/x86/intel/ishtp_eclite.c +INTEL IXP4XX CRYPTO SUPPORT +M: Corentin Labbe +L: linux-crypto@vger.kernel.org +S: Maintained +F: drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c + INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT M: Krzysztof Halasa S: Maintained @@ -10508,13 +10528,6 @@ F: drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c F: drivers/crypto/intel/keembay/ocs-hcu.c F: drivers/crypto/intel/keembay/ocs-hcu.h -INTEL THUNDER BAY EMMC PHY DRIVER -M: Nandhini Srikandan -M: Rashmi A -S: Maintained -F: Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml -F: drivers/phy/intel/phy-intel-thunderbay-emmc.c - INTEL MANAGEMENT ENGINE (mei) M: Tomas Winkler L: linux-kernel@vger.kernel.org @@ -10525,6 +10538,7 @@ F: drivers/watchdog/mei_wdt.c F: include/linux/mei_aux.h F: include/linux/mei_cl_bus.h F: include/uapi/linux/mei.h +F: include/uapi/linux/mei_uuid.h F: include/uapi/linux/uuid.h F: samples/mei/* @@ -10538,11 +10552,12 @@ F: drivers/hwmon/intel-m10-bmc-hwmon.c F: drivers/mfd/intel-m10-bmc* F: include/linux/mfd/intel-m10-bmc.h -INTEL MENLOW THERMAL DRIVER -M: Sujith Thomas -L: linux-pm@vger.kernel.org -S: Supported -F: drivers/thermal/intel/intel_menlow.c +INTEL MAX10 BMC SECURE UPDATES +M: Russ Weight +L: linux-fpga@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update +F: drivers/fpga/intel-m10-bmc-sec-update.c INTEL P-Unit IPC DRIVER M: Zha Qipeng @@ -10591,6 +10606,13 @@ L: linux-pm@vger.kernel.org S: Supported F: drivers/cpufreq/intel_pstate.c +INTEL PTP DFL ToD DRIVER +M: Tianfei Zhang +L: linux-fpga@vger.kernel.org +L: netdev@vger.kernel.org +S: Maintained +F: drivers/ptp/ptp_dfl_tod.c + INTEL QUADRATURE ENCODER PERIPHERAL DRIVER M: Jarkko Nikula L: linux-iio@vger.kernel.org @@ -10609,6 +10631,21 @@ F: drivers/platform/x86/intel/sdsi.c F: tools/arch/x86/intel_sdsi/ F: tools/testing/selftests/drivers/sdsi/ +INTEL SGX +M: Jarkko Sakkinen +R: Dave Hansen +L: linux-sgx@vger.kernel.org +S: Supported +Q: https://patchwork.kernel.org/project/intel-sgx/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx +F: Documentation/arch/x86/sgx.rst +F: arch/x86/entry/vdso/vsgx.S +F: arch/x86/include/asm/sgx.h +F: arch/x86/include/uapi/asm/sgx.h +F: arch/x86/kernel/cpu/sgx/* +F: tools/testing/selftests/sgx/* +K: \bSGX_ + INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER M: Daniel Scally S: Maintained @@ -10626,13 +10663,13 @@ INTEL STRATIX10 FIRMWARE DRIVERS M: Dinh Nguyen L: linux-kernel@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git F: Documentation/ABI/testing/sysfs-devices-platform-stratix10-rsu F: Documentation/devicetree/bindings/firmware/intel,stratix10-svc.txt F: drivers/firmware/stratix10-rsu.c F: drivers/firmware/stratix10-svc.c F: include/linux/firmware/intel/stratix10-smc.h F: include/linux/firmware/intel/stratix10-svc-client.h -T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git INTEL TELEMETRY DRIVER M: Rajneesh Bhardwaj @@ -10717,21 +10754,6 @@ F: Documentation/arch/x86/intel_txt.rst F: arch/x86/kernel/tboot.c F: include/linux/tboot.h -INTEL SGX -M: Jarkko Sakkinen -R: Dave Hansen -L: linux-sgx@vger.kernel.org -S: Supported -Q: https://patchwork.kernel.org/project/intel-sgx/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/sgx -F: Documentation/arch/x86/sgx.rst -F: arch/x86/entry/vdso/vsgx.S -F: arch/x86/include/asm/sgx.h -F: arch/x86/include/uapi/asm/sgx.h -F: arch/x86/kernel/cpu/sgx/* -F: tools/testing/selftests/sgx/* -K: \bSGX_ - INTERCONNECT API M: Georgi Djakov L: linux-pm@vger.kernel.org @@ -10800,18 +10822,6 @@ F: drivers/iommu/dma-iommu.h F: drivers/iommu/iova.c F: include/linux/iova.h -IOMMUFD -M: Jason Gunthorpe -M: Kevin Tian -L: iommu@lists.linux.dev -S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git -F: Documentation/userspace-api/iommufd.rst -F: drivers/iommu/iommufd/ -F: include/linux/iommufd.h -F: include/uapi/linux/iommufd.h -F: tools/testing/selftests/iommu/ - IOMMU SUBSYSTEM M: Joerg Roedel M: Will Deacon @@ -10827,6 +10837,18 @@ F: include/linux/iova.h F: include/linux/of_iommu.h F: include/uapi/linux/iommu.h +IOMMUFD +M: Jason Gunthorpe +M: Kevin Tian +L: iommu@lists.linux.dev +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git +F: Documentation/userspace-api/iommufd.rst +F: drivers/iommu/iommufd/ +F: include/linux/iommufd.h +F: include/uapi/linux/iommufd.h +F: tools/testing/selftests/iommu/ + IOSYS-MAP HELPERS M: Thomas Zimmermann L: dri-devel@lists.freedesktop.org @@ -10841,11 +10863,11 @@ L: io-uring@vger.kernel.org S: Maintained T: git git://git.kernel.dk/linux-block T: git git://git.kernel.dk/liburing -F: io_uring/ F: include/linux/io_uring.h F: include/linux/io_uring_types.h F: include/trace/events/io_uring.h F: include/uapi/linux/io_uring.h +F: io_uring/ F: tools/io_uring/ IPMI SUBSYSTEM @@ -10854,8 +10876,8 @@ L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers) S: Supported W: http://openipmi.sourceforge.net/ T: git https://github.com/cminyard/linux-ipmi.git for-next -F: Documentation/driver-api/ipmi.rst F: Documentation/devicetree/bindings/ipmi/ +F: Documentation/driver-api/ipmi.rst F: drivers/char/ipmi/ F: include/linux/ipmi* F: include/uapi/linux/ipmi* @@ -10907,8 +10929,8 @@ M: Thomas Gleixner L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core -F: kernel/irq/ F: include/linux/group_cpus.h +F: kernel/irq/ F: lib/group_cpus.c IRQCHIP DRIVERS @@ -11246,6 +11268,7 @@ L: linux-nfs@vger.kernel.org S: Supported W: http://nfs.sourceforge.net/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git +F: Documentation/filesystems/nfs/ F: fs/exportfs/ F: fs/lockd/ F: fs/nfs_common/ @@ -11261,7 +11284,6 @@ F: include/trace/misc/sunrpc.h F: include/uapi/linux/nfsd/ F: include/uapi/linux/sunrpc/ F: net/sunrpc/ -F: Documentation/filesystems/nfs/ KERNEL REGRESSIONS M: Thorsten Leemhuis @@ -11288,9 +11310,9 @@ R: Tom Talpey 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/ +F: Documentation/filesystems/smb/ksmbd.rst +F: fs/smb/common/ +F: fs/smb/server/ KERNEL UNIT TESTING FRAMEWORK (KUnit) M: Brendan Higgins @@ -11413,47 +11435,6 @@ F: arch/x86/include/uapi/asm/vmx.h F: arch/x86/kvm/ F: arch/x86/kvm/*/ -KVM PARAVIRT (KVM/paravirt) -M: Paolo Bonzini -R: Wanpeng Li -R: Vitaly Kuznetsov -L: kvm@vger.kernel.org -S: Supported -T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git -F: arch/x86/kernel/kvm.c -F: arch/x86/kernel/kvmclock.c -F: arch/x86/include/asm/pvclock-abi.h -F: include/linux/kvm_para.h -F: include/uapi/linux/kvm_para.h -F: include/uapi/asm-generic/kvm_para.h -F: include/asm-generic/kvm_para.h -F: arch/um/include/asm/kvm_para.h -F: arch/x86/include/asm/kvm_para.h -F: arch/x86/include/uapi/asm/kvm_para.h - -KVM X86 HYPER-V (KVM/hyper-v) -M: Vitaly Kuznetsov -M: Sean Christopherson -M: Paolo Bonzini -L: kvm@vger.kernel.org -S: Supported -T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git -F: arch/x86/kvm/hyperv.* -F: arch/x86/kvm/kvm_onhyperv.* -F: arch/x86/kvm/svm/hyperv.* -F: arch/x86/kvm/svm/svm_onhyperv.* -F: arch/x86/kvm/vmx/hyperv.* - -KVM X86 Xen (KVM/Xen) -M: David Woodhouse -M: Paul Durrant -M: Sean Christopherson -M: Paolo Bonzini -L: kvm@vger.kernel.org -S: Supported -T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git -F: arch/x86/kvm/xen.* - KERNFS M: Greg Kroah-Hartman M: Tejun Heo @@ -11492,14 +11473,6 @@ F: include/keys/trusted-type.h F: include/keys/trusted_tpm.h F: security/keys/trusted-keys/ -KEYS-TRUSTED-TEE -M: Sumit Garg -L: linux-integrity@vger.kernel.org -L: keyrings@vger.kernel.org -S: Supported -F: include/keys/trusted_tee.h -F: security/keys/trusted-keys/trusted_tee.c - KEYS-TRUSTED-CAAM M: Ahmad Fatoum R: Pengutronix Kernel Team @@ -11509,6 +11482,14 @@ S: Maintained F: include/keys/trusted_caam.h F: security/keys/trusted-keys/trusted_caam.c +KEYS-TRUSTED-TEE +M: Sumit Garg +L: linux-integrity@vger.kernel.org +L: keyrings@vger.kernel.org +S: Supported +F: include/keys/trusted_tee.h +F: security/keys/trusted-keys/trusted_tee.c + KEYS/KEYRINGS M: David Howells M: Jarkko Sakkinen @@ -11571,8 +11552,8 @@ L: linux-amlogic@lists.infradead.org S: Maintained F: Documentation/devicetree/bindings/mfd/khadas,mcu.yaml F: drivers/mfd/khadas-mcu.c -F: include/linux/mfd/khadas-mcu.h F: drivers/thermal/khadas_mcu_fan.c +F: include/linux/mfd/khadas-mcu.h KIONIX/ROHM KX022A ACCELEROMETER M: Matti Vaittinen @@ -11588,16 +11569,6 @@ F: include/linux/kmemleak.h F: mm/kmemleak.c F: samples/kmemleak/kmemleak-test.c -KMOD KERNEL MODULE LOADER - USERMODE HELPER -M: Luis Chamberlain -L: linux-kernel@vger.kernel.org -L: linux-modules@vger.kernel.org -S: Maintained -F: include/linux/kmod.h -F: kernel/kmod.c -F: lib/test_kmod.c -F: tools/testing/selftests/kmod/ - KMSAN M: Alexander Potapenko R: Marco Elver @@ -11619,8 +11590,8 @@ M: "David S. Miller" M: Masami Hiramatsu L: linux-kernel@vger.kernel.org L: linux-trace-kernel@vger.kernel.org -Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ S: Maintained +Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git F: Documentation/trace/kprobes.rst F: include/asm-generic/kprobes.h @@ -11654,6 +11625,47 @@ S: Maintained F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktz8866.yaml F: drivers/video/backlight/ktz8866.c +KVM PARAVIRT (KVM/paravirt) +M: Paolo Bonzini +R: Wanpeng Li +R: Vitaly Kuznetsov +L: kvm@vger.kernel.org +S: Supported +T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git +F: arch/um/include/asm/kvm_para.h +F: arch/x86/include/asm/kvm_para.h +F: arch/x86/include/asm/pvclock-abi.h +F: arch/x86/include/uapi/asm/kvm_para.h +F: arch/x86/kernel/kvm.c +F: arch/x86/kernel/kvmclock.c +F: include/asm-generic/kvm_para.h +F: include/linux/kvm_para.h +F: include/uapi/asm-generic/kvm_para.h +F: include/uapi/linux/kvm_para.h + +KVM X86 HYPER-V (KVM/hyper-v) +M: Vitaly Kuznetsov +M: Sean Christopherson +M: Paolo Bonzini +L: kvm@vger.kernel.org +S: Supported +T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git +F: arch/x86/kvm/hyperv.* +F: arch/x86/kvm/kvm_onhyperv.* +F: arch/x86/kvm/svm/hyperv.* +F: arch/x86/kvm/svm/svm_onhyperv.* +F: arch/x86/kvm/vmx/hyperv.* + +KVM X86 Xen (KVM/Xen) +M: David Woodhouse +M: Paul Durrant +M: Sean Christopherson +M: Paolo Bonzini +L: kvm@vger.kernel.org +S: Supported +T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git +F: arch/x86/kvm/xen.* + L3MDEV M: David Ahern L: netdev@vger.kernel.org @@ -11714,6 +11726,7 @@ L: linux-leds@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git F: Documentation/devicetree/bindings/leds/ +F: Documentation/leds/ F: drivers/leds/ F: include/dt-bindings/leds/ F: include/linux/leds.h @@ -11894,9 +11907,9 @@ F: scripts/spdxexclude LINEAR RANGES HELPERS M: Mark Brown R: Matti Vaittinen +F: include/linux/linear_range.h F: lib/linear_ranges.c F: lib/test_linear_ranges.c -F: include/linux/linear_range.h LINUX FOR POWER MACINTOSH M: Benjamin Herrenschmidt @@ -12023,11 +12036,11 @@ M: Joel Stanley S: Maintained F: Documentation/devicetree/bindings/*/litex,*.yaml F: arch/openrisc/boot/dts/or1klitex.dts -F: include/linux/litex.h -F: drivers/tty/serial/liteuart.c -F: drivers/soc/litex/* -F: drivers/net/ethernet/litex/* F: drivers/mmc/host/litex_mmc.c +F: drivers/net/ethernet/litex/* +F: drivers/soc/litex/* +F: drivers/tty/serial/liteuart.c +F: include/linux/litex.h N: litex LIVE PATCHING @@ -12156,10 +12169,17 @@ R: WANG Xuerui L: loongarch@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson.git -F: arch/loongarch/ -F: drivers/*/*loongarch* F: Documentation/loongarch/ F: Documentation/translations/zh_CN/loongarch/ +F: arch/loongarch/ +F: drivers/*/*loongarch* + +LOONGSON GPIO DRIVER +M: Yinbo Zhu +L: linux-gpio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml +F: drivers/gpio/gpio-loongson-64bit.c LOONGSON LS2X I2C DRIVER M: Binbin Zhou @@ -12168,6 +12188,14 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml F: drivers/i2c/busses/i2c-ls2x.c +LOONGSON-2 SOC SERIES CLOCK DRIVER +M: Yinbo Zhu +L: linux-clk@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml +F: drivers/clk/clk-loongson2.c +F: include/dt-bindings/clock/loongson,ls2k-clk.h + LOONGSON-2 SOC SERIES GUTS DRIVER M: Yinbo Zhu L: loongarch@lists.linux.dev @@ -12183,20 +12211,6 @@ S: Maintained F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k-pinctrl.yaml F: drivers/pinctrl/pinctrl-loongson2.c -LOONGSON GPIO DRIVER -M: Yinbo Zhu -L: linux-gpio@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml -F: drivers/gpio/gpio-loongson-64bit.c - -LOONGSON-2 SOC SERIES CLOCK DRIVER -M: Yinbo Zhu -L: linux-clk@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/clock/loongson,ls2k-clk.yaml -F: include/dt-bindings/clock/loongson,ls2k-clk.h - LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI) M: Sathya Prakash M: Sreekanth Reddy @@ -12357,20 +12371,26 @@ MAILBOX API M: Jassi Brar L: linux-kernel@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/mailbox/ F: drivers/mailbox/ +F: include/dt-bindings/mailbox/ F: include/linux/mailbox_client.h F: include/linux/mailbox_controller.h -F: include/dt-bindings/mailbox/ -F: Documentation/devicetree/bindings/mailbox/ MAILBOX ARM MHUv2 M: Viresh Kumar M: Tushar Khandelwal L: linux-kernel@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml F: drivers/mailbox/arm_mhuv2.c F: include/linux/mailbox/arm_mhuv2_message.h -F: Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml + +MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 +M: Michael Kerrisk +L: linux-man@vger.kernel.org +S: Maintained +W: http://www.kernel.org/doc/man-pages MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP) M: Jeremy Kerr @@ -12384,12 +12404,6 @@ F: include/net/mctpdevice.h F: include/net/netns/mctp.h F: net/mctp/ -MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 -M: Michael Kerrisk -L: linux-man@vger.kernel.org -S: Maintained -W: http://www.kernel.org/doc/man-pages - MAPLE TREE M: Liam R. Howlett L: linux-mm@kvack.org @@ -12421,8 +12435,8 @@ F: include/linux/platform_data/mv88e6xxx.h MARVELL ARMADA 3700 PHY DRIVERS M: Miquel Raynal S: Maintained -F: Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt F: Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml +F: Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt F: drivers/phy/marvell/phy-mvebu-a3700-comphy.c F: drivers/phy/marvell/phy-mvebu-a3700-utmi.c @@ -12524,6 +12538,13 @@ S: Maintained F: Documentation/devicetree/bindings/mtd/marvell-nand.txt F: drivers/mtd/nand/raw/marvell_nand.c +MARVELL OCTEON ENDPOINT DRIVER +M: Veerasenareddy Burru +M: Abhijit Ayarekar +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/marvell/octeon_ep + MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER M: Sunil Goutham M: Geetha sowjanya @@ -12571,13 +12592,6 @@ S: Supported F: Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml F: drivers/mmc/host/sdhci-xenon* -MARVELL OCTEON ENDPOINT DRIVER -M: Veerasenareddy Burru -M: Abhijit Ayarekar -L: netdev@vger.kernel.org -S: Supported -F: drivers/net/ethernet/marvell/octeon_ep - MATROX FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan @@ -12777,12 +12791,6 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/phy/mxl-gpy.c -MCBA MICROCHIP CAN BUS ANALYZER TOOL DRIVER -R: Yasushi SHOJI -L: linux-can@vger.kernel.org -S: Maintained -F: drivers/net/can/usb/mcba_usb.c - MCAN MMIO DEVICE DRIVER M: Chandrasekar Ramakrishnan L: linux-can@vger.kernel.org @@ -12792,6 +12800,12 @@ F: drivers/net/can/m_can/m_can.c F: drivers/net/can/m_can/m_can.h F: drivers/net/can/m_can/m_can_platform.c +MCBA MICROCHIP CAN BUS ANALYZER TOOL DRIVER +R: Yasushi SHOJI +L: linux-can@vger.kernel.org +S: Maintained +F: drivers/net/can/usb/mcba_usb.c + MCP2221A MICROCHIP USB-HID TO I2C BRIDGE DRIVER M: Rishi Gupta L: linux-i2c@vger.kernel.org @@ -13200,13 +13214,6 @@ S: Maintained F: Documentation/devicetree/bindings/clock/mediatek,mt7621-sysc.yaml F: drivers/clk/ralink/clk-mt7621.c -MEDIATEK MT7621/28/88 I2C DRIVER -M: Stefan Roese -L: linux-i2c@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/i2c/mediatek,mt7621-i2c.yaml -F: drivers/i2c/busses/i2c-mt7621.c - MEDIATEK MT7621 PCIE CONTROLLER DRIVER M: Sergio Paracuellos S: Maintained @@ -13219,6 +13226,13 @@ S: Maintained F: Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml F: drivers/phy/ralink/phy-mt7621-pci.c +MEDIATEK MT7621/28/88 I2C DRIVER +M: Stefan Roese +L: linux-i2c@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/i2c/mediatek,mt7621-i2c.yaml +F: drivers/i2c/busses/i2c-mt7621.c + MEDIATEK NAND CONTROLLER DRIVER L: linux-mtd@lists.infradead.org S: Orphan @@ -13453,13 +13467,14 @@ F: arch/powerpc/include/asm/membarrier.h F: include/uapi/linux/membarrier.h F: kernel/sched/membarrier.c -MEMBLOCK +MEMBLOCK AND MEMORY MANAGEMENT INITIALIZATION M: Mike Rapoport L: linux-mm@kvack.org S: Maintained F: Documentation/core-api/boot-time-mm.rst F: include/linux/memblock.h F: mm/memblock.c +F: mm/mm_init.c F: tools/testing/memblock/ MEMORY CONTROLLER DRIVERS @@ -13477,10 +13492,22 @@ MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA M: Dmitry Osipenko L: linux-pm@vger.kernel.org L: linux-tegra@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git F: drivers/devfreq/tegra30-devfreq.c +MEMORY HOT(UN)PLUG +M: David Hildenbrand +M: Oscar Salvador +L: linux-mm@kvack.org +S: Maintained +F: Documentation/admin-guide/mm/memory-hotplug.rst +F: Documentation/core-api/memory-hotplug.rst +F: drivers/base/memory.c +F: include/linux/memory_hotplug.h +F: mm/memory_hotplug.c +F: tools/testing/selftests/memory-hotplug/ + MEMORY MANAGEMENT M: Andrew Morton L: linux-mm@kvack.org @@ -13494,33 +13521,11 @@ F: include/linux/memory_hotplug.h F: include/linux/mm.h F: include/linux/mmzone.h F: include/linux/pagewalk.h +F: include/trace/events/ksm.h F: mm/ F: tools/mm/ F: tools/testing/selftests/mm/ -VMALLOC -M: Andrew Morton -R: Uladzislau Rezki -R: Christoph Hellwig -L: linux-mm@kvack.org -S: Maintained -W: http://www.linux-mm.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm -F: include/linux/vmalloc.h -F: mm/vmalloc.c - -MEMORY HOT(UN)PLUG -M: David Hildenbrand -M: Oscar Salvador -L: linux-mm@kvack.org -S: Maintained -F: Documentation/admin-guide/mm/memory-hotplug.rst -F: Documentation/core-api/memory-hotplug.rst -F: drivers/base/memory.c -F: include/linux/memory_hotplug.h -F: mm/memory_hotplug.c -F: tools/testing/selftests/memory-hotplug/ - MEMORY TECHNOLOGY DEVICES (MTD) M: Miquel Raynal M: Richard Weinberger @@ -13631,6 +13636,12 @@ W: http://www.monstr.eu/fdt/ T: git git://git.monstr.eu/linux-2.6-microblaze.git F: arch/microblaze/ +MICROBLAZE TMR INJECT +M: Appana Durga Kedareswara rao +S: Supported +F: Documentation/devicetree/bindings/misc/xlnx,tmr-inject.yaml +F: drivers/misc/xilinx_tmr_inject.c + MICROBLAZE TMR MANAGER M: Appana Durga Kedareswara rao S: Supported @@ -13638,12 +13649,6 @@ F: Documentation/ABI/testing/sysfs-driver-xilinx-tmr-manager F: Documentation/devicetree/bindings/misc/xlnx,tmr-manager.yaml F: drivers/misc/xilinx_tmr_manager.c -MICROBLAZE TMR INJECT -M: Appana Durga Kedareswara rao -S: Supported -F: Documentation/devicetree/bindings/misc/xlnx,tmr-inject.yaml -F: drivers/misc/xilinx_tmr_inject.c - MICROCHIP AT91 DMA DRIVERS M: Ludovic Desroches M: Tudor Ambarus @@ -13719,10 +13724,10 @@ L: linux-media@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/media/atmel,isc.yaml F: Documentation/devicetree/bindings/media/microchip,xisc.yaml -F: drivers/staging/media/deprecated/atmel/atmel-isc* -F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc* F: drivers/media/platform/microchip/microchip-isc* F: drivers/media/platform/microchip/microchip-sama*-isc* +F: drivers/staging/media/deprecated/atmel/atmel-isc* +F: drivers/staging/media/deprecated/atmel/atmel-sama*-isc* F: include/linux/atmel-isc-media.h MICROCHIP ISI DRIVER @@ -13744,13 +13749,6 @@ F: include/linux/dsa/ksz_common.h F: include/linux/platform_data/microchip-ksz.h F: net/dsa/tag_ksz.c -MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER -M: Arun Ramadoss -R: UNGLinuxDriver@microchip.com -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/phy/microchip_t1.c - MICROCHIP LAN743X ETHERNET DRIVER M: Bryan Whitehead M: UNGLinuxDriver@microchip.com @@ -13758,6 +13756,13 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/microchip/lan743x_* +MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER +M: Arun Ramadoss +R: UNGLinuxDriver@microchip.com +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/phy/microchip_t1.c + MICROCHIP LAN966X ETHERNET DRIVER M: Horatiu Vultur M: UNGLinuxDriver@microchip.com @@ -13799,14 +13804,6 @@ S: Supported F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: drivers/mtd/nand/raw/atmel/* -MICROCHIP PCI1XXXX GP DRIVER -M: Kumaravel Thiagarajan -L: linux-gpio@vger.kernel.org -S: Supported -F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c -F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h -F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c - MICROCHIP OTPC DRIVER M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -13815,6 +13812,14 @@ F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml F: drivers/nvmem/microchip-otpc.c F: include/dt-bindings/nvmem/microchip,sama7g5-otpc.h +MICROCHIP PCI1XXXX GP DRIVER +M: Kumaravel Thiagarajan +L: linux-gpio@vger.kernel.org +S: Supported +F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c +F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h +F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c + MICROCHIP PCI1XXXX I2C DRIVER M: Tharun Kumar P M: Kumaravel Thiagarajan @@ -13830,6 +13835,14 @@ L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/8250/8250_pci1xxxx.c +MICROCHIP POLARFIRE FPGA DRIVERS +M: Conor Dooley +R: Vladimir Georgiev +L: linux-fpga@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml +F: drivers/fpga/microchip-spi.c + MICROCHIP PWM DRIVER M: Claudiu Beznea L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -13851,6 +13864,12 @@ M: Claudiu Beznea S: Supported F: drivers/power/reset/at91-sama5d2_shdwc.c +MICROCHIP SOC DRIVERS +M: Conor Dooley +S: Supported +T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ +F: drivers/soc/microchip/ + MICROCHIP SPI DRIVER M: Tudor Ambarus S: Supported @@ -13864,11 +13883,12 @@ F: Documentation/devicetree/bindings/misc/atmel-ssc.txt F: drivers/misc/atmel-ssc.c F: include/linux/atmel-ssc.h -MICROCHIP SOC DRIVERS -M: Conor Dooley -S: Supported -T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ -F: drivers/soc/microchip/ +Microchip Timer Counter Block (TCB) Capture Driver +M: Kamel Bouhara +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/counter/microchip-tcb-capture.c MICROCHIP USB251XB DRIVER M: Richard Leitner @@ -13985,6 +14005,12 @@ L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/surface/surfacepro3_button.c +MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER +M: Maximilian Luz +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/surface/surface_aggregator_hub.c + MICROSOFT SURFACE SYSTEM AGGREGATOR SUBSYSTEM M: Maximilian Luz L: platform-driver-x86@vger.kernel.org @@ -14000,12 +14026,6 @@ F: include/linux/surface_acpi_notify.h F: include/linux/surface_aggregator/ F: include/uapi/linux/surface_aggregator/ -MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER -M: Maximilian Luz -L: platform-driver-x86@vger.kernel.org -S: Maintained -F: drivers/platform/surface/surface_aggregator_hub.c - MICROTEK X6 SCANNER M: Oliver Neukum S: Maintained @@ -14090,7 +14110,6 @@ L: linux-mips@vger.kernel.org S: Maintained F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ -F: drivers/*/*/*loongson1* F: drivers/*/*loongson1* MIPS/LOONGSON2EF ARCHITECTURE @@ -14172,9 +14191,12 @@ L: linux-modules@vger.kernel.org L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next +F: include/linux/kmod.h F: include/linux/module.h F: kernel/module/ +F: lib/test_kmod.c F: scripts/module* +F: tools/testing/selftests/kmod/ MONOLITHIC POWER SYSTEM PMIC DRIVER M: Saravanan Sekar @@ -14549,6 +14571,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/devicetree/bindings/net/ F: drivers/connector/ F: drivers/net/ +X: drivers/net/wireless/ F: include/dt-bindings/net/ F: include/linux/etherdevice.h F: include/linux/fcdevice.h @@ -14598,6 +14621,7 @@ B: mailto:netdev@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/core-api/netlink.rst +F: Documentation/netlink/ F: Documentation/networking/ F: Documentation/process/maintainer-netdev.rst F: Documentation/userspace-api/netlink/ @@ -14612,6 +14636,7 @@ F: include/uapi/linux/netdevice.h F: lib/net_utils.c F: lib/random32.c F: net/ +X: net/bluetooth/ F: tools/net/ F: tools/testing/selftests/net/ @@ -14762,6 +14787,7 @@ L: linux-nfs@vger.kernel.org S: Maintained W: http://client.linux-nfs.org T: git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git +F: Documentation/filesystems/nfs/ F: fs/lockd/ F: fs/nfs/ F: fs/nfs_common/ @@ -14771,7 +14797,6 @@ F: include/linux/sunrpc/ F: include/uapi/linux/nfs* F: include/uapi/linux/sunrpc/ F: net/sunrpc/ -F: Documentation/filesystems/nfs/ NILFS2 FILESYSTEM M: Ryusuke Konishi @@ -14861,6 +14886,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git F: tools/include/nolibc/ F: tools/testing/selftests/nolibc/ +NOVATEK NVT-TS I2C TOUCHSCREEN DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/input/touchscreen/novatek-nvt-ts.c + NSDEPS M: Matthias Maennich S: Maintained @@ -14905,6 +14936,7 @@ F: drivers/ntb/hw/intel/ NTFS FILESYSTEM M: Anton Altaparmakov +R: Namjae Jeon L: linux-ntfs-dev@lists.sourceforge.net S: Supported W: http://www.tuxera.com/ @@ -14969,12 +15001,6 @@ F: drivers/nvme/target/auth.c F: drivers/nvme/target/fabrics-cmd-auth.c F: include/linux/nvme-auth.h -NVM EXPRESS HARDWARE MONITORING SUPPORT -M: Guenter Roeck -L: linux-nvme@lists.infradead.org -S: Supported -F: drivers/nvme/host/hwmon.c - NVM EXPRESS FC TRANSPORT DRIVERS M: James Smart L: linux-nvme@lists.infradead.org @@ -14985,6 +15011,12 @@ F: drivers/nvme/target/fcloop.c F: include/linux/nvme-fc-driver.h F: include/linux/nvme-fc.h +NVM EXPRESS HARDWARE MONITORING SUPPORT +M: Guenter Roeck +L: linux-nvme@lists.infradead.org +S: Supported +F: drivers/nvme/host/hwmon.c + NVM EXPRESS TARGET DRIVER M: Christoph Hellwig M: Sagi Grimberg @@ -15005,6 +15037,13 @@ F: drivers/nvmem/ F: include/linux/nvmem-consumer.h F: include/linux/nvmem-provider.h +NXP BLUETOOTH WIRELESS DRIVERS +M: Amitkumar Karwar +M: Neeraj Kale +S: Maintained +F: Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml +F: drivers/bluetooth/btnxpuart.c + NXP C45 TJA11XX PHY DRIVER M: Radu Pirea L: netdev@vger.kernel.org @@ -15030,16 +15069,17 @@ F: drivers/iio/gyro/fxas21002c_core.c F: drivers/iio/gyro/fxas21002c_i2c.c F: drivers/iio/gyro/fxas21002c_spi.c -NXP i.MX CLOCK DRIVERS -M: Abel Vesa -R: Peng Fan -L: linux-clk@vger.kernel.org +NXP i.MX 7D/6SX/6UL/93 AND VF610 ADC DRIVER +M: Haibo Chen +L: linux-iio@vger.kernel.org L: linux-imx@nxp.com S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git clk/imx -F: Documentation/devicetree/bindings/clock/imx* -F: drivers/clk/imx/ -F: include/dt-bindings/clock/imx* +F: Documentation/devicetree/bindings/iio/adc/fsl,imx7d-adc.yaml +F: Documentation/devicetree/bindings/iio/adc/fsl,vf610-adc.yaml +F: Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml +F: drivers/iio/adc/imx7d_adc.c +F: drivers/iio/adc/imx93_adc.c +F: drivers/iio/adc/vf610_adc.c NXP i.MX 8M ISI DRIVER M: Laurent Pinchart @@ -15048,6 +15088,15 @@ S: Maintained F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml F: drivers/media/platform/nxp/imx8-isi/ +NXP i.MX 8MP DW100 V4L2 DRIVER +M: Xavier Roumegue +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/nxp,dw100.yaml +F: Documentation/userspace-api/media/drivers/dw100.rst +F: drivers/media/platform/nxp/dw100/ +F: include/uapi/linux/dw100.h + NXP i.MX 8MQ DCSS DRIVER M: Laurentiu Palcu R: Lucas Stach @@ -15065,17 +15114,24 @@ S: Maintained F: Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml F: drivers/iio/adc/imx8qxp-adc.c -NXP i.MX 7D/6SX/6UL/93 AND VF610 ADC DRIVER -M: Haibo Chen -L: linux-iio@vger.kernel.org +NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER +M: Mirela Rabulea +R: NXP Linux Team +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml +F: drivers/media/platform/nxp/imx-jpeg + +NXP i.MX CLOCK DRIVERS +M: Abel Vesa +R: Peng Fan +L: linux-clk@vger.kernel.org L: linux-imx@nxp.com S: Maintained -F: Documentation/devicetree/bindings/iio/adc/fsl,imx7d-adc.yaml -F: Documentation/devicetree/bindings/iio/adc/fsl,vf610-adc.yaml -F: Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml -F: drivers/iio/adc/imx7d_adc.c -F: drivers/iio/adc/imx93_adc.c -F: drivers/iio/adc/vf610_adc.c +T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelvesa/linux.git clk/imx +F: Documentation/devicetree/bindings/clock/imx* +F: drivers/clk/imx/ +F: include/dt-bindings/clock/imx* NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER M: Jagan Teki @@ -15121,6 +15177,11 @@ S: Maintained F: Documentation/devicetree/bindings/sound/tfa9879.txt F: sound/soc/codecs/tfa9879* +NXP-NCI NFC DRIVER +S: Orphan +F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml +F: drivers/nfc/nxp-nci + NXP/Goodix TFA989X (TFA1) DRIVER M: Stephan Gerhold L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -15128,28 +15189,6 @@ S: Maintained F: Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml F: sound/soc/codecs/tfa989x.c -NXP-NCI NFC DRIVER -S: Orphan -F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml -F: drivers/nfc/nxp-nci - -NXP i.MX 8MP DW100 V4L2 DRIVER -M: Xavier Roumegue -L: linux-media@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/media/nxp,dw100.yaml -F: Documentation/userspace-api/media/drivers/dw100.rst -F: drivers/media/platform/nxp/dw100/ -F: include/uapi/linux/dw100.h - -NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER -M: Mirela Rabulea -R: NXP Linux Team -L: linux-media@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml -F: drivers/media/platform/nxp/imx-jpeg - NZXT-KRAKEN2 HARDWARE MONITORING DRIVER M: Jonas Malaco L: linux-hwmon@vger.kernel.org @@ -15176,8 +15215,8 @@ OBJTOOL M: Josh Poimboeuf M: Peter Zijlstra S: Supported +F: include/linux/objtool*.h F: tools/objtool/ -F: include/linux/objtool.h OCELOT ETHERNET SWITCH DRIVER M: Vladimir Oltean @@ -15408,18 +15447,6 @@ S: Maintained F: Documentation/filesystems/omfs.rst F: fs/omfs/ -OMNIKEY CARDMAN 4000 DRIVER -M: Harald Welte -S: Maintained -F: drivers/char/pcmcia/cm4000_cs.c -F: include/linux/cm4000_cs.h -F: include/uapi/linux/cm4000_cs.h - -OMNIKEY CARDMAN 4040 DRIVER -M: Harald Welte -S: Maintained -F: drivers/char/pcmcia/cm4040_cs.* - OMNIVISION OG01A1B SENSOR DRIVER M: Shawn Tu L: linux-media@vger.kernel.org @@ -15637,6 +15664,12 @@ L: linux-hwmon@vger.kernel.org S: Maintained F: drivers/hwmon/oxp-sensors.c +ONIE TLV NVMEM LAYOUT DRIVER +M: Miquel Raynal +S: Maintained +F: Documentation/devicetree/bindings/nvmem/layouts/onie,tlv-layout.yaml +F: drivers/nvmem/layouts/onie-tlv.c + ONION OMEGA2+ BOARD M: Harvey Hunt L: linux-mips@vger.kernel.org @@ -15680,8 +15713,8 @@ M: Rob Herring M: Frank Rowand L: devicetree@vger.kernel.org S: Maintained -C: irc://irc.libera.chat/devicetree W: http://www.devicetree.org/ +C: irc://irc.libera.chat/devicetree T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git F: Documentation/ABI/testing/sysfs-firmware-ofw F: drivers/of/ @@ -15694,10 +15727,11 @@ K: of_overlay_remove OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS M: Rob Herring M: Krzysztof Kozlowski +M: Conor Dooley L: devicetree@vger.kernel.org S: Maintained -C: irc://irc.libera.chat/devicetree Q: http://patchwork.ozlabs.org/project/devicetree-bindings/list/ +C: irc://irc.libera.chat/devicetree T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git F: Documentation/devicetree/ F: arch/*/boot/dts/ @@ -15710,13 +15744,6 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/ptp/ptp_ocp.c -INTEL PTP DFL ToD DRIVER -M: Tianfei Zhang -L: linux-fpga@vger.kernel.org -L: netdev@vger.kernel.org -S: Maintained -F: drivers/ptp/ptp_dfl_tod.c - OPENCORES I2C BUS DRIVER M: Peter Korsgaard M: Andrew Lunn @@ -15735,8 +15762,8 @@ L: linux-openrisc@vger.kernel.org S: Maintained W: http://openrisc.io T: git https://github.com/openrisc/linux.git -F: Documentation/devicetree/bindings/openrisc/ F: Documentation/arch/openrisc/ +F: Documentation/devicetree/bindings/openrisc/ F: arch/openrisc/ F: drivers/irqchip/irq-ompic.c F: drivers/irqchip/irq-or1k-* @@ -16052,6 +16079,14 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/pci/controller/dwc/*layerscape* +PCI DRIVER FOR FU740 +M: Paul Walmsley +M: Greentime Hu +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml +F: drivers/pci/controller/dwc/pcie-fu740.c + PCI DRIVER FOR GENERIC OF HOSTS M: Will Deacon L: linux-pci@vger.kernel.org @@ -16072,14 +16107,6 @@ F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-ep.yaml F: Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml F: drivers/pci/controller/dwc/*imx6* -PCI DRIVER FOR FU740 -M: Paul Walmsley -M: Greentime Hu -L: linux-pci@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml -F: drivers/pci/controller/dwc/pcie-fu740.c - PCI DRIVER FOR INTEL IXP4XX M: Linus Walleij S: Maintained @@ -16159,8 +16186,8 @@ M: Jingoo Han M: Gustavo Pimentel L: linux-pci@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml F: Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml +F: Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml F: drivers/pci/controller/dwc/*designware* PCI DRIVER FOR TI DRA7XX/J721E @@ -16180,6 +16207,14 @@ S: Maintained F: Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt F: drivers/pci/controller/pci-v3-semi.c +PCI DRIVER FOR XILINX VERSAL CPM +M: Bharat Kumar Gogada +M: Michal Simek +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml +F: drivers/pci/controller/pcie-xilinx-cpm.c + PCI ENDPOINT SUBSYSTEM M: Lorenzo Pieralisi M: Krzysztof Wilczyński @@ -16217,19 +16252,6 @@ L: linux-pci@vger.kernel.org S: Supported F: Documentation/PCI/pci-error-recovery.rst -PCI PEER-TO-PEER DMA (P2PDMA) -M: Bjorn Helgaas -M: Logan Gunthorpe -L: linux-pci@vger.kernel.org -S: Supported -Q: https://patchwork.kernel.org/project/linux-pci/list/ -B: https://bugzilla.kernel.org -C: irc://irc.oftc.net/linux-pci -T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git -F: Documentation/driver-api/pci/p2pdma.rst -F: drivers/pci/p2pdma.c -F: include/linux/pci-p2pdma.h - PCI MSI DRIVER FOR ALTERA MSI IP M: Joyce Ooi L: linux-pci@vger.kernel.org @@ -16260,6 +16282,19 @@ F: drivers/pci/controller/ F: drivers/pci/pci-bridge-emul.c F: drivers/pci/pci-bridge-emul.h +PCI PEER-TO-PEER DMA (P2PDMA) +M: Bjorn Helgaas +M: Logan Gunthorpe +L: linux-pci@vger.kernel.org +S: Supported +Q: https://patchwork.kernel.org/project/linux-pci/list/ +B: https://bugzilla.kernel.org +C: irc://irc.oftc.net/linux-pci +T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: Documentation/driver-api/pci/p2pdma.rst +F: drivers/pci/p2pdma.c +F: include/linux/pci-p2pdma.h + PCI SUBSYSTEM M: Bjorn Helgaas L: linux-pci@vger.kernel.org @@ -16368,14 +16403,6 @@ L: linux-arm-msm@vger.kernel.org S: Maintained F: drivers/pci/controller/dwc/pcie-qcom.c -PCIE ENDPOINT DRIVER FOR QUALCOMM -M: Manivannan Sadhasivam -L: linux-pci@vger.kernel.org -L: linux-arm-msm@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml -F: drivers/pci/controller/dwc/pcie-qcom-ep.c - PCIE DRIVER FOR ROCKCHIP M: Shawn Lin L: linux-pci@vger.kernel.org @@ -16397,13 +16424,13 @@ L: linux-pci@vger.kernel.org S: Maintained F: drivers/pci/controller/dwc/*spear* -PCI DRIVER FOR XILINX VERSAL CPM -M: Bharat Kumar Gogada -M: Michal Simek +PCIE ENDPOINT DRIVER FOR QUALCOMM +M: Manivannan Sadhasivam L: linux-pci@vger.kernel.org +L: linux-arm-msm@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml -F: drivers/pci/controller/pcie-xilinx-cpm.c +F: Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml +F: drivers/pci/controller/dwc/pcie-qcom-ep.c PCMCIA SUBSYSTEM M: Dominik Brodowski @@ -16612,6 +16639,28 @@ F: Documentation/devicetree/bindings/pinctrl/mediatek,mt7622-pinctrl.yaml F: Documentation/devicetree/bindings/pinctrl/mediatek,mt8183-pinctrl.yaml F: drivers/pinctrl/mediatek/ +PIN CONTROLLER - MEDIATEK MIPS +M: Arınç ÜNAL +M: Sergio Paracuellos +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +L: linux-mips@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/mediatek,mt7620-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/mediatek,mt7621-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/mediatek,mt76x8-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/ralink,rt2880-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/ralink,rt305x-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/ralink,rt3352-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/ralink,rt3883-pinctrl.yaml +F: Documentation/devicetree/bindings/pinctrl/ralink,rt5350-pinctrl.yaml +F: drivers/pinctrl/mediatek/pinctrl-mt7620.c +F: drivers/pinctrl/mediatek/pinctrl-mt7621.c +F: drivers/pinctrl/mediatek/pinctrl-mt76x8.c +F: drivers/pinctrl/mediatek/pinctrl-mtmips.* +F: drivers/pinctrl/mediatek/pinctrl-rt2880.c +F: drivers/pinctrl/mediatek/pinctrl-rt305x.c +F: drivers/pinctrl/mediatek/pinctrl-rt3883.c + PIN CONTROLLER - MICROCHIP AT91 M: Ludovic Desroches L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -16620,6 +16669,14 @@ S: Supported F: drivers/gpio/gpio-sama5d2-piobu.c F: drivers/pinctrl/pinctrl-at91* +PIN CONTROLLER - NXP S32 +M: Chester Lin +R: NXP S32 Linux Team +L: linux-gpio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/nxp,s32* +F: drivers/pinctrl/nxp/ + PIN CONTROLLER - QUALCOMM M: Bjorn Andersson L: linux-arm-msm@vger.kernel.org @@ -16643,9 +16700,9 @@ R: Alim Akhtar L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org S: Maintained -C: irc://irc.libera.chat/linux-exynos Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/ B: mailto:linux-samsung-soc@vger.kernel.org +C: irc://irc.libera.chat/linux-exynos T: git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git F: Documentation/devicetree/bindings/pinctrl/samsung,pinctrl*yaml F: drivers/pinctrl/samsung/ @@ -16659,11 +16716,6 @@ L: linux-omap@vger.kernel.org S: Maintained F: drivers/pinctrl/pinctrl-single.c -PIN CONTROLLER - THUNDERBAY -M: Lakshmi Sowjanya D -S: Supported -F: drivers/pinctrl/pinctrl-thunderbay.c - PIN CONTROLLER - SUNPLUS / TIBBO M: Dvorkin Dmitry M: Wells Lu @@ -16712,13 +16764,6 @@ M: Logan Gunthorpe S: Maintained F: drivers/dma/plx_dma.c -PM6764TR DRIVER -M: Charles Hsu -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/hwmon/pm6764tr.rst -F: drivers/hwmon/pmbus/pm6764tr.c - PM-GRAPH UTILITY M: "Todd E Brandt" L: linux-pm@vger.kernel.org @@ -16728,6 +16773,13 @@ B: https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools T: git git://github.com/intel/pm-graph F: tools/power/pm-graph +PM6764TR DRIVER +M: Charles Hsu +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/pm6764tr.rst +F: drivers/hwmon/pmbus/pm6764tr.c + PMBUS HARDWARE MONITORING DRIVERS M: Guenter Roeck L: linux-hwmon@vger.kernel.org @@ -16808,15 +16860,6 @@ F: include/linux/pm_* F: include/linux/powercap.h F: kernel/configs/nopm.config -DYNAMIC THERMAL POWER MANAGEMENT (DTPM) -M: Daniel Lezcano -L: linux-pm@vger.kernel.org -S: Supported -B: https://bugzilla.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm -F: drivers/powercap/dtpm* -F: include/linux/dtpm.h - POWER STATE COORDINATION INTERFACE (PSCI) M: Mark Rutland M: Lorenzo Pieralisi @@ -16975,8 +17018,8 @@ R: Guilherme G. Piccoli L: linux-hardening@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore -F: Documentation/admin-guide/ramoops.rst F: Documentation/admin-guide/pstore-blk.rst +F: Documentation/admin-guide/ramoops.rst F: Documentation/devicetree/bindings/reserved-memory/ramoops.yaml F: drivers/acpi/apei/erst.c F: drivers/firmware/efi/efi-pstore.c @@ -17125,10 +17168,10 @@ F: sound/soc/codecs/lpass-va-macro.c F: sound/soc/codecs/lpass-wsa-macro.* F: sound/soc/codecs/msm8916-wcd-analog.c F: sound/soc/codecs/msm8916-wcd-digital.c -F: sound/soc/codecs/wcd9335.* -F: sound/soc/codecs/wcd934x.c F: sound/soc/codecs/wcd-clsh-v2.* F: sound/soc/codecs/wcd-mbhc-v2.* +F: sound/soc/codecs/wcd9335.* +F: sound/soc/codecs/wcd934x.c F: sound/soc/codecs/wsa881x.c F: sound/soc/codecs/wsa883x.c F: sound/soc/qcom/ @@ -17285,14 +17328,21 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/anttip/media_tree.git F: drivers/media/tuners/qt1010* +QUALCOMM ATH12K WIRELESS DRIVER +M: Kalle Valo +L: ath12k@lists.infradead.org +S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git +F: drivers/net/wireless/ath/ath12k/ + QUALCOMM ATHEROS ATH10K WIRELESS DRIVER M: Kalle Valo L: ath10k@lists.infradead.org S: Supported W: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git -F: drivers/net/wireless/ath/ath10k/ F: Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml +F: drivers/net/wireless/ath/ath10k/ QUALCOMM ATHEROS ATH11K WIRELESS DRIVER M: Kalle Valo @@ -17302,13 +17352,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git F: Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml F: drivers/net/wireless/ath/ath11k/ -QUALCOMM ATH12K WIRELESS DRIVER -M: Kalle Valo -L: ath12k@lists.infradead.org -S: Supported -T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git -F: drivers/net/wireless/ath/ath12k/ - QUALCOMM ATHEROS ATH9K WIRELESS DRIVER M: Toke Høiland-Jørgensen L: linux-wireless@vger.kernel.org @@ -17405,8 +17448,8 @@ F: include/uapi/misc/fastrpc.h QUALCOMM HEXAGON ARCHITECTURE M: Brian Cain L: linux-hexagon@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/bcain/linux.git S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bcain/linux.git F: arch/hexagon/ QUALCOMM HIDMA DRIVER @@ -17528,9 +17571,9 @@ M: Christian König M: Pan, Xinhui L: amd-gfx@lists.freedesktop.org S: Supported -T: git https://gitlab.freedesktop.org/agd5f/linux.git B: https://gitlab.freedesktop.org/drm/amd/-/issues C: irc://irc.oftc.net/radeon +T: git https://gitlab.freedesktop.org/agd5f/linux.git F: Documentation/gpu/amdgpu/ F: drivers/gpu/drm/amd/ F: drivers/gpu/drm/radeon/ @@ -17595,13 +17638,6 @@ L: linux-mips@vger.kernel.org S: Maintained F: arch/mips/boot/dts/ralink/mt7621* -RALINK PINCTRL DRIVER -M: Arınç ÜNAL -M: Sergio Paracuellos -L: linux-mips@vger.kernel.org -S: Maintained -F: drivers/pinctrl/ralink/ - RALINK RT2X00 WIRELESS LAN DRIVER M: Stanislaw Gruszka M: Helmut Schaa @@ -17625,8 +17661,8 @@ F: arch/mips/generic/board-ranchu.c RANDOM NUMBER DRIVER M: "Theodore Ts'o" M: Jason A. Donenfeld -T: git https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git S: Maintained +T: git https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git F: drivers/char/random.c F: drivers/virt/vmgenid.c @@ -17660,8 +17696,8 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/driver-api/media/rc-core.rst F: Documentation/userspace-api/media/rc/ F: drivers/media/rc/ -F: include/media/rc-map.h F: include/media/rc-core.h +F: include/media/rc-map.h F: include/uapi/linux/lirc.h RCMM REMOTE CONTROLS DECODER @@ -17778,6 +17814,14 @@ F: include/linux/rtc/ F: include/uapi/linux/rtc.h F: tools/testing/selftests/rtc/ +Real-time Linux Analysis (RTLA) tools +M: Daniel Bristot de Oliveira +M: Steven Rostedt +L: linux-trace-devel@vger.kernel.org +S: Maintained +F: Documentation/tools/rtla/ +F: tools/tracing/rtla/ + REALTEK AUDIO CODECS M: Oder Chiou S: Maintained @@ -17901,6 +17945,14 @@ S: Maintained F: Documentation/devicetree/bindings/sound/renesas,idt821034.yaml F: sound/soc/codecs/idt821034.c +RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER +M: Miquel Raynal +L: linux-mtd@lists.infradead.org +L: linux-renesas-soc@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/mtd/renesas-nandc.yaml +F: drivers/mtd/nand/raw/renesas-nand-controller.c + RENESAS R-CAR GYROADC DRIVER M: Marek Vasut L: linux-iio@vger.kernel.org @@ -17919,9 +17971,9 @@ F: drivers/i2c/busses/i2c-sh_mobile.c RENESAS R-CAR SATA DRIVER R: Sergey Shtylyov -S: Supported L: linux-ide@vger.kernel.org L: linux-renesas-soc@vger.kernel.org +S: Supported F: Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml F: drivers/ata/sata_rcar.c @@ -17941,12 +17993,6 @@ S: Supported F: Documentation/devicetree/bindings/i2c/renesas,riic.yaml F: drivers/i2c/busses/i2c-riic.c -RENESAS USB PHY DRIVER -M: Yoshihiro Shimoda -L: linux-renesas-soc@vger.kernel.org -S: Maintained -F: drivers/phy/renesas/phy-rcar-gen3-usb*.c - RENESAS RZ/G2L A/D DRIVER M: Lad Prabhakar L: linux-iio@vger.kernel.org @@ -17955,6 +18001,14 @@ S: Supported F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml F: drivers/iio/adc/rzg2l_adc.c +RENESAS RZ/G2L MTU3a COUNTER DRIVER +M: Biju Das +L: linux-iio@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml +F: drivers/counter/rz-mtu3-cnt.c + RENESAS RZ/N1 A5PSW SWITCH DRIVER M: Clément Léger L: linux-renesas-soc@vger.kernel.org @@ -17984,13 +18038,11 @@ S: Maintained F: Documentation/devicetree/bindings/usb/renesas,rzn1-usbf.yaml F: drivers/usb/gadget/udc/renesas_usbf.c -RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER -M: Miquel Raynal -L: linux-mtd@lists.infradead.org +RENESAS USB PHY DRIVER +M: Yoshihiro Shimoda L: linux-renesas-soc@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/mtd/renesas-nandc.yaml -F: drivers/mtd/nand/raw/renesas-nand-controller.c +F: drivers/phy/renesas/phy-rcar-gen3-usb*.c RENESAS VERSACLOCK 7 CLOCK DRIVER M: Alex Helms @@ -18058,15 +18110,6 @@ S: Maintained F: drivers/mtd/nand/raw/r852.c F: drivers/mtd/nand/raw/r852.h -RISC-V PMU DRIVERS -M: Atish Patra -R: Anup Patel -L: linux-riscv@lists.infradead.org -S: Supported -F: drivers/perf/riscv_pmu.c -F: drivers/perf/riscv_pmu_legacy.c -F: drivers/perf/riscv_pmu_sbi.c - RISC-V ARCHITECTURE M: Paul Walmsley M: Palmer Dabbelt @@ -18119,6 +18162,15 @@ T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ F: Documentation/devicetree/bindings/riscv/ F: arch/riscv/boot/dts/ +RISC-V PMU DRIVERS +M: Atish Patra +R: Anup Patel +L: linux-riscv@lists.infradead.org +S: Supported +F: drivers/perf/riscv_pmu.c +F: drivers/perf/riscv_pmu_legacy.c +F: drivers/perf/riscv_pmu_sbi.c + RNBD BLOCK DRIVERS M: Md. Haris Iqbal M: Jack Wang @@ -18200,6 +18252,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/bh1750.yaml F: drivers/iio/light/bh1750.c +ROHM BU27034 AMBIENT LIGHT SENSOR DRIVER +M: Matti Vaittinen +L: linux-iio@vger.kernel.org +S: Supported +F: drivers/iio/light/rohm-bu27034.c + ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS M: Marek Vasut L: linux-kernel@vger.kernel.org @@ -18336,6 +18394,7 @@ M: Wedson Almeida Filho R: Boqun Feng R: Gary Guo R: Björn Roy Baron +R: Benno Lossin L: rust-for-linux@vger.kernel.org S: Supported W: https://github.com/Rust-for-Linux/linux @@ -18416,14 +18475,6 @@ F: drivers/s390/net/*iucv* F: include/net/iucv/ F: net/iucv/ -S390 NETWORK DRIVERS -M: Alexandra Winter -M: Wenjia Zhang -L: linux-s390@vger.kernel.org -L: netdev@vger.kernel.org -S: Supported -F: drivers/s390/net/ - S390 MM M: Alexander Gordeev M: Gerald Schaefer @@ -18433,14 +18484,22 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git F: arch/s390/include/asm/pgtable.h F: arch/s390/mm +S390 NETWORK DRIVERS +M: Alexandra Winter +M: Wenjia Zhang +L: linux-s390@vger.kernel.org +L: netdev@vger.kernel.org +S: Supported +F: drivers/s390/net/ + S390 PCI SUBSYSTEM M: Niklas Schnelle M: Gerald Schaefer L: linux-s390@vger.kernel.org S: Supported +F: Documentation/s390/pci.rst F: arch/s390/pci/ F: drivers/pci/hotplug/s390_pci_hpc.c -F: Documentation/s390/pci.rst S390 SCM DRIVER M: Vineeth Vijayan @@ -18525,10 +18584,9 @@ F: Documentation/admin-guide/LSM/SafeSetID.rst F: security/safesetid/ SAMSUNG AUDIO (ASoC) DRIVERS -M: Krzysztof Kozlowski M: Sylwester Nawrocki L: alsa-devel@alsa-project.org (moderated for non-subscribers) -S: Supported +S: Maintained B: mailto:linux-samsung-soc@vger.kernel.org F: Documentation/devicetree/bindings/sound/samsung* F: sound/soc/samsung/ @@ -18656,7 +18714,6 @@ F: include/dt-bindings/clock/samsung,*.h F: include/linux/clk/samsung.h SAMSUNG SPI DRIVERS -M: Krzysztof Kozlowski M: Andi Shyti L: linux-spi@vger.kernel.org L: linux-samsung-soc@vger.kernel.org @@ -18724,11 +18781,6 @@ F: include/linux/wait.h F: include/uapi/linux/sched.h F: kernel/sched/ -SCR24X CHIP CARD INTERFACE DRIVER -M: Lubomir Rintel -S: Supported -F: drivers/char/pcmcia/scr24x_cs.c - SCSI RDMA PROTOCOL (SRP) INITIATOR M: Bart Van Assche L: linux-rdma@vger.kernel.org @@ -18797,12 +18849,11 @@ F: drivers/target/ F: include/target/ SCTP PROTOCOL -M: Neil Horman M: Marcelo Ricardo Leitner M: Xin Long L: linux-sctp@vger.kernel.org S: Maintained -W: http://lksctp.sourceforge.net +W: https://github.com/sctp/lksctp-tools/wiki F: Documentation/networking/sctp.rst F: include/linux/sctp.h F: include/net/sctp/ @@ -18878,6 +18929,13 @@ L: linux-mmc@vger.kernel.org S: Supported F: drivers/mmc/host/sdhci-of-at91.c +SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) NXP i.MX DRIVER +M: Haibo Chen +L: linux-imx@nxp.com +L: linux-mmc@vger.kernel.org +S: Maintained +F: drivers/mmc/host/sdhci-esdhc-imx.c + SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER M: Ben Dooks M: Jaehoon Chung @@ -18897,13 +18955,6 @@ L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/sdhci-omap.c -SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) NXP i.MX DRIVER -M: Haibo Chen -L: linux-imx@nxp.com -L: linux-mmc@vger.kernel.org -S: Maintained -F: drivers/mmc/host/sdhci-esdhc-imx.c - SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER M: Jonathan Derrick L: linux-block@vger.kernel.org @@ -18913,6 +18964,15 @@ F: block/sed* F: include/linux/sed* F: include/uapi/linux/sed* +SECURE MONITOR CALL(SMC) CALLING CONVENTION (SMCCC) +M: Mark Rutland +M: Lorenzo Pieralisi +M: Sudeep Holla +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: drivers/firmware/smccc/ +F: include/linux/arm-smccc.h + SECURITY CONTACT M: Security Officers S: Supported @@ -19021,6 +19081,7 @@ SFC NETWORK DRIVER M: Edward Cree M: Martin Habets L: netdev@vger.kernel.org +L: linux-net-drivers@amd.com S: Supported F: Documentation/networking/devlink/sfc.rst F: drivers/net/ethernet/sfc/ @@ -19307,6 +19368,12 @@ F: drivers/irqchip/irq-sl28cpld.c F: drivers/pwm/pwm-sl28cpld.c F: drivers/watchdog/sl28cpld_wdt.c +SL28 VPD NVMEM LAYOUT DRIVER +M: Michael Walle +S: Maintained +F: Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml +F: drivers/nvmem/layouts/sl28vpd.c + SLAB ALLOCATOR M: Christoph Lameter M: Pekka Enberg @@ -19355,15 +19422,6 @@ M: Nicolas Pitre S: Odd Fixes F: drivers/net/ethernet/smsc/smc91x.* -SECURE MONITOR CALL(SMC) CALLING CONVENTION (SMCCC) -M: Mark Rutland -M: Lorenzo Pieralisi -M: Sudeep Holla -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: drivers/firmware/smccc/ -F: include/linux/arm-smccc.h - SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck L: linux-hwmon@vger.kernel.org @@ -19411,6 +19469,10 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/smsc/smsc9420.* +SNET DPU VIRTIO DATA PATH ACCELERATOR +R: Alvaro Karsz +F: drivers/vdpa/solidrun/ + SOCIONEXT (SNI) AVE NETWORK DRIVER M: Kunihiko Hayashi L: netdev@vger.kernel.org @@ -19680,6 +19742,13 @@ F: include/uapi/sound/ F: sound/ F: tools/testing/selftests/alsa +SOUND - ALSA SELFTESTS +M: Mark Brown +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +L: linux-kselftest@vger.kernel.org +S: Supported +F: tools/testing/selftests/alsa + SOUND - COMPRESSED AUDIO M: Vinod Koul L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -19698,13 +19767,6 @@ F: include/sound/dmaengine_pcm.h F: sound/core/pcm_dmaengine.c F: sound/soc/soc-generic-dmaengine-pcm.c -SOUND - ALSA SELFTESTS -M: Mark Brown -L: alsa-devel@alsa-project.org (moderated for non-subscribers) -L: linux-kselftest@vger.kernel.org -S: Supported -F: tools/testing/selftests/alsa - SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC) M: Liam Girdwood M: Mark Brown @@ -19724,8 +19786,8 @@ M: Liam Girdwood M: Peter Ujfalusi M: Bard Liao M: Ranjani Sridharan -R: Kai Vehmanen M: Daniel Baluta +R: Kai Vehmanen L: sound-open-firmware@alsa-project.org (moderated for non-subscribers) S: Supported W: https://github.com/thesofproject/linux/ @@ -19787,9 +19849,9 @@ M: "Luc Van Oostenryck" L: linux-sparse@vger.kernel.org S: Maintained W: https://sparse.docs.kernel.org/ -T: git git://git.kernel.org/pub/scm/devel/sparse/sparse.git Q: https://patchwork.kernel.org/project/linux-sparse/list/ B: https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools +T: git git://git.kernel.org/pub/scm/devel/sparse/sparse.git F: include/linux/compiler.h SPEAKUP CONSOLE SPEECH DRIVER @@ -20036,19 +20098,20 @@ S: Maintained F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml F: drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c -STARFIVE JH7100 CLOCK DRIVERS -M: Emil Renner Berthing -S: Maintained -F: Documentation/devicetree/bindings/clock/starfive,jh7100-*.yaml -F: drivers/clk/starfive/clk-starfive-jh7100* -F: include/dt-bindings/clock/starfive-jh7100*.h - STARFIVE JH7110 MMC/SD/SDIO DRIVER M: William Qiu S: Supported F: Documentation/devicetree/bindings/mmc/starfive* F: drivers/mmc/host/dw_mmc-starfive.c +STARFIVE JH71X0 CLOCK DRIVERS +M: Emil Renner Berthing +M: Hal Feng +S: Maintained +F: Documentation/devicetree/bindings/clock/starfive,jh71*.yaml +F: drivers/clk/starfive/clk-starfive-jh71* +F: include/dt-bindings/clock/starfive?jh71*.h + STARFIVE JH71X0 PINCTRL DRIVERS M: Emil Renner Berthing M: Jianlong Huang @@ -20059,12 +20122,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h -STARFIVE JH7100 RESET CONTROLLER DRIVER +STARFIVE JH71X0 RESET CONTROLLER DRIVERS M: Emil Renner Berthing +M: Hal Feng S: Maintained F: Documentation/devicetree/bindings/reset/starfive,jh7100-reset.yaml -F: drivers/reset/reset-starfive-jh7100.c -F: include/dt-bindings/reset/starfive-jh7100.h +F: drivers/reset/starfive/reset-starfive-jh71* +F: include/dt-bindings/reset/starfive?jh71*.h STARFIVE JH71XX PMU CONTROLLER DRIVER M: Walker Chen @@ -20085,6 +20149,13 @@ S: Supported F: Documentation/devicetree/bindings/rng/starfive* F: drivers/char/hw_random/jh7110-trng.c +STARFIVE WATCHDOG DRIVER +M: Xingyu Wu +M: Samin Guo +S: Supported +F: Documentation/devicetree/bindings/watchdog/starfive* +F: drivers/watchdog/starfive-wdt.c + STATIC BRANCH/CALL M: Peter Zijlstra M: Josh Poimboeuf @@ -20149,6 +20220,11 @@ W: http://www.stlinux.com F: Documentation/networking/device_drivers/ethernet/stmicro/ F: drivers/net/ethernet/stmicro/stmmac/ +SUN HAPPY MEAL ETHERNET DRIVER +M: Sean Anderson +S: Maintained +F: drivers/net/ethernet/sun/sunhme.* + SUN3/3X M: Sam Creasey S: Maintained @@ -20171,11 +20247,6 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/dlink/sundance.c -SUN HAPPY MEAL ETHERNET DRIVER -M: Sean Anderson -S: Maintained -F: drivers/net/ethernet/sun/sunhme.* - SUNPLUS ETHERNET DRIVER M: Wells Lu L: netdev@vger.kernel.org @@ -20197,15 +20268,6 @@ S: Maintained F: Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml F: drivers/nvmem/sunplus-ocotp.c -SUNPLUS USB2 PHY DRIVER -M: Vincent Shih -L: linux-usb@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml -F: drivers/phy/sunplus/Kconfig -F: drivers/phy/sunplus/Makefile -F: drivers/phy/sunplus/phy-sunplus-usb2.c - SUNPLUS PWM DRIVER M: Hammer Hsieh S: Maintained @@ -20232,6 +20294,15 @@ S: Maintained F: Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml F: drivers/tty/serial/sunplus-uart.c +SUNPLUS USB2 PHY DRIVER +M: Vincent Shih +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml +F: drivers/phy/sunplus/Kconfig +F: drivers/phy/sunplus/Makefile +F: drivers/phy/sunplus/phy-sunplus-usb2.c + SUNPLUS WATCHDOG DRIVER M: Xiantao Hu L: linux-watchdog@vger.kernel.org @@ -20643,6 +20714,14 @@ F: include/linux/if_team.h F: include/uapi/linux/if_team.h F: tools/testing/selftests/drivers/net/team/ +TECHNICAL ADVISORY BOARD PROCESS DOCS +M: "Theodore Ts'o" +M: Greg Kroah-Hartman +L: tech-board-discuss@lists.linux-foundation.org +S: Maintained +F: Documentation/process/contribution-maturity-model.rst +F: Documentation/process/researcher-guidelines.rst + TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT M: "Savoir-faire Linux Inc." S: Maintained @@ -20722,6 +20801,14 @@ M: Thierry Reding S: Supported F: drivers/pwm/pwm-tegra.c +TEGRA QUAD SPI DRIVER +M: Thierry Reding +M: Jonathan Hunter +M: Sowjanya Komatineni +L: linux-tegra@vger.kernel.org +S: Maintained +F: drivers/spi/spi-tegra210-quad.c + TEGRA SERIAL DRIVER M: Laxman Dewangan S: Supported @@ -20732,14 +20819,6 @@ M: Laxman Dewangan S: Supported F: drivers/spi/spi-tegra* -TEGRA QUAD SPI DRIVER -M: Thierry Reding -M: Jonathan Hunter -M: Sowjanya Komatineni -L: linux-tegra@vger.kernel.org -S: Maintained -F: drivers/spi/spi-tegra210-quad.c - TEGRA VIDEO DRIVER M: Thierry Reding M: Jonathan Hunter @@ -20788,13 +20867,6 @@ S: Maintained F: Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml F: sound/soc/ti/ -TEXAS INSTRUMENTS' DAC7612 DAC DRIVER -M: Ricardo Ribalda -L: linux-iio@vger.kernel.org -S: Supported -F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml -F: drivers/iio/dac/ti-dac7612.c - TEXAS INSTRUMENTS DMA DRIVERS M: Peter Ujfalusi L: dmaengine@vger.kernel.org @@ -20803,10 +20875,26 @@ F: Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt F: Documentation/devicetree/bindings/dma/ti-edma.txt F: Documentation/devicetree/bindings/dma/ti/ F: drivers/dma/ti/ -X: drivers/dma/ti/cppi41.c +F: include/linux/dma/k3-psil.h F: include/linux/dma/k3-udma-glue.h F: include/linux/dma/ti-cppi5.h -F: include/linux/dma/k3-psil.h +X: drivers/dma/ti/cppi41.c + +TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER +M: Robert Marko +M: Luka Perkov +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml +F: Documentation/hwmon/tps23861.rst +F: drivers/hwmon/tps23861.c + +TEXAS INSTRUMENTS' DAC7612 DAC DRIVER +M: Ricardo Ribalda +L: linux-iio@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.yaml +F: drivers/iio/dac/ti-dac7612.c TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER M: Nishanth Menon @@ -20832,15 +20920,6 @@ F: include/dt-bindings/soc/ti,sci_pm_domain.h F: include/linux/soc/ti/ti_sci_inta_msi.h F: include/linux/soc/ti/ti_sci_protocol.h -TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER -M: Robert Marko -M: Luka Perkov -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml -F: Documentation/hwmon/tps23861.rst -F: drivers/hwmon/tps23861.c - TEXAS INSTRUMENTS' TMP117 TEMPERATURE SENSOR DRIVER M: Puranjay Mohan L: linux-iio@vger.kernel.org @@ -21317,8 +21396,8 @@ M: Steven Rostedt M: Masami Hiramatsu L: linux-kernel@vger.kernel.org L: linux-trace-kernel@vger.kernel.org -Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ S: Maintained +Q: https://patchwork.kernel.org/project/linux-trace-kernel/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git F: Documentation/trace/* F: fs/tracefs/ @@ -21346,31 +21425,15 @@ TRACING OS NOISE / LATENCY TRACERS M: Steven Rostedt M: Daniel Bristot de Oliveira S: Maintained -F: kernel/trace/trace_osnoise.c +F: Documentation/trace/hwlat_detector.rst +F: Documentation/trace/osnoise-tracer.rst +F: Documentation/trace/timerlat-tracer.rst +F: arch/*/kernel/trace.c F: include/trace/events/osnoise.h F: kernel/trace/trace_hwlat.c F: kernel/trace/trace_irqsoff.c +F: kernel/trace/trace_osnoise.c F: kernel/trace/trace_sched_wakeup.c -F: Documentation/trace/osnoise-tracer.rst -F: Documentation/trace/timerlat-tracer.rst -F: Documentation/trace/hwlat_detector.rst -F: arch/*/kernel/trace.c - -Real-time Linux Analysis (RTLA) tools -M: Daniel Bristot de Oliveira -M: Steven Rostedt -L: linux-trace-devel@vger.kernel.org -S: Maintained -F: Documentation/tools/rtla/ -F: tools/tracing/rtla/ - -TECHNICAL ADVISORY BOARD PROCESS DOCS -M: "Theodore Ts'o" -M: Greg Kroah-Hartman -L: tech-board-discuss@lists.linux-foundation.org -S: Maintained -F: Documentation/process/researcher-guidelines.rst -F: Documentation/process/contribution-maturity-model.rst TRADITIONAL CHINESE DOCUMENTATION M: Hu Haowen @@ -21506,10 +21569,8 @@ F: include/uapi/linux/ublk_cmd.h UCLINUX (M68KNOMMU AND COLDFIRE) M: Greg Ungerer L: linux-m68k@lists.linux-m68k.org -L: uclinux-dev@uclinux.org (subscribers-only) S: Maintained W: http://www.linux-m68k.org/ -W: http://www.uclinux.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu.git F: arch/m68k/*/*_no.* F: arch/m68k/68*/ @@ -21730,8 +21791,8 @@ USB ISP1760 DRIVER M: Rui Miguel Silva L: linux-usb@vger.kernel.org S: Maintained -F: drivers/usb/isp1760/* F: Documentation/devicetree/bindings/usb/nxp,isp1760.yaml +F: drivers/usb/isp1760/* USB LAN78XX ETHERNET DRIVER M: Woojung Huh @@ -21802,6 +21863,13 @@ L: linux-usb@vger.kernel.org S: Supported F: drivers/usb/class/usblp.c +USB QMI WWAN NETWORK DRIVER +M: Bjørn Mork +L: netdev@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-class-net-qmi +F: drivers/net/usb/qmi_wwan.c + USB RAW GADGET DRIVER R: Andrey Konovalov L: linux-usb@vger.kernel.org @@ -21810,13 +21878,6 @@ F: Documentation/usb/raw-gadget.rst F: drivers/usb/gadget/legacy/raw_gadget.c F: include/uapi/linux/usb/raw_gadget.h -USB QMI WWAN NETWORK DRIVER -M: Bjørn Mork -L: netdev@vger.kernel.org -S: Maintained -F: Documentation/ABI/testing/sysfs-class-net-qmi -F: drivers/net/usb/qmi_wwan.c - USB RTL8150 DRIVER M: Petko Manolov L: linux-usb@vger.kernel.org @@ -22068,6 +22129,12 @@ F: drivers/vfio/mdev/ F: include/linux/mdev.h F: samples/vfio-mdev/ +VFIO MLX5 PCI DRIVER +M: Yishai Hadas +L: kvm@vger.kernel.org +S: Maintained +F: drivers/vfio/pci/mlx5/ + VFIO PCI DEVICE SPECIFIC DRIVERS R: Jason Gunthorpe R: Yishai Hadas @@ -22084,12 +22151,6 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ -VFIO MLX5 PCI DRIVER -M: Yishai Hadas -L: kvm@vger.kernel.org -S: Maintained -F: drivers/vfio/pci/mlx5/ - VGA_SWITCHEROO R: Lukas Wunner S: Maintained @@ -22099,8 +22160,8 @@ F: drivers/gpu/vga/vga_switcheroo.c F: include/linux/vga_switcheroo.h VIA RHINE NETWORK DRIVER -S: Maintained M: Kevin Brace +S: Maintained F: drivers/net/ethernet/via/via-rhine.c VIA SD/MMC CARD CONTROLLER DRIVER @@ -22152,6 +22213,14 @@ S: Maintained F: drivers/media/common/videobuf2/* F: include/media/videobuf2-* +VIDTV VIRTUAL DIGITAL TV DRIVER +M: Daniel W. S. Almeida +L: linux-media@vger.kernel.org +S: Maintained +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +F: drivers/media/test-drivers/vidtv/* + VIMC VIRTUAL MEDIA CONTROLLER DRIVER M: Shuah Khan R: Kieran Bingham @@ -22181,6 +22250,16 @@ F: include/uapi/linux/virtio_vsock.h F: net/vmw_vsock/virtio_transport.c F: net/vmw_vsock/virtio_transport_common.c +VIRTIO BALLOON +M: "Michael S. Tsirkin" +M: David Hildenbrand +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/virtio/virtio_balloon.c +F: include/linux/balloon_compaction.h +F: include/uapi/linux/virtio_balloon.h +F: mm/balloon_compaction.c + VIRTIO BLOCK AND SCSI DRIVERS M: "Michael S. Tsirkin" M: Jason Wang @@ -22205,6 +22284,7 @@ F: include/uapi/linux/virtio_console.h VIRTIO CORE AND NET DRIVERS M: "Michael S. Tsirkin" M: Jason Wang +R: Xuan Zhuo L: virtualization@lists.linux-foundation.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-vdpa @@ -22218,33 +22298,10 @@ F: drivers/vdpa/ F: drivers/virtio/ F: include/linux/vdpa.h F: include/linux/virtio*.h +F: include/linux/vringh.h F: include/uapi/linux/virtio_*.h F: tools/virtio/ -VISL VIRTUAL STATELESS DECODER DRIVER -M: Daniel Almeida -L: linux-media@vger.kernel.org -S: Supported -F: drivers/media/test-drivers/visl - -IFCVF VIRTIO DATA PATH ACCELERATOR -R: Zhu Lingshan -F: drivers/vdpa/ifcvf/ - -SNET DPU VIRTIO DATA PATH ACCELERATOR -R: Alvaro Karsz -F: drivers/vdpa/solidrun/ - -VIRTIO BALLOON -M: "Michael S. Tsirkin" -M: David Hildenbrand -L: virtualization@lists.linux-foundation.org -S: Maintained -F: drivers/virtio/virtio_balloon.c -F: include/uapi/linux/virtio_balloon.h -F: include/linux/balloon_compaction.h -F: mm/balloon_compaction.c - VIRTIO CRYPTO DRIVER M: Gonglei L: virtualization@lists.linux-foundation.org @@ -22305,11 +22362,20 @@ L: virtualization@lists.linux-foundation.org L: netdev@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git -F: kernel/vhost_task.c F: drivers/vhost/ F: include/linux/sched/vhost_task.h F: include/linux/vhost_iotlb.h F: include/uapi/linux/vhost.h +F: kernel/vhost_task.c + +VIRTIO I2C DRIVER +M: Conghui Chen +M: Viresh Kumar +L: linux-i2c@vger.kernel.org +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/i2c/busses/i2c-virtio.c +F: include/uapi/linux/virtio_i2c.h VIRTIO INPUT DRIVER M: Gerd Hoffmann @@ -22332,6 +22398,13 @@ W: https://virtio-mem.gitlab.io/ F: drivers/virtio/virtio_mem.c F: include/uapi/linux/virtio_mem.h +VIRTIO PMEM DRIVER +M: Pankaj Gupta +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/nvdimm/nd_virtio.c +F: drivers/nvdimm/virtio_pmem.c + VIRTIO SOUND DRIVER M: Anton Yakovlev M: "Michael S. Tsirkin" @@ -22341,22 +22414,6 @@ S: Maintained F: include/uapi/linux/virtio_snd.h F: sound/virtio/* -VIRTIO I2C DRIVER -M: Conghui Chen -M: Viresh Kumar -L: linux-i2c@vger.kernel.org -L: virtualization@lists.linux-foundation.org -S: Maintained -F: drivers/i2c/busses/i2c-virtio.c -F: include/uapi/linux/virtio_i2c.h - -VIRTIO PMEM DRIVER -M: Pankaj Gupta -L: virtualization@lists.linux-foundation.org -S: Maintained -F: drivers/nvdimm/virtio_pmem.c -F: drivers/nvdimm/nd_virtio.c - VIRTUAL BOX GUEST DEVICE DRIVER M: Hans de Goede M: Arnd Bergmann @@ -22378,6 +22435,12 @@ S: Maintained F: drivers/input/serio/userio.c F: include/uapi/linux/userio.h +VISL VIRTUAL STATELESS DECODER DRIVER +M: Daniel Almeida +L: linux-media@vger.kernel.org +S: Supported +F: drivers/media/test-drivers/visl + VIVID VIRTUAL VIDEO DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org @@ -22386,14 +22449,6 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/test-drivers/vivid/* -VIDTV VIRTUAL DIGITAL TV DRIVER -M: Daniel W. S. Almeida -L: linux-media@vger.kernel.org -S: Maintained -W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git -F: drivers/media/test-drivers/vidtv/* - VLYNQ BUS M: Florian Fainelli L: openwrt-devel@lists.openwrt.org (subscribers-only) @@ -22401,16 +22456,6 @@ S: Maintained F: drivers/vlynq/vlynq.c F: include/linux/vlynq.h -VME SUBSYSTEM -M: Martyn Welch -M: Manohar Vanga -M: Greg Kroah-Hartman -L: linux-kernel@vger.kernel.org -S: Odd fixes -T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git -F: Documentation/driver-api/vme.rst -F: drivers/staging/vme_user/ - VM SOCKETS (AF_VSOCK) M: Stefano Garzarella L: virtualization@lists.linux-foundation.org @@ -22424,6 +22469,28 @@ F: include/uapi/linux/vsockmon.h F: net/vmw_vsock/ F: tools/testing/vsock/ +VMALLOC +M: Andrew Morton +R: Uladzislau Rezki +R: Christoph Hellwig +R: Lorenzo Stoakes +L: linux-mm@kvack.org +S: Maintained +W: http://www.linux-mm.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm +F: include/linux/vmalloc.h +F: mm/vmalloc.c + +VME SUBSYSTEM +M: Martyn Welch +M: Manohar Vanga +M: Greg Kroah-Hartman +L: linux-kernel@vger.kernel.org +S: Odd fixes +T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git +F: Documentation/driver-api/vme.rst +F: drivers/staging/vme_user/ + VMWARE BALLOON DRIVER M: Nadav Amit R: VMware PV-Drivers Reviewers @@ -22563,7 +22630,7 @@ S: Orphan F: drivers/mmc/host/vub300.c W1 DALLAS'S 1-WIRE BUS -M: Evgeniy Polyakov +M: Krzysztof Kozlowski S: Maintained F: Documentation/devicetree/bindings/w1/ F: Documentation/w1/ @@ -22605,9 +22672,9 @@ F: drivers/input/tablet/wacom_serial4.c WANGXUN ETHERNET DRIVER M: Jiawen Wu M: Mengyuan Lou -W: https://www.net-swift.com L: netdev@vger.kernel.org S: Maintained +W: https://www.net-swift.com F: Documentation/networking/device_drivers/ethernet/wangxun/* F: drivers/net/ethernet/wangxun/ @@ -22622,8 +22689,8 @@ F: Documentation/devicetree/bindings/watchdog/ F: Documentation/watchdog/ F: drivers/watchdog/ F: include/linux/watchdog.h -F: include/uapi/linux/watchdog.h F: include/trace/events/watchdog.h +F: include/uapi/linux/watchdog.h WHISKEYCOVE PMIC GPIO DRIVER M: Kuppuswamy Sathyanarayanan @@ -22655,9 +22722,8 @@ S: Maintained F: drivers/media/rc/winbond-cir.c WINSYSTEMS EBC-C384 WATCHDOG DRIVER -M: William Breathitt Gray L: linux-watchdog@vger.kernel.org -S: Maintained +S: Orphan F: drivers/watchdog/ebc-c384_wdt.c WINSYSTEMS WS16C48 GPIO DRIVER @@ -22733,6 +22799,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git F: Documentation/core-api/workqueue.rst F: include/linux/workqueue.h F: kernel/workqueue.c +F: kernel/workqueue_internal.h WWAN DRIVERS M: Loic Poulain @@ -22780,8 +22847,8 @@ R: "H. Peter Anvin" L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core -F: Documentation/devicetree/bindings/x86/ F: Documentation/arch/x86/ +F: Documentation/devicetree/bindings/x86/ F: arch/x86/ X86 ENTRY CODE @@ -22912,6 +22979,8 @@ M: John Fastabend L: netdev@vger.kernel.org L: bpf@vger.kernel.org S: Supported +F: drivers/net/ethernet/*/*/*/*/*xdp* +F: drivers/net/ethernet/*/*/*xdp* F: include/net/xdp.h F: include/net/xdp_priv.h F: include/trace/events/xdp.h @@ -22919,10 +22988,8 @@ F: kernel/bpf/cpumap.c F: kernel/bpf/devmap.c F: net/core/xdp.c F: samples/bpf/xdp* -F: tools/testing/selftests/bpf/*xdp* F: tools/testing/selftests/bpf/*/*xdp* -F: drivers/net/ethernet/*/*/*/*/*xdp* -F: drivers/net/ethernet/*/*/*xdp* +F: tools/testing/selftests/bpf/*xdp* K: (?:\b|_)xdp(?:\b|_) XDP SOCKETS (AF_XDP) @@ -22934,11 +23001,11 @@ L: netdev@vger.kernel.org L: bpf@vger.kernel.org S: Maintained F: Documentation/networking/af_xdp.rst +F: include/net/netns/xdp.h F: include/net/xdp_sock* F: include/net/xsk_buff_pool.h F: include/uapi/linux/if_xdp.h F: include/uapi/linux/xdp_diag.h -F: include/net/netns/xdp.h F: net/xdp/ F: tools/testing/selftests/bpf/*xsk* @@ -23040,11 +23107,11 @@ F: include/xen/arm/swiotlb-xen.h F: include/xen/swiotlb-xen.h XFS FILESYSTEM -C: irc://irc.oftc.net/xfs M: Darrick J. Wong L: linux-xfs@vger.kernel.org S: Supported W: http://xfs.org/ +C: irc://irc.oftc.net/xfs T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git F: Documentation/ABI/testing/sysfs-fs-xfs F: Documentation/admin-guide/xfs.rst @@ -23074,16 +23141,28 @@ S: Maintained F: Documentation/devicetree/bindings/net/can/xilinx,can.yaml F: drivers/net/can/xilinx_can.c +XILINX EVENT MANAGEMENT DRIVER +M: Abhyuday Godhasara +S: Maintained +F: drivers/soc/xilinx/xlnx_event_manager.c +F: include/linux/firmware/xlnx-event-manager.h + XILINX GPIO DRIVER M: Shubhrajyoti Datta R: Srinivas Neeli -R: Michal Simek +R: Michal Simek S: Maintained -F: Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml F: Documentation/devicetree/bindings/gpio/gpio-zynq.yaml +F: Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml F: drivers/gpio/gpio-xilinx.c F: drivers/gpio/gpio-zynq.c +XILINX PWM DRIVER +M: Sean Anderson +S: Maintained +F: drivers/pwm/pwm-xilinx.c +F: include/clocksource/timer-xilinx.h + XILINX SD-FEC IP CORES M: Derek Kiernan M: Dragan Cvetic @@ -23095,12 +23174,6 @@ F: drivers/misc/Makefile F: drivers/misc/xilinx_sdfec.c F: include/uapi/misc/xilinx_sdfec.h -XILINX PWM DRIVER -M: Sean Anderson -S: Maintained -F: drivers/pwm/pwm-xilinx.c -F: include/clocksource/timer-xilinx.h - XILINX UARTLITE SERIAL DRIVER M: Peter Korsgaard L: linux-serial@vger.kernel.org @@ -23117,6 +23190,14 @@ F: Documentation/devicetree/bindings/media/xilinx/ F: drivers/media/platform/xilinx/ F: include/uapi/linux/xilinx-v4l2-controls.h +XILINX WATCHDOG DRIVER +M: Srinivas Neeli +R: Shubhrajyoti Datta +R: Michal Simek +S: Maintained +F: Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml +F: drivers/watchdog/of_xilinx_wdt.c + XILINX XDMA DRIVER M: Lizhi Hou M: Brian Xu @@ -23158,12 +23239,6 @@ M: Harsha S: Maintained F: drivers/crypto/xilinx/zynqmp-sha.c -XILINX EVENT MANAGEMENT DRIVER -M: Abhyuday Godhasara -S: Maintained -F: drivers/soc/xilinx/xlnx_event_manager.c -F: include/linux/firmware/xlnx-event-manager.h - XILLYBUS DRIVER M: Eli Billauer L: linux-kernel@vger.kernel.org @@ -23211,6 +23286,13 @@ S: Maintained F: Documentation/input/devices/yealink.rst F: drivers/input/misc/yealink.* +Z3FOLD COMPRESSED PAGE ALLOCATOR +M: Vitaly Wool +R: Miaohe Lin +L: linux-mm@kvack.org +S: Maintained +F: mm/z3fold.c + Z8530 DRIVER FOR AX.25 M: Joerg Reuter L: linux-hams@vger.kernel.org @@ -23228,13 +23310,6 @@ L: linux-mm@kvack.org S: Maintained F: mm/zbud.c -Z3FOLD COMPRESSED PAGE ALLOCATOR -M: Vitaly Wool -R: Miaohe Lin -L: linux-mm@kvack.org -S: Maintained -F: mm/z3fold.c - ZD1211RW WIRELESS DRIVER M: Ulrich Kunitz L: linux-wireless@vger.kernel.org @@ -23321,10 +23396,10 @@ M: Nick Terrell S: Maintained B: https://github.com/facebook/zstd/issues T: git https://github.com/terrelln/linux.git -F: include/linux/zstd* -F: lib/zstd/ -F: lib/decompress_unzstd.c F: crypto/zstd.c +F: include/linux/zstd* +F: lib/decompress_unzstd.c +F: lib/zstd/ N: zstd K: zstd @@ -23336,13 +23411,6 @@ L: linux-mm@kvack.org S: Maintained F: mm/zswap.c -NXP BLUETOOTH WIRELESS DRIVERS -M: Amitkumar Karwar -M: Neeraj Kale -S: Maintained -F: Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml -F: drivers/bluetooth/btnxpuart.c - THE REST M: Linus Torvalds L: linux-kernel@vger.kernel.org diff --git a/Makefile b/Makefile index f5543eef4f82..09866a85bc2a 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 3 +PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc5 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* @@ -1113,7 +1113,8 @@ LDFLAGS_vmlinux += -X endif ifeq ($(CONFIG_RELR),y) -LDFLAGS_vmlinux += --pack-dyn-relocs=relr --use-android-relr-tags +# ld.lld before 15 did not support -z pack-relative-relocs. +LDFLAGS_vmlinux += $(call ld-option,--pack-dyn-relocs=relr,-z pack-relative-relocs) endif # We never want expected sections to be placed heuristically by the diff --git a/arch/Kconfig b/arch/Kconfig index e3511afbb7f2..205fd23e0cad 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -465,6 +465,38 @@ config ARCH_WANT_IRQS_OFF_ACTIVATE_MM irqs disabled over activate_mm. Architectures that do IPI based TLB shootdowns should enable this. +# Use normal mm refcounting for MMU_LAZY_TLB kernel thread references. +# MMU_LAZY_TLB_REFCOUNT=n can improve the scalability of context switching +# to/from kernel threads when the same mm is running on a lot of CPUs (a large +# multi-threaded application), by reducing contention on the mm refcount. +# +# This can be disabled if the architecture ensures no CPUs are using an mm as a +# "lazy tlb" beyond its final refcount (i.e., by the time __mmdrop frees the mm +# or its kernel page tables). This could be arranged by arch_exit_mmap(), or +# final exit(2) TLB flush, for example. +# +# To implement this, an arch *must*: +# Ensure the _lazy_tlb variants of mmgrab/mmdrop are used when manipulating +# the lazy tlb reference of a kthread's ->active_mm (non-arch code has been +# converted already). +config MMU_LAZY_TLB_REFCOUNT + def_bool y + depends on !MMU_LAZY_TLB_SHOOTDOWN + +# This option allows MMU_LAZY_TLB_REFCOUNT=n. It ensures no CPUs are using an +# mm as a lazy tlb beyond its last reference count, by shooting down these +# users before the mm is deallocated. __mmdrop() first IPIs all CPUs that may +# be using the mm as a lazy tlb, so that they may switch themselves to using +# init_mm for their active mm. mm_cpumask(mm) is used to determine which CPUs +# may be using mm as a lazy tlb mm. +# +# To implement this, an arch *must*: +# - At the time of the final mmdrop of the mm, ensure mm_cpumask(mm) contains +# at least all possible CPUs in which the mm is lazy. +# - It must meet the requirements for MMU_LAZY_TLB_REFCOUNT=n (see above). +config MMU_LAZY_TLB_SHOOTDOWN + bool + config ARCH_HAVE_NMI_SAFE_CMPXCHG bool diff --git a/arch/alpha/include/asm/cmpxchg.h b/arch/alpha/include/asm/cmpxchg.h index 6e0a850aa9d3..91d4a4d9258c 100644 --- a/arch/alpha/include/asm/cmpxchg.h +++ b/arch/alpha/include/asm/cmpxchg.h @@ -6,15 +6,15 @@ * Atomic exchange routines. */ -#define ____xchg(type, args...) __xchg ## type ## _local(args) +#define ____xchg(type, args...) __arch_xchg ## type ## _local(args) #define ____cmpxchg(type, args...) __cmpxchg ## type ## _local(args) #include #define xchg_local(ptr, x) \ ({ \ __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_, \ - sizeof(*(ptr))); \ + (__typeof__(*(ptr))) __arch_xchg_local((ptr), (unsigned long)_x_,\ + sizeof(*(ptr))); \ }) #define arch_cmpxchg_local(ptr, o, n) \ @@ -34,7 +34,7 @@ #undef ____xchg #undef ____cmpxchg -#define ____xchg(type, args...) __xchg ##type(args) +#define ____xchg(type, args...) __arch_xchg ##type(args) #define ____cmpxchg(type, args...) __cmpxchg ##type(args) #include @@ -48,7 +48,7 @@ __typeof__(*(ptr)) _x_ = (x); \ smp_mb(); \ __ret = (__typeof__(*(ptr))) \ - __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ + __arch_xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ smp_mb(); \ __ret; \ }) diff --git a/arch/alpha/include/asm/local.h b/arch/alpha/include/asm/local.h index fab26a1c93d5..0fcaad642cc3 100644 --- a/arch/alpha/include/asm/local.h +++ b/arch/alpha/include/asm/local.h @@ -52,8 +52,16 @@ static __inline__ long local_sub_return(long i, local_t * l) return result; } -#define local_cmpxchg(l, o, n) \ - (cmpxchg_local(&((l)->a.counter), (o), (n))) +static __inline__ long local_cmpxchg(local_t *l, long old, long new) +{ + return cmpxchg_local(&l->a.counter, old, new); +} + +static __inline__ bool local_try_cmpxchg(local_t *l, long *old, long new) +{ + return try_cmpxchg_local(&l->a.counter, (s64 *)old, new); +} + #define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n))) /** diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index e9cf7193eb81..582d96548385 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -9,6 +9,7 @@ * This file handles the architecture-dependent parts of process handling. */ +#include #include #include #include @@ -59,9 +60,10 @@ void arch_cpu_idle(void) wtint(0); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { wtint(INT_MAX); + BUG(); } #endif /* ALPHA_WTINT */ diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 0ede4b044e86..7439b2377df5 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -562,7 +562,7 @@ handle_ipi(struct pt_regs *regs) } void -smp_send_reschedule(int cpu) +arch_smp_send_reschedule(int cpu) { #ifdef DEBUG_IPI_MSG if (cpu == hard_smp_processor_id()) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index d9a13ccf89a3..ab6d701365bb 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -556,7 +556,7 @@ endmenu # "ARC Architecture Configuration" config ARCH_FORCE_MAX_ORDER int "Maximum zone order" - default "12" if ARC_HUGEPAGE_16M - default "11" + default "11" if ARC_HUGEPAGE_16M + default "10" source "kernel/power/Kconfig" diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h index c5b544a5fe81..e138fde067de 100644 --- a/arch/arc/include/asm/cmpxchg.h +++ b/arch/arc/include/asm/cmpxchg.h @@ -85,7 +85,7 @@ */ #ifdef CONFIG_ARC_HAS_LLSC -#define __xchg(ptr, val) \ +#define __arch_xchg(ptr, val) \ ({ \ __asm__ __volatile__( \ " ex %0, [%1] \n" /* set new value */ \ @@ -102,7 +102,7 @@ \ switch(sizeof(*(_p_))) { \ case 4: \ - _val_ = __xchg(_p_, _val_); \ + _val_ = __arch_xchg(_p_, _val_); \ break; \ default: \ BUILD_BUG(); \ diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index ad93fe6e4b77..409cfa4675b4 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -292,7 +292,7 @@ static void ipi_send_msg(const struct cpumask *callmap, enum ipi_msg_type msg) ipi_send_msg_one(cpu, msg); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { ipi_send_msg_one(cpu, IPI_RESCHEDULE); } diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index 200270a94558..9270d0a713c3 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c @@ -369,6 +369,8 @@ void *unwind_add_table(struct module *module, const void *table_start, unsigned long table_size) { struct unwind_table *table; + struct module_memory *core_text; + struct module_memory *init_text; if (table_size <= 0) return NULL; @@ -377,11 +379,11 @@ void *unwind_add_table(struct module *module, const void *table_start, if (!table) return NULL; - init_unwind_table(table, module->name, - module->core_layout.base, module->core_layout.size, - module->init_layout.base, module->init_layout.size, - table_start, table_size, - NULL, 0); + core_text = &module->mem[MOD_TEXT]; + init_text = &module->mem[MOD_INIT_TEXT]; + + init_unwind_table(table, module->name, core_text->base, core_text->size, + init_text->base, init_text->size, table_start, table_size, NULL, 0); init_unwind_hdr(table, unw_hdr_alloc); diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index ce4e939a7f07..2b89b6c53801 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -74,11 +74,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) base, TO_MB(size), !in_use ? "Not used":""); } -bool arch_has_descending_max_zone_pfns(void) -{ - return !IS_ENABLED(CONFIG_ARC_HAS_PAE40); -} - /* * First memory setup routine called from setup_arch() * 1. setup swapper's mm @init_mm diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a8b82c2f333b..0fb4b218f665 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1352,20 +1352,19 @@ config ARM_MODULE_PLTS configurations. If unsure, say y. config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - default "12" if SOC_AM33XX - default "9" if SA1111 - default "11" + int "Order of maximal physically contiguous allocations" + default "11" if SOC_AM33XX + default "8" if SA1111 + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + Don't change if unsure. config ALIGNMENT_TRAP def_bool CPU_CP15_MMU diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c index 74255e819831..0669851394f0 100644 --- a/arch/arm/boot/compressed/decompress.c +++ b/arch/arm/boot/compressed/decompress.c @@ -31,6 +31,7 @@ /* Not needed, but used in some headers pulled in by decompressors */ extern char * strstr(const char * s1, const char *s2); extern size_t strlen(const char *s); +extern int strcmp(const char *cs, const char *ct); extern int memcmp(const void *cs, const void *ct, size_t count); extern char * strchrnul(const char *, int); diff --git a/arch/arm/boot/dts/imx6qdl-mba6.dtsi b/arch/arm/boot/dts/imx6qdl-mba6.dtsi index 78555a618851..7b7e6c2ad190 100644 --- a/arch/arm/boot/dts/imx6qdl-mba6.dtsi +++ b/arch/arm/boot/dts/imx6qdl-mba6.dtsi @@ -209,6 +209,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pcie>; reset-gpio = <&gpio6 7 GPIO_ACTIVE_LOW>; + vpcie-supply = <®_pcie>; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6ull-dhcor-som.dtsi b/arch/arm/boot/dts/imx6ull-dhcor-som.dtsi index 5882c7565f64..32a6022625d9 100644 --- a/arch/arm/boot/dts/imx6ull-dhcor-som.dtsi +++ b/arch/arm/boot/dts/imx6ull-dhcor-som.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include "imx6ull.dtsi" / { @@ -84,16 +85,20 @@ regulators { vdd_soc_in_1v4: buck1 { + regulator-allowed-modes = ; /* PFM */ regulator-always-on; regulator-boot-on; + regulator-initial-mode = ; regulator-max-microvolt = <1400000>; regulator-min-microvolt = <1400000>; regulator-name = "vdd_soc_in_1v4"; }; vcc_3v3: buck2 { + regulator-allowed-modes = ; /* PWM */ regulator-always-on; regulator-boot-on; + regulator-initial-mode = ; regulator-max-microvolt = <3300000>; regulator-min-microvolt = <3300000>; regulator-name = "vcc_3v3"; @@ -106,8 +111,10 @@ * the voltage is set to 1.5V. */ vcc_ddr_1v35: buck3 { + regulator-allowed-modes = ; /* PWM */ regulator-always-on; regulator-boot-on; + regulator-initial-mode = ; regulator-max-microvolt = <1500000>; regulator-min-microvolt = <1500000>; regulator-name = "vcc_ddr_1v35"; diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi index 7f7d2d5122fb..f91bf719d4e2 100644 --- a/arch/arm/boot/dts/imx7ulp.dtsi +++ b/arch/arm/boot/dts/imx7ulp.dtsi @@ -189,7 +189,7 @@ }; usbotg1: usb@40330000 { - compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb"; + compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb"; reg = <0x40330000 0x200>; interrupts = ; clocks = <&pcc2 IMX7ULP_CLK_USB0>; @@ -202,7 +202,8 @@ }; usbmisc1: usbmisc@40330200 { - compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x40330200 0x200>; }; diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi index c9e05e3540d6..00bf53f99c29 100644 --- a/arch/arm/boot/dts/stm32f429.dtsi +++ b/arch/arm/boot/dts/stm32f429.dtsi @@ -387,6 +387,7 @@ interrupt-names = "tx", "rx0", "rx1", "sce"; resets = <&rcc STM32F4_APB1_RESET(CAN2)>; clocks = <&rcc 0 STM32F4_APB1_CLOCK(CAN2)>; + st,can-secondary; st,gcan = <&gcan>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/stm32f7-pinctrl.dtsi b/arch/arm/boot/dts/stm32f7-pinctrl.dtsi index c8e6c52fb248..9f65403295ca 100644 --- a/arch/arm/boot/dts/stm32f7-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32f7-pinctrl.dtsi @@ -283,6 +283,88 @@ slew-rate = <2>; }; }; + + can1_pins_a: can1-0 { + pins1 { + pinmux = ; /* CAN1_TX */ + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-pull-up; + }; + }; + + can1_pins_b: can1-1 { + pins1 { + pinmux = ; /* CAN1_TX */ + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-pull-up; + }; + }; + + can1_pins_c: can1-2 { + pins1 { + pinmux = ; /* CAN1_TX */ + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-pull-up; + + }; + }; + + can1_pins_d: can1-3 { + pins1 { + pinmux = ; /* CAN1_TX */ + }; + pins2 { + pinmux = ; /* CAN1_RX */ + bias-pull-up; + + }; + }; + + can2_pins_a: can2-0 { + pins1 { + pinmux = ; /* CAN2_TX */ + }; + pins2 { + pinmux = ; /* CAN2_RX */ + bias-pull-up; + }; + }; + + can2_pins_b: can2-1 { + pins1 { + pinmux = ; /* CAN2_TX */ + }; + pins2 { + pinmux = ; /* CAN2_RX */ + bias-pull-up; + }; + }; + + can3_pins_a: can3-0 { + pins1 { + pinmux = ; /* CAN3_TX */ + }; + pins2 { + pinmux = ; /* CAN3_RX */ + bias-pull-up; + }; + }; + + can3_pins_b: can3-1 { + pins1 { + pinmux = ; /* CAN3_TX */ + }; + pins2 { + pinmux = ; /* CAN3_RX */ + bias-pull-up; + }; + }; }; }; }; diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi index 4e437d3f2ed6..63f4c78fcc1d 100644 --- a/arch/arm/boot/dts/stm32mp151.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -1130,8 +1130,8 @@ usbotg_hs: usb-otg@49000000 { compatible = "st,stm32mp15-hsotg", "snps,dwc2"; reg = <0x49000000 0x10000>; - clocks = <&rcc USBO_K>; - clock-names = "otg"; + clocks = <&rcc USBO_K>, <&usbphyc>; + clock-names = "otg", "utmi"; resets = <&rcc USBO_R>; reset-names = "dwc2"; interrupts = ; diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts index 3b88209bacea..ff1f9a1bcfcf 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts @@ -132,6 +132,7 @@ reg = <0x2c0f0000 0x1000>; interrupts = <0 84 4>; cache-level = <2>; + cache-unified; }; pmu { diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 62f2b8972160..4de293da4789 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -31,7 +31,7 @@ CONFIG_SOC_VF610=y CONFIG_SMP=y CONFIG_ARM_PSCI=y CONFIG_HIGHMEM=y -CONFIG_ARCH_FORCE_MAX_ORDER=14 +CONFIG_ARCH_FORCE_MAX_ORDER=13 CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" CONFIG_KEXEC=y CONFIG_CPU_FREQ=y diff --git a/arch/arm/configs/milbeaut_m10v_defconfig b/arch/arm/configs/milbeaut_m10v_defconfig index bd29e5012cb0..385ad0f391a8 100644 --- a/arch/arm/configs/milbeaut_m10v_defconfig +++ b/arch/arm/configs/milbeaut_m10v_defconfig @@ -26,7 +26,7 @@ CONFIG_THUMB2_KERNEL=y # CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11 is not set # CONFIG_ARM_PATCH_IDIV is not set CONFIG_HIGHMEM=y -CONFIG_ARCH_FORCE_MAX_ORDER=12 +CONFIG_ARCH_FORCE_MAX_ORDER=11 CONFIG_SECCOMP=y CONFIG_KEXEC=y CONFIG_EFI=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index e656d3af2266..b46e39369dbb 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -20,7 +20,7 @@ CONFIG_PXA_SHARPSL=y CONFIG_MACH_AKITA=y CONFIG_MACH_BORZOI=y CONFIG_AEABI=y -CONFIG_ARCH_FORCE_MAX_ORDER=9 +CONFIG_ARCH_FORCE_MAX_ORDER=8 CONFIG_CMDLINE="root=/dev/ram0 ro" CONFIG_KEXEC=y CONFIG_CPU_FREQ=y diff --git a/arch/arm/configs/sama7_defconfig b/arch/arm/configs/sama7_defconfig index 0d964c613d71..954112041403 100644 --- a/arch/arm/configs/sama7_defconfig +++ b/arch/arm/configs/sama7_defconfig @@ -19,7 +19,7 @@ CONFIG_ATMEL_CLOCKSOURCE_TCB=y # CONFIG_CACHE_L2X0 is not set # CONFIG_ARM_PATCH_IDIV is not set # CONFIG_CPU_SW_DOMAIN_PAN is not set -CONFIG_ARCH_FORCE_MAX_ORDER=15 +CONFIG_ARCH_FORCE_MAX_ORDER=14 CONFIG_UACCESS_WITH_MEMCPY=y # CONFIG_ATAGS is not set CONFIG_CMDLINE="console=ttyS0,115200 earlyprintk ignore_loglevel" diff --git a/arch/arm/configs/sp7021_defconfig b/arch/arm/configs/sp7021_defconfig index 5bca2eb59b86..c6448ac860b6 100644 --- a/arch/arm/configs/sp7021_defconfig +++ b/arch/arm/configs/sp7021_defconfig @@ -17,7 +17,7 @@ CONFIG_ARCH_SUNPLUS=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_THUMB2_KERNEL=y -CONFIG_ARCH_FORCE_MAX_ORDER=12 +CONFIG_ARCH_FORCE_MAX_ORDER=11 CONFIG_VFP=y CONFIG_NEON=y CONFIG_MODULES=y diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h index 78d3d4b82c6c..f4db3e75d75f 100644 --- a/arch/arm/include/asm/arm_pmuv3.h +++ b/arch/arm/include/asm/arm_pmuv3.h @@ -92,7 +92,7 @@ #define RETURN_READ_PMEVCNTRN(n) \ return read_sysreg(PMEVCNTR##n) -static unsigned long read_pmevcntrn(int n) +static inline unsigned long read_pmevcntrn(int n) { PMEVN_SWITCH(n, RETURN_READ_PMEVCNTRN); return 0; @@ -100,14 +100,14 @@ static unsigned long read_pmevcntrn(int n) #define WRITE_PMEVCNTRN(n) \ write_sysreg(val, PMEVCNTR##n) -static void write_pmevcntrn(int n, unsigned long val) +static inline void write_pmevcntrn(int n, unsigned long val) { PMEVN_SWITCH(n, WRITE_PMEVCNTRN); } #define WRITE_PMEVTYPERN(n) \ write_sysreg(val, PMEVTYPER##n) -static void write_pmevtypern(int n, unsigned long val) +static inline void write_pmevtypern(int n, unsigned long val) { PMEVN_SWITCH(n, WRITE_PMEVTYPERN); } diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h index 4dfe538dfc68..44667bdb4707 100644 --- a/arch/arm/include/asm/cmpxchg.h +++ b/arch/arm/include/asm/cmpxchg.h @@ -25,7 +25,8 @@ #define swp_is_buggy #endif -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) +static inline unsigned long +__arch_xchg(unsigned long x, volatile void *ptr, int size) { extern void __bad_xchg(volatile void *, int); unsigned long ret; @@ -115,8 +116,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size } #define arch_xchg_relaxed(ptr, x) ({ \ - (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \ - sizeof(*(ptr))); \ + (__typeof__(*(ptr)))__arch_xchg((unsigned long)(x), (ptr), \ + sizeof(*(ptr))); \ }) #include diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h index fe9ef6f79e9c..82ec1ccf1fee 100644 --- a/arch/arm/include/asm/dma-iommu.h +++ b/arch/arm/include/asm/dma-iommu.h @@ -24,7 +24,7 @@ struct dma_iommu_mapping { }; struct dma_iommu_mapping * -arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size); +arm_iommu_create_mapping(const struct bus_type *bus, dma_addr_t base, u64 size); void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c index d8a509c5d5bd..20218876bef2 100644 --- a/arch/arm/kernel/isa.c +++ b/arch/arm/kernel/isa.c @@ -40,27 +40,11 @@ static struct ctl_table ctl_isa_vars[4] = { static struct ctl_table_header *isa_sysctl_header; -static struct ctl_table ctl_isa[2] = { - { - .procname = "isa", - .mode = 0555, - .child = ctl_isa_vars, - }, {} -}; - -static struct ctl_table ctl_bus[2] = { - { - .procname = "bus", - .mode = 0555, - .child = ctl_isa, - }, {} -}; - void __init register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift) { isa_membase = membase; isa_portbase = portbase; isa_portshift = portshift; - isa_sysctl_header = register_sysctl_table(ctl_bus); + isa_sysctl_header = register_sysctl("bus/isa", ctl_isa_vars); } diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index af7c322ebed6..f5a43fd8c163 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -28,11 +28,6 @@ static const u32 fixed_plts[] = { #endif }; -static bool in_init(const struct module *mod, unsigned long loc) -{ - return loc - (u32)mod->init_layout.base < mod->init_layout.size; -} - static void prealloc_fixed(struct mod_plt_sec *pltsec, struct plt_entries *plt) { int i; @@ -50,8 +45,8 @@ static void prealloc_fixed(struct mod_plt_sec *pltsec, struct plt_entries *plt) u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { - struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : - &mod->arch.init; + struct mod_plt_sec *pltsec = !within_module_init(loc, mod) ? + &mod->arch.core : &mod->arch.init; struct plt_entries *plt; int idx; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 0b8c25763adc..87f8d0e5e314 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -48,7 +48,6 @@ #include #include -#define CREATE_TRACE_POINTS #include /* @@ -320,7 +319,7 @@ void __cpu_die(unsigned int cpu) * of the other hotplug-cpu capable cores, so presumably coming * out of idle fixes this. */ -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { unsigned int cpu = smp_processor_id(); @@ -382,6 +381,8 @@ void arch_cpu_idle_dead(void) : "r" (task_stack_page(current) + THREAD_SIZE - 8), "r" (current) : "r0"); + + unreachable(); } #endif /* CONFIG_HOTPLUG_CPU */ @@ -747,7 +748,7 @@ void __init set_smp_ipi_range(int ipi_base, int n) ipi_setup(smp_processor_id()); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } @@ -777,7 +778,7 @@ void smp_send_stop(void) * kdump fails. So split out the panic_smp_self_stop() and add * set_cpu_online(smp_processor_id(), false). */ -void panic_smp_self_stop(void) +void __noreturn panic_smp_self_stop(void) { pr_debug("CPU %u will stop doing anything useful since another CPU has paniced\n", smp_processor_id()); diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 53be7ea6181b..9d2192156087 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -308,6 +308,29 @@ static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl, return URC_OK; } +static unsigned long unwind_decode_uleb128(struct unwind_ctrl_block *ctrl) +{ + unsigned long bytes = 0; + unsigned long insn; + unsigned long result = 0; + + /* + * unwind_get_byte() will advance `ctrl` one instruction at a time, so + * loop until we get an instruction byte where bit 7 is not set. + * + * Note: This decodes a maximum of 4 bytes to output 28 bits data where + * max is 0xfffffff: that will cover a vsp increment of 1073742336, hence + * it is sufficient for unwinding the stack. + */ + do { + insn = unwind_get_byte(ctrl); + result |= (insn & 0x7f) << (bytes * 7); + bytes++; + } while (!!(insn & 0x80) && (bytes != sizeof(result))); + + return result; +} + /* * Execute the current unwind instruction. */ @@ -361,7 +384,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) if (ret) goto error; } else if (insn == 0xb2) { - unsigned long uleb128 = unwind_get_byte(ctrl); + unsigned long uleb128 = unwind_decode_uleb128(ctrl); ctrl->vrs[SP] += 0x204 + (uleb128 << 2); } else { diff --git a/arch/arm/mach-actions/platsmp.c b/arch/arm/mach-actions/platsmp.c index f26618b43514..7b208e96fbb6 100644 --- a/arch/arm/mach-actions/platsmp.c +++ b/arch/arm/mach-actions/platsmp.c @@ -20,6 +20,8 @@ #include #include +#include + #define OWL_CPU1_ADDR 0x50 #define OWL_CPU1_FLAG 0x5c diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 26f0ebc4d136..4325bdc2b9ff 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c index 53813f9464a2..c30df1097c52 100644 --- a/arch/arm/mach-rpc/ecard.c +++ b/arch/arm/mach-rpc/ecard.c @@ -253,7 +253,7 @@ static int ecard_init_mm(void) current->mm = mm; current->active_mm = mm; activate_mm(active_mm, mm); - mmdrop(active_mm); + mmdrop_lazy_tlb(active_mm); ecard_init_pgtables(mm); return 0; } diff --git a/arch/arm/mach-sa1100/jornada720_ssp.c b/arch/arm/mach-sa1100/jornada720_ssp.c index 67f72ca984b2..1956b095e699 100644 --- a/arch/arm/mach-sa1100/jornada720_ssp.c +++ b/arch/arm/mach-sa1100/jornada720_ssp.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * arch/arm/mac-sa1100/jornada720_ssp.c * * Copyright (C) 2006/2007 Kristoffer Ericson @@ -26,6 +26,7 @@ static unsigned long jornada_ssp_flags; /** * jornada_ssp_reverse - reverses input byte + * @byte: input byte to reverse * * we need to reverse all data we receive from the mcu due to its physical location * returns : 01110111 -> 11101110 @@ -46,6 +47,7 @@ EXPORT_SYMBOL(jornada_ssp_reverse); /** * jornada_ssp_byte - waits for ready ssp bus and sends byte + * @byte: input byte to transmit * * waits for fifo buffer to clear and then transmits, if it doesn't then we will * timeout after rounds. Needs mcu running before its called. @@ -77,6 +79,7 @@ EXPORT_SYMBOL(jornada_ssp_byte); /** * jornada_ssp_inout - decide if input is command or trading byte + * @byte: input byte to send (may be %TXDUMMY) * * returns : (jornada_ssp_byte(byte)) on success * : %-ETIMEDOUT on timeout failure diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 8bc01071474a..b4a33358d2e9 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1543,7 +1543,7 @@ static const struct dma_map_ops iommu_ops = { * arm_iommu_attach_device function. */ struct dma_iommu_mapping * -arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size) +arm_iommu_create_mapping(const struct bus_type *bus, dma_addr_t base, u64 size) { unsigned int bits = size >> PAGE_SHIFT; unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 7483ef8bccda..62206ef25037 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -23,6 +23,9 @@ @ ENTRY(do_vfp) mov r1, r10 - mov r3, r9 - b vfp_entry + str lr, [sp, #-8]! + add r3, sp, #4 + str r9, [r3] + bl vfp_entry + ldr pc, [sp], #8 ENDPROC(do_vfp) diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 4d8478264d82..a4610d0f3215 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -172,13 +172,14 @@ vfp_hw_state_valid: @ out before setting an FPEXC that @ stops us reading stuff VFPFMXR FPEXC, r1 @ Restore FPEXC last + mov sp, r3 @ we think we have handled things + pop {lr} sub r2, r2, #4 @ Retry current instruction - if Thumb str r2, [sp, #S_PC] @ mode it's two 16-bit instructions, @ else it's one 32-bit instruction, so @ always subtract 4 from the following @ instruction address. - mov lr, r3 @ we think we have handled things local_bh_enable_and_ret: adr r0, . mov r1, #SOFTIRQ_DISABLE_OFFSET @@ -209,8 +210,9 @@ skip: process_exception: DBGSTR "bounce" + mov sp, r3 @ setup for a return to the user code. + pop {lr} mov r2, sp @ nothing stacked - regdump is at TOS - mov lr, r3 @ setup for a return to the user code. @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 3f5bf55050e8..b1201d25a8a4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -95,6 +95,7 @@ config ARM64 select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_SUPPORTS_PAGE_TABLE_CHECK + select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT select ARCH_WANT_DEFAULT_BPF_JIT select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT @@ -1505,39 +1506,34 @@ config XEN # include/linux/mmzone.h requires the following to be true: # -# MAX_ORDER - 1 + PAGE_SHIFT <= SECTION_SIZE_BITS +# MAX_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS # -# so the maximum value of MAX_ORDER is SECTION_SIZE_BITS + 1 - PAGE_SHIFT: +# so the maximum value of MAX_ORDER is SECTION_SIZE_BITS - PAGE_SHIFT: # # | SECTION_SIZE_BITS | PAGE_SHIFT | max MAX_ORDER | default MAX_ORDER | # ----+-------------------+--------------+-----------------+--------------------+ -# 4K | 27 | 12 | 16 | 11 | -# 16K | 27 | 14 | 14 | 12 | -# 64K | 29 | 16 | 14 | 14 | +# 4K | 27 | 12 | 15 | 10 | +# 16K | 27 | 14 | 13 | 11 | +# 64K | 29 | 16 | 13 | 13 | config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" if ARM64_4K_PAGES || ARM64_16K_PAGES - default "14" if ARM64_64K_PAGES - range 12 14 if ARM64_16K_PAGES - default "12" if ARM64_16K_PAGES - range 11 16 if ARM64_4K_PAGES - default "11" + int "Order of maximal physically contiguous allocations" if EXPERT && (ARM64_4K_PAGES || ARM64_16K_PAGES) + default "13" if ARM64_64K_PAGES + default "11" if ARM64_16K_PAGES + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + The maximal size of allocation cannot exceed the size of the + section, so the value of MAX_ORDER should satisfy - We make sure that we can allocate up to a HugePage size for each configuration. - Hence we have : - MAX_ORDER = (PMD_SHIFT - PAGE_SHIFT) + 1 => PAGE_SHIFT - 2 + MAX_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS - However for 4K, we choose a higher default value, 11 as opposed to 10, giving us - 4M allocations matching the default size used by generic code. + Don't change if unsure. config UNMAP_KERNEL_AT_EL0 bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index c65aee088410..1761f5972443 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -42,5 +42,9 @@ $(obj)/Image.zst: $(obj)/Image FORCE EFI_ZBOOT_PAYLOAD := Image EFI_ZBOOT_BFD_TARGET := elf64-littleaarch64 EFI_ZBOOT_MACH_TYPE := ARM64 +EFI_ZBOOT_FORWARD_CFI := $(CONFIG_ARM64_BTI_KERNEL) + +EFI_ZBOOT_OBJCOPY_FLAGS = --add-symbol zboot_code_size=0x$(shell \ + $(NM) vmlinux|grep _kernel_codesize|cut -d' ' -f1) include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi index feb27a0ccfb4..0c49655cc90c 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -2045,7 +2045,8 @@ }; uart_AO: serial@3000 { - compatible = "amlogic,meson-gx-uart", + compatible = "amlogic,meson-g12a-uart", + "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; reg = <0x0 0x3000 0x0 0x18>; interrupts = ; @@ -2055,7 +2056,8 @@ }; uart_AO_B: serial@4000 { - compatible = "amlogic,meson-gx-uart", + compatible = "amlogic,meson-g12a-uart", + "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; reg = <0x0 0x4000 0x0 0x18>; interrupts = ; @@ -2292,7 +2294,8 @@ }; uart_C: serial@22000 { - compatible = "amlogic,meson-gx-uart"; + compatible = "amlogic,meson-g12a-uart", + "amlogic,meson-gx-uart"; reg = <0x0 0x22000 0x0 0x18>; interrupts = ; clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; @@ -2301,7 +2304,8 @@ }; uart_B: serial@23000 { - compatible = "amlogic,meson-gx-uart"; + compatible = "amlogic,meson-g12a-uart", + "amlogic,meson-gx-uart"; reg = <0x0 0x23000 0x0 0x18>; interrupts = ; clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; @@ -2310,7 +2314,8 @@ }; uart_A: serial@24000 { - compatible = "amlogic,meson-gx-uart"; + compatible = "amlogic,meson-g12a-uart", + "amlogic,meson-gx-uart"; reg = <0x0 0x24000 0x0 0x18>; interrupts = ; clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dtsi b/arch/arm64/boot/dts/arm/foundation-v8.dtsi index 029578072d8f..7b41537731a6 100644 --- a/arch/arm64/boot/dts/arm/foundation-v8.dtsi +++ b/arch/arm64/boot/dts/arm/foundation-v8.dtsi @@ -59,6 +59,7 @@ L2_0: l2-cache0 { compatible = "cache"; cache-level = <2>; + cache-unified; }; }; diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts index ef68f5aae7dd..afdf954206f1 100644 --- a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts +++ b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts @@ -72,6 +72,7 @@ L2_0: l2-cache0 { compatible = "cache"; cache-level = <2>; + cache-unified; }; }; diff --git a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts index 796cd7d02eb5..7bdeb965f0a9 100644 --- a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts +++ b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts @@ -58,6 +58,7 @@ L2_0: l2-cache0 { compatible = "cache"; cache-level = <2>; + cache-unified; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi index b32c2e199c16..e62a43591361 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi @@ -35,7 +35,7 @@ conn_subsys: bus@5b000000 { }; usbotg1: usb@5b0d0000 { - compatible = "fsl,imx7ulp-usb"; + compatible = "fsl,imx7ulp-usb", "fsl,imx6ul-usb", "fsl,imx27-usb"; reg = <0x5b0d0000 0x200>; interrupt-parent = <&gic>; interrupts = ; @@ -51,7 +51,7 @@ conn_subsys: bus@5b000000 { usbmisc1: usbmisc@5b0d0200 { #index-cells = <1>; - compatible = "fsl,imx7ulp-usbmisc", "fsl,imx6q-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc"; reg = <0x5b0d0200 0x200>; }; @@ -171,6 +171,7 @@ conn_subsys: bus@5b000000 { interrupt-names = "host", "peripheral", "otg", "wakeup"; phys = <&usb3_phy>; phy-names = "cdns3,usb3-phy"; + cdns,on-chip-buff-size = /bits/ 16 <18>; status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index ca195e6d8f37..652493ae4bb5 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -34,7 +34,7 @@ }; usbotg2: usb@5b0e0000 { - compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb"; + compatible = "fsl,imx8dxl-usb", "fsl,imx7ulp-usb", "fsl,imx6ul-usb"; reg = <0x5b0e0000 0x200>; interrupt-parent = <&gic>; interrupts = ; @@ -49,7 +49,6 @@ ahb-burst-config = <0x0>; tx-burst-size-dword = <0x10>; rx-burst-size-dword = <0x10>; - #stream-id-cells = <1>; power-domains = <&pd IMX_SC_R_USB_1>; status = "disabled"; @@ -63,7 +62,7 @@ usbmisc2: usbmisc@5b0e0200 { #index-cells = <1>; - compatible = "fsl,imx7ulp-usbmisc"; + compatible = "fsl,imx7ulp-usbmisc", "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc"; reg = <0x5b0e0200 0x200>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index ba06b5273b91..d6b36f04f3dc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -1253,7 +1253,7 @@ }; usbotg1: usb@32e40000 { - compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e40000 0x200>; interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; @@ -1267,13 +1267,14 @@ }; usbmisc1: usbmisc@32e40200 { - compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e40200 0x200>; }; usbotg2: usb@32e50000 { - compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mm-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e50000 0x200>; interrupts = ; clocks = <&clk IMX8MM_CLK_USB1_CTRL_ROOT>; @@ -1287,7 +1288,8 @@ }; usbmisc2: usbmisc@32e50200 { - compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e50200 0x200>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi index 67072e6c77d5..cbd9d124c80d 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi @@ -98,11 +98,17 @@ #address-cells = <1>; #size-cells = <0>; - ethphy: ethernet-phy@4 { + ethphy: ethernet-phy@4 { /* AR8033 or ADIN1300 */ compatible = "ethernet-phy-ieee802.3-c22"; reg = <4>; reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; reset-assert-us = <10000>; + /* + * Deassert delay: + * ADIN1300 requires 5ms. + * AR8033 requires 1ms. + */ + reset-deassert-us = <20000>; }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index c94ab45ee96c..8be8f090e8b8 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -1069,13 +1069,6 @@ <&clk IMX8MN_CLK_DISP_APB_ROOT>, <&clk IMX8MN_CLK_DISP_AXI_ROOT>; clock-names = "pix", "axi", "disp_axi"; - assigned-clocks = <&clk IMX8MN_CLK_DISP_PIXEL_ROOT>, - <&clk IMX8MN_CLK_DISP_AXI>, - <&clk IMX8MN_CLK_DISP_APB>; - assigned-clock-parents = <&clk IMX8MN_CLK_DISP_PIXEL>, - <&clk IMX8MN_SYS_PLL2_1000M>, - <&clk IMX8MN_SYS_PLL1_800M>; - assigned-clock-rates = <594000000>, <500000000>, <200000000>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MN_DISPBLK_PD_LCDIF>; status = "disabled"; @@ -1093,12 +1086,6 @@ clocks = <&clk IMX8MN_CLK_DSI_CORE>, <&clk IMX8MN_CLK_DSI_PHY_REF>; clock-names = "bus_clk", "sclk_mipi"; - assigned-clocks = <&clk IMX8MN_CLK_DSI_CORE>, - <&clk IMX8MN_CLK_DSI_PHY_REF>; - assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_266M>, - <&clk IMX8MN_CLK_24M>; - assigned-clock-rates = <266000000>, <24000000>; - samsung,pll-clock-frequency = <24000000>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MN_DISPBLK_PD_MIPI_DSI>; status = "disabled"; @@ -1142,11 +1129,26 @@ "lcdif-axi", "lcdif-apb", "lcdif-pix", "dsi-pclk", "dsi-ref", "csi-aclk", "csi-pclk"; + assigned-clocks = <&clk IMX8MN_CLK_DSI_CORE>, + <&clk IMX8MN_CLK_DSI_PHY_REF>, + <&clk IMX8MN_CLK_DISP_PIXEL>, + <&clk IMX8MN_CLK_DISP_AXI>, + <&clk IMX8MN_CLK_DISP_APB>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL1_266M>, + <&clk IMX8MN_CLK_24M>, + <&clk IMX8MN_VIDEO_PLL1_OUT>, + <&clk IMX8MN_SYS_PLL2_1000M>, + <&clk IMX8MN_SYS_PLL1_800M>; + assigned-clock-rates = <266000000>, + <24000000>, + <594000000>, + <500000000>, + <200000000>; #power-domain-cells = <1>; }; usbotg1: usb@32e40000 { - compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb"; + compatible = "fsl,imx8mn-usb", "fsl,imx7d-usb", "fsl,imx27-usb"; reg = <0x32e40000 0x200>; interrupts = ; clocks = <&clk IMX8MN_CLK_USB1_CTRL_ROOT>; @@ -1160,7 +1162,8 @@ }; usbmisc1: usbmisc@32e40200 { - compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc"; + compatible = "fsl,imx8mn-usbmisc", "fsl,imx7d-usbmisc", + "fsl,imx6q-usbmisc"; #index-cells = <1>; reg = <0x32e40200 0x200>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index f81391993354..428c60462e3d 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1211,13 +1211,6 @@ <&clk IMX8MP_CLK_MEDIA_APB_ROOT>, <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>; clock-names = "pix", "axi", "disp_axi"; - assigned-clocks = <&clk IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT>, - <&clk IMX8MP_CLK_MEDIA_AXI>, - <&clk IMX8MP_CLK_MEDIA_APB>; - assigned-clock-parents = <&clk IMX8MP_CLK_MEDIA_DISP1_PIX>, - <&clk IMX8MP_SYS_PLL2_1000M>, - <&clk IMX8MP_SYS_PLL1_800M>; - assigned-clock-rates = <594000000>, <500000000>, <200000000>; interrupts = ; power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_LCDIF_1>; status = "disabled"; @@ -1237,11 +1230,6 @@ <&clk IMX8MP_CLK_MEDIA_APB_ROOT>, <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>; clock-names = "pix", "axi", "disp_axi"; - assigned-clocks = <&clk IMX8MP_CLK_MEDIA_DISP2_PIX>, - <&clk IMX8MP_VIDEO_PLL1>; - assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>, - <&clk IMX8MP_VIDEO_PLL1_REF_SEL>; - assigned-clock-rates = <0>, <1039500000>; power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_LCDIF_2>; status = "disabled"; @@ -1296,11 +1284,16 @@ "disp1", "disp2", "isp", "phy"; assigned-clocks = <&clk IMX8MP_CLK_MEDIA_AXI>, - <&clk IMX8MP_CLK_MEDIA_APB>; + <&clk IMX8MP_CLK_MEDIA_APB>, + <&clk IMX8MP_CLK_MEDIA_DISP1_PIX>, + <&clk IMX8MP_CLK_MEDIA_DISP2_PIX>, + <&clk IMX8MP_VIDEO_PLL1>; assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>, - <&clk IMX8MP_SYS_PLL1_800M>; - assigned-clock-rates = <500000000>, <200000000>; - + <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_VIDEO_PLL1_OUT>, + <&clk IMX8MP_VIDEO_PLL1_OUT>; + assigned-clock-rates = <500000000>, <200000000>, + <0>, <0>, <1039500000>; #power-domain-cells = <1>; lvds_bridge: bridge@5c { diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index cd925c0ac911..0492556a10db 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -1453,7 +1453,6 @@ phys = <&usb3_phy0>, <&usb3_phy0>; phy-names = "usb2-phy", "usb3-phy"; power-domains = <&pgc_otg1>; - usb3-resume-missing-cas; status = "disabled"; }; @@ -1485,7 +1484,6 @@ phys = <&usb3_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; power-domains = <&pgc_otg2>; - usb3-resume-missing-cas; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8x-colibri-eval-v3.dtsi b/arch/arm64/boot/dts/freescale/imx8x-colibri-eval-v3.dtsi index 7264d784ae72..9af769ab8ceb 100644 --- a/arch/arm64/boot/dts/freescale/imx8x-colibri-eval-v3.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8x-colibri-eval-v3.dtsi @@ -33,6 +33,12 @@ }; }; +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ext_io0>, <&pinctrl_hog0>, <&pinctrl_hog1>, + <&pinctrl_lpspi2_cs2>; +}; + /* Colibri SPI */ &lpspi2 { status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/imx8x-colibri-iris.dtsi b/arch/arm64/boot/dts/freescale/imx8x-colibri-iris.dtsi index 5f30c88855e7..f8953067bc3b 100644 --- a/arch/arm64/boot/dts/freescale/imx8x-colibri-iris.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8x-colibri-iris.dtsi @@ -48,8 +48,7 @@ , /* SODIMM 101 */ , /* SODIMM 97 */ , /* SODIMM 85 */ - , /* SODIMM 79 */ - ; /* SODIMM 45 */ + ; /* SODIMM 79 */ }; pinctrl_uart1_forceoff: uart1forceoffgrp { diff --git a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi index 7cad79102e1a..49d105eb4769 100644 --- a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi @@ -363,10 +363,6 @@ /* TODO VPU Encoder/Decoder */ &iomuxc { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ext_io0>, <&pinctrl_hog0>, <&pinctrl_hog1>, - <&pinctrl_hog2>, <&pinctrl_lpspi2_cs2>; - /* On-module touch pen-down interrupt */ pinctrl_ad7879_int: ad7879intgrp { fsl,pins = ; @@ -499,8 +495,7 @@ }; pinctrl_hog1: hog1grp { - fsl,pins = , /* SODIMM 75 */ - ; /* SODIMM 93 */ + fsl,pins = ; /* SODIMM 93 */ }; pinctrl_hog2: hog2grp { @@ -774,3 +769,10 @@ fsl,pins = ; }; }; + +/* Delete peripherals which are not present on SOC, but are defined in imx8-ss-*.dtsi */ + +/delete-node/ &adc1; +/delete-node/ &adc1_lpcg; +/delete-node/ &dsp; +/delete-node/ &dsp_lpcg; diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi index 78ff8ba5718e..5e83d4e9efa4 100644 --- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi @@ -324,6 +324,7 @@ #address-cells = <2>; #size-cells = <2>; compatible = "simple-bus"; + dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; ranges; gic: interrupt-controller@c000000 { diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi index 8652f41403ae..a44aae4ab953 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi @@ -452,6 +452,7 @@ #size-cells = <2>; compatible = "simple-bus"; ranges; + dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; gic: interrupt-controller@c000000 { compatible = "arm,gic-v3"; @@ -2471,7 +2472,6 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VENC>; #address-cells = <2>; #size-cells = <2>; - dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; }; jpgdec-master { @@ -2483,7 +2483,6 @@ <&iommu_vdo M4U_PORT_L19_JPGDEC_BSDMA1>, <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET1>, <&iommu_vdo M4U_PORT_L19_JPGDEC_BUFF_OFFSET0>; - dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; #address-cells = <2>; #size-cells = <2>; ranges; @@ -2555,7 +2554,6 @@ <&iommu_vpp M4U_PORT_L20_JPGENC_C_RDMA>, <&iommu_vpp M4U_PORT_L20_JPGENC_Q_TABLE>, <&iommu_vpp M4U_PORT_L20_JPGENC_BSDMA>; - dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi index 5d354f8923b4..18b4c2b2c42c 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi @@ -1154,6 +1154,14 @@ clock-names = "fuse"; }; + hte_lic: hardware-timestamp@3aa0000 { + compatible = "nvidia,tegra234-gte-lic"; + reg = <0x0 0x3aa0000 0x0 0x10000>; + interrupts = ; + nvidia,int-threshold = <1>; + #timestamp-cells = <1>; + }; + hsp_top0: hsp@3c00000 { compatible = "nvidia,tegra234-hsp", "nvidia,tegra194-hsp"; reg = <0x0 0x03c00000 0x0 0xa0000>; @@ -1671,6 +1679,15 @@ #mbox-cells = <2>; }; + hte_aon: hardware-timestamp@c1e0000 { + compatible = "nvidia,tegra234-gte-aon"; + reg = <0x0 0xc1e0000 0x0 0x10000>; + interrupts = ; + nvidia,int-threshold = <1>; + nvidia,gpio-controller = <&gpio_aon>; + #timestamp-cells = <1>; + }; + gen2_i2c: i2c@c240000 { compatible = "nvidia,tegra194-i2c"; reg = <0x0 0xc240000 0x0 0x100>; diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h index d6b51deb7bf0..18dc2fb3d7b7 100644 --- a/arch/arm64/include/asm/arm_pmuv3.h +++ b/arch/arm64/include/asm/arm_pmuv3.h @@ -13,7 +13,7 @@ #define RETURN_READ_PMEVCNTRN(n) \ return read_sysreg(pmevcntr##n##_el0) -static unsigned long read_pmevcntrn(int n) +static inline unsigned long read_pmevcntrn(int n) { PMEVN_SWITCH(n, RETURN_READ_PMEVCNTRN); return 0; @@ -21,14 +21,14 @@ static unsigned long read_pmevcntrn(int n) #define WRITE_PMEVCNTRN(n) \ write_sysreg(val, pmevcntr##n##_el0) -static void write_pmevcntrn(int n, unsigned long val) +static inline void write_pmevcntrn(int n, unsigned long val) { PMEVN_SWITCH(n, WRITE_PMEVCNTRN); } #define WRITE_PMEVTYPERN(n) \ write_sysreg(val, pmevtyper##n##_el0) -static void write_pmevtypern(int n, unsigned long val) +static inline void write_pmevtypern(int n, unsigned long val) { PMEVN_SWITCH(n, WRITE_PMEVTYPERN); } diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 497acf134d99..c6bc5d8ec3ca 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -62,9 +62,8 @@ __XCHG_CASE( , , mb_, 64, dmb ish, nop, , a, l, "memory") #undef __XCHG_CASE #define __XCHG_GEN(sfx) \ -static __always_inline unsigned long __xchg##sfx(unsigned long x, \ - volatile void *ptr, \ - int size) \ +static __always_inline unsigned long \ +__arch_xchg##sfx(unsigned long x, volatile void *ptr, int size) \ { \ switch (size) { \ case 1: \ @@ -93,7 +92,7 @@ __XCHG_GEN(_mb) ({ \ __typeof__(*(ptr)) __ret; \ __ret = (__typeof__(*(ptr))) \ - __xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \ + __arch_xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \ __ret; \ }) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 683ca3af4084..5f6f84837a49 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -126,6 +126,10 @@ #define APPLE_CPU_PART_M1_FIRESTORM_MAX 0x029 #define APPLE_CPU_PART_M2_BLIZZARD 0x032 #define APPLE_CPU_PART_M2_AVALANCHE 0x033 +#define APPLE_CPU_PART_M2_BLIZZARD_PRO 0x034 +#define APPLE_CPU_PART_M2_AVALANCHE_PRO 0x035 +#define APPLE_CPU_PART_M2_BLIZZARD_MAX 0x038 +#define APPLE_CPU_PART_M2_AVALANCHE_MAX 0x039 #define AMPERE_CPU_PART_AMPERE1 0xAC3 @@ -181,6 +185,10 @@ #define MIDR_APPLE_M1_FIRESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) #define MIDR_APPLE_M2_BLIZZARD MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) #define MIDR_APPLE_M2_AVALANCHE MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) +#define MIDR_APPLE_M2_BLIZZARD_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) +#define MIDR_APPLE_M2_AVALANCHE_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) +#define MIDR_APPLE_M2_BLIZZARD_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX) +#define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */ diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h index 92963f98afec..e73af709cb7a 100644 --- a/arch/arm64/include/asm/exception.h +++ b/arch/arm64/include/asm/exception.h @@ -31,7 +31,7 @@ static inline unsigned long disr_to_esr(u64 disr) return esr; } -asmlinkage void handle_bad_stack(struct pt_regs *regs); +asmlinkage void __noreturn handle_bad_stack(struct pt_regs *regs); asmlinkage void el1t_64_sync_handler(struct pt_regs *regs); asmlinkage void el1t_64_irq_handler(struct pt_regs *regs); @@ -80,5 +80,5 @@ void do_el1_fpac(struct pt_regs *regs, unsigned long esr); void do_serror(struct pt_regs *regs, unsigned long esr); void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags); -void panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far); +void __noreturn panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far); #endif /* __ASM_EXCEPTION_H */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 3dd691c85ca0..7e7e19ef6993 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -199,6 +200,9 @@ struct kvm_arch { /* Mandated version of PSCI */ u32 psci_version; + /* Protects VM-scoped configuration data */ + struct mutex config_lock; + /* * If we encounter a data abort without valid instruction syndrome * information, report this to user space. User space can (and @@ -221,7 +225,12 @@ struct kvm_arch { #define KVM_ARCH_FLAG_EL1_32BIT 4 /* PSCI SYSTEM_SUSPEND enabled for the guest */ #define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 5 - + /* VM counter offset */ +#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 6 + /* Timer PPIs made immutable */ +#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE 7 + /* SMCCC filter initialized for the VM */ +#define KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED 8 unsigned long flags; /* @@ -242,6 +251,7 @@ struct kvm_arch { /* Hypercall features firmware registers' descriptor */ struct kvm_smccc_features smccc_feat; + struct maple_tree smccc_filter; /* * For an untrusted host VM, 'pkvm.handle' is used to lookup @@ -365,6 +375,10 @@ enum vcpu_sysreg { TPIDR_EL2, /* EL2 Software Thread ID Register */ CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */ SP_EL2, /* EL2 Stack Pointer */ + CNTHP_CTL_EL2, + CNTHP_CVAL_EL2, + CNTHV_CTL_EL2, + CNTHV_CVAL_EL2, NR_SYS_REGS /* Nothing after this line! */ }; @@ -522,6 +536,7 @@ struct kvm_vcpu_arch { /* vcpu power state */ struct kvm_mp_state mp_state; + spinlock_t mp_state_lock; /* Cache some mmu pages needed inside spinlock regions */ struct kvm_mmu_memory_cache mmu_page_cache; @@ -939,6 +954,9 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); int __init kvm_sys_reg_table_init(void); +bool lock_all_vcpus(struct kvm *kvm); +void unlock_all_vcpus(struct kvm *kvm); + /* MMIO helpers */ void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len); @@ -1022,8 +1040,10 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); -long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, - struct kvm_arm_copy_mte_tags *copy_tags); +int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, + struct kvm_arm_copy_mte_tags *copy_tags); +int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm, + struct kvm_arm_counter_offset *offset); /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); @@ -1078,6 +1098,9 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); (system_supports_32bit_el0() && \ !static_branch_unlikely(&arm64_mismatched_32bit_el0)) +#define kvm_vm_has_ran_once(kvm) \ + (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags)) + int kvm_trng_call(struct kvm_vcpu *vcpu); #ifdef CONFIG_KVM extern phys_addr_t hyp_mem_base; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 083cc47dca08..27e63c111f78 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -63,6 +63,7 @@ * specific registers encoded in the instructions). */ .macro kern_hyp_va reg +#ifndef __KVM_VHE_HYPERVISOR__ alternative_cb ARM64_ALWAYS_SYSTEM, kvm_update_va_mask and \reg, \reg, #1 /* mask with va_mask */ ror \reg, \reg, #1 /* rotate to the first tag bit */ @@ -70,6 +71,7 @@ alternative_cb ARM64_ALWAYS_SYSTEM, kvm_update_va_mask add \reg, \reg, #0, lsl 12 /* insert the top 12 bits of the tag */ ror \reg, \reg, #63 /* rotate back */ alternative_cb_end +#endif .endm /* @@ -127,6 +129,7 @@ void kvm_apply_hyp_relocations(void); static __always_inline unsigned long __kern_hyp_va(unsigned long v) { +#ifndef __KVM_VHE_HYPERVISOR__ asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n" "ror %0, %0, #1\n" "add %0, %0, #0\n" @@ -135,6 +138,7 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v) ARM64_ALWAYS_SYSTEM, kvm_update_va_mask) : "+r" (v)); +#endif return v; } diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index 4cd6762bda80..93bd0975b15f 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -209,6 +209,7 @@ struct kvm_pgtable_visit_ctx { kvm_pte_t old; void *arg; struct kvm_pgtable_mm_ops *mm_ops; + u64 start; u64 addr; u64 end; u32 level; @@ -631,9 +632,9 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size); * * The walker will walk the page-table entries corresponding to the input * address range specified, visiting entries according to the walker flags. - * Invalid entries are treated as leaf entries. Leaf entries are reloaded - * after invoking the walker callback, allowing the walker to descend into - * a newly installed table. + * Invalid entries are treated as leaf entries. The visited page table entry is + * reloaded after invoking the walker callback, allowing the walker to descend + * into a newly installed table. * * Returning a negative error code from the walker callback function will * terminate the walk immediately with the same error code. diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index efcd68154a3a..c735afdf639b 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -261,9 +261,11 @@ static inline const void *__tag_set(const void *addr, u8 tag) } #ifdef CONFIG_KASAN_HW_TAGS -#define arch_enable_tagging_sync() mte_enable_kernel_sync() -#define arch_enable_tagging_async() mte_enable_kernel_async() -#define arch_enable_tagging_asymm() mte_enable_kernel_asymm() +#define arch_enable_tag_checks_sync() mte_enable_kernel_sync() +#define arch_enable_tag_checks_async() mte_enable_kernel_async() +#define arch_enable_tag_checks_asymm() mte_enable_kernel_asymm() +#define arch_suppress_tag_checks_start() mte_enable_tco() +#define arch_suppress_tag_checks_stop() mte_disable_tco() #define arch_force_async_tag_fault() mte_check_tfsr_exit() #define arch_get_random_tag() mte_get_random_tag() #define arch_get_mem_tag(addr) mte_get_mem_tag(addr) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 72dbd6400549..56911691bef0 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -288,6 +288,12 @@ void post_ttbr_update_workaround(void); unsigned long arm64_mm_context_get(struct mm_struct *mm); void arm64_mm_context_put(struct mm_struct *mm); +#define mm_untag_mask mm_untag_mask +static inline unsigned long mm_untag_mask(struct mm_struct *mm) +{ + return -1UL >> 8; +} + #include #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/mte-kasan.h b/arch/arm64/include/asm/mte-kasan.h index 9f79425fc65a..2e98028c1965 100644 --- a/arch/arm64/include/asm/mte-kasan.h +++ b/arch/arm64/include/asm/mte-kasan.h @@ -13,8 +13,73 @@ #include +#ifdef CONFIG_KASAN_HW_TAGS + +/* Whether the MTE asynchronous mode is enabled. */ +DECLARE_STATIC_KEY_FALSE(mte_async_or_asymm_mode); + +static inline bool system_uses_mte_async_or_asymm_mode(void) +{ + return static_branch_unlikely(&mte_async_or_asymm_mode); +} + +#else /* CONFIG_KASAN_HW_TAGS */ + +static inline bool system_uses_mte_async_or_asymm_mode(void) +{ + return false; +} + +#endif /* CONFIG_KASAN_HW_TAGS */ + #ifdef CONFIG_ARM64_MTE +/* + * The Tag Check Flag (TCF) mode for MTE is per EL, hence TCF0 + * affects EL0 and TCF affects EL1 irrespective of which TTBR is + * used. + * The kernel accesses TTBR0 usually with LDTR/STTR instructions + * when UAO is available, so these would act as EL0 accesses using + * TCF0. + * However futex.h code uses exclusives which would be executed as + * EL1, this can potentially cause a tag check fault even if the + * user disables TCF0. + * + * To address the problem we set the PSTATE.TCO bit in uaccess_enable() + * and reset it in uaccess_disable(). + * + * The Tag check override (TCO) bit disables temporarily the tag checking + * preventing the issue. + */ +static inline void mte_disable_tco(void) +{ + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(0), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +} + +static inline void mte_enable_tco(void) +{ + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(1), + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); +} + +/* + * These functions disable tag checking only if in MTE async mode + * since the sync mode generates exceptions synchronously and the + * nofault or load_unaligned_zeropad can handle them. + */ +static inline void __mte_disable_tco_async(void) +{ + if (system_uses_mte_async_or_asymm_mode()) + mte_disable_tco(); +} + +static inline void __mte_enable_tco_async(void) +{ + if (system_uses_mte_async_or_asymm_mode()) + mte_enable_tco(); +} + /* * These functions are meant to be only used from KASAN runtime through * the arch_*() interface defined in asm/memory.h. @@ -138,6 +203,22 @@ void mte_enable_kernel_asymm(void); #else /* CONFIG_ARM64_MTE */ +static inline void mte_disable_tco(void) +{ +} + +static inline void mte_enable_tco(void) +{ +} + +static inline void __mte_disable_tco_async(void) +{ +} + +static inline void __mte_enable_tco_async(void) +{ +} + static inline u8 mte_get_ptr_tag(void *ptr) { return 0xFF; diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h index 20dd06d70af5..c028afb1cd0b 100644 --- a/arch/arm64/include/asm/mte.h +++ b/arch/arm64/include/asm/mte.h @@ -178,14 +178,6 @@ static inline void mte_disable_tco_entry(struct task_struct *task) } #ifdef CONFIG_KASAN_HW_TAGS -/* Whether the MTE asynchronous mode is enabled. */ -DECLARE_STATIC_KEY_FALSE(mte_async_or_asymm_mode); - -static inline bool system_uses_mte_async_or_asymm_mode(void) -{ - return static_branch_unlikely(&mte_async_or_asymm_mode); -} - void mte_check_tfsr_el1(void); static inline void mte_check_tfsr_entry(void) @@ -212,10 +204,6 @@ static inline void mte_check_tfsr_exit(void) mte_check_tfsr_el1(); } #else -static inline bool system_uses_mte_async_or_asymm_mode(void) -{ - return false; -} static inline void mte_check_tfsr_el1(void) { } diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index b6ba466e2e8a..0bd18de9fd97 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -57,7 +57,7 @@ static inline bool arch_thp_swp_supported(void) * fault on one CPU which has been handled concurrently by another CPU * does not need to perform additional invalidation. */ -#define flush_tlb_fix_spurious_fault(vma, address) do { } while (0) +#define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0) /* * ZERO_PAGE is a global shared page that is always zero: used diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index fc55f5a57a06..f2d26235bfb4 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -100,10 +100,10 @@ static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask) extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); -extern void cpu_die(void); -extern void cpu_die_early(void); +extern void __noreturn cpu_die(void); +extern void __noreturn cpu_die_early(void); -static inline void cpu_park_loop(void) +static inline void __noreturn cpu_park_loop(void) { for (;;) { wfe(); @@ -123,7 +123,7 @@ static inline void update_cpu_boot_status(int val) * which calls for a kernel panic. Update the boot status and park the calling * CPU. */ -static inline void cpu_panic_kernel(void) +static inline void __noreturn cpu_panic_kernel(void) { update_cpu_boot_status(CPU_PANIC_KERNEL); cpu_park_loop(); @@ -143,7 +143,6 @@ bool cpus_are_stuck_in_kernel(void); extern void crash_smp_send_stop(void); extern bool smp_crash_stop_failed(void); -extern void panic_smp_self_stop(void); #endif /* ifndef __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h index 4b73463423c3..5f5437621029 100644 --- a/arch/arm64/include/asm/sparsemem.h +++ b/arch/arm64/include/asm/sparsemem.h @@ -10,7 +10,7 @@ /* * Section size must be at least 512MB for 64K base * page size config. Otherwise it will be less than - * (MAX_ORDER - 1) and the build process will fail. + * MAX_ORDER and the build process will fail. */ #ifdef CONFIG_ARM64_64K_PAGES #define SECTION_SIZE_BITS 29 diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index c48b41c9b0cc..eefd712f2430 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -115,8 +115,14 @@ #define SB_BARRIER_INSN __SYS_BARRIER_INSN(0, 7, 31) #define SYS_DC_ISW sys_insn(1, 0, 7, 6, 2) +#define SYS_DC_IGSW sys_insn(1, 0, 7, 6, 4) +#define SYS_DC_IGDSW sys_insn(1, 0, 7, 6, 6) #define SYS_DC_CSW sys_insn(1, 0, 7, 10, 2) +#define SYS_DC_CGSW sys_insn(1, 0, 7, 10, 4) +#define SYS_DC_CGDSW sys_insn(1, 0, 7, 10, 6) #define SYS_DC_CISW sys_insn(1, 0, 7, 14, 2) +#define SYS_DC_CIGSW sys_insn(1, 0, 7, 14, 4) +#define SYS_DC_CIGDSW sys_insn(1, 0, 7, 14, 6) /* * Automatically generated definitions for system registers, the @@ -388,6 +394,7 @@ #define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0) +#define SYS_CNTPCT_EL0 sys_reg(3, 3, 14, 0, 1) #define SYS_CNTPCTSS_EL0 sys_reg(3, 3, 14, 0, 5) #define SYS_CNTVCTSS_EL0 sys_reg(3, 3, 14, 0, 6) @@ -400,7 +407,9 @@ #define SYS_AARCH32_CNTP_TVAL sys_reg(0, 0, 14, 2, 0) #define SYS_AARCH32_CNTP_CTL sys_reg(0, 0, 14, 2, 1) +#define SYS_AARCH32_CNTPCT sys_reg(0, 0, 0, 14, 0) #define SYS_AARCH32_CNTP_CVAL sys_reg(0, 2, 0, 14, 0) +#define SYS_AARCH32_CNTPCTSS sys_reg(0, 8, 0, 14, 0) #define __PMEV_op2(n) ((n) & 0x7) #define __CNTR_CRm(n) (0x8 | (((n) >> 3) & 0x3)) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 8209e6a86989..05f4fc265428 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -136,55 +136,9 @@ static inline void __uaccess_enable_hw_pan(void) CONFIG_ARM64_PAN)); } -/* - * The Tag Check Flag (TCF) mode for MTE is per EL, hence TCF0 - * affects EL0 and TCF affects EL1 irrespective of which TTBR is - * used. - * The kernel accesses TTBR0 usually with LDTR/STTR instructions - * when UAO is available, so these would act as EL0 accesses using - * TCF0. - * However futex.h code uses exclusives which would be executed as - * EL1, this can potentially cause a tag check fault even if the - * user disables TCF0. - * - * To address the problem we set the PSTATE.TCO bit in uaccess_enable() - * and reset it in uaccess_disable(). - * - * The Tag check override (TCO) bit disables temporarily the tag checking - * preventing the issue. - */ -static inline void __uaccess_disable_tco(void) -{ - asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(0), - ARM64_MTE, CONFIG_KASAN_HW_TAGS)); -} - -static inline void __uaccess_enable_tco(void) -{ - asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(1), - ARM64_MTE, CONFIG_KASAN_HW_TAGS)); -} - -/* - * These functions disable tag checking only if in MTE async mode - * since the sync mode generates exceptions synchronously and the - * nofault or load_unaligned_zeropad can handle them. - */ -static inline void __uaccess_disable_tco_async(void) -{ - if (system_uses_mte_async_or_asymm_mode()) - __uaccess_disable_tco(); -} - -static inline void __uaccess_enable_tco_async(void) -{ - if (system_uses_mte_async_or_asymm_mode()) - __uaccess_enable_tco(); -} - static inline void uaccess_disable_privileged(void) { - __uaccess_disable_tco(); + mte_disable_tco(); if (uaccess_ttbr0_disable()) return; @@ -194,7 +148,7 @@ static inline void uaccess_disable_privileged(void) static inline void uaccess_enable_privileged(void) { - __uaccess_enable_tco(); + mte_enable_tco(); if (uaccess_ttbr0_enable()) return; @@ -302,8 +256,8 @@ do { \ #define get_user __get_user /* - * We must not call into the scheduler between __uaccess_enable_tco_async() and - * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking + * We must not call into the scheduler between __mte_enable_tco_async() and + * __mte_disable_tco_async(). As `dst` and `src` may contain blocking * functions, we must evaluate these outside of the critical section. */ #define __get_kernel_nofault(dst, src, type, err_label) \ @@ -312,10 +266,10 @@ do { \ __typeof__(src) __gkn_src = (src); \ int __gkn_err = 0; \ \ - __uaccess_enable_tco_async(); \ + __mte_enable_tco_async(); \ __raw_get_mem("ldr", *((type *)(__gkn_dst)), \ (__force type *)(__gkn_src), __gkn_err, K); \ - __uaccess_disable_tco_async(); \ + __mte_disable_tco_async(); \ \ if (unlikely(__gkn_err)) \ goto err_label; \ @@ -388,8 +342,8 @@ do { \ #define put_user __put_user /* - * We must not call into the scheduler between __uaccess_enable_tco_async() and - * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking + * We must not call into the scheduler between __mte_enable_tco_async() and + * __mte_disable_tco_async(). As `dst` and `src` may contain blocking * functions, we must evaluate these outside of the critical section. */ #define __put_kernel_nofault(dst, src, type, err_label) \ @@ -398,10 +352,10 @@ do { \ __typeof__(src) __pkn_src = (src); \ int __pkn_err = 0; \ \ - __uaccess_enable_tco_async(); \ + __mte_enable_tco_async(); \ __raw_put_mem("str", *((type *)(__pkn_src)), \ (__force type *)(__pkn_dst), __pkn_err, K); \ - __uaccess_disable_tco_async(); \ + __mte_disable_tco_async(); \ \ if (unlikely(__pkn_err)) \ goto err_label; \ diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h index 1c8e4f2490bf..f3b151ed0d7a 100644 --- a/arch/arm64/include/asm/word-at-a-time.h +++ b/arch/arm64/include/asm/word-at-a-time.h @@ -55,7 +55,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) { unsigned long ret; - __uaccess_enable_tco_async(); + __mte_enable_tco_async(); /* Load word from unaligned pointer addr */ asm( @@ -65,7 +65,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr) : "=&r" (ret) : "r" (addr), "Q" (*(unsigned long *)addr)); - __uaccess_disable_tco_async(); + __mte_disable_tco_async(); return ret; } diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index f8129c624b07..f7ddd73a8c0f 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -198,6 +198,15 @@ struct kvm_arm_copy_mte_tags { __u64 reserved[2]; }; +/* + * Counter/Timer offset structure. Describe the virtual/physical offset. + * To be used with KVM_ARM_SET_COUNTER_OFFSET. + */ +struct kvm_arm_counter_offset { + __u64 counter_offset; + __u64 reserved; +}; + #define KVM_ARM_TAGS_TO_GUEST 0 #define KVM_ARM_TAGS_FROM_GUEST 1 @@ -372,6 +381,10 @@ enum { #endif }; +/* Device Control API on vm fd */ +#define KVM_ARM_VM_SMCCC_CTRL 0 +#define KVM_ARM_VM_SMCCC_FILTER 0 + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 @@ -411,6 +424,8 @@ enum { #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 +#define KVM_ARM_VCPU_TIMER_IRQ_HVTIMER 2 +#define KVM_ARM_VCPU_TIMER_IRQ_HPTIMER 3 #define KVM_ARM_VCPU_PVTIME_CTRL 2 #define KVM_ARM_VCPU_PVTIME_IPA 0 @@ -469,6 +484,27 @@ enum { /* run->fail_entry.hardware_entry_failure_reason codes. */ #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) +enum kvm_smccc_filter_action { + KVM_SMCCC_FILTER_HANDLE = 0, + KVM_SMCCC_FILTER_DENY, + KVM_SMCCC_FILTER_FWD_TO_USER, + +#ifdef __KERNEL__ + NR_SMCCC_FILTER_ACTIONS +#endif +}; + +struct kvm_smccc_filter { + __u32 base; + __u32 nr_functions; + __u8 action; + __u8 pad[15]; +}; + +/* arm64-specific KVM_EXIT_HYPERCALL flags */ +#define KVM_HYPERCALL_EXIT_SMC (1U << 0) +#define KVM_HYPERCALL_EXIT_16BIT (1U << 1) + #endif #endif /* __ARM_KVM_H__ */ diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c index c307f69e9b55..d9c9218fa1fd 100644 --- a/arch/arm64/kernel/cacheinfo.c +++ b/arch/arm64/kernel/cacheinfo.c @@ -38,11 +38,9 @@ static void ci_leaf_init(struct cacheinfo *this_leaf, this_leaf->type = type; } -int init_cache_level(unsigned int cpu) +static void detect_cache_level(unsigned int *level_p, unsigned int *leaves_p) { unsigned int ctype, level, leaves; - int fw_level, ret; - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { ctype = get_cache_type(level); @@ -54,6 +52,27 @@ int init_cache_level(unsigned int cpu) leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; } + *level_p = level; + *leaves_p = leaves; +} + +int early_cache_level(unsigned int cpu) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + + detect_cache_level(&this_cpu_ci->num_levels, &this_cpu_ci->num_leaves); + + return 0; +} + +int init_cache_level(unsigned int cpu) +{ + unsigned int level, leaves; + int fw_level, ret; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + + detect_cache_level(&level, &leaves); + if (acpi_disabled) { fw_level = of_find_last_cache_level(cpu); } else { diff --git a/arch/arm64/kernel/cpu-reset.S b/arch/arm64/kernel/cpu-reset.S index 6b752fe89745..c87445dde674 100644 --- a/arch/arm64/kernel/cpu-reset.S +++ b/arch/arm64/kernel/cpu-reset.S @@ -14,7 +14,7 @@ #include .text -.pushsection .idmap.text, "awx" +.pushsection .idmap.text, "a" /* * cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 1bdad599e769..7d7128c65161 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1497,10 +1497,18 @@ static const DEVICE_ATTR_RO(aarch32_el0); static int __init aarch32_el0_sysfs_init(void) { + struct device *dev_root; + int ret = 0; + if (!allow_mismatched_32bit_el0) return 0; - return device_create_file(cpu_subsys.dev_root, &dev_attr_aarch32_el0); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + ret = device_create_file(dev_root, &dev_attr_aarch32_el0); + put_device(dev_root); + } + return ret; } device_initcall(aarch32_el0_sysfs_init); @@ -2222,6 +2230,17 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS(ID_AA64MMFR0_EL1, ECV, IMP) }, + { + .desc = "Enhanced Counter Virtualization (CNTPOFF)", + .capability = ARM64_HAS_ECV_CNTPOFF, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_cpuid_feature, + .sys_reg = SYS_ID_AA64MMFR0_EL1, + .field_pos = ID_AA64MMFR0_EL1_ECV_SHIFT, + .field_width = 4, + .sign = FTR_UNSIGNED, + .min_field_value = ID_AA64MMFR0_EL1_ECV_CNTPOFF, + }, #ifdef CONFIG_ARM64_PAN { .desc = "Privileged Access Never", @@ -2657,26 +2676,26 @@ static const struct arm64_cpu_capabilities arm64_features[] = { #ifdef CONFIG_ARM64_PTR_AUTH static const struct arm64_cpu_capabilities ptr_auth_hwcap_addr_matches[] = { { - ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, APA, PAuth) + HWCAP_CPUID_MATCH(ID_AA64ISAR1_EL1, APA, PAuth) }, { - ARM64_CPUID_FIELDS(ID_AA64ISAR2_EL1, APA3, PAuth) + HWCAP_CPUID_MATCH(ID_AA64ISAR2_EL1, APA3, PAuth) }, { - ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, API, PAuth) + HWCAP_CPUID_MATCH(ID_AA64ISAR1_EL1, API, PAuth) }, {}, }; static const struct arm64_cpu_capabilities ptr_auth_hwcap_gen_matches[] = { { - ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, GPA, IMP) + HWCAP_CPUID_MATCH(ID_AA64ISAR1_EL1, GPA, IMP) }, { - ARM64_CPUID_FIELDS(ID_AA64ISAR2_EL1, GPA3, IMP) + HWCAP_CPUID_MATCH(ID_AA64ISAR2_EL1, GPA3, IMP) }, { - ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, GPI, IMP) + HWCAP_CPUID_MATCH(ID_AA64ISAR1_EL1, GPI, IMP) }, {}, }; diff --git a/arch/arm64/kernel/efi-header.S b/arch/arm64/kernel/efi-header.S index d731b4655df8..11d7f7de202d 100644 --- a/arch/arm64/kernel/efi-header.S +++ b/arch/arm64/kernel/efi-header.S @@ -81,9 +81,47 @@ .quad 0 // CertificationTable .quad 0 // BaseRelocationTable -#ifdef CONFIG_DEBUG_EFI +#if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL) .long .Lefi_debug_table - .L_head // DebugTable .long .Lefi_debug_table_size + + /* + * The debug table is referenced via its Relative Virtual Address (RVA), + * which is only defined for those parts of the image that are covered + * by a section declaration. Since this header is not covered by any + * section, the debug table must be emitted elsewhere. So stick it in + * the .init.rodata section instead. + * + * Note that the payloads themselves are permitted to have zero RVAs, + * which means we can simply put those right after the section headers. + */ + __INITRODATA + + .align 2 +.Lefi_debug_table: +#ifdef CONFIG_DEBUG_EFI + // EFI_IMAGE_DEBUG_DIRECTORY_ENTRY + .long 0 // Characteristics + .long 0 // TimeDateStamp + .short 0 // MajorVersion + .short 0 // MinorVersion + .long IMAGE_DEBUG_TYPE_CODEVIEW // Type + .long .Lefi_debug_entry_size // SizeOfData + .long 0 // RVA + .long .Lefi_debug_entry - .L_head // FileOffset +#endif +#ifdef CONFIG_ARM64_BTI_KERNEL + .long 0 // Characteristics + .long 0 // TimeDateStamp + .short 0 // MajorVersion + .short 0 // MinorVersion + .long IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS // Type + .long 4 // SizeOfData + .long 0 // RVA + .long .Lefi_dll_characteristics_ex - .L_head // FileOffset +#endif + .set .Lefi_debug_table_size, . - .Lefi_debug_table + .previous #endif // Section table @@ -119,33 +157,6 @@ .set .Lsection_count, (. - .Lsection_table) / 40 #ifdef CONFIG_DEBUG_EFI - /* - * The debug table is referenced via its Relative Virtual Address (RVA), - * which is only defined for those parts of the image that are covered - * by a section declaration. Since this header is not covered by any - * section, the debug table must be emitted elsewhere. So stick it in - * the .init.rodata section instead. - * - * Note that the EFI debug entry itself may legally have a zero RVA, - * which means we can simply put it right after the section headers. - */ - __INITRODATA - - .align 2 -.Lefi_debug_table: - // EFI_IMAGE_DEBUG_DIRECTORY_ENTRY - .long 0 // Characteristics - .long 0 // TimeDateStamp - .short 0 // MajorVersion - .short 0 // MinorVersion - .long IMAGE_DEBUG_TYPE_CODEVIEW // Type - .long .Lefi_debug_entry_size // SizeOfData - .long 0 // RVA - .long .Lefi_debug_entry - .L_head // FileOffset - - .set .Lefi_debug_table_size, . - .Lefi_debug_table - .previous - .Lefi_debug_entry: // EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY .ascii "NB10" // Signature @@ -157,6 +168,10 @@ .set .Lefi_debug_entry_size, . - .Lefi_debug_entry #endif +#ifdef CONFIG_ARM64_BTI_KERNEL +.Lefi_dll_characteristics_ex: + .long IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT +#endif .balign SEGMENT_ALIGN .Lefi_header_end: diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index cce1167199e3..3af3c01c93a6 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -840,7 +840,7 @@ UNHANDLED(el0t, 32, error) #endif /* CONFIG_COMPAT */ #ifdef CONFIG_VMAP_STACK -asmlinkage void noinstr handle_bad_stack(struct pt_regs *regs) +asmlinkage void noinstr __noreturn handle_bad_stack(struct pt_regs *regs) { unsigned long esr = read_sysreg(esr_el1); unsigned long far = read_sysreg(far_el1); diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index b98970907226..e92caebff46a 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -150,8 +150,8 @@ CPU_BE( tbz x19, #SCTLR_ELx_EE_SHIFT, 1f ) pre_disable_mmu_workaround msr sctlr_el2, x19 b 3f - pre_disable_mmu_workaround -2: msr sctlr_el1, x19 +2: pre_disable_mmu_workaround + msr sctlr_el1, x19 3: isb mov x19, xzr ret diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 8309197c0ebd..35f3c7959513 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -108,4 +108,8 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized); #endif /* CONFIG_KVM */ +#ifdef CONFIG_EFI_ZBOOT +_kernel_codesize = ABSOLUTE(__inittext_end - _text); +#endif + #endif /* __ARM64_KERNEL_IMAGE_VARS_H */ diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index 5a0a8f552a61..543493bf924d 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -65,17 +65,12 @@ static bool plt_entries_equal(const struct plt_entry *a, (q + aarch64_insn_adrp_get_offset(le32_to_cpu(b->adrp))); } -static bool in_init(const struct module *mod, void *loc) -{ - return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; -} - u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, void *loc, const Elf64_Rela *rela, Elf64_Sym *sym) { - struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : - &mod->arch.init; + struct mod_plt_sec *pltsec = !within_module_init((unsigned long)loc, mod) ? + &mod->arch.core : &mod->arch.init; struct plt_entry *plt = (struct plt_entry *)sechdrs[pltsec->plt_shndx].sh_addr; int i = pltsec->plt_num_entries; int j = i - 1; @@ -105,8 +100,8 @@ u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, u64 module_emit_veneer_for_adrp(struct module *mod, Elf64_Shdr *sechdrs, void *loc, u64 val) { - struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : - &mod->arch.init; + struct mod_plt_sec *pltsec = !within_module_init((unsigned long)loc, mod) ? + &mod->arch.core : &mod->arch.init; struct plt_entry *plt = (struct plt_entry *)sechdrs[pltsec->plt_shndx].sh_addr; int i = pltsec->plt_num_entries++; u32 br; diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c index f5bcb0dc6267..7e89968bd282 100644 --- a/arch/arm64/kernel/mte.c +++ b/arch/arm64/kernel/mte.c @@ -66,13 +66,10 @@ void mte_sync_tags(pte_t old_pte, pte_t pte) return; /* if PG_mte_tagged is set, tags have already been initialised */ - for (i = 0; i < nr_pages; i++, page++) { - if (!page_mte_tagged(page)) { + for (i = 0; i < nr_pages; i++, page++) + if (!page_mte_tagged(page)) mte_sync_page_tags(page, old_pte, check_swap, pte_is_tagged); - set_page_mte_tagged(page); - } - } /* ensure the tags are visible before the PTE is set */ smp_wmb(); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index b5bed62483cb..0fcc4eb1a7ab 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -69,7 +69,7 @@ void (*pm_power_off)(void); EXPORT_SYMBOL_GPL(pm_power_off); #ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { cpu_die(); } diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 2ae7cff1953a..2aa5129d8253 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -97,7 +97,7 @@ SYM_FUNC_START(__cpu_suspend_enter) ret SYM_FUNC_END(__cpu_suspend_enter) - .pushsection ".idmap.text", "awx" + .pushsection ".idmap.text", "a" SYM_CODE_START(cpu_resume) mov x0, xzr bl init_kernel_el diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 4e8327264255..d00d4cbb31b1 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -51,7 +51,6 @@ #include #include -#define CREATE_TRACE_POINTS #include DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number); @@ -361,7 +360,7 @@ void __cpu_die(unsigned int cpu) * Called from the idle thread for the CPU which has been shutdown. * */ -void cpu_die(void) +void __noreturn cpu_die(void) { unsigned int cpu = smp_processor_id(); const struct cpu_operations *ops = get_cpu_ops(cpu); @@ -398,7 +397,7 @@ static void __cpu_try_die(int cpu) * Kill the calling secondary CPU, early in bringup before it is turned * online. */ -void cpu_die_early(void) +void __noreturn cpu_die_early(void) { int cpu = smp_processor_id(); @@ -816,7 +815,7 @@ void arch_irq_work_raise(void) } #endif -static void local_cpu_stop(void) +static void __noreturn local_cpu_stop(void) { set_cpu_online(smp_processor_id(), false); @@ -830,7 +829,7 @@ static void local_cpu_stop(void) * that cpu_online_mask gets correctly updated and smp_send_stop() can skip * CPUs that have already stopped themselves. */ -void panic_smp_self_stop(void) +void __noreturn panic_smp_self_stop(void) { local_cpu_stop(); } @@ -839,7 +838,7 @@ void panic_smp_self_stop(void) static atomic_t waiting_for_crash_ipi = ATOMIC_INIT(0); #endif -static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) +static void __noreturn ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) { #ifdef CONFIG_KEXEC_CORE crash_save_cpu(regs, cpu); @@ -854,6 +853,8 @@ static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) /* just in case */ cpu_park_loop(); +#else + BUG(); #endif } @@ -977,7 +978,7 @@ void __init set_smp_ipi_range(int ipi_base, int n) ipi_setup(smp_processor_id()); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 4a79ba100799..4bb1b8f47298 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -863,7 +863,7 @@ void bad_el0_sync(struct pt_regs *regs, int reason, unsigned long esr) DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack) __aligned(16); -void panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far) +void __noreturn panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far) { unsigned long tsk_stk = (unsigned long)current->stack; unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr); @@ -905,7 +905,6 @@ void __noreturn arm64_serror_panic(struct pt_regs *regs, unsigned long esr) nmi_panic(regs, "Asynchronous SError Interrupt"); cpu_park_loop(); - unreachable(); } bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned long esr) diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 0119dc91abb5..d9e1355730ef 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -288,7 +288,7 @@ static int aarch32_alloc_kuser_vdso_page(void) memcpy((void *)(vdso_page + 0x1000 - kuser_sz), __kuser_helper_start, kuser_sz); - aarch32_vectors_page = virt_to_page(vdso_page); + aarch32_vectors_page = virt_to_page((void *)vdso_page); return 0; } diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index b9202c2ee18e..3cd7e76cc562 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -181,18 +181,8 @@ SECTIONS KPROBES_TEXT HYPERVISOR_TEXT *(.gnu.warning) - . = ALIGN(16); - *(.got) /* Global offset table */ } - /* - * Make sure that the .got.plt is either completely empty or it - * contains only the lazy dispatch entries. - */ - .got.plt : { *(.got.plt) } - ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, - "Unexpected GOT/PLT entries detected!") - . = ALIGN(SEGMENT_ALIGN); _etext = .; /* End of text section */ @@ -201,6 +191,15 @@ SECTIONS HYPERVISOR_DATA_SECTIONS + .got : { *(.got) } + /* + * Make sure that the .got.plt is either completely empty or it + * contains only the lazy dispatch entries. + */ + .got.plt : { *(.got.plt) } + ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, + "Unexpected GOT/PLT entries detected!") + /* code sections that are never executed via the kernel mapping */ .rodata.text : { TRAMP_TEXT diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index e1af4301b913..05b022be885b 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -30,14 +31,11 @@ static u32 host_ptimer_irq_flags; static DEFINE_STATIC_KEY_FALSE(has_gic_active_state); -static const struct kvm_irq_level default_ptimer_irq = { - .irq = 30, - .level = 1, -}; - -static const struct kvm_irq_level default_vtimer_irq = { - .irq = 27, - .level = 1, +static const u8 default_ppi[] = { + [TIMER_PTIMER] = 30, + [TIMER_VTIMER] = 27, + [TIMER_HPTIMER] = 26, + [TIMER_HVTIMER] = 28, }; static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx); @@ -51,6 +49,24 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu, static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, struct arch_timer_context *timer, enum kvm_arch_timer_regs treg); +static bool kvm_arch_timer_get_input_level(int vintid); + +static struct irq_ops arch_timer_irq_ops = { + .get_input_level = kvm_arch_timer_get_input_level, +}; + +static bool has_cntpoff(void) +{ + return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF)); +} + +static int nr_timers(struct kvm_vcpu *vcpu) +{ + if (!vcpu_has_nv(vcpu)) + return NR_KVM_EL0_TIMERS; + + return NR_KVM_TIMERS; +} u32 timer_get_ctl(struct arch_timer_context *ctxt) { @@ -61,6 +77,10 @@ u32 timer_get_ctl(struct arch_timer_context *ctxt) return __vcpu_sys_reg(vcpu, CNTV_CTL_EL0); case TIMER_PTIMER: return __vcpu_sys_reg(vcpu, CNTP_CTL_EL0); + case TIMER_HVTIMER: + return __vcpu_sys_reg(vcpu, CNTHV_CTL_EL2); + case TIMER_HPTIMER: + return __vcpu_sys_reg(vcpu, CNTHP_CTL_EL2); default: WARN_ON(1); return 0; @@ -76,6 +96,10 @@ u64 timer_get_cval(struct arch_timer_context *ctxt) return __vcpu_sys_reg(vcpu, CNTV_CVAL_EL0); case TIMER_PTIMER: return __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0); + case TIMER_HVTIMER: + return __vcpu_sys_reg(vcpu, CNTHV_CVAL_EL2); + case TIMER_HPTIMER: + return __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2); default: WARN_ON(1); return 0; @@ -84,10 +108,17 @@ u64 timer_get_cval(struct arch_timer_context *ctxt) static u64 timer_get_offset(struct arch_timer_context *ctxt) { - if (ctxt->offset.vm_offset) - return *ctxt->offset.vm_offset; + u64 offset = 0; - return 0; + if (!ctxt) + return 0; + + if (ctxt->offset.vm_offset) + offset += *ctxt->offset.vm_offset; + if (ctxt->offset.vcpu_offset) + offset += *ctxt->offset.vcpu_offset; + + return offset; } static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl) @@ -101,6 +132,12 @@ static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl) case TIMER_PTIMER: __vcpu_sys_reg(vcpu, CNTP_CTL_EL0) = ctl; break; + case TIMER_HVTIMER: + __vcpu_sys_reg(vcpu, CNTHV_CTL_EL2) = ctl; + break; + case TIMER_HPTIMER: + __vcpu_sys_reg(vcpu, CNTHP_CTL_EL2) = ctl; + break; default: WARN_ON(1); } @@ -117,6 +154,12 @@ static void timer_set_cval(struct arch_timer_context *ctxt, u64 cval) case TIMER_PTIMER: __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0) = cval; break; + case TIMER_HVTIMER: + __vcpu_sys_reg(vcpu, CNTHV_CVAL_EL2) = cval; + break; + case TIMER_HPTIMER: + __vcpu_sys_reg(vcpu, CNTHP_CVAL_EL2) = cval; + break; default: WARN_ON(1); } @@ -139,13 +182,27 @@ u64 kvm_phys_timer_read(void) static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map) { - if (has_vhe()) { + if (vcpu_has_nv(vcpu)) { + if (is_hyp_ctxt(vcpu)) { + map->direct_vtimer = vcpu_hvtimer(vcpu); + map->direct_ptimer = vcpu_hptimer(vcpu); + map->emul_vtimer = vcpu_vtimer(vcpu); + map->emul_ptimer = vcpu_ptimer(vcpu); + } else { + map->direct_vtimer = vcpu_vtimer(vcpu); + map->direct_ptimer = vcpu_ptimer(vcpu); + map->emul_vtimer = vcpu_hvtimer(vcpu); + map->emul_ptimer = vcpu_hptimer(vcpu); + } + } else if (has_vhe()) { map->direct_vtimer = vcpu_vtimer(vcpu); map->direct_ptimer = vcpu_ptimer(vcpu); + map->emul_vtimer = NULL; map->emul_ptimer = NULL; } else { map->direct_vtimer = vcpu_vtimer(vcpu); map->direct_ptimer = NULL; + map->emul_vtimer = NULL; map->emul_ptimer = vcpu_ptimer(vcpu); } @@ -212,7 +269,7 @@ static u64 kvm_counter_compute_delta(struct arch_timer_context *timer_ctx, ns = cyclecounter_cyc2ns(timecounter->cc, val - now, timecounter->mask, - &timecounter->frac); + &timer_ctx->ns_frac); return ns; } @@ -240,8 +297,11 @@ static bool vcpu_has_wfit_active(struct kvm_vcpu *vcpu) static u64 wfit_delay_ns(struct kvm_vcpu *vcpu) { - struct arch_timer_context *ctx = vcpu_vtimer(vcpu); u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); + struct arch_timer_context *ctx; + + ctx = (vcpu_has_nv(vcpu) && is_hyp_ctxt(vcpu)) ? vcpu_hvtimer(vcpu) + : vcpu_vtimer(vcpu); return kvm_counter_compute_delta(ctx, val); } @@ -255,7 +315,7 @@ static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu) u64 min_delta = ULLONG_MAX; int i; - for (i = 0; i < NR_KVM_TIMERS; i++) { + for (i = 0; i < nr_timers(vcpu); i++) { struct arch_timer_context *ctx = &vcpu->arch.timer_cpu.timers[i]; WARN(ctx->loaded, "timer %d loaded\n", i); @@ -338,9 +398,11 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx) switch (index) { case TIMER_VTIMER: + case TIMER_HVTIMER: cnt_ctl = read_sysreg_el0(SYS_CNTV_CTL); break; case TIMER_PTIMER: + case TIMER_HPTIMER: cnt_ctl = read_sysreg_el0(SYS_CNTP_CTL); break; case NR_KVM_TIMERS: @@ -392,12 +454,12 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, int ret; timer_ctx->irq.level = new_level; - trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq, + trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_irq(timer_ctx), timer_ctx->irq.level); if (!userspace_irqchip(vcpu->kvm)) { ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, - timer_ctx->irq.irq, + timer_irq(timer_ctx), timer_ctx->irq.level, timer_ctx); WARN_ON(ret); @@ -432,6 +494,12 @@ static void set_cntvoff(u64 cntvoff) kvm_call_hyp(__kvm_timer_set_cntvoff, cntvoff); } +static void set_cntpoff(u64 cntpoff) +{ + if (has_cntpoff()) + write_sysreg_s(cntpoff, SYS_CNTPOFF_EL2); +} + static void timer_save_state(struct arch_timer_context *ctx) { struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu); @@ -447,7 +515,10 @@ static void timer_save_state(struct arch_timer_context *ctx) goto out; switch (index) { + u64 cval; + case TIMER_VTIMER: + case TIMER_HVTIMER: timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTV_CTL)); timer_set_cval(ctx, read_sysreg_el0(SYS_CNTV_CVAL)); @@ -473,13 +544,20 @@ static void timer_save_state(struct arch_timer_context *ctx) set_cntvoff(0); break; case TIMER_PTIMER: + case TIMER_HPTIMER: timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTP_CTL)); - timer_set_cval(ctx, read_sysreg_el0(SYS_CNTP_CVAL)); + cval = read_sysreg_el0(SYS_CNTP_CVAL); + + if (!has_cntpoff()) + cval -= timer_get_offset(ctx); + + timer_set_cval(ctx, cval); /* Disable the timer */ write_sysreg_el0(0, SYS_CNTP_CTL); isb(); + set_cntpoff(0); break; case NR_KVM_TIMERS: BUG(); @@ -510,6 +588,7 @@ static void kvm_timer_blocking(struct kvm_vcpu *vcpu) */ if (!kvm_timer_irq_can_fire(map.direct_vtimer) && !kvm_timer_irq_can_fire(map.direct_ptimer) && + !kvm_timer_irq_can_fire(map.emul_vtimer) && !kvm_timer_irq_can_fire(map.emul_ptimer) && !vcpu_has_wfit_active(vcpu)) return; @@ -543,14 +622,23 @@ static void timer_restore_state(struct arch_timer_context *ctx) goto out; switch (index) { + u64 cval, offset; + case TIMER_VTIMER: + case TIMER_HVTIMER: set_cntvoff(timer_get_offset(ctx)); write_sysreg_el0(timer_get_cval(ctx), SYS_CNTV_CVAL); isb(); write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTV_CTL); break; case TIMER_PTIMER: - write_sysreg_el0(timer_get_cval(ctx), SYS_CNTP_CVAL); + case TIMER_HPTIMER: + cval = timer_get_cval(ctx); + offset = timer_get_offset(ctx); + set_cntpoff(offset); + if (!has_cntpoff()) + cval += offset; + write_sysreg_el0(cval, SYS_CNTP_CVAL); isb(); write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTP_CTL); break; @@ -586,7 +674,7 @@ static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx) kvm_timer_update_irq(ctx->vcpu, kvm_timer_should_fire(ctx), ctx); if (irqchip_in_kernel(vcpu->kvm)) - phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq); + phys_active = kvm_vgic_map_is_active(vcpu, timer_irq(ctx)); phys_active |= ctx->irq.level; @@ -621,6 +709,128 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu) enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags); } +/* If _pred is true, set bit in _set, otherwise set it in _clr */ +#define assign_clear_set_bit(_pred, _bit, _clr, _set) \ + do { \ + if (_pred) \ + (_set) |= (_bit); \ + else \ + (_clr) |= (_bit); \ + } while (0) + +static void kvm_timer_vcpu_load_nested_switch(struct kvm_vcpu *vcpu, + struct timer_map *map) +{ + int hw, ret; + + if (!irqchip_in_kernel(vcpu->kvm)) + return; + + /* + * We only ever unmap the vtimer irq on a VHE system that runs nested + * virtualization, in which case we have both a valid emul_vtimer, + * emul_ptimer, direct_vtimer, and direct_ptimer. + * + * Since this is called from kvm_timer_vcpu_load(), a change between + * vEL2 and vEL1/0 will have just happened, and the timer_map will + * represent this, and therefore we switch the emul/direct mappings + * below. + */ + hw = kvm_vgic_get_map(vcpu, timer_irq(map->direct_vtimer)); + if (hw < 0) { + kvm_vgic_unmap_phys_irq(vcpu, timer_irq(map->emul_vtimer)); + kvm_vgic_unmap_phys_irq(vcpu, timer_irq(map->emul_ptimer)); + + ret = kvm_vgic_map_phys_irq(vcpu, + map->direct_vtimer->host_timer_irq, + timer_irq(map->direct_vtimer), + &arch_timer_irq_ops); + WARN_ON_ONCE(ret); + ret = kvm_vgic_map_phys_irq(vcpu, + map->direct_ptimer->host_timer_irq, + timer_irq(map->direct_ptimer), + &arch_timer_irq_ops); + WARN_ON_ONCE(ret); + + /* + * The virtual offset behaviour is "interresting", as it + * always applies when HCR_EL2.E2H==0, but only when + * accessed from EL1 when HCR_EL2.E2H==1. So make sure we + * track E2H when putting the HV timer in "direct" mode. + */ + if (map->direct_vtimer == vcpu_hvtimer(vcpu)) { + struct arch_timer_offset *offs = &map->direct_vtimer->offset; + + if (vcpu_el2_e2h_is_set(vcpu)) + offs->vcpu_offset = NULL; + else + offs->vcpu_offset = &__vcpu_sys_reg(vcpu, CNTVOFF_EL2); + } + } +} + +static void timer_set_traps(struct kvm_vcpu *vcpu, struct timer_map *map) +{ + bool tpt, tpc; + u64 clr, set; + + /* + * No trapping gets configured here with nVHE. See + * __timer_enable_traps(), which is where the stuff happens. + */ + if (!has_vhe()) + return; + + /* + * Our default policy is not to trap anything. As we progress + * within this function, reality kicks in and we start adding + * traps based on emulation requirements. + */ + tpt = tpc = false; + + /* + * We have two possibility to deal with a physical offset: + * + * - Either we have CNTPOFF (yay!) or the offset is 0: + * we let the guest freely access the HW + * + * - or neither of these condition apply: + * we trap accesses to the HW, but still use it + * after correcting the physical offset + */ + if (!has_cntpoff() && timer_get_offset(map->direct_ptimer)) + tpt = tpc = true; + + /* + * Apply the enable bits that the guest hypervisor has requested for + * its own guest. We can only add traps that wouldn't have been set + * above. + */ + if (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)) { + u64 val = __vcpu_sys_reg(vcpu, CNTHCTL_EL2); + + /* Use the VHE format for mental sanity */ + if (!vcpu_el2_e2h_is_set(vcpu)) + val = (val & (CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN)) << 10; + + tpt |= !(val & (CNTHCTL_EL1PCEN << 10)); + tpc |= !(val & (CNTHCTL_EL1PCTEN << 10)); + } + + /* + * Now that we have collected our requirements, compute the + * trap and enable bits. + */ + set = 0; + clr = 0; + + assign_clear_set_bit(tpt, CNTHCTL_EL1PCEN << 10, set, clr); + assign_clear_set_bit(tpc, CNTHCTL_EL1PCTEN << 10, set, clr); + + /* This only happens on VHE, so use the CNTKCTL_EL1 accessor */ + sysreg_clear_set(cntkctl_el1, clr, set); +} + void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = vcpu_timer(vcpu); @@ -632,6 +842,9 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) get_timer_map(vcpu, &map); if (static_branch_likely(&has_gic_active_state)) { + if (vcpu_has_nv(vcpu)) + kvm_timer_vcpu_load_nested_switch(vcpu, &map); + kvm_timer_vcpu_load_gic(map.direct_vtimer); if (map.direct_ptimer) kvm_timer_vcpu_load_gic(map.direct_ptimer); @@ -644,9 +857,12 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) timer_restore_state(map.direct_vtimer); if (map.direct_ptimer) timer_restore_state(map.direct_ptimer); - + if (map.emul_vtimer) + timer_emulate(map.emul_vtimer); if (map.emul_ptimer) timer_emulate(map.emul_ptimer); + + timer_set_traps(vcpu, &map); } bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu) @@ -689,6 +905,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu) * In any case, we re-schedule the hrtimer for the physical timer when * coming back to the VCPU thread in kvm_timer_vcpu_load(). */ + if (map.emul_vtimer) + soft_timer_cancel(&map.emul_vtimer->hrtimer); if (map.emul_ptimer) soft_timer_cancel(&map.emul_ptimer->hrtimer); @@ -738,56 +956,89 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu) * resets the timer to be disabled and unmasked and is compliant with * the ARMv7 architecture. */ - timer_set_ctl(vcpu_vtimer(vcpu), 0); - timer_set_ctl(vcpu_ptimer(vcpu), 0); + for (int i = 0; i < nr_timers(vcpu); i++) + timer_set_ctl(vcpu_get_timer(vcpu, i), 0); + + /* + * A vcpu running at EL2 is in charge of the offset applied to + * the virtual timer, so use the physical VM offset, and point + * the vcpu offset to CNTVOFF_EL2. + */ + if (vcpu_has_nv(vcpu)) { + struct arch_timer_offset *offs = &vcpu_vtimer(vcpu)->offset; + + offs->vcpu_offset = &__vcpu_sys_reg(vcpu, CNTVOFF_EL2); + offs->vm_offset = &vcpu->kvm->arch.timer_data.poffset; + } if (timer->enabled) { - kvm_timer_update_irq(vcpu, false, vcpu_vtimer(vcpu)); - kvm_timer_update_irq(vcpu, false, vcpu_ptimer(vcpu)); + for (int i = 0; i < nr_timers(vcpu); i++) + kvm_timer_update_irq(vcpu, false, + vcpu_get_timer(vcpu, i)); if (irqchip_in_kernel(vcpu->kvm)) { - kvm_vgic_reset_mapped_irq(vcpu, map.direct_vtimer->irq.irq); + kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_vtimer)); if (map.direct_ptimer) - kvm_vgic_reset_mapped_irq(vcpu, map.direct_ptimer->irq.irq); + kvm_vgic_reset_mapped_irq(vcpu, timer_irq(map.direct_ptimer)); } } + if (map.emul_vtimer) + soft_timer_cancel(&map.emul_vtimer->hrtimer); if (map.emul_ptimer) soft_timer_cancel(&map.emul_ptimer->hrtimer); return 0; } +static void timer_context_init(struct kvm_vcpu *vcpu, int timerid) +{ + struct arch_timer_context *ctxt = vcpu_get_timer(vcpu, timerid); + struct kvm *kvm = vcpu->kvm; + + ctxt->vcpu = vcpu; + + if (timerid == TIMER_VTIMER) + ctxt->offset.vm_offset = &kvm->arch.timer_data.voffset; + else + ctxt->offset.vm_offset = &kvm->arch.timer_data.poffset; + + hrtimer_init(&ctxt->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); + ctxt->hrtimer.function = kvm_hrtimer_expire; + + switch (timerid) { + case TIMER_PTIMER: + case TIMER_HPTIMER: + ctxt->host_timer_irq = host_ptimer_irq; + break; + case TIMER_VTIMER: + case TIMER_HVTIMER: + ctxt->host_timer_irq = host_vtimer_irq; + break; + } +} + void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = vcpu_timer(vcpu); - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); - struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); - vtimer->vcpu = vcpu; - vtimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.voffset; - ptimer->vcpu = vcpu; + for (int i = 0; i < NR_KVM_TIMERS; i++) + timer_context_init(vcpu, i); - /* Synchronize cntvoff across all vtimers of a VM. */ - timer_set_offset(vtimer, kvm_phys_timer_read()); - timer_set_offset(ptimer, 0); + /* Synchronize offsets across timers of a VM if not already provided */ + if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) { + timer_set_offset(vcpu_vtimer(vcpu), kvm_phys_timer_read()); + timer_set_offset(vcpu_ptimer(vcpu), 0); + } hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); timer->bg_timer.function = kvm_bg_timer_expire; +} - hrtimer_init(&vtimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); - hrtimer_init(&ptimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); - vtimer->hrtimer.function = kvm_hrtimer_expire; - ptimer->hrtimer.function = kvm_hrtimer_expire; - - vtimer->irq.irq = default_vtimer_irq.irq; - ptimer->irq.irq = default_ptimer_irq.irq; - - vtimer->host_timer_irq = host_vtimer_irq; - ptimer->host_timer_irq = host_ptimer_irq; - - vtimer->host_timer_irq_flags = host_vtimer_irq_flags; - ptimer->host_timer_irq_flags = host_ptimer_irq_flags; +void kvm_timer_init_vm(struct kvm *kvm) +{ + for (int i = 0; i < NR_KVM_TIMERS; i++) + kvm->arch.timer_data.ppi[i] = default_ppi[i]; } void kvm_timer_cpu_up(void) @@ -814,8 +1065,11 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value); break; case KVM_REG_ARM_TIMER_CNT: - timer = vcpu_vtimer(vcpu); - timer_set_offset(timer, kvm_phys_timer_read() - value); + if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, + &vcpu->kvm->arch.flags)) { + timer = vcpu_vtimer(vcpu); + timer_set_offset(timer, kvm_phys_timer_read() - value); + } break; case KVM_REG_ARM_TIMER_CVAL: timer = vcpu_vtimer(vcpu); @@ -825,6 +1079,13 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) timer = vcpu_ptimer(vcpu); kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value); break; + case KVM_REG_ARM_PTIMER_CNT: + if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, + &vcpu->kvm->arch.flags)) { + timer = vcpu_ptimer(vcpu); + timer_set_offset(timer, kvm_phys_timer_read() - value); + } + break; case KVM_REG_ARM_PTIMER_CVAL: timer = vcpu_ptimer(vcpu); kvm_arm_timer_write(vcpu, timer, TIMER_REG_CVAL, value); @@ -902,6 +1163,10 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, val = kvm_phys_timer_read() - timer_get_offset(timer); break; + case TIMER_REG_VOFF: + val = *timer->offset.vcpu_offset; + break; + default: BUG(); } @@ -920,7 +1185,7 @@ u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu, get_timer_map(vcpu, &map); timer = vcpu_get_timer(vcpu, tmr); - if (timer == map.emul_ptimer) + if (timer == map.emul_vtimer || timer == map.emul_ptimer) return kvm_arm_timer_read(vcpu, timer, treg); preempt_disable(); @@ -952,6 +1217,10 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu, timer_set_cval(timer, val); break; + case TIMER_REG_VOFF: + *timer->offset.vcpu_offset = val; + break; + default: BUG(); } @@ -967,7 +1236,7 @@ void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu, get_timer_map(vcpu, &map); timer = vcpu_get_timer(vcpu, tmr); - if (timer == map.emul_ptimer) { + if (timer == map.emul_vtimer || timer == map.emul_ptimer) { soft_timer_cancel(&timer->hrtimer); kvm_arm_timer_write(vcpu, timer, treg, val); timer_emulate(timer); @@ -1047,10 +1316,6 @@ static const struct irq_domain_ops timer_domain_ops = { .free = timer_irq_domain_free, }; -static struct irq_ops arch_timer_irq_ops = { - .get_input_level = kvm_arch_timer_get_input_level, -}; - static void kvm_irq_fixup_flags(unsigned int virq, u32 *flags) { *flags = irq_get_trigger_type(virq); @@ -1192,44 +1457,56 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) static bool timer_irqs_are_valid(struct kvm_vcpu *vcpu) { - int vtimer_irq, ptimer_irq, ret; - unsigned long i; + u32 ppis = 0; + bool valid; - vtimer_irq = vcpu_vtimer(vcpu)->irq.irq; - ret = kvm_vgic_set_owner(vcpu, vtimer_irq, vcpu_vtimer(vcpu)); - if (ret) - return false; + mutex_lock(&vcpu->kvm->arch.config_lock); - ptimer_irq = vcpu_ptimer(vcpu)->irq.irq; - ret = kvm_vgic_set_owner(vcpu, ptimer_irq, vcpu_ptimer(vcpu)); - if (ret) - return false; + for (int i = 0; i < nr_timers(vcpu); i++) { + struct arch_timer_context *ctx; + int irq; - kvm_for_each_vcpu(i, vcpu, vcpu->kvm) { - if (vcpu_vtimer(vcpu)->irq.irq != vtimer_irq || - vcpu_ptimer(vcpu)->irq.irq != ptimer_irq) - return false; + ctx = vcpu_get_timer(vcpu, i); + irq = timer_irq(ctx); + if (kvm_vgic_set_owner(vcpu, irq, ctx)) + break; + + /* + * We know by construction that we only have PPIs, so + * all values are less than 32. + */ + ppis |= BIT(irq); } - return true; + valid = hweight32(ppis) == nr_timers(vcpu); + + if (valid) + set_bit(KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE, &vcpu->kvm->arch.flags); + + mutex_unlock(&vcpu->kvm->arch.config_lock); + + return valid; } -bool kvm_arch_timer_get_input_level(int vintid) +static bool kvm_arch_timer_get_input_level(int vintid) { struct kvm_vcpu *vcpu = kvm_get_running_vcpu(); - struct arch_timer_context *timer; if (WARN(!vcpu, "No vcpu context!\n")) return false; - if (vintid == vcpu_vtimer(vcpu)->irq.irq) - timer = vcpu_vtimer(vcpu); - else if (vintid == vcpu_ptimer(vcpu)->irq.irq) - timer = vcpu_ptimer(vcpu); - else - BUG(); + for (int i = 0; i < nr_timers(vcpu); i++) { + struct arch_timer_context *ctx; - return kvm_timer_should_fire(timer); + ctx = vcpu_get_timer(vcpu, i); + if (timer_irq(ctx) == vintid) + return kvm_timer_should_fire(ctx); + } + + /* A timer IRQ has fired, but no matching timer was found? */ + WARN_RATELIMIT(1, "timer INTID%d unknown\n", vintid); + + return false; } int kvm_timer_enable(struct kvm_vcpu *vcpu) @@ -1258,7 +1535,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) ret = kvm_vgic_map_phys_irq(vcpu, map.direct_vtimer->host_timer_irq, - map.direct_vtimer->irq.irq, + timer_irq(map.direct_vtimer), &arch_timer_irq_ops); if (ret) return ret; @@ -1266,7 +1543,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) if (map.direct_ptimer) { ret = kvm_vgic_map_phys_irq(vcpu, map.direct_ptimer->host_timer_irq, - map.direct_ptimer->irq.irq, + timer_irq(map.direct_ptimer), &arch_timer_irq_ops); } @@ -1278,45 +1555,17 @@ no_vgic: return 0; } -/* - * On VHE system, we only need to configure the EL2 timer trap register once, - * not for every world switch. - * The host kernel runs at EL2 with HCR_EL2.TGE == 1, - * and this makes those bits have no effect for the host kernel execution. - */ +/* If we have CNTPOFF, permanently set ECV to enable it */ void kvm_timer_init_vhe(void) { - /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */ - u32 cnthctl_shift = 10; - u64 val; - - /* - * VHE systems allow the guest direct access to the EL1 physical - * timer/counter. - */ - val = read_sysreg(cnthctl_el2); - val |= (CNTHCTL_EL1PCEN << cnthctl_shift); - val |= (CNTHCTL_EL1PCTEN << cnthctl_shift); - write_sysreg(val, cnthctl_el2); -} - -static void set_timer_irqs(struct kvm *kvm, int vtimer_irq, int ptimer_irq) -{ - struct kvm_vcpu *vcpu; - unsigned long i; - - kvm_for_each_vcpu(i, vcpu, kvm) { - vcpu_vtimer(vcpu)->irq.irq = vtimer_irq; - vcpu_ptimer(vcpu)->irq.irq = ptimer_irq; - } + if (cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF)) + sysreg_clear_set(cntkctl_el1, 0, CNTHCTL_ECV); } int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { int __user *uaddr = (int __user *)(long)attr->addr; - struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); - struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); - int irq; + int irq, idx, ret = 0; if (!irqchip_in_kernel(vcpu->kvm)) return -EINVAL; @@ -1327,21 +1576,42 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) if (!(irq_is_ppi(irq))) return -EINVAL; - if (vcpu->arch.timer_cpu.enabled) - return -EBUSY; + mutex_lock(&vcpu->kvm->arch.config_lock); + + if (test_bit(KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE, + &vcpu->kvm->arch.flags)) { + ret = -EBUSY; + goto out; + } switch (attr->attr) { case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: - set_timer_irqs(vcpu->kvm, irq, ptimer->irq.irq); + idx = TIMER_VTIMER; break; case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: - set_timer_irqs(vcpu->kvm, vtimer->irq.irq, irq); + idx = TIMER_PTIMER; + break; + case KVM_ARM_VCPU_TIMER_IRQ_HVTIMER: + idx = TIMER_HVTIMER; + break; + case KVM_ARM_VCPU_TIMER_IRQ_HPTIMER: + idx = TIMER_HPTIMER; break; default: - return -ENXIO; + ret = -ENXIO; + goto out; } - return 0; + /* + * We cannot validate the IRQ unicity before we run, so take it at + * face value. The verdict will be given on first vcpu run, for each + * vcpu. Yes this is late. Blame it on the stupid API. + */ + vcpu->kvm->arch.timer_data.ppi[idx] = irq; + +out: + mutex_unlock(&vcpu->kvm->arch.config_lock); + return ret; } int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) @@ -1357,11 +1627,17 @@ int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: timer = vcpu_ptimer(vcpu); break; + case KVM_ARM_VCPU_TIMER_IRQ_HVTIMER: + timer = vcpu_hvtimer(vcpu); + break; + case KVM_ARM_VCPU_TIMER_IRQ_HPTIMER: + timer = vcpu_hptimer(vcpu); + break; default: return -ENXIO; } - irq = timer->irq.irq; + irq = timer_irq(timer); return put_user(irq, uaddr); } @@ -1370,8 +1646,42 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) switch (attr->attr) { case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: + case KVM_ARM_VCPU_TIMER_IRQ_HVTIMER: + case KVM_ARM_VCPU_TIMER_IRQ_HPTIMER: return 0; } return -ENXIO; } + +int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm, + struct kvm_arm_counter_offset *offset) +{ + int ret = 0; + + if (offset->reserved) + return -EINVAL; + + mutex_lock(&kvm->lock); + + if (lock_all_vcpus(kvm)) { + set_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &kvm->arch.flags); + + /* + * If userspace decides to set the offset using this + * API rather than merely restoring the counter + * values, the offset applies to both the virtual and + * physical views. + */ + kvm->arch.timer_data.voffset = offset->counter_offset; + kvm->arch.timer_data.poffset = offset->counter_offset; + + unlock_all_vcpus(kvm); + } else { + ret = -EBUSY; + } + + mutex_unlock(&kvm->lock); + + return ret; +} diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 6673c7b4f1a8..14391826241c 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -126,6 +126,16 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { int ret; + mutex_init(&kvm->arch.config_lock); + +#ifdef CONFIG_LOCKDEP + /* Clue in lockdep that the config_lock must be taken inside kvm->lock */ + mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); + mutex_unlock(&kvm->arch.config_lock); + mutex_unlock(&kvm->lock); +#endif + ret = kvm_share_hyp(kvm, kvm + 1); if (ret) return ret; @@ -146,6 +156,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_vgic_early_init(kvm); + kvm_timer_init_vm(kvm); + /* The maximum number of VCPUs is limited by the host's GIC model */ kvm->max_vcpus = kvm_arm_default_max_vcpus(); @@ -190,6 +202,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_destroy_vcpus(kvm); kvm_unshare_hyp(kvm, kvm + 1); + + kvm_arm_teardown_hypercalls(kvm); } int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) @@ -219,6 +233,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_PTP_KVM: case KVM_CAP_ARM_SYSTEM_SUSPEND: case KVM_CAP_IRQFD_RESAMPLE: + case KVM_CAP_COUNTER_OFFSET: r = 1; break; case KVM_CAP_SET_GUEST_DEBUG2: @@ -325,6 +340,16 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) { int err; + spin_lock_init(&vcpu->arch.mp_state_lock); + +#ifdef CONFIG_LOCKDEP + /* Inform lockdep that the config_lock is acquired after vcpu->mutex */ + mutex_lock(&vcpu->mutex); + mutex_lock(&vcpu->kvm->arch.config_lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); + mutex_unlock(&vcpu->mutex); +#endif + /* Force users to call KVM_ARM_VCPU_INIT */ vcpu->arch.target = -1; bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); @@ -442,34 +467,41 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) vcpu->cpu = -1; } -void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) +static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) { - vcpu->arch.mp_state.mp_state = KVM_MP_STATE_STOPPED; + WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED); kvm_make_request(KVM_REQ_SLEEP, vcpu); kvm_vcpu_kick(vcpu); } +void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) +{ + spin_lock(&vcpu->arch.mp_state_lock); + __kvm_arm_vcpu_power_off(vcpu); + spin_unlock(&vcpu->arch.mp_state_lock); +} + bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu) { - return vcpu->arch.mp_state.mp_state == KVM_MP_STATE_STOPPED; + return READ_ONCE(vcpu->arch.mp_state.mp_state) == KVM_MP_STATE_STOPPED; } static void kvm_arm_vcpu_suspend(struct kvm_vcpu *vcpu) { - vcpu->arch.mp_state.mp_state = KVM_MP_STATE_SUSPENDED; + WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_SUSPENDED); kvm_make_request(KVM_REQ_SUSPEND, vcpu); kvm_vcpu_kick(vcpu); } static bool kvm_arm_vcpu_suspended(struct kvm_vcpu *vcpu) { - return vcpu->arch.mp_state.mp_state == KVM_MP_STATE_SUSPENDED; + return READ_ONCE(vcpu->arch.mp_state.mp_state) == KVM_MP_STATE_SUSPENDED; } int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - *mp_state = vcpu->arch.mp_state; + *mp_state = READ_ONCE(vcpu->arch.mp_state); return 0; } @@ -479,12 +511,14 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, { int ret = 0; + spin_lock(&vcpu->arch.mp_state_lock); + switch (mp_state->mp_state) { case KVM_MP_STATE_RUNNABLE: - vcpu->arch.mp_state = *mp_state; + WRITE_ONCE(vcpu->arch.mp_state, *mp_state); break; case KVM_MP_STATE_STOPPED: - kvm_arm_vcpu_power_off(vcpu); + __kvm_arm_vcpu_power_off(vcpu); break; case KVM_MP_STATE_SUSPENDED: kvm_arm_vcpu_suspend(vcpu); @@ -493,6 +527,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, ret = -EINVAL; } + spin_unlock(&vcpu->arch.mp_state_lock); + return ret; } @@ -592,9 +628,9 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) if (kvm_vm_is_protected(kvm)) kvm_call_hyp_nvhe(__pkvm_vcpu_init_traps, vcpu); - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags); - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); return ret; } @@ -1209,10 +1245,14 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, /* * Handle the "start in power-off" case. */ + spin_lock(&vcpu->arch.mp_state_lock); + if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) - kvm_arm_vcpu_power_off(vcpu); + __kvm_arm_vcpu_power_off(vcpu); else - vcpu->arch.mp_state.mp_state = KVM_MP_STATE_RUNNABLE; + WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE); + + spin_unlock(&vcpu->arch.mp_state_lock); return 0; } @@ -1438,11 +1478,31 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, } } -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_ARM_VM_SMCCC_CTRL: + return kvm_vm_smccc_has_attr(kvm, attr); + default: + return -ENXIO; + } +} + +static int kvm_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_ARM_VM_SMCCC_CTRL: + return kvm_vm_smccc_set_attr(kvm, attr); + default: + return -ENXIO; + } +} + +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; void __user *argp = (void __user *)arg; + struct kvm_device_attr attr; switch (ioctl) { case KVM_CREATE_IRQCHIP: { @@ -1478,11 +1538,73 @@ long kvm_arch_vm_ioctl(struct file *filp, return -EFAULT; return kvm_vm_ioctl_mte_copy_tags(kvm, ©_tags); } + case KVM_ARM_SET_COUNTER_OFFSET: { + struct kvm_arm_counter_offset offset; + + if (copy_from_user(&offset, argp, sizeof(offset))) + return -EFAULT; + return kvm_vm_ioctl_set_counter_offset(kvm, &offset); + } + case KVM_HAS_DEVICE_ATTR: { + if (copy_from_user(&attr, argp, sizeof(attr))) + return -EFAULT; + + return kvm_vm_has_attr(kvm, &attr); + } + case KVM_SET_DEVICE_ATTR: { + if (copy_from_user(&attr, argp, sizeof(attr))) + return -EFAULT; + + return kvm_vm_set_attr(kvm, &attr); + } default: return -EINVAL; } } +/* unlocks vcpus from @vcpu_lock_idx and smaller */ +static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx) +{ + struct kvm_vcpu *tmp_vcpu; + + for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) { + tmp_vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx); + mutex_unlock(&tmp_vcpu->mutex); + } +} + +void unlock_all_vcpus(struct kvm *kvm) +{ + lockdep_assert_held(&kvm->lock); + + unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1); +} + +/* Returns true if all vcpus were locked, false otherwise */ +bool lock_all_vcpus(struct kvm *kvm) +{ + struct kvm_vcpu *tmp_vcpu; + unsigned long c; + + lockdep_assert_held(&kvm->lock); + + /* + * Any time a vcpu is in an ioctl (including running), the + * core KVM code tries to grab the vcpu->mutex. + * + * By grabbing the vcpu->mutex of all VCPUs we ensure that no + * other VCPUs can fiddle with the state while we access it. + */ + kvm_for_each_vcpu(c, tmp_vcpu, kvm) { + if (!mutex_trylock(&tmp_vcpu->mutex)) { + unlock_vcpus(kvm, c - 1); + return false; + } + } + + return true; +} + static unsigned long nvhe_percpu_size(void) { return (unsigned long)CHOOSE_NVHE_SYM(__per_cpu_end) - diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index 1279949599b5..4c9dcd8fc939 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -81,26 +81,34 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) fpsimd_kvm_prepare(); + /* + * We will check TIF_FOREIGN_FPSTATE just before entering the + * guest in kvm_arch_vcpu_ctxflush_fp() and override this to + * FP_STATE_FREE if the flag set. + */ vcpu->arch.fp_state = FP_STATE_HOST_OWNED; vcpu_clear_flag(vcpu, HOST_SVE_ENABLED); if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN) vcpu_set_flag(vcpu, HOST_SVE_ENABLED); - /* - * We don't currently support SME guests but if we leave - * things in streaming mode then when the guest starts running - * FPSIMD or SVE code it may generate SME traps so as a - * special case if we are in streaming mode we force the host - * state to be saved now and exit streaming mode so that we - * don't have to handle any SME traps for valid guest - * operations. Do this for ZA as well for now for simplicity. - */ if (system_supports_sme()) { vcpu_clear_flag(vcpu, HOST_SME_ENABLED); if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN) vcpu_set_flag(vcpu, HOST_SME_ENABLED); + /* + * If PSTATE.SM is enabled then save any pending FP + * state and disable PSTATE.SM. If we leave PSTATE.SM + * enabled and the guest does not enable SME via + * CPACR_EL1.SMEN then operations that should be valid + * may generate SME traps from EL1 to EL1 which we + * can't intercept and which would confuse the guest. + * + * Do the same for PSTATE.ZA in the case where there + * is state in the registers which has not already + * been saved, this is very unlikely to happen. + */ if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) { vcpu->arch.fp_state = FP_STATE_FREE; fpsimd_save_and_flush_cpu_state(); diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 07444fa22888..20280a5233f6 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -590,11 +590,16 @@ static unsigned long num_core_regs(const struct kvm_vcpu *vcpu) return copy_core_reg_indices(vcpu, NULL); } -/** - * ARM64 versions of the TIMER registers, always available on arm64 - */ +static const u64 timer_reg_list[] = { + KVM_REG_ARM_TIMER_CTL, + KVM_REG_ARM_TIMER_CNT, + KVM_REG_ARM_TIMER_CVAL, + KVM_REG_ARM_PTIMER_CTL, + KVM_REG_ARM_PTIMER_CNT, + KVM_REG_ARM_PTIMER_CVAL, +}; -#define NUM_TIMER_REGS 3 +#define NUM_TIMER_REGS ARRAY_SIZE(timer_reg_list) static bool is_timer_reg(u64 index) { @@ -602,6 +607,9 @@ static bool is_timer_reg(u64 index) case KVM_REG_ARM_TIMER_CTL: case KVM_REG_ARM_TIMER_CNT: case KVM_REG_ARM_TIMER_CVAL: + case KVM_REG_ARM_PTIMER_CTL: + case KVM_REG_ARM_PTIMER_CNT: + case KVM_REG_ARM_PTIMER_CVAL: return true; } return false; @@ -609,14 +617,11 @@ static bool is_timer_reg(u64 index) static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) { - if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) - return -EFAULT; - uindices++; - if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) - return -EFAULT; - uindices++; - if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) - return -EFAULT; + for (int i = 0; i < NUM_TIMER_REGS; i++) { + if (put_user(timer_reg_list[i], uindices)) + return -EFAULT; + uindices++; + } return 0; } @@ -957,7 +962,9 @@ int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, switch (attr->group) { case KVM_ARM_VCPU_PMU_V3_CTRL: + mutex_lock(&vcpu->kvm->arch.config_lock); ret = kvm_arm_pmu_v3_set_attr(vcpu, attr); + mutex_unlock(&vcpu->kvm->arch.config_lock); break; case KVM_ARM_VCPU_TIMER_CTRL: ret = kvm_arm_timer_set_attr(vcpu, attr); @@ -1019,8 +1026,8 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, return ret; } -long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, - struct kvm_arm_copy_mte_tags *copy_tags) +int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, + struct kvm_arm_copy_mte_tags *copy_tags) { gpa_t guest_ipa = copy_tags->guest_ipa; size_t length = copy_tags->length; @@ -1041,6 +1048,10 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, if (length & ~PAGE_MASK || guest_ipa & ~PAGE_MASK) return -EINVAL; + /* Lengths above INT_MAX cannot be represented in the return value */ + if (length > INT_MAX) + return -EINVAL; + gfn = gpa_to_gfn(guest_ipa); mutex_lock(&kvm->slots_lock); diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index a798c0b4d717..6dcd6604b6bc 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -36,8 +36,6 @@ static void kvm_handle_guest_serror(struct kvm_vcpu *vcpu, u64 esr) static int handle_hvc(struct kvm_vcpu *vcpu) { - int ret; - trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0), kvm_vcpu_hvc_get_imm(vcpu)); vcpu->stat.hvc_exit_stat++; @@ -52,33 +50,29 @@ static int handle_hvc(struct kvm_vcpu *vcpu) return 1; } - ret = kvm_hvc_call_handler(vcpu); - if (ret < 0) { - vcpu_set_reg(vcpu, 0, ~0UL); - return 1; - } - - return ret; + return kvm_smccc_call_handler(vcpu); } static int handle_smc(struct kvm_vcpu *vcpu) { - int ret; - /* * "If an SMC instruction executed at Non-secure EL1 is * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a * Trap exception, not a Secure Monitor Call exception [...]" * * We need to advance the PC after the trap, as it would - * otherwise return to the same address... - * - * Only handle SMCs from the virtual EL2 with an immediate of zero and - * skip it otherwise. + * otherwise return to the same address. Furthermore, pre-incrementing + * the PC before potentially exiting to userspace maintains the same + * abstraction for both SMCs and HVCs. */ - if (!vcpu_is_el2(vcpu) || kvm_vcpu_hvc_get_imm(vcpu)) { + kvm_incr_pc(vcpu); + + /* + * SMCs with a nonzero immediate are reserved according to DEN0028E 2.9 + * "SMC and HVC immediate value". + */ + if (kvm_vcpu_hvc_get_imm(vcpu)) { vcpu_set_reg(vcpu, 0, ~0UL); - kvm_incr_pc(vcpu); return 1; } @@ -89,13 +83,7 @@ static int handle_smc(struct kvm_vcpu *vcpu) * at Non-secure EL1 is trapped to EL2 if HCR_EL2.TSC==1, rather than * being treated as UNDEFINED. */ - ret = kvm_hvc_call_handler(vcpu); - if (ret < 0) - vcpu_set_reg(vcpu, 0, ~0UL); - - kvm_incr_pc(vcpu); - - return ret; + return kvm_smccc_call_handler(vcpu); } /* diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 07d37ff88a3f..5c15c58f90cc 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -176,9 +177,17 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code) sve_guest = vcpu_has_sve(vcpu); esr_ec = kvm_vcpu_trap_get_class(vcpu); - /* Don't handle SVE traps for non-SVE vcpus here: */ - if (!sve_guest && esr_ec != ESR_ELx_EC_FP_ASIMD) + /* Only handle traps the vCPU can support here: */ + switch (esr_ec) { + case ESR_ELx_EC_FP_ASIMD: + break; + case ESR_ELx_EC_SVE: + if (!sve_guest) + return false; + break; + default: return false; + } /* Valid trap. Switch the context: */ @@ -326,6 +335,55 @@ static bool kvm_hyp_handle_ptrauth(struct kvm_vcpu *vcpu, u64 *exit_code) return true; } +static bool kvm_hyp_handle_cntpct(struct kvm_vcpu *vcpu) +{ + struct arch_timer_context *ctxt; + u32 sysreg; + u64 val; + + /* + * We only get here for 64bit guests, 32bit guests will hit + * the long and winding road all the way to the standard + * handling. Yes, it sucks to be irrelevant. + */ + sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu)); + + switch (sysreg) { + case SYS_CNTPCT_EL0: + case SYS_CNTPCTSS_EL0: + if (vcpu_has_nv(vcpu)) { + if (is_hyp_ctxt(vcpu)) { + ctxt = vcpu_hptimer(vcpu); + break; + } + + /* Check for guest hypervisor trapping */ + val = __vcpu_sys_reg(vcpu, CNTHCTL_EL2); + if (!vcpu_el2_e2h_is_set(vcpu)) + val = (val & CNTHCTL_EL1PCTEN) << 10; + + if (!(val & (CNTHCTL_EL1PCTEN << 10))) + return false; + } + + ctxt = vcpu_ptimer(vcpu); + break; + default: + return false; + } + + val = arch_timer_read_cntpct_el0(); + + if (ctxt->offset.vm_offset) + val -= *kern_hyp_va(ctxt->offset.vm_offset); + if (ctxt->offset.vcpu_offset) + val -= *kern_hyp_va(ctxt->offset.vcpu_offset); + + vcpu_set_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu), val); + __kvm_skip_instr(vcpu); + return true; +} + static bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code) { if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) && @@ -339,6 +397,9 @@ static bool kvm_hyp_handle_sysreg(struct kvm_vcpu *vcpu, u64 *exit_code) if (esr_is_ptrauth_trap(kvm_vcpu_get_esr(vcpu))) return kvm_hyp_handle_ptrauth(vcpu, exit_code); + if (kvm_hyp_handle_cntpct(vcpu)) + return true; + return false; } @@ -351,17 +412,21 @@ static bool kvm_hyp_handle_cp15_32(struct kvm_vcpu *vcpu, u64 *exit_code) return false; } -static bool kvm_hyp_handle_iabt_low(struct kvm_vcpu *vcpu, u64 *exit_code) +static bool kvm_hyp_handle_memory_fault(struct kvm_vcpu *vcpu, u64 *exit_code) { if (!__populate_fault_info(vcpu)) return true; return false; } +static bool kvm_hyp_handle_iabt_low(struct kvm_vcpu *vcpu, u64 *exit_code) + __alias(kvm_hyp_handle_memory_fault); +static bool kvm_hyp_handle_watchpt_low(struct kvm_vcpu *vcpu, u64 *exit_code) + __alias(kvm_hyp_handle_memory_fault); static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code) { - if (!__populate_fault_info(vcpu)) + if (kvm_hyp_handle_memory_fault(vcpu, exit_code)) return true; if (static_branch_unlikely(&vgic_v2_cpuif_trap)) { diff --git a/arch/arm64/kvm/hyp/include/nvhe/gfp.h b/arch/arm64/kvm/hyp/include/nvhe/gfp.h index 0a048dc06a7d..fe5472a184a3 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/gfp.h +++ b/arch/arm64/kvm/hyp/include/nvhe/gfp.h @@ -16,7 +16,7 @@ struct hyp_pool { * API at EL2. */ hyp_spinlock_t lock; - struct list_head free_area[MAX_ORDER]; + struct list_head free_area[MAX_ORDER + 1]; phys_addr_t range_start; phys_addr_t range_end; unsigned short max_order; diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c index 2673bde62fad..d756b939f296 100644 --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c @@ -37,7 +37,6 @@ static void __debug_save_spe(u64 *pmscr_el1) /* Now drain all buffered data to memory */ psb_csync(); - dsb(nsh); } static void __debug_restore_spe(u64 pmscr_el1) @@ -69,7 +68,6 @@ static void __debug_save_trace(u64 *trfcr_el1) isb(); /* Drain the trace buffer to memory */ tsb_csync(); - dsb(nsh); } static void __debug_restore_trace(u64 trfcr_el1) diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 552653fa18be..a8813b212996 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -297,6 +297,13 @@ int __pkvm_prot_finalize(void) params->vttbr = kvm_get_vttbr(mmu); params->vtcr = host_mmu.arch.vtcr; params->hcr_el2 |= HCR_VM; + + /* + * The CMO below not only cleans the updated params to the + * PoC, but also provides the DSB that ensures ongoing + * page-table walks that have started before we trapped to EL2 + * have completed. + */ kvm_flush_dcache_to_poc(params, sizeof(*params)); write_sysreg(params->hcr_el2, hcr_el2); @@ -568,7 +575,7 @@ struct pkvm_mem_donation { struct check_walk_data { enum pkvm_page_state desired; - enum pkvm_page_state (*get_page_state)(kvm_pte_t pte); + enum pkvm_page_state (*get_page_state)(kvm_pte_t pte, u64 addr); }; static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx, @@ -576,10 +583,7 @@ static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx, { struct check_walk_data *d = ctx->arg; - if (kvm_pte_valid(ctx->old) && !addr_is_allowed_memory(kvm_pte_to_phys(ctx->old))) - return -EINVAL; - - return d->get_page_state(ctx->old) == d->desired ? 0 : -EPERM; + return d->get_page_state(ctx->old, ctx->addr) == d->desired ? 0 : -EPERM; } static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size, @@ -594,8 +598,11 @@ static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size, return kvm_pgtable_walk(pgt, addr, size, &walker); } -static enum pkvm_page_state host_get_page_state(kvm_pte_t pte) +static enum pkvm_page_state host_get_page_state(kvm_pte_t pte, u64 addr) { + if (!addr_is_allowed_memory(addr)) + return PKVM_NOPAGE; + if (!kvm_pte_valid(pte) && pte) return PKVM_NOPAGE; @@ -702,7 +709,7 @@ static int host_complete_donation(u64 addr, const struct pkvm_mem_transition *tx return host_stage2_set_owner_locked(addr, size, host_id); } -static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte) +static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte, u64 addr) { if (!kvm_pte_valid(pte)) return PKVM_NOPAGE; diff --git a/arch/arm64/kvm/hyp/nvhe/page_alloc.c b/arch/arm64/kvm/hyp/nvhe/page_alloc.c index 803ba3222e75..b1e392186a0f 100644 --- a/arch/arm64/kvm/hyp/nvhe/page_alloc.c +++ b/arch/arm64/kvm/hyp/nvhe/page_alloc.c @@ -110,7 +110,7 @@ static void __hyp_attach_page(struct hyp_pool *pool, * after coalescing, so make sure to mark it HYP_NO_ORDER proactively. */ p->order = HYP_NO_ORDER; - for (; (order + 1) < pool->max_order; order++) { + for (; (order + 1) <= pool->max_order; order++) { buddy = __find_buddy_avail(pool, p, order); if (!buddy) break; @@ -203,9 +203,9 @@ void *hyp_alloc_pages(struct hyp_pool *pool, unsigned short order) hyp_spin_lock(&pool->lock); /* Look for a high-enough-order page */ - while (i < pool->max_order && list_empty(&pool->free_area[i])) + while (i <= pool->max_order && list_empty(&pool->free_area[i])) i++; - if (i >= pool->max_order) { + if (i > pool->max_order) { hyp_spin_unlock(&pool->lock); return NULL; } @@ -228,8 +228,8 @@ int hyp_pool_init(struct hyp_pool *pool, u64 pfn, unsigned int nr_pages, int i; hyp_spin_lock_init(&pool->lock); - pool->max_order = min(MAX_ORDER, get_order((nr_pages + 1) << PAGE_SHIFT)); - for (i = 0; i < pool->max_order; i++) + pool->max_order = min(MAX_ORDER, get_order(nr_pages << PAGE_SHIFT)); + for (i = 0; i <= pool->max_order; i++) INIT_LIST_HEAD(&pool->free_area[i]); pool->range_start = phys; pool->range_end = phys + (nr_pages << PAGE_SHIFT); diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index c2cb46ca4fb6..77791495c995 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -186,6 +186,7 @@ static const exit_handler_fn hyp_exit_handlers[] = { [ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd, [ESR_ELx_EC_IABT_LOW] = kvm_hyp_handle_iabt_low, [ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low, + [ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low, [ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth, }; @@ -196,6 +197,7 @@ static const exit_handler_fn pvm_exit_handlers[] = { [ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd, [ESR_ELx_EC_IABT_LOW] = kvm_hyp_handle_iabt_low, [ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low, + [ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low, [ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth, }; @@ -272,6 +274,17 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) */ __debug_save_host_buffers_nvhe(vcpu); + /* + * We're about to restore some new MMU state. Make sure + * ongoing page-table walks that have started before we + * trapped to EL2 have completed. This also synchronises the + * above disabling of SPE and TRBE. + * + * See DDI0487I.a D8.1.5 "Out-of-context translation regimes", + * rule R_LFHQG and subsequent information statements. + */ + dsb(nsh); + __kvm_adjust_pc(vcpu); /* @@ -306,6 +319,13 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) __timer_disable_traps(vcpu); __hyp_vgic_save_state(vcpu); + /* + * Same thing as before the guest run: we're about to switch + * the MMU context, so let's make sure we don't have any + * ongoing EL1&0 translations. + */ + dsb(nsh); + __deactivate_traps(vcpu); __load_host_stage2(); diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c index 9072e71693ba..b185ac0dbd47 100644 --- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c @@ -9,6 +9,7 @@ #include #include +#include void __kvm_timer_set_cntvoff(u64 cntvoff) { @@ -35,14 +36,19 @@ void __timer_disable_traps(struct kvm_vcpu *vcpu) */ void __timer_enable_traps(struct kvm_vcpu *vcpu) { - u64 val; + u64 clr = 0, set = 0; /* * Disallow physical timer access for the guest - * Physical counter access is allowed + * Physical counter access is allowed if no offset is enforced + * or running protected (we don't offset anything in this case). */ - val = read_sysreg(cnthctl_el2); - val &= ~CNTHCTL_EL1PCEN; - val |= CNTHCTL_EL1PCTEN; - write_sysreg(val, cnthctl_el2); + clr = CNTHCTL_EL1PCEN; + if (is_protected_kvm_enabled() || + !kern_hyp_va(vcpu->kvm)->arch.timer_data.poffset) + set |= CNTHCTL_EL1PCTEN; + else + clr |= CNTHCTL_EL1PCTEN; + + sysreg_clear_set(cnthctl_el2, clr, set); } diff --git a/arch/arm64/kvm/hyp/nvhe/tlb.c b/arch/arm64/kvm/hyp/nvhe/tlb.c index d296d617f589..978179133f4b 100644 --- a/arch/arm64/kvm/hyp/nvhe/tlb.c +++ b/arch/arm64/kvm/hyp/nvhe/tlb.c @@ -15,8 +15,31 @@ struct tlb_inv_context { }; static void __tlb_switch_to_guest(struct kvm_s2_mmu *mmu, - struct tlb_inv_context *cxt) + struct tlb_inv_context *cxt, + bool nsh) { + /* + * We have two requirements: + * + * - ensure that the page table updates are visible to all + * CPUs, for which a dsb(DOMAIN-st) is what we need, DOMAIN + * being either ish or nsh, depending on the invalidation + * type. + * + * - complete any speculative page table walk started before + * we trapped to EL2 so that we can mess with the MM + * registers out of context, for which dsb(nsh) is enough + * + * The composition of these two barriers is a dsb(DOMAIN), and + * the 'nsh' parameter tracks the distinction between + * Inner-Shareable and Non-Shareable, as specified by the + * callers. + */ + if (nsh) + dsb(nsh); + else + dsb(ish); + if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) { u64 val; @@ -60,10 +83,8 @@ void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, { struct tlb_inv_context cxt; - dsb(ishst); - /* Switch to requested VMID */ - __tlb_switch_to_guest(mmu, &cxt); + __tlb_switch_to_guest(mmu, &cxt, false); /* * We could do so much better if we had the VA as well. @@ -113,10 +134,8 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu) { struct tlb_inv_context cxt; - dsb(ishst); - /* Switch to requested VMID */ - __tlb_switch_to_guest(mmu, &cxt); + __tlb_switch_to_guest(mmu, &cxt, false); __tlbi(vmalls12e1is); dsb(ish); @@ -130,7 +149,7 @@ void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu) struct tlb_inv_context cxt; /* Switch to requested VMID */ - __tlb_switch_to_guest(mmu, &cxt); + __tlb_switch_to_guest(mmu, &cxt, false); __tlbi(vmalle1); asm volatile("ic iallu"); @@ -142,7 +161,8 @@ void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu) void __kvm_flush_vm_context(void) { - dsb(ishst); + /* Same remark as in __tlb_switch_to_guest() */ + dsb(ish); __tlbi(alle1is); /* diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index 3d61bd3e591d..95dae02ccc2e 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -58,8 +58,9 @@ struct kvm_pgtable_walk_data { struct kvm_pgtable_walker *walker; + const u64 start; u64 addr; - u64 end; + const u64 end; }; static bool kvm_phys_is_valid(u64 phys) @@ -201,20 +202,33 @@ static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data, .old = READ_ONCE(*ptep), .arg = data->walker->arg, .mm_ops = mm_ops, + .start = data->start, .addr = data->addr, .end = data->end, .level = level, .flags = flags, }; int ret = 0; + bool reload = false; kvm_pteref_t childp; bool table = kvm_pte_table(ctx.old, level); - if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE)) + if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE)) { ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_TABLE_PRE); + reload = true; + } if (!table && (ctx.flags & KVM_PGTABLE_WALK_LEAF)) { ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_LEAF); + reload = true; + } + + /* + * Reload the page table after invoking the walker callback for leaf + * entries or after pre-order traversal, to allow the walker to descend + * into a newly installed or replaced table. + */ + if (reload) { ctx.old = READ_ONCE(*ptep); table = kvm_pte_table(ctx.old, level); } @@ -293,6 +307,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size, struct kvm_pgtable_walker *walker) { struct kvm_pgtable_walk_data walk_data = { + .start = ALIGN_DOWN(addr, PAGE_SIZE), .addr = ALIGN_DOWN(addr, PAGE_SIZE), .end = PAGE_ALIGN(walk_data.addr + size), .walker = walker, @@ -349,7 +364,7 @@ int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr, } struct hyp_map_data { - u64 phys; + const u64 phys; kvm_pte_t attr; }; @@ -407,13 +422,12 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte) static bool hyp_map_walker_try_leaf(const struct kvm_pgtable_visit_ctx *ctx, struct hyp_map_data *data) { + u64 phys = data->phys + (ctx->addr - ctx->start); kvm_pte_t new; - u64 granule = kvm_granule_size(ctx->level), phys = data->phys; if (!kvm_block_mapping_supported(ctx, phys)) return false; - data->phys += granule; new = kvm_init_valid_leaf_pte(phys, data->attr, ctx->level); if (ctx->old == new) return true; @@ -576,7 +590,7 @@ void kvm_pgtable_hyp_destroy(struct kvm_pgtable *pgt) } struct stage2_map_data { - u64 phys; + const u64 phys; kvm_pte_t attr; u8 owner_id; @@ -794,20 +808,43 @@ static bool stage2_pte_executable(kvm_pte_t pte) return !(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN); } +static u64 stage2_map_walker_phys_addr(const struct kvm_pgtable_visit_ctx *ctx, + const struct stage2_map_data *data) +{ + u64 phys = data->phys; + + /* + * Stage-2 walks to update ownership data are communicated to the map + * walker using an invalid PA. Avoid offsetting an already invalid PA, + * which could overflow and make the address valid again. + */ + if (!kvm_phys_is_valid(phys)) + return phys; + + /* + * Otherwise, work out the correct PA based on how far the walk has + * gotten. + */ + return phys + (ctx->addr - ctx->start); +} + static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx, struct stage2_map_data *data) { + u64 phys = stage2_map_walker_phys_addr(ctx, data); + if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1))) return false; - return kvm_block_mapping_supported(ctx, data->phys); + return kvm_block_mapping_supported(ctx, phys); } static int stage2_map_walker_try_leaf(const struct kvm_pgtable_visit_ctx *ctx, struct stage2_map_data *data) { kvm_pte_t new; - u64 granule = kvm_granule_size(ctx->level), phys = data->phys; + u64 phys = stage2_map_walker_phys_addr(ctx, data); + u64 granule = kvm_granule_size(ctx->level); struct kvm_pgtable *pgt = data->mmu->pgt; struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops; @@ -841,8 +878,6 @@ static int stage2_map_walker_try_leaf(const struct kvm_pgtable_visit_ctx *ctx, stage2_make_pte(ctx, new); - if (kvm_phys_is_valid(phys)) - data->phys += granule; return 0; } @@ -1297,4 +1332,7 @@ void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pg }; WARN_ON(__kvm_pgtable_walk(&data, mm_ops, ptep, level + 1)); + + WARN_ON(mm_ops->page_count(pgtable) != 1); + mm_ops->put_page(pgtable); } diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index cd3f3117bf16..7a1aa511e7da 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -110,6 +110,7 @@ static const exit_handler_fn hyp_exit_handlers[] = { [ESR_ELx_EC_FP_ASIMD] = kvm_hyp_handle_fpsimd, [ESR_ELx_EC_IABT_LOW] = kvm_hyp_handle_iabt_low, [ESR_ELx_EC_DABT_LOW] = kvm_hyp_handle_dabt_low, + [ESR_ELx_EC_WATCHPT_LOW] = kvm_hyp_handle_watchpt_low, [ESR_ELx_EC_PAC] = kvm_hyp_handle_ptrauth, }; @@ -227,11 +228,10 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) /* * When we exit from the guest we change a number of CPU configuration - * parameters, such as traps. Make sure these changes take effect - * before running the host or additional guests. + * parameters, such as traps. We rely on the isb() in kvm_call_hyp*() + * to make sure these changes take effect before running the host or + * additional guests. */ - isb(); - return ret; } diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c index 7b44f6b3b547..b35a178e7e0d 100644 --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and @@ -69,6 +70,17 @@ void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu) host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; __sysreg_save_user_state(host_ctxt); + /* + * When running a normal EL1 guest, we only load a new vcpu + * after a context switch, which imvolves a DSB, so all + * speculative EL1&0 walks will have already completed. + * If running NV, the vcpu may transition between vEL1 and + * vEL2 without a context switch, so make sure we complete + * those walks before loading a new context. + */ + if (vcpu_has_nv(vcpu)) + dsb(nsh); + /* * Load guest EL1 and user state * diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index c4b4678bc4a4..7fb4df0456de 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -47,7 +47,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset; break; case KVM_PTP_PHYS_COUNTER: - cycles = systime_snapshot.cycles; + cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.poffset; break; default: return; @@ -65,7 +65,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) val[3] = lower_32_bits(cycles); } -static bool kvm_hvc_call_default_allowed(u32 func_id) +static bool kvm_smccc_default_allowed(u32 func_id) { switch (func_id) { /* @@ -93,7 +93,7 @@ static bool kvm_hvc_call_default_allowed(u32 func_id) } } -static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) +static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id) { struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; @@ -117,20 +117,161 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, &smccc_feat->vendor_hyp_bmap); default: - return kvm_hvc_call_default_allowed(func_id); + return false; } } -int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) +#define SMC32_ARCH_RANGE_BEGIN ARM_SMCCC_VERSION_FUNC_ID +#define SMC32_ARCH_RANGE_END ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, ARM_SMCCC_FUNC_MASK) + +#define SMC64_ARCH_RANGE_BEGIN ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + 0, 0) +#define SMC64_ARCH_RANGE_END ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + 0, ARM_SMCCC_FUNC_MASK) + +static void init_smccc_filter(struct kvm *kvm) +{ + int r; + + mt_init(&kvm->arch.smccc_filter); + + /* + * Prevent userspace from handling any SMCCC calls in the architecture + * range, avoiding the risk of misrepresenting Spectre mitigation status + * to the guest. + */ + r = mtree_insert_range(&kvm->arch.smccc_filter, + SMC32_ARCH_RANGE_BEGIN, SMC32_ARCH_RANGE_END, + xa_mk_value(KVM_SMCCC_FILTER_HANDLE), + GFP_KERNEL_ACCOUNT); + WARN_ON_ONCE(r); + + r = mtree_insert_range(&kvm->arch.smccc_filter, + SMC64_ARCH_RANGE_BEGIN, SMC64_ARCH_RANGE_END, + xa_mk_value(KVM_SMCCC_FILTER_HANDLE), + GFP_KERNEL_ACCOUNT); + WARN_ON_ONCE(r); + +} + +static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user *uaddr) +{ + const void *zero_page = page_to_virt(ZERO_PAGE(0)); + struct kvm_smccc_filter filter; + u32 start, end; + int r; + + if (copy_from_user(&filter, uaddr, sizeof(filter))) + return -EFAULT; + + if (memcmp(filter.pad, zero_page, sizeof(filter.pad))) + return -EINVAL; + + start = filter.base; + end = start + filter.nr_functions - 1; + + if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS) + return -EINVAL; + + mutex_lock(&kvm->arch.config_lock); + + if (kvm_vm_has_ran_once(kvm)) { + r = -EBUSY; + goto out_unlock; + } + + r = mtree_insert_range(&kvm->arch.smccc_filter, start, end, + xa_mk_value(filter.action), GFP_KERNEL_ACCOUNT); + if (r) + goto out_unlock; + + set_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags); + +out_unlock: + mutex_unlock(&kvm->arch.config_lock); + return r; +} + +static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) +{ + unsigned long idx = func_id; + void *val; + + if (!test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags)) + return KVM_SMCCC_FILTER_HANDLE; + + /* + * But where's the error handling, you say? + * + * mt_find() returns NULL if no entry was found, which just so happens + * to match KVM_SMCCC_FILTER_HANDLE. + */ + val = mt_find(&kvm->arch.smccc_filter, &idx, idx); + return xa_to_value(val); +} + +static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id) +{ + /* + * Intervening actions in the SMCCC filter take precedence over the + * pseudo-firmware register bitmaps. + */ + u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); + if (action != KVM_SMCCC_FILTER_HANDLE) + return action; + + if (kvm_smccc_test_fw_bmap(vcpu, func_id) || + kvm_smccc_default_allowed(func_id)) + return KVM_SMCCC_FILTER_HANDLE; + + return KVM_SMCCC_FILTER_DENY; +} + +static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id) +{ + u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu)); + struct kvm_run *run = vcpu->run; + u64 flags = 0; + + if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64) + flags |= KVM_HYPERCALL_EXIT_SMC; + + if (!kvm_vcpu_trap_il_is32bit(vcpu)) + flags |= KVM_HYPERCALL_EXIT_16BIT; + + run->exit_reason = KVM_EXIT_HYPERCALL; + run->hypercall = (typeof(run->hypercall)) { + .nr = func_id, + .flags = flags, + }; +} + +int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) { struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; u32 func_id = smccc_get_function(vcpu); u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; u32 feature; + u8 action; gpa_t gpa; - if (!kvm_hvc_call_allowed(vcpu, func_id)) + action = kvm_smccc_get_action(vcpu, func_id); + switch (action) { + case KVM_SMCCC_FILTER_HANDLE: + break; + case KVM_SMCCC_FILTER_DENY: goto out; + case KVM_SMCCC_FILTER_FWD_TO_USER: + kvm_prepare_hypercall_exit(vcpu, func_id); + return 0; + default: + WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action); + goto out; + } switch (func_id) { case ARM_SMCCC_VERSION_FUNC_ID: @@ -245,6 +386,13 @@ void kvm_arm_init_hypercalls(struct kvm *kvm) smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; + + init_smccc_filter(kvm); +} + +void kvm_arm_teardown_hypercalls(struct kvm *kvm) +{ + mtree_destroy(&kvm->arch.smccc_filter); } int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) @@ -377,17 +525,16 @@ static int kvm_arm_set_fw_reg_bmap(struct kvm_vcpu *vcpu, u64 reg_id, u64 val) if (val & ~fw_reg_features) return -EINVAL; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); - if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) && - val != *fw_reg_bmap) { + if (kvm_vm_has_ran_once(kvm) && val != *fw_reg_bmap) { ret = -EBUSY; goto out; } WRITE_ONCE(*fw_reg_bmap, val); out: - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); return ret; } @@ -481,3 +628,25 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) return -EINVAL; } + +int kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->attr) { + case KVM_ARM_VM_SMCCC_FILTER: + return 0; + default: + return -ENXIO; + } +} + +int kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + void __user *uaddr = (void __user *)attr->addr; + + switch (attr->attr) { + case KVM_ARM_VM_SMCCC_FILTER: + return kvm_smccc_set_filter(kvm, uaddr); + default: + return -ENXIO; + } +} diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 64c3aec0d937..0bd93a5f21ce 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -204,7 +204,7 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu) * Size Fault at level 0, as if exceeding PARange. * * Non-LPAE guests will only get the external abort, as there - * is no way to to describe the ASF. + * is no way to describe the ASF. */ if (vcpu_el1_is_32bit(vcpu) && !(vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE)) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 5eca0cdd961d..491ca7eb2a4c 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -694,45 +694,23 @@ out_unlock: static struct arm_pmu *kvm_pmu_probe_armpmu(void) { - struct perf_event_attr attr = { }; - struct perf_event *event; - struct arm_pmu *pmu = NULL; + struct arm_pmu *tmp, *pmu = NULL; + struct arm_pmu_entry *entry; + int cpu; - /* - * Create a dummy event that only counts user cycles. As we'll never - * leave this function with the event being live, it will never - * count anything. But it allows us to probe some of the PMU - * details. Yes, this is terrible. - */ - attr.type = PERF_TYPE_RAW; - attr.size = sizeof(attr); - attr.pinned = 1; - attr.disabled = 0; - attr.exclude_user = 0; - attr.exclude_kernel = 1; - attr.exclude_hv = 1; - attr.exclude_host = 1; - attr.config = ARMV8_PMUV3_PERFCTR_CPU_CYCLES; - attr.sample_period = GENMASK(63, 0); + mutex_lock(&arm_pmus_lock); - event = perf_event_create_kernel_counter(&attr, -1, current, - kvm_pmu_perf_overflow, &attr); + cpu = smp_processor_id(); + list_for_each_entry(entry, &arm_pmus, entry) { + tmp = entry->arm_pmu; - if (IS_ERR(event)) { - pr_err_once("kvm: pmu event creation failed %ld\n", - PTR_ERR(event)); - return NULL; + if (cpumask_test_cpu(cpu, &tmp->supported_cpus)) { + pmu = tmp; + break; + } } - if (event->pmu) { - pmu = to_arm_pmu(event->pmu); - if (pmu->pmuver == ID_AA64DFR0_EL1_PMUVer_NI || - pmu->pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF) - pmu = NULL; - } - - perf_event_disable(event); - perf_event_release_kernel(event); + mutex_unlock(&arm_pmus_lock); return pmu; } @@ -876,13 +854,13 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id) struct arm_pmu *arm_pmu; int ret = -ENXIO; - mutex_lock(&kvm->lock); + lockdep_assert_held(&kvm->arch.config_lock); mutex_lock(&arm_pmus_lock); list_for_each_entry(entry, &arm_pmus, entry) { arm_pmu = entry->arm_pmu; if (arm_pmu->pmu.type == pmu_id) { - if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) || + if (kvm_vm_has_ran_once(kvm) || (kvm->arch.pmu_filter && kvm->arch.arm_pmu != arm_pmu)) { ret = -EBUSY; break; @@ -896,7 +874,6 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id) } mutex_unlock(&arm_pmus_lock); - mutex_unlock(&kvm->lock); return ret; } @@ -904,22 +881,30 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { struct kvm *kvm = vcpu->kvm; + lockdep_assert_held(&kvm->arch.config_lock); + if (!kvm_vcpu_has_pmu(vcpu)) return -ENODEV; if (vcpu->arch.pmu.created) return -EBUSY; - mutex_lock(&kvm->lock); if (!kvm->arch.arm_pmu) { - /* No PMU set, get the default one */ + /* + * No PMU set, get the default one. + * + * The observant among you will notice that the supported_cpus + * mask does not get updated for the default PMU even though it + * is quite possible the selected instance supports only a + * subset of cores in the system. This is intentional, and + * upholds the preexisting behavior on heterogeneous systems + * where vCPUs can be scheduled on any core but the guest + * counters could stop working. + */ kvm->arch.arm_pmu = kvm_pmu_probe_armpmu(); - if (!kvm->arch.arm_pmu) { - mutex_unlock(&kvm->lock); + if (!kvm->arch.arm_pmu) return -ENODEV; - } } - mutex_unlock(&kvm->lock); switch (attr->attr) { case KVM_ARM_VCPU_PMU_V3_IRQ: { @@ -963,19 +948,13 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) filter.action != KVM_PMU_EVENT_DENY)) return -EINVAL; - mutex_lock(&kvm->lock); - - if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) { - mutex_unlock(&kvm->lock); + if (kvm_vm_has_ran_once(kvm)) return -EBUSY; - } if (!kvm->arch.pmu_filter) { kvm->arch.pmu_filter = bitmap_alloc(nr_events, GFP_KERNEL_ACCOUNT); - if (!kvm->arch.pmu_filter) { - mutex_unlock(&kvm->lock); + if (!kvm->arch.pmu_filter) return -ENOMEM; - } /* * The default depends on the first applied filter. @@ -994,8 +973,6 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) else bitmap_clear(kvm->arch.pmu_filter, filter.base_event, filter.nevents); - mutex_unlock(&kvm->lock); - return 0; } case KVM_ARM_VCPU_PMU_V3_SET_PMU: { diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c index 7fbc4c1b9df0..1f69b667332b 100644 --- a/arch/arm64/kvm/psci.c +++ b/arch/arm64/kvm/psci.c @@ -62,6 +62,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) struct vcpu_reset_state *reset_state; struct kvm *kvm = source_vcpu->kvm; struct kvm_vcpu *vcpu = NULL; + int ret = PSCI_RET_SUCCESS; unsigned long cpu_id; cpu_id = smccc_get_arg1(source_vcpu); @@ -76,11 +77,15 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) */ if (!vcpu) return PSCI_RET_INVALID_PARAMS; + + spin_lock(&vcpu->arch.mp_state_lock); if (!kvm_arm_vcpu_stopped(vcpu)) { if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1) - return PSCI_RET_ALREADY_ON; + ret = PSCI_RET_ALREADY_ON; else - return PSCI_RET_INVALID_PARAMS; + ret = PSCI_RET_INVALID_PARAMS; + + goto out_unlock; } reset_state = &vcpu->arch.reset_state; @@ -96,7 +101,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) */ reset_state->r0 = smccc_get_arg3(source_vcpu); - WRITE_ONCE(reset_state->reset, true); + reset_state->reset = true; kvm_make_request(KVM_REQ_VCPU_RESET, vcpu); /* @@ -105,10 +110,12 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) */ smp_wmb(); - vcpu->arch.mp_state.mp_state = KVM_MP_STATE_RUNNABLE; + WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE); kvm_vcpu_wake_up(vcpu); - return PSCI_RET_SUCCESS; +out_unlock: + spin_unlock(&vcpu->arch.mp_state_lock); + return ret; } static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) @@ -168,8 +175,11 @@ static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type, u64 flags) * after this call is handled and before the VCPUs have been * re-initialized. */ - kvm_for_each_vcpu(i, tmp, vcpu->kvm) - tmp->arch.mp_state.mp_state = KVM_MP_STATE_STOPPED; + kvm_for_each_vcpu(i, tmp, vcpu->kvm) { + spin_lock(&tmp->arch.mp_state_lock); + WRITE_ONCE(tmp->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED); + spin_unlock(&tmp->arch.mp_state_lock); + } kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP); memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); @@ -229,7 +239,6 @@ static unsigned long kvm_psci_check_allowed_function(struct kvm_vcpu *vcpu, u32 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) { - struct kvm *kvm = vcpu->kvm; u32 psci_fn = smccc_get_function(vcpu); unsigned long val; int ret = 1; @@ -254,9 +263,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) kvm_psci_narrow_to_32bit(vcpu); fallthrough; case PSCI_0_2_FN64_CPU_ON: - mutex_lock(&kvm->lock); val = kvm_psci_vcpu_on(vcpu); - mutex_unlock(&kvm->lock); break; case PSCI_0_2_FN_AFFINITY_INFO: kvm_psci_narrow_to_32bit(vcpu); @@ -395,7 +402,6 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { - struct kvm *kvm = vcpu->kvm; u32 psci_fn = smccc_get_function(vcpu); unsigned long val; @@ -405,9 +411,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) val = PSCI_RET_SUCCESS; break; case KVM_PSCI_FN_CPU_ON: - mutex_lock(&kvm->lock); val = kvm_psci_vcpu_on(vcpu); - mutex_unlock(&kvm->lock); break; default: val = PSCI_RET_NOT_SUPPORTED; @@ -435,6 +439,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) int kvm_psci_call(struct kvm_vcpu *vcpu) { u32 psci_fn = smccc_get_function(vcpu); + int version = kvm_psci_version(vcpu); unsigned long val; val = kvm_psci_check_allowed_function(vcpu, psci_fn); @@ -443,7 +448,7 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) return 1; } - switch (kvm_psci_version(vcpu)) { + switch (version) { case KVM_ARM_PSCI_1_1: return kvm_psci_1_x_call(vcpu, 1); case KVM_ARM_PSCI_1_0: @@ -453,6 +458,8 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) case KVM_ARM_PSCI_0_1: return kvm_psci_0_1_call(vcpu); default: - return -EINVAL; + WARN_ONCE(1, "Unknown PSCI version %d", version); + smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0); + return 1; } } diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 49a3257dec46..b5dee8e57e77 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -205,7 +205,7 @@ static int kvm_set_vm_width(struct kvm_vcpu *vcpu) is32bit = vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT); - lockdep_assert_held(&kvm->lock); + lockdep_assert_held(&kvm->arch.config_lock); if (test_bit(KVM_ARCH_FLAG_REG_WIDTH_CONFIGURED, &kvm->arch.flags)) { /* @@ -262,17 +262,18 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) bool loaded; u32 pstate; - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->arch.config_lock); ret = kvm_set_vm_width(vcpu); - if (!ret) { - reset_state = vcpu->arch.reset_state; - WRITE_ONCE(vcpu->arch.reset_state.reset, false); - } - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); if (ret) return ret; + spin_lock(&vcpu->arch.mp_state_lock); + reset_state = vcpu->arch.reset_state; + vcpu->arch.reset_state.reset = false; + spin_unlock(&vcpu->arch.mp_state_lock); + /* Reset PMU outside of the non-preemptible section */ kvm_pmu_vcpu_reset(vcpu); diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 34688918c811..753aa7418149 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -211,6 +211,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu, return true; } +static bool access_dcgsw(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + if (!kvm_has_mte(vcpu->kvm)) { + kvm_inject_undefined(vcpu); + return false; + } + + /* Treat MTE S/W ops as we treat the classic ones: with contempt */ + return access_dcsw(vcpu, p, r); +} + static void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift) { switch (r->aarch32_map) { @@ -1154,6 +1167,12 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, tmr = TIMER_PTIMER; treg = TIMER_REG_CVAL; break; + case SYS_CNTPCT_EL0: + case SYS_CNTPCTSS_EL0: + case SYS_AARCH32_CNTPCT: + tmr = TIMER_PTIMER; + treg = TIMER_REG_CNT; + break; default: print_sys_reg_msg(p, "%s", "Unhandled trapped timer register"); kvm_inject_undefined(vcpu); @@ -1750,8 +1769,14 @@ static bool access_spsr(struct kvm_vcpu *vcpu, */ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_DC_ISW), access_dcsw }, + { SYS_DESC(SYS_DC_IGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_IGDSW), access_dcgsw }, { SYS_DESC(SYS_DC_CSW), access_dcsw }, + { SYS_DESC(SYS_DC_CGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CGDSW), access_dcgsw }, { SYS_DESC(SYS_DC_CISW), access_dcsw }, + { SYS_DESC(SYS_DC_CIGSW), access_dcgsw }, + { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw }, DBG_BCR_BVR_WCR_WVR_EL1(0), DBG_BCR_BVR_WCR_WVR_EL1(1), @@ -2091,6 +2116,8 @@ static const struct sys_reg_desc sys_reg_descs[] = { AMU_AMEVTYPER1_EL0(14), AMU_AMEVTYPER1_EL0(15), + { SYS_DESC(SYS_CNTPCT_EL0), access_arch_timer }, + { SYS_DESC(SYS_CNTPCTSS_EL0), access_arch_timer }, { SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer }, { SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer }, { SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer }, @@ -2541,10 +2568,12 @@ static const struct sys_reg_desc cp15_64_regs[] = { { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR0_EL1 }, { CP15_PMU_SYS_REG(DIRECT, 0, 0, 9, 0), .access = access_pmu_evcntr }, { Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI1R */ + { SYS_DESC(SYS_AARCH32_CNTPCT), access_arch_timer }, { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR1_EL1 }, { Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */ { Op1( 2), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI0R */ { SYS_DESC(SYS_AARCH32_CNTP_CVAL), access_arch_timer }, + { SYS_DESC(SYS_AARCH32_CNTPCTSS), access_arch_timer }, }; static bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n, diff --git a/arch/arm64/kvm/trace_arm.h b/arch/arm64/kvm/trace_arm.h index f3e46a976125..6ce5c025218d 100644 --- a/arch/arm64/kvm/trace_arm.h +++ b/arch/arm64/kvm/trace_arm.h @@ -206,6 +206,7 @@ TRACE_EVENT(kvm_get_timer_map, __field( unsigned long, vcpu_id ) __field( int, direct_vtimer ) __field( int, direct_ptimer ) + __field( int, emul_vtimer ) __field( int, emul_ptimer ) ), @@ -214,14 +215,17 @@ TRACE_EVENT(kvm_get_timer_map, __entry->direct_vtimer = arch_timer_ctx_index(map->direct_vtimer); __entry->direct_ptimer = (map->direct_ptimer) ? arch_timer_ctx_index(map->direct_ptimer) : -1; + __entry->emul_vtimer = + (map->emul_vtimer) ? arch_timer_ctx_index(map->emul_vtimer) : -1; __entry->emul_ptimer = (map->emul_ptimer) ? arch_timer_ctx_index(map->emul_ptimer) : -1; ), - TP_printk("VCPU: %ld, dv: %d, dp: %d, ep: %d", + TP_printk("VCPU: %ld, dv: %d, dp: %d, ev: %d, ep: %d", __entry->vcpu_id, __entry->direct_vtimer, __entry->direct_ptimer, + __entry->emul_vtimer, __entry->emul_ptimer) ); diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c index 78cde687383c..07aa0437125a 100644 --- a/arch/arm64/kvm/vgic/vgic-debug.c +++ b/arch/arm64/kvm/vgic/vgic-debug.c @@ -85,7 +85,7 @@ static void *vgic_debug_start(struct seq_file *s, loff_t *pos) struct kvm *kvm = s->private; struct vgic_state_iter *iter; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); iter = kvm->arch.vgic.iter; if (iter) { iter = ERR_PTR(-EBUSY); @@ -104,7 +104,7 @@ static void *vgic_debug_start(struct seq_file *s, loff_t *pos) if (end_of_vgic(iter)) iter = NULL; out: - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); return iter; } @@ -132,12 +132,12 @@ static void vgic_debug_stop(struct seq_file *s, void *v) if (IS_ERR(v)) return; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); iter = kvm->arch.vgic.iter; kfree(iter->lpi_array); kfree(iter); kvm->arch.vgic.iter = NULL; - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); } static void print_dist_state(struct seq_file *s, struct vgic_dist *dist) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index cd134db41a57..6eafc2c45cfc 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -74,9 +74,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) unsigned long i; int ret; - if (irqchip_in_kernel(kvm)) - return -EEXIST; - /* * This function is also called by the KVM_CREATE_IRQCHIP handler, * which had no chance yet to check the availability of the GICv2 @@ -87,10 +84,20 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) !kvm_vgic_global_state.can_emulate_gicv2) return -ENODEV; + /* Must be held to avoid race with vCPU creation */ + lockdep_assert_held(&kvm->lock); + ret = -EBUSY; if (!lock_all_vcpus(kvm)) return ret; + mutex_lock(&kvm->arch.config_lock); + + if (irqchip_in_kernel(kvm)) { + ret = -EEXIST; + goto out_unlock; + } + kvm_for_each_vcpu(i, vcpu, kvm) { if (vcpu_has_run_once(vcpu)) goto out_unlock; @@ -118,6 +125,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions); out_unlock: + mutex_unlock(&kvm->arch.config_lock); unlock_all_vcpus(kvm); return ret; } @@ -227,9 +235,9 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) * KVM io device for the redistributor that belongs to this VCPU. */ if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->slots_lock); ret = vgic_register_redist_iodev(vcpu); - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->slots_lock); } return ret; } @@ -250,7 +258,6 @@ static void kvm_vgic_vcpu_enable(struct kvm_vcpu *vcpu) * The function is generally called when nr_spis has been explicitly set * by the guest through the KVM DEVICE API. If not nr_spis is set to 256. * vgic_initialized() returns true when this function has succeeded. - * Must be called with kvm->lock held! */ int vgic_init(struct kvm *kvm) { @@ -259,6 +266,8 @@ int vgic_init(struct kvm *kvm) int ret = 0, i; unsigned long idx; + lockdep_assert_held(&kvm->arch.config_lock); + if (vgic_initialized(kvm)) return 0; @@ -373,12 +382,13 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF; } -/* To be called with kvm->lock held */ static void __kvm_vgic_destroy(struct kvm *kvm) { struct kvm_vcpu *vcpu; unsigned long i; + lockdep_assert_held(&kvm->arch.config_lock); + vgic_debug_destroy(kvm); kvm_for_each_vcpu(i, vcpu, kvm) @@ -389,14 +399,14 @@ static void __kvm_vgic_destroy(struct kvm *kvm) void kvm_vgic_destroy(struct kvm *kvm) { - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); __kvm_vgic_destroy(kvm); - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); } /** * vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest - * is a GICv2. A GICv3 must be explicitly initialized by the guest using the + * is a GICv2. A GICv3 must be explicitly initialized by userspace using the * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group. * @kvm: kvm struct pointer */ @@ -414,9 +424,9 @@ int vgic_lazy_init(struct kvm *kvm) if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2) return -EBUSY; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); ret = vgic_init(kvm); - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); } return ret; @@ -436,12 +446,14 @@ int vgic_lazy_init(struct kvm *kvm) int kvm_vgic_map_resources(struct kvm *kvm) { struct vgic_dist *dist = &kvm->arch.vgic; + gpa_t dist_base; int ret = 0; if (likely(vgic_ready(kvm))) return 0; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->slots_lock); + mutex_lock(&kvm->arch.config_lock); if (vgic_ready(kvm)) goto out; @@ -453,13 +465,26 @@ int kvm_vgic_map_resources(struct kvm *kvm) else ret = vgic_v3_map_resources(kvm); - if (ret) + if (ret) { __kvm_vgic_destroy(kvm); - else - dist->ready = true; + goto out; + } + dist->ready = true; + dist_base = dist->vgic_dist_base; + mutex_unlock(&kvm->arch.config_lock); + + ret = vgic_register_dist_iodev(kvm, dist_base, + kvm_vgic_global_state.type); + if (ret) { + kvm_err("Unable to register VGIC dist MMIO regions\n"); + kvm_vgic_destroy(kvm); + } + mutex_unlock(&kvm->slots_lock); + return ret; out: - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); + mutex_unlock(&kvm->slots_lock); return ret; } diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 2642e9ce2819..5fe2365a629f 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -1936,6 +1936,7 @@ void vgic_lpi_translation_cache_destroy(struct kvm *kvm) static int vgic_its_create(struct kvm_device *dev, u32 type) { + int ret; struct vgic_its *its; if (type != KVM_DEV_TYPE_ARM_VGIC_ITS) @@ -1945,9 +1946,12 @@ static int vgic_its_create(struct kvm_device *dev, u32 type) if (!its) return -ENOMEM; + mutex_lock(&dev->kvm->arch.config_lock); + if (vgic_initialized(dev->kvm)) { - int ret = vgic_v4_init(dev->kvm); + ret = vgic_v4_init(dev->kvm); if (ret < 0) { + mutex_unlock(&dev->kvm->arch.config_lock); kfree(its); return ret; } @@ -1958,6 +1962,14 @@ static int vgic_its_create(struct kvm_device *dev, u32 type) mutex_init(&its->its_lock); mutex_init(&its->cmd_lock); + /* Yep, even more trickery for lock ordering... */ +#ifdef CONFIG_LOCKDEP + mutex_lock(&its->cmd_lock); + mutex_lock(&its->its_lock); + mutex_unlock(&its->its_lock); + mutex_unlock(&its->cmd_lock); +#endif + its->vgic_its_base = VGIC_ADDR_UNDEF; INIT_LIST_HEAD(&its->device_list); @@ -1976,7 +1988,11 @@ static int vgic_its_create(struct kvm_device *dev, u32 type) dev->private = its; - return vgic_its_set_abi(its, NR_ITS_ABIS - 1); + ret = vgic_its_set_abi(its, NR_ITS_ABIS - 1); + + mutex_unlock(&dev->kvm->arch.config_lock); + + return ret; } static void vgic_its_destroy(struct kvm_device *kvm_dev) @@ -2045,6 +2061,13 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev, mutex_lock(&dev->kvm->lock); + if (!lock_all_vcpus(dev->kvm)) { + mutex_unlock(&dev->kvm->lock); + return -EBUSY; + } + + mutex_lock(&dev->kvm->arch.config_lock); + if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) { ret = -ENXIO; goto out; @@ -2058,11 +2081,6 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev, goto out; } - if (!lock_all_vcpus(dev->kvm)) { - ret = -EBUSY; - goto out; - } - addr = its->vgic_its_base + offset; len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4; @@ -2076,8 +2094,9 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev, } else { *reg = region->its_read(dev->kvm, its, addr, len); } - unlock_all_vcpus(dev->kvm); out: + mutex_unlock(&dev->kvm->arch.config_lock); + unlock_all_vcpus(dev->kvm); mutex_unlock(&dev->kvm->lock); return ret; } @@ -2749,14 +2768,15 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr) return 0; mutex_lock(&kvm->lock); - mutex_lock(&its->its_lock); if (!lock_all_vcpus(kvm)) { - mutex_unlock(&its->its_lock); mutex_unlock(&kvm->lock); return -EBUSY; } + mutex_lock(&kvm->arch.config_lock); + mutex_lock(&its->its_lock); + switch (attr) { case KVM_DEV_ARM_ITS_CTRL_RESET: vgic_its_reset(kvm, its); @@ -2769,8 +2789,9 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr) break; } - unlock_all_vcpus(kvm); mutex_unlock(&its->its_lock); + mutex_unlock(&kvm->arch.config_lock); + unlock_all_vcpus(kvm); mutex_unlock(&kvm->lock); return ret; } diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index edeac2380591..212b73a715c1 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -46,7 +46,7 @@ int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev struct vgic_dist *vgic = &kvm->arch.vgic; int r; - mutex_lock(&kvm->lock); + mutex_lock(&kvm->arch.config_lock); switch (FIELD_GET(KVM_ARM_DEVICE_TYPE_MASK, dev_addr->id)) { case KVM_VGIC_V2_ADDR_TYPE_DIST: r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); @@ -68,7 +68,7 @@ int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev r = -ENODEV; } - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->arch.config_lock); return r; } @@ -102,7 +102,11 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri if (get_user(addr, uaddr)) return -EFAULT; - mutex_lock(&kvm->lock); + /* + * Since we can't hold config_lock while registering the redistributor + * iodevs, take the slots_lock immediately. + */ + mutex_lock(&kvm->slots_lock); switch (attr->attr) { case KVM_VGIC_V2_ADDR_TYPE_DIST: r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); @@ -182,6 +186,7 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri if (r) goto out; + mutex_lock(&kvm->arch.config_lock); if (write) { r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size); if (!r) @@ -189,9 +194,10 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri } else { addr = *addr_ptr; } + mutex_unlock(&kvm->arch.config_lock); out: - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->slots_lock); if (!r && !write) r = put_user(addr, uaddr); @@ -227,7 +233,7 @@ static int vgic_set_common_attr(struct kvm_device *dev, (val & 31)) return -EINVAL; - mutex_lock(&dev->kvm->lock); + mutex_lock(&dev->kvm->arch.config_lock); if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis) ret = -EBUSY; @@ -235,16 +241,16 @@ static int vgic_set_common_attr(struct kvm_device *dev, dev->kvm->arch.vgic.nr_spis = val - VGIC_NR_PRIVATE_IRQS; - mutex_unlock(&dev->kvm->lock); + mutex_unlock(&dev->kvm->arch.config_lock); return ret; } case KVM_DEV_ARM_VGIC_GRP_CTRL: { switch (attr->attr) { case KVM_DEV_ARM_VGIC_CTRL_INIT: - mutex_lock(&dev->kvm->lock); + mutex_lock(&dev->kvm->arch.config_lock); r = vgic_init(dev->kvm); - mutex_unlock(&dev->kvm->lock); + mutex_unlock(&dev->kvm->arch.config_lock); return r; case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: /* @@ -260,7 +266,10 @@ static int vgic_set_common_attr(struct kvm_device *dev, mutex_unlock(&dev->kvm->lock); return -EBUSY; } + + mutex_lock(&dev->kvm->arch.config_lock); r = vgic_v3_save_pending_tables(dev->kvm); + mutex_unlock(&dev->kvm->arch.config_lock); unlock_all_vcpus(dev->kvm); mutex_unlock(&dev->kvm->lock); return r; @@ -342,44 +351,6 @@ int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, return 0; } -/* unlocks vcpus from @vcpu_lock_idx and smaller */ -static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx) -{ - struct kvm_vcpu *tmp_vcpu; - - for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) { - tmp_vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx); - mutex_unlock(&tmp_vcpu->mutex); - } -} - -void unlock_all_vcpus(struct kvm *kvm) -{ - unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1); -} - -/* Returns true if all vcpus were locked, false otherwise */ -bool lock_all_vcpus(struct kvm *kvm) -{ - struct kvm_vcpu *tmp_vcpu; - unsigned long c; - - /* - * Any time a vcpu is run, vcpu_load is called which tries to grab the - * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure - * that no other VCPUs are run and fiddle with the vgic state while we - * access it. - */ - kvm_for_each_vcpu(c, tmp_vcpu, kvm) { - if (!mutex_trylock(&tmp_vcpu->mutex)) { - unlock_vcpus(kvm, c - 1); - return false; - } - } - - return true; -} - /** * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state * @@ -411,15 +382,17 @@ static int vgic_v2_attr_regs_access(struct kvm_device *dev, mutex_lock(&dev->kvm->lock); + if (!lock_all_vcpus(dev->kvm)) { + mutex_unlock(&dev->kvm->lock); + return -EBUSY; + } + + mutex_lock(&dev->kvm->arch.config_lock); + ret = vgic_init(dev->kvm); if (ret) goto out; - if (!lock_all_vcpus(dev->kvm)) { - ret = -EBUSY; - goto out; - } - switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, &val); @@ -432,8 +405,9 @@ static int vgic_v2_attr_regs_access(struct kvm_device *dev, break; } - unlock_all_vcpus(dev->kvm); out: + mutex_unlock(&dev->kvm->arch.config_lock); + unlock_all_vcpus(dev->kvm); mutex_unlock(&dev->kvm->lock); if (!ret && !is_write) @@ -569,12 +543,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, mutex_lock(&dev->kvm->lock); - if (unlikely(!vgic_initialized(dev->kvm))) { - ret = -EBUSY; - goto out; + if (!lock_all_vcpus(dev->kvm)) { + mutex_unlock(&dev->kvm->lock); + return -EBUSY; } - if (!lock_all_vcpus(dev->kvm)) { + mutex_lock(&dev->kvm->arch.config_lock); + + if (unlikely(!vgic_initialized(dev->kvm))) { ret = -EBUSY; goto out; } @@ -609,8 +585,9 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, break; } - unlock_all_vcpus(dev->kvm); out: + mutex_unlock(&dev->kvm->arch.config_lock); + unlock_all_vcpus(dev->kvm); mutex_unlock(&dev->kvm->lock); if (!ret && uaccess && !is_write) { diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 91201f743033..188d2187eede 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -111,7 +111,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, case GICD_CTLR: { bool was_enabled, is_hwsgi; - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->arch.config_lock); was_enabled = dist->enabled; is_hwsgi = dist->nassgireq; @@ -139,7 +139,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, else if (!was_enabled && dist->enabled) vgic_kick_vcpus(vcpu->kvm); - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); break; } case GICD_TYPER: @@ -769,10 +769,13 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu) struct vgic_io_device *rd_dev = &vcpu->arch.vgic_cpu.rd_iodev; struct vgic_redist_region *rdreg; gpa_t rd_base; - int ret; + int ret = 0; + + lockdep_assert_held(&kvm->slots_lock); + mutex_lock(&kvm->arch.config_lock); if (!IS_VGIC_ADDR_UNDEF(vgic_cpu->rd_iodev.base_addr)) - return 0; + goto out_unlock; /* * We may be creating VCPUs before having set the base address for the @@ -782,10 +785,12 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu) */ rdreg = vgic_v3_rdist_free_slot(&vgic->rd_regions); if (!rdreg) - return 0; + goto out_unlock; - if (!vgic_v3_check_base(kvm)) - return -EINVAL; + if (!vgic_v3_check_base(kvm)) { + ret = -EINVAL; + goto out_unlock; + } vgic_cpu->rdreg = rdreg; vgic_cpu->rdreg_index = rdreg->free_index; @@ -799,16 +804,20 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu) rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rd_registers); rd_dev->redist_vcpu = vcpu; - mutex_lock(&kvm->slots_lock); + mutex_unlock(&kvm->arch.config_lock); + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, rd_base, 2 * SZ_64K, &rd_dev->dev); - mutex_unlock(&kvm->slots_lock); - if (ret) return ret; + /* Protected by slots_lock */ rdreg->free_index++; return 0; + +out_unlock: + mutex_unlock(&kvm->arch.config_lock); + return ret; } static void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu) @@ -834,12 +843,10 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm) /* The current c failed, so iterate over the previous ones. */ int i; - mutex_lock(&kvm->slots_lock); for (i = 0; i < c; i++) { vcpu = kvm_get_vcpu(kvm, i); vgic_unregister_redist_iodev(vcpu); } - mutex_unlock(&kvm->slots_lock); } return ret; @@ -938,7 +945,9 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count) { int ret; + mutex_lock(&kvm->arch.config_lock); ret = vgic_v3_alloc_redist_region(kvm, index, addr, count); + mutex_unlock(&kvm->arch.config_lock); if (ret) return ret; @@ -950,8 +959,10 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count) if (ret) { struct vgic_redist_region *rdreg; + mutex_lock(&kvm->arch.config_lock); rdreg = vgic_v3_rdist_region_from_index(kvm, index); vgic_v3_free_redist_region(rdreg); + mutex_unlock(&kvm->arch.config_lock); return ret; } diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index e67b3b2c8044..ff558c05e990 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -530,13 +530,13 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu, u32 intid = VGIC_ADDR_TO_INTID(addr, 1); u32 val; - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->arch.config_lock); vgic_access_active_prepare(vcpu, intid); val = __vgic_mmio_read_active(vcpu, addr, len); vgic_access_active_finish(vcpu, intid); - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); return val; } @@ -625,13 +625,13 @@ void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu, { u32 intid = VGIC_ADDR_TO_INTID(addr, 1); - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->arch.config_lock); vgic_access_active_prepare(vcpu, intid); __vgic_mmio_write_cactive(vcpu, addr, len, val); vgic_access_active_finish(vcpu, intid); - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); } int vgic_mmio_uaccess_write_cactive(struct kvm_vcpu *vcpu, @@ -662,13 +662,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu, { u32 intid = VGIC_ADDR_TO_INTID(addr, 1); - mutex_lock(&vcpu->kvm->lock); + mutex_lock(&vcpu->kvm->arch.config_lock); vgic_access_active_prepare(vcpu, intid); __vgic_mmio_write_sactive(vcpu, addr, len, val); vgic_access_active_finish(vcpu, intid); - mutex_unlock(&vcpu->kvm->lock); + mutex_unlock(&vcpu->kvm->arch.config_lock); } int vgic_mmio_uaccess_write_sactive(struct kvm_vcpu *vcpu, @@ -1096,7 +1096,6 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address, enum vgic_type type) { struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev; - int ret = 0; unsigned int len; switch (type) { @@ -1114,10 +1113,6 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address, io_device->iodev_type = IODEV_DIST; io_device->redist_vcpu = NULL; - mutex_lock(&kvm->slots_lock); - ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address, - len, &io_device->dev); - mutex_unlock(&kvm->slots_lock); - - return ret; + return kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address, + len, &io_device->dev); } diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c index 645648349c99..7e9cdb78f7ce 100644 --- a/arch/arm64/kvm/vgic/vgic-v2.c +++ b/arch/arm64/kvm/vgic/vgic-v2.c @@ -312,12 +312,6 @@ int vgic_v2_map_resources(struct kvm *kvm) return ret; } - ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2); - if (ret) { - kvm_err("Unable to register VGIC MMIO regions\n"); - return ret; - } - if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) { ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base, kvm_vgic_global_state.vcpu_base, diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index 469d816f356f..c3b8e132d599 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -539,7 +539,6 @@ int vgic_v3_map_resources(struct kvm *kvm) { struct vgic_dist *dist = &kvm->arch.vgic; struct kvm_vcpu *vcpu; - int ret = 0; unsigned long c; kvm_for_each_vcpu(c, vcpu, kvm) { @@ -569,12 +568,6 @@ int vgic_v3_map_resources(struct kvm *kvm) return -EBUSY; } - ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3); - if (ret) { - kvm_err("Unable to register VGICv3 dist MMIO regions\n"); - return ret; - } - if (kvm_vgic_global_state.has_gicv4_1) vgic_v4_configure_vsgis(kvm); @@ -616,6 +609,10 @@ static const struct midr_range broken_seis[] = { MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM_MAX), MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD), MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_PRO), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_PRO), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD_MAX), + MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE_MAX), {}, }; diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c index a413718be92b..c1c28fe680ba 100644 --- a/arch/arm64/kvm/vgic/vgic-v4.c +++ b/arch/arm64/kvm/vgic/vgic-v4.c @@ -184,13 +184,14 @@ static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu) } } -/* Must be called with the kvm lock held */ void vgic_v4_configure_vsgis(struct kvm *kvm) { struct vgic_dist *dist = &kvm->arch.vgic; struct kvm_vcpu *vcpu; unsigned long i; + lockdep_assert_held(&kvm->arch.config_lock); + kvm_arm_halt_guest(kvm); kvm_for_each_vcpu(i, vcpu, kvm) { @@ -232,9 +233,8 @@ int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq) * @kvm: Pointer to the VM being initialized * * We may be called each time a vITS is created, or when the - * vgic is initialized. This relies on kvm->lock to be - * held. In both cases, the number of vcpus should now be - * fixed. + * vgic is initialized. In both cases, the number of vcpus + * should now be fixed. */ int vgic_v4_init(struct kvm *kvm) { @@ -243,6 +243,8 @@ int vgic_v4_init(struct kvm *kvm) int nr_vcpus, ret; unsigned long i; + lockdep_assert_held(&kvm->arch.config_lock); + if (!kvm_vgic_global_state.has_gicv4) return 0; /* Nothing to see here... move along. */ @@ -309,14 +311,14 @@ int vgic_v4_init(struct kvm *kvm) /** * vgic_v4_teardown - Free the GICv4 data structures * @kvm: Pointer to the VM being destroyed - * - * Relies on kvm->lock to be held. */ void vgic_v4_teardown(struct kvm *kvm) { struct its_vm *its_vm = &kvm->arch.vgic.its_vm; int i; + lockdep_assert_held(&kvm->arch.config_lock); + if (!its_vm->vpes) return; diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index d97e6080b421..8be4c1ebdec2 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -24,11 +24,13 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = { /* * Locking order is always: * kvm->lock (mutex) - * its->cmd_lock (mutex) - * its->its_lock (mutex) - * vgic_cpu->ap_list_lock must be taken with IRQs disabled - * kvm->lpi_list_lock must be taken with IRQs disabled - * vgic_irq->irq_lock must be taken with IRQs disabled + * vcpu->mutex (mutex) + * kvm->arch.config_lock (mutex) + * its->cmd_lock (mutex) + * its->its_lock (mutex) + * vgic_cpu->ap_list_lock must be taken with IRQs disabled + * kvm->lpi_list_lock must be taken with IRQs disabled + * vgic_irq->irq_lock must be taken with IRQs disabled * * As the ap_list_lock might be taken from the timer interrupt handler, * we have to disable IRQs before taking this lock and everything lower @@ -573,6 +575,21 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid) return 0; } +int kvm_vgic_get_map(struct kvm_vcpu *vcpu, unsigned int vintid) +{ + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + unsigned long flags; + int ret = -1; + + raw_spin_lock_irqsave(&irq->irq_lock, flags); + if (irq->hw) + ret = irq->hwintid; + raw_spin_unlock_irqrestore(&irq->irq_lock, flags); + + vgic_put_irq(vcpu->kvm, irq); + return ret; +} + /** * kvm_vgic_set_owner - Set the owner of an interrupt for a VM * diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 7f7f3c5ed85a..f9923beedd27 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -273,9 +273,6 @@ int vgic_init(struct kvm *kvm); void vgic_debug_init(struct kvm *kvm); void vgic_debug_destroy(struct kvm *kvm); -bool lock_all_vcpus(struct kvm *kvm); -void unlock_all_vcpus(struct kvm *kvm); - static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu) { struct vgic_cpu *cpu_if = &vcpu->arch.vgic_cpu; diff --git a/arch/arm64/kvm/vmid.c b/arch/arm64/kvm/vmid.c index 08978d0672e7..7fe8ba1a2851 100644 --- a/arch/arm64/kvm/vmid.c +++ b/arch/arm64/kvm/vmid.c @@ -47,7 +47,7 @@ static void flush_context(void) int cpu; u64 vmid; - bitmap_clear(vmid_map, 0, NUM_USER_VMIDS); + bitmap_zero(vmid_map, NUM_USER_VMIDS); for_each_possible_cpu(cpu) { vmid = atomic64_xchg_relaxed(&per_cpu(active_vmids, cpu), 0); @@ -182,8 +182,7 @@ int __init kvm_arm_vmid_alloc_init(void) */ WARN_ON(NUM_USER_VMIDS - 1 <= num_possible_cpus()); atomic64_set(&vmid_generation, VMID_FIRST_VERSION); - vmid_map = kcalloc(BITS_TO_LONGS(NUM_USER_VMIDS), - sizeof(*vmid_map), GFP_KERNEL); + vmid_map = bitmap_zalloc(NUM_USER_VMIDS, GFP_KERNEL); if (!vmid_map) return -ENOMEM; @@ -192,5 +191,5 @@ int __init kvm_arm_vmid_alloc_init(void) void __init kvm_arm_vmid_alloc_free(void) { - kfree(vmid_map); + bitmap_free(vmid_map); } diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index 4aadcfb01754..a7bb20055ce0 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -21,9 +21,10 @@ void copy_highpage(struct page *to, struct page *from) copy_page(kto, kfrom); + if (kasan_hw_tags_enabled()) + page_kasan_tag_reset(to); + if (system_supports_mte() && page_mte_tagged(from)) { - if (kasan_hw_tags_enabled()) - page_kasan_tag_reset(to); /* It's a new page, shouldn't have been tagged yet */ WARN_ON_ONCE(!try_page_mte_tagging(to)); mte_copy_page_tags(kto, kfrom); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index f4cb0f85ccf4..cb21ccd7940d 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -480,8 +480,8 @@ static void do_bad_area(unsigned long far, unsigned long esr, } } -#define VM_FAULT_BADMAP 0x010000 -#define VM_FAULT_BADACCESS 0x020000 +#define VM_FAULT_BADMAP ((__force vm_fault_t)0x010000) +#define VM_FAULT_BADACCESS ((__force vm_fault_t)0x020000) static vm_fault_t __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int mm_flags, unsigned long vm_flags, @@ -535,6 +535,9 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr, unsigned long vm_flags; unsigned int mm_flags = FAULT_FLAG_DEFAULT; unsigned long addr = untagged_addr(far); +#ifdef CONFIG_PER_VMA_LOCK + struct vm_area_struct *vma; +#endif if (kprobe_page_fault(regs, esr)) return 0; @@ -585,6 +588,36 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr, perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); +#ifdef CONFIG_PER_VMA_LOCK + if (!(mm_flags & FAULT_FLAG_USER)) + goto lock_mmap; + + vma = lock_vma_under_rcu(mm, addr); + if (!vma) + goto lock_mmap; + + if (!(vma->vm_flags & vm_flags)) { + vma_end_read(vma); + goto lock_mmap; + } + fault = handle_mm_fault(vma, addr & PAGE_MASK, + mm_flags | FAULT_FLAG_VMA_LOCK, regs); + vma_end_read(vma); + + if (!(fault & VM_FAULT_RETRY)) { + count_vm_vma_lock_event(VMA_LOCK_SUCCESS); + goto done; + } + count_vm_vma_lock_event(VMA_LOCK_RETRY); + + /* Quick path to respond to signals */ + if (fault_signal_pending(fault, regs)) { + if (!user_mode(regs)) + goto no_context; + return 0; + } +lock_mmap: +#endif /* CONFIG_PER_VMA_LOCK */ /* * As per x86, we may deadlock here. However, since the kernel only * validly references user space from well defined areas of the code, @@ -628,6 +661,9 @@ retry: } mmap_read_unlock(mm); +#ifdef CONFIG_PER_VMA_LOCK +done: +#endif /* * Handle the "normal" (no error) case first. */ diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 91410f488090..c2cb437821ca 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -167,7 +167,7 @@ alternative_else_nop_endif SYM_FUNC_END(cpu_do_resume) #endif - .pushsection ".idmap.text", "awx" + .pushsection ".idmap.text", "a" .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 adrp \tmp1, reserved_pg_dir @@ -201,7 +201,7 @@ SYM_FUNC_END(idmap_cpu_replace_ttbr1) #define KPTI_NG_PTE_FLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS) - .pushsection ".idmap.text", "awx" + .pushsection ".idmap.text", "a" .macro kpti_mk_tbl_ng, type, num_entries add end_\type\()p, cur_\type\()p, #\num_entries * 8 @@ -400,7 +400,7 @@ SYM_FUNC_END(idmap_kpti_install_ng_mappings) * Output: * Return in x0 the value of the SCTLR_EL1 register. */ - .pushsection ".idmap.text", "awx" + .pushsection ".idmap.text", "a" SYM_FUNC_START(__cpu_setup) tlbi vmalle1 // Invalidate local TLB dsb nsh diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index 37b1340e9646..40ba95472594 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -23,6 +23,7 @@ HAS_DCPOP HAS_DIT HAS_E0PD HAS_ECV +HAS_ECV_CNTPOFF HAS_EPAN HAS_GENERIC_AUTH HAS_GENERIC_AUTH_ARCH_QARMA3 diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index 77edce16f4f9..c9a0d1fa3209 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -2115,6 +2115,10 @@ Sysreg CONTEXTIDR_EL2 3 4 13 0 1 Fields CONTEXTIDR_ELx EndSysreg +Sysreg CNTPOFF_EL2 3 4 14 0 6 +Field 63:0 PhysicalOffset +EndSysreg + Sysreg CPACR_EL12 3 5 1 0 2 Fields CPACR_ELx EndSysreg diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index dba02da6fa34..4df1f8c9d170 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -166,11 +166,6 @@ config STACKTRACE_SUPPORT config TIME_LOW_RES def_bool y -config CPU_TLB_SIZE - int - default "128" if (CPU_CK610 || CPU_CK807 || CPU_CK810) - default "1024" if (CPU_CK860) - config CPU_ASID_BITS int default "8" if (CPU_CK610 || CPU_CK807 || CPU_CK810) @@ -332,10 +327,6 @@ config HIGHMEM select KMAP_LOCAL default y -config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - default "11" - config DRAM_BASE hex "DRAM start addr (the same with memory-section in dts)" default 0x0 diff --git a/arch/csky/abiv1/alignment.c b/arch/csky/abiv1/alignment.c index 2df115d0e210..b60259daed1b 100644 --- a/arch/csky/abiv1/alignment.c +++ b/arch/csky/abiv1/alignment.c @@ -332,22 +332,9 @@ static struct ctl_table alignment_tbl[5] = { {} }; -static struct ctl_table sysctl_table[2] = { - { - .procname = "csky_alignment", - .mode = 0555, - .child = alignment_tbl}, - {} -}; - -static struct ctl_path sysctl_path[2] = { - {.procname = "csky"}, - {} -}; - static int __init csky_alignment_init(void) { - register_sysctl_paths(sysctl_path, sysctl_table); + register_sysctl_init("csky/csky_alignment", alignment_tbl); return 0; } diff --git a/arch/csky/abiv1/cacheflush.c b/arch/csky/abiv1/cacheflush.c index fb91b069dc69..94fbc03cbe70 100644 --- a/arch/csky/abiv1/cacheflush.c +++ b/arch/csky/abiv1/cacheflush.c @@ -11,6 +11,7 @@ #include #include #include +#include #define PG_dcache_clean PG_arch_1 @@ -40,6 +41,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn = pte_pfn(*ptep); struct page *page; + flush_tlb_page(vma, addr); + if (!pfn_valid(pfn)) return; diff --git a/arch/csky/abiv2/cacheflush.c b/arch/csky/abiv2/cacheflush.c index 39c51399dd81..9923cd24db58 100644 --- a/arch/csky/abiv2/cacheflush.c +++ b/arch/csky/abiv2/cacheflush.c @@ -5,6 +5,7 @@ #include #include #include +#include void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *pte) @@ -12,6 +13,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, unsigned long addr; struct page *page; + flush_tlb_page(vma, address); + if (!pfn_valid(pte_pfn(*pte))) return; diff --git a/arch/csky/kernel/smp.c b/arch/csky/kernel/smp.c index b45d1073307f..b12e2c3c387f 100644 --- a/arch/csky/kernel/smp.c +++ b/arch/csky/kernel/smp.c @@ -140,7 +140,7 @@ void smp_send_stop(void) on_each_cpu(ipi_stop, NULL, 1); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } @@ -300,7 +300,7 @@ void __cpu_die(unsigned int cpu) pr_notice("CPU%u: shutdown\n", cpu); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { idle_task_exit(); @@ -317,5 +317,7 @@ void arch_cpu_idle_dead(void) "jmpi csky_start_secondary" : : "r" (secondary_stack)); + + BUG(); } #endif diff --git a/arch/hexagon/include/asm/cmpxchg.h b/arch/hexagon/include/asm/cmpxchg.h index cdb705e1496a..bf6cf5579cf4 100644 --- a/arch/hexagon/include/asm/cmpxchg.h +++ b/arch/hexagon/include/asm/cmpxchg.h @@ -9,7 +9,7 @@ #define _ASM_CMPXCHG_H /* - * __xchg - atomically exchange a register and a memory location + * __arch_xchg - atomically exchange a register and a memory location * @x: value to swap * @ptr: pointer to memory * @size: size of the value @@ -19,8 +19,8 @@ * Note: there was an errata for V2 about .new's and memw_locked. * */ -static inline unsigned long __xchg(unsigned long x, volatile void *ptr, - int size) +static inline unsigned long +__arch_xchg(unsigned long x, volatile void *ptr, int size) { unsigned long retval; @@ -42,8 +42,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, * Atomically swap the contents of a register with memory. Should be atomic * between multiple CPU's and within interrupts on the same CPU. */ -#define arch_xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ - sizeof(*(ptr)))) +#define arch_xchg(ptr, v) ((__typeof__(*(ptr)))__arch_xchg((unsigned long)(v), (ptr), \ + sizeof(*(ptr)))) /* * see rt-mutex-design.txt; cmpxchg supposedly checks if *ptr == A and swaps. diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c index 4ba93e59370c..4e8bee25b8c6 100644 --- a/arch/hexagon/kernel/smp.c +++ b/arch/hexagon/kernel/smp.c @@ -217,7 +217,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { send_ipi(cpumask_of(cpu), IPI_RESCHEDULE); } diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 2e13ec8263b9..21fa63ce5ffc 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -203,10 +203,9 @@ config IA64_CYCLONE If you're unsure, answer N. config ARCH_FORCE_MAX_ORDER - int "MAX_ORDER (11 - 17)" if !HUGETLB_PAGE - range 11 17 if !HUGETLB_PAGE - default "17" if HUGETLB_PAGE - default "11" + int + default "16" if HUGETLB_PAGE + default "10" config SMP bool "Symmetric multi-processing support" diff --git a/arch/ia64/include/asm/cmpxchg.h b/arch/ia64/include/asm/cmpxchg.h index 94ef84429843..8b2e644ef6a1 100644 --- a/arch/ia64/include/asm/cmpxchg.h +++ b/arch/ia64/include/asm/cmpxchg.h @@ -5,7 +5,7 @@ #include #define arch_xchg(ptr, x) \ -({(__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));}) +({(__typeof__(*(ptr))) __arch_xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));}) #define arch_cmpxchg(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) #define arch_cmpxchg64(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) diff --git a/arch/ia64/include/asm/sparsemem.h b/arch/ia64/include/asm/sparsemem.h index 84e8ce387b69..a58f8b466d96 100644 --- a/arch/ia64/include/asm/sparsemem.h +++ b/arch/ia64/include/asm/sparsemem.h @@ -12,9 +12,9 @@ #define SECTION_SIZE_BITS (30) #define MAX_PHYSMEM_BITS (50) #ifdef CONFIG_ARCH_FORCE_MAX_ORDER -#if ((CONFIG_ARCH_FORCE_MAX_ORDER - 1 + PAGE_SHIFT) > SECTION_SIZE_BITS) +#if (CONFIG_ARCH_FORCE_MAX_ORDER + PAGE_SHIFT > SECTION_SIZE_BITS) #undef SECTION_SIZE_BITS -#define SECTION_SIZE_BITS (CONFIG_ARCH_FORCE_MAX_ORDER - 1 + PAGE_SHIFT) +#define SECTION_SIZE_BITS (CONFIG_ARCH_FORCE_MAX_ORDER + PAGE_SHIFT) #endif #endif diff --git a/arch/ia64/include/uapi/asm/cmpxchg.h b/arch/ia64/include/uapi/asm/cmpxchg.h index 259ae57570bf..85cba138311f 100644 --- a/arch/ia64/include/uapi/asm/cmpxchg.h +++ b/arch/ia64/include/uapi/asm/cmpxchg.h @@ -23,7 +23,7 @@ */ extern void ia64_xchg_called_with_bad_pointer(void); -#define __xchg(x, ptr, size) \ +#define __arch_xchg(x, ptr, size) \ ({ \ unsigned long __xchg_result; \ \ @@ -51,7 +51,7 @@ extern void ia64_xchg_called_with_bad_pointer(void); #ifndef __KERNEL__ #define xchg(ptr, x) \ -({(__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));}) +({(__typeof__(*(ptr))) __arch_xchg((unsigned long) (x), (ptr), sizeof(*(ptr)));}) #endif /* diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index 76730f34685c..88b3ce3e66cd 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -234,15 +234,6 @@ static struct ctl_table kdump_ctl_table[] = { }, { } }; - -static struct ctl_table sys_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = kdump_ctl_table, - }, - { } -}; #endif static int @@ -257,7 +248,7 @@ machine_crash_setup(void) if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0) return ret; #ifdef CONFIG_SYSCTL - register_sysctl_table(sys_table); + register_sysctl("kernel", kdump_ctl_table); #endif return 0; } diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 8f62cf97f691..3661135da9d9 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -485,19 +485,19 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, return 0; } -static inline int +static inline bool in_init (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->init_layout.base < mod->init_layout.size; + return within_module_init(addr, mod); } -static inline int +static inline bool in_core (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->core_layout.base < mod->core_layout.size; + return within_module_core(addr, mod); } -static inline int +static inline bool is_internal (const struct module *mod, uint64_t value) { return in_init(mod, value) || in_core(mod, value); @@ -677,7 +677,8 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, break; case RV_BDREL: - val -= (uint64_t) (in_init(mod, val) ? mod->init_layout.base : mod->core_layout.base); + val -= (uint64_t) (in_init(mod, val) ? mod->mem[MOD_INIT_TEXT].base : + mod->mem[MOD_TEXT].base); break; case RV_LTV: @@ -812,15 +813,18 @@ apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symind * addresses have been selected... */ uint64_t gp; - if (mod->core_layout.size > MAX_LTOFF) + struct module_memory *mod_mem; + + mod_mem = &mod->mem[MOD_DATA]; + if (mod_mem->size > MAX_LTOFF) /* * This takes advantage of fact that SHF_ARCH_SMALL gets allocated * at the end of the module. */ - gp = mod->core_layout.size - MAX_LTOFF / 2; + gp = mod_mem->size - MAX_LTOFF / 2; else - gp = mod->core_layout.size / 2; - gp = (uint64_t) mod->core_layout.base + ((gp + 7) & -8); + gp = mod_mem->size / 2; + gp = (uint64_t) mod_mem->base + ((gp + 7) & -8); mod->arch.gp = gp; DEBUGP("%s: placing gp at 0x%lx\n", __func__, gp); } diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index f6195a0a00ae..9a5cd9fad3a9 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -201,7 +201,7 @@ __setup("nohalt", nohalt_setup); #ifdef CONFIG_HOTPLUG_CPU /* We don't actually take CPU down, just spin without interrupts. */ -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { unsigned int this_cpu = smp_processor_id(); @@ -219,13 +219,13 @@ static inline void play_dead(void) BUG(); } #else -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { BUG(); } #endif /* CONFIG_HOTPLUG_CPU */ -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { play_dead(); } diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index bd3ba276e69c..03b632c56899 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -581,7 +581,7 @@ static int salinfo_cpu_pre_down(unsigned int cpu) * 'data' contains an integer that corresponds to the feature we're * testing */ -static int proc_salinfo_show(struct seq_file *m, void *v) +static int __maybe_unused proc_salinfo_show(struct seq_file *m, void *v) { unsigned long data = (unsigned long)v; seq_puts(m, (sal_platform_features & data) ? "1\n" : "0\n"); diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index e2cc59db86bc..ea4f009a232b 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -220,11 +220,11 @@ kdump_smp_send_init(void) * Called with preemption disabled. */ void -smp_send_reschedule (int cpu) +arch_smp_send_reschedule (int cpu) { ia64_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } -EXPORT_SYMBOL_GPL(smp_send_reschedule); +EXPORT_SYMBOL_GPL(arch_smp_send_reschedule); /* * Called with preemption disabled. diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 24901d809301..1e9eaa107eb7 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -77,7 +77,7 @@ skip: return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; } -static inline void +static inline __init void alloc_per_cpu_data(void) { size_t size = PERCPU_PAGE_SIZE * num_possible_cpus(); diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index 380d2f3966c9..78a02e026164 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -58,7 +58,7 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr, unsigned long sz) pgd = pgd_offset(mm, taddr); if (pgd_present(*pgd)) { - p4d = p4d_offset(pgd, addr); + p4d = p4d_offset(pgd, taddr); if (p4d_present(*p4d)) { pud = pud_offset(p4d, taddr); if (pud_present(*pud)) { @@ -170,7 +170,7 @@ static int __init hugetlb_setup_sz(char *str) size = memparse(str, &str); if (*str || !is_power_of_2(size) || !(tr_pages & size) || size <= PAGE_SIZE || - size >= (1UL << PAGE_SHIFT << MAX_ORDER)) { + size > (1UL << PAGE_SHIFT << MAX_ORDER)) { printk(KERN_WARNING "Invalid huge page size specified\n"); return 1; } diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 3a19045a76f7..d38b066fc931 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -10,6 +10,7 @@ config LOONGARCH select ARCH_ENABLE_MEMORY_HOTPLUG select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI + select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST @@ -53,8 +54,8 @@ config LOONGARCH select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT - select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP select ARCH_WANT_LD_ORPHAN_WARN + select ARCH_WANT_OPTIMIZE_VMEMMAP select ARCH_WANTS_NO_INSTR select BUILDTIME_TABLE_SORT select COMMON_CLK @@ -93,6 +94,7 @@ config LOONGARCH select HAVE_DMA_CONTIGUOUS select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_ARGS + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_EBPF_JIT select HAVE_EFFICIENT_UNALIGNED_ACCESS if !ARCH_STRICT_ALIGN @@ -100,6 +102,7 @@ config LOONGARCH select HAVE_FAST_GUP select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_ARG_ACCESS_API + select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_GENERIC_VDSO @@ -118,6 +121,8 @@ config LOONGARCH select HAVE_PERF_USER_STACK_DUMP select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RSEQ + select HAVE_SAMPLE_FTRACE_DIRECT + select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_SETUP_PER_CPU_AREA if NUMA select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS @@ -421,12 +426,9 @@ config NODES_SHIFT config ARCH_FORCE_MAX_ORDER int "Maximum zone order" - range 14 64 if PAGE_SIZE_64KB - default "14" if PAGE_SIZE_64KB - range 12 64 if PAGE_SIZE_16KB - default "12" if PAGE_SIZE_16KB - range 11 64 - default "11" + default "13" if PAGE_SIZE_64KB + default "11" if PAGE_SIZE_16KB + default "10" help The kernel memory allocator divides physically contiguous memory blocks into "zones", where each zone is a power of two number of @@ -435,9 +437,6 @@ config ARCH_FORCE_MAX_ORDER blocks of physically contiguous memory, then you may need to increase this value. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. - The page size is not necessarily 4KB. Keep this in mind when choosing a value for this option. diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index f71edf574101..a27e264bdaa5 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -115,6 +115,8 @@ endif libs-y += arch/loongarch/lib/ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a +drivers-y += arch/loongarch/crypto/ + # suspend and hibernation support drivers-$(CONFIG_PM) += arch/loongarch/power/ diff --git a/arch/loongarch/crypto/Kconfig b/arch/loongarch/crypto/Kconfig new file mode 100644 index 000000000000..200a6e8b43b1 --- /dev/null +++ b/arch/loongarch/crypto/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 + +menu "Accelerated Cryptographic Algorithms for CPU (loongarch)" + +config CRYPTO_CRC32_LOONGARCH + tristate "CRC32c and CRC32" + select CRC32 + select CRYPTO_HASH + help + CRC32c and CRC32 CRC algorithms + + Architecture: LoongArch with CRC32 instructions + +endmenu diff --git a/arch/loongarch/crypto/Makefile b/arch/loongarch/crypto/Makefile new file mode 100644 index 000000000000..d22613d27ce9 --- /dev/null +++ b/arch/loongarch/crypto/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for LoongArch crypto files.. +# + +obj-$(CONFIG_CRYPTO_CRC32_LOONGARCH) += crc32-loongarch.o diff --git a/arch/loongarch/crypto/crc32-loongarch.c b/arch/loongarch/crypto/crc32-loongarch.c new file mode 100644 index 000000000000..1f2a2c3839bc --- /dev/null +++ b/arch/loongarch/crypto/crc32-loongarch.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * crc32.c - CRC32 and CRC32C using LoongArch crc* instructions + * + * Module based on mips/crypto/crc32-mips.c + * + * Copyright (C) 2014 Linaro Ltd + * Copyright (C) 2018 MIPS Tech, LLC + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#include +#include + +#include +#include + +#define _CRC32(crc, value, size, type) \ +do { \ + __asm__ __volatile__( \ + #type ".w." #size ".w" " %0, %1, %0\n\t"\ + : "+r" (crc) \ + : "r" (value) \ + : "memory"); \ +} while (0) + +#define CRC32(crc, value, size) _CRC32(crc, value, size, crc) +#define CRC32C(crc, value, size) _CRC32(crc, value, size, crcc) + +static u32 crc32_loongarch_hw(u32 crc_, const u8 *p, unsigned int len) +{ + u32 crc = crc_; + + while (len >= sizeof(u64)) { + u64 value = get_unaligned_le64(p); + + CRC32(crc, value, d); + p += sizeof(u64); + len -= sizeof(u64); + } + + if (len & sizeof(u32)) { + u32 value = get_unaligned_le32(p); + + CRC32(crc, value, w); + p += sizeof(u32); + len -= sizeof(u32); + } + + if (len & sizeof(u16)) { + u16 value = get_unaligned_le16(p); + + CRC32(crc, value, h); + p += sizeof(u16); + } + + if (len & sizeof(u8)) { + u8 value = *p++; + + CRC32(crc, value, b); + } + + return crc; +} + +static u32 crc32c_loongarch_hw(u32 crc_, const u8 *p, unsigned int len) +{ + u32 crc = crc_; + + while (len >= sizeof(u64)) { + u64 value = get_unaligned_le64(p); + + CRC32C(crc, value, d); + p += sizeof(u64); + len -= sizeof(u64); + } + + if (len & sizeof(u32)) { + u32 value = get_unaligned_le32(p); + + CRC32C(crc, value, w); + p += sizeof(u32); + len -= sizeof(u32); + } + + if (len & sizeof(u16)) { + u16 value = get_unaligned_le16(p); + + CRC32C(crc, value, h); + p += sizeof(u16); + } + + if (len & sizeof(u8)) { + u8 value = *p++; + + CRC32C(crc, value, b); + } + + return crc; +} + +#define CHKSUM_BLOCK_SIZE 1 +#define CHKSUM_DIGEST_SIZE 4 + +struct chksum_ctx { + u32 key; +}; + +struct chksum_desc_ctx { + u32 crc; +}; + +static int chksum_init(struct shash_desc *desc) +{ + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + ctx->crc = mctx->key; + + return 0; +} + +/* + * Setting the seed allows arbitrary accumulators and flexible XOR policy + * If your algorithm starts with ~0, then XOR with ~0 before you set the seed. + */ +static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) +{ + struct chksum_ctx *mctx = crypto_shash_ctx(tfm); + + if (keylen != sizeof(mctx->key)) + return -EINVAL; + + mctx->key = get_unaligned_le32(key); + + return 0; +} + +static int chksum_update(struct shash_desc *desc, const u8 *data, unsigned int length) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + ctx->crc = crc32_loongarch_hw(ctx->crc, data, length); + return 0; +} + +static int chksumc_update(struct shash_desc *desc, const u8 *data, unsigned int length) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + ctx->crc = crc32c_loongarch_hw(ctx->crc, data, length); + return 0; +} + +static int chksum_final(struct shash_desc *desc, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + put_unaligned_le32(ctx->crc, out); + return 0; +} + +static int chksumc_final(struct shash_desc *desc, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + put_unaligned_le32(~ctx->crc, out); + return 0; +} + +static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) +{ + put_unaligned_le32(crc32_loongarch_hw(crc, data, len), out); + return 0; +} + +static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) +{ + put_unaligned_le32(~crc32c_loongarch_hw(crc, data, len), out); + return 0; +} + +static int chksum_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + return __chksum_finup(ctx->crc, data, len, out); +} + +static int chksumc_finup(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + return __chksumc_finup(ctx->crc, data, len, out); +} + +static int chksum_digest(struct shash_desc *desc, const u8 *data, unsigned int length, u8 *out) +{ + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); + + return __chksum_finup(mctx->key, data, length, out); +} + +static int chksumc_digest(struct shash_desc *desc, const u8 *data, unsigned int length, u8 *out) +{ + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); + + return __chksumc_finup(mctx->key, data, length, out); +} + +static int chksum_cra_init(struct crypto_tfm *tfm) +{ + struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + + mctx->key = 0; + return 0; +} + +static int chksumc_cra_init(struct crypto_tfm *tfm) +{ + struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); + + mctx->key = ~0; + return 0; +} + +static struct shash_alg crc32_alg = { + .digestsize = CHKSUM_DIGEST_SIZE, + .setkey = chksum_setkey, + .init = chksum_init, + .update = chksum_update, + .final = chksum_final, + .finup = chksum_finup, + .digest = chksum_digest, + .descsize = sizeof(struct chksum_desc_ctx), + .base = { + .cra_name = "crc32", + .cra_driver_name = "crc32-loongarch", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = CHKSUM_BLOCK_SIZE, + .cra_alignmask = 0, + .cra_ctxsize = sizeof(struct chksum_ctx), + .cra_module = THIS_MODULE, + .cra_init = chksum_cra_init, + } +}; + +static struct shash_alg crc32c_alg = { + .digestsize = CHKSUM_DIGEST_SIZE, + .setkey = chksum_setkey, + .init = chksum_init, + .update = chksumc_update, + .final = chksumc_final, + .finup = chksumc_finup, + .digest = chksumc_digest, + .descsize = sizeof(struct chksum_desc_ctx), + .base = { + .cra_name = "crc32c", + .cra_driver_name = "crc32c-loongarch", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .cra_blocksize = CHKSUM_BLOCK_SIZE, + .cra_alignmask = 0, + .cra_ctxsize = sizeof(struct chksum_ctx), + .cra_module = THIS_MODULE, + .cra_init = chksumc_cra_init, + } +}; + +static int __init crc32_mod_init(void) +{ + int err; + + if (!cpu_has(CPU_FEATURE_CRC32)) + return 0; + + err = crypto_register_shash(&crc32_alg); + if (err) + return err; + + err = crypto_register_shash(&crc32c_alg); + if (err) + return err; + + return 0; +} + +static void __exit crc32_mod_exit(void) +{ + if (!cpu_has(CPU_FEATURE_CRC32)) + return; + + crypto_unregister_shash(&crc32_alg); + crypto_unregister_shash(&crc32c_alg); +} + +module_init(crc32_mod_init); +module_exit(crc32_mod_exit); + +MODULE_AUTHOR("Min Zhou "); +MODULE_AUTHOR("Huacai Chen "); +MODULE_DESCRIPTION("CRC32 and CRC32C using LoongArch crc* instructions"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/loongarch/include/asm/checksum.h b/arch/loongarch/include/asm/checksum.h new file mode 100644 index 000000000000..cabbf6af44c4 --- /dev/null +++ b/arch/loongarch/include/asm/checksum.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2016 ARM Ltd. + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ +#ifndef __ASM_CHECKSUM_H +#define __ASM_CHECKSUM_H + +#include +#include + +#define _HAVE_ARCH_IPV6_CSUM +__sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, __wsum sum); + +/* + * turns a 32-bit partial checksum (e.g. from csum_partial) into a + * 1's complement 16-bit checksum. + */ +static inline __sum16 csum_fold(__wsum sum) +{ + u32 tmp = (__force u32)sum; + + /* + * swap the two 16-bit halves of sum + * if there is a carry from adding the two 16-bit halves, + * it will carry from the lower half into the upper half, + * giving us the correct sum in the upper half. + */ + return (__force __sum16)(~(tmp + rol32(tmp, 16)) >> 16); +} +#define csum_fold csum_fold + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. ihl is the number + * of 32-bit words and is always >= 5. + */ +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + u64 sum; + __uint128_t tmp; + int n = ihl; /* we want it signed */ + + tmp = *(const __uint128_t *)iph; + iph += 16; + n -= 4; + tmp += ((tmp >> 64) | (tmp << 64)); + sum = tmp >> 64; + do { + sum += *(const u32 *)iph; + iph += 4; + } while (--n > 0); + + sum += ror64(sum, 32); + return csum_fold((__force __wsum)(sum >> 32)); +} +#define ip_fast_csum ip_fast_csum + +extern unsigned int do_csum(const unsigned char *buff, int len); +#define do_csum do_csum + +#include + +#endif /* __ASM_CHECKSUM_H */ diff --git a/arch/loongarch/include/asm/cmpxchg.h b/arch/loongarch/include/asm/cmpxchg.h index ecfa6cf79806..979fde61bba8 100644 --- a/arch/loongarch/include/asm/cmpxchg.h +++ b/arch/loongarch/include/asm/cmpxchg.h @@ -62,7 +62,7 @@ static inline unsigned int __xchg_small(volatile void *ptr, unsigned int val, } static __always_inline unsigned long -__xchg(volatile void *ptr, unsigned long x, int size) +__arch_xchg(volatile void *ptr, unsigned long x, int size) { switch (size) { case 1: @@ -87,7 +87,7 @@ __xchg(volatile void *ptr, unsigned long x, int size) __typeof__(*(ptr)) __res; \ \ __res = (__typeof__(*(ptr))) \ - __xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \ + __arch_xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \ \ __res; \ }) diff --git a/arch/loongarch/include/asm/fpu.h b/arch/loongarch/include/asm/fpu.h index 358b254d9c1d..192f8e35d912 100644 --- a/arch/loongarch/include/asm/fpu.h +++ b/arch/loongarch/include/asm/fpu.h @@ -21,6 +21,9 @@ struct sigcontext; +extern void kernel_fpu_begin(void); +extern void kernel_fpu_end(void); + extern void _init_fpu(unsigned int); extern void _save_fp(struct loongarch_fpu *); extern void _restore_fp(struct loongarch_fpu *); diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h index 3418d32d4fc7..23e2ba78dcb0 100644 --- a/arch/loongarch/include/asm/ftrace.h +++ b/arch/loongarch/include/asm/ftrace.h @@ -54,9 +54,46 @@ static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs * return &fregs->regs; } +static __always_inline unsigned long +ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) +{ + return instruction_pointer(&fregs->regs); +} + +static __always_inline void +ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) +{ + regs_set_return_value(&fregs->regs, ip); +} + +#define ftrace_regs_get_argument(fregs, n) \ + regs_get_kernel_argument(&(fregs)->regs, n) +#define ftrace_regs_get_stack_pointer(fregs) \ + kernel_stack_pointer(&(fregs)->regs) +#define ftrace_regs_return_value(fregs) \ + regs_return_value(&(fregs)->regs) +#define ftrace_regs_set_return_value(fregs, ret) \ + regs_set_return_value(&(fregs)->regs, ret) +#define ftrace_override_function_with_return(fregs) \ + override_function_with_return(&(fregs)->regs) +#define ftrace_regs_query_register_offset(name) \ + regs_query_register_offset(name) + #define ftrace_graph_func ftrace_graph_func void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs); + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +static inline void +__arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) +{ + regs->regs[13] = addr; /* t1 */ +} + +#define arch_ftrace_set_direct_caller(fregs, addr) \ + __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h index a04fe755d719..b09887ffcd15 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -121,6 +121,8 @@ enum reg2bstrd_op { }; enum reg3_op { + asrtle_op = 0x02, + asrtgt_op = 0x03, addw_op = 0x20, addd_op = 0x21, subw_op = 0x22, @@ -176,6 +178,30 @@ enum reg3_op { amord_op = 0x70c7, amxorw_op = 0x70c8, amxord_op = 0x70c9, + fldgts_op = 0x70e8, + fldgtd_op = 0x70e9, + fldles_op = 0x70ea, + fldled_op = 0x70eb, + fstgts_op = 0x70ec, + fstgtd_op = 0x70ed, + fstles_op = 0x70ee, + fstled_op = 0x70ef, + ldgtb_op = 0x70f0, + ldgth_op = 0x70f1, + ldgtw_op = 0x70f2, + ldgtd_op = 0x70f3, + ldleb_op = 0x70f4, + ldleh_op = 0x70f5, + ldlew_op = 0x70f6, + ldled_op = 0x70f7, + stgtb_op = 0x70f8, + stgth_op = 0x70f9, + stgtw_op = 0x70fa, + stgtd_op = 0x70fb, + stleb_op = 0x70fc, + stleh_op = 0x70fd, + stlew_op = 0x70fe, + stled_op = 0x70ff, }; enum reg3sa2_op { diff --git a/arch/loongarch/include/asm/local.h b/arch/loongarch/include/asm/local.h index 65fbbae9fc4d..83e995b30e47 100644 --- a/arch/loongarch/include/asm/local.h +++ b/arch/loongarch/include/asm/local.h @@ -56,8 +56,17 @@ static inline long local_sub_return(long i, local_t *l) return result; } -#define local_cmpxchg(l, o, n) \ - ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) +static inline long local_cmpxchg(local_t *l, long old, long new) +{ + return cmpxchg_local(&l->a.counter, old, new); +} + +static inline bool local_try_cmpxchg(local_t *l, long *old, long new) +{ + typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; + return try_cmpxchg_local(&l->a.counter, __old, new); +} + #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) /** diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h index 83da5d29e2d1..b3323ab5b78d 100644 --- a/arch/loongarch/include/asm/loongarch.h +++ b/arch/loongarch/include/asm/loongarch.h @@ -311,8 +311,8 @@ static __always_inline void iocsr_write64(u64 val, u32 reg) #define CSR_ECFG_VS_WIDTH 3 #define CSR_ECFG_VS (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT) #define CSR_ECFG_IM_SHIFT 0 -#define CSR_ECFG_IM_WIDTH 13 -#define CSR_ECFG_IM (_ULCAST_(0x1fff) << CSR_ECFG_IM_SHIFT) +#define CSR_ECFG_IM_WIDTH 14 +#define CSR_ECFG_IM (_ULCAST_(0x3fff) << CSR_ECFG_IM_SHIFT) #define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ #define CSR_ESTAT_ESUBCODE_SHIFT 22 @@ -322,8 +322,8 @@ static __always_inline void iocsr_write64(u64 val, u32 reg) #define CSR_ESTAT_EXC_WIDTH 6 #define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT) #define CSR_ESTAT_IS_SHIFT 0 -#define CSR_ESTAT_IS_WIDTH 15 -#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT) +#define CSR_ESTAT_IS_WIDTH 14 +#define CSR_ESTAT_IS (_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT) #define LOONGARCH_CSR_ERA 0x6 /* ERA */ @@ -1090,7 +1090,7 @@ static __always_inline void iocsr_write64(u64 val, u32 reg) #define ECFGF_IPI (_ULCAST_(1) << ECFGB_IPI) #define ECFGF(hwirq) (_ULCAST_(1) << hwirq) -#define ESTATF_IP 0x00001fff +#define ESTATF_IP 0x00003fff #define LOONGARCH_IOCSR_FEATURES 0x8 #define IOCSRF_TEMP BIT_ULL(0) @@ -1397,7 +1397,7 @@ __BUILD_CSR_OP(tlbidx) #define EXSUBCODE_ADEF 0 /* Fetch Instruction */ #define EXSUBCODE_ADEM 1 /* Access Memory*/ #define EXCCODE_ALE 9 /* Unalign Access */ -#define EXCCODE_OOB 10 /* Out of bounds */ +#define EXCCODE_BCE 10 /* Bounds Check Error */ #define EXCCODE_SYS 11 /* System call */ #define EXCCODE_BP 12 /* Breakpoint */ #define EXCCODE_INE 13 /* Inst. Not Exist */ @@ -1408,33 +1408,38 @@ __BUILD_CSR_OP(tlbidx) #define EXCCODE_FPE 18 /* Floating Point Exception */ #define EXCSUBCODE_FPE 0 /* Floating Point Exception */ #define EXCSUBCODE_VFPE 1 /* Vector Exception */ -#define EXCCODE_WATCH 19 /* Watch address reference */ +#define EXCCODE_WATCH 19 /* WatchPoint Exception */ + #define EXCSUBCODE_WPEF 0 /* ... on Instruction Fetch */ + #define EXCSUBCODE_WPEM 1 /* ... on Memory Accesses */ #define EXCCODE_BTDIS 20 /* Binary Trans. Disabled */ #define EXCCODE_BTE 21 /* Binary Trans. Exception */ -#define EXCCODE_PSI 22 /* Guest Privileged Error */ -#define EXCCODE_HYP 23 /* Hypercall */ +#define EXCCODE_GSPR 22 /* Guest Privileged Error */ +#define EXCCODE_HVC 23 /* Hypercall */ #define EXCCODE_GCM 24 /* Guest CSR modified */ #define EXCSUBCODE_GCSC 0 /* Software caused */ #define EXCSUBCODE_GCHC 1 /* Hardware caused */ #define EXCCODE_SE 25 /* Security */ -#define EXCCODE_INT_START 64 -#define EXCCODE_SIP0 64 -#define EXCCODE_SIP1 65 -#define EXCCODE_IP0 66 -#define EXCCODE_IP1 67 -#define EXCCODE_IP2 68 -#define EXCCODE_IP3 69 -#define EXCCODE_IP4 70 -#define EXCCODE_IP5 71 -#define EXCCODE_IP6 72 -#define EXCCODE_IP7 73 -#define EXCCODE_PMC 74 /* Performance Counter */ -#define EXCCODE_TIMER 75 -#define EXCCODE_IPI 76 -#define EXCCODE_NMI 77 -#define EXCCODE_INT_END 78 -#define EXCCODE_INT_NUM (EXCCODE_INT_END - EXCCODE_INT_START) +/* Interrupt numbers */ +#define INT_SWI0 0 /* Software Interrupts */ +#define INT_SWI1 1 +#define INT_HWI0 2 /* Hardware Interrupts */ +#define INT_HWI1 3 +#define INT_HWI2 4 +#define INT_HWI3 5 +#define INT_HWI4 6 +#define INT_HWI5 7 +#define INT_HWI6 8 +#define INT_HWI7 9 +#define INT_PCOV 10 /* Performance Counter Overflow */ +#define INT_TI 11 /* Timer */ +#define INT_IPI 12 +#define INT_NMI 13 + +/* ExcCodes corresponding to interrupts */ +#define EXCCODE_INT_NUM (INT_NMI + 1) +#define EXCCODE_INT_START 64 +#define EXCCODE_INT_END (EXCCODE_INT_START + EXCCODE_INT_NUM - 1) /* FPU register names */ #define LOONGARCH_FCSR0 $r0 diff --git a/arch/loongarch/include/asm/ptrace.h b/arch/loongarch/include/asm/ptrace.h index d761db943335..35f0958163ac 100644 --- a/arch/loongarch/include/asm/ptrace.h +++ b/arch/loongarch/include/asm/ptrace.h @@ -154,6 +154,11 @@ static inline long regs_return_value(struct pt_regs *regs) return regs->regs[4]; } +static inline void regs_set_return_value(struct pt_regs *regs, unsigned long val) +{ + regs->regs[4] = val; +} + #define instruction_pointer(regs) ((regs)->csr_era) #define profile_pc(regs) instruction_pointer(regs) diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h index d82687390b4a..416b653bccb4 100644 --- a/arch/loongarch/include/asm/smp.h +++ b/arch/loongarch/include/asm/smp.h @@ -99,7 +99,7 @@ static inline void __cpu_die(unsigned int cpu) loongson_cpu_die(cpu); } -extern void play_dead(void); +extern void __noreturn play_dead(void); #endif #endif /* __ASM_SMP_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 78d4e3384305..9a72d91cd104 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -13,7 +13,7 @@ obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_EFI) += efi.o -obj-$(CONFIG_CPU_HAS_FPU) += fpu.o +obj-$(CONFIG_CPU_HAS_FPU) += fpu.o kfpu.o obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c index 4a3ef8516ccc..73858c9029cc 100644 --- a/arch/loongarch/kernel/ftrace_dyn.c +++ b/arch/loongarch/kernel/ftrace_dyn.c @@ -30,19 +30,12 @@ static int ftrace_modify_code(unsigned long pc, u32 old, u32 new, bool validate) return 0; } -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS - #ifdef CONFIG_MODULES -static inline int __get_mod(struct module **mod, unsigned long addr) +static bool reachable_by_bl(unsigned long addr, unsigned long pc) { - preempt_disable(); - *mod = __module_text_address(addr); - preempt_enable(); + long offset = (long)addr - (long)pc; - if (WARN_ON(!(*mod))) - return -EINVAL; - - return 0; + return offset >= -SZ_128M && offset < SZ_128M; } static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr) @@ -58,51 +51,88 @@ static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr) return NULL; } -static unsigned long get_plt_addr(struct module *mod, unsigned long addr) +/* + * Find the address the callsite must branch to in order to reach '*addr'. + * + * Due to the limited range of 'bl' instruction, modules may be placed too far + * away to branch directly and we must use a PLT. + * + * Returns true when '*addr' contains a reachable target address, or has been + * modified to contain a PLT address. Returns false otherwise. + */ +static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, struct module *mod, unsigned long *addr) { + unsigned long pc = rec->ip + LOONGARCH_INSN_SIZE; struct plt_entry *plt; - plt = get_ftrace_plt(mod, addr); - if (!plt) { - pr_err("ftrace: no module PLT for %ps\n", (void *)addr); - return -EINVAL; + /* + * If a custom trampoline is unreachable, rely on the ftrace_regs_caller + * trampoline which knows how to indirectly reach that trampoline through + * ops->direct_call. + */ + if (*addr != FTRACE_ADDR && *addr != FTRACE_REGS_ADDR && !reachable_by_bl(*addr, pc)) + *addr = FTRACE_REGS_ADDR; + + /* + * When the target is within range of the 'bl' instruction, use 'addr' + * as-is and branch to that directly. + */ + if (reachable_by_bl(*addr, pc)) + return true; + + /* + * 'mod' is only set at module load time, but if we end up + * dealing with an out-of-range condition, we can assume it + * is due to a module being loaded far away from the kernel. + * + * NOTE: __module_text_address() must be called with preemption + * disabled, but we can rely on ftrace_lock to ensure that 'mod' + * retains its validity throughout the remainder of this code. + */ + if (!mod) { + preempt_disable(); + mod = __module_text_address(pc); + preempt_enable(); } - return (unsigned long)plt; + if (WARN_ON(!mod)) + return false; + + plt = get_ftrace_plt(mod, *addr); + if (!plt) { + pr_err("ftrace: no module PLT for %ps\n", (void *)*addr); + return false; + } + + *addr = (unsigned long)plt; + return true; +} +#else /* !CONFIG_MODULES */ +static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, struct module *mod, unsigned long *addr) +{ + return true; } #endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { u32 old, new; unsigned long pc; - long offset __maybe_unused; pc = rec->ip + LOONGARCH_INSN_SIZE; -#ifdef CONFIG_MODULES - offset = (long)pc - (long)addr; + if (!ftrace_find_callable_addr(rec, NULL, &addr)) + return -EINVAL; - if (offset < -SZ_128M || offset >= SZ_128M) { - int ret; - struct module *mod; - - ret = __get_mod(&mod, pc); - if (ret) - return ret; - - addr = get_plt_addr(mod, addr); - - old_addr = get_plt_addr(mod, old_addr); - } -#endif + if (!ftrace_find_callable_addr(rec, NULL, &old_addr)) + return -EINVAL; new = larch_insn_gen_bl(pc, addr); old = larch_insn_gen_bl(pc, old_addr); return ftrace_modify_code(pc, old, new, true); } - #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ int ftrace_update_ftrace_func(ftrace_func_t func) @@ -153,24 +183,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { u32 old, new; unsigned long pc; - long offset __maybe_unused; pc = rec->ip + LOONGARCH_INSN_SIZE; -#ifdef CONFIG_MODULES - offset = (long)pc - (long)addr; - - if (offset < -SZ_128M || offset >= SZ_128M) { - int ret; - struct module *mod; - - ret = __get_mod(&mod, pc); - if (ret) - return ret; - - addr = get_plt_addr(mod, addr); - } -#endif + if (!ftrace_find_callable_addr(rec, NULL, &addr)) + return -EINVAL; old = larch_insn_gen_nop(); new = larch_insn_gen_bl(pc, addr); @@ -182,24 +199,11 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long ad { u32 old, new; unsigned long pc; - long offset __maybe_unused; pc = rec->ip + LOONGARCH_INSN_SIZE; -#ifdef CONFIG_MODULES - offset = (long)pc - (long)addr; - - if (offset < -SZ_128M || offset >= SZ_128M) { - int ret; - struct module *mod; - - ret = __get_mod(&mod, pc); - if (ret) - return ret; - - addr = get_plt_addr(mod, addr); - } -#endif + if (!ftrace_find_callable_addr(rec, NULL, &addr)) + return -EINVAL; new = larch_insn_gen_nop(); old = larch_insn_gen_bl(pc, addr); diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S index 44ff1ff64260..78f066384657 100644 --- a/arch/loongarch/kernel/genex.S +++ b/arch/loongarch/kernel/genex.S @@ -82,6 +82,7 @@ SYM_FUNC_END(except_vec_cex) BUILD_HANDLER ade ade badv BUILD_HANDLER ale ale badv + BUILD_HANDLER bce bce none BUILD_HANDLER bp bp none BUILD_HANDLER fpe fpe fcsr BUILD_HANDLER fpu fpu none diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c index 0524bf1169b7..883e5066ae44 100644 --- a/arch/loongarch/kernel/irq.c +++ b/arch/loongarch/kernel/irq.c @@ -92,7 +92,7 @@ static int __init get_ipi_irq(void) struct irq_domain *d = irq_find_matching_fwnode(cpuintc_handle, DOMAIN_BUS_ANY); if (d) - return irq_create_mapping(d, EXCCODE_IPI - EXCCODE_INT_START); + return irq_create_mapping(d, INT_IPI); return -EINVAL; } diff --git a/arch/loongarch/kernel/kfpu.c b/arch/loongarch/kernel/kfpu.c new file mode 100644 index 000000000000..5c46ae8c6cac --- /dev/null +++ b/arch/loongarch/kernel/kfpu.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +#include +#include +#include +#include + +static DEFINE_PER_CPU(bool, in_kernel_fpu); + +void kernel_fpu_begin(void) +{ + preempt_disable(); + + WARN_ON(this_cpu_read(in_kernel_fpu)); + + this_cpu_write(in_kernel_fpu, true); + + if (!is_fpu_owner()) + enable_fpu(); + else + _save_fp(¤t->thread.fpu); + + write_fcsr(LOONGARCH_FCSR0, 0); +} +EXPORT_SYMBOL_GPL(kernel_fpu_begin); + +void kernel_fpu_end(void) +{ + WARN_ON(!this_cpu_read(in_kernel_fpu)); + + if (!is_fpu_owner()) + disable_fpu(); + else + _restore_fp(¤t->thread.fpu); + + this_cpu_write(in_kernel_fpu, false); + + preempt_enable(); +} +EXPORT_SYMBOL_GPL(kernel_fpu_end); diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S index bbabf06244c2..c7d961fc72c2 100644 --- a/arch/loongarch/kernel/mcount_dyn.S +++ b/arch/loongarch/kernel/mcount_dyn.S @@ -42,7 +42,6 @@ .if \allregs PTR_S tp, sp, PT_R2 PTR_S t0, sp, PT_R12 - PTR_S t1, sp, PT_R13 PTR_S t2, sp, PT_R14 PTR_S t3, sp, PT_R15 PTR_S t4, sp, PT_R16 @@ -64,6 +63,8 @@ PTR_S zero, sp, PT_R0 .endif PTR_S ra, sp, PT_ERA /* Save trace function ra at PT_ERA */ + move t1, zero + PTR_S t1, sp, PT_R13 PTR_ADDI t8, sp, PT_SIZE PTR_S t8, sp, PT_R3 .endm @@ -104,8 +105,12 @@ ftrace_common_return: PTR_L a7, sp, PT_R11 PTR_L fp, sp, PT_R22 PTR_L t0, sp, PT_ERA + PTR_L t1, sp, PT_R13 PTR_ADDI sp, sp, PT_SIZE + bnez t1, .Ldirect jr t0 +.Ldirect: + jr t1 SYM_CODE_END(ftrace_common) SYM_CODE_START(ftrace_caller) @@ -147,3 +152,9 @@ SYM_CODE_START(return_to_handler) jr ra SYM_CODE_END(return_to_handler) #endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +SYM_CODE_START(ftrace_stub_direct_tramp) + jr t0 +SYM_CODE_END(ftrace_stub_direct_tramp) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c index 707bd32e5c4f..ff28f99b47d7 100644 --- a/arch/loongarch/kernel/perf_event.c +++ b/arch/loongarch/kernel/perf_event.c @@ -461,7 +461,7 @@ static int get_pmc_irq(void) struct irq_domain *d = irq_find_matching_fwnode(cpuintc_handle, DOMAIN_BUS_ANY); if (d) - return irq_create_mapping(d, EXCCODE_PMC - EXCCODE_INT_START); + return irq_create_mapping(d, INT_PCOV); return -EINVAL; } diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index fa2443c7afb2..b71e17c1cc0c 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -62,7 +62,7 @@ unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; EXPORT_SYMBOL(boot_option_idle_override); #ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { play_dead(); } diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index 8c6e227cb29d..ed167e244cda 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -155,11 +155,11 @@ void loongson_send_ipi_mask(const struct cpumask *mask, unsigned int action) * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { loongson_send_ipi_single(cpu, SMP_RESCHEDULE); } -EXPORT_SYMBOL_GPL(smp_send_reschedule); +EXPORT_SYMBOL_GPL(arch_smp_send_reschedule); irqreturn_t loongson_ipi_interrupt(int irq, void *dev) { @@ -336,7 +336,7 @@ void play_dead(void) iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR); init_fn(); - unreachable(); + BUG(); } #endif diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 4351f69d9950..f377e50f3c66 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -133,7 +133,7 @@ static int get_timer_irq(void) struct irq_domain *d = irq_find_matching_fwnode(cpuintc_handle, DOMAIN_BUS_ANY); if (d) - return irq_create_mapping(d, EXCCODE_TIMER - EXCCODE_INT_START); + return irq_create_mapping(d, INT_TI); return -EINVAL; } diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index de8ebe20b666..8db26e4ca447 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -3,6 +3,7 @@ * Author: Huacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +52,7 @@ extern asmlinkage void handle_ade(void); extern asmlinkage void handle_ale(void); +extern asmlinkage void handle_bce(void); extern asmlinkage void handle_sys(void); extern asmlinkage void handle_bp(void); extern asmlinkage void handle_ri(void); @@ -153,53 +156,210 @@ static void show_code(unsigned int *pc, bool user) pr_cont("\n"); } +static void print_bool_fragment(const char *key, unsigned long val, bool first) +{ + /* e.g. "+PG", "-DA" */ + pr_cont("%s%c%s", first ? "" : " ", val ? '+' : '-', key); +} + +static void print_plv_fragment(const char *key, int val) +{ + /* e.g. "PLV0", "PPLV3" */ + pr_cont("%s%d", key, val); +} + +static void print_memory_type_fragment(const char *key, unsigned long val) +{ + const char *humanized_type; + + switch (val) { + case 0: + humanized_type = "SUC"; + break; + case 1: + humanized_type = "CC"; + break; + case 2: + humanized_type = "WUC"; + break; + default: + pr_cont(" %s=Reserved(%lu)", key, val); + return; + } + + /* e.g. " DATM=WUC" */ + pr_cont(" %s=%s", key, humanized_type); +} + +static void print_intr_fragment(const char *key, unsigned long val) +{ + /* e.g. "LIE=0-1,3,5-7" */ + pr_cont("%s=%*pbl", key, EXCCODE_INT_NUM, &val); +} + +static void print_crmd(unsigned long x) +{ + printk(" CRMD: %08lx (", x); + print_plv_fragment("PLV", (int) FIELD_GET(CSR_CRMD_PLV, x)); + print_bool_fragment("IE", FIELD_GET(CSR_CRMD_IE, x), false); + print_bool_fragment("DA", FIELD_GET(CSR_CRMD_DA, x), false); + print_bool_fragment("PG", FIELD_GET(CSR_CRMD_PG, x), false); + print_memory_type_fragment("DACF", FIELD_GET(CSR_CRMD_DACF, x)); + print_memory_type_fragment("DACM", FIELD_GET(CSR_CRMD_DACM, x)); + print_bool_fragment("WE", FIELD_GET(CSR_CRMD_WE, x), false); + pr_cont(")\n"); +} + +static void print_prmd(unsigned long x) +{ + printk(" PRMD: %08lx (", x); + print_plv_fragment("PPLV", (int) FIELD_GET(CSR_PRMD_PPLV, x)); + print_bool_fragment("PIE", FIELD_GET(CSR_PRMD_PIE, x), false); + print_bool_fragment("PWE", FIELD_GET(CSR_PRMD_PWE, x), false); + pr_cont(")\n"); +} + +static void print_euen(unsigned long x) +{ + printk(" EUEN: %08lx (", x); + print_bool_fragment("FPE", FIELD_GET(CSR_EUEN_FPEN, x), true); + print_bool_fragment("SXE", FIELD_GET(CSR_EUEN_LSXEN, x), false); + print_bool_fragment("ASXE", FIELD_GET(CSR_EUEN_LASXEN, x), false); + print_bool_fragment("BTE", FIELD_GET(CSR_EUEN_LBTEN, x), false); + pr_cont(")\n"); +} + +static void print_ecfg(unsigned long x) +{ + printk(" ECFG: %08lx (", x); + print_intr_fragment("LIE", FIELD_GET(CSR_ECFG_IM, x)); + pr_cont(" VS=%d)\n", (int) FIELD_GET(CSR_ECFG_VS, x)); +} + +static const char *humanize_exc_name(unsigned int ecode, unsigned int esubcode) +{ + /* + * LoongArch users and developers are probably more familiar with + * those names found in the ISA manual, so we are going to print out + * the latter. This will require some mapping. + */ + switch (ecode) { + case EXCCODE_RSV: return "INT"; + case EXCCODE_TLBL: return "PIL"; + case EXCCODE_TLBS: return "PIS"; + case EXCCODE_TLBI: return "PIF"; + case EXCCODE_TLBM: return "PME"; + case EXCCODE_TLBNR: return "PNR"; + case EXCCODE_TLBNX: return "PNX"; + case EXCCODE_TLBPE: return "PPI"; + case EXCCODE_ADE: + switch (esubcode) { + case EXSUBCODE_ADEF: return "ADEF"; + case EXSUBCODE_ADEM: return "ADEM"; + } + break; + case EXCCODE_ALE: return "ALE"; + case EXCCODE_BCE: return "BCE"; + case EXCCODE_SYS: return "SYS"; + case EXCCODE_BP: return "BRK"; + case EXCCODE_INE: return "INE"; + case EXCCODE_IPE: return "IPE"; + case EXCCODE_FPDIS: return "FPD"; + case EXCCODE_LSXDIS: return "SXD"; + case EXCCODE_LASXDIS: return "ASXD"; + case EXCCODE_FPE: + switch (esubcode) { + case EXCSUBCODE_FPE: return "FPE"; + case EXCSUBCODE_VFPE: return "VFPE"; + } + break; + case EXCCODE_WATCH: + switch (esubcode) { + case EXCSUBCODE_WPEF: return "WPEF"; + case EXCSUBCODE_WPEM: return "WPEM"; + } + break; + case EXCCODE_BTDIS: return "BTD"; + case EXCCODE_BTE: return "BTE"; + case EXCCODE_GSPR: return "GSPR"; + case EXCCODE_HVC: return "HVC"; + case EXCCODE_GCM: + switch (esubcode) { + case EXCSUBCODE_GCSC: return "GCSC"; + case EXCSUBCODE_GCHC: return "GCHC"; + } + break; + /* + * The manual did not mention the EXCCODE_SE case, but print out it + * nevertheless. + */ + case EXCCODE_SE: return "SE"; + } + + return "???"; +} + +static void print_estat(unsigned long x) +{ + unsigned int ecode = FIELD_GET(CSR_ESTAT_EXC, x); + unsigned int esubcode = FIELD_GET(CSR_ESTAT_ESUBCODE, x); + + printk("ESTAT: %08lx [%s] (", x, humanize_exc_name(ecode, esubcode)); + print_intr_fragment("IS", FIELD_GET(CSR_ESTAT_IS, x)); + pr_cont(" ECode=%d EsubCode=%d)\n", (int) ecode, (int) esubcode); +} + static void __show_regs(const struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); - unsigned int excsubcode; - unsigned int exccode; - int i; + unsigned int exccode = FIELD_GET(CSR_ESTAT_EXC, regs->csr_estat); show_regs_print_info(KERN_DEFAULT); - /* - * Saved main processor registers - */ - for (i = 0; i < 32; ) { - if ((i % 4) == 0) - printk("$%2d :", i); - pr_cont(" %0*lx", field, regs->regs[i]); + /* Print saved GPRs except $zero (substituting with PC/ERA) */ +#define GPR_FIELD(x) field, regs->regs[x] + printk("pc %0*lx ra %0*lx tp %0*lx sp %0*lx\n", + field, regs->csr_era, GPR_FIELD(1), GPR_FIELD(2), GPR_FIELD(3)); + printk("a0 %0*lx a1 %0*lx a2 %0*lx a3 %0*lx\n", + GPR_FIELD(4), GPR_FIELD(5), GPR_FIELD(6), GPR_FIELD(7)); + printk("a4 %0*lx a5 %0*lx a6 %0*lx a7 %0*lx\n", + GPR_FIELD(8), GPR_FIELD(9), GPR_FIELD(10), GPR_FIELD(11)); + printk("t0 %0*lx t1 %0*lx t2 %0*lx t3 %0*lx\n", + GPR_FIELD(12), GPR_FIELD(13), GPR_FIELD(14), GPR_FIELD(15)); + printk("t4 %0*lx t5 %0*lx t6 %0*lx t7 %0*lx\n", + GPR_FIELD(16), GPR_FIELD(17), GPR_FIELD(18), GPR_FIELD(19)); + printk("t8 %0*lx u0 %0*lx s9 %0*lx s0 %0*lx\n", + GPR_FIELD(20), GPR_FIELD(21), GPR_FIELD(22), GPR_FIELD(23)); + printk("s1 %0*lx s2 %0*lx s3 %0*lx s4 %0*lx\n", + GPR_FIELD(24), GPR_FIELD(25), GPR_FIELD(26), GPR_FIELD(27)); + printk("s5 %0*lx s6 %0*lx s7 %0*lx s8 %0*lx\n", + GPR_FIELD(28), GPR_FIELD(29), GPR_FIELD(30), GPR_FIELD(31)); - i++; - if ((i % 4) == 0) - pr_cont("\n"); + /* The slot for $zero is reused as the syscall restart flag */ + if (regs->regs[0]) + printk("syscall restart flag: %0*lx\n", GPR_FIELD(0)); + + if (user_mode(regs)) { + printk(" ra: %0*lx\n", GPR_FIELD(1)); + printk(" ERA: %0*lx\n", field, regs->csr_era); + } else { + printk(" ra: %0*lx %pS\n", GPR_FIELD(1), (void *) regs->regs[1]); + printk(" ERA: %0*lx %pS\n", field, regs->csr_era, (void *) regs->csr_era); } +#undef GPR_FIELD - /* - * Saved csr registers - */ - printk("era : %0*lx %pS\n", field, regs->csr_era, - (void *) regs->csr_era); - printk("ra : %0*lx %pS\n", field, regs->regs[1], - (void *) regs->regs[1]); - - printk("CSR crmd: %08lx ", regs->csr_crmd); - printk("CSR prmd: %08lx ", regs->csr_prmd); - printk("CSR euen: %08lx ", regs->csr_euen); - printk("CSR ecfg: %08lx ", regs->csr_ecfg); - printk("CSR estat: %08lx ", regs->csr_estat); - - pr_cont("\n"); - - exccode = ((regs->csr_estat) & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; - excsubcode = ((regs->csr_estat) & CSR_ESTAT_ESUBCODE) >> CSR_ESTAT_ESUBCODE_SHIFT; - printk("ExcCode : %x (SubCode %x)\n", exccode, excsubcode); + /* Print saved important CSRs */ + print_crmd(regs->csr_crmd); + print_prmd(regs->csr_prmd); + print_euen(regs->csr_euen); + print_ecfg(regs->csr_ecfg); + print_estat(regs->csr_estat); if (exccode >= EXCCODE_TLBL && exccode <= EXCCODE_ALE) - printk("BadVA : %0*lx\n", field, regs->csr_badvaddr); + printk(" BADV: %0*lx\n", field, regs->csr_badvaddr); - printk("PrId : %08x (%s)\n", read_cpucfg(LOONGARCH_CPUCFG0), - cpu_family_string()); + printk(" PRID: %08x (%s, %s)\n", read_cpucfg(LOONGARCH_CPUCFG0), + cpu_family_string(), cpu_full_name_string()); } void show_regs(struct pt_regs *regs) @@ -430,6 +590,95 @@ static void bug_handler(struct pt_regs *regs) } } +asmlinkage void noinstr do_bce(struct pt_regs *regs) +{ + bool user = user_mode(regs); + unsigned long era = exception_era(regs); + u64 badv = 0, lower = 0, upper = ULONG_MAX; + union loongarch_instruction insn; + irqentry_state_t state = irqentry_enter(regs); + + if (regs->csr_prmd & CSR_PRMD_PIE) + local_irq_enable(); + + current->thread.trap_nr = read_csr_excode(); + + die_if_kernel("Bounds check error in kernel code", regs); + + /* + * Pull out the address that failed bounds checking, and the lower / + * upper bound, by minimally looking at the faulting instruction word + * and reading from the correct register. + */ + if (__get_inst(&insn.word, (u32 *)era, user)) + goto bad_era; + + switch (insn.reg3_format.opcode) { + case asrtle_op: + if (insn.reg3_format.rd != 0) + break; /* not asrtle */ + badv = regs->regs[insn.reg3_format.rj]; + upper = regs->regs[insn.reg3_format.rk]; + break; + + case asrtgt_op: + if (insn.reg3_format.rd != 0) + break; /* not asrtgt */ + badv = regs->regs[insn.reg3_format.rj]; + lower = regs->regs[insn.reg3_format.rk]; + break; + + case ldleb_op: + case ldleh_op: + case ldlew_op: + case ldled_op: + case stleb_op: + case stleh_op: + case stlew_op: + case stled_op: + case fldles_op: + case fldled_op: + case fstles_op: + case fstled_op: + badv = regs->regs[insn.reg3_format.rj]; + upper = regs->regs[insn.reg3_format.rk]; + break; + + case ldgtb_op: + case ldgth_op: + case ldgtw_op: + case ldgtd_op: + case stgtb_op: + case stgth_op: + case stgtw_op: + case stgtd_op: + case fldgts_op: + case fldgtd_op: + case fstgts_op: + case fstgtd_op: + badv = regs->regs[insn.reg3_format.rj]; + lower = regs->regs[insn.reg3_format.rk]; + break; + } + + force_sig_bnderr((void __user *)badv, (void __user *)lower, (void __user *)upper); + +out: + if (regs->csr_prmd & CSR_PRMD_PIE) + local_irq_disable(); + + irqentry_exit(regs, state); + return; + +bad_era: + /* + * Cannot pull out the instruction word, hence cannot provide more + * info than a regular SIGSEGV in this case. + */ + force_sig(SIGSEGV); + goto out; +} + asmlinkage void noinstr do_bp(struct pt_regs *regs) { bool user = user_mode(regs); @@ -792,11 +1041,12 @@ void __init trap_init(void) long i; /* Set interrupt vector handler */ - for (i = EXCCODE_INT_START; i < EXCCODE_INT_END; i++) + for (i = EXCCODE_INT_START; i <= EXCCODE_INT_END; i++) set_handler(i * VECSIZE, handle_vint, VECSIZE); set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE); set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE); + set_handler(EXCCODE_BCE * VECSIZE, handle_bce, VECSIZE); set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE); set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE); set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE); diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile index 40bde632900f..d60d4e096cfa 100644 --- a/arch/loongarch/lib/Makefile +++ b/arch/loongarch/lib/Makefile @@ -4,4 +4,6 @@ # lib-y += delay.o memset.o memcpy.o memmove.o \ - clear_user.o copy_user.o dump_tlb.o unaligned.o + clear_user.o copy_user.o csum.o dump_tlb.o unaligned.o + +obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/loongarch/lib/clear_user.S b/arch/loongarch/lib/clear_user.S index 2dc48e61a2c8..fd1d62b244f2 100644 --- a/arch/loongarch/lib/clear_user.S +++ b/arch/loongarch/lib/clear_user.S @@ -13,7 +13,14 @@ .irp to, 0, 1, 2, 3, 4, 5, 6, 7 .L_fixup_handle_\to\(): - addi.d a0, a1, (\to) * (-8) + sub.d a0, a2, a0 + addi.d a0, a0, (\to) * (-8) + jr ra +.endr + +.irp to, 0, 2, 4 +.L_fixup_handle_s\to\(): + addi.d a0, a1, -\to jr ra .endr @@ -44,7 +51,7 @@ SYM_FUNC_START(__clear_user_generic) 2: move a0, a1 jr ra - _asm_extable 1b, .L_fixup_handle_0 + _asm_extable 1b, .L_fixup_handle_s0 SYM_FUNC_END(__clear_user_generic) /* @@ -54,12 +61,21 @@ SYM_FUNC_END(__clear_user_generic) * a1: size */ SYM_FUNC_START(__clear_user_fast) - beqz a1, 10f + sltui t0, a1, 9 + bnez t0, .Lsmall - ori a2, zero, 64 - blt a1, a2, 9f + add.d a2, a0, a1 +0: st.d zero, a0, 0 + + /* align up address */ + addi.d a0, a0, 8 + bstrins.d a0, zero, 2, 0 + + addi.d a3, a2, -64 + bgeu a0, a3, .Llt64 /* set 64 bytes at a time */ +.Lloop64: 1: st.d zero, a0, 0 2: st.d zero, a0, 8 3: st.d zero, a0, 16 @@ -68,24 +84,95 @@ SYM_FUNC_START(__clear_user_fast) 6: st.d zero, a0, 40 7: st.d zero, a0, 48 8: st.d zero, a0, 56 - addi.d a0, a0, 64 - addi.d a1, a1, -64 - bge a1, a2, 1b - - beqz a1, 10f + bltu a0, a3, .Lloop64 /* set the remaining bytes */ -9: st.b zero, a0, 0 - addi.d a0, a0, 1 - addi.d a1, a1, -1 - bgt a1, zero, 9b +.Llt64: + addi.d a3, a2, -32 + bgeu a0, a3, .Llt32 +9: st.d zero, a0, 0 +10: st.d zero, a0, 8 +11: st.d zero, a0, 16 +12: st.d zero, a0, 24 + addi.d a0, a0, 32 + +.Llt32: + addi.d a3, a2, -16 + bgeu a0, a3, .Llt16 +13: st.d zero, a0, 0 +14: st.d zero, a0, 8 + addi.d a0, a0, 16 + +.Llt16: + addi.d a3, a2, -8 + bgeu a0, a3, .Llt8 +15: st.d zero, a0, 0 + +.Llt8: +16: st.d zero, a2, -8 /* return */ -10: move a0, a1 + move a0, zero + jr ra + + .align 4 +.Lsmall: + pcaddi t0, 4 + slli.d a2, a1, 4 + add.d t0, t0, a2 + jr t0 + + .align 4 + move a0, zero + jr ra + + .align 4 +17: st.b zero, a0, 0 + move a0, zero + jr ra + + .align 4 +18: st.h zero, a0, 0 + move a0, zero + jr ra + + .align 4 +19: st.h zero, a0, 0 +20: st.b zero, a0, 2 + move a0, zero + jr ra + + .align 4 +21: st.w zero, a0, 0 + move a0, zero + jr ra + + .align 4 +22: st.w zero, a0, 0 +23: st.b zero, a0, 4 + move a0, zero + jr ra + + .align 4 +24: st.w zero, a0, 0 +25: st.h zero, a0, 4 + move a0, zero + jr ra + + .align 4 +26: st.w zero, a0, 0 +27: st.w zero, a0, 3 + move a0, zero + jr ra + + .align 4 +28: st.d zero, a0, 0 + move a0, zero jr ra /* fixup and ex_table */ + _asm_extable 0b, .L_fixup_handle_0 _asm_extable 1b, .L_fixup_handle_0 _asm_extable 2b, .L_fixup_handle_1 _asm_extable 3b, .L_fixup_handle_2 @@ -95,4 +182,23 @@ SYM_FUNC_START(__clear_user_fast) _asm_extable 7b, .L_fixup_handle_6 _asm_extable 8b, .L_fixup_handle_7 _asm_extable 9b, .L_fixup_handle_0 + _asm_extable 10b, .L_fixup_handle_1 + _asm_extable 11b, .L_fixup_handle_2 + _asm_extable 12b, .L_fixup_handle_3 + _asm_extable 13b, .L_fixup_handle_0 + _asm_extable 14b, .L_fixup_handle_1 + _asm_extable 15b, .L_fixup_handle_0 + _asm_extable 16b, .L_fixup_handle_1 + _asm_extable 17b, .L_fixup_handle_s0 + _asm_extable 18b, .L_fixup_handle_s0 + _asm_extable 19b, .L_fixup_handle_s0 + _asm_extable 20b, .L_fixup_handle_s2 + _asm_extable 21b, .L_fixup_handle_s0 + _asm_extable 22b, .L_fixup_handle_s0 + _asm_extable 23b, .L_fixup_handle_s4 + _asm_extable 24b, .L_fixup_handle_s0 + _asm_extable 25b, .L_fixup_handle_s4 + _asm_extable 26b, .L_fixup_handle_s0 + _asm_extable 27b, .L_fixup_handle_s4 + _asm_extable 28b, .L_fixup_handle_s0 SYM_FUNC_END(__clear_user_fast) diff --git a/arch/loongarch/lib/copy_user.S b/arch/loongarch/lib/copy_user.S index 55ac6020a1ad..b21f6d5d38f5 100644 --- a/arch/loongarch/lib/copy_user.S +++ b/arch/loongarch/lib/copy_user.S @@ -13,7 +13,14 @@ .irp to, 0, 1, 2, 3, 4, 5, 6, 7 .L_fixup_handle_\to\(): - addi.d a0, a2, (\to) * (-8) + sub.d a0, a2, a0 + addi.d a0, a0, (\to) * (-8) + jr ra +.endr + +.irp to, 0, 2, 4 +.L_fixup_handle_s\to\(): + addi.d a0, a2, -\to jr ra .endr @@ -47,8 +54,8 @@ SYM_FUNC_START(__copy_user_generic) 3: move a0, a2 jr ra - _asm_extable 1b, .L_fixup_handle_0 - _asm_extable 2b, .L_fixup_handle_0 + _asm_extable 1b, .L_fixup_handle_s0 + _asm_extable 2b, .L_fixup_handle_s0 SYM_FUNC_END(__copy_user_generic) /* @@ -59,65 +66,209 @@ SYM_FUNC_END(__copy_user_generic) * a2: n */ SYM_FUNC_START(__copy_user_fast) - beqz a2, 19f + sltui t0, a2, 9 + bnez t0, .Lsmall - ori a3, zero, 64 - blt a2, a3, 17f + add.d a3, a1, a2 + add.d a2, a0, a2 +0: ld.d t0, a1, 0 +1: st.d t0, a0, 0 + + /* align up destination address */ + andi t1, a0, 7 + sub.d t0, zero, t1 + addi.d t0, t0, 8 + add.d a1, a1, t0 + add.d a0, a0, t0 + + addi.d a4, a3, -64 + bgeu a1, a4, .Llt64 /* copy 64 bytes at a time */ -1: ld.d t0, a1, 0 -2: ld.d t1, a1, 8 -3: ld.d t2, a1, 16 -4: ld.d t3, a1, 24 -5: ld.d t4, a1, 32 -6: ld.d t5, a1, 40 -7: ld.d t6, a1, 48 -8: ld.d t7, a1, 56 -9: st.d t0, a0, 0 -10: st.d t1, a0, 8 -11: st.d t2, a0, 16 -12: st.d t3, a0, 24 -13: st.d t4, a0, 32 -14: st.d t5, a0, 40 -15: st.d t6, a0, 48 -16: st.d t7, a0, 56 - - addi.d a0, a0, 64 +.Lloop64: +2: ld.d t0, a1, 0 +3: ld.d t1, a1, 8 +4: ld.d t2, a1, 16 +5: ld.d t3, a1, 24 +6: ld.d t4, a1, 32 +7: ld.d t5, a1, 40 +8: ld.d t6, a1, 48 +9: ld.d t7, a1, 56 addi.d a1, a1, 64 - addi.d a2, a2, -64 - bge a2, a3, 1b - - beqz a2, 19f +10: st.d t0, a0, 0 +11: st.d t1, a0, 8 +12: st.d t2, a0, 16 +13: st.d t3, a0, 24 +14: st.d t4, a0, 32 +15: st.d t5, a0, 40 +16: st.d t6, a0, 48 +17: st.d t7, a0, 56 + addi.d a0, a0, 64 + bltu a1, a4, .Lloop64 /* copy the remaining bytes */ -17: ld.b t0, a1, 0 -18: st.b t0, a0, 0 - addi.d a0, a0, 1 - addi.d a1, a1, 1 - addi.d a2, a2, -1 - bgt a2, zero, 17b +.Llt64: + addi.d a4, a3, -32 + bgeu a1, a4, .Llt32 +18: ld.d t0, a1, 0 +19: ld.d t1, a1, 8 +20: ld.d t2, a1, 16 +21: ld.d t3, a1, 24 + addi.d a1, a1, 32 +22: st.d t0, a0, 0 +23: st.d t1, a0, 8 +24: st.d t2, a0, 16 +25: st.d t3, a0, 24 + addi.d a0, a0, 32 + +.Llt32: + addi.d a4, a3, -16 + bgeu a1, a4, .Llt16 +26: ld.d t0, a1, 0 +27: ld.d t1, a1, 8 + addi.d a1, a1, 16 +28: st.d t0, a0, 0 +29: st.d t1, a0, 8 + addi.d a0, a0, 16 + +.Llt16: + addi.d a4, a3, -8 + bgeu a1, a4, .Llt8 +30: ld.d t0, a1, 0 +31: st.d t0, a0, 0 + +.Llt8: +32: ld.d t0, a3, -8 +33: st.d t0, a2, -8 /* return */ -19: move a0, a2 + move a0, zero + jr ra + + .align 5 +.Lsmall: + pcaddi t0, 8 + slli.d a3, a2, 5 + add.d t0, t0, a3 + jr t0 + + .align 5 + move a0, zero + jr ra + + .align 5 +34: ld.b t0, a1, 0 +35: st.b t0, a0, 0 + move a0, zero + jr ra + + .align 5 +36: ld.h t0, a1, 0 +37: st.h t0, a0, 0 + move a0, zero + jr ra + + .align 5 +38: ld.h t0, a1, 0 +39: ld.b t1, a1, 2 +40: st.h t0, a0, 0 +41: st.b t1, a0, 2 + move a0, zero + jr ra + + .align 5 +42: ld.w t0, a1, 0 +43: st.w t0, a0, 0 + move a0, zero + jr ra + + .align 5 +44: ld.w t0, a1, 0 +45: ld.b t1, a1, 4 +46: st.w t0, a0, 0 +47: st.b t1, a0, 4 + move a0, zero + jr ra + + .align 5 +48: ld.w t0, a1, 0 +49: ld.h t1, a1, 4 +50: st.w t0, a0, 0 +51: st.h t1, a0, 4 + move a0, zero + jr ra + + .align 5 +52: ld.w t0, a1, 0 +53: ld.w t1, a1, 3 +54: st.w t0, a0, 0 +55: st.w t1, a0, 3 + move a0, zero + jr ra + + .align 5 +56: ld.d t0, a1, 0 +57: st.d t0, a0, 0 + move a0, zero jr ra /* fixup and ex_table */ + _asm_extable 0b, .L_fixup_handle_0 _asm_extable 1b, .L_fixup_handle_0 - _asm_extable 2b, .L_fixup_handle_1 - _asm_extable 3b, .L_fixup_handle_2 - _asm_extable 4b, .L_fixup_handle_3 - _asm_extable 5b, .L_fixup_handle_4 - _asm_extable 6b, .L_fixup_handle_5 - _asm_extable 7b, .L_fixup_handle_6 - _asm_extable 8b, .L_fixup_handle_7 + _asm_extable 2b, .L_fixup_handle_0 + _asm_extable 3b, .L_fixup_handle_0 + _asm_extable 4b, .L_fixup_handle_0 + _asm_extable 5b, .L_fixup_handle_0 + _asm_extable 6b, .L_fixup_handle_0 + _asm_extable 7b, .L_fixup_handle_0 + _asm_extable 8b, .L_fixup_handle_0 _asm_extable 9b, .L_fixup_handle_0 - _asm_extable 10b, .L_fixup_handle_1 - _asm_extable 11b, .L_fixup_handle_2 - _asm_extable 12b, .L_fixup_handle_3 - _asm_extable 13b, .L_fixup_handle_4 - _asm_extable 14b, .L_fixup_handle_5 - _asm_extable 15b, .L_fixup_handle_6 - _asm_extable 16b, .L_fixup_handle_7 - _asm_extable 17b, .L_fixup_handle_0 + _asm_extable 10b, .L_fixup_handle_0 + _asm_extable 11b, .L_fixup_handle_1 + _asm_extable 12b, .L_fixup_handle_2 + _asm_extable 13b, .L_fixup_handle_3 + _asm_extable 14b, .L_fixup_handle_4 + _asm_extable 15b, .L_fixup_handle_5 + _asm_extable 16b, .L_fixup_handle_6 + _asm_extable 17b, .L_fixup_handle_7 _asm_extable 18b, .L_fixup_handle_0 + _asm_extable 19b, .L_fixup_handle_0 + _asm_extable 20b, .L_fixup_handle_0 + _asm_extable 21b, .L_fixup_handle_0 + _asm_extable 22b, .L_fixup_handle_0 + _asm_extable 23b, .L_fixup_handle_1 + _asm_extable 24b, .L_fixup_handle_2 + _asm_extable 25b, .L_fixup_handle_3 + _asm_extable 26b, .L_fixup_handle_0 + _asm_extable 27b, .L_fixup_handle_0 + _asm_extable 28b, .L_fixup_handle_0 + _asm_extable 29b, .L_fixup_handle_1 + _asm_extable 30b, .L_fixup_handle_0 + _asm_extable 31b, .L_fixup_handle_0 + _asm_extable 32b, .L_fixup_handle_0 + _asm_extable 33b, .L_fixup_handle_1 + _asm_extable 34b, .L_fixup_handle_s0 + _asm_extable 35b, .L_fixup_handle_s0 + _asm_extable 36b, .L_fixup_handle_s0 + _asm_extable 37b, .L_fixup_handle_s0 + _asm_extable 38b, .L_fixup_handle_s0 + _asm_extable 39b, .L_fixup_handle_s0 + _asm_extable 40b, .L_fixup_handle_s0 + _asm_extable 41b, .L_fixup_handle_s2 + _asm_extable 42b, .L_fixup_handle_s0 + _asm_extable 43b, .L_fixup_handle_s0 + _asm_extable 44b, .L_fixup_handle_s0 + _asm_extable 45b, .L_fixup_handle_s0 + _asm_extable 46b, .L_fixup_handle_s0 + _asm_extable 47b, .L_fixup_handle_s4 + _asm_extable 48b, .L_fixup_handle_s0 + _asm_extable 49b, .L_fixup_handle_s0 + _asm_extable 50b, .L_fixup_handle_s0 + _asm_extable 51b, .L_fixup_handle_s4 + _asm_extable 52b, .L_fixup_handle_s0 + _asm_extable 53b, .L_fixup_handle_s0 + _asm_extable 54b, .L_fixup_handle_s0 + _asm_extable 55b, .L_fixup_handle_s4 + _asm_extable 56b, .L_fixup_handle_s0 + _asm_extable 57b, .L_fixup_handle_s0 SYM_FUNC_END(__copy_user_fast) diff --git a/arch/loongarch/lib/csum.c b/arch/loongarch/lib/csum.c new file mode 100644 index 000000000000..a5e84b403c3b --- /dev/null +++ b/arch/loongarch/lib/csum.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019-2020 Arm Ltd. + +#include +#include +#include + +#include + +static u64 accumulate(u64 sum, u64 data) +{ + sum += data; + if (sum < data) + sum += 1; + return sum; +} + +/* + * We over-read the buffer and this makes KASAN unhappy. Instead, disable + * instrumentation and call kasan explicitly. + */ +unsigned int __no_sanitize_address do_csum(const unsigned char *buff, int len) +{ + unsigned int offset, shift, sum; + const u64 *ptr; + u64 data, sum64 = 0; + + if (unlikely(len == 0)) + return 0; + + offset = (unsigned long)buff & 7; + /* + * This is to all intents and purposes safe, since rounding down cannot + * result in a different page or cache line being accessed, and @buff + * should absolutely not be pointing to anything read-sensitive. We do, + * however, have to be careful not to piss off KASAN, which means using + * unchecked reads to accommodate the head and tail, for which we'll + * compensate with an explicit check up-front. + */ + kasan_check_read(buff, len); + ptr = (u64 *)(buff - offset); + len = len + offset - 8; + + /* + * Head: zero out any excess leading bytes. Shifting back by the same + * amount should be at least as fast as any other way of handling the + * odd/even alignment, and means we can ignore it until the very end. + */ + shift = offset * 8; + data = *ptr++; + data = (data >> shift) << shift; + + /* + * Body: straightforward aligned loads from here on (the paired loads + * underlying the quadword type still only need dword alignment). The + * main loop strictly excludes the tail, so the second loop will always + * run at least once. + */ + while (unlikely(len > 64)) { + __uint128_t tmp1, tmp2, tmp3, tmp4; + + tmp1 = *(__uint128_t *)ptr; + tmp2 = *(__uint128_t *)(ptr + 2); + tmp3 = *(__uint128_t *)(ptr + 4); + tmp4 = *(__uint128_t *)(ptr + 6); + + len -= 64; + ptr += 8; + + /* This is the "don't dump the carry flag into a GPR" idiom */ + tmp1 += (tmp1 >> 64) | (tmp1 << 64); + tmp2 += (tmp2 >> 64) | (tmp2 << 64); + tmp3 += (tmp3 >> 64) | (tmp3 << 64); + tmp4 += (tmp4 >> 64) | (tmp4 << 64); + tmp1 = ((tmp1 >> 64) << 64) | (tmp2 >> 64); + tmp1 += (tmp1 >> 64) | (tmp1 << 64); + tmp3 = ((tmp3 >> 64) << 64) | (tmp4 >> 64); + tmp3 += (tmp3 >> 64) | (tmp3 << 64); + tmp1 = ((tmp1 >> 64) << 64) | (tmp3 >> 64); + tmp1 += (tmp1 >> 64) | (tmp1 << 64); + tmp1 = ((tmp1 >> 64) << 64) | sum64; + tmp1 += (tmp1 >> 64) | (tmp1 << 64); + sum64 = tmp1 >> 64; + } + while (len > 8) { + __uint128_t tmp; + + sum64 = accumulate(sum64, data); + tmp = *(__uint128_t *)ptr; + + len -= 16; + ptr += 2; + + data = tmp >> 64; + sum64 = accumulate(sum64, tmp); + } + if (len > 0) { + sum64 = accumulate(sum64, data); + data = *ptr; + len -= 8; + } + /* + * Tail: zero any over-read bytes similarly to the head, again + * preserving odd/even alignment. + */ + shift = len * -8; + data = (data << shift) >> shift; + sum64 = accumulate(sum64, data); + + /* Finally, folding */ + sum64 += (sum64 >> 32) | (sum64 << 32); + sum = sum64 >> 32; + sum += (sum >> 16) | (sum << 16); + if (offset & 1) + return (u16)swab32(sum); + + return sum >> 16; +} + +__sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, __wsum csum) +{ + __uint128_t src, dst; + u64 sum = (__force u64)csum; + + src = *(const __uint128_t *)saddr->s6_addr; + dst = *(const __uint128_t *)daddr->s6_addr; + + sum += (__force u32)htonl(len); + sum += (u32)proto << 24; + src += (src >> 64) | (src << 64); + dst += (dst >> 64) | (dst << 64); + + sum = accumulate(sum, src >> 64); + sum = accumulate(sum, dst >> 64); + + sum += ((sum >> 32) | (sum << 32)); + return csum_fold((__force __wsum)(sum >> 32)); +} +EXPORT_SYMBOL(csum_ipv6_magic); diff --git a/arch/loongarch/lib/error-inject.c b/arch/loongarch/lib/error-inject.c new file mode 100644 index 000000000000..afc9e1c7c973 --- /dev/null +++ b/arch/loongarch/lib/error-inject.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +void override_function_with_return(struct pt_regs *regs) +{ + instruction_pointer_set(regs, regs->regs[1]); +} +NOKPROBE_SYMBOL(override_function_with_return); diff --git a/arch/loongarch/lib/memcpy.S b/arch/loongarch/lib/memcpy.S index 3b7e1dec7109..39ce6621c704 100644 --- a/arch/loongarch/lib/memcpy.S +++ b/arch/loongarch/lib/memcpy.S @@ -44,6 +44,66 @@ SYM_FUNC_START(__memcpy_generic) SYM_FUNC_END(__memcpy_generic) _ASM_NOKPROBE(__memcpy_generic) + .align 5 +SYM_FUNC_START_NOALIGN(__memcpy_small) + pcaddi t0, 8 + slli.d a2, a2, 5 + add.d t0, t0, a2 + jr t0 + + .align 5 +0: jr ra + + .align 5 +1: ld.b t0, a1, 0 + st.b t0, a0, 0 + jr ra + + .align 5 +2: ld.h t0, a1, 0 + st.h t0, a0, 0 + jr ra + + .align 5 +3: ld.h t0, a1, 0 + ld.b t1, a1, 2 + st.h t0, a0, 0 + st.b t1, a0, 2 + jr ra + + .align 5 +4: ld.w t0, a1, 0 + st.w t0, a0, 0 + jr ra + + .align 5 +5: ld.w t0, a1, 0 + ld.b t1, a1, 4 + st.w t0, a0, 0 + st.b t1, a0, 4 + jr ra + + .align 5 +6: ld.w t0, a1, 0 + ld.h t1, a1, 4 + st.w t0, a0, 0 + st.h t1, a0, 4 + jr ra + + .align 5 +7: ld.w t0, a1, 0 + ld.w t1, a1, 3 + st.w t0, a0, 0 + st.w t1, a0, 3 + jr ra + + .align 5 +8: ld.d t0, a1, 0 + st.d t0, a0, 0 + jr ra +SYM_FUNC_END(__memcpy_small) +_ASM_NOKPROBE(__memcpy_small) + /* * void *__memcpy_fast(void *dst, const void *src, size_t n) * @@ -52,14 +112,27 @@ _ASM_NOKPROBE(__memcpy_generic) * a2: n */ SYM_FUNC_START(__memcpy_fast) - move a3, a0 - beqz a2, 3f + sltui t0, a2, 9 + bnez t0, __memcpy_small - ori a4, zero, 64 - blt a2, a4, 2f + add.d a3, a1, a2 + add.d a2, a0, a2 + ld.d a6, a1, 0 + ld.d a7, a3, -8 + + /* align up destination address */ + andi t1, a0, 7 + sub.d t0, zero, t1 + addi.d t0, t0, 8 + add.d a1, a1, t0 + add.d a5, a0, t0 + + addi.d a4, a3, -64 + bgeu a1, a4, .Llt64 /* copy 64 bytes at a time */ -1: ld.d t0, a1, 0 +.Lloop64: + ld.d t0, a1, 0 ld.d t1, a1, 8 ld.d t2, a1, 16 ld.d t3, a1, 24 @@ -67,32 +140,54 @@ SYM_FUNC_START(__memcpy_fast) ld.d t5, a1, 40 ld.d t6, a1, 48 ld.d t7, a1, 56 - st.d t0, a0, 0 - st.d t1, a0, 8 - st.d t2, a0, 16 - st.d t3, a0, 24 - st.d t4, a0, 32 - st.d t5, a0, 40 - st.d t6, a0, 48 - st.d t7, a0, 56 - - addi.d a0, a0, 64 addi.d a1, a1, 64 - addi.d a2, a2, -64 - bge a2, a4, 1b - - beqz a2, 3f + st.d t0, a5, 0 + st.d t1, a5, 8 + st.d t2, a5, 16 + st.d t3, a5, 24 + st.d t4, a5, 32 + st.d t5, a5, 40 + st.d t6, a5, 48 + st.d t7, a5, 56 + addi.d a5, a5, 64 + bltu a1, a4, .Lloop64 /* copy the remaining bytes */ -2: ld.b t0, a1, 0 - st.b t0, a0, 0 - addi.d a0, a0, 1 - addi.d a1, a1, 1 - addi.d a2, a2, -1 - bgt a2, zero, 2b +.Llt64: + addi.d a4, a3, -32 + bgeu a1, a4, .Llt32 + ld.d t0, a1, 0 + ld.d t1, a1, 8 + ld.d t2, a1, 16 + ld.d t3, a1, 24 + addi.d a1, a1, 32 + st.d t0, a5, 0 + st.d t1, a5, 8 + st.d t2, a5, 16 + st.d t3, a5, 24 + addi.d a5, a5, 32 + +.Llt32: + addi.d a4, a3, -16 + bgeu a1, a4, .Llt16 + ld.d t0, a1, 0 + ld.d t1, a1, 8 + addi.d a1, a1, 16 + st.d t0, a5, 0 + st.d t1, a5, 8 + addi.d a5, a5, 16 + +.Llt16: + addi.d a4, a3, -8 + bgeu a1, a4, .Llt8 + ld.d t0, a1, 0 + st.d t0, a5, 0 + +.Llt8: + st.d a6, a0, 0 + st.d a7, a2, -8 /* return */ -3: move a0, a3 jr ra SYM_FUNC_END(__memcpy_fast) _ASM_NOKPROBE(__memcpy_fast) diff --git a/arch/loongarch/lib/memmove.S b/arch/loongarch/lib/memmove.S index b796c3d6da05..45b725ba7867 100644 --- a/arch/loongarch/lib/memmove.S +++ b/arch/loongarch/lib/memmove.S @@ -11,23 +11,9 @@ #include SYM_FUNC_START(memmove) - blt a0, a1, 1f /* dst < src, memcpy */ - blt a1, a0, 3f /* src < dst, rmemcpy */ + blt a0, a1, memcpy /* dst < src, memcpy */ + blt a1, a0, rmemcpy /* src < dst, rmemcpy */ jr ra /* dst == src, return */ - - /* if (src - dst) < 64, copy 1 byte at a time */ -1: ori a3, zero, 64 - sub.d t0, a1, a0 - blt t0, a3, 2f - b memcpy -2: b __memcpy_generic - - /* if (dst - src) < 64, copy 1 byte at a time */ -3: ori a3, zero, 64 - sub.d t0, a0, a1 - blt t0, a3, 4f - b rmemcpy -4: b __rmemcpy_generic SYM_FUNC_END(memmove) _ASM_NOKPROBE(memmove) @@ -76,50 +62,80 @@ _ASM_NOKPROBE(__rmemcpy_generic) * a2: n */ SYM_FUNC_START(__rmemcpy_fast) - move a3, a0 - beqz a2, 3f + sltui t0, a2, 9 + bnez t0, __memcpy_small - add.d a0, a0, a2 - add.d a1, a1, a2 + add.d a3, a1, a2 + add.d a2, a0, a2 + ld.d a6, a1, 0 + ld.d a7, a3, -8 - ori a4, zero, 64 - blt a2, a4, 2f + /* align up destination address */ + andi t1, a2, 7 + sub.d a3, a3, t1 + sub.d a5, a2, t1 + + addi.d a4, a1, 64 + bgeu a4, a3, .Llt64 /* copy 64 bytes at a time */ -1: ld.d t0, a1, -8 - ld.d t1, a1, -16 - ld.d t2, a1, -24 - ld.d t3, a1, -32 - ld.d t4, a1, -40 - ld.d t5, a1, -48 - ld.d t6, a1, -56 - ld.d t7, a1, -64 - st.d t0, a0, -8 - st.d t1, a0, -16 - st.d t2, a0, -24 - st.d t3, a0, -32 - st.d t4, a0, -40 - st.d t5, a0, -48 - st.d t6, a0, -56 - st.d t7, a0, -64 - - addi.d a0, a0, -64 - addi.d a1, a1, -64 - addi.d a2, a2, -64 - bge a2, a4, 1b - - beqz a2, 3f +.Lloop64: + ld.d t0, a3, -8 + ld.d t1, a3, -16 + ld.d t2, a3, -24 + ld.d t3, a3, -32 + ld.d t4, a3, -40 + ld.d t5, a3, -48 + ld.d t6, a3, -56 + ld.d t7, a3, -64 + addi.d a3, a3, -64 + st.d t0, a5, -8 + st.d t1, a5, -16 + st.d t2, a5, -24 + st.d t3, a5, -32 + st.d t4, a5, -40 + st.d t5, a5, -48 + st.d t6, a5, -56 + st.d t7, a5, -64 + addi.d a5, a5, -64 + bltu a4, a3, .Lloop64 /* copy the remaining bytes */ -2: ld.b t0, a1, -1 - st.b t0, a0, -1 - addi.d a0, a0, -1 - addi.d a1, a1, -1 - addi.d a2, a2, -1 - bgt a2, zero, 2b +.Llt64: + addi.d a4, a1, 32 + bgeu a4, a3, .Llt32 + ld.d t0, a3, -8 + ld.d t1, a3, -16 + ld.d t2, a3, -24 + ld.d t3, a3, -32 + addi.d a3, a3, -32 + st.d t0, a5, -8 + st.d t1, a5, -16 + st.d t2, a5, -24 + st.d t3, a5, -32 + addi.d a5, a5, -32 + +.Llt32: + addi.d a4, a1, 16 + bgeu a4, a3, .Llt16 + ld.d t0, a3, -8 + ld.d t1, a3, -16 + addi.d a3, a3, -16 + st.d t0, a5, -8 + st.d t1, a5, -16 + addi.d a5, a5, -16 + +.Llt16: + addi.d a4, a1, 8 + bgeu a4, a3, .Llt8 + ld.d t0, a3, -8 + st.d t0, a5, -8 + +.Llt8: + st.d a6, a0, 0 + st.d a7, a2, -8 /* return */ -3: move a0, a3 jr ra SYM_FUNC_END(__rmemcpy_fast) _ASM_NOKPROBE(__rmemcpy_fast) diff --git a/arch/loongarch/lib/memset.S b/arch/loongarch/lib/memset.S index a9eb732ab2ad..b39c6194e3ae 100644 --- a/arch/loongarch/lib/memset.S +++ b/arch/loongarch/lib/memset.S @@ -56,39 +56,107 @@ _ASM_NOKPROBE(__memset_generic) * a2: n */ SYM_FUNC_START(__memset_fast) - move a3, a0 - beqz a2, 3f - - ori a4, zero, 64 - blt a2, a4, 2f - /* fill a1 to 64 bits */ fill_to_64 a1 + sltui t0, a2, 9 + bnez t0, .Lsmall + + add.d a2, a0, a2 + st.d a1, a0, 0 + + /* align up address */ + addi.d a3, a0, 8 + bstrins.d a3, zero, 2, 0 + + addi.d a4, a2, -64 + bgeu a3, a4, .Llt64 + /* set 64 bytes at a time */ -1: st.d a1, a0, 0 - st.d a1, a0, 8 - st.d a1, a0, 16 - st.d a1, a0, 24 - st.d a1, a0, 32 - st.d a1, a0, 40 - st.d a1, a0, 48 - st.d a1, a0, 56 - - addi.d a0, a0, 64 - addi.d a2, a2, -64 - bge a2, a4, 1b - - beqz a2, 3f +.Lloop64: + st.d a1, a3, 0 + st.d a1, a3, 8 + st.d a1, a3, 16 + st.d a1, a3, 24 + st.d a1, a3, 32 + st.d a1, a3, 40 + st.d a1, a3, 48 + st.d a1, a3, 56 + addi.d a3, a3, 64 + bltu a3, a4, .Lloop64 /* set the remaining bytes */ -2: st.b a1, a0, 0 - addi.d a0, a0, 1 - addi.d a2, a2, -1 - bgt a2, zero, 2b +.Llt64: + addi.d a4, a2, -32 + bgeu a3, a4, .Llt32 + st.d a1, a3, 0 + st.d a1, a3, 8 + st.d a1, a3, 16 + st.d a1, a3, 24 + addi.d a3, a3, 32 + +.Llt32: + addi.d a4, a2, -16 + bgeu a3, a4, .Llt16 + st.d a1, a3, 0 + st.d a1, a3, 8 + addi.d a3, a3, 16 + +.Llt16: + addi.d a4, a2, -8 + bgeu a3, a4, .Llt8 + st.d a1, a3, 0 + +.Llt8: + st.d a1, a2, -8 /* return */ -3: move a0, a3 + jr ra + + .align 4 +.Lsmall: + pcaddi t0, 4 + slli.d a2, a2, 4 + add.d t0, t0, a2 + jr t0 + + .align 4 +0: jr ra + + .align 4 +1: st.b a1, a0, 0 + jr ra + + .align 4 +2: st.h a1, a0, 0 + jr ra + + .align 4 +3: st.h a1, a0, 0 + st.b a1, a0, 2 + jr ra + + .align 4 +4: st.w a1, a0, 0 + jr ra + + .align 4 +5: st.w a1, a0, 0 + st.b a1, a0, 4 + jr ra + + .align 4 +6: st.w a1, a0, 0 + st.h a1, a0, 4 + jr ra + + .align 4 +7: st.w a1, a0, 0 + st.w a1, a0, 3 + jr ra + + .align 4 +8: st.d a1, a0, 0 jr ra SYM_FUNC_END(__memset_fast) _ASM_NOKPROBE(__memset_fast) diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index 96a0fb4f1af5..b826e9c677b2 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -397,23 +397,22 @@ config SINGLE_MEMORY_CHUNK Say N if not sure. config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" if ADVANCED + int "Order of maximal physically contiguous allocations" if ADVANCED depends on !SINGLE_MEMORY_CHUNK - default "11" + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. For systems that have holes in their physical address space this value also defines the minimal size of the hole that allows freeing unused memory map. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + Don't change if unsure. config 060_WRITETHROUGH bool "Use write-through caching for 68060 supervisor accesses" diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine index 28eebabfd34b..1f3574aef638 100644 --- a/arch/m68k/Kconfig.machine +++ b/arch/m68k/Kconfig.machine @@ -439,15 +439,6 @@ config ROM that can be stored in flash, with possibly the text, and data regions being copied out to RAM at startup. -config ROMBASE - hex "Address of the base of ROM device" - default "0" - depends on ROM - help - Define the address that the ROM region starts at. Some platforms - use this to set their chip select region accordingly for the boot - device. - config ROMVEC hex "Address of the base of the ROM vectors" default "0" @@ -465,14 +456,6 @@ config ROMSTART Define the start address of the system image in ROM. Commonly this is strait after the ROM vectors. -config ROMSIZE - hex "Size of the ROM device" - default "0x100000" - depends on ROM - help - Size of the ROM device. On some platforms this is used to setup - the chip select that controls the boot ROM device. - choice prompt "Kernel executes from" help diff --git a/arch/m68k/include/asm/cmpxchg.h b/arch/m68k/include/asm/cmpxchg.h index 6cf464cdab06..d7f3de9c5d6f 100644 --- a/arch/m68k/include/asm/cmpxchg.h +++ b/arch/m68k/include/asm/cmpxchg.h @@ -9,7 +9,7 @@ extern unsigned long __invalid_xchg_size(unsigned long, volatile void *, int); #ifndef CONFIG_RMW_INSNS -static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +static inline unsigned long __arch_xchg(unsigned long x, volatile void * ptr, int size) { unsigned long flags, tmp; @@ -40,7 +40,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz return x; } #else -static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +static inline unsigned long __arch_xchg(unsigned long x, volatile void * ptr, int size) { switch (size) { case 1: @@ -75,7 +75,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz } #endif -#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));}) +#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__arch_xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));}) #include diff --git a/arch/m68k/include/asm/mcf_pgtable.h b/arch/m68k/include/asm/mcf_pgtable.h index 13741c1245e1..d97fbb812f63 100644 --- a/arch/m68k/include/asm/mcf_pgtable.h +++ b/arch/m68k/include/asm/mcf_pgtable.h @@ -46,7 +46,7 @@ #define _CACHEMASK040 (~0x060) #define _PAGE_GLOBAL040 0x400 /* 68040 global bit, used for kva descs */ -/* We borrow bit 24 to store the exclusive marker in swap PTEs. */ +/* We borrow bit 7 to store the exclusive marker in swap PTEs. */ #define _PAGE_SWP_EXCLUSIVE CF_PAGE_NOCACHE /* diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index b9f6908a31bc..ba468b5f3f0b 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -858,11 +858,17 @@ static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs * } static inline void __user * -get_sigframe(struct ksignal *ksig, size_t frame_size) +get_sigframe(struct ksignal *ksig, struct pt_regs *tregs, size_t frame_size) { unsigned long usp = sigsp(rdusp(), ksig); + unsigned long gap = 0; - return (void __user *)((usp - frame_size) & -8UL); + if (CPU_IS_020_OR_030 && tregs->format == 0xb) { + /* USP is unreliable so use worst-case value */ + gap = 256; + } + + return (void __user *)((usp - gap - frame_size) & -8UL); } static int setup_frame(struct ksignal *ksig, sigset_t *set, @@ -880,7 +886,7 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, return -EFAULT; } - frame = get_sigframe(ksig, sizeof(*frame) + fsize); + frame = get_sigframe(ksig, tregs, sizeof(*frame) + fsize); if (fsize) err |= copy_to_user (frame + 1, regs + 1, fsize); @@ -952,7 +958,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, return -EFAULT; } - frame = get_sigframe(ksig, sizeof(*frame)); + frame = get_sigframe(ksig, tregs, sizeof(*frame)); if (fsize) err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 5d04438ee12e..caad195ba5c1 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -29,7 +29,6 @@ platform-$(CONFIG_SGI_IP30) += sgi-ip30/ platform-$(CONFIG_SGI_IP32) += sgi-ip32/ platform-$(CONFIG_SIBYTE_BCM112X) += sibyte/ platform-$(CONFIG_SIBYTE_SB1250) += sibyte/ -platform-$(CONFIG_SIBYTE_BCM1x55) += sibyte/ platform-$(CONFIG_SIBYTE_BCM1x80) += sibyte/ platform-$(CONFIG_SNI_RM) += sni/ platform-$(CONFIG_MACH_TX49XX) += txx9/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 916af9cbac65..675a8660cb85 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -16,7 +16,6 @@ config MIPS select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_KEEP_MEMBLOCK - select ARCH_SUPPORTS_UPROBES select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select ARCH_USE_MEMTEST @@ -80,6 +79,7 @@ config MIPS select HAVE_LD_DEAD_CODE_DATA_ELIMINATION select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI + select HAVE_PATA_PLATFORM select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP @@ -113,7 +113,6 @@ config MACH_INGENIC select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_ZBOOT select DMA_NONCOHERENT - select ARCH_HAS_SYNC_DMA_FOR_CPU select IRQ_MIPS_CPU select PINCTRL select GPIOLIB @@ -132,7 +131,6 @@ choice config MIPS_GENERIC_KERNEL bool "Generic board-agnostic MIPS kernel" - select ARCH_HAS_SETUP_DMA_OPS select MIPS_GENERIC select BOOT_RAW select BUILTIN_DTB @@ -488,7 +486,6 @@ config MACH_LOONGSON64 select BOARD_SCACHE select CSRC_R4K select CEVT_R4K - select CPU_HAS_WB select FORCE_PCI select ISA select I8259 @@ -565,7 +562,6 @@ config MIPS_MALTA select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_MICROMIPS select SYS_SUPPORTS_MIPS16 - select SYS_SUPPORTS_MIPS_CMP select SYS_SUPPORTS_MIPS_CPS select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_RELOCATABLE @@ -793,24 +789,6 @@ config SGI_IP32 help If you want this kernel to run on SGI O2 workstation, say Y here. -config SIBYTE_CRHINE - bool "Sibyte BCM91120C-CRhine" - select BOOT_ELF32 - select SIBYTE_BCM1120 - select SWAP_IO_SPACE - select SYS_HAS_CPU_SB1 - select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_LITTLE_ENDIAN - -config SIBYTE_CARMEL - bool "Sibyte BCM91120x-Carmel" - select BOOT_ELF32 - select SIBYTE_BCM1120 - select SWAP_IO_SPACE - select SYS_HAS_CPU_SB1 - select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_LITTLE_ENDIAN - config SIBYTE_CRHONE bool "Sibyte BCM91125C-CRhone" select BOOT_ELF32 @@ -824,7 +802,7 @@ config SIBYTE_CRHONE config SIBYTE_RHONE bool "Sibyte BCM91125E-Rhone" select BOOT_ELF32 - select SIBYTE_BCM1125H + select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 select SYS_SUPPORTS_BIG_ENDIAN @@ -1075,7 +1053,7 @@ config FW_CFE bool config ARCH_SUPPORTS_UPROBES - bool + def_bool y config DMA_NONCOHERENT bool @@ -1086,8 +1064,10 @@ config DMA_NONCOHERENT # by pgprot_writcombine can be mixed, and the latter sometimes provides # significant advantages. # + select ARCH_HAS_SETUP_DMA_OPS select ARCH_HAS_DMA_WRITE_COMBINE select ARCH_HAS_DMA_PREP_COHERENT + select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_DMA_SET_UNCACHED select DMA_NONCOHERENT_MMAP @@ -1181,12 +1161,6 @@ config SYS_SUPPORTS_LITTLE_ENDIAN config MIPS_HUGE_TLB_SUPPORT def_bool HUGETLB_PAGE || TRANSPARENT_HUGEPAGE -config IRQ_MSP_SLP - bool - -config IRQ_MSP_CIC - bool - config IRQ_TXX9 bool @@ -1364,7 +1338,6 @@ config CPU_LOONGSON2F bool "Loongson 2F" depends on SYS_HAS_CPU_LOONGSON2F select CPU_LOONGSON2EF - select GPIOLIB help The Loongson 2F processor implements the MIPS III instruction set with many extensions. @@ -1786,7 +1759,6 @@ config CPU_LOONGSON2EF select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM select CPU_SUPPORTS_HUGEPAGES - select ARCH_HAS_PHYS_TO_DMA config CPU_LOONGSON32 bool @@ -1851,11 +1823,9 @@ config SYS_HAS_CPU_MIPS32_R3_5 config SYS_HAS_CPU_MIPS32_R5 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS32_R6 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS64_R1 bool @@ -1865,15 +1835,12 @@ config SYS_HAS_CPU_MIPS64_R2 config SYS_HAS_CPU_MIPS64_R5 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_MIPS64_R6 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_P5600 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_R3000 bool @@ -1898,7 +1865,6 @@ config SYS_HAS_CPU_NEVADA config SYS_HAS_CPU_R10000 bool - select ARCH_HAS_SYNC_DMA_FOR_CPU if DMA_NONCOHERENT config SYS_HAS_CPU_RM7000 bool @@ -1927,7 +1893,6 @@ config SYS_HAS_CPU_BMIPS4380 config SYS_HAS_CPU_BMIPS5000 bool select SYS_HAS_CPU_BMIPS - select ARCH_HAS_SYNC_DMA_FOR_CPU # # CPU may reorder R->R, R->W, W->R, W->W @@ -2135,14 +2100,10 @@ endchoice config ARCH_FORCE_MAX_ORDER int "Maximum zone order" - range 14 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB - default "14" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB - range 13 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB - default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB - range 12 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB - default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB - range 0 64 - default "11" + default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB + default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB + default "11" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB + default "10" help The kernel memory allocator divides physically contiguous memory blocks into "zones", where each zone is a power of two number of @@ -2151,9 +2112,6 @@ config ARCH_FORCE_MAX_ORDER blocks of physically contiguous memory, then you may need to increase this value. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. - The page size is not necessarily 4KB. Keep this in mind when choosing a value for this option. @@ -2298,15 +2256,10 @@ config MIPS_VPE_LOADER Includes a loader for loading an elf relocatable object onto another VPE and running it. -config MIPS_VPE_LOADER_CMP - bool - default "y" - depends on MIPS_VPE_LOADER && MIPS_CMP - config MIPS_VPE_LOADER_MT bool default "y" - depends on MIPS_VPE_LOADER && !MIPS_CMP + depends on MIPS_VPE_LOADER config MIPS_VPE_LOADER_TOM bool "Load VPE program into memory hidden from linux" @@ -2322,31 +2275,10 @@ config MIPS_VPE_APSP_API bool "Enable support for AP/SP API (RTLX)" depends on MIPS_VPE_LOADER -config MIPS_VPE_APSP_API_CMP - bool - default "y" - depends on MIPS_VPE_APSP_API && MIPS_CMP - config MIPS_VPE_APSP_API_MT bool default "y" - depends on MIPS_VPE_APSP_API && !MIPS_CMP - -config MIPS_CMP - bool "MIPS CMP framework support (DEPRECATED)" - depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 - select SMP - select SYNC_R4K - select SYS_SUPPORTS_SMP - select WEAK_ORDERING - default n - help - Select this if you are using a bootloader which implements the "CMP - framework" protocol (ie. YAMON) and want your kernel to make use of - its ability to start secondary CPUs. - - Unless you have a specific need, you should use CONFIG_MIPS_CPS - instead of this. + depends on MIPS_VPE_APSP_API config MIPS_CPS bool "MIPS Coherent Processing System support" @@ -2802,9 +2734,6 @@ config HOTPLUG_CPU config SMP_UP bool -config SYS_SUPPORTS_MIPS_CMP - bool - config SYS_SUPPORTS_MIPS_CPS bool diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 04e46ec24319..a7a4ee66a9d3 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -181,9 +181,47 @@ endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -Wa,--trap +# Some -march= flags enable MMI instructions, and GCC complains about that +# support being enabled alongside -msoft-float. Thus explicitly disable MMI. +cflags-$(CONFIG_CPU_LOONGSON2EF) += $(call cc-option,-mno-loongson-mmi) +ifdef CONFIG_CPU_LOONGSON64 +cflags-$(CONFIG_CPU_LOONGSON64) += -Wa,--trap +cflags-$(CONFIG_CC_IS_GCC) += -march=loongson3a +cflags-$(CONFIG_CC_IS_CLANG) += -march=mips64r2 +endif +cflags-$(CONFIG_CPU_LOONGSON64) += $(call cc-option,-mno-loongson-mmi) + cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,) +ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS +cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa,-mfix-loongson2f-nop +cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa,-mfix-loongson2f-jump +endif + +# +# Some versions of binutils, not currently mainline as of 2019/02/04, support +# an -mfix-loongson3-llsc flag which emits a sync prior to each ll instruction +# to work around a CPU bug (see __SYNC_loongson3_war in asm/sync.h for a +# description). +# +# We disable this in order to prevent the assembler meddling with the +# instruction that labels refer to, ie. if we label an ll instruction: +# +# 1: ll v0, 0(a0) +# +# ...then with the assembler fix applied the label may actually point at a sync +# instruction inserted by the assembler, and if we were using the label in an +# exception table the table would no longer contain the address of the ll +# instruction. +# +# Avoid this by explicitly disabling that assembler behaviour. If upstream +# binutils does not merge support for the flag then we can revisit & remove +# this later - for now it ensures vendor toolchains don't cause problems. +# +cflags-$(CONFIG_CPU_LOONGSON64) += $(call as-option,-Wa$(comma)-mno-fix-loongson3-llsc,) # For smartmips configurations, there are hundreds of warnings due to ISA overrides # in assembly and header files. smartmips is only supported for MIPS32r1 onwards diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index 5ab043000409..6a3c890f7bbf 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -30,6 +30,7 @@ * */ +#include /* for dma_default_coherent */ #include #include #include @@ -623,17 +624,18 @@ u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags) dp->dscr_cmd0 &= ~DSCR_CMD0_IE; /* - * There is an errata on the Au1200/Au1550 parts that could result - * in "stale" data being DMA'ed. It has to do with the snoop logic on - * the cache eviction buffer. DMA_NONCOHERENT is on by default for - * these parts. If it is fixed in the future, these dma_cache_inv will - * just be nothing more than empty macros. See io.h. + * There is an erratum on certain Au1200/Au1550 revisions that could + * result in "stale" data being DMA'ed. It has to do with the snoop + * logic on the cache eviction buffer. dma_default_coherent is set + * to false on these parts. */ - dma_cache_wback_inv((unsigned long)buf, nbytes); + if (!dma_default_coherent) + dma_cache_wback_inv(KSEG0ADDR(buf), nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ wmb(); /* drain writebuffer */ dma_cache_wback_inv((unsigned long)dp, sizeof(*dp)); ctp->chan_ptr->ddma_dbell = 0; + wmb(); /* force doorbell write out to dma engine */ /* Get next descriptor pointer. */ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); @@ -685,17 +687,18 @@ u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags) dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1); #endif /* - * There is an errata on the Au1200/Au1550 parts that could result in - * "stale" data being DMA'ed. It has to do with the snoop logic on the - * cache eviction buffer. DMA_NONCOHERENT is on by default for these - * parts. If it is fixed in the future, these dma_cache_inv will just - * be nothing more than empty macros. See io.h. + * There is an erratum on certain Au1200/Au1550 revisions that could + * result in "stale" data being DMA'ed. It has to do with the snoop + * logic on the cache eviction buffer. dma_default_coherent is set + * to false on these parts. */ - dma_cache_inv((unsigned long)buf, nbytes); + if (!dma_default_coherent) + dma_cache_inv(KSEG0ADDR(buf), nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ wmb(); /* drain writebuffer */ dma_cache_wback_inv((unsigned long)dp, sizeof(*dp)); ctp->chan_ptr->ddma_dbell = 0; + wmb(); /* force doorbell write out to dma engine */ /* Get next descriptor pointer. */ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 7367416642cb..04154128c4de 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -29,20 +29,4 @@ config SOC_QCA955X config PCI_AR724X def_bool n -config ATH79_DEV_GPIO_BUTTONS - def_bool n - -config ATH79_DEV_LEDS_GPIO - def_bool n - -config ATH79_DEV_SPI - def_bool n - -config ATH79_DEV_USB - def_bool n - -config ATH79_DEV_WMAC - depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X) - def_bool n - endif diff --git a/arch/mips/bcm47xx/board.c b/arch/mips/bcm47xx/board.c index 90fb48b046c0..b487f687f62d 100644 --- a/arch/mips/bcm47xx/board.c +++ b/arch/mips/bcm47xx/board.c @@ -193,6 +193,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = { /* boardtype, boardnum, boardrev */ static const struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = { + {{BCM47XX_BOARD_HUAWEI_B593U_12, "Huawei B593u-12"}, "0x053d", "1234", "0x1301"}, {{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"}, {{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"}, {{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"}, diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c index 8e257d0896d2..64e37505b9b4 100644 --- a/arch/mips/bcm47xx/leds.c +++ b/arch/mips/bcm47xx/leds.c @@ -222,6 +222,11 @@ bcm47xx_leds_dlink_dir330[] __initconst = { /* Huawei */ +static const struct gpio_led +bcm47xx_leds_huawei_b593u_12[] __initconst = { + BCM47XX_GPIO_LED(5, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), +}; + static const struct gpio_led bcm47xx_leds_huawei_e970[] __initconst = { BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF), @@ -672,6 +677,9 @@ void __init bcm47xx_leds_register(void) bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330); break; + case BCM47XX_BOARD_HUAWEI_B593U_12: + bcm47xx_set_pdata(bcm47xx_leds_huawei_b593u_12); + break; case BCM47XX_BOARD_HUAWEI_E970: bcm47xx_set_pdata(bcm47xx_leds_huawei_e970); break; diff --git a/arch/mips/boot/tools/relocs.c b/arch/mips/boot/tools/relocs.c index 02fc85f3e8ff..a88d66c46d7f 100644 --- a/arch/mips/boot/tools/relocs.c +++ b/arch/mips/boot/tools/relocs.c @@ -245,7 +245,7 @@ static void read_ehdr(FILE *fp) die("Unknown ELF version\n"); if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) - die("Bad Elf header size\n"); + die("Bad ELF header size\n"); if (ehdr.e_phentsize != sizeof(Elf_Phdr)) die("Bad program header entry\n"); diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index c1899f109e19..450e979ef5d9 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -14,7 +14,8 @@ config CAVIUM_CN63XXP1 config CAVIUM_OCTEON_CVMSEG_SIZE int "Number of L1 cache lines reserved for CVMSEG memory" range 0 54 - default 1 + default 0 if !CAVIUM_OCTEON_SOC + default 1 if CAVIUM_OCTEON_SOC help CVMSEG LM is a segment that accesses portions of the dcache as a local memory; the larger CVMSEG is, the smaller the cache is. diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index fd8043f6ff8a..8425a6b38aa2 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2290,7 +2290,7 @@ static irqreturn_t octeon_irq_cib_handler(int my_irq, void *data) static int __init octeon_irq_init_cib(struct device_node *ciu_node, struct device_node *parent) { - const __be32 *addr; + struct resource res; u32 val; struct octeon_irq_cib_host_data *host_data; int parent_irq; @@ -2309,21 +2309,19 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, return -ENOMEM; raw_spin_lock_init(&host_data->lock); - addr = of_get_address(ciu_node, 0, NULL, NULL); - if (!addr) { + r = of_address_to_resource(ciu_node, 0, &res); + if (r) { pr_err("ERROR: Couldn't acquire reg(0) %pOFn\n", ciu_node); - return -EINVAL; + return r; } - host_data->raw_reg = (u64)phys_to_virt( - of_translate_address(ciu_node, addr)); + host_data->raw_reg = (u64)phys_to_virt(res.start); - addr = of_get_address(ciu_node, 1, NULL, NULL); - if (!addr) { + r = of_address_to_resource(ciu_node, 1, &res); + if (r) { pr_err("ERROR: Couldn't acquire reg(1) %pOFn\n", ciu_node); - return -EINVAL; + return r; } - host_data->en_reg = (u64)phys_to_virt( - of_translate_address(ciu_node, addr)); + host_data->en_reg = (u64)phys_to_virt(res.start); r = of_property_read_u32(ciu_node, "cavium,max-bits", &val); if (r) { @@ -2874,11 +2872,11 @@ static struct irq_chip octeon_irq_chip_ciu3_mbox = { static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, struct device_node *parent) { - int i; + int i, ret; int node; struct irq_domain *domain; struct octeon_ciu3_info *ciu3_info; - const __be32 *zero_addr; + struct resource res; u64 base_addr; union cvmx_ciu3_const consts; @@ -2888,14 +2886,11 @@ static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, if (!ciu3_info) return -ENOMEM; - zero_addr = of_get_address(ciu_node, 0, NULL, NULL); - if (WARN_ON(!zero_addr)) - return -EINVAL; + ret = of_address_to_resource(ciu_node, 0, &res); + if (WARN_ON(ret)) + return ret; - base_addr = of_translate_address(ciu_node, zero_addr); - base_addr = (u64)phys_to_virt(base_addr); - - ciu3_info->ciu3_addr = base_addr; + ciu3_info->ciu3_addr = base_addr = (u64)phys_to_virt(res.start); ciu3_info->node = node; consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST); diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index a71727f7a608..c5561016f577 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -72,7 +72,7 @@ extern void pci_console_init(const char *arg); static unsigned long long max_memory = ULLONG_MAX; static unsigned long long reserve_low_mem; -DEFINE_SEMAPHORE(octeon_bootbus_sem); +DEFINE_SEMAPHORE(octeon_bootbus_sem, 1); EXPORT_SYMBOL(octeon_bootbus_sem); static struct octeon_boot_descriptor *octeon_boot_desc_ptr; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 89954f5f87fb..4212584e6efa 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include diff --git a/arch/mips/configs/generic/board-virt.config b/arch/mips/configs/generic/board-virt.config new file mode 100644 index 000000000000..5594f9e5c3a8 --- /dev/null +++ b/arch/mips/configs/generic/board-virt.config @@ -0,0 +1,38 @@ +CONFIG_COMMON_CLK=y + +CONFIG_GOLDFISH=y +CONFIG_GOLDFISH_PIC=y + +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_HOST_GENERIC=y + +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_SYSCON_REBOOT_MODE=y + +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_GOLDFISH=y + +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y + +CONFIG_MTD=y +CONFIG_MTD_CFI=y + +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_XHCI_HCD=y + +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_NET=y +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index e1b66aac7025..a5c68e9b0482 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -497,7 +497,6 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_USB_UHCI_HCD=m -CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m CONFIG_USB_SL811_CS=m CONFIG_USB_ACM=m @@ -554,7 +553,6 @@ CONFIG_USB_LCD=m CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYTHERM=m CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_LD=m diff --git a/arch/mips/fw/lib/cmdline.c b/arch/mips/fw/lib/cmdline.c index f24cbb4a39b5..892765b742bb 100644 --- a/arch/mips/fw/lib/cmdline.c +++ b/arch/mips/fw/lib/cmdline.c @@ -53,7 +53,7 @@ char *fw_getenv(char *envname) { char *result = NULL; - if (_fw_envp != NULL) { + if (_fw_envp != NULL && fw_envp(0) != NULL) { /* * Return a pointer to the given environment variable. * YAMON uses "name", "value" pairs, while U-Boot uses diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 1c4438f3f2ab..067a635d3bc8 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -45,12 +45,12 @@ #endif #ifdef CONFIG_CPU_HAS_DIEI - .macro local_irq_enable reg=t0 + .macro local_irq_enable ei irq_enable_hazard .endm - .macro local_irq_disable reg=t0 + .macro local_irq_disable di irq_disable_hazard .endm diff --git a/arch/mips/include/asm/bugs.h b/arch/mips/include/asm/bugs.h index d72dc6e1cf3c..653f78f3a685 100644 --- a/arch/mips/include/asm/bugs.h +++ b/arch/mips/include/asm/bugs.h @@ -24,13 +24,7 @@ extern void check_bugs64_early(void); extern void check_bugs32(void); extern void check_bugs64(void); -static inline void check_bugs_early(void) -{ - if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64)) - check_bugs64_early(); -} - -static inline void check_bugs(void) +static inline void __init check_bugs(void) { unsigned int cpu = smp_processor_id(); diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 29187e12b861..3424a7908c0f 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -16,4 +16,6 @@ #define __read_mostly __section(".data..read_mostly") +extern void cache_noop(void); + #endif /* _ASM_CACHE_H */ diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index b3dc9c589442..d8d3f80f9fc0 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -110,7 +110,6 @@ extern void copy_from_user_page(struct vm_area_struct *vma, unsigned long len); extern void (*flush_icache_all)(void); -extern void (*local_flush_data_cache_page)(void * addr); extern void (*flush_data_cache_page)(unsigned long addr); /* Run kernel code uncached, useful for cache probing functions. */ diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h index 7ec9493b2861..feed343ad483 100644 --- a/arch/mips/include/asm/cmpxchg.h +++ b/arch/mips/include/asm/cmpxchg.h @@ -68,7 +68,7 @@ extern unsigned long __xchg_small(volatile void *ptr, unsigned long val, unsigned int size); static __always_inline -unsigned long __xchg(volatile void *ptr, unsigned long x, int size) +unsigned long __arch_xchg(volatile void *ptr, unsigned long x, int size) { switch (size) { case 1: @@ -102,7 +102,7 @@ unsigned long __xchg(volatile void *ptr, unsigned long x, int size) smp_mb__before_llsc(); \ \ __res = (__typeof__(*(ptr))) \ - __xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \ + __arch_xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \ \ smp_llsc_mb(); \ \ diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index c0983130a44c..51a1737b03d0 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -118,10 +118,27 @@ #define cpu_has_3k_cache __isa_lt_and_opt(1, MIPS_CPU_3K_CACHE) #endif #ifndef cpu_has_4k_cache -#define cpu_has_4k_cache __isa_ge_or_opt(1, MIPS_CPU_4K_CACHE) +#define cpu_has_4k_cache __opt(MIPS_CPU_4K_CACHE) #endif #ifndef cpu_has_octeon_cache -#define cpu_has_octeon_cache 0 +#define cpu_has_octeon_cache \ +({ \ + int __res; \ + \ + switch (current_cpu_type()) { \ + case CPU_CAVIUM_OCTEON: \ + case CPU_CAVIUM_OCTEON_PLUS: \ + case CPU_CAVIUM_OCTEON2: \ + case CPU_CAVIUM_OCTEON3: \ + __res = 1; \ + break; \ + \ + default: \ + __res = 0; \ + } \ + \ + __res; \ +}) #endif /* Don't override `cpu_has_fpu' to 1 or the "nofpu" option won't work. */ #ifndef cpu_has_fpu diff --git a/arch/mips/include/asm/fixmap.h b/arch/mips/include/asm/fixmap.h index beea14761cef..b037718d7e8b 100644 --- a/arch/mips/include/asm/fixmap.h +++ b/arch/mips/include/asm/fixmap.h @@ -70,7 +70,7 @@ enum fixed_addresses { #include /* - * Called from pgtable_init() + * Called from pagetable_init() */ extern void fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base); diff --git a/arch/mips/include/asm/ide.h b/arch/mips/include/asm/ide.h deleted file mode 100644 index bb674c3b0303..000000000000 --- a/arch/mips/include/asm/ide.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * This file contains the MIPS architecture specific IDE code. - */ -#ifndef __ASM_IDE_H -#define __ASM_IDE_H - -#include - -#endif /* __ASM_IDE_H */ diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index e6d5ccaa309e..cc28d207a061 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -210,7 +210,7 @@ void iounmap(const volatile void __iomem *addr); #define ioremap_wc(offset, size) \ ioremap_prot((offset), (size), boot_cpu_data.writecombine) -#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_CPU_LOONGSON64) +#if defined(CONFIG_CPU_CAVIUM_OCTEON) #define war_io_reorder_wmb() wmb() #else #define war_io_reorder_wmb() barrier() diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 2803c9c21ef9..957121a495f0 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -757,7 +757,7 @@ struct kvm_mips_callbacks { int (*vcpu_run)(struct kvm_vcpu *vcpu); void (*vcpu_reenter)(struct kvm_vcpu *vcpu); }; -extern struct kvm_mips_callbacks *kvm_mips_callbacks; +extern const struct kvm_mips_callbacks * const kvm_mips_callbacks; int kvm_mips_emulation_init(void); /* Debug: dump vcpu state */ diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h index 08366b1fd273..5daf6fe8e3e9 100644 --- a/arch/mips/include/asm/local.h +++ b/arch/mips/include/asm/local.h @@ -94,8 +94,17 @@ static __inline__ long local_sub_return(long i, local_t * l) return result; } -#define local_cmpxchg(l, o, n) \ - ((long)cmpxchg_local(&((l)->a.counter), (o), (n))) +static __inline__ long local_cmpxchg(local_t *l, long old, long new) +{ + return cmpxchg_local(&l->a.counter, old, new); +} + +static __inline__ bool local_try_cmpxchg(local_t *l, long *old, long new) +{ + typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; + return try_cmpxchg_local(&l->a.counter, __old, new); +} + #define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n))) /** diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h index 3c401f11655e..4bd8c86ec6c3 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h @@ -53,6 +53,7 @@ enum bcm47xx_board { BCM47XX_BOARD_DLINK_DIR130, BCM47XX_BOARD_DLINK_DIR330, + BCM47XX_BOARD_HUAWEI_B593U_12, BCM47XX_BOARD_HUAWEI_E970, BCM47XX_BOARD_LINKSYS_E900V1, diff --git a/arch/mips/include/asm/mach-generic/ide.h b/arch/mips/include/asm/mach-generic/ide.h deleted file mode 100644 index 4ae5fbcb15a5..000000000000 --- a/arch/mips/include/asm/mach-generic/ide.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - * - * Copied from i386; many of the especially older MIPS or ISA-based platforms - * are basically identical. Using this file probably implies i8259 PIC - * support in a system but the very least interrupt numbers 0 - 15 need to - * be put aside for legacy devices. - */ -#ifndef __ASM_MACH_GENERIC_IDE_H -#define __ASM_MACH_GENERIC_IDE_H - -#ifdef __KERNEL__ - -#include -#include -#include - -/* MIPS port and memory-mapped I/O string operations. */ -static inline void __ide_flush_prologue(void) -{ -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_disable(); -#endif -} - -static inline void __ide_flush_epilogue(void) -{ -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_enable(); -#endif -} - -static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) -{ - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) { - unsigned long end = addr + size; - - while (addr < end) { - local_flush_data_cache_page((void *)addr); - addr += PAGE_SIZE; - } - } -} - -/* - * insw() and gang might be called with interrupts disabled, so we can't - * send IPIs for flushing due to the potencial of deadlocks, see the comment - * above smp_call_function() in arch/mips/kernel/smp.c. We work around the - * problem by disabling preemption so we know we actually perform the flush - * on the processor that actually has the lines to be flushed which hopefully - * is even better for performance anyway. - */ -static inline void __ide_insw(unsigned long port, void *addr, - unsigned int count) -{ - __ide_flush_prologue(); - insw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) -{ - __ide_flush_prologue(); - insl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_outsw(unsigned long port, const void *addr, - unsigned long count) -{ - __ide_flush_prologue(); - outsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_outsl(unsigned long port, const void *addr, - unsigned long count) -{ - __ide_flush_prologue(); - outsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - readsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - readsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) -{ - __ide_flush_prologue(); - writesw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); -} - -static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) -{ - __ide_flush_prologue(); - writesl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); -} - -/* ide_insw calls insw, not __ide_insw. Why? */ -#undef insw -#undef insl -#undef outsw -#undef outsl -#define insw(port, addr, count) __ide_insw(port, addr, count) -#define insl(port, addr, count) __ide_insl(port, addr, count) -#define outsw(port, addr, count) __ide_outsw(port, addr, count) -#define outsl(port, addr, count) __ide_outsl(port, addr, count) - -#endif /* __KERNEL__ */ - -#endif /* __ASM_MACH_GENERIC_IDE_H */ diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 4790cfa190d6..c2e0acb755cd 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -94,9 +94,6 @@ extern __iomem void *ltq_cgu_membase; #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) -/* allow booting xrx200 phys */ -int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr); - /* request a non-gpio and set the PIO config */ #define PMU_PPE BIT(13) extern void ltq_pmu_enable(unsigned int module); diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index 86e1a6aab4e5..2cdcfb5f6012 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -20,7 +20,6 @@ extern struct platform_device ls1x_gpio1_pdev; extern struct platform_device ls1x_rtc_pdev; extern struct platform_device ls1x_wdt_pdev; -void __init ls1x_clk_init(void); void __init ls1x_rtc_set_extclk(struct platform_device *pdev); void __init ls1x_serial_set_uartclk(struct platform_device *pdev); diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index d51dfad8f543..3e37705ea9cf 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -11,7 +11,8 @@ #ifndef _MT7620_REGS_H_ #define _MT7620_REGS_H_ -#define MT7620_SYSC_BASE 0x10000000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define MT7620_SYSC_BASE IOMEM(0x10000000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h index 5f213534f0f5..66a999cd1d80 100644 --- a/arch/mips/include/asm/mach-ralink/rt288x.h +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -11,7 +11,8 @@ #ifndef _RT288X_REGS_H_ #define _RT288X_REGS_H_ -#define RT2880_SYSC_BASE 0x00300000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define RT2880_SYSC_BASE IOMEM(0x00300000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h index 4d8e8c8d83ce..ef58f7bff957 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -43,7 +43,8 @@ static inline int soc_is_rt5350(void) return ralink_soc == RT305X_SOC_RT5350; } -#define RT305X_SYSC_BASE 0x10000000 +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) +#define RT305X_SYSC_BASE IOMEM(0x10000000) #define SYSC_REG_CHIP_NAME0 0x00 #define SYSC_REG_CHIP_NAME1 0x04 diff --git a/arch/mips/include/asm/mach-ralink/rt3883.h b/arch/mips/include/asm/mach-ralink/rt3883.h index f250de9c055b..ad25d5e8d2dc 100644 --- a/arch/mips/include/asm/mach-ralink/rt3883.h +++ b/arch/mips/include/asm/mach-ralink/rt3883.h @@ -10,8 +10,10 @@ #include +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(x))) + #define RT3883_SDRAM_BASE 0x00000000 -#define RT3883_SYSC_BASE 0x10000000 +#define RT3883_SYSC_BASE IOMEM(0x10000000) #define RT3883_TIMER_BASE 0x10000100 #define RT3883_INTC_BASE 0x10000200 #define RT3883_MEMC_BASE 0x10000300 diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 2362842ee2b5..1c576679aa87 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -280,6 +280,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define __WRITEABLE (_PAGE_SILENT_WRITE | _PAGE_WRITE | _PAGE_MODIFIED) #define _PAGE_CHG_MASK (_PAGE_ACCESSED | _PAGE_MODIFIED | \ - _PAGE_SOFT_DIRTY | _PFN_MASK | _CACHE_MASK) + _PAGE_SOFT_DIRTY | _PFN_MASK | \ + _CACHE_MASK | _PAGE_SPECIAL) #endif /* _ASM_PGTABLE_BITS_H */ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 791389bf3c12..574fa14ac8b2 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -469,7 +469,8 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) } static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma, - unsigned long address) + unsigned long address, + pte_t *ptep) { } diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 3fde1ff72bd1..ae2cd37a38f0 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -202,11 +202,13 @@ struct octeon_cop2_state { #define COP2_INIT \ .cp2 = {0,}, +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 struct octeon_cvmseg_state { unsigned long cvmseg[CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE] [cpu_dcache_line_size() / sizeof(unsigned long)]; }; - +#endif #else #define COP2_INIT #endif @@ -263,7 +265,10 @@ struct thread_struct { unsigned long trap_nr; #ifdef CONFIG_CPU_CAVIUM_OCTEON struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); +#endif #endif struct mips_abi *abi; }; diff --git a/arch/mips/include/asm/rtlx.h b/arch/mips/include/asm/rtlx.h index c1020654876e..a72785b4bbf4 100644 --- a/arch/mips/include/asm/rtlx.h +++ b/arch/mips/include/asm/rtlx.h @@ -81,7 +81,6 @@ struct rtlx_channel { extern struct rtlx_info { unsigned long id; enum rtlx_state state; - int ap_int_pending; /* Status of 0 or 1 for CONFIG_MIPS_CMP only */ struct rtlx_channel channel[RTLX_CHANNELS]; } *rtlx; diff --git a/arch/mips/include/asm/sibyte/board.h b/arch/mips/include/asm/sibyte/board.h index 20fe2f16c97e..03463faa4244 100644 --- a/arch/mips/include/asm/sibyte/board.h +++ b/arch/mips/include/asm/sibyte/board.h @@ -7,7 +7,7 @@ #define _SIBYTE_BOARD_H #if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_CRHONE) || \ - defined(CONFIG_SIBYTE_CRHINE) || defined(CONFIG_SIBYTE_LITTLESUR) + defined(CONFIG_SIBYTE_LITTLESUR) #include #endif @@ -15,10 +15,6 @@ #include #endif -#ifdef CONFIG_SIBYTE_CARMEL -#include -#endif - #ifdef CONFIG_SIBYTE_BIGSUR #include #endif diff --git a/arch/mips/include/asm/sibyte/carmel.h b/arch/mips/include/asm/sibyte/carmel.h deleted file mode 100644 index c6730d7a6392..000000000000 --- a/arch/mips/include/asm/sibyte/carmel.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2002 Broadcom Corporation - */ -#ifndef __ASM_SIBYTE_CARMEL_H -#define __ASM_SIBYTE_CARMEL_H - -#include -#include - -#define SIBYTE_BOARD_NAME "Carmel" - -#define GPIO_PHY_INTERRUPT 2 -#define GPIO_NONMASKABLE_INT 3 -#define GPIO_CF_INSERTED 6 -#define GPIO_MONTEREY_RESET 7 -#define GPIO_QUADUART_INT 8 -#define GPIO_CF_INT 9 -#define GPIO_FPGA_CCLK 10 -#define GPIO_FPGA_DOUT 11 -#define GPIO_FPGA_DIN 12 -#define GPIO_FPGA_PGM 13 -#define GPIO_FPGA_DONE 14 -#define GPIO_FPGA_INIT 15 - -#define LEDS_CS 2 -#define LEDS_PHYS 0x100C0000 -#define MLEDS_CS 3 -#define MLEDS_PHYS 0x100A0000 -#define UART_CS 4 -#define UART_PHYS 0x100D0000 -#define ARAVALI_CS 5 -#define ARAVALI_PHYS 0x11000000 -#define IDE_CS 6 -#define IDE_PHYS 0x100B0000 -#define ARAVALI2_CS 7 -#define ARAVALI2_PHYS 0x100E0000 - -#if defined(CONFIG_SIBYTE_CARMEL) -#define K_GPIO_GB_IDE 9 -#define K_INT_GB_IDE (K_INT_GPIO_0 + K_GPIO_GB_IDE) -#endif - - -#endif /* __ASM_SIBYTE_CARMEL_H */ diff --git a/arch/mips/include/asm/sibyte/swarm.h b/arch/mips/include/asm/sibyte/swarm.h index 947122f487ed..49ea7a645c15 100644 --- a/arch/mips/include/asm/sibyte/swarm.h +++ b/arch/mips/include/asm/sibyte/swarm.h @@ -24,11 +24,6 @@ #define SIBYTE_HAVE_PCMCIA 0 #define SIBYTE_HAVE_IDE 0 #endif -#ifdef CONFIG_SIBYTE_CRHINE -#define SIBYTE_BOARD_NAME "BCM91120C (CRhine)" -#define SIBYTE_HAVE_PCMCIA 0 -#define SIBYTE_HAVE_IDE 0 -#endif /* Generic bus chip selects */ #define LEDS_CS 3 diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 864aea803984..0145bbfb5efb 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h @@ -80,22 +80,6 @@ static inline int register_up_smp_ops(void) #endif } -static inline int register_cmp_smp_ops(void) -{ -#ifdef CONFIG_MIPS_CMP - extern const struct plat_smp_ops cmp_smp_ops; - - if (!mips_cm_present()) - return -ENODEV; - - register_smp_ops(&cmp_smp_ops); - - return 0; -#else - return -ENODEV; -#endif -} - static inline int register_vsmp_smp_ops(void) { #ifdef CONFIG_MIPS_MT_SMP diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 5d9ff61004ca..aab8981bc32c 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -66,7 +66,7 @@ extern void calculate_cpu_foreign_map(void); * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ -static inline void smp_send_reschedule(int cpu) +static inline void arch_smp_send_reschedule(int cpu) { extern const struct plat_smp_ops *mp_ops; /* private */ @@ -88,7 +88,7 @@ static inline void __cpu_die(unsigned int cpu) mp_ops->cpu_die(cpu); } -extern void play_dead(void); +extern void __noreturn play_dead(void); #endif #ifdef CONFIG_KEXEC diff --git a/arch/mips/include/asm/vpe.h b/arch/mips/include/asm/vpe.h index ef7e07829607..61fd4d0aeda4 100644 --- a/arch/mips/include/asm/vpe.h +++ b/arch/mips/include/asm/vpe.h @@ -29,12 +29,8 @@ static inline int aprp_cpu_index(void) { -#ifdef CONFIG_MIPS_CMP - return setup_max_cpus; -#else extern int tclimit; return tclimit; -#endif } enum vpe_state { diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 5d1addac5e28..853a43ee4b44 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -58,16 +58,13 @@ obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o bmips_5xxx_init.o obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o -obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o obj-$(CONFIG_MIPS_SPRAM) += spram.o obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o -obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o -obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index c4501897b870..40fd4051bb3d 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -306,7 +306,10 @@ void output_octeon_cop2_state_defines(void) OFFSET(OCTEON_CP2_HSH_IVW, octeon_cop2_state, cop2_hsh_ivw); OFFSET(OCTEON_CP2_SHA3, octeon_cop2_state, cop2_sha3); OFFSET(THREAD_CP2, task_struct, thread.cp2); +#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \ + CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0 OFFSET(THREAD_CVMSEG, task_struct, thread.cvmseg.cvmseg); +#endif BLANK(); } #endif diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 8ef492da827f..64ecfdac6580 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -116,6 +116,8 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS + /* We don't know how to do coherence setup on earlier ISA */ +#if MIPS_ISA_REV > 0 /* Skip cache & coherence setup if we're already coherent */ lw s7, GCR_CL_COHERENCE_OFS(s1) bnez s7, 1f @@ -129,6 +131,7 @@ not_nmi: li t0, 0xff sw t0, GCR_CL_COHERENCE_OFS(s1) ehb +#endif /* MIPS_ISA_REV > 0 */ /* Set Kseg0 CCA to that in s0 */ 1: mfc0 t0, CP0_CONFIG @@ -515,6 +518,7 @@ LEAF(mips_cps_boot_vpes) nop END(mips_cps_boot_vpes) +#if MIPS_ISA_REV > 0 LEAF(mips_cps_cache_init) /* * Clear the bits used to index the caches. Note that the architecture @@ -588,6 +592,7 @@ dcache_done: jr ra nop END(mips_cps_cache_init) +#endif /* MIPS_ISA_REV > 0 */ #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 7ddf07f255f3..e79adcb128e6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1502,6 +1502,10 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu) break; } break; + case PRID_IMP_NETLOGIC_AU13XX: + c->cputype = CPU_ALCHEMY; + __cpu_name[cpu] = "Au1300"; + break; } } @@ -1602,6 +1606,8 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); + /* Octeon has different cache interface */ + c->options &= ~MIPS_CPU_4K_CACHE; switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_CAVIUM_CN38XX: case PRID_IMP_CAVIUM_CN31XX: @@ -1861,6 +1867,7 @@ void cpu_probe(void) cpu_probe_mips(c, cpu); break; case PRID_COMP_ALCHEMY: + case PRID_COMP_NETLOGIC: cpu_probe_alchemy(c, cpu); break; case PRID_COMP_SIBYTE: diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index b4f7d950c846..3f00788b0871 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -181,11 +181,16 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); phys_addr_t __mips_cm_phys_base(void) { - u32 config3 = read_c0_config3(); unsigned long cmgcr; /* Check the CMGCRBase register is implemented */ - if (!(config3 & MIPS_CONF3_CMGCR)) + if (!(read_c0_config() & MIPS_CONF_M)) + return 0; + + if (!(read_c0_config2() & MIPS_CONF_M)) + return 0; + + if (!(read_c0_config3() & MIPS_CONF3_CMGCR)) return 0; /* Read the address from CMGCRBase */ diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index dc023a979803..f88b7919f11f 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -234,7 +234,7 @@ static int __init mips_mt_init(void) { struct class *mtc; - mtc = class_create(THIS_MODULE, "mt"); + mtc = class_create("mt"); if (IS_ERR(mtc)) return PTR_ERR(mtc); diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S index 896080b445c2..9b7c8ab6f08c 100644 --- a/arch/mips/kernel/octeon_switch.S +++ b/arch/mips/kernel/octeon_switch.S @@ -428,7 +428,6 @@ done_restore: jr ra nop .space 30 * 4, 0 -octeon_mult_save_end: EXPORT(octeon_mult_save_end) END(octeon_mult_save) @@ -448,7 +447,6 @@ octeon_mult_save_end: sd k0, PT_MPL+8(sp) /* PT_MPL+8 has MPL1 */ jr ra sd k1, PT_MPL+16(sp) /* PT_MPL+16 has MPL2 */ -octeon_mult_save2_end: EXPORT(octeon_mult_save2_end) END(octeon_mult_save2) @@ -480,7 +478,6 @@ octeon_mult_save2_end: sd $10, PT_MPL+(4*8)(sp) /* store MPL4 */ jr ra sd $11, PT_MPL+(5*8)(sp) /* store MPL5 */ -octeon_mult_save3_end: EXPORT(octeon_mult_save3_end) END(octeon_mult_save3) .set pop @@ -498,7 +495,6 @@ octeon_mult_save3_end: jr ra nop .space 30 * 4, 0 -octeon_mult_restore_end: EXPORT(octeon_mult_restore_end) END(octeon_mult_restore) @@ -517,7 +513,6 @@ octeon_mult_restore_end: mtp1 v0 /* P1 */ jr ra mtp0 v1 /* P0 */ -octeon_mult_restore2_end: EXPORT(octeon_mult_restore2_end) END(octeon_mult_restore2) @@ -548,7 +543,6 @@ octeon_mult_restore2_end: .word 0x714b000b /* mtp2 $10, $11 restore P2 and P5 */ -octeon_mult_restore3_end: EXPORT(octeon_mult_restore3_end) END(octeon_mult_restore3) .set pop diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 093dbbd6b843..a3225912c862 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -40,7 +40,7 @@ #include #ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { play_dead(); } diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c deleted file mode 100644 index d26dcc4b46e7..000000000000 --- a/arch/mips/kernel/rtlx-cmp.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int major; - -static void rtlx_interrupt(void) -{ - int i; - struct rtlx_info *info; - struct rtlx_info **p = vpe_get_shared(aprp_cpu_index()); - - if (p == NULL || *p == NULL) - return; - - info = *p; - - if (info->ap_int_pending == 1 && smp_processor_id() == 0) { - for (i = 0; i < RTLX_CHANNELS; i++) { - wake_up(&channel_wqs[i].lx_queue); - wake_up(&channel_wqs[i].rt_queue); - } - info->ap_int_pending = 0; - } -} - -void _interrupt_sp(void) -{ - smp_send_reschedule(aprp_cpu_index()); -} - -int __init rtlx_module_init(void) -{ - struct device *dev; - int i, err; - - if (!cpu_has_mipsmt) { - pr_warn("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (num_possible_cpus() - aprp_cpu_index() < 1) { - pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n" - "Pass maxcpus= argument as kernel argument\n"); - - return -ENODEV; - } - - major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops); - if (major < 0) { - pr_err("rtlx_module_init: unable to register device\n"); - return major; - } - - /* initialise the wait queues */ - for (i = 0; i < RTLX_CHANNELS; i++) { - init_waitqueue_head(&channel_wqs[i].rt_queue); - init_waitqueue_head(&channel_wqs[i].lx_queue); - atomic_set(&channel_wqs[i].in_open, 0); - mutex_init(&channel_wqs[i].mutex); - - dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, - "%s%d", RTLX_MODULE_NAME, i); - if (IS_ERR(dev)) { - while (i--) - device_destroy(mt_class, MKDEV(major, i)); - - err = PTR_ERR(dev); - goto out_chrdev; - } - } - - /* set up notifiers */ - rtlx_notify.start = rtlx_starting; - rtlx_notify.stop = rtlx_stopping; - vpe_notify(aprp_cpu_index(), &rtlx_notify); - - if (cpu_has_vint) { - aprp_hook = rtlx_interrupt; - } else { - pr_err("APRP RTLX init on non-vectored-interrupt processor\n"); - err = -ENODEV; - goto out_class; - } - - return 0; - -out_class: - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); -out_chrdev: - unregister_chrdev(major, RTLX_MODULE_NAME); - - return err; -} - -void __exit rtlx_module_exit(void) -{ - int i; - - for (i = 0; i < RTLX_CHANNELS; i++) - device_destroy(mt_class, MKDEV(major, i)); - - unregister_chrdev(major, RTLX_MODULE_NAME); - - aprp_hook = NULL; -} diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f1c88f8a1dc5..c0e65135481b 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -158,10 +158,6 @@ static unsigned long __init init_initrd(void) pr_err("initrd start must be page aligned\n"); goto disable; } - if (initrd_start < PAGE_OFFSET) { - pr_err("initrd start < PAGE_OFFSET\n"); - goto disable; - } /* * Sanitize initrd addresses. For example firmware @@ -174,6 +170,11 @@ static unsigned long __init init_initrd(void) initrd_end = (unsigned long)__va(end); initrd_start = (unsigned long)__va(__pa(initrd_start)); + if (initrd_start < PAGE_OFFSET) { + pr_err("initrd start < PAGE_OFFSET\n"); + goto disable; + } + ROOT_DEV = Root_RAM0; return PFN_UP(end); disable: @@ -786,7 +787,8 @@ void __init setup_arch(char **cmdline_p) setup_early_printk(); #endif cpu_report(); - check_bugs_early(); + if (IS_ENABLED(CONFIG_CPU_R4X00_BUGS64)) + check_bugs64_early(); #if defined(CONFIG_VT) #if defined(CONFIG_VGA_CONSOLE) diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index f5d7bfa3472a..15466d4cf4a0 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -54,6 +54,8 @@ static void bmips_set_reset_vec(int cpu, u32 val); #ifdef CONFIG_SMP +#include + /* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */ unsigned long bmips_smp_boot_sp; unsigned long bmips_smp_boot_gp; @@ -413,6 +415,8 @@ void __ref play_dead(void) " wait\n" " j bmips_secondary_reentry\n" : : : "memory"); + + BUG(); } #endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c deleted file mode 100644 index 76f5824cdb00..000000000000 --- a/arch/mips/kernel/smp-cmp.c +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * - * Copyright (C) 2007 MIPS Technologies, Inc. - * Chris Dearman (chris@mips.com) - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void cmp_init_secondary(void) -{ - struct cpuinfo_mips *c __maybe_unused = ¤t_cpu_data; - - /* Assume GIC is present */ - change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | - STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); - - /* Enable per-cpu interrupts: platform specific */ - -#ifdef CONFIG_MIPS_MT_SMP - if (cpu_has_mipsmt) - cpu_set_vpe_id(c, (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & - TCBIND_CURVPE); -#endif -} - -static void cmp_smp_finish(void) -{ - pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); - - /* CDFIXME: remove this? */ - write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ)); - -#ifdef CONFIG_MIPS_MT_FPAFF - /* If we have an FPU, enroll ourselves in the FPU-full mask */ - if (cpu_has_fpu) - cpumask_set_cpu(smp_processor_id(), &mt_fpu_cpumask); -#endif /* CONFIG_MIPS_MT_FPAFF */ - - local_irq_enable(); -} - -/* - * Setup the PC, SP, and GP of a secondary processor and start it running - * smp_bootstrap is the place to resume from - * __KSTK_TOS(idle) is apparently the stack pointer - * (unsigned long)idle->thread_info the gp - */ -static int cmp_boot_secondary(int cpu, struct task_struct *idle) -{ - struct thread_info *gp = task_thread_info(idle); - unsigned long sp = __KSTK_TOS(idle); - unsigned long pc = (unsigned long)&smp_bootstrap; - unsigned long a0 = 0; - - pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(), - __func__, cpu); - -#if 0 - /* Needed? */ - flush_icache_range((unsigned long)gp, - (unsigned long)(gp + sizeof(struct thread_info))); -#endif - - amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0); - return 0; -} - -/* - * Common setup before any secondaries are started - */ -void __init cmp_smp_setup(void) -{ - int i; - int ncpu = 0; - - pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__); - -#ifdef CONFIG_MIPS_MT_FPAFF - /* If we have an FPU, enroll ourselves in the FPU-full mask */ - if (cpu_has_fpu) - cpumask_set_cpu(0, &mt_fpu_cpumask); -#endif /* CONFIG_MIPS_MT_FPAFF */ - - for (i = 1; i < NR_CPUS; i++) { - if (amon_cpu_avail(i)) { - set_cpu_possible(i, true); - __cpu_number_map[i] = ++ncpu; - __cpu_logical_map[ncpu] = i; - } - } - - if (cpu_has_mipsmt) { - unsigned int nvpe = 1; -#ifdef CONFIG_MIPS_MT_SMP - unsigned int mvpconf0 = read_c0_mvpconf0(); - - nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; -#endif - smp_num_siblings = nvpe; - } - pr_info("Detected %i available secondary CPU(s)\n", ncpu); -} - -void __init cmp_prepare_cpus(unsigned int max_cpus) -{ - pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n", - smp_processor_id(), __func__, max_cpus); - -#ifdef CONFIG_MIPS_MT - /* - * FIXME: some of these options are per-system, some per-core and - * some per-cpu - */ - mips_mt_set_cpuoptions(); -#endif - -} - -const struct plat_smp_ops cmp_smp_ops = { - .send_ipi_single = mips_smp_send_ipi_single, - .send_ipi_mask = mips_smp_send_ipi_mask, - .init_secondary = cmp_init_secondary, - .smp_finish = cmp_smp_finish, - .boot_secondary = cmp_boot_secondary, - .smp_setup = cmp_smp_setup, - .prepare_cpus = cmp_prepare_cpus, -}; diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 4fc288bb85b9..62f677b2306f 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -361,6 +362,8 @@ out: static void cps_init_secondary(void) { + int core = cpu_core(¤t_cpu_data); + /* Disable MT - we only want to run 1 TC per VPE */ if (cpu_has_mipsmt) dmt(); @@ -376,6 +379,9 @@ static void cps_init_secondary(void) BUG_ON(ident != mips_cm_vp_id(smp_processor_id())); } + if (core > 0 && !read_gcr_cl_coherence()) + pr_warn("Core %u is not in coherent domain\n", core); + if (cpu_has_veic) clear_c0_status(ST0_IM); else diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c index 6c063aa188e6..401b148f8917 100644 --- a/arch/mips/kernel/uprobes.c +++ b/arch/mips/kernel/uprobes.c @@ -191,6 +191,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *aup, { struct uprobe_task *utask = current->utask; + current->thread.trap_nr = utask->autask.saved_trap_nr; instruction_pointer_set(regs, utask->vaddr); } @@ -207,24 +208,6 @@ unsigned long arch_uretprobe_hijack_return_addr( return ra; } -/** - * set_swbp - store breakpoint at a given address. - * @auprobe: arch specific probepoint information. - * @mm: the probed process address space. - * @vaddr: the virtual address to insert the opcode. - * - * For mm @mm, store the breakpoint instruction at @vaddr. - * Return 0 (success) or a negative errno. - * - * This version overrides the weak version in kernel/events/uprobes.c. - * It is required to handle MIPS16 and microMIPS. - */ -int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, - unsigned long vaddr) -{ - return uprobe_write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); -} - void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *src, unsigned long len) { diff --git a/arch/mips/kernel/vpe-cmp.c b/arch/mips/kernel/vpe-cmp.c deleted file mode 100644 index 92140edb3ce3..000000000000 --- a/arch/mips/kernel/vpe-cmp.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - */ -#include -#include -#include -#include -#include - -#include - -static int major; - -void cleanup_tc(struct tc *tc) -{ - -} - -static ssize_t store_kill(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - struct vpe_notifications *notifier; - - list_for_each_entry(notifier, &vpe->notify, list) - notifier->stop(aprp_cpu_index()); - - release_progmem(vpe->load_addr); - vpe->state = VPE_STATE_UNUSED; - - return len; -} -static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); - -static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, - char *buf) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - - return sprintf(buf, "%d\n", vpe->ntcs); -} - -static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct vpe *vpe = get_vpe(aprp_cpu_index()); - unsigned long new; - int ret; - - ret = kstrtoul(buf, 0, &new); - if (ret < 0) - return ret; - - /* APRP can only reserve one TC in a VPE and no more. */ - if (new != 1) - return -EINVAL; - - vpe->ntcs = new; - - return len; -} -static DEVICE_ATTR_RW(ntcs); - -static struct attribute *vpe_attrs[] = { - &dev_attr_kill.attr, - &dev_attr_ntcs.attr, - NULL, -}; -ATTRIBUTE_GROUPS(vpe); - -static void vpe_device_release(struct device *cd) -{ -} - -static struct class vpe_class = { - .name = "vpe", - .owner = THIS_MODULE, - .dev_release = vpe_device_release, - .dev_groups = vpe_groups, -}; - -static struct device vpe_device; - -int __init vpe_module_init(void) -{ - struct vpe *v = NULL; - struct tc *t; - int err; - - if (!cpu_has_mipsmt) { - pr_warn("VPE loader: not a MIPS MT capable processor\n"); - return -ENODEV; - } - - if (num_possible_cpus() - aprp_cpu_index() < 1) { - pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n" - "Pass maxcpus= argument as kernel argument\n"); - return -ENODEV; - } - - major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops); - if (major < 0) { - pr_warn("VPE loader: unable to register character device\n"); - return major; - } - - err = class_register(&vpe_class); - if (err) { - pr_err("vpe_class registration failed\n"); - goto out_chrdev; - } - - device_initialize(&vpe_device); - vpe_device.class = &vpe_class; - vpe_device.parent = NULL; - dev_set_name(&vpe_device, "vpe_sp"); - vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR); - err = device_add(&vpe_device); - if (err) { - pr_err("Adding vpe_device failed\n"); - goto out_class; - } - - t = alloc_tc(aprp_cpu_index()); - if (!t) { - pr_warn("VPE: unable to allocate TC\n"); - err = -ENOMEM; - goto out_dev; - } - - /* VPE */ - v = alloc_vpe(aprp_cpu_index()); - if (v == NULL) { - pr_warn("VPE: unable to allocate VPE\n"); - kfree(t); - err = -ENOMEM; - goto out_dev; - } - - v->ntcs = 1; - - /* add the tc to the list of this vpe's tc's. */ - list_add(&t->tc, &v->tc); - - /* TC */ - t->pvpe = v; /* set the parent vpe */ - - return 0; - -out_dev: - device_del(&vpe_device); - -out_class: - put_device(&vpe_device); - class_unregister(&vpe_class); - -out_chrdev: - unregister_chrdev(major, VPE_MODULE_NAME); - - return err; -} - -void __exit vpe_module_exit(void) -{ - struct vpe *v, *n; - - device_unregister(&vpe_device); - class_unregister(&vpe_class); - unregister_chrdev(major, VPE_MODULE_NAME); - - /* No locking needed here */ - list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) - if (v->state != VPE_STATE_UNUSED) - release_vpe(v); -} diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c index 223d6274f2e5..667bc75f6420 100644 --- a/arch/mips/kernel/vpe-mt.c +++ b/arch/mips/kernel/vpe-mt.c @@ -316,7 +316,6 @@ static void vpe_device_release(struct device *cd) static struct class vpe_class = { .name = "vpe", - .owner = THIS_MODULE, .dev_release = vpe_device_release, .dev_groups = vpe_groups, }; diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 13294972707b..e9a0cfd02ae2 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -199,18 +199,17 @@ static void layout_sections(struct module *mod, const Elf_Ehdr *hdr, for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < hdr->e_shnum; ++i) { Elf_Shdr *s = &sechdrs[i]; + struct module_memory *mod_mem; + + mod_mem = &mod->mem[MOD_TEXT]; if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL) continue; s->sh_entsize = - get_offset((unsigned long *)&mod->core_layout.size, s); + get_offset((unsigned long *)&mod_mem->size, s); } - - if (m == 0) - mod->core_layout.text_size = mod->core_layout.size; - } } @@ -641,7 +640,7 @@ static int vpe_elfload(struct vpe *v) layout_sections(&mod, hdr, sechdrs, secstrings); } - v->load_addr = alloc_progmem(mod.core_layout.size); + v->load_addr = alloc_progmem(mod.mem[MOD_TEXT].size); if (!v->load_addr) return -ENOMEM; @@ -795,7 +794,7 @@ static int vpe_open(struct inode *inode, struct file *filp) static int vpe_release(struct inode *inode, struct file *filp) { -#if defined(CONFIG_MIPS_VPE_LOADER_MT) || defined(CONFIG_MIPS_VPE_LOADER_CMP) +#ifdef CONFIG_MIPS_VPE_LOADER_MT struct vpe *v; Elf_Ehdr *hdr; int ret = 0; diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 36c8991b5d39..884be4ef99dc 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -993,9 +993,9 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, kvm_flush_remote_tlbs(kvm); } -long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { - long r; + int r; switch (ioctl) { default: diff --git a/arch/mips/kvm/vz.c b/arch/mips/kvm/vz.c index dafab003ea0d..3d21cbfa7443 100644 --- a/arch/mips/kvm/vz.c +++ b/arch/mips/kvm/vz.c @@ -3305,7 +3305,7 @@ static struct kvm_mips_callbacks kvm_vz_callbacks = { }; /* FIXME: Get rid of the callbacks now that trap-and-emulate is gone. */ -struct kvm_mips_callbacks *kvm_mips_callbacks = &kvm_vz_callbacks; +const struct kvm_mips_callbacks * const kvm_mips_callbacks = &kvm_vz_callbacks; int kvm_mips_emulation_init(void) { diff --git a/arch/mips/loongson2ef/Kconfig b/arch/mips/loongson2ef/Kconfig index 96dc6eba4310..f93eb6f42238 100644 --- a/arch/mips/loongson2ef/Kconfig +++ b/arch/mips/loongson2ef/Kconfig @@ -7,6 +7,7 @@ choice config LEMOTE_FULOONG2E bool "Lemote Fuloong(2e) mini-PC" select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_PHYS_TO_DMA select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select CEVT_R4K @@ -36,6 +37,7 @@ config LEMOTE_FULOONG2E config LEMOTE_MACH2F bool "Lemote Loongson 2F family machines" select ARCH_SPARSEMEM_ENABLE + select ARCH_HAS_PHYS_TO_DMA select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select BOARD_SCACHE @@ -46,6 +48,7 @@ config LEMOTE_MACH2F select CSRC_R4K if ! MIPS_EXTERNAL_TIMER select DMA_NONCOHERENT select GENERIC_ISA_DMA_SUPPORT_BROKEN + select GPIOLIB select FORCE_PCI select I8259 select IRQ_MIPS_CPU diff --git a/arch/mips/loongson2ef/Platform b/arch/mips/loongson2ef/Platform index c6f7a4b95997..d446b705fba4 100644 --- a/arch/mips/loongson2ef/Platform +++ b/arch/mips/loongson2ef/Platform @@ -2,41 +2,6 @@ # Loongson Processors' Support # -cflags-$(CONFIG_CPU_LOONGSON2EF) += -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -# -# Some versions of binutils, not currently mainline as of 2019/02/04, support -# an -mfix-loongson3-llsc flag which emits a sync prior to each ll instruction -# to work around a CPU bug (see __SYNC_loongson3_war in asm/sync.h for a -# description). -# -# We disable this in order to prevent the assembler meddling with the -# instruction that labels refer to, ie. if we label an ll instruction: -# -# 1: ll v0, 0(a0) -# -# ...then with the assembler fix applied the label may actually point at a sync -# instruction inserted by the assembler, and if we were using the label in an -# exception table the table would no longer contain the address of the ll -# instruction. -# -# Avoid this by explicitly disabling that assembler behaviour. If upstream -# binutils does not merge support for the flag then we can revisit & remove -# this later - for now it ensures vendor toolchains don't cause problems. -# -cflags-$(CONFIG_CPU_LOONGSON2EF) += $(call cc-option,-Wa$(comma)-mno-fix-loongson3-llsc,) - -# Enable the workarounds for Loongson2f -ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS -cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa,-mfix-loongson2f-nop -cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa,-mfix-loongson2f-jump -endif - -# Some -march= flags enable MMI instructions, and GCC complains about that -# support being enabled alongside -msoft-float. Thus explicitly disable MMI. -cflags-y += $(call cc-option,-mno-loongson-mmi) - # # Loongson Machines' Support # diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c index 5ad38f86ee62..d60dd9992377 100644 --- a/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c +++ b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c @@ -213,7 +213,7 @@ void pci_isa_write_reg(int reg, u32 value) lo |= 0x00000063; _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo); } - + break; default: /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */ break; diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c index 459b15c96d3b..965c04aa56fd 100644 --- a/arch/mips/loongson32/common/time.c +++ b/arch/mips/loongson32/common/time.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -211,7 +212,7 @@ void __init plat_time_init(void) struct clk *clk = NULL; /* initialize LS1X clocks */ - ls1x_clk_init(); + of_clk_init(NULL); #ifdef CONFIG_CEVT_CSRC_LS1X /* setup LS1X PWM timer */ diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform index 473404cae1c4..49c9889e3d56 100644 --- a/arch/mips/loongson64/Platform +++ b/arch/mips/loongson64/Platform @@ -1,19 +1,3 @@ -# -# Loongson Processors' Support -# - - -cflags-$(CONFIG_CPU_LOONGSON64) += -Wa,--trap - -ifdef CONFIG_CPU_LOONGSON64 -cflags-$(CONFIG_CC_IS_GCC) += -march=loongson3a -cflags-$(CONFIG_CC_IS_CLANG) += -march=mips64r2 -endif - -# Some -march= flags enable MMI instructions, and GCC complains about that -# support being enabled alongside -msoft-float. Thus explicitly disable MMI. -cflags-y += $(call cc-option,-mno-loongson-mmi) - # # Loongson Machines' Support # diff --git a/arch/mips/loongson64/setup.c b/arch/mips/loongson64/setup.c index 3cd11c2b308b..257038e18779 100644 --- a/arch/mips/loongson64/setup.c +++ b/arch/mips/loongson64/setup.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -17,20 +16,6 @@ void *loongson_fdt_blob; -static void wbflush_loongson(void) -{ - asm(".set\tpush\n\t" - ".set\tnoreorder\n\t" - ".set mips3\n\t" - "sync\n\t" - "nop\n\t" - ".set\tpop\n\t" - ".set mips0\n\t"); -} - -void (*__wbflush)(void) = wbflush_loongson; -EXPORT_SYMBOL(__wbflush); - void __init plat_mem_setup(void) { if (loongson_fdt_blob) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 660e1de4412a..b0e8bb9fa036 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -27,30 +28,13 @@ DEFINE_PER_CPU(int, cpu_state); #define LS_IPI_IRQ (MIPS_CPU_IRQ_BASE + 6) -static void *ipi_set0_regs[16]; -static void *ipi_clear0_regs[16]; -static void *ipi_status0_regs[16]; -static void *ipi_en0_regs[16]; -static void *ipi_mailbox_buf[16]; +static void __iomem *ipi_set0_regs[16]; +static void __iomem *ipi_clear0_regs[16]; +static void __iomem *ipi_status0_regs[16]; +static void __iomem *ipi_en0_regs[16]; +static void __iomem *ipi_mailbox_buf[16]; static uint32_t core0_c0count[NR_CPUS]; -/* read a 32bit value from ipi register */ -#define loongson3_ipi_read32(addr) readl(addr) -/* read a 64bit value from ipi register */ -#define loongson3_ipi_read64(addr) readq(addr) -/* write a 32bit value to ipi register */ -#define loongson3_ipi_write32(action, addr) \ - do { \ - writel(action, addr); \ - __wbflush(); \ - } while (0) -/* write a 64bit value to ipi register */ -#define loongson3_ipi_write64(action, addr) \ - do { \ - writeq(action, addr); \ - __wbflush(); \ - } while (0) - static u32 (*ipi_read_clear)(int cpu); static void (*ipi_write_action)(int cpu, u32 action); static void (*ipi_write_enable)(int cpu); @@ -136,26 +120,28 @@ static u32 legacy_ipi_read_clear(int cpu) u32 action; /* Load the ipi register to figure out what we're supposed to do */ - action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]); + action = readl_relaxed(ipi_status0_regs[cpu_logical_map(cpu)]); /* Clear the ipi register to clear the interrupt */ - loongson3_ipi_write32(action, ipi_clear0_regs[cpu_logical_map(cpu)]); + writel_relaxed(action, ipi_clear0_regs[cpu_logical_map(cpu)]); + nudge_writes(); return action; } static void legacy_ipi_write_action(int cpu, u32 action) { - loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]); + writel_relaxed((u32)action, ipi_set0_regs[cpu]); + nudge_writes(); } static void legacy_ipi_write_enable(int cpu) { - loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(cpu)]); + writel_relaxed(0xffffffff, ipi_en0_regs[cpu_logical_map(cpu)]); } static void legacy_ipi_clear_buf(int cpu) { - loongson3_ipi_write64(0, ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); + writeq_relaxed(0, ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); } static void legacy_ipi_write_buf(int cpu, struct task_struct *idle) @@ -171,14 +157,15 @@ static void legacy_ipi_write_buf(int cpu, struct task_struct *idle) pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n", cpu, startargs[0], startargs[1], startargs[2]); - loongson3_ipi_write64(startargs[3], + writeq_relaxed(startargs[3], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18); - loongson3_ipi_write64(startargs[2], + writeq_relaxed(startargs[2], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10); - loongson3_ipi_write64(startargs[1], + writeq_relaxed(startargs[1], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8); - loongson3_ipi_write64(startargs[0], + writeq_relaxed(startargs[0], ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0); + nudge_writes(); } static void csr_ipi_probe(void) @@ -418,7 +405,7 @@ static irqreturn_t loongson3_ipi_interrupt(int irq, void *dev_id) c0count = c0count ? c0count : 1; for (i = 1; i < nr_cpu_ids; i++) core0_c0count[i] = c0count; - __wbflush(); /* Let others see the result ASAP */ + nudge_writes(); /* Let others see the result ASAP */ } return IRQ_HANDLED; @@ -822,6 +809,7 @@ out: state_addr = &per_cpu(cpu_state, cpu); mb(); play_dead_at_ckseg1(state_addr); + BUG(); } static int loongson3_disable_clock(unsigned int cpu) diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index c7ed589de882..b7393b61cfa7 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -83,8 +83,13 @@ static void octeon_flush_icache_all_cores(struct vm_area_struct *vma) else mask = *cpu_online_mask; cpumask_clear_cpu(cpu, &mask); +#ifdef CONFIG_CAVIUM_OCTEON_SOC for_each_cpu(cpu, &mask) octeon_send_ipi_single(cpu, SMP_ICACHE_FLUSH); +#else + smp_call_function_many(&mask, (smp_call_func_t)octeon_local_flush_icache, + NULL, 1); +#endif preempt_enable(); #endif diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index df6755ca1892..5869df848fab 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -261,10 +261,6 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE); } -static void local_r3k_flush_data_cache_page(void *addr) -{ -} - static void r3k_flush_data_cache_page(unsigned long addr) { } @@ -302,7 +298,6 @@ void r3k_cache_init(void) __flush_kernel_vmap_range = r3k_flush_kernel_vmap_range; - local_flush_data_cache_page = local_r3k_flush_data_cache_page; flush_data_cache_page = r3k_flush_data_cache_page; _dma_cache_wback_inv = r3k_dma_cache_wback_inv; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index a549fa98c2f4..4b6554b48923 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -110,20 +110,6 @@ static unsigned long dcache_size __read_mostly; static unsigned long vcache_size __read_mostly; static unsigned long scache_size __read_mostly; -/* - * Dummy cache handling routines for machines without boardcaches - */ -static void cache_noop(void) {} - -static struct bcache_ops no_sc_ops = { - .bc_enable = (void *)cache_noop, - .bc_disable = (void *)cache_noop, - .bc_wback_inv = (void *)cache_noop, - .bc_inv = (void *)cache_noop -}; - -struct bcache_ops *bcops = &no_sc_ops; - #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010) #define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020) @@ -201,24 +187,6 @@ static void r4k_blast_dcache_user_page_setup(void) #endif -static void (* r4k_blast_dcache_page_indexed)(unsigned long addr); - -static void r4k_blast_dcache_page_indexed_setup(void) -{ - unsigned long dc_lsize = cpu_dcache_line_size(); - - if (dc_lsize == 0) - r4k_blast_dcache_page_indexed = (void *)cache_noop; - else if (dc_lsize == 16) - r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed; - else if (dc_lsize == 32) - r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed; - else if (dc_lsize == 64) - r4k_blast_dcache_page_indexed = blast_dcache64_page_indexed; - else if (dc_lsize == 128) - r4k_blast_dcache_page_indexed = blast_dcache128_page_indexed; -} - void (* r4k_blast_dcache)(void); EXPORT_SYMBOL(r4k_blast_dcache); @@ -280,39 +248,6 @@ static inline void tx49_blast_icache32(void) addr | ws, 32); } -static inline void blast_icache32_r4600_v1_page_indexed(unsigned long page) -{ - unsigned long flags; - - local_irq_save(flags); - blast_icache32_page_indexed(page); - local_irq_restore(flags); -} - -static inline void tx49_blast_icache32_page_indexed(unsigned long page) -{ - unsigned long indexmask = current_cpu_data.icache.waysize - 1; - unsigned long start = INDEX_BASE + (page & indexmask); - unsigned long end = start + PAGE_SIZE; - unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; - unsigned long ws_end = current_cpu_data.icache.ways << - current_cpu_data.icache.waybit; - unsigned long ws, addr; - - CACHE32_UNROLL32_ALIGN2; - /* I'm in even chunk. blast odd chunks */ - for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start + 0x400; addr < end; addr += 0x400 * 2) - cache_unroll(32, kernel_cache, Index_Invalidate_I, - addr | ws, 32); - CACHE32_UNROLL32_ALIGN; - /* I'm in odd chunk. blast even chunks */ - for (ws = 0; ws < ws_end; ws += ws_inc) - for (addr = start; addr < end; addr += 0x400 * 2) - cache_unroll(32, kernel_cache, Index_Invalidate_I, - addr | ws, 32); -} - static void (* r4k_blast_icache_page)(unsigned long addr); static void r4k_blast_icache_page_setup(void) @@ -355,34 +290,6 @@ static void r4k_blast_icache_user_page_setup(void) #endif -static void (* r4k_blast_icache_page_indexed)(unsigned long addr); - -static void r4k_blast_icache_page_indexed_setup(void) -{ - unsigned long ic_lsize = cpu_icache_line_size(); - - if (ic_lsize == 0) - r4k_blast_icache_page_indexed = (void *)cache_noop; - else if (ic_lsize == 16) - r4k_blast_icache_page_indexed = blast_icache16_page_indexed; - else if (ic_lsize == 32) { - if (IS_ENABLED(CONFIG_WAR_R4600_V1_INDEX_ICACHEOP) && - cpu_is_r4600_v1_x()) - r4k_blast_icache_page_indexed = - blast_icache32_r4600_v1_page_indexed; - else if (IS_ENABLED(CONFIG_WAR_TX49XX_ICACHE_INDEX_INV)) - r4k_blast_icache_page_indexed = - tx49_blast_icache32_page_indexed; - else if (current_cpu_type() == CPU_LOONGSON2EF) - r4k_blast_icache_page_indexed = - loongson2_blast_icache32_page_indexed; - else - r4k_blast_icache_page_indexed = - blast_icache32_page_indexed; - } else if (ic_lsize == 64) - r4k_blast_icache_page_indexed = blast_icache64_page_indexed; -} - void (* r4k_blast_icache)(void); EXPORT_SYMBOL(r4k_blast_icache); @@ -428,24 +335,6 @@ static void r4k_blast_scache_page_setup(void) r4k_blast_scache_page = blast_scache128_page; } -static void (* r4k_blast_scache_page_indexed)(unsigned long addr); - -static void r4k_blast_scache_page_indexed_setup(void) -{ - unsigned long sc_lsize = cpu_scache_line_size(); - - if (scache_size == 0) - r4k_blast_scache_page_indexed = (void *)cache_noop; - else if (sc_lsize == 16) - r4k_blast_scache_page_indexed = blast_scache16_page_indexed; - else if (sc_lsize == 32) - r4k_blast_scache_page_indexed = blast_scache32_page_indexed; - else if (sc_lsize == 64) - r4k_blast_scache_page_indexed = blast_scache64_page_indexed; - else if (sc_lsize == 128) - r4k_blast_scache_page_indexed = blast_scache128_page_indexed; -} - static void (* r4k_blast_scache)(void); static void r4k_blast_scache_setup(void) @@ -1821,13 +1710,10 @@ void r4k_cache_init(void) setup_scache(); r4k_blast_dcache_page_setup(); - r4k_blast_dcache_page_indexed_setup(); r4k_blast_dcache_setup(); r4k_blast_icache_page_setup(); - r4k_blast_icache_page_indexed_setup(); r4k_blast_icache_setup(); r4k_blast_scache_page_setup(); - r4k_blast_scache_page_indexed_setup(); r4k_blast_scache_setup(); r4k_blast_scache_node_setup(); #ifdef CONFIG_EVA @@ -1859,7 +1745,6 @@ void r4k_cache_init(void) __flush_kernel_vmap_range = r4k_flush_kernel_vmap_range; flush_icache_all = r4k_flush_icache_all; - local_flush_data_cache_page = local_r4k_flush_data_cache_page; flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; local_flush_icache_range = local_r4k_flush_icache_range; @@ -1867,15 +1752,9 @@ void r4k_cache_init(void) __local_flush_icache_user_range = local_r4k_flush_icache_user_range; #ifdef CONFIG_DMA_NONCOHERENT - if (dma_default_coherent) { - _dma_cache_wback_inv = (void *)cache_noop; - _dma_cache_wback = (void *)cache_noop; - _dma_cache_inv = (void *)cache_noop; - } else { - _dma_cache_wback_inv = r4k_dma_cache_wback_inv; - _dma_cache_wback = r4k_dma_cache_wback_inv; - _dma_cache_inv = r4k_dma_cache_inv; - } + _dma_cache_wback_inv = r4k_dma_cache_wback_inv; + _dma_cache_wback = r4k_dma_cache_wback_inv; + _dma_cache_inv = r4k_dma_cache_inv; #endif /* CONFIG_DMA_NONCOHERENT */ build_clear_page(); @@ -1908,7 +1787,6 @@ void r4k_cache_init(void) /* I$ fills from D$ just by emptying the write buffers */ flush_cache_page = (void *)b5k_instruction_hazard; flush_cache_range = (void *)b5k_instruction_hazard; - local_flush_data_cache_page = (void *)b5k_instruction_hazard; flush_data_cache_page = (void *)b5k_instruction_hazard; flush_icache_range = (void *)b5k_instruction_hazard; local_flush_icache_range = (void *)b5k_instruction_hazard; @@ -1928,7 +1806,6 @@ void r4k_cache_init(void) flush_cache_range = (void *)cache_noop; flush_icache_all = (void *)cache_noop; flush_data_cache_page = (void *)cache_noop; - local_flush_data_cache_page = (void *)cache_noop; break; } } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 11b3e7ddafd5..d21cf8c6cf6c 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -48,14 +49,30 @@ void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size); EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range); /* MIPS specific cache operations */ -void (*local_flush_data_cache_page)(void * addr); void (*flush_data_cache_page)(unsigned long addr); void (*flush_icache_all)(void); -EXPORT_SYMBOL_GPL(local_flush_data_cache_page); EXPORT_SYMBOL(flush_data_cache_page); EXPORT_SYMBOL(flush_icache_all); +/* + * Dummy cache handling routine + */ + +void cache_noop(void) {} + +#ifdef CONFIG_BOARD_SCACHE + +static struct bcache_ops no_sc_ops = { + .bc_enable = (void *)cache_noop, + .bc_disable = (void *)cache_noop, + .bc_wback_inv = (void *)cache_noop, + .bc_inv = (void *)cache_noop +}; + +struct bcache_ops *bcops = &no_sc_ops; +#endif + #ifdef CONFIG_DMA_NONCOHERENT /* DMA cache operations. */ diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index 13bbd12bfa65..bb2c706e11b0 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile @@ -14,6 +14,4 @@ obj-y += malta-platform.o obj-y += malta-setup.o obj-y += malta-time.o -obj-$(CONFIG_MIPS_CMP) += malta-amon.o - CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c deleted file mode 100644 index 84ac523b0ce0..000000000000 --- a/arch/mips/mti-malta/malta-amon.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2007 MIPS Technologies, Inc. All rights reserved. - * Copyright (C) 2013 Imagination Technologies Ltd. - * - * Arbitrary Monitor Interface - */ -#include -#include - -#include -#include -#include -#include - -int amon_cpu_avail(int cpu) -{ - struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); - - if (cpu < 0 || cpu >= NCPULAUNCH) { - pr_debug("avail: cpu%d is out of range\n", cpu); - return 0; - } - - launch += cpu; - if (!(launch->flags & LAUNCH_FREADY)) { - pr_debug("avail: cpu%d is not ready\n", cpu); - return 0; - } - if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { - pr_debug("avail: too late.. cpu%d is already gone\n", cpu); - return 0; - } - - return 1; -} - -int amon_cpu_start(int cpu, - unsigned long pc, unsigned long sp, - unsigned long gp, unsigned long a0) -{ - volatile struct cpulaunch *launch = - (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); - - if (!amon_cpu_avail(cpu)) - return -1; - if (cpu == smp_processor_id()) { - pr_debug("launch: I am cpu%d!\n", cpu); - return -1; - } - launch += cpu; - - pr_debug("launch: starting cpu%d\n", cpu); - - launch->pc = pc; - launch->gp = gp; - launch->sp = sp; - launch->a0 = a0; - - smp_wmb(); /* Target must see parameters before go */ - launch->flags |= LAUNCH_FGO; - smp_wmb(); /* Target must see go before we poll */ - - while ((launch->flags & LAUNCH_FGONE) == 0) - ; - smp_rmb(); /* Target will be updating flags soon */ - pr_debug("launch: cpu%d gone!\n", cpu); - - return 0; -} - -#ifdef CONFIG_MIPS_VPE_LOADER_CMP -int vpe_run(struct vpe *v) -{ - struct vpe_notifications *n; - - if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0) - return -1; - - list_for_each_entry(n, &v->notify, list) - n->start(VPE_MODULE_MINOR); - - return 0; -} -#endif diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index b03cac5fdc02..000d6d50520a 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -289,8 +289,6 @@ mips_pci_controller: if (!register_cps_smp_ops()) return; - if (!register_cmp_smp_ops()) - return; if (!register_vsmp_smp_ops()) return; register_up_smp_ops(); diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c index 4ffbcc58c6f6..6961a23aefe9 100644 --- a/arch/mips/mti-malta/malta-platform.c +++ b/arch/mips/mti-malta/malta-platform.c @@ -43,7 +43,6 @@ static struct plat_serial8250_port uart8250_data[] = { SMC_PORT(0x3F8, 4), SMC_PORT(0x2F8, 3), -#ifndef CONFIG_MIPS_CMP { .mapbase = 0x1f000900, /* The CBUS UART */ .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, @@ -53,7 +52,6 @@ static struct plat_serial8250_port uart8250_data[] = { .flags = CBUS_UART_FLAGS, .regshift = 3, }, -#endif { }, }; diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index d967e4c0cf24..79e29bf42a24 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -118,7 +118,7 @@ static int ltq_pci_startup(struct platform_device *pdev) /* and enable the clocks */ clk_enable(clk_pci); - if (of_find_property(node, "lantiq,external-clock", NULL)) + if (of_property_read_bool(node, "lantiq,external-clock")) clk_enable(clk_external); else clk_disable(clk_external); diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index d59888aaed81..4ac68a534e4f 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -419,7 +419,7 @@ static int rt3883_pci_probe(struct platform_device *pdev) /* find the interrupt controller child node */ for_each_child_of_node(np, child) { - if (of_get_property(child, "interrupt-controller", NULL)) { + if (of_property_read_bool(child, "interrupt-controller")) { rpc->intc_of_node = child; break; } diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 83e61e147b90..08c012a2591f 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -29,18 +29,22 @@ choice select MIPS_AUTO_PFN_OFFSET select MIPS_L1_CACHE_SHIFT_4 select HAVE_PCI + select SOC_BUS config SOC_RT305X bool "RT305x" + select SOC_BUS config SOC_RT3883 bool "RT3883" select HAVE_PCI + select SOC_BUS config SOC_MT7620 bool "MT7620/8" select CPU_MIPSR2_IRQ_VI select HAVE_PCI + select SOC_BUS config SOC_MT7621 bool "MT7621" diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index ae1fa0391c88..4435f50b8d24 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -49,6 +51,8 @@ /* does the board have sdram or ddram */ static int dram_type; +static struct ralink_soc_info *soc_info_ptr; + static __init u32 mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div) { @@ -324,35 +328,76 @@ mt7628_dram_init(struct ralink_soc_info *soc_info) } } -void __init prom_soc_init(struct ralink_soc_info *soc_info) +static unsigned int __init mt7620_get_soc_name0(void) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7620_SYSC_BASE); - unsigned char *name = NULL; - u32 n0; - u32 n1; - u32 rev; - u32 cfg0; - u32 pmu0; - u32 pmu1; - u32 bga; + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); - rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); - bga = (rev >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; +static unsigned int __init mt7620_get_soc_name1(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} + +static bool __init mt7620_soc_valid(void) +{ + if (mt7620_get_soc_name0() == MT7620_CHIP_NAME0 && + mt7620_get_soc_name1() == MT7620_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init mt7628_soc_valid(void) +{ + if (mt7620_get_soc_name0() == MT7620_CHIP_NAME0 && + mt7620_get_soc_name1() == MT7628_CHIP_NAME1) + return true; + else + return false; +} + +static unsigned int __init mt7620_get_rev(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_CHIP_REV); +} + +static unsigned int __init mt7620_get_bga(void) +{ + return (mt7620_get_rev() >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; +} + +static unsigned int __init mt7620_get_efuse(void) +{ + return __raw_readl(MT7620_SYSC_BASE + SYSC_REG_EFUSE_CFG); +} + +static unsigned int __init mt7620_get_soc_ver(void) +{ + return (mt7620_get_rev() >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK; +} + +static unsigned int __init mt7620_get_soc_eco(void) +{ + return (mt7620_get_rev() & CHIP_REV_ECO_MASK); +} + +static const char __init *mt7620_get_soc_name(struct ralink_soc_info *soc_info) +{ + if (mt7620_soc_valid()) { + u32 bga = mt7620_get_bga(); - if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) { if (bga) { ralink_soc = MT762X_SOC_MT7620A; - name = "MT7620A"; soc_info->compatible = "ralink,mt7620a-soc"; + return "MT7620A"; } else { ralink_soc = MT762X_SOC_MT7620N; - name = "MT7620N"; soc_info->compatible = "ralink,mt7620n-soc"; + return "MT7620N"; } - } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { - u32 efuse = __raw_readl(sysc + SYSC_REG_EFUSE_CFG); + } else if (mt7628_soc_valid()) { + u32 efuse = mt7620_get_efuse(); + unsigned char *name = NULL; if (efuse & EFUSE_MT7688) { ralink_soc = MT762X_SOC_MT7688; @@ -362,17 +407,63 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) name = "MT7628AN"; } soc_info->compatible = "ralink,mt7628an-soc"; + return name; } else { - panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", n0, n1); + panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", + mt7620_get_soc_name0(), mt7620_get_soc_name1()); } +} + +static const char __init *mt7620_get_soc_id_name(void) +{ + if (ralink_soc == MT762X_SOC_MT7620A) + return "mt7620a"; + else if (ralink_soc == MT762X_SOC_MT7620N) + return "mt7620n"; + else if (ralink_soc == MT762X_SOC_MT7688) + return "mt7688"; + else if (ralink_soc == MT762X_SOC_MT7628AN) + return "mt7628n"; + else + return "invalid"; +} + +static int __init mt7620_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = mt7620_get_soc_id_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(mt7620_soc_dev_init); + +void __init prom_soc_init(struct ralink_soc_info *soc_info) +{ + const char *name = mt7620_get_soc_name(soc_info); + u32 cfg0; + u32 pmu0; + u32 pmu1; snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "MediaTek %s ver:%u eco:%u", - name, - (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, - (rev & CHIP_REV_ECO_MASK)); + name, mt7620_get_soc_ver(), mt7620_get_soc_eco()); - cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); + cfg0 = __raw_readl(MT7620_SYSC_BASE + SYSC_REG_SYSTEM_CONFIG0); if (is_mt76x8()) { dram_type = cfg0 & DRAM_TYPE_MT7628_MASK; } else { @@ -388,11 +479,13 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) else mt7620_dram_init(soc_info); - pmu0 = __raw_readl(sysc + PMU0_CFG); - pmu1 = __raw_readl(sysc + PMU1_CFG); + pmu0 = __raw_readl(MT7620_SYSC_BASE + PMU0_CFG); + pmu1 = __raw_readl(MT7620_SYSC_BASE + PMU1_CFG); pr_info("Analog PMU set to %s control\n", (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); pr_info("Digital PMU set to %s control\n", (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw")); + + soc_info_ptr = soc_info; } diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index bbf5811afbf2..c3fbab50b95c 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -217,8 +217,6 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) if (!register_cps_smp_ops()) return; - if (!register_cmp_smp_ops()) - return; if (!register_vsmp_smp_ops()) return; } diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 493335db2fe1..456ba0b2599e 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -17,6 +19,8 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + void __init ralink_clk_init(void) { unsigned long cpu_rate, wmac_rate = 40000000; @@ -57,34 +61,90 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } +static unsigned int __init rt2880_get_soc_name0(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} + +static unsigned int __init rt2880_get_soc_name1(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} + +static bool __init rt2880_soc_valid(void) +{ + if (rt2880_get_soc_name0() == RT2880_CHIP_NAME0 && + rt2880_get_soc_name1() == RT2880_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt2880_get_soc_name(void) +{ + if (rt2880_soc_valid()) + return "RT2880"; + else + return "invalid"; +} + +static unsigned int __init rt2880_get_soc_id(void) +{ + return __raw_readl(RT2880_SYSC_BASE + SYSC_REG_CHIP_ID); +} + +static unsigned int __init rt2880_get_soc_ver(void) +{ + return (rt2880_get_soc_id() >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK; +} + +static unsigned int __init rt2880_get_soc_rev(void) +{ + return (rt2880_get_soc_id() & CHIP_ID_REV_MASK); +} + +static int __init rt2880_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt2880_get_soc_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(rt2880_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT2880_SYSC_BASE); - const char *name; - u32 n0; - u32 n1; - u32 id; - - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); - id = __raw_readl(sysc + SYSC_REG_CHIP_ID); - - if (n0 == RT2880_CHIP_NAME0 && n1 == RT2880_CHIP_NAME1) { + if (rt2880_soc_valid()) soc_info->compatible = "ralink,r2880-soc"; - name = "RT2880"; - } else { - panic("rt288x: unknown SoC, n0:%08x n1:%08x", n0, n1); - } + else + panic("rt288x: unknown SoC, n0:%08x n1:%08x", + rt2880_get_soc_name0(), rt2880_get_soc_name1()); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s id:%u rev:%u", - name, - (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, - (id & CHIP_ID_REV_MASK)); + rt2880_get_soc_name(), + rt2880_get_soc_ver(), + rt2880_get_soc_rev()); soc_info->mem_base = RT2880_SDRAM_BASE; soc_info->mem_size_min = RT2880_MEM_SIZE_MIN; soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; ralink_soc = RT2880_SOC; + soc_info_ptr = soc_info; } diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index 8b095a9dcb15..d8dcc5cc66cc 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -19,13 +21,14 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + static unsigned long rt5350_get_mem_size(void) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); unsigned long ret; u32 t; - t = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG); + t = __raw_readl(RT305X_SYSC_BASE + SYSC_REG_SYSTEM_CONFIG); t = (t >> RT5350_SYSCFG0_DRAM_SIZE_SHIFT) & RT5350_SYSCFG0_DRAM_SIZE_MASK; @@ -140,53 +143,149 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } -void __init prom_soc_init(struct ralink_soc_info *soc_info) +static unsigned int __init rt305x_get_soc_name0(void) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); - unsigned char *name; - u32 n0; - u32 n1; - u32 id; + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME0); +} - n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); - n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); +static unsigned int __init rt305x_get_soc_name1(void) +{ + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_NAME1); +} - if (n0 == RT3052_CHIP_NAME0 && n1 == RT3052_CHIP_NAME1) { +static bool __init rt3052_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3052_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3052_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt3350_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3350_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3350_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt3352_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT3352_CHIP_NAME0 && + rt305x_get_soc_name1() == RT3352_CHIP_NAME1) + return true; + else + return false; +} + +static bool __init rt5350_soc_valid(void) +{ + if (rt305x_get_soc_name0() == RT5350_CHIP_NAME0 && + rt305x_get_soc_name1() == RT5350_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt305x_get_soc_name(struct ralink_soc_info *soc_info) +{ + if (rt3052_soc_valid()) { unsigned long icache_sets; icache_sets = (read_c0_config1() >> 22) & 7; if (icache_sets == 1) { ralink_soc = RT305X_SOC_RT3050; - name = "RT3050"; soc_info->compatible = "ralink,rt3050-soc"; + return "RT3050"; } else { ralink_soc = RT305X_SOC_RT3052; - name = "RT3052"; soc_info->compatible = "ralink,rt3052-soc"; + return "RT3052"; } - } else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) { + } else if (rt3350_soc_valid()) { ralink_soc = RT305X_SOC_RT3350; - name = "RT3350"; soc_info->compatible = "ralink,rt3350-soc"; - } else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) { + return "RT3350"; + } else if (rt3352_soc_valid()) { ralink_soc = RT305X_SOC_RT3352; - name = "RT3352"; soc_info->compatible = "ralink,rt3352-soc"; - } else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) { + return "RT3352"; + } else if (rt5350_soc_valid()) { ralink_soc = RT305X_SOC_RT5350; - name = "RT5350"; soc_info->compatible = "ralink,rt5350-soc"; + return "RT5350"; } else { - panic("rt305x: unknown SoC, n0:%08x n1:%08x", n0, n1); + panic("rt305x: unknown SoC, n0:%08x n1:%08x", + rt305x_get_soc_name0(), rt305x_get_soc_name1()); + } +} + +static unsigned int __init rt305x_get_soc_id(void) +{ + return __raw_readl(RT305X_SYSC_BASE + SYSC_REG_CHIP_ID); +} + +static unsigned int __init rt305x_get_soc_ver(void) +{ + return (rt305x_get_soc_id() >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK; +} + +static unsigned int __init rt305x_get_soc_rev(void) +{ + return (rt305x_get_soc_id() & CHIP_ID_REV_MASK); +} + +static const char __init *rt305x_get_soc_id_name(void) +{ + if (soc_is_rt3050()) + return "rt3050"; + else if (soc_is_rt3052()) + return "rt3052"; + else if (soc_is_rt3350()) + return "rt3350"; + else if (soc_is_rt3352()) + return "rt3352"; + else if (soc_is_rt5350()) + return "rt5350"; + else + return "invalid"; +} + +static int __init rt305x_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt305x_get_soc_id_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); } - id = __raw_readl(sysc + SYSC_REG_CHIP_ID); + return 0; +} +device_initcall(rt305x_soc_dev_init); + +void __init prom_soc_init(struct ralink_soc_info *soc_info) +{ + const char *name = rt305x_get_soc_name(soc_info); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s id:%u rev:%u", name, - (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, - (id & CHIP_ID_REV_MASK)); + rt305x_get_soc_ver(), + rt305x_get_soc_rev()); soc_info->mem_base = RT305X_SDRAM_BASE; if (soc_is_rt5350()) { @@ -198,4 +297,6 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_size_min = RT3352_MEM_SIZE_MIN; soc_info->mem_size_max = RT3352_MEM_SIZE_MAX; } + + soc_info_ptr = soc_info; } diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index d9875f146d66..cca887af378f 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -17,6 +19,8 @@ #include "common.h" +static struct ralink_soc_info *soc_info_ptr; + void __init ralink_clk_init(void) { unsigned long cpu_rate, sys_rate; @@ -70,34 +74,90 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } +static unsigned int __init rt3883_get_soc_name0(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID0_3); +} + +static unsigned int __init rt3883_get_soc_name1(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_CHIPID4_7); +} + +static bool __init rt3883_soc_valid(void) +{ + if (rt3883_get_soc_name0() == RT3883_CHIP_NAME0 && + rt3883_get_soc_name1() == RT3883_CHIP_NAME1) + return true; + else + return false; +} + +static const char __init *rt3883_get_soc_name(void) +{ + if (rt3883_soc_valid()) + return "RT3883"; + else + return "invalid"; +} + +static unsigned int __init rt3883_get_soc_id(void) +{ + return __raw_readl(RT3883_SYSC_BASE + RT3883_SYSC_REG_REVID); +} + +static unsigned int __init rt3883_get_soc_ver(void) +{ + return (rt3883_get_soc_id() >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK; +} + +static unsigned int __init rt3883_get_soc_rev(void) +{ + return (rt3883_get_soc_id() & RT3883_REVID_ECO_ID_MASK); +} + +static int __init rt3883_soc_dev_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Ralink"; + soc_dev_attr->soc_id = rt3883_get_soc_name(); + + soc_dev_attr->data = soc_info_ptr; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +device_initcall(rt3883_soc_dev_init); + void __init prom_soc_init(struct ralink_soc_info *soc_info) { - void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT3883_SYSC_BASE); - const char *name; - u32 n0; - u32 n1; - u32 id; - - n0 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID0_3); - n1 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID4_7); - id = __raw_readl(sysc + RT3883_SYSC_REG_REVID); - - if (n0 == RT3883_CHIP_NAME0 && n1 == RT3883_CHIP_NAME1) { + if (rt3883_soc_valid()) soc_info->compatible = "ralink,rt3883-soc"; - name = "RT3883"; - } else { - panic("rt3883: unknown SoC, n0:%08x n1:%08x", n0, n1); - } + else + panic("rt3883: unknown SoC, n0:%08x n1:%08x", + rt3883_get_soc_name0(), rt3883_get_soc_name1()); snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s ver:%u eco:%u", - name, - (id >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK, - (id & RT3883_REVID_ECO_ID_MASK)); + rt3883_get_soc_name(), + rt3883_get_soc_ver(), + rt3883_get_soc_rev()); soc_info->mem_base = RT3883_SDRAM_BASE; soc_info->mem_size_min = RT3883_MEM_SIZE_MIN; soc_info->mem_size_max = RT3883_MEM_SIZE_MAX; ralink_soc = RT3883_SOC; + soc_info_ptr = soc_info; } diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index 470d46183677..5fb92fe84149 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -10,15 +10,6 @@ config SIBYTE_SB1250 select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP -config SIBYTE_BCM1120 - bool - select CEVT_SB1250 - select CSRC_SB1250 - select IRQ_MIPS_CPU - select SIBYTE_BCM112X - select SIBYTE_HAS_ZBUS_PROFILING - select SIBYTE_SB1xxx_SOC - config SIBYTE_BCM1125 bool select CEVT_SB1250 @@ -29,17 +20,6 @@ config SIBYTE_BCM1125 select SIBYTE_HAS_ZBUS_PROFILING select SIBYTE_SB1xxx_SOC -config SIBYTE_BCM1125H - bool - select CEVT_SB1250 - select CSRC_SB1250 - select HAVE_PCI - select IRQ_MIPS_CPU - select SIBYTE_BCM112X - select SIBYTE_ENABLE_LDT_IF_PCI - select SIBYTE_HAS_ZBUS_PROFILING - select SIBYTE_SB1xxx_SOC - config SIBYTE_BCM112X bool select CEVT_SB1250 @@ -58,16 +38,6 @@ config SIBYTE_BCM1x80 select SIBYTE_SB1xxx_SOC select SYS_SUPPORTS_SMP -config SIBYTE_BCM1x55 - bool - select CEVT_BCM1480 - select CSRC_BCM1480 - select HAVE_PCI - select IRQ_MIPS_CPU - select SIBYTE_SB1xxx_SOC - select SIBYTE_HAS_ZBUS_PROFILING - select SYS_SUPPORTS_SMP - config SIBYTE_SB1xxx_SOC bool select IRQ_MIPS_CPU @@ -143,8 +113,7 @@ config SIBYTE_CFE_CONSOLE config SIBYTE_BUS_WATCHER bool "Support for Bus Watcher statistics" depends on SIBYTE_SB1xxx_SOC && \ - (SIBYTE_BCM112X || SIBYTE_SB1250 || \ - SIBYTE_BCM1x55 || SIBYTE_BCM1x80) + (SIBYTE_BCM112X || SIBYTE_SB1250 || SIBYTE_BCM1x80) help Handle and keep statistics on the bus error interrupts (COR_ECC, BAD_ECC, IO_BUS). diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile index d015c4d79c3e..47078353fe8a 100644 --- a/arch/mips/sibyte/Makefile +++ b/arch/mips/sibyte/Makefile @@ -6,21 +6,15 @@ obj-$(CONFIG_SIBYTE_BCM112X) += sb1250/ obj-$(CONFIG_SIBYTE_BCM112X) += common/ obj-$(CONFIG_SIBYTE_SB1250) += sb1250/ obj-$(CONFIG_SIBYTE_SB1250) += common/ -obj-$(CONFIG_SIBYTE_BCM1x55) += bcm1480/ -obj-$(CONFIG_SIBYTE_BCM1x55) += common/ obj-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/ obj-$(CONFIG_SIBYTE_BCM1x80) += common/ # -# Sibyte BCM91120x (Carmel) board -# Sibyte BCM91120C (CRhine) board # Sibyte BCM91125C (CRhone) board # Sibyte BCM91125E (Rhone) board # Sibyte SWARM board # Sibyte BCM91x80 (BigSur) board # -obj-$(CONFIG_SIBYTE_CARMEL) += swarm/ -obj-$(CONFIG_SIBYTE_CRHINE) += swarm/ obj-$(CONFIG_SIBYTE_CRHONE) += swarm/ obj-$(CONFIG_SIBYTE_RHONE) += swarm/ obj-$(CONFIG_SIBYTE_SENTOSA) += swarm/ diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform index 65b2225b76b2..937108e41f13 100644 --- a/arch/mips/sibyte/Platform +++ b/arch/mips/sibyte/Platform @@ -13,25 +13,17 @@ cflags-$(CONFIG_SIBYTE_SB1250) += \ -I$(srctree)/arch/mips/include/asm/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL -cflags-$(CONFIG_SIBYTE_BCM1x55) += \ - -I$(srctree)/arch/mips/include/asm/mach-sibyte \ - -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL - cflags-$(CONFIG_SIBYTE_BCM1x80) += \ -I$(srctree)/arch/mips/include/asm/mach-sibyte \ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL # -# Sibyte BCM91120x (Carmel) board -# Sibyte BCM91120C (CRhine) board # Sibyte BCM91125C (CRhone) board # Sibyte BCM91125E (Rhone) board # Sibyte BCM91250A (SWARM) board # Sibyte BCM91250C2 (LittleSur) board # Sibyte BCM91x80 (BigSur) board # -load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000 -load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000 load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000 diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c index d43291473f76..a296d2c51841 100644 --- a/arch/mips/sibyte/common/bus_watcher.c +++ b/arch/mips/sibyte/common/bus_watcher.c @@ -24,7 +24,7 @@ #include #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #endif @@ -71,7 +71,7 @@ void check_bus_watcher(void) #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) /* Use non-destructive register */ status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG)); -#elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#elif defined(CONFIG_SIBYTE_BCM1x80) /* Use non-destructive register */ /* Same as 1250 except BUS_ERR_STATUS_DEBUG is in a different place. */ status = csr_in32(IOADDR(A_BCM1480_BUS_ERR_STATUS_DEBUG)); diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c index 1a504294d85f..2cb90dbbe843 100644 --- a/arch/mips/sibyte/common/cfe.c +++ b/arch/mips/sibyte/common/cfe.c @@ -35,11 +35,6 @@ #endif #endif -#define SIBYTE_MAX_MEM_REGIONS 8 -phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS]; -phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS]; -unsigned int board_mem_region_count; - int cfe_cons_handle; #ifdef CONFIG_BLK_DEV_INITRD @@ -141,16 +136,6 @@ static __init void prom_meminit(void) size -= 512; memblock_add(addr, size); } - board_mem_region_addrs[board_mem_region_count] = addr; - board_mem_region_sizes[board_mem_region_count] = size; - board_mem_region_count++; - if (board_mem_region_count == - SIBYTE_MAX_MEM_REGIONS) { - /* - * Too many regions. Need to configure more - */ - while(1); - } } } #ifdef CONFIG_BLK_DEV_INITRD @@ -310,7 +295,7 @@ void __init prom_init(void) #if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250) register_smp_ops(&sb_smp_ops); #endif -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 register_smp_ops(&bcm1480_smp_ops); #endif } diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index bc47681e825a..408db45efdc8 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c @@ -23,7 +23,7 @@ #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #include #include @@ -35,7 +35,7 @@ #error invalid SiByte UART configuration #endif -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #undef K_INT_TRACE_FREEZE #define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE #undef K_INT_PERF_CNT @@ -157,7 +157,7 @@ static void arm_tb(void) * a previous interrupt request. This means that bus profiling * requires ALL of the SCD perf counters. */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) | /* keep counters 0,2,3,4,5,6,7 as is */ V_SPC_CFG_SRC1(1), /* counter 1 counts cycles */ @@ -290,7 +290,7 @@ static int sbprof_zbprof_start(struct file *filp) * pass them through. I am exploiting my knowledge that * cp0_status masks out IP[5]. krw */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq(K_BCM1480_INT_MAP_I3, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) + ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3))); @@ -343,7 +343,7 @@ static int sbprof_zbprof_start(struct file *filp) __raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7)); /* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */ -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 __raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f), IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L))); #else @@ -550,7 +550,7 @@ static int __init sbprof_tb_init(void) return -EIO; } - tbc = class_create(THIS_MODULE, "sb_tracebuffer"); + tbc = class_create("sb_tracebuffer"); if (IS_ERR(tbc)) { err = PTR_ERR(tbc); goto out_chrdev; diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 72a31eeeebba..76683993cdd3 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -24,7 +24,7 @@ #include #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 #include #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include @@ -34,7 +34,7 @@ #include #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 extern void bcm1480_setup(void); #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) extern void sb1250_setup(void); @@ -114,7 +114,7 @@ int update_persistent_clock64(struct timespec64 now) void __init plat_mem_setup(void) { -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#ifdef CONFIG_SIBYTE_BCM1x80 bcm1480_setup(); #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) sb1250_setup(); @@ -146,12 +146,6 @@ void __init plat_mem_setup(void) #ifdef LEDS_PHYS -#ifdef CONFIG_SIBYTE_CARMEL -/* XXXKW need to detect Monterey/LittleSur/etc */ -#undef LEDS_PHYS -#define LEDS_PHYS MLEDS_PHYS -#endif - void setleds(char *str) { void *reg; diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index a582f72104f3..e5936417d3cd 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -45,19 +45,17 @@ menu "Kernel features" source "kernel/Kconfig.hz" config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - range 9 20 - default "11" + int "Order of maximal physically contiguous allocations" + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + Don't change if unsure. endmenu diff --git a/arch/openrisc/include/asm/cmpxchg.h b/arch/openrisc/include/asm/cmpxchg.h index 79fd16162ccb..8ee151c072e4 100644 --- a/arch/openrisc/include/asm/cmpxchg.h +++ b/arch/openrisc/include/asm/cmpxchg.h @@ -147,8 +147,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, extern unsigned long __xchg_called_with_bad_pointer(void) __compiletime_error("Bad argument size for xchg"); -static inline unsigned long __xchg(volatile void *ptr, unsigned long with, - int size) +static inline unsigned long +__arch_xchg(volatile void *ptr, unsigned long with, int size) { switch (size) { case 1: @@ -163,9 +163,9 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long with, #define arch_xchg(ptr, with) \ ({ \ - (__typeof__(*(ptr))) __xchg((ptr), \ - (unsigned long)(with), \ - sizeof(*(ptr))); \ + (__typeof__(*(ptr))) __arch_xchg((ptr), \ + (unsigned long)(with), \ + sizeof(*(ptr))); \ }) #endif /* __ASM_OPENRISC_CMPXCHG_H */ diff --git a/arch/openrisc/include/asm/ptrace.h b/arch/openrisc/include/asm/ptrace.h index 01f81d4e97dc..375147ff71fc 100644 --- a/arch/openrisc/include/asm/ptrace.h +++ b/arch/openrisc/include/asm/ptrace.h @@ -59,7 +59,7 @@ struct pt_regs { * -1 for all other exceptions. */ long orig_gpr11; /* For restarting system calls */ - long dummy; /* Cheap alignment fix */ + long fpcsr; /* Floating point control status register. */ long dummy2; /* Cheap alignment fix */ }; @@ -115,6 +115,6 @@ static inline long regs_return_value(struct pt_regs *regs) #define PT_GPR31 124 #define PT_PC 128 #define PT_ORIG_GPR11 132 -#define PT_SYSCALLNO 136 +#define PT_FPCSR 136 #endif /* __ASM_OPENRISC_PTRACE_H */ diff --git a/arch/openrisc/include/uapi/asm/elf.h b/arch/openrisc/include/uapi/asm/elf.h index e892d5061685..6868f81c281e 100644 --- a/arch/openrisc/include/uapi/asm/elf.h +++ b/arch/openrisc/include/uapi/asm/elf.h @@ -53,8 +53,7 @@ typedef unsigned long elf_greg_t; #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -/* A placeholder; OR32 does not have fp support yes, so no fp regs for now. */ -typedef unsigned long elf_fpregset_t; +typedef struct __or1k_fpu_state elf_fpregset_t; /* EM_OPENRISC is defined in linux/elf-em.h */ #define EM_OR32 0x8472 diff --git a/arch/openrisc/include/uapi/asm/ptrace.h b/arch/openrisc/include/uapi/asm/ptrace.h index d4fab268f6aa..a77cc9915ca8 100644 --- a/arch/openrisc/include/uapi/asm/ptrace.h +++ b/arch/openrisc/include/uapi/asm/ptrace.h @@ -30,6 +30,10 @@ struct user_regs_struct { unsigned long pc; unsigned long sr; }; + +struct __or1k_fpu_state { + unsigned long fpcsr; +}; #endif diff --git a/arch/openrisc/include/uapi/asm/sigcontext.h b/arch/openrisc/include/uapi/asm/sigcontext.h index 8ab775fc3450..ca585e4af6b8 100644 --- a/arch/openrisc/include/uapi/asm/sigcontext.h +++ b/arch/openrisc/include/uapi/asm/sigcontext.h @@ -28,6 +28,7 @@ struct sigcontext { struct user_regs_struct regs; /* needs to be first */ + struct __or1k_fpu_state fpu; unsigned long oldmask; }; diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index 54a87bba35ca..c9f48e750b72 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -106,6 +106,8 @@ l.mtspr r0,r3,SPR_EPCR_BASE ;\ l.lwz r3,PT_SR(r1) ;\ l.mtspr r0,r3,SPR_ESR_BASE ;\ + l.lwz r3,PT_FPCSR(r1) ;\ + l.mtspr r0,r3,SPR_FPCSR ;\ l.lwz r2,PT_GPR2(r1) ;\ l.lwz r3,PT_GPR3(r1) ;\ l.lwz r4,PT_GPR4(r1) ;\ @@ -173,9 +175,10 @@ handler: ;\ l.sw PT_GPR28(r1),r28 ;\ l.sw PT_GPR29(r1),r29 ;\ /* r30 already save */ ;\ -/* l.sw PT_GPR30(r1),r30*/ ;\ l.sw PT_GPR31(r1),r31 ;\ TRACE_IRQS_OFF_ENTRY ;\ + l.mfspr r30,r0,SPR_FPCSR ;\ + l.sw PT_FPCSR(r1),r30 ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ l.addi r30,r0,-1 ;\ l.sw PT_ORIG_GPR11(r1),r30 @@ -211,12 +214,13 @@ handler: ;\ l.sw PT_GPR27(r1),r27 ;\ l.sw PT_GPR28(r1),r28 ;\ l.sw PT_GPR29(r1),r29 ;\ - /* r31 already saved */ ;\ - l.sw PT_GPR30(r1),r30 ;\ -/* l.sw PT_GPR31(r1),r31 */ ;\ + /* r30 already saved */ ;\ + l.sw PT_GPR31(r1),r31 ;\ /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\ l.addi r30,r0,-1 ;\ l.sw PT_ORIG_GPR11(r1),r30 ;\ + l.mfspr r30,r0,SPR_FPCSR ;\ + l.sw PT_FPCSR(r1),r30 ;\ l.addi r3,r1,0 ;\ /* r4 is exception EA */ ;\ l.addi r5,r0,vector ;\ @@ -844,9 +848,16 @@ _syscall_badsys: /******* END SYSCALL HANDLING *******/ -/* ---[ 0xd00: Trap exception ]------------------------------------------ */ +/* ---[ 0xd00: Floating Point exception ]-------------------------------- */ -UNHANDLED_EXCEPTION(_vector_0xd00,0xd00) +EXCEPTION_ENTRY(_fpe_trap_handler) + CLEAR_LWA_FLAG(r3) + /* r4: EA of fault (set by EXCEPTION_HANDLE) */ + l.jal do_fpe_trap + l.addi r3,r1,0 /* pt_regs */ + + l.j _ret_from_exception + l.nop /* ---[ 0xe00: Trap exception ]------------------------------------------ */ @@ -1089,6 +1100,10 @@ ENTRY(_switch) l.sw PT_GPR28(r1),r28 l.sw PT_GPR30(r1),r30 + /* Store the old FPU state to new pt_regs */ + l.mfspr r29,r0,SPR_FPCSR + l.sw PT_FPCSR(r1),r29 + l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/ /* We use thread_info->ksp for storing the address of the above @@ -1111,6 +1126,10 @@ ENTRY(_switch) l.lwz r29,PT_SP(r1) l.sw TI_KSP(r10),r29 + /* Restore the old value of FPCSR */ + l.lwz r29,PT_FPCSR(r1) + l.mtspr r0,r29,SPR_FPCSR + /* ...and restore the registers, except r11 because the return value * has already been set above. */ diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index e11699f3d6bd..439e00f81e5d 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S @@ -424,9 +424,9 @@ _dispatch_do_ipage_fault: .org 0xc00 EXCEPTION_HANDLE(_sys_call_handler) -/* ---[ 0xd00: Trap exception ]------------------------------------------ */ +/* ---[ 0xd00: Floating point exception ]--------------------------------- */ .org 0xd00 - UNHANDLED_EXCEPTION(_vector_0xd00) + EXCEPTION_HANDLE(_fpe_trap_handler) /* ---[ 0xe00: Trap exception ]------------------------------------------ */ .org 0xe00 diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c index 85ace93fc251..0b7d2ca6ba3b 100644 --- a/arch/openrisc/kernel/ptrace.c +++ b/arch/openrisc/kernel/ptrace.c @@ -84,11 +84,40 @@ static int genregs_set(struct task_struct *target, return ret; } +/* + * As OpenRISC shares GPRs and floating point registers we don't need to export + * the floating point registers again. So here we only export the fpcsr special + * purpose register. + */ +static int fpregs_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + const struct pt_regs *regs = task_pt_regs(target); + + return membuf_store(&to, regs->fpcsr); +} + +static int fpregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + /* FPCSR */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->fpcsr, 0, 4); + return ret; +} + /* * Define the register sets available on OpenRISC under Linux */ enum or1k_regset { REGSET_GENERAL, + REGSET_FPU, }; static const struct user_regset or1k_regsets[] = { @@ -100,6 +129,14 @@ static const struct user_regset or1k_regsets[] = { .regset_get = genregs_get, .set = genregs_set, }, + [REGSET_FPU] = { + .core_note_type = NT_PRFPREG, + .n = sizeof(struct __or1k_fpu_state) / sizeof(long), + .size = sizeof(long), + .align = sizeof(long), + .regset_get = fpregs_get, + .set = fpregs_set, + }, }; static const struct user_regset_view user_or1k_native_view = { diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c index 0cd04d936a7a..9cf7fb60441f 100644 --- a/arch/openrisc/kernel/setup.c +++ b/arch/openrisc/kernel/setup.c @@ -152,21 +152,6 @@ static void print_cpuinfo(void) printk(KERN_INFO "-- custom unit(s)\n"); } -static struct device_node *setup_find_cpu_node(int cpu) -{ - u32 hwid; - struct device_node *cpun; - - for_each_of_cpu_node(cpun) { - if (of_property_read_u32(cpun, "reg", &hwid)) - continue; - if (hwid == cpu) - return cpun; - } - - return NULL; -} - void __init setup_cpuinfo(void) { struct device_node *cpu; @@ -175,7 +160,7 @@ void __init setup_cpuinfo(void) int cpu_id = smp_processor_id(); struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id]; - cpu = setup_find_cpu_node(cpu_id); + cpu = of_get_cpu_node(cpu_id, NULL); if (!cpu) panic("Couldn't find CPU%d in device tree...\n", cpu_id); @@ -255,7 +240,7 @@ static inline unsigned long extract_value(unsigned long reg, unsigned long mask) void calibrate_delay(void) { const int *val; - struct device_node *cpu = setup_find_cpu_node(smp_processor_id()); + struct device_node *cpu = of_get_cpu_node(smp_processor_id(), NULL); val = of_get_property(cpu, "clock-frequency", NULL); if (!val) diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index 80f69740c731..4664a18f0787 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -50,6 +50,7 @@ static int restore_sigcontext(struct pt_regs *regs, err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)); err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)); + err |= __copy_from_user(®s->fpcsr, &sc->fpu.fpcsr, sizeof(unsigned long)); /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; @@ -112,6 +113,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); + err |= __copy_to_user(&sc->fpu.fpcsr, ®s->fpcsr, sizeof(unsigned long)); return err; } diff --git a/arch/openrisc/kernel/smp.c b/arch/openrisc/kernel/smp.c index e1419095a6f0..0a7a059e2dff 100644 --- a/arch/openrisc/kernel/smp.c +++ b/arch/openrisc/kernel/smp.c @@ -173,7 +173,7 @@ void handle_IPI(unsigned int ipi_msg) } } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index fd9a0f2b66c4..0aa6b07efda1 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -75,8 +75,9 @@ void show_registers(struct pt_regs *regs) in_kernel = 0; printk("CPU #: %d\n" - " PC: %08lx SR: %08lx SP: %08lx\n", - smp_processor_id(), regs->pc, regs->sr, regs->sp); + " PC: %08lx SR: %08lx SP: %08lx FPCSR: %08lx\n", + smp_processor_id(), regs->pc, regs->sr, regs->sp, + regs->fpcsr); printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", 0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]); printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", @@ -242,6 +243,28 @@ asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector) die("Oops", regs, 9); } +asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address) +{ + int code = FPE_FLTUNK; + unsigned long fpcsr = regs->fpcsr; + + if (fpcsr & SPR_FPCSR_IVF) + code = FPE_FLTINV; + else if (fpcsr & SPR_FPCSR_OVF) + code = FPE_FLTOVF; + else if (fpcsr & SPR_FPCSR_UNF) + code = FPE_FLTUND; + else if (fpcsr & SPR_FPCSR_DZF) + code = FPE_FLTDIV; + else if (fpcsr & SPR_FPCSR_IXF) + code = FPE_FLTRES; + + /* Clear all flags */ + regs->fpcsr &= ~SPR_FPCSR_ALLF; + + force_sig_fault(SIGFPE, code, (void __user *)regs->pc); +} + asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) { force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 466a25525364..967bde65dd0e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -130,6 +130,10 @@ config PM config STACKTRACE_SUPPORT def_bool y +config LOCKDEP_SUPPORT + bool + default y + config ISA_DMA_API bool diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug index f66554cd5c45..3a059cb5e112 100644 --- a/arch/parisc/Kconfig.debug +++ b/arch/parisc/Kconfig.debug @@ -1 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 +# +config LIGHTWEIGHT_SPINLOCK_CHECK + bool "Enable lightweight spinlock checks" + depends on SMP && !DEBUG_SPINLOCK + default y + help + Add checks with low performance impact to the spinlock functions + to catch memory overwrites at runtime. For more advanced + spinlock debugging you should choose the DEBUG_SPINLOCK option + which will detect unitialized spinlocks too. + If unsure say Y here. diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 0bdee6724132..c8b6928cee1e 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -48,6 +48,10 @@ void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages) #define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages) +#define flush_dcache_mmap_lock_irqsave(mapping, flags) \ + xa_lock_irqsave(&mapping->i_pages, flags) +#define flush_dcache_mmap_unlock_irqrestore(mapping, flags) \ + xa_unlock_irqrestore(&mapping->i_pages, flags) #define flush_icache_page(vma,page) do { \ flush_kernel_dcache_page_addr(page_address(page)); \ diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h index 5f274be10567..c1d776bb16b4 100644 --- a/arch/parisc/include/asm/cmpxchg.h +++ b/arch/parisc/include/asm/cmpxchg.h @@ -22,7 +22,7 @@ extern unsigned long __xchg64(unsigned long, volatile unsigned long *); /* optimizer better get rid of switch since size is a constant */ static inline unsigned long -__xchg(unsigned long x, volatile void *ptr, int size) +__arch_xchg(unsigned long x, volatile void *ptr, int size) { switch (size) { #ifdef CONFIG_64BIT @@ -49,7 +49,7 @@ __xchg(unsigned long x, volatile void *ptr, int size) __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) _x_ = (x); \ __ret = (__typeof__(*(ptr))) \ - __xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \ + __arch_xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \ __ret; \ }) diff --git a/arch/parisc/include/asm/grfioctl.h b/arch/parisc/include/asm/grfioctl.h index a740844a1581..597201530d20 100644 --- a/arch/parisc/include/asm/grfioctl.h +++ b/arch/parisc/include/asm/grfioctl.h @@ -59,42 +59,4 @@ #define CRT_ID_LEGO 0x35ACDA30 /* Lego FX5, FX10 ... */ #define CRT_ID_PINNACLE 0x35ACDA16 /* Pinnacle FXe */ -/* structure for ioctl(GCDESCRIBE) */ - -#define gaddr_t unsigned long /* FIXME: PA2.0 (64bit) portable ? */ - -struct grf_fbinfo { - unsigned int id; /* upper 32 bits of graphics id */ - unsigned int mapsize; /* mapped size of framebuffer */ - unsigned int dwidth, dlength;/* x and y sizes */ - unsigned int width, length; /* total x and total y size */ - unsigned int xlen; /* x pitch size */ - unsigned int bpp, bppu; /* bits per pixel and used bpp */ - unsigned int npl, nplbytes; /* # of planes and bytes per plane */ - char name[32]; /* name of the device (from ROM) */ - unsigned int attr; /* attributes */ - gaddr_t fbbase, regbase;/* framebuffer and register base addr */ - gaddr_t regions[6]; /* region bases */ -}; - -#define GCID _IOR('G', 0, int) -#define GCON _IO('G', 1) -#define GCOFF _IO('G', 2) -#define GCAON _IO('G', 3) -#define GCAOFF _IO('G', 4) -#define GCMAP _IOWR('G', 5, int) -#define GCUNMAP _IOWR('G', 6, int) -#define GCMAP_HPUX _IO('G', 5) -#define GCUNMAP_HPUX _IO('G', 6) -#define GCLOCK _IO('G', 7) -#define GCUNLOCK _IO('G', 8) -#define GCLOCK_MINIMUM _IO('G', 9) -#define GCUNLOCK_MINIMUM _IO('G', 10) -#define GCSTATIC_CMAP _IO('G', 11) -#define GCVARIABLE_CMAP _IO('G', 12) -#define GCTERM _IOWR('G',20,int) /* multi-headed Tomcat */ -#define GCDESCRIBE _IOR('G', 21, struct grf_fbinfo) -#define GCFASTLOCK _IO('G', 26) - #endif /* __ASM_PARISC_GRFIOCTL_H */ - diff --git a/arch/parisc/include/asm/kgdb.h b/arch/parisc/include/asm/kgdb.h index f23e7f8f13a5..317cd434bee3 100644 --- a/arch/parisc/include/asm/kgdb.h +++ b/arch/parisc/include/asm/kgdb.h @@ -17,6 +17,8 @@ #define NUMREGBYTES sizeof(struct parisc_gdb_regs) #define BUFMAX 4096 +#define KGDB_MAX_BREAKPOINTS 40 + #define CACHE_FLUSH_IS_SAFE 1 #ifndef __ASSEMBLY__ diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h index 40793bef8429..2b4fad8328e8 100644 --- a/arch/parisc/include/asm/pdc.h +++ b/arch/parisc/include/asm/pdc.h @@ -80,6 +80,7 @@ int pdc_do_firm_test_reset(unsigned long ftc_bitmap); int pdc_do_reset(void); int pdc_soft_power_info(unsigned long *power_reg); int pdc_soft_power_button(int sw_control); +int pdc_soft_power_button_panic(int sw_control); void pdc_io_reset(void); void pdc_io_reset_devices(void); int pdc_iodc_getc(void); diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index e2950f5db7c9..e715df5385d6 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -413,12 +413,12 @@ extern void paging_init (void); * For the 64bit version, the offset is extended by 32bit. */ #define __swp_type(x) ((x).val & 0x1f) -#define __swp_offset(x) ( (((x).val >> 6) & 0x7) | \ - (((x).val >> 8) & ~0x7) ) +#define __swp_offset(x) ( (((x).val >> 5) & 0x7) | \ + (((x).val >> 10) << 3) ) #define __swp_entry(type, offset) ((swp_entry_t) { \ ((type) & 0x1f) | \ - ((offset & 0x7) << 6) | \ - ((offset & ~0x7) << 8) }) + ((offset & 0x7) << 5) | \ + ((offset >> 3) << 10) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index a6e5d66a7656..edfcb9858bcb 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -7,10 +7,26 @@ #include #include +#define SPINLOCK_BREAK_INSN 0x0000c006 /* break 6,6 */ + +static inline void arch_spin_val_check(int lock_val) +{ + if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)) + asm volatile( "andcm,= %0,%1,%%r0\n" + ".word %2\n" + : : "r" (lock_val), "r" (__ARCH_SPIN_LOCK_UNLOCKED_VAL), + "i" (SPINLOCK_BREAK_INSN)); +} + static inline int arch_spin_is_locked(arch_spinlock_t *x) { - volatile unsigned int *a = __ldcw_align(x); - return READ_ONCE(*a) == 0; + volatile unsigned int *a; + int lock_val; + + a = __ldcw_align(x); + lock_val = READ_ONCE(*a); + arch_spin_val_check(lock_val); + return (lock_val == 0); } static inline void arch_spin_lock(arch_spinlock_t *x) @@ -18,9 +34,18 @@ static inline void arch_spin_lock(arch_spinlock_t *x) volatile unsigned int *a; a = __ldcw_align(x); - while (__ldcw(a) == 0) + do { + int lock_val_old; + + lock_val_old = __ldcw(a); + arch_spin_val_check(lock_val_old); + if (lock_val_old) + return; /* got lock */ + + /* wait until we should try to get lock again */ while (*a == 0) continue; + } while (1); } static inline void arch_spin_unlock(arch_spinlock_t *x) @@ -29,15 +54,19 @@ static inline void arch_spin_unlock(arch_spinlock_t *x) a = __ldcw_align(x); /* Release with ordered store. */ - __asm__ __volatile__("stw,ma %0,0(%1)" : : "r"(1), "r"(a) : "memory"); + __asm__ __volatile__("stw,ma %0,0(%1)" + : : "r"(__ARCH_SPIN_LOCK_UNLOCKED_VAL), "r"(a) : "memory"); } static inline int arch_spin_trylock(arch_spinlock_t *x) { volatile unsigned int *a; + int lock_val; a = __ldcw_align(x); - return __ldcw(a) != 0; + lock_val = __ldcw(a); + arch_spin_val_check(lock_val); + return lock_val != 0; } /* diff --git a/arch/parisc/include/asm/spinlock_types.h b/arch/parisc/include/asm/spinlock_types.h index ca39ee350c3f..d65934079ebd 100644 --- a/arch/parisc/include/asm/spinlock_types.h +++ b/arch/parisc/include/asm/spinlock_types.h @@ -2,13 +2,17 @@ #ifndef __ASM_SPINLOCK_TYPES_H #define __ASM_SPINLOCK_TYPES_H +#define __ARCH_SPIN_LOCK_UNLOCKED_VAL 0x1a46 + typedef struct { #ifdef CONFIG_PA20 volatile unsigned int slock; -# define __ARCH_SPIN_LOCK_UNLOCKED { 1 } +# define __ARCH_SPIN_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED_VAL } #else volatile unsigned int lock[4]; -# define __ARCH_SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } } +# define __ARCH_SPIN_LOCK_UNLOCKED \ + { { __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL, \ + __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL } } #endif } arch_spinlock_t; diff --git a/arch/parisc/kernel/alternative.c b/arch/parisc/kernel/alternative.c index 66f5672c70bd..25c4d6c3375d 100644 --- a/arch/parisc/kernel/alternative.c +++ b/arch/parisc/kernel/alternative.c @@ -25,7 +25,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start, { struct alt_instr *entry; int index = 0, applied = 0; - int num_cpus = num_online_cpus(); + int num_cpus = num_present_cpus(); u16 cond_check; cond_check = ALT_COND_ALWAYS | diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 1d3b8bc8a623..ca4a302d4365 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -399,6 +399,7 @@ void flush_dcache_page(struct page *page) unsigned long offset; unsigned long addr, old_addr = 0; unsigned long count = 0; + unsigned long flags; pgoff_t pgoff; if (mapping && !mapping_mapped(mapping)) { @@ -420,7 +421,7 @@ void flush_dcache_page(struct page *page) * to flush one address here for them all to become coherent * on machines that support equivalent aliasing */ - flush_dcache_mmap_lock(mapping); + flush_dcache_mmap_lock_irqsave(mapping, flags); vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) { offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; @@ -460,7 +461,7 @@ void flush_dcache_page(struct page *page) } WARN_ON(++count == 4096); } - flush_dcache_mmap_unlock(mapping); + flush_dcache_mmap_unlock_irqrestore(mapping, flags); } EXPORT_SYMBOL(flush_dcache_page); diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 6817892a2c58..cc124d9f1f7f 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -1232,15 +1232,18 @@ int __init pdc_soft_power_info(unsigned long *power_reg) } /* - * pdc_soft_power_button - Control the soft power button behaviour - * @sw_control: 0 for hardware control, 1 for software control + * pdc_soft_power_button{_panic} - Control the soft power button behaviour + * @sw_control: 0 for hardware control, 1 for software control * * * This PDC function places the soft power button under software or * hardware control. - * Under software control the OS may control to when to allow to shut - * down the system. Under hardware control pressing the power button + * Under software control the OS may control to when to allow to shut + * down the system. Under hardware control pressing the power button * powers off the system immediately. + * + * The _panic version relies on spin_trylock to prevent deadlock + * on panic path. */ int pdc_soft_power_button(int sw_control) { @@ -1254,6 +1257,22 @@ int pdc_soft_power_button(int sw_control) return retval; } +int pdc_soft_power_button_panic(int sw_control) +{ + int retval; + unsigned long flags; + + if (!spin_trylock_irqsave(&pdc_lock, flags)) { + pr_emerg("Couldn't enable soft power button\n"); + return -EBUSY; /* ignored by the panic notifier */ + } + + retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control); + spin_unlock_irqrestore(&pdc_lock, flags); + + return retval; +} + /* * pdc_io_reset - Hack to avoid overlapping range registers of Bridges devices. * Primarily a problem on T600 (which parisc-linux doesn't support) but diff --git a/arch/parisc/kernel/kexec.c b/arch/parisc/kernel/kexec.c index 5eb7f30edc1f..db57345a9daf 100644 --- a/arch/parisc/kernel/kexec.c +++ b/arch/parisc/kernel/kexec.c @@ -4,6 +4,8 @@ #include #include #include +#include + #include #include diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 7df140545b22..f6e38c4d3904 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -27,9 +27,9 @@ * We are not doing SEGREL32 handling correctly. According to the ABI, we * should do a value offset, like this: * if (in_init(me, (void *)val)) - * val -= (uint32_t)me->init_layout.base; + * val -= (uint32_t)me->mem[MOD_INIT_TEXT].base; * else - * val -= (uint32_t)me->core_layout.base; + * val -= (uint32_t)me->mem[MOD_TEXT].base; * However, SEGREL32 is used only for PARISC unwind entries, and we want * those entries to have an absolute address, and not just an offset. * @@ -76,25 +76,6 @@ * allows us to allocate up to 4095 GOT entries. */ #define MAX_GOTS 4095 -/* three functions to determine where in the module core - * or init pieces the location is */ -static inline int in_init(struct module *me, void *loc) -{ - return (loc >= me->init_layout.base && - loc <= (me->init_layout.base + me->init_layout.size)); -} - -static inline int in_core(struct module *me, void *loc) -{ - return (loc >= me->core_layout.base && - loc <= (me->core_layout.base + me->core_layout.size)); -} - -static inline int in_local(struct module *me, void *loc) -{ - return in_init(me, loc) || in_core(me, loc); -} - #ifndef CONFIG_64BIT struct got_entry { Elf32_Addr addr; @@ -302,6 +283,7 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, { unsigned long gots = 0, fdescs = 0, len; unsigned int i; + struct module_memory *mod_mem; len = hdr->e_shnum * sizeof(me->arch.section[0]); me->arch.section = kzalloc(len, GFP_KERNEL); @@ -346,14 +328,15 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, me->arch.section[s].stub_entries += count; } + mod_mem = &me->mem[MOD_TEXT]; /* align things a bit */ - me->core_layout.size = ALIGN(me->core_layout.size, 16); - me->arch.got_offset = me->core_layout.size; - me->core_layout.size += gots * sizeof(struct got_entry); + mod_mem->size = ALIGN(mod_mem->size, 16); + me->arch.got_offset = mod_mem->size; + mod_mem->size += gots * sizeof(struct got_entry); - me->core_layout.size = ALIGN(me->core_layout.size, 16); - me->arch.fdesc_offset = me->core_layout.size; - me->core_layout.size += fdescs * sizeof(Elf_Fdesc); + mod_mem->size = ALIGN(mod_mem->size, 16); + me->arch.fdesc_offset = mod_mem->size; + mod_mem->size += fdescs * sizeof(Elf_Fdesc); me->arch.got_max = gots; me->arch.fdesc_max = fdescs; @@ -371,7 +354,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) BUG_ON(value == 0); - got = me->core_layout.base + me->arch.got_offset; + got = me->mem[MOD_TEXT].base + me->arch.got_offset; for (i = 0; got[i].addr; i++) if (got[i].addr == value) goto out; @@ -389,7 +372,7 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) #ifdef CONFIG_64BIT static Elf_Addr get_fdesc(struct module *me, unsigned long value) { - Elf_Fdesc *fdesc = me->core_layout.base + me->arch.fdesc_offset; + Elf_Fdesc *fdesc = me->mem[MOD_TEXT].base + me->arch.fdesc_offset; if (!value) { printk(KERN_ERR "%s: zero OPD requested!\n", me->name); @@ -407,7 +390,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value) /* Create new one */ fdesc->addr = value; - fdesc->gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset; + fdesc->gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset; return (Elf_Addr)fdesc; } #endif /* CONFIG_64BIT */ @@ -742,7 +725,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, loc, val); val += addend; /* can we reach it locally? */ - if (in_local(me, (void *)val)) { + if (within_module(val, me)) { /* this is the case where the symbol is local * to the module, but in a different section, * so stub the jump in case it's more than 22 @@ -801,7 +784,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, break; case R_PARISC_FPTR64: /* 64-bit function address */ - if(in_local(me, (void *)(val + addend))) { + if (within_module(val + addend, me)) { *loc64 = get_fdesc(me, val+addend); pr_debug("FDESC for %s at %llx points to %llx\n", strtab + sym->st_name, *loc64, @@ -839,7 +822,7 @@ register_unwind_table(struct module *me, table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr; end = table + sechdrs[me->arch.unwind_section].sh_size; - gp = (Elf_Addr)me->core_layout.base + me->arch.got_offset; + gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset; pr_debug("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n", me->arch.unwind_section, table, end, gp); @@ -977,7 +960,7 @@ void module_arch_cleanup(struct module *mod) #ifdef CONFIG_64BIT void *dereference_module_function_descriptor(struct module *mod, void *ptr) { - unsigned long start_opd = (Elf64_Addr)mod->core_layout.base + + unsigned long start_opd = (Elf64_Addr)mod->mem[MOD_TEXT].base + mod->arch.fdesc_offset; unsigned long end_opd = start_opd + mod->arch.fdesc_count * sizeof(Elf64_Fdesc); diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 9a0018f1f42c..541370d14559 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -889,6 +889,7 @@ ENDPROC_CFI(flush_icache_page_asm) ENTRY_CFI(flush_kernel_dcache_page_asm) 88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 + depi_safe 0, 31,PAGE_SHIFT, %r26 /* Clear any offset bits */ #ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 @@ -925,6 +926,7 @@ ENDPROC_CFI(flush_kernel_dcache_page_asm) ENTRY_CFI(purge_kernel_dcache_page_asm) 88: ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 + depi_safe 0, 31,PAGE_SHIFT, %r26 /* Clear any offset bits */ #ifdef CONFIG_64BIT depdi,z 1, 63-PAGE_SHIFT,1, %r25 diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index ba87f791323b..71ed5391f29d 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -446,11 +446,27 @@ void arch_dma_free(struct device *dev, size_t size, void *vaddr, void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, enum dma_data_direction dir) { + /* + * fdc: The data cache line is written back to memory, if and only if + * it is dirty, and then invalidated from the data cache. + */ flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); } void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, enum dma_data_direction dir) { - flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); + unsigned long addr = (unsigned long) phys_to_virt(paddr); + + switch (dir) { + case DMA_TO_DEVICE: + case DMA_BIDIRECTIONAL: + flush_kernel_dcache_range(addr, size); + return; + case DMA_FROM_DEVICE: + purge_kernel_dcache_range_asm(addr, addr + size); + return; + default: + BUG(); + } } diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index c064719b49b0..24411ab79c30 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -122,13 +122,18 @@ void machine_power_off(void) /* It seems we have no way to power the system off via * software. The user has to press the button himself. */ - printk(KERN_EMERG "System shut down completed.\n" - "Please power this system off now."); + printk("Power off or press RETURN to reboot.\n"); /* prevent soft lockup/stalled CPU messages for endless loop. */ rcu_sysrq_start(); lockup_detector_soft_poweroff(); - for (;;); + while (1) { + /* reboot if user presses RETURN key */ + if (pdc_iodc_getc() == 13) { + printk("Rebooting...\n"); + machine_restart(NULL); + } + } } void (*pm_power_off)(void); @@ -159,7 +164,7 @@ EXPORT_SYMBOL(running_on_qemu); /* * Called from the idle thread for the CPU which has been shutdown. */ -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { #ifdef CONFIG_HOTPLUG_CPU idle_task_exit(); diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 4dc12c4c0980..509d18b8e0e6 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -235,9 +235,6 @@ ENTRY_CFI(real64_call_asm) /* save fn */ copy %arg2, %r31 - /* set up the new ap */ - ldo 64(%arg1), %r29 - /* load up the arg registers from the saved arg area */ /* 32-bit calling convention passes first 4 args in registers */ ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */ @@ -249,7 +246,9 @@ ENTRY_CFI(real64_call_asm) ldd 7*REG_SZ(%arg1), %r19 ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */ + /* set up real-mode stack and real-mode ap */ tophys_r1 %sp + ldo -16(%sp), %r29 /* Reference param save area */ b,l rfi_virt2real,%r2 nop diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 7dbd92cafae3..b7fc859fa87d 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -246,8 +246,8 @@ void kgdb_roundup_cpus(void) inline void smp_send_stop(void) { send_IPI_allbutself(IPI_CPU_STOP); } -void -smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } +void +arch_smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); } void smp_send_all_nop(void) diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 09a34b07f02e..39acccabf2ed 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -25,31 +25,26 @@ #include #include -/* we construct an artificial offset for the mapping based on the physical - * address of the kernel mapping variable */ -#define GET_LAST_MMAP(filp) \ - (filp ? ((unsigned long) filp->f_mapping) >> 8 : 0UL) -#define SET_LAST_MMAP(filp, val) \ - { /* nothing */ } +/* + * Construct an artificial page offset for the mapping based on the physical + * address of the kernel file mapping variable. + */ +#define GET_FILP_PGOFF(filp) \ + (filp ? (((unsigned long) filp->f_mapping) >> 8) \ + & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL) -static int get_offset(unsigned int last_mmap) -{ - return (last_mmap & (SHM_COLOUR-1)) >> PAGE_SHIFT; -} - -static unsigned long shared_align_offset(unsigned int last_mmap, +static unsigned long shared_align_offset(unsigned long filp_pgoff, unsigned long pgoff) { - return (get_offset(last_mmap) + pgoff) << PAGE_SHIFT; + return (filp_pgoff + pgoff) << PAGE_SHIFT; } static inline unsigned long COLOR_ALIGN(unsigned long addr, - unsigned int last_mmap, unsigned long pgoff) + unsigned long filp_pgoff, unsigned long pgoff) { unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1); unsigned long off = (SHM_COLOUR-1) & - (shared_align_offset(last_mmap, pgoff) << PAGE_SHIFT); - + shared_align_offset(filp_pgoff, pgoff); return base + off; } @@ -98,92 +93,41 @@ static unsigned long mmap_upper_limit(struct rlimit *rlim_stack) return PAGE_ALIGN(STACK_TOP - stack_base); } +enum mmap_allocation_direction {UP, DOWN}; -unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) +static unsigned long arch_get_unmapped_area_common(struct file *filp, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags, enum mmap_allocation_direction dir) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *prev; - unsigned long task_size = TASK_SIZE; - int do_color_align, last_mmap; + unsigned long filp_pgoff; + int do_color_align; struct vm_unmapped_area_info info; - if (len > task_size) + if (unlikely(len > TASK_SIZE)) return -ENOMEM; do_color_align = 0; if (filp || (flags & MAP_SHARED)) do_color_align = 1; - last_mmap = GET_LAST_MMAP(filp); + filp_pgoff = GET_FILP_PGOFF(filp); if (flags & MAP_FIXED) { - if ((flags & MAP_SHARED) && last_mmap && - (addr - shared_align_offset(last_mmap, pgoff)) + /* Even MAP_FIXED mappings must reside within TASK_SIZE */ + if (TASK_SIZE - len < addr) + return -EINVAL; + + if ((flags & MAP_SHARED) && filp && + (addr - shared_align_offset(filp_pgoff, pgoff)) & (SHM_COLOUR - 1)) return -EINVAL; - goto found_addr; + return addr; } if (addr) { - if (do_color_align && last_mmap) - addr = COLOR_ALIGN(addr, last_mmap, pgoff); - else - addr = PAGE_ALIGN(addr); - - vma = find_vma_prev(mm, addr, &prev); - if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma)) && - (!prev || addr >= vm_end_gap(prev))) - goto found_addr; - } - - info.flags = 0; - info.length = len; - info.low_limit = mm->mmap_legacy_base; - info.high_limit = mmap_upper_limit(NULL); - info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; - info.align_offset = shared_align_offset(last_mmap, pgoff); - addr = vm_unmapped_area(&info); - -found_addr: - if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK)) - SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT)); - - return addr; -} - -unsigned long -arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - const unsigned long len, const unsigned long pgoff, - const unsigned long flags) -{ - struct vm_area_struct *vma, *prev; - struct mm_struct *mm = current->mm; - unsigned long addr = addr0; - int do_color_align, last_mmap; - struct vm_unmapped_area_info info; - - /* requested length too big for entire address space */ - if (len > TASK_SIZE) - return -ENOMEM; - - do_color_align = 0; - if (filp || (flags & MAP_SHARED)) - do_color_align = 1; - last_mmap = GET_LAST_MMAP(filp); - - if (flags & MAP_FIXED) { - if ((flags & MAP_SHARED) && last_mmap && - (addr - shared_align_offset(last_mmap, pgoff)) - & (SHM_COLOUR - 1)) - return -EINVAL; - goto found_addr; - } - - /* requesting a specific address */ - if (addr) { - if (do_color_align && last_mmap) - addr = COLOR_ALIGN(addr, last_mmap, pgoff); + if (do_color_align) + addr = COLOR_ALIGN(addr, filp_pgoff, pgoff); else addr = PAGE_ALIGN(addr); @@ -191,33 +135,49 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (TASK_SIZE - len >= addr && (!vma || addr + len <= vm_start_gap(vma)) && (!prev || addr >= vm_end_gap(prev))) - goto found_addr; + return addr; } - info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = PAGE_SIZE; - info.high_limit = mm->mmap_base; - info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; - info.align_offset = shared_align_offset(last_mmap, pgoff); - addr = vm_unmapped_area(&info); - if (!(addr & ~PAGE_MASK)) - goto found_addr; - VM_BUG_ON(addr != -ENOMEM); + info.align_mask = do_color_align ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; + info.align_offset = shared_align_offset(filp_pgoff, pgoff); - /* - * A failed mmap() very likely causes application failure, - * so fall back to the bottom-up function here. This scenario - * can happen with large stack limits and large mmap() - * allocations. - */ - return arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + if (dir == DOWN) { + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.low_limit = PAGE_SIZE; + info.high_limit = mm->mmap_base; + addr = vm_unmapped_area(&info); + if (!(addr & ~PAGE_MASK)) + return addr; + VM_BUG_ON(addr != -ENOMEM); -found_addr: - if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK)) - SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT)); + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + } - return addr; + info.flags = 0; + info.low_limit = mm->mmap_legacy_base; + info.high_limit = mmap_upper_limit(NULL); + return vm_unmapped_area(&info); +} + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + return arch_get_unmapped_area_common(filp, + addr, len, pgoff, flags, UP); +} + +unsigned long arch_get_unmapped_area_topdown(struct file *filp, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + return arch_get_unmapped_area_common(filp, + addr, len, pgoff, flags, DOWN); } static int mmap_is_legacy(void) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index f9696fbf646c..304eebd1c83e 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -47,6 +47,10 @@ #include #include +#if defined(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK) +#include +#endif + #include "../math-emu/math-emu.h" /* for handle_fpe() */ static void parisc_show_stack(struct task_struct *task, @@ -291,24 +295,30 @@ static void handle_break(struct pt_regs *regs) } #ifdef CONFIG_KPROBES - if (unlikely(iir == PARISC_KPROBES_BREAK_INSN)) { + if (unlikely(iir == PARISC_KPROBES_BREAK_INSN && !user_mode(regs))) { parisc_kprobe_break_handler(regs); return; } - if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2)) { + if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2 && !user_mode(regs))) { parisc_kprobe_ss_handler(regs); return; } #endif #ifdef CONFIG_KGDB - if (unlikely(iir == PARISC_KGDB_COMPILED_BREAK_INSN || - iir == PARISC_KGDB_BREAK_INSN)) { + if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN || + iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) { kgdb_handle_exception(9, SIGTRAP, 0, regs); return; } #endif +#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK + if ((iir == SPINLOCK_BREAK_INSN) && !user_mode(regs)) { + die_if_kernel("Spinlock was trashed", regs, 1); + } +#endif + if (unlikely(iir != GDB_BREAK_INSN)) parisc_printk_ratelimited(0, regs, KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 02fd9bcd9215..bff5820b7cda 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -4,6 +4,17 @@ source "arch/powerpc/platforms/Kconfig.cputype" config CC_HAS_ELFV2 def_bool PPC64 && $(cc-option, -mabi=elfv2) +config CC_HAS_PREFIXED + def_bool PPC64 && $(cc-option, -mcpu=power10 -mprefixed) + +config CC_HAS_PCREL + # Clang has a bug (https://github.com/llvm/llvm-project/issues/62372) + # where pcrel code is not generated if -msoft-float, -mno-altivec, or + # -mno-vsx options are also given. Without these options, fp/vec + # instructions are generated from regular kernel code. So Clang can't + # do pcrel yet. + def_bool PPC64 && CC_IS_GCC && $(cc-option, -mcpu=power10 -mpcrel) + config 32BIT bool default y if PPC32 @@ -113,6 +124,7 @@ config PPC # select ARCH_32BIT_OFF_T if PPC32 select ARCH_DISABLE_KASAN_INLINE if PPC_RADIX_MMU + select ARCH_DMA_DEFAULT_COHERENT if !NOT_COHERENT_CACHE select ARCH_ENABLE_MEMORY_HOTPLUG select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_HAS_COPY_MC if PPC64 @@ -158,6 +170,7 @@ config PPC select ARCH_USE_CMPXCHG_LOCKREF if PPC64 select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS if PPC_QUEUED_SPINLOCKS + select ARCH_WANT_DEFAULT_BPF_JIT select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IRQS_OFF_ACTIVATE_MM @@ -201,6 +214,7 @@ config PPC select HAVE_ARCH_KCSAN if PPC_BOOK3S_64 select HAVE_ARCH_KFENCE if ARCH_SUPPORTS_DEBUG_PAGEALLOC select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET + select HAVE_ARCH_WITHIN_STACK_FRAMES select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT @@ -267,13 +281,13 @@ config PPC select MMU_GATHER_PAGE_SIZE select MMU_GATHER_RCU_TABLE_FREE select MMU_GATHER_MERGE_VMAS + select MMU_LAZY_TLB_SHOOTDOWN if PPC_BOOK3S_64 select MODULES_USE_ELF_RELA select NEED_DMA_MAP_STATE if PPC64 || NOT_COHERENT_CACHE select NEED_PER_CPU_EMBED_FIRST_CHUNK if PPC64 select NEED_PER_CPU_PAGE_FIRST_CHUNK if PPC64 select NEED_SG_DMA_LENGTH select OF - select OF_DMA_DEFAULT_COHERENT if !NOT_COHERENT_CACHE select OF_EARLY_FLATTREE select OLD_SIGACTION if PPC32 select OLD_SIGSUSPEND @@ -291,10 +305,6 @@ config PPC # Please keep this list sorted alphabetically. # -config PPC_LONG_DOUBLE_128 - depends on PPC64 && ALTIVEC - def_bool $(success,test "$(shell,echo __LONG_DOUBLE_128__ | $(CC) -E -P -)" = 1) - config PPC_BARRIER_NOSPEC bool default y @@ -617,8 +627,7 @@ config PPC64_BIG_ENDIAN_ELF_ABI_V2 bool "Build big-endian kernel using ELF ABI V2 (EXPERIMENTAL)" depends on PPC64 && CPU_BIG_ENDIAN depends on CC_HAS_ELFV2 - depends on LD_IS_BFD && LD_VERSION >= 22400 - default n + depends on LD_VERSION >= 22400 || LLD_VERSION >= 150000 help This builds the kernel image using the "Power Architecture 64-Bit ELF V2 ABI Specification", which has a reduced stack overhead and faster @@ -896,34 +905,33 @@ config DATA_SHIFT 8M pages will be pinned. config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - range 8 9 if PPC64 && PPC_64K_PAGES - default "9" if PPC64 && PPC_64K_PAGES - range 13 13 if PPC64 && !PPC_64K_PAGES - default "13" if PPC64 && !PPC_64K_PAGES - range 9 64 if PPC32 && PPC_16K_PAGES - default "9" if PPC32 && PPC_16K_PAGES - range 7 64 if PPC32 && PPC_64K_PAGES - default "7" if PPC32 && PPC_64K_PAGES - range 5 64 if PPC32 && PPC_256K_PAGES - default "5" if PPC32 && PPC_256K_PAGES - range 11 64 - default "11" + int "Order of maximal physically contiguous allocations" + range 7 8 if PPC64 && PPC_64K_PAGES + default "8" if PPC64 && PPC_64K_PAGES + range 12 12 if PPC64 && !PPC_64K_PAGES + default "12" if PPC64 && !PPC_64K_PAGES + range 8 10 if PPC32 && PPC_16K_PAGES + default "8" if PPC32 && PPC_16K_PAGES + range 6 10 if PPC32 && PPC_64K_PAGES + default "6" if PPC32 && PPC_64K_PAGES + range 4 10 if PPC32 && PPC_256K_PAGES + default "4" if PPC32 && PPC_256K_PAGES + range 10 10 + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. - - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. The page size is not necessarily 4KB. For example, on 64-bit systems, 64KB pages can be enabled via CONFIG_PPC_64K_PAGES. Keep this in mind when choosing a value for this option. + Don't change if unsure. + config PPC_SUBPAGE_PROT bool "Support setting protections for 4k subpages (subpage_prot syscall)" default n diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index e91d7e91347d..dca73f673d70 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -107,6 +107,7 @@ LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) += -z notext LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) ifdef CONFIG_PPC64 +ifndef CONFIG_PPC_KERNEL_PCREL ifeq ($(call cc-option-yn,-mcmodel=medium),y) # -mcmodel=medium breaks modules because it uses 32bit offsets from # the TOC pointer to create pointers where possible. Pointers into the @@ -121,20 +122,20 @@ else export NO_MINIMAL_TOC := -mno-minimal-toc endif endif +endif CFLAGS-$(CONFIG_PPC64) := $(call cc-option,-mtraceback=no) -ifndef CONFIG_CC_IS_CLANG ifdef CONFIG_PPC64_ELF_ABI_V2 CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc)) -AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2) else +ifndef CONFIG_CC_IS_CLANG CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcall-aixdesc) -AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1) endif endif CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,$(call cc-option,-mminimal-toc)) CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions) +CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mlong-double-128) # Clang unconditionally reserves r2 on ppc32 and does not support the flag # https://bugs.llvm.org/show_bug.cgi?id=39555 @@ -181,8 +182,16 @@ ifdef CONFIG_476FPE_ERR46 endif # No prefix or pcrel +ifdef CONFIG_PPC_KERNEL_PREFIXED +KBUILD_CFLAGS += $(call cc-option,-mprefixed) +else KBUILD_CFLAGS += $(call cc-option,-mno-prefixed) +endif +ifdef CONFIG_PPC_KERNEL_PCREL +KBUILD_CFLAGS += $(call cc-option,-mpcrel) +else KBUILD_CFLAGS += $(call cc-option,-mno-pcrel) +endif # No AltiVec or VSX or MMA instructions when building kernel KBUILD_CFLAGS += $(call cc-option,-mno-altivec) @@ -238,110 +247,118 @@ bootwrapper_install: $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) include $(srctree)/scripts/Makefile.defconf -PHONY += pseries_le_defconfig -pseries_le_defconfig: - $(call merge_into_defconfig,pseries_defconfig,le) -PHONY += ppc64le_defconfig +generated_configs += ppc64le_defconfig ppc64le_defconfig: $(call merge_into_defconfig,ppc64_defconfig,le) -PHONY += ppc64le_guest_defconfig +generated_configs += ppc64le_guest_defconfig ppc64le_guest_defconfig: - $(call merge_into_defconfig,ppc64_defconfig,le guest) + $(call merge_into_defconfig,ppc64_defconfig,le guest kvm_guest) -PHONY += ppc64_guest_defconfig +generated_configs += ppc64_guest_defconfig ppc64_guest_defconfig: - $(call merge_into_defconfig,ppc64_defconfig,be guest) + $(call merge_into_defconfig,ppc64_defconfig,be guest kvm_guest) -PHONY += powernv_be_defconfig +generated_configs += pseries_le_defconfig +pseries_le_defconfig: ppc64le_guest_defconfig + +generated_configs += pseries_defconfig +pseries_defconfig: ppc64le_guest_defconfig + +generated_configs += powernv_be_defconfig powernv_be_defconfig: $(call merge_into_defconfig,powernv_defconfig,be) -PHONY += mpc85xx_defconfig +generated_configs += mpc85xx_defconfig mpc85xx_defconfig: $(call merge_into_defconfig,mpc85xx_base.config,\ 85xx-32bit 85xx-hw fsl-emb-nonhw) -PHONY += mpc85xx_smp_defconfig +generated_configs += mpc85xx_smp_defconfig mpc85xx_smp_defconfig: $(call merge_into_defconfig,mpc85xx_base.config,\ 85xx-32bit 85xx-smp 85xx-hw fsl-emb-nonhw) -PHONY += corenet32_smp_defconfig +generated_configs += corenet32_smp_defconfig corenet32_smp_defconfig: $(call merge_into_defconfig,corenet_base.config,\ 85xx-32bit 85xx-smp 85xx-hw fsl-emb-nonhw dpaa) -PHONY += corenet64_smp_defconfig +generated_configs += corenet64_smp_defconfig corenet64_smp_defconfig: $(call merge_into_defconfig,corenet_base.config,\ 85xx-64bit 85xx-smp altivec 85xx-hw fsl-emb-nonhw dpaa) -PHONY += mpc86xx_defconfig +generated_configs += mpc86xx_defconfig mpc86xx_defconfig: $(call merge_into_defconfig,mpc86xx_base.config,\ 86xx-hw fsl-emb-nonhw) -PHONY += mpc86xx_smp_defconfig +generated_configs += mpc86xx_smp_defconfig mpc86xx_smp_defconfig: $(call merge_into_defconfig,mpc86xx_base.config,\ 86xx-smp 86xx-hw fsl-emb-nonhw) -PHONY += ppc32_allmodconfig +generated_configs += ppc32_allmodconfig ppc32_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/book3s_32.config \ -f $(srctree)/Makefile allmodconfig -PHONY += ppc_defconfig +generated_configs += ppc_defconfig ppc_defconfig: $(call merge_into_defconfig,book3s_32.config,) -PHONY += ppc64le_allmodconfig +generated_configs += ppc64le_allmodconfig ppc64le_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/le.config \ -f $(srctree)/Makefile allmodconfig -PHONY += ppc64le_allnoconfig +generated_configs += ppc64le_allnoconfig ppc64le_allnoconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/ppc64le.config \ -f $(srctree)/Makefile allnoconfig -PHONY += ppc64_book3e_allmodconfig +generated_configs += ppc64_book3e_allmodconfig ppc64_book3e_allmodconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/85xx-64bit.config \ -f $(srctree)/Makefile allmodconfig -PHONY += ppc32_randconfig +generated_configs += ppc32_randconfig ppc32_randconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/32-bit.config \ -f $(srctree)/Makefile randconfig -PHONY += ppc64_randconfig +generated_configs += ppc64_randconfig ppc64_randconfig: $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/powerpc/configs/64-bit.config \ -f $(srctree)/Makefile randconfig +PHONY += $(generated_configs) + define archhelp - @echo '* zImage - Build default images selected by kernel config' - @echo ' zImage.* - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)' - @echo ' uImage - U-Boot native image format' - @echo ' cuImage.
- Backwards compatible U-Boot image for older' - @echo ' versions which do not support device trees' - @echo ' dtbImage.
- zImage with an embedded device tree blob' - @echo ' simpleImage.
- Firmware independent image.' - @echo ' treeImage.
- Support for older IBM 4xx firmware (not U-Boot)' - @echo ' install - Install kernel using' - @echo ' (your) ~/bin/$(INSTALLKERNEL) or' - @echo ' (distribution) /sbin/$(INSTALLKERNEL) or' - @echo ' install to $$(INSTALL_PATH) and run lilo' - @echo ' *_defconfig - Select default config from arch/$(ARCH)/configs' - @echo '' - @echo ' Targets with
embed a device tree blob inside the image' - @echo ' These targets support board with firmware that does not' - @echo ' support passing a device tree directly. Replace
with the' - @echo ' name of a dts file from the arch/$(ARCH)/boot/dts/ directory' - @echo ' (minus the .dts extension).' + echo '* zImage - Build default images selected by kernel config' + echo ' zImage.* - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)' + echo ' uImage - U-Boot native image format' + echo ' cuImage.
- Backwards compatible U-Boot image for older' + echo ' versions which do not support device trees' + echo ' dtbImage.
- zImage with an embedded device tree blob' + echo ' simpleImage.
- Firmware independent image.' + echo ' treeImage.
- Support for older IBM 4xx firmware (not U-Boot)' + echo ' install - Install kernel using' + echo ' (your) ~/bin/$(INSTALLKERNEL) or' + echo ' (distribution) /sbin/$(INSTALLKERNEL) or' + echo ' install to $$(INSTALL_PATH) and run lilo' + echo ' *_defconfig - Select default config from arch/$(ARCH)/configs' + echo '' + echo ' Targets with
embed a device tree blob inside the image' + echo ' These targets support board with firmware that does not' + echo ' support passing a device tree directly. Replace
with the' + echo ' name of a dts file from the arch/$(ARCH)/boot/dts/ directory' + echo ' (minus the .dts extension).' + echo + $(foreach cfg,$(generated_configs), + printf " %-27s - Build for %s\\n" $(cfg) $(subst _defconfig,,$(cfg));) endef PHONY += install diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 295f76df13b5..771b79423bbc 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -40,6 +40,9 @@ BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ ifdef CONFIG_PPC64_BOOT_WRAPPER BOOTCFLAGS += -m64 +ifdef CONFIG_PPC64_ELF_ABI_V2 +BOOTCFLAGS += $(call cc-option,-mabi=elfv2) +endif else BOOTCFLAGS += -m32 endif @@ -61,14 +64,15 @@ BOOTCFLAGS += -mbig-endian else BOOTCFLAGS += -mlittle-endian endif -ifdef CONFIG_PPC64_ELF_ABI_V2 -BOOTCFLAGS += $(call cc-option,-mabi=elfv2) -endif BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -nostdinc BOOTARFLAGS := -crD +BOOTCFLAGS += $(call cc-option,-mno-prefixed) \ + $(call cc-option,-mno-pcrel) \ + $(call cc-option,-mno-mma) + ifdef CONFIG_CC_IS_CLANG BOOTCFLAGS += $(CLANG_FLAGS) BOOTAFLAGS += $(CLANG_FLAGS) @@ -164,7 +168,7 @@ src-plat-$(CONFIG_PPC_MPC52xx) += cuboot-52xx.c src-plat-$(CONFIG_PPC_82xx) += cuboot-pq2.c fixed-head.S ep8248e.c cuboot-824x.c src-plat-$(CONFIG_PPC_83xx) += cuboot-83xx.c fixed-head.S redboot-83xx.c src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c -src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \ +src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c \ gamecube-head.S gamecube.c \ wii-head.S wii.c holly.c \ fixed-head.S mvme5100.c @@ -327,17 +331,12 @@ image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200b image-$(CONFIG_PPC_MEDIA5200) += cuImage.media5200 # Board ports in arch/powerpc/platform/82xx/Kconfig -image-$(CONFIG_MPC8272_ADS) += cuImage.mpc8272ads -image-$(CONFIG_PQ2FADS) += cuImage.pq2fads image-$(CONFIG_EP8248E) += dtbImage.ep8248e # Board ports in arch/powerpc/platform/83xx/Kconfig -image-$(CONFIG_MPC832x_MDS) += cuImage.mpc832x_mds image-$(CONFIG_MPC832x_RDB) += cuImage.mpc832x_rdb image-$(CONFIG_MPC834x_ITX) += cuImage.mpc8349emitx \ cuImage.mpc8349emitxgp -image-$(CONFIG_MPC834x_MDS) += cuImage.mpc834x_mds -image-$(CONFIG_MPC836x_MDS) += cuImage.mpc836x_mds image-$(CONFIG_ASP834x) += dtbImage.asp834x-redboot # Board ports in arch/powerpc/platform/85xx/Kconfig @@ -361,7 +360,6 @@ image-$(CONFIG_MVME7100) += dtbImage.mvme7100 # Board ports in arch/powerpc/platform/embedded6xx/Kconfig image-$(CONFIG_STORCENTER) += cuImage.storcenter -image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2 image-$(CONFIG_GAMECUBE) += dtbImage.gamecube image-$(CONFIG_WII) += dtbImage.wii image-$(CONFIG_MVME5100) += dtbImage.mvme5100 diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 44544720daae..121cab9d579b 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -51,7 +51,7 @@ _zimage_start: _zimage_start_lib: /* Work out the offset between the address we were linked at and the address where we're running. */ - bl .+4 + bcl 20,31,.+4 p_base: mflr r10 /* r10 now points to runtime addr of p_base */ #ifndef __powerpc64__ /* grab the link address of the dynamic section in r11 */ @@ -274,7 +274,7 @@ prom: mtsrr1 r10 /* Load FW address, set LR to label 1, and jump to FW */ - bl 0f + bcl 20,31,0f 0: mflr r10 addi r11,r10,(1f-0b) mtlr r11 diff --git a/arch/powerpc/boot/cuboot-mpc7448hpc2.c b/arch/powerpc/boot/cuboot-mpc7448hpc2.c deleted file mode 100644 index 335fb65212e7..000000000000 --- a/arch/powerpc/boot/cuboot-mpc7448hpc2.c +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Roy Zang - * - * Description: - * Old U-boot compatibility for mpc7448hpc2 board - * Based on the code of Scott Wood - * for 83xx and 85xx. - */ - -#include "ops.h" -#include "stdio.h" -#include "cuboot.h" - -#define TARGET_HAS_ETH1 -#include "ppcboot.h" - -static bd_t bd; -extern char _dtb_start[], _dtb_end[]; - -static void platform_fixups(void) -{ - void *tsi; - - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); - dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); - tsi = find_node_by_devtype(NULL, "tsi-bridge"); - if (tsi) - setprop(tsi, "bus-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - CUBOOT_INIT(); - fdt_init(_dtb_start); - serial_console_init(); - platform_ops.fixups = platform_fixups; -} diff --git a/arch/powerpc/boot/dts/fsl/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/fsl/mpc8641_hpcn.dts deleted file mode 100644 index f7a2430d6629..000000000000 --- a/arch/powerpc/boot/dts/fsl/mpc8641_hpcn.dts +++ /dev/null @@ -1,394 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8641 HPCN Device Tree Source - * - * Copyright 2006 Freescale Semiconductor Inc. - */ - -/include/ "mpc8641si-pre.dtsi" - -/ { - model = "MPC8641HPCN"; - compatible = "fsl,mpc8641hpcn"; - - memory { - device_type = "memory"; - reg = <0x00000000 0x40000000>; // 1G at 0x0 - }; - - lbc: localbus@ffe05000 { - reg = <0xffe05000 0x1000>; - - ranges = <0 0 0xef800000 0x00800000 - 2 0 0xffdf8000 0x00008000 - 3 0 0xffdf0000 0x00008000>; - - flash@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x00800000>; - bank-width = <2>; - device-width = <2>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel"; - reg = <0x00000000 0x00300000>; - }; - partition@300000 { - label = "firmware b"; - reg = <0x00300000 0x00100000>; - read-only; - }; - partition@400000 { - label = "fs"; - reg = <0x00400000 0x00300000>; - }; - partition@700000 { - label = "firmware a"; - reg = <0x00700000 0x00100000>; - read-only; - }; - }; - }; - - soc: soc8641@ffe00000 { - ranges = <0x00000000 0xffe00000 0x00100000>; - - enet0: ethernet@24000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupts = <10 1 0 0>; - reg = <0>; - }; - phy1: ethernet-phy@1 { - interrupts = <10 1 0 0>; - reg = <1>; - }; - phy2: ethernet-phy@2 { - interrupts = <10 1 0 0>; - reg = <2>; - }; - phy3: ethernet-phy@3 { - interrupts = <10 1 0 0>; - reg = <3>; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; - - mdio@25520 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet2: ethernet@26000 { - tbi-handle = <&tbi2>; - phy-handle = <&phy2>; - phy-connection-type = "rgmii-id"; - }; - - mdio@26520 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet3: ethernet@27000 { - tbi-handle = <&tbi3>; - phy-handle = <&phy3>; - phy-connection-type = "rgmii-id"; - }; - - mdio@27520 { - tbi3: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - rmu: rmu@d3000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,srio-rmu"; - reg = <0xd3000 0x500>; - ranges = <0x0 0xd3000 0x500>; - - message-unit@0 { - compatible = "fsl,srio-msg-unit"; - reg = <0x0 0x100>; - interrupts = < - 53 2 0 0 /* msg1_tx_irq */ - 54 2 0 0>;/* msg1_rx_irq */ - }; - message-unit@100 { - compatible = "fsl,srio-msg-unit"; - reg = <0x100 0x100>; - interrupts = < - 55 2 0 0 /* msg2_tx_irq */ - 56 2 0 0>;/* msg2_rx_irq */ - }; - doorbell-unit@400 { - compatible = "fsl,srio-dbell-unit"; - reg = <0x400 0x80>; - interrupts = < - 49 2 0 0 /* bell_outb_irq */ - 50 2 0 0>;/* bell_inb_irq */ - }; - port-write-unit@4e0 { - compatible = "fsl,srio-port-write-unit"; - reg = <0x4e0 0x20>; - interrupts = <48 2 0 0>; - }; - }; - }; - - pci0: pcie@ffe08000 { - reg = <0xffe08000 0x1000>; - ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x20000000 - 0x01000000 0x0 0x00000000 0xffc00000 0x0 0x00010000>; - interrupt-map-mask = <0xff00 0 0 7>; - interrupt-map = < - /* IDSEL 0x11 func 0 - PCI slot 1 */ - 0x8800 0 0 1 &mpic 2 1 0 0 - 0x8800 0 0 2 &mpic 3 1 0 0 - 0x8800 0 0 3 &mpic 4 1 0 0 - 0x8800 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 1 - PCI slot 1 */ - 0x8900 0 0 1 &mpic 2 1 0 0 - 0x8900 0 0 2 &mpic 3 1 0 0 - 0x8900 0 0 3 &mpic 4 1 0 0 - 0x8900 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 2 - PCI slot 1 */ - 0x8a00 0 0 1 &mpic 2 1 0 0 - 0x8a00 0 0 2 &mpic 3 1 0 0 - 0x8a00 0 0 3 &mpic 4 1 0 0 - 0x8a00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 3 - PCI slot 1 */ - 0x8b00 0 0 1 &mpic 2 1 0 0 - 0x8b00 0 0 2 &mpic 3 1 0 0 - 0x8b00 0 0 3 &mpic 4 1 0 0 - 0x8b00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 4 - PCI slot 1 */ - 0x8c00 0 0 1 &mpic 2 1 0 0 - 0x8c00 0 0 2 &mpic 3 1 0 0 - 0x8c00 0 0 3 &mpic 4 1 0 0 - 0x8c00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 5 - PCI slot 1 */ - 0x8d00 0 0 1 &mpic 2 1 0 0 - 0x8d00 0 0 2 &mpic 3 1 0 0 - 0x8d00 0 0 3 &mpic 4 1 0 0 - 0x8d00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 6 - PCI slot 1 */ - 0x8e00 0 0 1 &mpic 2 1 0 0 - 0x8e00 0 0 2 &mpic 3 1 0 0 - 0x8e00 0 0 3 &mpic 4 1 0 0 - 0x8e00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 7 - PCI slot 1 */ - 0x8f00 0 0 1 &mpic 2 1 0 0 - 0x8f00 0 0 2 &mpic 3 1 0 0 - 0x8f00 0 0 3 &mpic 4 1 0 0 - 0x8f00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x12 func 0 - PCI slot 2 */ - 0x9000 0 0 1 &mpic 3 1 0 0 - 0x9000 0 0 2 &mpic 4 1 0 0 - 0x9000 0 0 3 &mpic 1 1 0 0 - 0x9000 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 1 - PCI slot 2 */ - 0x9100 0 0 1 &mpic 3 1 0 0 - 0x9100 0 0 2 &mpic 4 1 0 0 - 0x9100 0 0 3 &mpic 1 1 0 0 - 0x9100 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 2 - PCI slot 2 */ - 0x9200 0 0 1 &mpic 3 1 0 0 - 0x9200 0 0 2 &mpic 4 1 0 0 - 0x9200 0 0 3 &mpic 1 1 0 0 - 0x9200 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 3 - PCI slot 2 */ - 0x9300 0 0 1 &mpic 3 1 0 0 - 0x9300 0 0 2 &mpic 4 1 0 0 - 0x9300 0 0 3 &mpic 1 1 0 0 - 0x9300 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 4 - PCI slot 2 */ - 0x9400 0 0 1 &mpic 3 1 0 0 - 0x9400 0 0 2 &mpic 4 1 0 0 - 0x9400 0 0 3 &mpic 1 1 0 0 - 0x9400 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 5 - PCI slot 2 */ - 0x9500 0 0 1 &mpic 3 1 0 0 - 0x9500 0 0 2 &mpic 4 1 0 0 - 0x9500 0 0 3 &mpic 1 1 0 0 - 0x9500 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 6 - PCI slot 2 */ - 0x9600 0 0 1 &mpic 3 1 0 0 - 0x9600 0 0 2 &mpic 4 1 0 0 - 0x9600 0 0 3 &mpic 1 1 0 0 - 0x9600 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 7 - PCI slot 2 */ - 0x9700 0 0 1 &mpic 3 1 0 0 - 0x9700 0 0 2 &mpic 4 1 0 0 - 0x9700 0 0 3 &mpic 1 1 0 0 - 0x9700 0 0 4 &mpic 2 1 0 0 - - // IDSEL 0x1c USB - 0xe000 0 0 1 &i8259 12 2 - 0xe100 0 0 2 &i8259 9 2 - 0xe200 0 0 3 &i8259 10 2 - 0xe300 0 0 4 &i8259 11 2 - - // IDSEL 0x1d Audio - 0xe800 0 0 1 &i8259 6 2 - - // IDSEL 0x1e Legacy - 0xf000 0 0 1 &i8259 7 2 - 0xf100 0 0 1 &i8259 7 2 - - // IDSEL 0x1f IDE/SATA - 0xf800 0 0 1 &i8259 14 2 - 0xf900 0 0 1 &i8259 5 2 - >; - - pcie@0 { - ranges = <0x02000000 0x0 0x80000000 - 0x02000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - uli1575@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <0x02000000 0x0 0x80000000 - 0x02000000 0x0 0x80000000 - 0x0 0x20000000 - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - isa@1e { - device_type = "isa"; - #size-cells = <1>; - #address-cells = <2>; - reg = <0xf000 0 0 0 0>; - ranges = <1 0 0x01000000 0 0 - 0x00001000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - reg = <1 0x20 2 - 1 0xa0 2 - 1 0x4d0 2>; - interrupt-controller; - device_type = "interrupt-controller"; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <9 2 0 0>; - }; - - i8042@60 { - #size-cells = <0>; - #address-cells = <1>; - reg = <1 0x60 1 1 0x64 1>; - interrupts = <1 3 12 3>; - interrupt-parent = <&i8259>; - - keyboard@0 { - reg = <0>; - compatible = "pnpPNP,303"; - }; - - mouse@1 { - reg = <1>; - compatible = "pnpPNP,f03"; - }; - }; - - rtc@70 { - compatible = - "pnpPNP,b00"; - reg = <1 0x70 2>; - }; - - gpio@400 { - reg = <1 0x400 0x80>; - }; - }; - }; - }; - - }; - - pci1: pcie@ffe09000 { - reg = <0xffe09000 0x1000>; - ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000 - 0x01000000 0x0 0x00000000 0xffc10000 0x0 0x00010000>; - - pcie@0 { - ranges = <0x02000000 0x0 0xa0000000 - 0x02000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - }; - }; -/* - * Only one of Rapid IO or PCI can be present due to HW limitations and - * due to the fact that the 2 now share address space in the new memory - * map. The most likely case is that we have PCI, so comment out the - * rapidio node. Leave it here for reference. - - rapidio@ffec0000 { - reg = <0xffec0000 0x11000>; - compatible = "fsl,srio"; - interrupts = <48 2 0 0>; - #address-cells = <2>; - #size-cells = <2>; - fsl,srio-rmu-handle = <&rmu>; - ranges; - - port1 { - #address-cells = <2>; - #size-cells = <2>; - cell-index = <1>; - ranges = <0 0 0x80000000 0 0x20000000>; - }; - }; -*/ - -}; - -/include/ "mpc8641si-post.dtsi" diff --git a/arch/powerpc/boot/dts/fsl/mpc8641_hpcn_36b.dts b/arch/powerpc/boot/dts/fsl/mpc8641_hpcn_36b.dts deleted file mode 100644 index 3f5f7a99b9ea..000000000000 --- a/arch/powerpc/boot/dts/fsl/mpc8641_hpcn_36b.dts +++ /dev/null @@ -1,337 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8641 HPCN Device Tree Source - * - * Copyright 2008-2009 Freescale Semiconductor Inc. - */ - -/include/ "mpc8641si-pre.dtsi" - -/ { - model = "MPC8641HPCN"; - compatible = "fsl,mpc8641hpcn"; - #address-cells = <2>; - #size-cells = <2>; - - memory { - device_type = "memory"; - reg = <0x0 0x00000000 0x0 0x40000000>; // 1G at 0x0 - }; - - lbc: localbus@fffe05000 { - reg = <0x0f 0xffe05000 0x0 0x1000>; - - ranges = <0 0 0xf 0xef800000 0x00800000 - 2 0 0xf 0xffdf8000 0x00008000 - 3 0 0xf 0xffdf0000 0x00008000>; - - flash@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x00800000>; - bank-width = <2>; - device-width = <2>; - #address-cells = <1>; - #size-cells = <1>; - partition@0 { - label = "kernel"; - reg = <0x00000000 0x00300000>; - }; - partition@300000 { - label = "firmware b"; - reg = <0x00300000 0x00100000>; - read-only; - }; - partition@400000 { - label = "fs"; - reg = <0x00400000 0x00300000>; - }; - partition@700000 { - label = "firmware a"; - reg = <0x00700000 0x00100000>; - read-only; - }; - }; - }; - - soc: soc8641@fffe00000 { - ranges = <0x00000000 0x0f 0xffe00000 0x00100000>; - - enet0: ethernet@24000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupts = <10 1 0 0>; - reg = <0>; - }; - phy1: ethernet-phy@1 { - interrupts = <10 1 0 0>; - reg = <1>; - }; - phy2: ethernet-phy@2 { - interrupts = <10 1 0 0>; - reg = <2>; - }; - phy3: ethernet-phy@3 { - interrupts = <10 1 0 0>; - reg = <3>; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; - - mdio@25520 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet2: ethernet@26000 { - tbi-handle = <&tbi2>; - phy-handle = <&phy2>; - phy-connection-type = "rgmii-id"; - }; - - mdio@26520 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet3: ethernet@27000 { - tbi-handle = <&tbi3>; - phy-handle = <&phy3>; - phy-connection-type = "rgmii-id"; - }; - - mdio@27520 { - tbi3: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - pci0: pcie@fffe08000 { - reg = <0x0f 0xffe08000 0x0 0x1000>; - ranges = <0x02000000 0x0 0xe0000000 0x0c 0x00000000 0x0 0x20000000 - 0x01000000 0x0 0x00000000 0x0f 0xffc00000 0x0 0x00010000>; - interrupt-map-mask = <0xff00 0 0 7>; - interrupt-map = < - /* IDSEL 0x11 func 0 - PCI slot 1 */ - 0x8800 0 0 1 &mpic 2 1 0 0 - 0x8800 0 0 2 &mpic 3 1 0 0 - 0x8800 0 0 3 &mpic 4 1 0 0 - 0x8800 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 1 - PCI slot 1 */ - 0x8900 0 0 1 &mpic 2 1 0 0 - 0x8900 0 0 2 &mpic 3 1 0 0 - 0x8900 0 0 3 &mpic 4 1 0 0 - 0x8900 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 2 - PCI slot 1 */ - 0x8a00 0 0 1 &mpic 2 1 0 0 - 0x8a00 0 0 2 &mpic 3 1 0 0 - 0x8a00 0 0 3 &mpic 4 1 0 0 - 0x8a00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 3 - PCI slot 1 */ - 0x8b00 0 0 1 &mpic 2 1 0 0 - 0x8b00 0 0 2 &mpic 3 1 0 0 - 0x8b00 0 0 3 &mpic 4 1 0 0 - 0x8b00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 4 - PCI slot 1 */ - 0x8c00 0 0 1 &mpic 2 1 0 0 - 0x8c00 0 0 2 &mpic 3 1 0 0 - 0x8c00 0 0 3 &mpic 4 1 0 0 - 0x8c00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 5 - PCI slot 1 */ - 0x8d00 0 0 1 &mpic 2 1 0 0 - 0x8d00 0 0 2 &mpic 3 1 0 0 - 0x8d00 0 0 3 &mpic 4 1 0 0 - 0x8d00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 6 - PCI slot 1 */ - 0x8e00 0 0 1 &mpic 2 1 0 0 - 0x8e00 0 0 2 &mpic 3 1 0 0 - 0x8e00 0 0 3 &mpic 4 1 0 0 - 0x8e00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x11 func 7 - PCI slot 1 */ - 0x8f00 0 0 1 &mpic 2 1 0 0 - 0x8f00 0 0 2 &mpic 3 1 0 0 - 0x8f00 0 0 3 &mpic 4 1 0 0 - 0x8f00 0 0 4 &mpic 1 1 0 0 - - /* IDSEL 0x12 func 0 - PCI slot 2 */ - 0x9000 0 0 1 &mpic 3 1 0 0 - 0x9000 0 0 2 &mpic 4 1 0 0 - 0x9000 0 0 3 &mpic 1 1 0 0 - 0x9000 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 1 - PCI slot 2 */ - 0x9100 0 0 1 &mpic 3 1 0 0 - 0x9100 0 0 2 &mpic 4 1 0 0 - 0x9100 0 0 3 &mpic 1 1 0 0 - 0x9100 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 2 - PCI slot 2 */ - 0x9200 0 0 1 &mpic 3 1 0 0 - 0x9200 0 0 2 &mpic 4 1 0 0 - 0x9200 0 0 3 &mpic 1 1 0 0 - 0x9200 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 3 - PCI slot 2 */ - 0x9300 0 0 1 &mpic 3 1 0 0 - 0x9300 0 0 2 &mpic 4 1 0 0 - 0x9300 0 0 3 &mpic 1 1 0 0 - 0x9300 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 4 - PCI slot 2 */ - 0x9400 0 0 1 &mpic 3 1 0 0 - 0x9400 0 0 2 &mpic 4 1 0 0 - 0x9400 0 0 3 &mpic 1 1 0 0 - 0x9400 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 5 - PCI slot 2 */ - 0x9500 0 0 1 &mpic 3 1 0 0 - 0x9500 0 0 2 &mpic 4 1 0 0 - 0x9500 0 0 3 &mpic 1 1 0 0 - 0x9500 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 6 - PCI slot 2 */ - 0x9600 0 0 1 &mpic 3 1 0 0 - 0x9600 0 0 2 &mpic 4 1 0 0 - 0x9600 0 0 3 &mpic 1 1 0 0 - 0x9600 0 0 4 &mpic 2 1 0 0 - - /* IDSEL 0x12 func 7 - PCI slot 2 */ - 0x9700 0 0 1 &mpic 3 1 0 0 - 0x9700 0 0 2 &mpic 4 1 0 0 - 0x9700 0 0 3 &mpic 1 1 0 0 - 0x9700 0 0 4 &mpic 2 1 0 0 - - // IDSEL 0x1c USB - 0xe000 0 0 1 &i8259 12 2 - 0xe100 0 0 2 &i8259 9 2 - 0xe200 0 0 3 &i8259 10 2 - 0xe300 0 0 4 &i8259 11 2 - - // IDSEL 0x1d Audio - 0xe800 0 0 1 &i8259 6 2 - - // IDSEL 0x1e Legacy - 0xf000 0 0 1 &i8259 7 2 - 0xf100 0 0 1 &i8259 7 2 - - // IDSEL 0x1f IDE/SATA - 0xf800 0 0 1 &i8259 14 2 - 0xf900 0 0 1 &i8259 5 2 - >; - - pcie@0 { - ranges = <0x02000000 0x0 0xe0000000 - 0x02000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - uli1575@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <0x02000000 0x0 0xe0000000 - 0x02000000 0x0 0xe0000000 - 0x0 0x20000000 - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - isa@1e { - device_type = "isa"; - #size-cells = <1>; - #address-cells = <2>; - reg = <0xf000 0 0 0 0>; - ranges = <1 0 0x01000000 0 0 - 0x00001000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - reg = <1 0x20 2 - 1 0xa0 2 - 1 0x4d0 2>; - interrupt-controller; - device_type = "interrupt-controller"; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <9 2 0 0>; - }; - - i8042@60 { - #size-cells = <0>; - #address-cells = <1>; - reg = <1 0x60 1 1 0x64 1>; - interrupts = <1 3 12 3>; - interrupt-parent = <&i8259>; - - keyboard@0 { - reg = <0>; - compatible = "pnpPNP,303"; - }; - - mouse@1 { - reg = <1>; - compatible = "pnpPNP,f03"; - }; - }; - - rtc@70 { - compatible = - "pnpPNP,b00"; - reg = <1 0x70 2>; - }; - - gpio@400 { - reg = <1 0x400 0x80>; - }; - }; - }; - }; - - }; - - pci1: pcie@fffe09000 { - reg = <0x0f 0xffe09000 0x0 0x1000>; - ranges = <0x02000000 0x0 0xe0000000 0x0c 0x20000000 0x0 0x20000000 - 0x01000000 0x0 0x00000000 0x0f 0xffc10000 0x0 0x00010000>; - - pcie@0 { - ranges = <0x02000000 0x0 0xe0000000 - 0x02000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00010000>; - }; - }; -}; - -/include/ "mpc8641si-post.dtsi" diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts deleted file mode 100644 index 9494af160e95..000000000000 --- a/arch/powerpc/boot/dts/mpc7448hpc2.dts +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC7448HPC2 (Taiga) board Device Tree Source - * - * Copyright 2006, 2008 Freescale Semiconductor Inc. - * 2006 Roy Zang . - */ - -/dts-v1/; - -/ { - model = "mpc7448hpc2"; - compatible = "mpc74xx"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - - serial0 = &serial0; - serial1 = &serial1; - - pci0 = &pci0; - }; - - cpus { - #address-cells = <1>; - #size-cells =<0>; - - PowerPC,7448@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; // 32 bytes - i-cache-line-size = <32>; // 32 bytes - d-cache-size = <0x8000>; // L1, 32K bytes - i-cache-size = <0x8000>; // L1, 32K bytes - timebase-frequency = <0>; // 33 MHz, from uboot - clock-frequency = <0>; // From U-Boot - bus-frequency = <0>; // From U-Boot - }; - }; - - memory { - device_type = "memory"; - reg = <0x0 0x20000000 // DDR2 512M at 0 - >; - }; - - tsi108@c0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "tsi-bridge"; - ranges = <0x0 0xc0000000 0x10000>; - reg = <0xc0000000 0x10000>; - bus-frequency = <0>; - - i2c@7000 { - interrupt-parent = <&mpic>; - interrupts = <14 0>; - reg = <0x7000 0x400>; - device_type = "i2c"; - compatible = "tsi108-i2c"; - }; - - MDIO: mdio@6000 { - compatible = "tsi108-mdio"; - reg = <0x6000 0x50>; - #address-cells = <1>; - #size-cells = <0>; - - phy8: ethernet-phy@8 { - interrupt-parent = <&mpic>; - interrupts = <2 1>; - reg = <0x8>; - }; - - phy9: ethernet-phy@9 { - interrupt-parent = <&mpic>; - interrupts = <2 1>; - reg = <0x9>; - }; - - }; - - enet0: ethernet@6200 { - linux,network-index = <0>; - #size-cells = <0>; - device_type = "network"; - compatible = "tsi108-ethernet"; - reg = <0x6000 0x200>; - address = [ 00 06 D2 00 00 01 ]; - interrupts = <16 2>; - interrupt-parent = <&mpic>; - mdio-handle = <&MDIO>; - phy-handle = <&phy8>; - }; - - enet1: ethernet@6600 { - linux,network-index = <1>; - #address-cells = <1>; - #size-cells = <0>; - device_type = "network"; - compatible = "tsi108-ethernet"; - reg = <0x6400 0x200>; - address = [ 00 06 D2 00 00 02 ]; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - mdio-handle = <&MDIO>; - phy-handle = <&phy9>; - }; - - serial0: serial@7808 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0x7808 0x200>; - clock-frequency = <1064000000>; - interrupts = <12 0>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@7c08 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0x7c08 0x200>; - clock-frequency = <1064000000>; - interrupts = <13 0>; - interrupt-parent = <&mpic>; - }; - - mpic: pic@7400 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x7400 0x400>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - pci0: pci@1000 { - compatible = "tsi108-pci"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0x1000 0x1000>; - bus-range = <0 0>; - ranges = <0x2000000 0x0 0xe0000000 0xe0000000 0x0 0x1a000000 - 0x1000000 0x0 0x0 0xfa000000 0x0 0x10000>; - clock-frequency = <133333332>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x800 0x0 0x0 0x1 &RT0 0x24 0x0 - 0x800 0x0 0x0 0x2 &RT0 0x25 0x0 - 0x800 0x0 0x0 0x3 &RT0 0x26 0x0 - 0x800 0x0 0x0 0x4 &RT0 0x27 0x0 - - /* IDSEL 0x12 */ - 0x1000 0x0 0x0 0x1 &RT0 0x25 0x0 - 0x1000 0x0 0x0 0x2 &RT0 0x26 0x0 - 0x1000 0x0 0x0 0x3 &RT0 0x27 0x0 - 0x1000 0x0 0x0 0x4 &RT0 0x24 0x0 - - /* IDSEL 0x13 */ - 0x1800 0x0 0x0 0x1 &RT0 0x26 0x0 - 0x1800 0x0 0x0 0x2 &RT0 0x27 0x0 - 0x1800 0x0 0x0 0x3 &RT0 0x24 0x0 - 0x1800 0x0 0x0 0x4 &RT0 0x25 0x0 - - /* IDSEL 0x14 */ - 0x2000 0x0 0x0 0x1 &RT0 0x27 0x0 - 0x2000 0x0 0x0 0x2 &RT0 0x24 0x0 - 0x2000 0x0 0x0 0x3 &RT0 0x25 0x0 - 0x2000 0x0 0x0 0x4 &RT0 0x26 0x0 - >; - - RT0: router@1180 { - clock-frequency = <0>; - interrupt-controller; - device_type = "pic-router"; - #address-cells = <0>; - #interrupt-cells = <2>; - big-endian; - interrupts = <23 2>; - interrupt-parent = <&mpic>; - }; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts deleted file mode 100644 index 13ec786f6adf..000000000000 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ /dev/null @@ -1,263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8272 ADS Device Tree Source - * - * Copyright 2005,2008 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "MPC8272ADS"; - compatible = "fsl,mpc8272ads"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = ð0; - ethernet1 = ð1; - serial0 = &scc1; - serial1 = &scc4; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8272@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <16384>; - i-cache-size = <16384>; - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x0 0x0>; - }; - - localbus@f0010100 { - compatible = "fsl,mpc8272-localbus", - "fsl,pq2-localbus"; - #address-cells = <2>; - #size-cells = <1>; - reg = <0xf0010100 0x40>; - - ranges = <0x0 0x0 0xff800000 0x00800000 - 0x1 0x0 0xf4500000 0x8000 - 0x3 0x0 0xf8200000 0x8000>; - - flash@0,0 { - compatible = "jedec-flash"; - reg = <0x0 0x0 0x00800000>; - bank-width = <4>; - device-width = <1>; - }; - - board-control@1,0 { - reg = <0x1 0x0 0x20>; - compatible = "fsl,mpc8272ads-bcsr"; - }; - - PCI_PIC: interrupt-controller@3,0 { - compatible = "fsl,mpc8272ads-pci-pic", - "fsl,pq2ads-pci-pic"; - #interrupt-cells = <1>; - interrupt-controller; - reg = <0x3 0x0 0x8>; - interrupt-parent = <&PIC>; - interrupts = <20 8>; - }; - }; - - - pci@f0010800 { - device_type = "pci"; - reg = <0xf0010800 0x10c 0xf00101ac 0x8 0xf00101c4 0x8>; - compatible = "fsl,mpc8272-pci", "fsl,pq2-pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - clock-frequency = <66666666>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &PCI_PIC 0 - 0xb000 0x0 0x0 0x2 &PCI_PIC 1 - 0xb000 0x0 0x0 0x3 &PCI_PIC 2 - 0xb000 0x0 0x0 0x4 &PCI_PIC 3 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &PCI_PIC 4 - 0xb800 0x0 0x0 0x2 &PCI_PIC 5 - 0xb800 0x0 0x0 0x3 &PCI_PIC 6 - 0xb800 0x0 0x0 0x4 &PCI_PIC 7 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &PCI_PIC 8 - 0xc000 0x0 0x0 0x2 &PCI_PIC 9 - 0xc000 0x0 0x0 0x3 &PCI_PIC 10 - 0xc000 0x0 0x0 0x4 &PCI_PIC 11>; - - interrupt-parent = <&PIC>; - interrupts = <18 8>; - ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x20000000 - 0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x0 0xf6000000 0x0 0x2000000>; - }; - - soc@f0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,mpc8272", "fsl,pq2-soc"; - ranges = <0x0 0xf0000000 0x53000>; - - // Temporary -- will go away once kernel uses ranges for get_immrbase(). - reg = <0xf0000000 0x53000>; - - cpm@119c0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; - reg = <0x119c0 0x30>; - ranges; - - muram@0 { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x10000>; - - data@0 { - compatible = "fsl,cpm-muram-data"; - reg = <0x0 0x2000 0x9800 0x800>; - }; - }; - - brg@119f0 { - compatible = "fsl,mpc8272-brg", - "fsl,cpm2-brg", - "fsl,cpm-brg"; - reg = <0x119f0 0x10 0x115f0 0x10>; - }; - - scc1: serial@11a00 { - device_type = "serial"; - compatible = "fsl,mpc8272-scc-uart", - "fsl,cpm2-scc-uart"; - reg = <0x11a00 0x20 0x8000 0x100>; - interrupts = <40 8>; - interrupt-parent = <&PIC>; - fsl,cpm-brg = <1>; - fsl,cpm-command = <0x800000>; - }; - - scc4: serial@11a60 { - device_type = "serial"; - compatible = "fsl,mpc8272-scc-uart", - "fsl,cpm2-scc-uart"; - reg = <0x11a60 0x20 0x8300 0x100>; - interrupts = <43 8>; - interrupt-parent = <&PIC>; - fsl,cpm-brg = <4>; - fsl,cpm-command = <0xce00000>; - }; - - usb@11b60 { - compatible = "fsl,mpc8272-cpm-usb"; - reg = <0x11b60 0x40 0x8b00 0x100>; - interrupts = <11 8>; - interrupt-parent = <&PIC>; - mode = "peripheral"; - }; - - mdio@10d40 { - compatible = "fsl,mpc8272ads-mdio-bitbang", - "fsl,mpc8272-mdio-bitbang", - "fsl,cpm2-mdio-bitbang"; - reg = <0x10d40 0x14>; - #address-cells = <1>; - #size-cells = <0>; - fsl,mdio-pin = <18>; - fsl,mdc-pin = <19>; - - PHY0: ethernet-phy@0 { - interrupt-parent = <&PIC>; - interrupts = <23 8>; - reg = <0x0>; - }; - - PHY1: ethernet-phy@1 { - interrupt-parent = <&PIC>; - interrupts = <23 8>; - reg = <0x3>; - }; - }; - - eth0: ethernet@11300 { - device_type = "network"; - compatible = "fsl,mpc8272-fcc-enet", - "fsl,cpm2-fcc-enet"; - reg = <0x11300 0x20 0x8400 0x100 0x11390 0x1>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <32 8>; - interrupt-parent = <&PIC>; - phy-handle = <&PHY0>; - linux,network-index = <0>; - fsl,cpm-command = <0x12000300>; - }; - - eth1: ethernet@11320 { - device_type = "network"; - compatible = "fsl,mpc8272-fcc-enet", - "fsl,cpm2-fcc-enet"; - reg = <0x11320 0x20 0x8500 0x100 0x113b0 0x1>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <33 8>; - interrupt-parent = <&PIC>; - phy-handle = <&PHY1>; - linux,network-index = <1>; - fsl,cpm-command = <0x16200300>; - }; - - i2c@11860 { - compatible = "fsl,mpc8272-i2c", - "fsl,cpm2-i2c"; - reg = <0x11860 0x20 0x8afc 0x2>; - interrupts = <1 8>; - interrupt-parent = <&PIC>; - fsl,cpm-command = <0x29600000>; - #address-cells = <1>; - #size-cells = <0>; - }; - }; - - PIC: interrupt-controller@10c00 { - #interrupt-cells = <2>; - interrupt-controller; - reg = <0x10c00 0x80>; - compatible = "fsl,mpc8272-pic", "fsl,cpm2-pic"; - }; - - crypto@30000 { - compatible = "fsl,sec1.0"; - reg = <0x40000 0x13000>; - interrupts = <47 0x8>; - interrupt-parent = <&PIC>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x7e>; - fsl,descriptor-types-mask = <0x1010415>; - }; - }; - - chosen { - stdout-path = "/soc/cpm/serial@11a00"; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts deleted file mode 100644 index 3af073f01e71..000000000000 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ /dev/null @@ -1,436 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8323E EMDS Device Tree Source - * - * Copyright 2006 Freescale Semiconductor Inc. - * - - * To enable external serial I/O on a Freescale MPC 8323 SYS/MDS board, do - * this: - * - * 1) On chip U61, lift (disconnect) pins 21 (TXD) and 22 (RXD) from the board. - * 2) Solder a wire from U61-21 to P19A-23. P19 is a grid of pins on the board - * next to the serial ports. - * 3) Solder a wire from U61-22 to P19K-22. - * - * Note that there's a typo in the schematic. The board labels the last column - * of pins "P19K", but in the schematic, that column is called "P19J". So if - * you're going by the schematic, the pin is called "P19J-K22". - */ - -/dts-v1/; - -/ { - model = "MPC8323EMDS"; - compatible = "MPC8323EMDS", "MPC832xMDS", "MPC83xxMDS"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8323@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; // 32 bytes - i-cache-line-size = <32>; // 32 bytes - d-cache-size = <16384>; // L1, 16K - i-cache-size = <16384>; // L1, 16K - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x08000000>; - }; - - bcsr@f8000000 { - compatible = "fsl,mpc8323mds-bcsr"; - reg = <0xf8000000 0x8000>; - }; - - soc8323@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <132000000>; - - wdt@200 { - device_type = "watchdog"; - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - pmc: power@b00 { - compatible = "fsl,mpc8323-pmc", "fsl,mpc8349-pmc"; - reg = <0xb00 0x100 0xa00 0x100>; - interrupts = <80 0x8>; - interrupt-parent = <&ipic>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - }; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8323-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - }; - - crypto@30000 { - compatible = "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <1>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x4c>; - fsl,descriptor-types-mask = <0x0122003f>; - sleep = <&pmc 0x03000000>; - }; - - ipic: pic@700 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - device_type = "ipic"; - }; - - par_io@1400 { - reg = <0x1400 0x100>; - device_type = "par_io"; - num-ports = <7>; - - pio3: ucc_pin@3 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 3 4 3 0 2 0 /* MDIO */ - 3 5 1 0 2 0 /* MDC */ - 0 13 2 0 1 0 /* RX_CLK (CLK9) */ - 3 24 2 0 1 0 /* TX_CLK (CLK10) */ - 1 0 1 0 1 0 /* TxD0 */ - 1 1 1 0 1 0 /* TxD1 */ - 1 2 1 0 1 0 /* TxD2 */ - 1 3 1 0 1 0 /* TxD3 */ - 1 4 2 0 1 0 /* RxD0 */ - 1 5 2 0 1 0 /* RxD1 */ - 1 6 2 0 1 0 /* RxD2 */ - 1 7 2 0 1 0 /* RxD3 */ - 1 8 2 0 1 0 /* RX_ER */ - 1 9 1 0 1 0 /* TX_ER */ - 1 10 2 0 1 0 /* RX_DV */ - 1 11 2 0 1 0 /* COL */ - 1 12 1 0 1 0 /* TX_EN */ - 1 13 2 0 1 0>; /* CRS */ - }; - pio4: ucc_pin@4 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 3 31 2 0 1 0 /* RX_CLK (CLK7) */ - 3 6 2 0 1 0 /* TX_CLK (CLK8) */ - 1 18 1 0 1 0 /* TxD0 */ - 1 19 1 0 1 0 /* TxD1 */ - 1 20 1 0 1 0 /* TxD2 */ - 1 21 1 0 1 0 /* TxD3 */ - 1 22 2 0 1 0 /* RxD0 */ - 1 23 2 0 1 0 /* RxD1 */ - 1 24 2 0 1 0 /* RxD2 */ - 1 25 2 0 1 0 /* RxD3 */ - 1 26 2 0 1 0 /* RX_ER */ - 1 27 1 0 1 0 /* TX_ER */ - 1 28 2 0 1 0 /* RX_DV */ - 1 29 2 0 1 0 /* COL */ - 1 30 1 0 1 0 /* TX_EN */ - 1 31 2 0 1 0>; /* CRS */ - }; - pio5: ucc_pin@5 { - pio-map = < - /* - * open has - * port pin dir drain sel irq - */ - 2 0 1 0 2 0 /* TxD5 */ - 2 8 2 0 2 0 /* RxD5 */ - - 2 29 2 0 0 0 /* CTS5 */ - 2 31 1 0 2 0 /* RTS5 */ - - 2 24 2 0 0 0 /* CD */ - - >; - }; - - }; - }; - - qe@e0100000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "qe"; - compatible = "fsl,qe"; - ranges = <0x0 0xe0100000 0x00100000>; - reg = <0xe0100000 0x480>; - brg-frequency = <0>; - bus-frequency = <198000000>; - fsl,qe-num-riscs = <1>; - fsl,qe-num-snums = <28>; - - muram@10000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,qe-muram", "fsl,cpm-muram"; - ranges = <0x0 0x00010000 0x00004000>; - - data-only@0 { - compatible = "fsl,qe-muram-data", - "fsl,cpm-muram-data"; - reg = <0x0 0x4000>; - }; - }; - - spi@4c0 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x4c0 0x40>; - interrupts = <2>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - spi@500 { - cell-index = <1>; - compatible = "fsl,spi"; - reg = <0x500 0x40>; - interrupts = <1>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - usb@6c0 { - compatible = "qe_udc"; - reg = <0x6c0 0x40 0x8b00 0x100>; - interrupts = <11>; - interrupt-parent = <&qeic>; - mode = "slave"; - }; - - enet0: ucc@2200 { - device_type = "network"; - compatible = "ucc_geth"; - cell-index = <3>; - reg = <0x2200 0x200>; - interrupts = <34>; - interrupt-parent = <&qeic>; - local-mac-address = [ 00 00 00 00 00 00 ]; - rx-clock-name = "clk9"; - tx-clock-name = "clk10"; - phy-handle = <&phy3>; - pio-handle = <&pio3>; - }; - - enet1: ucc@3200 { - device_type = "network"; - compatible = "ucc_geth"; - cell-index = <4>; - reg = <0x3200 0x200>; - interrupts = <35>; - interrupt-parent = <&qeic>; - local-mac-address = [ 00 00 00 00 00 00 ]; - rx-clock-name = "clk7"; - tx-clock-name = "clk8"; - phy-handle = <&phy4>; - pio-handle = <&pio4>; - }; - - ucc@2400 { - device_type = "serial"; - compatible = "ucc_uart"; - cell-index = <5>; /* The UCC number, 1-7*/ - port-number = <0>; /* Which ttyQEx device */ - soft-uart; /* We need Soft-UART */ - reg = <0x2400 0x200>; - interrupts = <40>; /* From Table 18-12 */ - interrupt-parent = < &qeic >; - /* - * For Soft-UART, we need to set TX to 1X, which - * means specifying separate clock sources. - */ - rx-clock-name = "brg5"; - tx-clock-name = "brg6"; - pio-handle = < &pio5 >; - }; - - - mdio@2320 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x2320 0x18>; - compatible = "fsl,ucc-mdio"; - - phy3: ethernet-phy@3 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x3>; - }; - phy4: ethernet-phy@4 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x4>; - }; - }; - - qeic: interrupt-controller@80 { - interrupt-controller; - compatible = "fsl,qe-ic"; - #address-cells = <0>; - #interrupt-cells = <1>; - reg = <0x80 0x80>; - big-endian; - interrupts = <32 0x8 33 0x8>; //high:32 low:33 - interrupt-parent = <&ipic>; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 0x11 AD17 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 AD18 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 AD19 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 AD21*/ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 AD22*/ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 AD23*/ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 AD24*/ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0x0 0x0>; - ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xd0000000 0x0 0x00100000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - sleep = <&pmc 0x00010000>; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts deleted file mode 100644 index 6c8cb859c55f..000000000000 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ /dev/null @@ -1,403 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8349E MDS Device Tree Source - * - * Copyright 2005, 2006 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "MPC8349EMDS"; - compatible = "MPC8349EMDS", "MPC834xMDS", "MPC83xxMDS"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - pci1 = &pci1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8349@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <32768>; - i-cache-size = <32768>; - timebase-frequency = <0>; // from bootloader - bus-frequency = <0>; // from bootloader - clock-frequency = <0>; // from bootloader - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x10000000>; // 256MB at 0 - }; - - bcsr@e2400000 { - compatible = "fsl,mpc8349mds-bcsr"; - reg = <0xe2400000 0x8000>; - }; - - soc8349@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <0>; - - wdt@200 { - device_type = "watchdog"; - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <15 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - }; - - spi@7000 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x7000 0x1000>; - interrupts = <16 0x8>; - interrupt-parent = <&ipic>; - mode = "cpu"; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8349-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - }; - - /* phy type (ULPI or SERIAL) are only types supported for MPH */ - /* port = 0 or 1 */ - usb@22000 { - compatible = "fsl-usb2-mph"; - reg = <0x22000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&ipic>; - interrupts = <39 0x8>; - phy_type = "ulpi"; - port0; - }; - /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */ - usb@23000 { - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&ipic>; - interrupts = <38 0x8>; - dr_mode = "otg"; - phy_type = "ulpi"; - }; - - enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <32 0x8 33 0x8 34 0x8>; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - linux,network-index = <0>; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy0: ethernet-phy@0 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x0>; - }; - - phy1: ethernet-phy@1 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x1>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "TSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 0x8 36 0x8 37 0x8>; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - linux,network-index = <1>; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - crypto@30000 { - compatible = "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x7e>; - fsl,descriptor-types-mask = <0x01010ebf>; - }; - - /* IPIC - * interrupts cell = - * sense values match linux IORESOURCE_IRQ_* defines: - * sense == 8: Level, low assertion - * sense == 2: Edge, high-to-low change - */ - ipic: pic@700 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - device_type = "ipic"; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0 0>; - ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>; - clock-frequency = <66666666>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - - pci1: pci@e0008600 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <67 0x8>; - bus-range = <0 0>; - ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000 - 0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe2100000 0x0 0x00100000>; - clock-frequency = <66666666>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008600 0x100 /* internal registers */ - 0xe0008380 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts deleted file mode 100644 index f4ca12ec57f1..000000000000 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ /dev/null @@ -1,481 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8360E EMDS Device Tree Source - * - * Copyright 2006 Freescale Semiconductor Inc. - */ - - -/* -/memreserve/ 00000000 1000000; -*/ - -/dts-v1/; - -/ { - model = "MPC8360MDS"; - compatible = "MPC8360EMDS", "MPC836xMDS", "MPC83xxMDS"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8360@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; // 32 bytes - i-cache-line-size = <32>; // 32 bytes - d-cache-size = <32768>; // L1, 32K - i-cache-size = <32768>; // L1, 32K - timebase-frequency = <66000000>; - bus-frequency = <264000000>; - clock-frequency = <528000000>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x10000000>; - }; - - localbus@e0005000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,mpc8360-localbus", "fsl,pq2pro-localbus", - "simple-bus"; - reg = <0xe0005000 0xd8>; - ranges = <0 0 0xfe000000 0x02000000 - 1 0 0xf8000000 0x00008000>; - - flash@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x2000000>; - bank-width = <2>; - device-width = <1>; - }; - - bcsr@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8360mds-bcsr"; - reg = <1 0 0x8000>; - ranges = <0 1 0 0x8000>; - - bcsr13: gpio-controller@d { - #gpio-cells = <2>; - compatible = "fsl,mpc8360mds-bcsr-gpio"; - reg = <0xd 1>; - gpio-controller; - }; - }; - }; - - soc8360@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <264000000>; - - wdt@200 { - device_type = "watchdog"; - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - pmc: power@b00 { - compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc"; - reg = <0xb00 0x100 0xa00 0x100>; - interrupts = <80 0x8>; - interrupt-parent = <&ipic>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <15 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <264000000>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <264000000>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8360-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - }; - - crypto@30000 { - compatible = "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x7e>; - fsl,descriptor-types-mask = <0x01010ebf>; - sleep = <&pmc 0x03000000>; - }; - - ipic: pic@700 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - device_type = "ipic"; - }; - - par_io@1400 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0x1400 0x100>; - ranges = <0 0x1400 0x100>; - device_type = "par_io"; - num-ports = <7>; - - qe_pio_b: gpio-controller@18 { - #gpio-cells = <2>; - compatible = "fsl,mpc8360-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank"; - reg = <0x18 0x18>; - gpio-controller; - }; - - pio1: ucc_pin@1 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 0 3 1 0 1 0 /* TxD0 */ - 0 4 1 0 1 0 /* TxD1 */ - 0 5 1 0 1 0 /* TxD2 */ - 0 6 1 0 1 0 /* TxD3 */ - 1 6 1 0 3 0 /* TxD4 */ - 1 7 1 0 1 0 /* TxD5 */ - 1 9 1 0 2 0 /* TxD6 */ - 1 10 1 0 2 0 /* TxD7 */ - 0 9 2 0 1 0 /* RxD0 */ - 0 10 2 0 1 0 /* RxD1 */ - 0 11 2 0 1 0 /* RxD2 */ - 0 12 2 0 1 0 /* RxD3 */ - 0 13 2 0 1 0 /* RxD4 */ - 1 1 2 0 2 0 /* RxD5 */ - 1 0 2 0 2 0 /* RxD6 */ - 1 4 2 0 2 0 /* RxD7 */ - 0 7 1 0 1 0 /* TX_EN */ - 0 8 1 0 1 0 /* TX_ER */ - 0 15 2 0 1 0 /* RX_DV */ - 0 16 2 0 1 0 /* RX_ER */ - 0 0 2 0 1 0 /* RX_CLK */ - 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ - 2 8 2 0 1 0>; /* GTX125 - CLK9 */ - }; - pio2: ucc_pin@2 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 0 17 1 0 1 0 /* TxD0 */ - 0 18 1 0 1 0 /* TxD1 */ - 0 19 1 0 1 0 /* TxD2 */ - 0 20 1 0 1 0 /* TxD3 */ - 1 2 1 0 1 0 /* TxD4 */ - 1 3 1 0 2 0 /* TxD5 */ - 1 5 1 0 3 0 /* TxD6 */ - 1 8 1 0 3 0 /* TxD7 */ - 0 23 2 0 1 0 /* RxD0 */ - 0 24 2 0 1 0 /* RxD1 */ - 0 25 2 0 1 0 /* RxD2 */ - 0 26 2 0 1 0 /* RxD3 */ - 0 27 2 0 1 0 /* RxD4 */ - 1 12 2 0 2 0 /* RxD5 */ - 1 13 2 0 3 0 /* RxD6 */ - 1 11 2 0 2 0 /* RxD7 */ - 0 21 1 0 1 0 /* TX_EN */ - 0 22 1 0 1 0 /* TX_ER */ - 0 29 2 0 1 0 /* RX_DV */ - 0 30 2 0 1 0 /* RX_ER */ - 0 31 2 0 1 0 /* RX_CLK */ - 2 2 1 0 2 0 /* GTX_CLK - CLK10 */ - 2 3 2 0 1 0 /* GTX125 - CLK4 */ - 0 1 3 0 2 0 /* MDIO */ - 0 2 1 0 1 0>; /* MDC */ - }; - - }; - }; - - qe@e0100000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "qe"; - compatible = "fsl,qe"; - ranges = <0x0 0xe0100000 0x00100000>; - reg = <0xe0100000 0x480>; - brg-frequency = <0>; - bus-frequency = <396000000>; - fsl,qe-num-riscs = <2>; - fsl,qe-num-snums = <28>; - - muram@10000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,qe-muram", "fsl,cpm-muram"; - ranges = <0x0 0x00010000 0x0000c000>; - - data-only@0 { - compatible = "fsl,qe-muram-data", - "fsl,cpm-muram-data"; - reg = <0x0 0xc000>; - }; - }; - - timer@440 { - compatible = "fsl,mpc8360-qe-gtm", - "fsl,qe-gtm", "fsl,gtm"; - reg = <0x440 0x40>; - clock-frequency = <132000000>; - interrupts = <12 13 14 15>; - interrupt-parent = <&qeic>; - }; - - spi@4c0 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x4c0 0x40>; - interrupts = <2>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - spi@500 { - cell-index = <1>; - compatible = "fsl,spi"; - reg = <0x500 0x40>; - interrupts = <1>; - interrupt-parent = <&qeic>; - mode = "cpu"; - }; - - usb@6c0 { - compatible = "fsl,mpc8360-qe-usb", - "fsl,mpc8323-qe-usb"; - reg = <0x6c0 0x40 0x8b00 0x100>; - interrupts = <11>; - interrupt-parent = <&qeic>; - fsl,fullspeed-clock = "clk21"; - fsl,lowspeed-clock = "brg9"; - gpios = <&qe_pio_b 2 0 /* USBOE */ - &qe_pio_b 3 0 /* USBTP */ - &qe_pio_b 8 0 /* USBTN */ - &qe_pio_b 9 0 /* USBRP */ - &qe_pio_b 11 0 /* USBRN */ - &bcsr13 5 0 /* SPEED */ - &bcsr13 4 1>; /* POWER */ - }; - - enet0: ucc@2000 { - device_type = "network"; - compatible = "ucc_geth"; - cell-index = <1>; - reg = <0x2000 0x200>; - interrupts = <32>; - interrupt-parent = <&qeic>; - local-mac-address = [ 00 00 00 00 00 00 ]; - rx-clock-name = "none"; - tx-clock-name = "clk9"; - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; - pio-handle = <&pio1>; - }; - - enet1: ucc@3000 { - device_type = "network"; - compatible = "ucc_geth"; - cell-index = <2>; - reg = <0x3000 0x200>; - interrupts = <33>; - interrupt-parent = <&qeic>; - local-mac-address = [ 00 00 00 00 00 00 ]; - rx-clock-name = "none"; - tx-clock-name = "clk4"; - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - pio-handle = <&pio2>; - }; - - mdio@2120 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x2120 0x18>; - compatible = "fsl,ucc-mdio"; - - phy0: ethernet-phy@0 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x1>; - }; - tbi-phy@2 { - device_type = "tbi-phy"; - reg = <0x2>; - }; - }; - - qeic: interrupt-controller@80 { - interrupt-controller; - compatible = "fsl,qe-ic"; - #address-cells = <0>; - #interrupt-cells = <1>; - reg = <0x80 0x80>; - big-endian; - interrupts = <32 0x8 33 0x8>; // high:32 low:33 - interrupt-parent = <&ipic>; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 AD17 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 AD18 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 AD19 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 AD21*/ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 AD22*/ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 AD23*/ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 AD24*/ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0 0>; - ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>; - clock-frequency = <66666666>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - sleep = <&pmc 0x00010000>; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts deleted file mode 100644 index 9227bce0e2f5..000000000000 --- a/arch/powerpc/boot/dts/mpc8377_mds.dts +++ /dev/null @@ -1,505 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8377E MDS Device Tree Source - * - * Copyright 2007 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "fsl,mpc8377emds"; - compatible = "fsl,mpc8377emds","fsl,mpc837xmds"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - pci1 = &pci1; - pci2 = &pci2; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8377@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <32768>; - i-cache-size = <32768>; - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x20000000>; // 512MB at 0 - }; - - localbus@e0005000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,mpc8377-elbc", "fsl,elbc", "simple-bus"; - reg = <0xe0005000 0x1000>; - interrupts = <77 0x8>; - interrupt-parent = <&ipic>; - - // booting from NOR flash - ranges = <0 0x0 0xfe000000 0x02000000 - 1 0x0 0xf8000000 0x00008000 - 3 0x0 0xe0600000 0x00008000>; - - flash@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0 0x0 0x2000000>; - bank-width = <2>; - device-width = <1>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - fs@100000 { - reg = <0x100000 0x800000>; - }; - - kernel@1d00000 { - reg = <0x1d00000 0x200000>; - }; - - dtb@1f00000 { - reg = <0x1f00000 0x100000>; - }; - }; - - bcsr@1,0 { - reg = <1 0x0 0x8000>; - compatible = "fsl,mpc837xmds-bcsr"; - }; - - nand@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8377-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <3 0x0 0x8000>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - kernel@100000 { - reg = <0x100000 0x300000>; - }; - - fs@400000 { - reg = <0x400000 0x1c00000>; - }; - }; - }; - - soc@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <0>; - - wdt@200 { - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - sleep-nexus { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - sleep = <&pmc 0x0c000000>; - ranges; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - interrupts = <19 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - sdhci@2e000 { - compatible = "fsl,mpc8377-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <42 0x8>; - interrupt-parent = <&ipic>; - sdhci,wp-inverted; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <15 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - }; - - spi@7000 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x7000 0x1000>; - interrupts = <16 0x8>; - interrupt-parent = <&ipic>; - mode = "cpu"; - }; - - usb@23000 { - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&ipic>; - interrupts = <38 0x8>; - dr_mode = "host"; - phy_type = "ulpi"; - sleep = <&pmc 0x00c00000>; - }; - - enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <32 0x8 33 0x8 34 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi0>; - phy-handle = <&phy2>; - sleep = <&pmc 0xc0000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy2: ethernet-phy@2 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x2>; - }; - - phy3: ethernet-phy@3 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x3>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 0x8 36 0x8 37 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi1>; - phy-handle = <&phy3>; - sleep = <&pmc 0x30000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8377-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <0x47 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <0x47 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <0x47 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <0x47 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <0x47 8>; - }; - }; - - crypto@30000 { - compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2", - "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x9fe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - sleep = <&pmc 0x03000000>; - }; - - sata@18000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x18000 0x1000>; - interrupts = <44 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x000000c0>; - }; - - sata@19000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x19000 0x1000>; - interrupts = <45 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x00000030>; - }; - - /* IPIC - * interrupts cell = - * sense values match linux IORESOURCE_IRQ_* defines: - * sense == 8: Level, low assertion - * sense == 2: Edge, high-to-low change - */ - ipic: pic@700 { - compatible = "fsl,ipic"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - }; - - pmc: power@b00 { - compatible = "fsl,mpc8377-pmc", "fsl,mpc8349-pmc"; - reg = <0xb00 0x100 0xa00 0x100>; - interrupts = <80 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0x0 0x0>; - ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>; - sleep = <&pmc 0x00010000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - - pci1: pcie@e0009000 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - compatible = "fsl,mpc8377-pcie", "fsl,mpc8314-pcie"; - reg = <0xe0009000 0x00001000>; - ranges = <0x02000000 0 0xa8000000 0xa8000000 0 0x10000000 - 0x01000000 0 0x00000000 0xb8000000 0 0x00800000>; - bus-range = <0 255>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = <0 0 0 1 &ipic 1 8 - 0 0 0 2 &ipic 1 8 - 0 0 0 3 &ipic 1 8 - 0 0 0 4 &ipic 1 8>; - sleep = <&pmc 0x00300000>; - clock-frequency = <0>; - - pcie@0 { - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - reg = <0 0 0 0 0>; - ranges = <0x02000000 0 0xa8000000 - 0x02000000 0 0xa8000000 - 0 0x10000000 - 0x01000000 0 0x00000000 - 0x01000000 0 0x00000000 - 0 0x00800000>; - }; - }; - - pci2: pcie@e000a000 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - compatible = "fsl,mpc8377-pcie", "fsl,mpc8314-pcie"; - reg = <0xe000a000 0x00001000>; - ranges = <0x02000000 0 0xc8000000 0xc8000000 0 0x10000000 - 0x01000000 0 0x00000000 0xd8000000 0 0x00800000>; - bus-range = <0 255>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = <0 0 0 1 &ipic 2 8 - 0 0 0 2 &ipic 2 8 - 0 0 0 3 &ipic 2 8 - 0 0 0 4 &ipic 2 8>; - sleep = <&pmc 0x000c0000>; - clock-frequency = <0>; - - pcie@0 { - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - reg = <0 0 0 0 0>; - ranges = <0x02000000 0 0xc8000000 - 0x02000000 0 0xc8000000 - 0 0x10000000 - 0x01000000 0 0x00000000 - 0x01000000 0 0x00000000 - 0 0x00800000>; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts deleted file mode 100644 index e45b25554e8c..000000000000 --- a/arch/powerpc/boot/dts/mpc8378_mds.dts +++ /dev/null @@ -1,489 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8378E MDS Device Tree Source - * - * Copyright 2007 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "fsl,mpc8378emds"; - compatible = "fsl,mpc8378emds","fsl,mpc837xmds"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - pci1 = &pci1; - pci2 = &pci2; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8378@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <32768>; - i-cache-size = <32768>; - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x20000000>; // 512MB at 0 - }; - - localbus@e0005000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,mpc8378-elbc", "fsl,elbc", "simple-bus"; - reg = <0xe0005000 0x1000>; - interrupts = <77 0x8>; - interrupt-parent = <&ipic>; - - // booting from NOR flash - ranges = <0 0x0 0xfe000000 0x02000000 - 1 0x0 0xf8000000 0x00008000 - 3 0x0 0xe0600000 0x00008000>; - - flash@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0 0x0 0x2000000>; - bank-width = <2>; - device-width = <1>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - fs@100000 { - reg = <0x100000 0x800000>; - }; - - kernel@1d00000 { - reg = <0x1d00000 0x200000>; - }; - - dtb@1f00000 { - reg = <0x1f00000 0x100000>; - }; - }; - - bcsr@1,0 { - reg = <1 0x0 0x8000>; - compatible = "fsl,mpc837xmds-bcsr"; - }; - - nand@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8378-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <3 0x0 0x8000>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - kernel@100000 { - reg = <0x100000 0x300000>; - }; - - fs@400000 { - reg = <0x400000 0x1c00000>; - }; - }; - }; - - soc@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <0>; - - wdt@200 { - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - sleep-nexus { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - sleep = <&pmc 0x0c000000>; - ranges; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - interrupts = <19 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - sdhci@2e000 { - compatible = "fsl,mpc8378-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <42 0x8>; - interrupt-parent = <&ipic>; - sdhci,wp-inverted; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <15 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - }; - - spi@7000 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x7000 0x1000>; - interrupts = <16 0x8>; - interrupt-parent = <&ipic>; - mode = "cpu"; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8378-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - }; - - usb@23000 { - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&ipic>; - interrupts = <38 0x8>; - dr_mode = "host"; - phy_type = "ulpi"; - sleep = <&pmc 0x00c00000>; - }; - - enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <32 0x8 33 0x8 34 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi0>; - phy-handle = <&phy2>; - sleep = <&pmc 0xc0000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy2: ethernet-phy@2 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x2>; - }; - - phy3: ethernet-phy@3 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x3>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 0x8 36 0x8 37 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi1>; - phy-handle = <&phy3>; - sleep = <&pmc 0x30000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - crypto@30000 { - compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2", - "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x9fe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - sleep = <&pmc 0x03000000>; - }; - - /* IPIC - * interrupts cell = - * sense values match linux IORESOURCE_IRQ_* defines: - * sense == 8: Level, low assertion - * sense == 2: Edge, high-to-low change - */ - ipic: pic@700 { - compatible = "fsl,ipic"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - }; - - pmc: power@b00 { - compatible = "fsl,mpc8378-pmc", "fsl,mpc8349-pmc"; - reg = <0xb00 0x100 0xa00 0x100>; - interrupts = <80 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0x0 0x0>; - ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>; - clock-frequency = <0>; - sleep = <&pmc 0x00010000>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; - - pci1: pcie@e0009000 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - compatible = "fsl,mpc8378-pcie", "fsl,mpc8314-pcie"; - reg = <0xe0009000 0x00001000>; - ranges = <0x02000000 0 0xa8000000 0xa8000000 0 0x10000000 - 0x01000000 0 0x00000000 0xb8000000 0 0x00800000>; - bus-range = <0 255>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = <0 0 0 1 &ipic 1 8 - 0 0 0 2 &ipic 1 8 - 0 0 0 3 &ipic 1 8 - 0 0 0 4 &ipic 1 8>; - sleep = <&pmc 0x00300000>; - clock-frequency = <0>; - - pcie@0 { - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - reg = <0 0 0 0 0>; - ranges = <0x02000000 0 0xa8000000 - 0x02000000 0 0xa8000000 - 0 0x10000000 - 0x01000000 0 0x00000000 - 0x01000000 0 0x00000000 - 0 0x00800000>; - }; - }; - - pci2: pcie@e000a000 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - compatible = "fsl,mpc8378-pcie", "fsl,mpc8314-pcie"; - reg = <0xe000a000 0x00001000>; - ranges = <0x02000000 0 0xc8000000 0xc8000000 0 0x10000000 - 0x01000000 0 0x00000000 0xd8000000 0 0x00800000>; - bus-range = <0 255>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = <0 0 0 1 &ipic 2 8 - 0 0 0 2 &ipic 2 8 - 0 0 0 3 &ipic 2 8 - 0 0 0 4 &ipic 2 8>; - sleep = <&pmc 0x000c0000>; - clock-frequency = <0>; - - pcie@0 { - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - reg = <0 0 0 0 0>; - ranges = <0x02000000 0 0xc8000000 - 0x02000000 0 0xc8000000 - 0 0x10000000 - 0x01000000 0 0x00000000 - 0x01000000 0 0x00000000 - 0 0x00800000>; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts deleted file mode 100644 index f7379a1cbb6c..000000000000 --- a/arch/powerpc/boot/dts/mpc8379_mds.dts +++ /dev/null @@ -1,455 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8379E MDS Device Tree Source - * - * Copyright 2007 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "fsl,mpc8379emds"; - compatible = "fsl,mpc8379emds","fsl,mpc837xmds"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8379@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <32768>; - i-cache-size = <32768>; - timebase-frequency = <0>; - bus-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x20000000>; // 512MB at 0 - }; - - localbus@e0005000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,mpc8379-elbc", "fsl,elbc", "simple-bus"; - reg = <0xe0005000 0x1000>; - interrupts = <77 0x8>; - interrupt-parent = <&ipic>; - - // booting from NOR flash - ranges = <0 0x0 0xfe000000 0x02000000 - 1 0x0 0xf8000000 0x00008000 - 3 0x0 0xe0600000 0x00008000>; - - flash@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0 0x0 0x2000000>; - bank-width = <2>; - device-width = <1>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - fs@100000 { - reg = <0x100000 0x800000>; - }; - - kernel@1d00000 { - reg = <0x1d00000 0x200000>; - }; - - dtb@1f00000 { - reg = <0x1f00000 0x100000>; - }; - }; - - bcsr@1,0 { - reg = <1 0x0 0x8000>; - compatible = "fsl,mpc837xmds-bcsr"; - }; - - nand@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8379-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <3 0x0 0x8000>; - - u-boot@0 { - reg = <0x0 0x100000>; - read-only; - }; - - kernel@100000 { - reg = <0x100000 0x300000>; - }; - - fs@400000 { - reg = <0x400000 0x1c00000>; - }; - }; - }; - - soc@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - reg = <0xe0000000 0x00000200>; - bus-frequency = <0>; - - wdt@200 { - compatible = "mpc83xx_wdt"; - reg = <0x200 0x100>; - }; - - sleep-nexus { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - sleep = <&pmc 0x0c000000>; - ranges; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <14 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - - rtc@68 { - compatible = "dallas,ds1374"; - reg = <0x68>; - interrupts = <19 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - sdhci@2e000 { - compatible = "fsl,mpc8379-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <42 0x8>; - interrupt-parent = <&ipic>; - sdhci,wp-inverted; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <15 0x8>; - interrupt-parent = <&ipic>; - dfsrr; - }; - - spi@7000 { - cell-index = <0>; - compatible = "fsl,spi"; - reg = <0x7000 0x1000>; - interrupts = <16 0x8>; - interrupt-parent = <&ipic>; - mode = "cpu"; - }; - - dma@82a8 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8379-dma", "fsl,elo-dma"; - reg = <0x82a8 4>; - ranges = <0 0x8100 0x1a8>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel"; - reg = <0 0x80>; - cell-index = <0>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@80 { - compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@100 { - compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - dma-channel@180 { - compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel"; - reg = <0x180 0x28>; - cell-index = <3>; - interrupt-parent = <&ipic>; - interrupts = <71 8>; - }; - }; - - usb@23000 { - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&ipic>; - interrupts = <38 0x8>; - dr_mode = "host"; - phy_type = "ulpi"; - sleep = <&pmc 0x00c00000>; - }; - - enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <32 0x8 33 0x8 34 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi0>; - phy-handle = <&phy2>; - sleep = <&pmc 0xc0000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy2: ethernet-phy@2 { - interrupt-parent = <&ipic>; - interrupts = <17 0x8>; - reg = <0x2>; - }; - - phy3: ethernet-phy@3 { - interrupt-parent = <&ipic>; - interrupts = <18 0x8>; - reg = <0x3>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 0x8 36 0x8 37 0x8>; - phy-connection-type = "mii"; - interrupt-parent = <&ipic>; - tbi-handle = <&tbi1>; - phy-handle = <&phy3>; - sleep = <&pmc 0x30000000>; - fsl,magic-packet; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <9 0x8>; - interrupt-parent = <&ipic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <10 0x8>; - interrupt-parent = <&ipic>; - }; - - crypto@30000 { - compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2", - "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <11 0x8>; - interrupt-parent = <&ipic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0x9fe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - sleep = <&pmc 0x03000000>; - }; - - sata@18000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x18000 0x1000>; - interrupts = <44 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x000000c0>; - }; - - sata@19000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x19000 0x1000>; - interrupts = <45 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x00000030>; - }; - - sata@1a000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x1a000 0x1000>; - interrupts = <46 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x0000000c>; - }; - - sata@1b000 { - compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; - reg = <0x1b000 0x1000>; - interrupts = <47 0x8>; - interrupt-parent = <&ipic>; - sleep = <&pmc 0x00000003>; - }; - - /* IPIC - * interrupts cell = - * sense values match linux IORESOURCE_IRQ_* defines: - * sense == 8: Level, low assertion - * sense == 2: Edge, high-to-low change - */ - ipic: pic@700 { - compatible = "fsl,ipic"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x700 0x100>; - }; - - pmc: power@b00 { - compatible = "fsl,mpc8379-pmc", "fsl,mpc8349-pmc"; - reg = <0xb00 0x100 0xa00 0x100>; - interrupts = <80 0x8>; - interrupt-parent = <&ipic>; - }; - }; - - pci0: pci@e0008500 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x11 */ - 0x8800 0x0 0x0 0x1 &ipic 20 0x8 - 0x8800 0x0 0x0 0x2 &ipic 21 0x8 - 0x8800 0x0 0x0 0x3 &ipic 22 0x8 - 0x8800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x12 */ - 0x9000 0x0 0x0 0x1 &ipic 22 0x8 - 0x9000 0x0 0x0 0x2 &ipic 23 0x8 - 0x9000 0x0 0x0 0x3 &ipic 20 0x8 - 0x9000 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x13 */ - 0x9800 0x0 0x0 0x1 &ipic 23 0x8 - 0x9800 0x0 0x0 0x2 &ipic 20 0x8 - 0x9800 0x0 0x0 0x3 &ipic 21 0x8 - 0x9800 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &ipic 20 0x8 - 0xa800 0x0 0x0 0x2 &ipic 21 0x8 - 0xa800 0x0 0x0 0x3 &ipic 22 0x8 - 0xa800 0x0 0x0 0x4 &ipic 23 0x8 - - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &ipic 23 0x8 - 0xb000 0x0 0x0 0x2 &ipic 20 0x8 - 0xb000 0x0 0x0 0x3 &ipic 21 0x8 - 0xb000 0x0 0x0 0x4 &ipic 22 0x8 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &ipic 22 0x8 - 0xb800 0x0 0x0 0x2 &ipic 23 0x8 - 0xb800 0x0 0x0 0x3 &ipic 20 0x8 - 0xb800 0x0 0x0 0x4 &ipic 21 0x8 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &ipic 21 0x8 - 0xc000 0x0 0x0 0x2 &ipic 22 0x8 - 0xc000 0x0 0x0 0x3 &ipic 23 0x8 - 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; - interrupt-parent = <&ipic>; - interrupts = <66 0x8>; - bus-range = <0x0 0x0>; - ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 - 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>; - sleep = <&pmc 0x00010000>; - clock-frequency = <0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008500 0x100 /* internal registers */ - 0xe0008300 0x8>; /* config space access registers */ - compatible = "fsl,mpc8349-pci"; - device_type = "pci"; - }; -}; diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts deleted file mode 100644 index 33bbe58c1ad0..000000000000 --- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts +++ /dev/null @@ -1,503 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * MPC8610 HPCD Device Tree Source - * - * Copyright 2007-2008 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "MPC8610HPCD"; - compatible = "fsl,MPC8610HPCD"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - pci1 = &pci1; - pci2 = &pci2; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,8610@0 { - device_type = "cpu"; - reg = <0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <32768>; // L1 - i-cache-size = <32768>; // L1 - sleep = <&pmc 0x00008000 0 // core - &pmc 0x00004000 0>; // timebase - timebase-frequency = <0>; // From uboot - bus-frequency = <0>; // From uboot - clock-frequency = <0>; // From uboot - }; - }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x20000000>; // 512M at 0x0 - }; - - localbus@e0005000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,mpc8610-elbc", "fsl,elbc", "simple-bus"; - reg = <0xe0005000 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; - ranges = <0 0 0xf8000000 0x08000000 - 1 0 0xf0000000 0x08000000 - 2 0 0xe8400000 0x00008000 - 4 0 0xe8440000 0x00008000 - 5 0 0xe8480000 0x00008000 - 6 0 0xe84c0000 0x00008000 - 3 0 0xe8000000 0x00000020>; - sleep = <&pmc 0x08000000 0>; - - flash@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x8000000>; - bank-width = <2>; - device-width = <1>; - }; - - flash@1,0 { - compatible = "cfi-flash"; - reg = <1 0 0x8000000>; - bank-width = <2>; - device-width = <1>; - }; - - flash@2,0 { - compatible = "fsl,mpc8610-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <2 0 0x8000>; - }; - - flash@4,0 { - compatible = "fsl,mpc8610-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <4 0 0x8000>; - }; - - flash@5,0 { - compatible = "fsl,mpc8610-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <5 0 0x8000>; - }; - - flash@6,0 { - compatible = "fsl,mpc8610-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <6 0 0x8000>; - }; - - board-control@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,fpga-pixis"; - reg = <3 0 0x20>; - ranges = <0 3 0 0x20>; - interrupt-parent = <&mpic>; - interrupts = <8 8>; - - sdcsr_pio: gpio-controller@a { - #gpio-cells = <2>; - compatible = "fsl,fpga-pixis-gpio-bank"; - reg = <0xa 1>; - gpio-controller; - }; - }; - }; - - soc@e0000000 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - device_type = "soc"; - compatible = "fsl,mpc8610-immr", "simple-bus"; - ranges = <0x0 0xe0000000 0x00100000>; - bus-frequency = <0>; - - mcm-law@0 { - compatible = "fsl,mcm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <10>; - }; - - mcm@1000 { - compatible = "fsl,mpc8610-mcm", "fsl,mcm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - - cs4270:codec@4f { - compatible = "cirrus,cs4270"; - reg = <0x4f>; - /* MCLK source is a stand-alone oscillator */ - clock-frequency = <12288000>; - }; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - sleep = <&pmc 0x00000004 0>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - sleep = <&pmc 0x00000002 0>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "fsl,ns16550", "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - sleep = <&pmc 0x00000008 0>; - }; - - spi@7000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,mpc8610-spi", "fsl,spi"; - reg = <0x7000 0x40>; - cell-index = <0>; - interrupts = <59 2>; - interrupt-parent = <&mpic>; - mode = "cpu"; - cs-gpios = <&sdcsr_pio 7 0>; - sleep = <&pmc 0x00000800 0>; - - mmc-slot@0 { - compatible = "fsl,mpc8610hpcd-mmc-slot", - "mmc-spi-slot"; - reg = <0>; - gpios = <&sdcsr_pio 0 1 /* nCD */ - &sdcsr_pio 1 0>; /* WP */ - voltage-ranges = <3300 3300>; - spi-max-frequency = <50000000>; - }; - }; - - display@2c000 { - compatible = "fsl,diu"; - reg = <0x2c000 100>; - interrupts = <72 2>; - interrupt-parent = <&mpic>; - sleep = <&pmc 0x04000000 0>; - }; - - mpic: interrupt-controller@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - - msi@41600 { - compatible = "fsl,mpc8610-msi", "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8610-guts"; - reg = <0xe0000 0x1000>; - ranges = <0 0xe0000 0x1000>; - fsl,has-rstcr; - - pmc: power@70 { - compatible = "fsl,mpc8610-pmc", - "fsl,mpc8641d-pmc"; - reg = <0x70 0x20>; - }; - }; - - wdt@e4000 { - compatible = "fsl,mpc8610-wdt"; - reg = <0xe4000 0x100>; - }; - - ssi@16000 { - compatible = "fsl,mpc8610-ssi"; - cell-index = <0>; - reg = <0x16000 0x100>; - interrupt-parent = <&mpic>; - interrupts = <62 2>; - fsl,mode = "i2s-slave"; - codec-handle = <&cs4270>; - fsl,playback-dma = <&dma00>; - fsl,capture-dma = <&dma01>; - fsl,fifo-depth = <8>; - sleep = <&pmc 0 0x08000000>; - }; - - ssi@16100 { - compatible = "fsl,mpc8610-ssi"; - status = "disabled"; - cell-index = <1>; - reg = <0x16100 0x100>; - interrupt-parent = <&mpic>; - interrupts = <63 2>; - fsl,fifo-depth = <8>; - sleep = <&pmc 0 0x04000000>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8610-dma", "fsl,eloplus-dma"; - cell-index = <0>; - reg = <0x21300 0x4>; /* DMA general status register */ - ranges = <0x0 0x21100 0x200>; - sleep = <&pmc 0x00000400 0>; - - dma00: dma-channel@0 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,ssi-dma-channel"; - cell-index = <0>; - reg = <0x0 0x80>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma01: dma-channel@1 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,ssi-dma-channel"; - cell-index = <1>; - reg = <0x80 0x80>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@2 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <2>; - reg = <0x100 0x80>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@3 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <3>; - reg = <0x180 0x80>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; - - dma@c300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8610-dma", "fsl,eloplus-dma"; - cell-index = <1>; - reg = <0xc300 0x4>; /* DMA general status register */ - ranges = <0x0 0xc100 0x200>; - sleep = <&pmc 0x00000200 0>; - - dma-channel@0 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <0>; - reg = <0x0 0x80>; - interrupt-parent = <&mpic>; - interrupts = <76 2>; - }; - dma-channel@1 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <1>; - reg = <0x80 0x80>; - interrupt-parent = <&mpic>; - interrupts = <77 2>; - }; - dma-channel@2 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <2>; - reg = <0x100 0x80>; - interrupt-parent = <&mpic>; - interrupts = <78 2>; - }; - dma-channel@3 { - compatible = "fsl,mpc8610-dma-channel", - "fsl,eloplus-dma-channel"; - cell-index = <3>; - reg = <0x180 0x80>; - interrupt-parent = <&mpic>; - interrupts = <79 2>; - }; - }; - - }; - - pci0: pci@e0008000 { - compatible = "fsl,mpc8610-pci"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe0008000 0x1000>; - bus-range = <0 0>; - ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe1000000 0x0 0x00100000>; - sleep = <&pmc 0x80000000 0>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <24 2>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = < - /* IDSEL 0x11 */ - 0x8800 0 0 1 &mpic 4 1 - 0x8800 0 0 2 &mpic 5 1 - 0x8800 0 0 3 &mpic 6 1 - 0x8800 0 0 4 &mpic 7 1 - - /* IDSEL 0x12 */ - 0x9000 0 0 1 &mpic 5 1 - 0x9000 0 0 2 &mpic 6 1 - 0x9000 0 0 3 &mpic 7 1 - 0x9000 0 0 4 &mpic 4 1 - >; - }; - - pci1: pcie@e000a000 { - compatible = "fsl,mpc8641-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0xe000a000 0x1000>; - bus-range = <1 3>; - ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 - 0x01000000 0x0 0x00000000 0xe3000000 0x0 0x00100000>; - sleep = <&pmc 0x40000000 0>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; - interrupt-map-mask = <0xf800 0 0 7>; - - interrupt-map = < - /* IDSEL 0x1b */ - 0xd800 0 0 1 &mpic 2 1 - - /* IDSEL 0x1c*/ - 0xe000 0 0 1 &mpic 1 1 - 0xe000 0 0 2 &mpic 1 1 - 0xe000 0 0 3 &mpic 1 1 - 0xe000 0 0 4 &mpic 1 1 - - /* IDSEL 0x1f */ - 0xf800 0 0 1 &mpic 3 2 - 0xf800 0 0 2 &mpic 0 1 - >; - - pcie@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - device_type = "pci"; - ranges = <0x02000000 0x0 0xa0000000 - 0x02000000 0x0 0xa0000000 - 0x0 0x10000000 - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00100000>; - uli1575@0 { - reg = <0 0 0 0 0>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <0x02000000 0x0 0xa0000000 - 0x02000000 0x0 0xa0000000 - 0x0 0x10000000 - 0x01000000 0x0 0x00000000 - 0x01000000 0x0 0x00000000 - 0x0 0x00100000>; - - isa@1e { - device_type = "isa"; - #size-cells = <1>; - #address-cells = <2>; - reg = <0xf000 0 0 0 0>; - ranges = <1 0 0x01000000 0 0 - 0x00001000>; - - rtc@70 { - compatible = "pnpPNP,b00"; - reg = <1 0x70 2>; - }; - }; - }; - }; - }; - - pci2: pcie@e0009000 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - compatible = "fsl,mpc8641-pcie"; - reg = <0xe0009000 0x00001000>; - ranges = <0x02000000 0 0x90000000 0x90000000 0 0x10000000 - 0x01000000 0 0x00000000 0xe2000000 0 0x00100000>; - bus-range = <0 255>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = <0x0000 0 0 1 &mpic 4 1 - 0x0000 0 0 2 &mpic 5 1 - 0x0000 0 0 3 &mpic 6 1 - 0x0000 0 0 4 &mpic 7 1>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; - sleep = <&pmc 0x20000000 0>; - clock-frequency = <33333333>; - }; -}; diff --git a/arch/powerpc/boot/dts/pq2fads.dts b/arch/powerpc/boot/dts/pq2fads.dts deleted file mode 100644 index b6666215ed63..000000000000 --- a/arch/powerpc/boot/dts/pq2fads.dts +++ /dev/null @@ -1,243 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Device Tree for the PQ2FADS-ZU board with an MPC8280 chip. - * - * Copyright 2007,2008 Freescale Semiconductor Inc. - */ - -/dts-v1/; - -/ { - model = "pq2fads"; - compatible = "fsl,pq2fads"; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - reg = <0x0>; - d-cache-line-size = <32>; - i-cache-line-size = <32>; - d-cache-size = <16384>; - i-cache-size = <16384>; - timebase-frequency = <0>; - clock-frequency = <0>; - }; - }; - - memory { - device_type = "memory"; - reg = <0x0 0x0>; - }; - - localbus@f0010100 { - compatible = "fsl,mpc8280-localbus", - "fsl,pq2-localbus"; - #address-cells = <2>; - #size-cells = <1>; - reg = <0xf0010100 0x60>; - - ranges = <0x0 0x0 0xff800000 0x800000 - 0x1 0x0 0xf4500000 0x8000 - 0x8 0x0 0xf8200000 0x8000>; - - flash@0,0 { - compatible = "jedec-flash"; - reg = <0x0 0x0 0x800000>; - bank-width = <4>; - device-width = <1>; - }; - - bcsr@1,0 { - reg = <0x1 0x0 0x20>; - compatible = "fsl,pq2fads-bcsr"; - }; - - PCI_PIC: pic@8,0 { - #interrupt-cells = <1>; - interrupt-controller; - reg = <0x8 0x0 0x8>; - compatible = "fsl,pq2ads-pci-pic"; - interrupt-parent = <&PIC>; - interrupts = <24 8>; - }; - }; - - pci0: pci@f0010800 { - device_type = "pci"; - reg = <0xf0010800 0x10c 0xf00101ac 0x8 0xf00101c4 0x8>; - compatible = "fsl,mpc8280-pci", "fsl,pq2-pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - clock-frequency = <66000000>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 0x16 */ - 0xb000 0x0 0x0 0x1 &PCI_PIC 0 - 0xb000 0x0 0x0 0x2 &PCI_PIC 1 - 0xb000 0x0 0x0 0x3 &PCI_PIC 2 - 0xb000 0x0 0x0 0x4 &PCI_PIC 3 - - /* IDSEL 0x17 */ - 0xb800 0x0 0x0 0x1 &PCI_PIC 4 - 0xb800 0x0 0x0 0x2 &PCI_PIC 5 - 0xb800 0x0 0x0 0x3 &PCI_PIC 6 - 0xb800 0x0 0x0 0x4 &PCI_PIC 7 - - /* IDSEL 0x18 */ - 0xc000 0x0 0x0 0x1 &PCI_PIC 8 - 0xc000 0x0 0x0 0x2 &PCI_PIC 9 - 0xc000 0x0 0x0 0x3 &PCI_PIC 10 - 0xc000 0x0 0x0 0x4 &PCI_PIC 11>; - - interrupt-parent = <&PIC>; - interrupts = <18 8>; - ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x20000000 - 0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x0 0xf6000000 0x0 0x2000000>; - }; - - soc@f0000000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,mpc8280", "fsl,pq2-soc"; - ranges = <0x0 0xf0000000 0x53000>; - - // Temporary -- will go away once kernel uses ranges for get_immrbase(). - reg = <0xf0000000 0x53000>; - - cpm@119c0 { - #address-cells = <1>; - #size-cells = <1>; - #interrupt-cells = <2>; - compatible = "fsl,mpc8280-cpm", "fsl,cpm2"; - reg = <0x119c0 0x30>; - ranges; - - muram@0 { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x10000>; - - data@0 { - compatible = "fsl,cpm-muram-data"; - reg = <0x0 0x2000 0x9800 0x800>; - }; - }; - - brg@119f0 { - compatible = "fsl,mpc8280-brg", - "fsl,cpm2-brg", - "fsl,cpm-brg"; - reg = <0x119f0 0x10 0x115f0 0x10>; - }; - - serial0: serial@11a00 { - device_type = "serial"; - compatible = "fsl,mpc8280-scc-uart", - "fsl,cpm2-scc-uart"; - reg = <0x11a00 0x20 0x8000 0x100>; - interrupts = <40 8>; - interrupt-parent = <&PIC>; - fsl,cpm-brg = <1>; - fsl,cpm-command = <0x800000>; - }; - - serial1: serial@11a20 { - device_type = "serial"; - compatible = "fsl,mpc8280-scc-uart", - "fsl,cpm2-scc-uart"; - reg = <0x11a20 0x20 0x8100 0x100>; - interrupts = <41 8>; - interrupt-parent = <&PIC>; - fsl,cpm-brg = <2>; - fsl,cpm-command = <0x4a00000>; - }; - - enet0: ethernet@11320 { - device_type = "network"; - compatible = "fsl,mpc8280-fcc-enet", - "fsl,cpm2-fcc-enet"; - reg = <0x11320 0x20 0x8500 0x100 0x113b0 0x1>; - interrupts = <33 8>; - interrupt-parent = <&PIC>; - phy-handle = <&PHY0>; - linux,network-index = <0>; - fsl,cpm-command = <0x16200300>; - }; - - enet1: ethernet@11340 { - device_type = "network"; - compatible = "fsl,mpc8280-fcc-enet", - "fsl,cpm2-fcc-enet"; - reg = <0x11340 0x20 0x8600 0x100 0x113d0 0x1>; - interrupts = <34 8>; - interrupt-parent = <&PIC>; - phy-handle = <&PHY1>; - linux,network-index = <1>; - fsl,cpm-command = <0x1a400300>; - local-mac-address = [00 e0 0c 00 79 01]; - }; - - mdio@10d40 { - compatible = "fsl,pq2fads-mdio-bitbang", - "fsl,mpc8280-mdio-bitbang", - "fsl,cpm2-mdio-bitbang"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x10d40 0x14>; - fsl,mdio-pin = <9>; - fsl,mdc-pin = <10>; - - PHY0: ethernet-phy@0 { - interrupt-parent = <&PIC>; - interrupts = <25 2>; - reg = <0x0>; - }; - - PHY1: ethernet-phy@1 { - interrupt-parent = <&PIC>; - interrupts = <25 2>; - reg = <0x3>; - }; - }; - - usb@11b60 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,mpc8280-usb", - "fsl,cpm2-usb"; - reg = <0x11b60 0x18 0x8b00 0x100>; - interrupt-parent = <&PIC>; - interrupts = <11 8>; - fsl,cpm-command = <0x2e600000>; - }; - }; - - PIC: interrupt-controller@10c00 { - #interrupt-cells = <2>; - interrupt-controller; - reg = <0x10c00 0x80>; - compatible = "fsl,mpc8280-pic", "fsl,cpm2-pic"; - }; - - }; - - chosen { - stdout-path = "/soc/cpm/serial@11a00"; - }; -}; diff --git a/arch/powerpc/boot/dts/turris1x.dts b/arch/powerpc/boot/dts/turris1x.dts index c9b619f6ed5c..6612160c19d5 100644 --- a/arch/powerpc/boot/dts/turris1x.dts +++ b/arch/powerpc/boot/dts/turris1x.dts @@ -15,7 +15,7 @@ / { model = "Turris 1.x"; - compatible = "cznic,turris1x", "fsl,P2020RDB-PC"; /* fsl,P2020RDB-PC is required for booting Linux */ + compatible = "cznic,turris1x"; aliases { ethernet0 = &enet0; diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig deleted file mode 100644 index e94555452fb2..000000000000 --- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig +++ /dev/null @@ -1,59 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_KALLSYMS is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_83xx=y -CONFIG_MPC832x_MDS=y -CONFIG_MATH_EMULATION=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -# CONFIG_IPV6 is not set -# CONFIG_FW_LOADER is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_SCSI=y -CONFIG_NETDEVICES=y -CONFIG_UCC_GETH=y -CONFIG_DAVICOM_PHY=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MPC=y -CONFIG_WATCHDOG=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1374=y -CONFIG_QUICC_ENGINE=y -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig deleted file mode 100644 index e2ff684d8792..000000000000 --- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig +++ /dev/null @@ -1,58 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_KALLSYMS is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_83xx=y -CONFIG_MPC834x_MDS=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -# CONFIG_IPV6 is not set -# CONFIG_FW_LOADER is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_NETDEVICES=y -CONFIG_GIANFAR=y -CONFIG_E100=y -CONFIG_MARVELL_PHY=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MPC=y -CONFIG_WATCHDOG=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1374=y -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig deleted file mode 100644 index 3eceb6db2982..000000000000 --- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig +++ /dev/null @@ -1,64 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_KALLSYMS is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_83xx=y -CONFIG_MPC836x_MDS=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -# CONFIG_IPV6 is not set -# CONFIG_FW_LOADER is not set -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_SCSI=y -CONFIG_NETDEVICES=y -CONFIG_UCC_GETH=y -CONFIG_MARVELL_PHY=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MPC=y -CONFIG_WATCHDOG=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1374=y -CONFIG_QUICC_ENGINE=y -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig deleted file mode 100644 index 3f5e5d10789f..000000000000 --- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig +++ /dev/null @@ -1,58 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_83xx=y -CONFIG_MPC837x_MDS=y -CONFIG_GEN_RTC=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -# CONFIG_IPV6 is not set -# CONFIG_FW_LOADER is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_SG=y -CONFIG_ATA=y -CONFIG_SATA_FSL=y -CONFIG_NETDEVICES=y -CONFIG_GIANFAR=y -CONFIG_MARVELL_PHY=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MPC=y -CONFIG_WATCHDOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_CRC_T10DIF=y -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig index ea719898b581..6cb7e90d52c1 100644 --- a/arch/powerpc/configs/85xx/ge_imp3a_defconfig +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -30,7 +30,7 @@ CONFIG_PREEMPT=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y -CONFIG_ARCH_FORCE_MAX_ORDER=17 +CONFIG_ARCH_FORCE_MAX_ORDER=16 CONFIG_PCI=y CONFIG_PCIEPORTBUS=y CONFIG_PCI_MSI=y diff --git a/arch/powerpc/configs/corenet_base.config b/arch/powerpc/configs/corenet_base.config index b568d465e59e..1c40de1e764b 100644 --- a/arch/powerpc/configs/corenet_base.config +++ b/arch/powerpc/configs/corenet_base.config @@ -1 +1,2 @@ CONFIG_CORENET_GENERIC=y +CONFIG_PPC_QEMU_E500=y diff --git a/arch/powerpc/configs/fsl-emb-nonhw.config b/arch/powerpc/configs/fsl-emb-nonhw.config index ab8a8c4530d9..3009b0efaf34 100644 --- a/arch/powerpc/configs/fsl-emb-nonhw.config +++ b/arch/powerpc/configs/fsl-emb-nonhw.config @@ -41,7 +41,7 @@ CONFIG_FIXED_PHY=y CONFIG_FONT_8x16=y CONFIG_FONT_8x8=y CONFIG_FONTS=y -CONFIG_ARCH_FORCE_MAX_ORDER=13 +CONFIG_ARCH_FORCE_MAX_ORDER=12 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAME_WARN=1024 CONFIG_FTL=y diff --git a/arch/powerpc/configs/guest.config b/arch/powerpc/configs/guest.config index 209f58515d88..fece83487215 100644 --- a/arch/powerpc/configs/guest.config +++ b/arch/powerpc/configs/guest.config @@ -10,3 +10,5 @@ CONFIG_EPAPR_PARAVIRT=y CONFIG_VIRTIO_BALLOON=y CONFIG_VHOST_NET=y CONFIG_VHOST=y +CONFIG_IBMVETH=y +CONFIG_IBMVNIC=y diff --git a/arch/powerpc/configs/kvm_guest.config b/arch/powerpc/configs/kvm_guest.config new file mode 120000 index 000000000000..a5f7a2fa74ef --- /dev/null +++ b/arch/powerpc/configs/kvm_guest.config @@ -0,0 +1 @@ +../../../kernel/configs/kvm_guest.config \ No newline at end of file diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig deleted file mode 100644 index 19406a6c2648..000000000000 --- a/arch/powerpc/configs/mpc7448_hpc2_defconfig +++ /dev/null @@ -1,54 +0,0 @@ -CONFIG_ALTIVEC=y -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_EMBEDDED6xx=y -CONFIG_MPC7448HPC2=y -CONFIG_GEN_RTC=y -CONFIG_BINFMT_MISC=y -# CONFIG_SECCOMP is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -# CONFIG_IPV6 is not set -# CONFIG_FW_LOADER is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_BLK_DEV_SD=y -CONFIG_ATA=y -CONFIG_SATA_MV=y -CONFIG_NETDEVICES=y -CONFIG_E100=y -CONFIG_8139TOO=y -# CONFIG_8139TOO_PIO is not set -CONFIG_TSI108_ETH=y -CONFIG_PHYLIB=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_CRC_T10DIF=y diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig deleted file mode 100644 index 4145ef5689ca..000000000000 --- a/arch/powerpc/configs/mpc8272_ads_defconfig +++ /dev/null @@ -1,79 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_82xx=y -CONFIG_MPC8272_ADS=y -CONFIG_BINFMT_MISC=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -CONFIG_NETFILTER=y -# CONFIG_FW_LOADER is not set -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_GEOMETRY=y -# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set -# CONFIG_MTD_CFI_I1 is not set -# CONFIG_MTD_CFI_I2 is not set -CONFIG_MTD_CFI_I4=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_NETDEVICES=y -CONFIG_TUN=y -CONFIG_FS_ENET=y -# CONFIG_FS_ENET_HAS_SCC is not set -CONFIG_FS_ENET_MDIO_FCC=y -CONFIG_DAVICOM_PHY=y -CONFIG_PPP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_INPUT_EVDEV=y -# CONFIG_VT is not set -CONFIG_SERIAL_CPM=y -CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_HWMON is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_AUTOFS4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_ROOT_NFS=y -CONFIG_NLS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_BDI_SWITCH=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index 95d43f8a3869..8779f03bced1 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -11,13 +11,9 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC831x_RDB=y -CONFIG_MPC832x_MDS=y CONFIG_MPC832x_RDB=y -CONFIG_MPC834x_MDS=y CONFIG_MPC834x_ITX=y -CONFIG_MPC836x_MDS=y CONFIG_MPC836x_RDK=y -CONFIG_MPC837x_MDS=y CONFIG_MPC837x_RDB=y CONFIG_ASP834x=y CONFIG_QE_GPIO=y diff --git a/arch/powerpc/configs/mpc86xx_base.config b/arch/powerpc/configs/mpc86xx_base.config index 588870e6af3b..632c014b122d 100644 --- a/arch/powerpc/configs/mpc86xx_base.config +++ b/arch/powerpc/configs/mpc86xx_base.config @@ -1,6 +1,4 @@ CONFIG_PPC_86xx=y -CONFIG_MPC8641_HPCN=y -CONFIG_MPC8610_HPCD=y CONFIG_GEF_PPC9A=y CONFIG_GEF_SBC310=y CONFIG_GEF_SBC610=y diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig index f2a9be02a8d2..e02ab94a09bf 100644 --- a/arch/powerpc/configs/powernv_defconfig +++ b/arch/powerpc/configs/powernv_defconfig @@ -170,6 +170,7 @@ CONFIG_S2IO=m CONFIG_E100=y CONFIG_E1000=y CONFIG_E1000E=y +CONFIG_IGB=y CONFIG_IXGBE=m CONFIG_I40E=m CONFIG_MLX4_EN=m diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 6c46e5560d96..268fa361a06d 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -1,35 +1,48 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ_FULL=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_BPF_LSM=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_LOG_CPU_MAX_BUF_SHIFT=13 CONFIG_NUMA_BALANCING=y -CONFIG_CGROUPS=y CONFIG_MEMCG=y -CONFIG_CGROUP_SCHED=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y CONFIG_CPUSETS=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y -CONFIG_BPF_SYSCALL=y -# CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_PPC64=y CONFIG_NR_CPUS=2048 -CONFIG_PPC_SPLPAR=y CONFIG_DTL=y CONFIG_PPC_SMLPAR=y CONFIG_IBMEBUS=y +CONFIG_PAPR_SCM=m CONFIG_PPC_SVM=y CONFIG_PPC_MAPLE=y CONFIG_PPC_PASEMI=y @@ -54,27 +67,32 @@ CONFIG_CRASH_DUMP=y CONFIG_FA_DUMP=y CONFIG_IRQ_ALL_CPUS=y CONFIG_SCHED_SMT=y -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_RPA=m -CONFIG_HOTPLUG_PCI_RPA_DLPAR=m -CONFIG_PCCARD=y -CONFIG_ELECTRA_CF=y +CONFIG_PPC_SECURE_BOOT=y CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m -CONFIG_VHOST_NET=m CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y +CONFIG_Z3FOLD=y +CONFIG_ZSMALLOC=y +# CONFIG_SLAB_MERGE_DEFAULT is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_SHUFFLE_PAGE_ALLOCATOR=y +# CONFIG_COMPAT_BRK is not set CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_ZONE_DEVICE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -90,23 +108,29 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m -CONFIG_IPV6=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m CONFIG_NET_SCHED=y CONFIG_NET_CLS_BPF=m CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_BPF=m -CONFIG_BPF_JIT=y +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_RPA=m +CONFIG_HOTPLUG_PCI_RPA_DLPAR=m +CONFIG_PCCARD=y +CONFIG_ELECTRA_CF=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_BLK_DEV_FD=y +CONFIG_ZRAM=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=65536 CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_NVME=m CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=y @@ -143,18 +167,30 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m CONFIG_MD_MULTIPATH=m CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y +CONFIG_DM_UNSTRIPED=m CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_EBS=m +CONFIG_DM_ERA=m +CONFIG_DM_CLONE=m CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m CONFIG_DM_ZERO=m CONFIG_DM_MULTIPATH=m CONFIG_DM_MULTIPATH_QL=m CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_MULTIPATH_HST=m +CONFIG_DM_MULTIPATH_IOA=m +CONFIG_DM_DELAY=m +CONFIG_DM_DUST=m +CONFIG_DM_INIT=y CONFIG_DM_UEVENT=y CONFIG_ADB_PMU=y CONFIG_PMAC_SMU=y @@ -266,9 +302,9 @@ CONFIG_LEDS_POWERNV=m CONFIG_INFINIBAND=m CONFIG_INFINIBAND_USER_MAD=m CONFIG_INFINIBAND_USER_ACCESS=m -CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_CXGB4=m CONFIG_MLX4_INFINIBAND=m +CONFIG_INFINIBAND_MTHCA=m CONFIG_INFINIBAND_IPOIB=m CONFIG_INFINIBAND_IPOIB_CM=y CONFIG_INFINIBAND_SRP=m @@ -279,22 +315,12 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_VIRTIO_PCI=m CONFIG_VIRTIO_BALLOON=m -CONFIG_LIBNVDIMM=y +CONFIG_VHOST_NET=m CONFIG_RAS=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y +CONFIG_LIBNVDIMM=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y -CONFIG_REISERFS_FS=m -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y CONFIG_XFS_FS=y CONFIG_XFS_POSIX_ACL=y CONFIG_BTRFS_FS=m @@ -319,6 +345,7 @@ CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y +CONFIG_PSTORE=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y @@ -334,42 +361,110 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_YAMA=y +CONFIG_SECURITY_LOCKDOWN_LSM=y +CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_INTEGRITY_SIGNATURE=y +CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y +CONFIG_INTEGRITY_PLATFORM_KEYRING=y +CONFIG_IMA=y +CONFIG_IMA_KEXEC=y +CONFIG_IMA_DEFAULT_HASH_SHA256=y +CONFIG_IMA_WRITE_POLICY=y +CONFIG_IMA_APPRAISE=y +CONFIG_IMA_ARCH_POLICY=y +CONFIG_IMA_APPRAISE_MODSIG=y CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_CRC32C_VPMSUM=m -CONFIG_CRYPTO_MD5_PPC=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA1_PPC=m -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_CRC32C_VPMSUM=m +CONFIG_CRYPTO_MD5_PPC=m +CONFIG_CRYPTO_SHA1_PPC=m CONFIG_CRYPTO_DEV_NX=y CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_CRYPTO_DEV_VMX=y +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_BLACKLIST_KEYRING=y CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CALLER=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_RODATA_TEST=y +CONFIG_DEBUG_WX=y CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_VM=y +# CONFIG_DEBUG_VM_PGTABLE is not set CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_SOFTLOCKUP_DETECTOR=y CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_SCHEDSTATS=y CONFIG_DEBUG_MUTEXES=y CONFIG_FUNCTION_TRACER=y -CONFIG_FTRACE_SYSCALLS=y -CONFIG_SCHED_TRACER=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_STACK_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_FTRACE_SYSCALLS=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_IO_STRICT_DEVMEM=y +CONFIG_PPC_EMULATED_STATS=y CONFIG_CODE_PATCHING_SELFTEST=y CONFIG_FTR_FIXUP_SELFTEST=y CONFIG_MSI_BITMAP_SELFTEST=y CONFIG_XMON=y CONFIG_BOOTX_TEXT=y +CONFIG_KUNIT=m +CONFIG_KUNIT_ALL_TESTS=m +CONFIG_LKDTM=m +CONFIG_TEST_MIN_HEAP=m +CONFIG_TEST_DIV64=m +CONFIG_BACKTRACE_SELF_TEST=m +CONFIG_TEST_REF_TRACKER=m +CONFIG_RBTREE_TEST=m +CONFIG_REED_SOLOMON_TEST=m +CONFIG_INTERVAL_TREE_TEST=m +CONFIG_PERCPU_TEST=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_ASYNC_RAID6_TEST=m +CONFIG_TEST_HEXDUMP=m +CONFIG_STRING_SELFTEST=m +CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_PRINTF=m +CONFIG_TEST_SCANF=m +CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m +CONFIG_TEST_XARRAY=m +CONFIG_TEST_MAPLE_TREE=m +CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_IDA=m +CONFIG_TEST_BITOPS=m +CONFIG_TEST_VMALLOC=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m +CONFIG_FIND_BIT_BENCHMARK=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_SYSCTL=m +CONFIG_LINEAR_RANGES_TEST=m +CONFIG_TEST_UDELAY=m +CONFIG_TEST_STATIC_KEYS=m +CONFIG_TEST_KMOD=m +CONFIG_TEST_MEMCAT_P=m +CONFIG_TEST_MEMINIT=m +CONFIG_TEST_FREE_PAGES=m +CONFIG_MEMTEST=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 5927b2312936..f21170b8fa11 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -38,24 +38,16 @@ CONFIG_PPC_MPC52xx=y CONFIG_PPC_EFIKA=y CONFIG_PPC_MPC5200_BUGFIX=y CONFIG_PPC_82xx=y -CONFIG_MPC8272_ADS=y -CONFIG_PQ2FADS=y CONFIG_EP8248E=y CONFIG_MGCOGE=y CONFIG_PPC_83xx=y CONFIG_MPC831x_RDB=y -CONFIG_MPC832x_MDS=y CONFIG_MPC832x_RDB=y -CONFIG_MPC834x_MDS=y CONFIG_MPC834x_ITX=y -CONFIG_MPC836x_MDS=y CONFIG_MPC836x_RDK=y -CONFIG_MPC837x_MDS=y CONFIG_MPC837x_RDB=y CONFIG_ASP834x=y CONFIG_PPC_86xx=y -CONFIG_MPC8641_HPCN=y -CONFIG_MPC8610_HPCD=y CONFIG_GEF_SBC610=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y @@ -614,8 +606,6 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=m CONFIG_NVRAM=y CONFIG_DTLK=m -CONFIG_CARDMAN_4000=m -CONFIG_CARDMAN_4040=m CONFIG_IPWIRELESS=m CONFIG_I2C_CHARDEV=m CONFIG_I2C_HYDRA=m @@ -845,7 +835,6 @@ CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_OHCI_HCD_PPC_OF_LE=y CONFIG_USB_UHCI_HCD=m -CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m @@ -908,7 +897,6 @@ CONFIG_USB_SEVSEG=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m CONFIG_USB_SISUSBVGA=m CONFIG_USB_LD=m diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig deleted file mode 100644 index 9d63e2e65211..000000000000 --- a/arch/powerpc/configs/pq2fads_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_KALLSYMS_ALL=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_PPC_CHRP is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_82xx=y -CONFIG_PQ2FADS=y -CONFIG_BINFMT_MISC=y -CONFIG_PCI=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_SYN_COOKIES=y -CONFIG_NETFILTER=y -# CONFIG_FW_LOADER is not set -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_GEOMETRY=y -# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set -# CONFIG_MTD_CFI_I1 is not set -# CONFIG_MTD_CFI_I2 is not set -CONFIG_MTD_CFI_I4=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_NETDEVICES=y -CONFIG_TUN=y -CONFIG_FS_ENET=y -# CONFIG_FS_ENET_HAS_SCC is not set -CONFIG_FS_ENET_MDIO_FCC=y -CONFIG_DAVICOM_PHY=y -CONFIG_PPP=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_INPUT_EVDEV=y -# CONFIG_VT is not set -CONFIG_SERIAL_CPM=y -CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_HWMON is not set -CONFIG_USB_GADGET=y -CONFIG_USB_ETH=y -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_AUTOFS4_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DETECT_HUNG_TASK=y -# CONFIG_SCHED_DEBUG is not set -CONFIG_BDI_SWITCH=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_PCBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig deleted file mode 100644 index 49b3ff4e3b18..000000000000 --- a/arch/powerpc/configs/pseries_defconfig +++ /dev/null @@ -1,322 +0,0 @@ -CONFIG_PPC64=y -CONFIG_NR_CPUS=2048 -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_AUDIT=y -# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_VIRT_CPU_ACCOUNTING_GEN=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_LOG_CPU_MAX_BUF_SHIFT=13 -CONFIG_NUMA_BALANCING=y -CONFIG_CGROUPS=y -CONFIG_MEMCG=y -CONFIG_CGROUP_SCHED=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_PERF=y -CONFIG_CGROUP_BPF=y -CONFIG_USER_NS=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_BPF_SYSCALL=y -# CONFIG_COMPAT_BRK is not set -CONFIG_PROFILING=y -CONFIG_KPROBES=y -CONFIG_JUMP_LABEL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_PPC_SPLPAR=y -CONFIG_DTL=y -CONFIG_PPC_SMLPAR=y -CONFIG_IBMEBUS=y -CONFIG_LIBNVDIMM=m -CONFIG_PAPR_SCM=m -CONFIG_PPC_SVM=y -# CONFIG_PPC_PMAC is not set -CONFIG_RTAS_FLASH=m -CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y -CONFIG_HZ_100=y -CONFIG_BINFMT_MISC=m -CONFIG_PPC_TRANSACTIONAL_MEM=y -CONFIG_KEXEC=y -CONFIG_KEXEC_FILE=y -CONFIG_IRQ_ALL_CPUS=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTREMOVE=y -CONFIG_KSM=y -CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_SCHED_SMT=y -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_RPA=m -CONFIG_HOTPLUG_PCI_RPA_DLPAR=m -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_NET_IPIP=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_ADVANCED is not set -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_NET_SCHED=y -CONFIG_NET_CLS_BPF=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_BPF=m -CONFIG_BPF_JIT=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_BLK_DEV_FD=m -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=65536 -CONFIG_VIRTIO_BLK=m -CONFIG_BLK_DEV_NVME=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_FC_ATTRS=y -CONFIG_SCSI_CXGB3_ISCSI=m -CONFIG_SCSI_CXGB4_ISCSI=m -CONFIG_SCSI_BNX2_ISCSI=m -CONFIG_BE2ISCSI=m -CONFIG_SCSI_MPT2SAS=m -CONFIG_SCSI_IBMVSCSI=y -CONFIG_SCSI_IBMVFC=m -CONFIG_SCSI_SYM53C8XX_2=m -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 -CONFIG_SCSI_IPR=y -CONFIG_SCSI_QLA_FC=m -CONFIG_SCSI_QLA_ISCSI=m -CONFIG_SCSI_LPFC=m -CONFIG_SCSI_VIRTIO=m -CONFIG_SCSI_DH=y -CONFIG_SCSI_DH_RDAC=m -CONFIG_SCSI_DH_ALUA=m -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_PATA_AMD=y -CONFIG_ATA_GENERIC=y -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m -CONFIG_MD_MULTIPATH=m -CONFIG_MD_FAULTY=m -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_THIN_PROVISIONING=m -CONFIG_DM_MIRROR=m -CONFIG_DM_ZERO=m -CONFIG_DM_MULTIPATH=m -CONFIG_DM_MULTIPATH_QL=m -CONFIG_DM_MULTIPATH_ST=m -CONFIG_DM_UEVENT=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m -CONFIG_VXLAN=m -CONFIG_NETCONSOLE=y -CONFIG_TUN=m -CONFIG_VETH=m -CONFIG_VIRTIO_NET=m -CONFIG_VORTEX=m -CONFIG_ACENIC=m -CONFIG_ACENIC_OMIT_TIGON_I=y -CONFIG_PCNET32=m -CONFIG_TIGON3=y -CONFIG_BNX2X=m -CONFIG_CHELSIO_T1=m -CONFIG_BE2NET=m -CONFIG_S2IO=m -CONFIG_IBMVETH=y -CONFIG_EHEA=y -CONFIG_IBMVNIC=y -CONFIG_E100=y -CONFIG_E1000=y -CONFIG_E1000E=y -CONFIG_IXGBE=m -CONFIG_I40E=m -CONFIG_MLX4_EN=m -CONFIG_MYRI10GE=m -CONFIG_NETXEN_NIC=m -CONFIG_PPP=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPPOE=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_INPUT_EVDEV=m -CONFIG_INPUT_MISC=y -CONFIG_INPUT_PCSPKR=m -# CONFIG_SERIO_SERPORT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_ICOM=m -CONFIG_SERIAL_JSM=m -CONFIG_HVC_CONSOLE=y -CONFIG_HVC_RTAS=y -CONFIG_HVCS=m -CONFIG_VIRTIO_CONSOLE=m -CONFIG_IBM_BSR=m -CONFIG_I2C_CHARDEV=y -CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_OF=y -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -CONFIG_FB_RADEON=y -CONFIG_FB_IBM_GXT4500=y -CONFIG_LCD_PLATFORM=m -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_LOGO=y -CONFIG_HID_GYRATION=y -CONFIG_HID_PANTHERLORD=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SUNPLUS=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_MON=m -CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_HCD_PPC_OF is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_STORAGE=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=m -CONFIG_LEDS_POWERNV=m -CONFIG_INFINIBAND=m -CONFIG_INFINIBAND_USER_MAD=m -CONFIG_INFINIBAND_USER_ACCESS=m -CONFIG_INFINIBAND_MTHCA=m -CONFIG_INFINIBAND_CXGB4=m -CONFIG_MLX4_INFINIBAND=m -CONFIG_INFINIBAND_IPOIB=m -CONFIG_INFINIBAND_IPOIB_CM=y -CONFIG_INFINIBAND_SRP=m -CONFIG_INFINIBAND_ISER=m -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_GENERIC=y -CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_BALLOON=m -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y -CONFIG_XFS_FS=m -CONFIG_XFS_POSIX_ACL=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_NILFS2_FS=m -CONFIG_FS_DAX=y -CONFIG_AUTOFS4_FS=m -CONFIG_FUSE_FS=m -CONFIG_OVERLAY_FS=m -CONFIG_ISO9660_FS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=m -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_HUGETLBFS=y -CONFIG_CRAMFS=m -CONFIG_SQUASHFS=m -CONFIG_SQUASHFS_XATTR=y -CONFIG_SQUASHFS_LZO=y -CONFIG_SQUASHFS_XZ=y -CONFIG_PSTORE=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_CIFS=m -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_STACK_USAGE=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_SOFTLOCKUP_DETECTOR=y -CONFIG_HARDLOCKUP_DETECTOR=y -CONFIG_FUNCTION_TRACER=y -CONFIG_FTRACE_SYSCALLS=y -CONFIG_SCHED_TRACER=y -CONFIG_STACK_TRACER=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_CODE_PATCHING_SELFTEST=y -CONFIG_FTR_FIXUP_SELFTEST=y -CONFIG_MSI_BITMAP_SELFTEST=y -CONFIG_XMON=y -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_CRC32C_VPMSUM=m -CONFIG_CRYPTO_MD5_PPC=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA1_PPC=m -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_LZO=m -CONFIG_CRYPTO_DEV_NX=y -CONFIG_CRYPTO_DEV_NX_ENCRYPT=m -CONFIG_CRYPTO_DEV_VMX=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM_BOOK3S_64=m -CONFIG_KVM_BOOK3S_64_HV=m -CONFIG_VHOST_NET=m -CONFIG_PRINTK_TIME=y -CONFIG_PRINTK_CALLER=y diff --git a/arch/powerpc/crypto/Kconfig b/arch/powerpc/crypto/Kconfig index 7113f9355165..ad1872518992 100644 --- a/arch/powerpc/crypto/Kconfig +++ b/arch/powerpc/crypto/Kconfig @@ -96,7 +96,7 @@ config CRYPTO_AES_PPC_SPE config CRYPTO_AES_GCM_P10 tristate "Stitched AES/GCM acceleration support on P10 or later CPU (PPC)" - depends on PPC64 && CPU_LITTLE_ENDIAN + depends on PPC64 && CPU_LITTLE_ENDIAN && VSX select CRYPTO_LIB_AES select CRYPTO_ALGAPI select CRYPTO_AEAD diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile index 05c7486f42c5..7b4f516abec1 100644 --- a/arch/powerpc/crypto/Makefile +++ b/arch/powerpc/crypto/Makefile @@ -22,15 +22,15 @@ sha1-ppc-spe-y := sha1-spe-asm.o sha1-spe-glue.o sha256-ppc-spe-y := sha256-spe-asm.o sha256-spe-glue.o crc32c-vpmsum-y := crc32c-vpmsum_asm.o crc32c-vpmsum_glue.o crct10dif-vpmsum-y := crct10dif-vpmsum_asm.o crct10dif-vpmsum_glue.o -aes-gcm-p10-crypto-y := aes-gcm-p10-glue.o aes-gcm-p10.o ghashp8-ppc.o aesp8-ppc.o +aes-gcm-p10-crypto-y := aes-gcm-p10-glue.o aes-gcm-p10.o ghashp10-ppc.o aesp10-ppc.o quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $< $(if $(CONFIG_CPU_LITTLE_ENDIAN), linux-ppc64le, linux-ppc64) > $@ -targets += aesp8-ppc.S ghashp8-ppc.S +targets += aesp10-ppc.S ghashp10-ppc.S -$(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE +$(obj)/aesp10-ppc.S $(obj)/ghashp10-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE $(call if_changed,perl) -OBJECT_FILES_NON_STANDARD_aesp8-ppc.o := y -OBJECT_FILES_NON_STANDARD_ghashp8-ppc.o := y +OBJECT_FILES_NON_STANDARD_aesp10-ppc.o := y +OBJECT_FILES_NON_STANDARD_ghashp10-ppc.o := y diff --git a/arch/powerpc/crypto/aes-gcm-p10-glue.c b/arch/powerpc/crypto/aes-gcm-p10-glue.c index bd3475f5348d..4b6e899895e7 100644 --- a/arch/powerpc/crypto/aes-gcm-p10-glue.c +++ b/arch/powerpc/crypto/aes-gcm-p10-glue.c @@ -30,15 +30,15 @@ MODULE_AUTHOR("Danny Tsen aadLen = alen; i = alen & ~0xf; if (i) { - gcm_ghash_p8(nXi, hash->Htable+32, aad, i); + gcm_ghash_p10(nXi, hash->Htable+32, aad, i); aad += i; alen -= i; } @@ -102,7 +102,7 @@ static void set_aad(struct gcm_ctx *gctx, struct Hash_ctx *hash, nXi[i] ^= aad[i]; memset(gctx->aad_hash, 0, 16); - gcm_ghash_p8(gctx->aad_hash, hash->Htable+32, nXi, 16); + gcm_ghash_p10(gctx->aad_hash, hash->Htable+32, nXi, 16); } else { memcpy(gctx->aad_hash, nXi, 16); } @@ -115,7 +115,7 @@ static void gcmp10_init(struct gcm_ctx *gctx, u8 *iv, unsigned char *rdkey, { __be32 counter = cpu_to_be32(1); - aes_p8_encrypt(hash->H, hash->H, rdkey); + aes_p10_encrypt(hash->H, hash->H, rdkey); set_subkey(hash->H); gcm_init_htable(hash->Htable+32, hash->H); @@ -126,7 +126,7 @@ static void gcmp10_init(struct gcm_ctx *gctx, u8 *iv, unsigned char *rdkey, /* * Encrypt counter vector as iv tag and increment counter. */ - aes_p8_encrypt(iv, gctx->ivtag, rdkey); + aes_p10_encrypt(iv, gctx->ivtag, rdkey); counter = cpu_to_be32(2); *((__be32 *)(iv+12)) = counter; @@ -160,7 +160,7 @@ static void finish_tag(struct gcm_ctx *gctx, struct Hash_ctx *hash, int len) /* * hash (AAD len and len) */ - gcm_ghash_p8(hash->Htable, hash->Htable+32, aclen, 16); + gcm_ghash_p10(hash->Htable, hash->Htable+32, aclen, 16); for (i = 0; i < 16; i++) hash->Htable[i] ^= gctx->ivtag[i]; @@ -192,7 +192,7 @@ static int p10_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key, int ret; vsx_begin(); - ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); + ret = aes_p10_set_encrypt_key(key, keylen * 8, &ctx->enc_key); vsx_end(); return ret ? -EINVAL : 0; diff --git a/arch/powerpc/crypto/aesp8-ppc.pl b/arch/powerpc/crypto/aesp10-ppc.pl similarity index 99% rename from arch/powerpc/crypto/aesp8-ppc.pl rename to arch/powerpc/crypto/aesp10-ppc.pl index 1f22aec27d79..2c06ce2a2c7c 100644 --- a/arch/powerpc/crypto/aesp8-ppc.pl +++ b/arch/powerpc/crypto/aesp10-ppc.pl @@ -110,7 +110,7 @@ die "can't locate ppc-xlate.pl"; open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!"; $FRAME=8*$SIZE_T; -$prefix="aes_p8"; +$prefix="aes_p10"; $sp="r1"; $vrsave="r12"; diff --git a/arch/powerpc/crypto/ghashp8-ppc.pl b/arch/powerpc/crypto/ghashp10-ppc.pl similarity index 97% rename from arch/powerpc/crypto/ghashp8-ppc.pl rename to arch/powerpc/crypto/ghashp10-ppc.pl index b56603b4a893..27a6b0bec645 100644 --- a/arch/powerpc/crypto/ghashp8-ppc.pl +++ b/arch/powerpc/crypto/ghashp10-ppc.pl @@ -64,7 +64,7 @@ $code=<<___; .text -.globl .gcm_init_p8 +.globl .gcm_init_p10 lis r0,0xfff0 li r8,0x10 mfspr $vrsave,256 @@ -110,7 +110,7 @@ $code=<<___; .long 0 .byte 0,12,0x14,0,0,0,2,0 .long 0 -.size .gcm_init_p8,.-.gcm_init_p8 +.size .gcm_init_p10,.-.gcm_init_p10 .globl .gcm_init_htable lis r0,0xfff0 @@ -237,7 +237,7 @@ $code=<<___; .long 0 .size .gcm_init_htable,.-.gcm_init_htable -.globl .gcm_gmult_p8 +.globl .gcm_gmult_p10 lis r0,0xfff8 li r8,0x10 mfspr $vrsave,256 @@ -283,9 +283,9 @@ $code=<<___; .long 0 .byte 0,12,0x14,0,0,0,2,0 .long 0 -.size .gcm_gmult_p8,.-.gcm_gmult_p8 +.size .gcm_gmult_p10,.-.gcm_gmult_p10 -.globl .gcm_ghash_p8 +.globl .gcm_ghash_p10 lis r0,0xfff8 li r8,0x10 mfspr $vrsave,256 @@ -350,7 +350,7 @@ Loop: .long 0 .byte 0,12,0x14,0,0,0,4,0 .long 0 -.size .gcm_ghash_p8,.-.gcm_ghash_p8 +.size .gcm_ghash_p10,.-.gcm_ghash_p10 .asciz "GHASH for PowerISA 2.07, CRYPTOGAMS by " .align 2 diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 486ab7889121..47228b177478 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -27,14 +27,22 @@ static __inline__ int arch_atomic_read(const atomic_t *v) { int t; - __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); + /* -mprefixed can generate offsets beyond range, fall back hack */ + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("lwz %0,0(%1)" : "=r"(t) : "b"(&v->counter)); + else + __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); return t; } static __inline__ void arch_atomic_set(atomic_t *v, int i) { - __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); + /* -mprefixed can generate offsets beyond range, fall back hack */ + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("stw %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter)); + else + __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); } #define ATOMIC_OP(op, asm_op, suffix, sign, ...) \ @@ -130,35 +138,6 @@ ATOMIC_OPS(xor, xor, "", K) #define arch_atomic_xchg_relaxed(v, new) \ arch_xchg_relaxed(&((v)->counter), (new)) -/* - * Don't want to override the generic atomic_try_cmpxchg_acquire, because - * we add a lock hint to the lwarx, which may not be wanted for the - * _acquire case (and is not used by the other _acquire variants so it - * would be a surprise). - */ -static __always_inline bool -arch_atomic_try_cmpxchg_lock(atomic_t *v, int *old, int new) -{ - int r, o = *old; - unsigned int eh = IS_ENABLED(CONFIG_PPC64); - - __asm__ __volatile__ ( -"1: lwarx %0,0,%2,%[eh] # atomic_try_cmpxchg_acquire \n" -" cmpw 0,%0,%3 \n" -" bne- 2f \n" -" stwcx. %4,0,%2 \n" -" bne- 1b \n" -"\t" PPC_ACQUIRE_BARRIER " \n" -"2: \n" - : "=&r" (r), "+m" (v->counter) - : "r" (&v->counter), "r" (o), "r" (new), [eh] "n" (eh) - : "cr0", "memory"); - - if (unlikely(r != o)) - *old = r; - return likely(r == o); -} - /** * atomic_fetch_add_unless - add unless the number is a given value * @v: pointer of type atomic_t @@ -226,14 +205,22 @@ static __inline__ s64 arch_atomic64_read(const atomic64_t *v) { s64 t; - __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); + /* -mprefixed can generate offsets beyond range, fall back hack */ + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("ld %0,0(%1)" : "=r"(t) : "b"(&v->counter)); + else + __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m<>"(v->counter)); return t; } static __inline__ void arch_atomic64_set(atomic64_t *v, s64 i) { - __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); + /* -mprefixed can generate offsets beyond range, fall back hack */ + if (IS_ENABLED(CONFIG_PPC_KERNEL_PREFIXED)) + __asm__ __volatile__("std %1,0(%2)" : "=m"(v->counter) : "r"(i), "b"(&v->counter)); + else + __asm__ __volatile__("std%U0%X0 %1,%0" : "=m<>"(v->counter) : "r"(i)); } #define ATOMIC64_OP(op, asm_op) \ diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush.h b/arch/powerpc/include/asm/book3s/64/tlbflush.h index 5e26c7f2c25a..0d0c1447ecf0 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush.h @@ -121,7 +121,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, #define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma, - unsigned long address) + unsigned long address, + pte_t *ptep) { /* * Book3S 64 does not require spurious fault flushes because the PTE diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h index d0ea0571e79a..dbb50c06f0bf 100644 --- a/arch/powerpc/include/asm/cmpxchg.h +++ b/arch/powerpc/include/asm/cmpxchg.h @@ -229,7 +229,7 @@ __xchg_local(void *ptr, unsigned long x, unsigned int size) return __xchg_u64_local(ptr, x); #endif } - BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg"); + BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local"); return x; } @@ -248,7 +248,7 @@ __xchg_relaxed(void *ptr, unsigned long x, unsigned int size) return __xchg_u64_relaxed(ptr, x); #endif } - BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local"); + BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_relaxed"); return x; } #define arch_xchg_local(ptr,x) \ diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index ed6db13a1d7c..69ae9cf57d50 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -56,6 +56,7 @@ #define FW_FEATURE_FORM2_AFFINITY ASM_CONST(0x0000020000000000) #define FW_FEATURE_ENERGY_SCALE_INFO ASM_CONST(0x0000040000000000) #define FW_FEATURE_WATCHDOG ASM_CONST(0x0000080000000000) +#define FW_FEATURE_PLPKS ASM_CONST(0x0000100000000000) #ifndef __ASSEMBLY__ @@ -77,7 +78,8 @@ enum { FW_FEATURE_DRC_INFO | FW_FEATURE_BLOCK_REMOVE | FW_FEATURE_PAPR_SCM | FW_FEATURE_ULTRAVISOR | FW_FEATURE_RPT_INVALIDATE | FW_FEATURE_FORM2_AFFINITY | - FW_FEATURE_ENERGY_SCALE_INFO | FW_FEATURE_WATCHDOG, + FW_FEATURE_ENERGY_SCALE_INFO | FW_FEATURE_WATCHDOG | + FW_FEATURE_PLPKS, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_ULTRAVISOR, FW_FEATURE_POWERNV_ALWAYS = 0, diff --git a/arch/powerpc/include/asm/idle.h b/arch/powerpc/include/asm/idle.h index accd1f50085a..00f360667391 100644 --- a/arch/powerpc/include/asm/idle.h +++ b/arch/powerpc/include/asm/idle.h @@ -9,17 +9,17 @@ DECLARE_PER_CPU(u64, idle_spurr_cycles); DECLARE_PER_CPU(u64, idle_entry_purr_snap); DECLARE_PER_CPU(u64, idle_entry_spurr_snap); -static inline void snapshot_purr_idle_entry(void) +static __always_inline void snapshot_purr_idle_entry(void) { *this_cpu_ptr(&idle_entry_purr_snap) = mfspr(SPRN_PURR); } -static inline void snapshot_spurr_idle_entry(void) +static __always_inline void snapshot_spurr_idle_entry(void) { *this_cpu_ptr(&idle_entry_spurr_snap) = mfspr(SPRN_SPURR); } -static inline void update_idle_purr_accounting(void) +static __always_inline void update_idle_purr_accounting(void) { u64 wait_cycles; u64 in_purr = *this_cpu_ptr(&idle_entry_purr_snap); @@ -29,7 +29,7 @@ static inline void update_idle_purr_accounting(void) get_lppaca()->wait_state_cycles = cpu_to_be64(wait_cycles); } -static inline void update_idle_spurr_accounting(void) +static __always_inline void update_idle_spurr_accounting(void) { u64 *idle_spurr_cycles_ptr = this_cpu_ptr(&idle_spurr_cycles); u64 in_spurr = *this_cpu_ptr(&idle_entry_spurr_snap); @@ -37,7 +37,7 @@ static inline void update_idle_spurr_accounting(void) *idle_spurr_cycles_ptr += mfspr(SPRN_SPURR) - in_spurr; } -static inline void pseries_idle_prolog(void) +static __always_inline void pseries_idle_prolog(void) { ppc64_runlatch_off(); snapshot_purr_idle_entry(); @@ -49,7 +49,7 @@ static inline void pseries_idle_prolog(void) get_lppaca()->idle = 1; } -static inline void pseries_idle_epilog(void) +static __always_inline void pseries_idle_epilog(void) { update_idle_purr_accounting(); update_idle_spurr_accounting(); diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index fc112a91d0c2..f1e657c9bbe8 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -97,6 +97,42 @@ extern bool isa_io_special; * */ +/* -mprefixed can generate offsets beyond range, fall back hack */ +#ifdef CONFIG_PPC_KERNEL_PREFIXED +#define DEF_MMIO_IN_X(name, size, insn) \ +static inline u##size name(const volatile u##size __iomem *addr) \ +{ \ + u##size ret; \ + __asm__ __volatile__("sync;"#insn" %0,0,%1;twi 0,%0,0;isync" \ + : "=r" (ret) : "r" (addr) : "memory"); \ + return ret; \ +} + +#define DEF_MMIO_OUT_X(name, size, insn) \ +static inline void name(volatile u##size __iomem *addr, u##size val) \ +{ \ + __asm__ __volatile__("sync;"#insn" %1,0,%0" \ + : : "r" (addr), "r" (val) : "memory"); \ + mmiowb_set_pending(); \ +} + +#define DEF_MMIO_IN_D(name, size, insn) \ +static inline u##size name(const volatile u##size __iomem *addr) \ +{ \ + u##size ret; \ + __asm__ __volatile__("sync;"#insn" %0,0(%1);twi 0,%0,0;isync"\ + : "=r" (ret) : "b" (addr) : "memory"); \ + return ret; \ +} + +#define DEF_MMIO_OUT_D(name, size, insn) \ +static inline void name(volatile u##size __iomem *addr, u##size val) \ +{ \ + __asm__ __volatile__("sync;"#insn" %1,0(%0)" \ + : : "b" (addr), "r" (val) : "memory"); \ + mmiowb_set_pending(); \ +} +#else #define DEF_MMIO_IN_X(name, size, insn) \ static inline u##size name(const volatile u##size __iomem *addr) \ { \ @@ -130,6 +166,7 @@ static inline void name(volatile u##size __iomem *addr, u##size val) \ : "=m<>" (*addr) : "r" (val) : "memory"); \ mmiowb_set_pending(); \ } +#endif DEF_MMIO_IN_D(in_8, 8, lbz); DEF_MMIO_OUT_D(out_8, 8, stb); diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 7e29c73e3dd4..34e14dfd8e04 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -175,7 +175,7 @@ struct iommu_table_group_ops { long (*unset_window)(struct iommu_table_group *table_group, int num); /* Switch ownership from platform code to external user (e.g. VFIO) */ - void (*take_ownership)(struct iommu_table_group *table_group); + long (*take_ownership)(struct iommu_table_group *table_group); /* Switch ownership from external user (e.g. VFIO) back to core */ void (*release_ownership)(struct iommu_table_group *table_group); }; @@ -205,7 +205,6 @@ extern void iommu_register_group(struct iommu_table_group *table_group, int pci_domain_number, unsigned long pe_num); extern int iommu_add_device(struct iommu_table_group *table_group, struct device *dev); -extern void iommu_del_device(struct device *dev); extern long iommu_tce_xchg(struct mm_struct *mm, struct iommu_table *tbl, unsigned long entry, unsigned long *hpa, enum dma_data_direction *direction); @@ -215,6 +214,8 @@ extern long iommu_tce_xchg_no_kill(struct mm_struct *mm, enum dma_data_direction *direction); extern void iommu_tce_kill(struct iommu_table *tbl, unsigned long entry, unsigned long pages); + +extern struct iommu_table_group_ops spapr_tce_table_group_ops; #else static inline void iommu_register_group(struct iommu_table_group *table_group, int pci_domain_number, @@ -227,10 +228,6 @@ static inline int iommu_add_device(struct iommu_table_group *table_group, { return 0; } - -static inline void iommu_del_device(struct device *dev) -{ -} #endif /* !CONFIG_IOMMU_API */ u64 dma_iommu_get_required_mask(struct device *dev); @@ -303,8 +300,6 @@ extern int iommu_tce_check_gpa(unsigned long page_shift, iommu_tce_check_gpa((tbl)->it_page_shift, (gpa))) extern void iommu_flush_tce(struct iommu_table *tbl); -extern int iommu_take_ownership(struct iommu_table *tbl); -extern void iommu_release_ownership(struct iommu_table *tbl); extern enum dma_data_direction iommu_tce_direction(unsigned long tce); extern unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir); diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 959f566a455c..14ee0dece853 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -758,7 +758,7 @@ struct kvm_vcpu_arch { u8 prodded; u8 doorbell_request; u8 irq_pending; /* Used by XIVE to signal pending guest irqs */ - u32 last_inst; + unsigned long last_inst; struct rcuwait wait; struct rcuwait *waitp; @@ -818,7 +818,7 @@ struct kvm_vcpu_arch { u64 busy_stolen; u64 busy_preempt; - u32 emul_inst; + u64 emul_inst; u32 online; diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 6bef23d6d0e3..79a9c0bb8bba 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -28,6 +28,7 @@ #include #include #endif +#include /* * KVMPPC_INST_SW_BREAKPOINT is debug Instruction @@ -84,7 +85,8 @@ extern int kvmppc_handle_vsx_store(struct kvm_vcpu *vcpu, int is_default_endian); extern int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *inst); + enum instruction_fetch_type type, + unsigned long *inst); extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); @@ -126,25 +128,34 @@ extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu); extern int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu); extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu); -extern void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong flags); + +extern void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, + ulong srr1_flags); extern void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu); -extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags); -extern void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu); -extern void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu); -extern void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu); +extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, + ulong srr1_flags); +extern void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu, + ulong srr1_flags); +extern void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu, + ulong srr1_flags); +extern void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu, + ulong srr1_flags); extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu); extern void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu); extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq); extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu); -extern void kvmppc_core_queue_dtlb_miss(struct kvm_vcpu *vcpu, ulong dear_flags, +extern void kvmppc_core_queue_dtlb_miss(struct kvm_vcpu *vcpu, + ulong dear_flags, ulong esr_flags); extern void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, - ulong dear_flags, - ulong esr_flags); + ulong srr1_flags, + ulong dar, + ulong dsisr); extern void kvmppc_core_queue_itlb_miss(struct kvm_vcpu *vcpu); extern void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, - ulong esr_flags); + ulong srr1_flags); + extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu); extern int kvmppc_core_check_requests(struct kvm_vcpu *vcpu); @@ -156,7 +167,7 @@ extern void kvmppc_map_magic(struct kvm_vcpu *vcpu); extern int kvmppc_allocate_hpt(struct kvm_hpt_info *info, u32 order); extern void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info); -extern long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order); +extern int kvmppc_alloc_reset_hpt(struct kvm *kvm, int order); extern void kvmppc_free_hpt(struct kvm_hpt_info *info); extern void kvmppc_rmap_reset(struct kvm *kvm); extern void kvmppc_map_vrma(struct kvm_vcpu *vcpu, @@ -170,7 +181,7 @@ extern int kvmppc_switch_mmu_to_hpt(struct kvm *kvm); extern int kvmppc_switch_mmu_to_radix(struct kvm *kvm); extern void kvmppc_setup_partition_table(struct kvm *kvm); -extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, +extern int kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, struct kvm_create_spapr_tce_64 *args); #define kvmppc_ioba_validate(stt, ioba, npages) \ (iommu_tce_check_ioba((stt)->page_shift, (stt)->offset, \ @@ -211,10 +222,10 @@ extern void kvmppc_bookehv_exit(void); extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu); extern int kvm_vm_ioctl_get_htab_fd(struct kvm *kvm, struct kvm_get_htab_fd *); -extern long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, - struct kvm_ppc_resize_hpt *rhpt); -extern long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, +extern int kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, struct kvm_ppc_resize_hpt *rhpt); +extern int kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, + struct kvm_ppc_resize_hpt *rhpt); int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq); @@ -286,8 +297,8 @@ struct kvmppc_ops { int (*emulate_mtspr)(struct kvm_vcpu *vcpu, int sprn, ulong spr_val); int (*emulate_mfspr)(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val); void (*fast_vcpu_kick)(struct kvm_vcpu *vcpu); - long (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl, - unsigned long arg); + int (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl, + unsigned long arg); int (*hcall_implemented)(unsigned long hcall); int (*irq_bypass_add_producer)(struct irq_bypass_consumer *, struct irq_bypass_producer *); @@ -315,7 +326,7 @@ extern struct kvmppc_ops *kvmppc_hv_ops; extern struct kvmppc_ops *kvmppc_pr_ops; static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *inst) + enum instruction_fetch_type type, ppc_inst_t *inst) { int ret = EMULATE_DONE; u32 fetched_inst; @@ -326,15 +337,30 @@ static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu, ret = kvmppc_load_last_inst(vcpu, type, &vcpu->arch.last_inst); /* Write fetch_failed unswapped if the fetch failed */ - if (ret == EMULATE_DONE) - fetched_inst = kvmppc_need_byteswap(vcpu) ? - swab32(vcpu->arch.last_inst) : - vcpu->arch.last_inst; - else - fetched_inst = vcpu->arch.last_inst; + if (ret != EMULATE_DONE) { + *inst = ppc_inst(KVM_INST_FETCH_FAILED); + return ret; + } - *inst = fetched_inst; - return ret; +#ifdef CONFIG_PPC64 + /* Is this a prefixed instruction? */ + if ((vcpu->arch.last_inst >> 32) != 0) { + u32 prefix = vcpu->arch.last_inst >> 32; + u32 suffix = vcpu->arch.last_inst; + if (kvmppc_need_byteswap(vcpu)) { + prefix = swab32(prefix); + suffix = swab32(suffix); + } + *inst = ppc_inst_prefix(prefix, suffix); + return EMULATE_DONE; + } +#endif + + fetched_inst = kvmppc_need_byteswap(vcpu) ? + swab32(vcpu->arch.last_inst) : + vcpu->arch.last_inst; + *inst = ppc_inst(fetched_inst); + return EMULATE_DONE; } static inline bool is_kvmppc_hv_enabled(struct kvm *kvm) diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h index bc4bd19b7fc2..45492fb5bf22 100644 --- a/arch/powerpc/include/asm/local.h +++ b/arch/powerpc/include/asm/local.h @@ -90,6 +90,17 @@ static __inline__ long local_cmpxchg(local_t *l, long o, long n) return t; } +static __inline__ bool local_try_cmpxchg(local_t *l, long *po, long n) +{ + long o = *po, r; + + r = local_cmpxchg(l, o, n); + if (unlikely(r != o)) + *po = r; + + return likely(r == o); +} + static __inline__ long local_xchg(local_t *l, long n) { long t; diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 459736d5e511..4f6e7d7ee388 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -20,7 +20,8 @@ struct kimage; struct pci_host_bridge; struct machdep_calls { - char *name; + const char *name; + const char *compatible; #ifdef CONFIG_PPC64 #ifdef CONFIG_PM void (*iommu_restore)(void); diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index 09e2ffd360bb..ac53606c2594 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -27,8 +27,13 @@ struct ppc_plt_entry { struct mod_arch_specific { #ifdef __powerpc64__ unsigned int stubs_section; /* Index of stubs section in module */ +#ifdef CONFIG_PPC_KERNEL_PCREL + unsigned int got_section; /* What section is the GOT? */ + unsigned int pcpu_section; /* .data..percpu section */ +#else unsigned int toc_section; /* What section is the TOC? */ bool toc_fixed; /* Have we fixed up .TOC.? */ +#endif /* For module function descriptor dereference */ unsigned long start_opd; @@ -52,12 +57,15 @@ struct mod_arch_specific { /* * Select ELF headers. - * Make empty section for module_frob_arch_sections to expand. + * Make empty sections for module_frob_arch_sections to expand. */ #ifdef __powerpc64__ # ifdef MODULE asm(".section .stubs,\"ax\",@nobits; .align 3; .previous"); +# ifdef CONFIG_PPC_KERNEL_PCREL + asm(".section .mygot,\"a\",@nobits; .align 3; .previous"); +# endif # endif #else # ifdef MODULE diff --git a/arch/powerpc/include/asm/mpc8260.h b/arch/powerpc/include/asm/mpc8260.h index fd8c5707425b..155114bbd1a2 100644 --- a/arch/powerpc/include/asm/mpc8260.h +++ b/arch/powerpc/include/asm/mpc8260.h @@ -13,10 +13,6 @@ #ifdef CONFIG_8260 -#if defined(CONFIG_PQ2ADS) || defined (CONFIG_PQ2FADS) -#include -#endif - #ifdef CONFIG_PCI_8260 #include #endif diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 0ab3511a47d7..da0377f46597 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -88,7 +88,9 @@ struct paca_struct { u16 lock_token; /* Constant 0x8000, used in locks */ #endif +#ifndef CONFIG_PPC_KERNEL_PCREL u64 kernel_toc; /* Kernel TOC address */ +#endif u64 kernelbase; /* Base address of kernel */ u64 kernel_msr; /* MSR while running in kernel */ void *emergency_sp; /* pointer to emergency stack */ diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 71c1d26f2400..2aa3a091ef20 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -8,6 +8,7 @@ #include #include #include +#include struct device_node; @@ -44,6 +45,9 @@ struct pci_controller_ops { #endif void (*shutdown)(struct pci_controller *hose); + + struct iommu_group *(*device_group)(struct pci_controller *hose, + struct pci_dev *pdev); }; /* @@ -131,6 +135,9 @@ struct pci_controller { struct irq_domain *dev_domain; struct irq_domain *msi_domain; struct fwnode_handle *fwnode; + + /* iommu_ops support */ + struct iommu_device iommu; }; /* These are used for config access before all the PCI probing diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 21e33e46f4b8..ca5a0da7df4e 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -120,11 +120,18 @@ * 16-bit immediate helper macros: HA() is for use with sign-extending instrs * (e.g. LD, ADDI). If the bottom 16 bits is "-ve", add another bit into the * top half to negate the effect (i.e. 0xffff + 1 = 0x(1)0000). + * + * XXX: should these mask out possible sign bits? */ #define IMM_H(i) ((uintptr_t)(i)>>16) #define IMM_HA(i) (((uintptr_t)(i)>>16) + \ (((uintptr_t)(i) & 0x8000) >> 15)) +/* + * 18-bit immediate helper for prefix 18-bit upper immediate si0 field. + */ +#define IMM_H18(i) (((uintptr_t)(i)>>16) & 0x3ffff) + /* opcode and xopcode for instructions */ #define OP_PREFIX 1 @@ -306,6 +313,7 @@ #define PPC_PREFIX_8LS 0x04000000 /* Prefixed instructions */ +#define PPC_INST_PADDI 0x38000000 #define PPC_INST_PLD 0xe4000000 #define PPC_INST_PSTD 0xf4000000 diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index f6cf0159024e..d9fcff575027 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -57,11 +57,19 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev); #endif /* CONFIG_EEH */ +#ifdef CONFIG_FSL_ULI1575 +void __init uli_init(void); +#endif /* CONFIG_FSL_ULI1575 */ + #define PCI_BUSNO(bdfn) ((bdfn >> 8) & 0xff) #else /* CONFIG_PCI */ static inline void init_pci_config_tokens(void) { } #endif /* !CONFIG_PCI */ +#if !defined(CONFIG_PCI) || !defined(CONFIG_FSL_ULI1575) +static inline void __init uli_init(void) {} +#endif /* !defined(CONFIG_PCI) || !defined(CONFIG_FSL_ULI1575) */ + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PPC_PCI_H */ diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index d2f44612f4b0..5f05a984b103 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -180,6 +180,15 @@ #ifdef __KERNEL__ +/* + * Used to name C functions called from asm + */ +#ifdef CONFIG_PPC_KERNEL_PCREL +#define CFUNC(name) name@notoc +#else +#define CFUNC(name) name +#endif + /* * We use __powerpc64__ here because we want the compat VDSO to use the 32-bit * version below in the else case of the ifdef. @@ -207,6 +216,9 @@ .globl name; \ name: +#ifdef CONFIG_PPC_KERNEL_PCREL +#define _GLOBAL_TOC _GLOBAL +#else #define _GLOBAL_TOC(name) \ .align 2 ; \ .type name,@function; \ @@ -215,6 +227,7 @@ name: \ 0: addis r2,r12,(.TOC.-0b)@ha; \ addi r2,r2,(.TOC.-0b)@l; \ .localentry name,.-name +#endif #define DOTSYM(a) a @@ -346,8 +359,13 @@ n: #ifdef __powerpc64__ +#ifdef CONFIG_PPC_KERNEL_PCREL +#define __LOAD_PACA_TOC(reg) \ + li reg,-1 +#else #define __LOAD_PACA_TOC(reg) \ ld reg,PACATOC(r13) +#endif #define LOAD_PACA_TOC() \ __LOAD_PACA_TOC(r2) @@ -361,9 +379,15 @@ n: ori reg, reg, (expr)@l; \ rldimi reg, tmp, 32, 0 +#ifdef CONFIG_PPC_KERNEL_PCREL +#define LOAD_REG_ADDR(reg,name) \ + pla reg,name@pcrel + +#else #define LOAD_REG_ADDR(reg,name) \ addis reg,r2,name@toc@ha; \ addi reg,reg,name@toc@l +#endif #ifdef CONFIG_PPC_BOOK3E_64 /* @@ -837,4 +861,12 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96) #define BTB_FLUSH(reg) #endif /* CONFIG_PPC_E500 */ +#if defined(CONFIG_PPC64_ELF_ABI_V1) +#define STACK_FRAME_PARAMS 48 +#elif defined(CONFIG_PPC64_ELF_ABI_V2) +#define STACK_FRAME_PARAMS 32 +#elif defined(CONFIG_PPC32) +#define STACK_FRAME_PARAMS 8 +#endif + #endif /* _ASM_POWERPC_PPC_ASM_H */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1e8b2e04e626..6372e5f55ef0 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -382,8 +382,6 @@ #define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ #define SPRN_RMOR 0x138 /* Real mode offset register */ #define SPRN_HRMOR 0x139 /* Real mode offset register */ -#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ -#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ #define SPRN_ASDR 0x330 /* Access segment descriptor register */ #define SPRN_IC 0x350 /* Virtual Instruction Count */ #define SPRN_VTB 0x351 /* Virtual Time Base */ @@ -417,6 +415,7 @@ #define FSCR_DSCR __MASK(FSCR_DSCR_LG) #define FSCR_INTR_CAUSE (ASM_CONST(0xFF) << 56) /* interrupt cause */ #define SPRN_HFSCR 0xbe /* HV=1 Facility Status & Control Register */ +#define HFSCR_PREFIX __MASK(FSCR_PREFIX_LG) #define HFSCR_MSGP __MASK(FSCR_MSGP_LG) #define HFSCR_TAR __MASK(FSCR_TAR_LG) #define HFSCR_EBB __MASK(FSCR_EBB_LG) @@ -1310,6 +1309,11 @@ #define PVR_VER_E500MC 0x8023 #define PVR_VER_E5500 0x8024 #define PVR_VER_E6500 0x8040 +#define PVR_VER_7450 0x8000 +#define PVR_VER_7455 0x8001 +#define PVR_VER_7447 0x8002 +#define PVR_VER_7447A 0x8003 +#define PVR_VER_7448 0x8004 /* * For the 8xx processors, all of them report the same PVR family for diff --git a/arch/powerpc/include/asm/rtas-types.h b/arch/powerpc/include/asm/rtas-types.h index f2ad4a96cbc5..9d5b16803cbb 100644 --- a/arch/powerpc/include/asm/rtas-types.h +++ b/arch/powerpc/include/asm/rtas-types.h @@ -2,7 +2,7 @@ #ifndef _ASM_POWERPC_RTAS_TYPES_H #define _ASM_POWERPC_RTAS_TYPES_H -#include +#include typedef __be32 rtas_arg_t; @@ -12,7 +12,7 @@ struct rtas_args { __be32 nret; rtas_arg_t args[16]; rtas_arg_t *rets; /* Pointer to return values in args[]. */ -}; +} __aligned(8); struct rtas_t { unsigned long entry; /* physical address pointer */ diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index 9c00c9c0ca8f..4e1f548c8d37 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -46,10 +46,15 @@ extern char end_virt_trampolines[]; */ static inline unsigned long kernel_toc_addr(void) { +#ifdef CONFIG_PPC_KERNEL_PCREL + BUILD_BUG(); + return -1UL; +#else unsigned long toc_ptr; asm volatile("mr %0, 2" : "=r" (toc_ptr)); return toc_ptr; +#endif } static inline int overlaps_interrupt_vector_text(unsigned long start, diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 6c6cb53d7045..aaaa576d0e15 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,7 +67,7 @@ void start_secondary(void *unused); extern int smp_send_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us); extern int smp_send_safe_nmi_ipi(int cpu, void (*fn)(struct pt_regs *), u64 delay_us); extern void smp_send_debugger_break(void); -extern void start_secondary_resume(void); +extern void __noreturn start_secondary_resume(void); extern void smp_generic_give_timebase(void); extern void smp_generic_take_timebase(void); diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index af58f1ed3952..bf5dde1a4114 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -45,6 +45,7 @@ #include #include #include +#include #define SLB_PRELOAD_NR 16U /* @@ -175,9 +176,11 @@ static inline bool test_thread_local_flags(unsigned int flags) #ifdef CONFIG_COMPAT #define is_32bit_task() (test_thread_flag(TIF_32BIT)) #define is_tsk_32bit_task(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT)) +#define clear_tsk_compat_task(tsk) (clear_tsk_thread_flag(p, TIF_32BIT)) #else #define is_32bit_task() (IS_ENABLED(CONFIG_PPC32)) #define is_tsk_32bit_task(tsk) (IS_ENABLED(CONFIG_PPC32)) +#define clear_tsk_compat_task(tsk) do { } while (0) #endif #if defined(CONFIG_PPC64) @@ -186,6 +189,43 @@ static inline bool test_thread_local_flags(unsigned int flags) #define is_elf2_task() (0) #endif +/* + * Walks up the stack frames to make sure that the specified object is + * entirely contained by a single stack frame. + * + * Returns: + * GOOD_FRAME if within a frame + * BAD_STACK if placed across a frame boundary (or outside stack) + */ +static inline int arch_within_stack_frames(const void * const stack, + const void * const stackend, + const void *obj, unsigned long len) +{ + const void *params; + const void *frame; + + params = *(const void * const *)current_stack_pointer + STACK_FRAME_PARAMS; + frame = **(const void * const * const *)current_stack_pointer; + + /* + * low -----------------------------------------------------------> high + * [backchain][metadata][params][local vars][saved registers][backchain] + * ^------------------------------------^ + * | allows copies only in this region | + * | | + * params frame + * The metadata region contains the saved LR, CR etc. + */ + while (stack <= frame && frame < stackend) { + if (obj + len <= frame) + return obj >= params ? GOOD_FRAME : BAD_STACK; + params = frame + STACK_FRAME_PARAMS; + frame = *(const void * const *)frame; + } + + return BAD_STACK; +} + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 3ddc65c63a49..a2d255aa9627 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -71,14 +71,26 @@ __pu_failed: \ * because we do not write to any memory gcc knows about, so there * are no aliasing issues. */ +/* -mprefixed can generate offsets beyond range, fall back hack */ +#ifdef CONFIG_PPC_KERNEL_PREFIXED +#define __put_user_asm_goto(x, addr, label, op) \ + asm_volatile_goto( \ + "1: " op " %0,0(%1) # put_user\n" \ + EX_TABLE(1b, %l2) \ + : \ + : "r" (x), "b" (addr) \ + : \ + : label) +#else #define __put_user_asm_goto(x, addr, label, op) \ asm_volatile_goto( \ "1: " op "%U1%X1 %0,%1 # put_user\n" \ EX_TABLE(1b, %l2) \ : \ - : "r" (x), "m<>" (*addr) \ + : "r" (x), "m<>" (*addr) \ : \ : label) +#endif #ifdef __powerpc64__ #define __put_user_asm2_goto(x, ptr, label) \ @@ -131,14 +143,26 @@ do { \ #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT +/* -mprefixed can generate offsets beyond range, fall back hack */ +#ifdef CONFIG_PPC_KERNEL_PREFIXED +#define __get_user_asm_goto(x, addr, label, op) \ + asm_volatile_goto( \ + "1: "op" %0,0(%1) # get_user\n" \ + EX_TABLE(1b, %l2) \ + : "=r" (x) \ + : "b" (addr) \ + : \ + : label) +#else #define __get_user_asm_goto(x, addr, label, op) \ asm_volatile_goto( \ "1: "op"%U1%X1 %0, %1 # get_user\n" \ EX_TABLE(1b, %l2) \ : "=r" (x) \ - : "m<>" (*addr) \ + : "m<>" (*addr) \ : \ : label) +#endif #ifdef __powerpc64__ #define __get_user_asm2_goto(x, addr, label) \ @@ -361,8 +385,6 @@ copy_mc_to_user(void __user *to, const void *from, unsigned long n) extern long __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size); -extern void memcpy_page_flushcache(char *to, struct page *page, size_t offset, - size_t len); static __must_check inline bool user_access_begin(const void __user *ptr, size_t len) { diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h index 308857123a08..dbc4a5b8d02d 100644 --- a/arch/powerpc/include/uapi/asm/elf.h +++ b/arch/powerpc/include/uapi/asm/elf.h @@ -279,8 +279,12 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG]; #define R_PPC64_TLSLD 108 #define R_PPC64_TOCSAVE 109 +#define R_PPC64_REL24_NOTOC 116 #define R_PPC64_ENTRY 118 +#define R_PPC64_PCREL34 132 +#define R_PPC64_GOT_PCREL34 133 + #define R_PPC64_REL16 249 #define R_PPC64_REL16_LO 250 #define R_PPC64_REL16_HI 251 diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index d24a59a98c0c..9f14d95b8b32 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -185,7 +185,9 @@ int main(void) offsetof(struct task_struct, thread_info)); OFFSET(PACASAVEDMSR, paca_struct, saved_msr); OFFSET(PACAR1, paca_struct, saved_r1); +#ifndef CONFIG_PPC_KERNEL_PCREL OFFSET(PACATOC, paca_struct, kernel_toc); +#endif OFFSET(PACAKBASE, paca_struct, kernelbase); OFFSET(PACAKMSR, paca_struct, kernel_msr); #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 2769889219bf..19e46fd623b0 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -235,7 +235,7 @@ int __init btext_find_display(int allow_nonstdout) return rc; for_each_node_by_type(np, "display") { - if (of_get_property(np, "linux,opened", NULL)) { + if (of_property_read_bool(np, "linux,opened")) { printk("trying %pOF ...\n", np); rc = btext_initialize(np); printk("result: %d\n", rc); diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 038ce8d9061d..8920862ffd79 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -144,7 +144,7 @@ static bool dma_iommu_bypass_supported(struct device *dev, u64 mask) /* We support DMA to/from any memory page via the iommu */ int dma_iommu_dma_supported(struct device *dev, u64 mask) { - struct iommu_table *tbl = get_iommu_table_base(dev); + struct iommu_table *tbl; if (dev_is_pci(dev) && dma_iommu_bypass_supported(dev, mask)) { /* @@ -162,6 +162,8 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask) return 1; } + tbl = get_iommu_table_base(dev); + if (!tbl) { dev_err(dev, "Warning: IOMMU dma not supported: mask 0x%08llx, table unavailable\n", mask); return 0; diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 5604c9a1ac22..47f0dd9a45ad 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -183,12 +183,11 @@ syscall_exit_finish: ret_from_fork: REST_NVGPRS(r1) bl schedule_tail - li r3,0 + li r3,0 /* fork() return value */ b ret_from_syscall - .globl ret_from_kernel_thread -ret_from_kernel_thread: - REST_NVGPRS(r1) + .globl ret_from_kernel_user_thread +ret_from_kernel_user_thread: bl schedule_tail mtctr r14 mr r3,r15 @@ -197,6 +196,22 @@ ret_from_kernel_thread: li r3,0 b ret_from_syscall + .globl start_kernel_thread +start_kernel_thread: + bl schedule_tail + mtctr r14 + mr r3,r15 + PPC440EP_ERR42 + bctrl + /* + * This must not return. We actually want to BUG here, not WARN, + * because BUG will exit the process which is what the kernel thread + * should have done, which may give some hope of continuing. + */ +100: trap + EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,0 + + /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 6441a1ba57ac..c33c8ebf8641 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1075,7 +1075,7 @@ EXC_COMMON_BEGIN(system_reset_common) __GEN_COMMON_BODY system_reset addi r3,r1,STACK_INT_FRAME_REGS - bl system_reset_exception + bl CFUNC(system_reset_exception) /* Clear MSR_RI before setting SRR0 and SRR1. */ li r9,0 @@ -1223,9 +1223,9 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) addi r3,r1,STACK_INT_FRAME_REGS BEGIN_FTR_SECTION - bl machine_check_early_boot + bl CFUNC(machine_check_early_boot) END_FTR_SECTION(0, 1) // nop out after boot - bl machine_check_early + bl CFUNC(machine_check_early) std r3,RESULT(r1) /* Save result */ ld r12,_MSR(r1) @@ -1286,7 +1286,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) * Queue up the MCE event so that we can log it later, while * returning from kernel or opal call. */ - bl machine_check_queue_event + bl CFUNC(machine_check_queue_event) MACHINE_CHECK_HANDLER_WINDUP RFI_TO_KERNEL @@ -1312,7 +1312,7 @@ EXC_COMMON_BEGIN(machine_check_common) */ GEN_COMMON machine_check addi r3,r1,STACK_INT_FRAME_REGS - bl machine_check_exception_async + bl CFUNC(machine_check_exception_async) b interrupt_return_srr @@ -1322,7 +1322,7 @@ EXC_COMMON_BEGIN(machine_check_common) * done. Queue the event then call the idle code to do the wake up. */ EXC_COMMON_BEGIN(machine_check_idle_common) - bl machine_check_queue_event + bl CFUNC(machine_check_queue_event) /* * GPR-loss wakeups are relatively straightforward, because the @@ -1361,7 +1361,7 @@ EXC_COMMON_BEGIN(unrecoverable_mce) BEGIN_FTR_SECTION li r10,0 /* clear MSR_RI */ mtmsrd r10,1 - bl disable_machine_check + bl CFUNC(disable_machine_check) END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) ld r10,PACAKMSR(r13) li r3,MSR_ME @@ -1378,14 +1378,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) * the early handler which is a true NMI. */ addi r3,r1,STACK_INT_FRAME_REGS - bl machine_check_exception + bl CFUNC(machine_check_exception) /* * We will not reach here. Even if we did, there is no way out. * Call unrecoverable_exception and die. */ addi r3,r1,STACK_INT_FRAME_REGS - bl unrecoverable_exception + bl CFUNC(unrecoverable_exception) b . @@ -1440,16 +1440,16 @@ EXC_COMMON_BEGIN(data_access_common) bne- 1f #ifdef CONFIG_PPC_64S_HASH_MMU BEGIN_MMU_FTR_SECTION - bl do_hash_fault + bl CFUNC(do_hash_fault) MMU_FTR_SECTION_ELSE - bl do_page_fault + bl CFUNC(do_page_fault) ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) #else - bl do_page_fault + bl CFUNC(do_page_fault) #endif b interrupt_return_srr -1: bl do_break +1: bl CFUNC(do_break) /* * do_break() may have changed the NV GPRS while handling a breakpoint. * If so, we need to restore them with their updated values. @@ -1493,7 +1493,7 @@ EXC_COMMON_BEGIN(data_access_slb_common) BEGIN_MMU_FTR_SECTION /* HPT case, do SLB fault */ addi r3,r1,STACK_INT_FRAME_REGS - bl do_slb_fault + bl CFUNC(do_slb_fault) cmpdi r3,0 bne- 1f b fast_interrupt_return_srr @@ -1507,7 +1507,7 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) #endif std r3,RESULT(r1) addi r3,r1,STACK_INT_FRAME_REGS - bl do_bad_segment_interrupt + bl CFUNC(do_bad_segment_interrupt) b interrupt_return_srr @@ -1541,12 +1541,12 @@ EXC_COMMON_BEGIN(instruction_access_common) addi r3,r1,STACK_INT_FRAME_REGS #ifdef CONFIG_PPC_64S_HASH_MMU BEGIN_MMU_FTR_SECTION - bl do_hash_fault + bl CFUNC(do_hash_fault) MMU_FTR_SECTION_ELSE - bl do_page_fault + bl CFUNC(do_page_fault) ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) #else - bl do_page_fault + bl CFUNC(do_page_fault) #endif b interrupt_return_srr @@ -1581,7 +1581,7 @@ EXC_COMMON_BEGIN(instruction_access_slb_common) BEGIN_MMU_FTR_SECTION /* HPT case, do SLB fault */ addi r3,r1,STACK_INT_FRAME_REGS - bl do_slb_fault + bl CFUNC(do_slb_fault) cmpdi r3,0 bne- 1f b fast_interrupt_return_srr @@ -1595,7 +1595,7 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) #endif std r3,RESULT(r1) addi r3,r1,STACK_INT_FRAME_REGS - bl do_bad_segment_interrupt + bl CFUNC(do_bad_segment_interrupt) b interrupt_return_srr @@ -1649,7 +1649,7 @@ EXC_VIRT_END(hardware_interrupt, 0x4500, 0x100) EXC_COMMON_BEGIN(hardware_interrupt_common) GEN_COMMON hardware_interrupt addi r3,r1,STACK_INT_FRAME_REGS - bl do_IRQ + bl CFUNC(do_IRQ) BEGIN_FTR_SECTION b interrupt_return_hsrr FTR_SECTION_ELSE @@ -1679,7 +1679,7 @@ EXC_VIRT_END(alignment, 0x4600, 0x100) EXC_COMMON_BEGIN(alignment_common) GEN_COMMON alignment addi r3,r1,STACK_INT_FRAME_REGS - bl alignment_exception + bl CFUNC(alignment_exception) HANDLER_RESTORE_NVGPRS() /* instruction emulation may change GPRs */ b interrupt_return_srr @@ -1745,7 +1745,7 @@ EXC_COMMON_BEGIN(program_check_common) .Ldo_program_check: addi r3,r1,STACK_INT_FRAME_REGS - bl program_check_exception + bl CFUNC(program_check_exception) HANDLER_RESTORE_NVGPRS() /* instruction emulation may change GPRs */ b interrupt_return_srr @@ -1777,7 +1777,7 @@ EXC_COMMON_BEGIN(fp_unavailable_common) GEN_COMMON fp_unavailable bne 1f /* if from user, just load it up */ addi r3,r1,STACK_INT_FRAME_REGS - bl kernel_fp_unavailable_exception + bl CFUNC(kernel_fp_unavailable_exception) 0: trap EMIT_BUG_ENTRY 0b, __FILE__, __LINE__, 0 1: @@ -1790,12 +1790,12 @@ BEGIN_FTR_SECTION bne- 2f END_FTR_SECTION_IFSET(CPU_FTR_TM) #endif - bl load_up_fpu + bl CFUNC(load_up_fpu) b fast_interrupt_return_srr #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ addi r3,r1,STACK_INT_FRAME_REGS - bl fp_unavailable_tm + bl CFUNC(fp_unavailable_tm) b interrupt_return_srr #endif @@ -1839,7 +1839,7 @@ EXC_VIRT_END(decrementer, 0x4900, 0x80) EXC_COMMON_BEGIN(decrementer_common) GEN_COMMON decrementer addi r3,r1,STACK_INT_FRAME_REGS - bl timer_interrupt + bl CFUNC(timer_interrupt) b interrupt_return_srr @@ -1925,9 +1925,9 @@ EXC_COMMON_BEGIN(doorbell_super_common) GEN_COMMON doorbell_super addi r3,r1,STACK_INT_FRAME_REGS #ifdef CONFIG_PPC_DOORBELL - bl doorbell_exception + bl CFUNC(doorbell_exception) #else - bl unknown_async_exception + bl CFUNC(unknown_async_exception) #endif b interrupt_return_srr @@ -2091,7 +2091,7 @@ EXC_VIRT_END(single_step, 0x4d00, 0x100) EXC_COMMON_BEGIN(single_step_common) GEN_COMMON single_step addi r3,r1,STACK_INT_FRAME_REGS - bl single_step_exception + bl CFUNC(single_step_exception) b interrupt_return_srr @@ -2126,9 +2126,9 @@ EXC_COMMON_BEGIN(h_data_storage_common) GEN_COMMON h_data_storage addi r3,r1,STACK_INT_FRAME_REGS BEGIN_MMU_FTR_SECTION - bl do_bad_page_fault_segv + bl CFUNC(do_bad_page_fault_segv) MMU_FTR_SECTION_ELSE - bl unknown_exception + bl CFUNC(unknown_exception) ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_TYPE_RADIX) b interrupt_return_hsrr @@ -2154,7 +2154,7 @@ EXC_VIRT_END(h_instr_storage, 0x4e20, 0x20) EXC_COMMON_BEGIN(h_instr_storage_common) GEN_COMMON h_instr_storage addi r3,r1,STACK_INT_FRAME_REGS - bl unknown_exception + bl CFUNC(unknown_exception) b interrupt_return_hsrr @@ -2177,7 +2177,7 @@ EXC_VIRT_END(emulation_assist, 0x4e40, 0x20) EXC_COMMON_BEGIN(emulation_assist_common) GEN_COMMON emulation_assist addi r3,r1,STACK_INT_FRAME_REGS - bl emulation_assist_interrupt + bl CFUNC(emulation_assist_interrupt) HANDLER_RESTORE_NVGPRS() /* instruction emulation may change GPRs */ b interrupt_return_hsrr @@ -2237,7 +2237,7 @@ EXC_COMMON_BEGIN(hmi_exception_early_common) __GEN_COMMON_BODY hmi_exception_early addi r3,r1,STACK_INT_FRAME_REGS - bl hmi_exception_realmode + bl CFUNC(hmi_exception_realmode) cmpdi cr0,r3,0 bne 1f @@ -2255,7 +2255,7 @@ EXC_COMMON_BEGIN(hmi_exception_early_common) EXC_COMMON_BEGIN(hmi_exception_common) GEN_COMMON hmi_exception addi r3,r1,STACK_INT_FRAME_REGS - bl handle_hmi_exception + bl CFUNC(handle_hmi_exception) b interrupt_return_hsrr @@ -2290,9 +2290,9 @@ EXC_COMMON_BEGIN(h_doorbell_common) GEN_COMMON h_doorbell addi r3,r1,STACK_INT_FRAME_REGS #ifdef CONFIG_PPC_DOORBELL - bl doorbell_exception + bl CFUNC(doorbell_exception) #else - bl unknown_async_exception + bl CFUNC(unknown_async_exception) #endif b interrupt_return_hsrr @@ -2325,7 +2325,7 @@ EXC_VIRT_END(h_virt_irq, 0x4ea0, 0x20) EXC_COMMON_BEGIN(h_virt_irq_common) GEN_COMMON h_virt_irq addi r3,r1,STACK_INT_FRAME_REGS - bl do_IRQ + bl CFUNC(do_IRQ) b interrupt_return_hsrr @@ -2374,10 +2374,10 @@ EXC_COMMON_BEGIN(performance_monitor_common) lbz r4,PACAIRQSOFTMASK(r13) cmpdi r4,IRQS_ENABLED bne 1f - bl performance_monitor_exception_async + bl CFUNC(performance_monitor_exception_async) b interrupt_return_srr 1: - bl performance_monitor_exception_nmi + bl CFUNC(performance_monitor_exception_nmi) /* Clear MSR_RI before setting SRR0 and SRR1. */ li r9,0 mtmsrd r9,1 @@ -2421,19 +2421,19 @@ BEGIN_FTR_SECTION bne- 2f END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69) #endif - bl load_up_altivec + bl CFUNC(load_up_altivec) b fast_interrupt_return_srr #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ addi r3,r1,STACK_INT_FRAME_REGS - bl altivec_unavailable_tm + bl CFUNC(altivec_unavailable_tm) b interrupt_return_srr #endif 1: END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif addi r3,r1,STACK_INT_FRAME_REGS - bl altivec_unavailable_exception + bl CFUNC(altivec_unavailable_exception) b interrupt_return_srr @@ -2475,14 +2475,14 @@ BEGIN_FTR_SECTION #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2: /* User process was in a transaction */ addi r3,r1,STACK_INT_FRAME_REGS - bl vsx_unavailable_tm + bl CFUNC(vsx_unavailable_tm) b interrupt_return_srr #endif 1: END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif addi r3,r1,STACK_INT_FRAME_REGS - bl vsx_unavailable_exception + bl CFUNC(vsx_unavailable_exception) b interrupt_return_srr @@ -2509,7 +2509,7 @@ EXC_VIRT_END(facility_unavailable, 0x4f60, 0x20) EXC_COMMON_BEGIN(facility_unavailable_common) GEN_COMMON facility_unavailable addi r3,r1,STACK_INT_FRAME_REGS - bl facility_unavailable_exception + bl CFUNC(facility_unavailable_exception) HANDLER_RESTORE_NVGPRS() /* instruction emulation may change GPRs */ b interrupt_return_srr @@ -2537,7 +2537,7 @@ EXC_VIRT_END(h_facility_unavailable, 0x4f80, 0x20) EXC_COMMON_BEGIN(h_facility_unavailable_common) GEN_COMMON h_facility_unavailable addi r3,r1,STACK_INT_FRAME_REGS - bl facility_unavailable_exception + bl CFUNC(facility_unavailable_exception) /* XXX Shouldn't be necessary in practice */ HANDLER_RESTORE_NVGPRS() b interrupt_return_hsrr @@ -2568,7 +2568,7 @@ EXC_VIRT_NONE(0x5200, 0x100) EXC_COMMON_BEGIN(cbe_system_error_common) GEN_COMMON cbe_system_error addi r3,r1,STACK_INT_FRAME_REGS - bl cbe_system_error_exception + bl CFUNC(cbe_system_error_exception) b interrupt_return_hsrr #else /* CONFIG_CBE_RAS */ @@ -2599,7 +2599,7 @@ EXC_VIRT_END(instruction_breakpoint, 0x5300, 0x100) EXC_COMMON_BEGIN(instruction_breakpoint_common) GEN_COMMON instruction_breakpoint addi r3,r1,STACK_INT_FRAME_REGS - bl instruction_breakpoint_exception + bl CFUNC(instruction_breakpoint_exception) b interrupt_return_srr @@ -2721,7 +2721,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) EXC_COMMON_BEGIN(denorm_exception_common) GEN_COMMON denorm_exception addi r3,r1,STACK_INT_FRAME_REGS - bl unknown_exception + bl CFUNC(unknown_exception) b interrupt_return_hsrr @@ -2738,7 +2738,7 @@ EXC_VIRT_NONE(0x5600, 0x100) EXC_COMMON_BEGIN(cbe_maintenance_common) GEN_COMMON cbe_maintenance addi r3,r1,STACK_INT_FRAME_REGS - bl cbe_maintenance_exception + bl CFUNC(cbe_maintenance_exception) b interrupt_return_hsrr #else /* CONFIG_CBE_RAS */ @@ -2764,10 +2764,10 @@ EXC_COMMON_BEGIN(altivec_assist_common) GEN_COMMON altivec_assist addi r3,r1,STACK_INT_FRAME_REGS #ifdef CONFIG_ALTIVEC - bl altivec_assist_exception + bl CFUNC(altivec_assist_exception) HANDLER_RESTORE_NVGPRS() /* instruction emulation may change GPRs */ #else - bl unknown_exception + bl CFUNC(unknown_exception) #endif b interrupt_return_srr @@ -2785,7 +2785,7 @@ EXC_VIRT_NONE(0x5800, 0x100) EXC_COMMON_BEGIN(cbe_thermal_common) GEN_COMMON cbe_thermal addi r3,r1,STACK_INT_FRAME_REGS - bl cbe_thermal_exception + bl CFUNC(cbe_thermal_exception) b interrupt_return_hsrr #else /* CONFIG_CBE_RAS */ @@ -2818,7 +2818,7 @@ EXC_COMMON_BEGIN(soft_nmi_common) __GEN_COMMON_BODY soft_nmi addi r3,r1,STACK_INT_FRAME_REGS - bl soft_nmi_interrupt + bl CFUNC(soft_nmi_interrupt) /* Clear MSR_RI before setting SRR0 and SRR1. */ li r9,0 diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 1febb56ebaeb..f132d8704263 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -76,6 +76,13 @@ * 2. The kernel is entered at __start */ +/* + * boot_from_prom and prom_init run at the physical address. Everything + * after prom and kexec entry run at the virtual address (PAGE_OFFSET). + * Secondaries run at the virtual address from generic_secondary_common_init + * onward. + */ + OPEN_FIXED_SECTION(first_256B, 0x0, 0x100) USE_FIXED_SECTION(first_256B) /* @@ -303,13 +310,11 @@ _GLOBAL(fsl_secondary_thread_init) /* turn on 64-bit mode */ bl enable_64b_mode - /* get a valid TOC pointer, wherever we're mapped at */ - bl relative_toc - tovirt(r2,r2) - /* Book3E initialization */ mr r3,r24 bl book3e_secondary_thread_init + bl relative_toc + b generic_secondary_common_init #endif /* CONFIG_PPC_BOOK3E_64 */ @@ -325,22 +330,24 @@ _GLOBAL(fsl_secondary_thread_init) */ _GLOBAL(generic_secondary_smp_init) FIXUP_ENDIAN + + li r13,0 + + /* Poison TOC */ + li r2,-1 + mr r24,r3 mr r25,r4 /* turn on 64-bit mode */ bl enable_64b_mode - /* get a valid TOC pointer, wherever we're mapped at */ - bl relative_toc - tovirt(r2,r2) - #ifdef CONFIG_PPC_BOOK3E_64 /* Book3E initialization */ mr r3,r24 mr r4,r25 bl book3e_secondary_core_init - + /* Now NIA and r2 are relocated to PAGE_OFFSET if not already */ /* * After common core init has finished, check if the current thread is the * one we wanted to boot. If not, start the specified thread and stop the @@ -378,6 +385,16 @@ _GLOBAL(generic_secondary_smp_init) 10: b 10b 20: +#else + /* Now the MMU is off, can branch to our PAGE_OFFSET address */ + bcl 20,31,$+4 +1: mflr r11 + addi r11,r11,(2f - 1b) + tovirt(r11, r11) + mtctr r11 + bctr +2: + bl relative_toc #endif generic_secondary_common_init: @@ -492,6 +509,8 @@ SYM_FUNC_START_LOCAL(start_initialization_book3s) /* Switch off MMU if not already off */ bl __mmu_off + /* Now the MMU is off, can return to our PAGE_OFFSET address */ + tovirt(r25,r25) mtlr r25 blr SYM_FUNC_END(start_initialization_book3s) @@ -515,14 +534,8 @@ __start_initialization_multiplatform: /* Zero r13 (paca) so early program check / mce don't use it */ li r13,0 - /* Get TOC pointer (current runtime address) */ - bl relative_toc - - /* find out where we are now */ - bcl 20,31,$+4 -0: mflr r26 /* r26 = runtime addr here */ - addis r26,r26,(_stext - 0b)@ha - addi r26,r26,(_stext - 0b)@l /* current runtime base addr */ + /* Poison TOC */ + li r2,-1 /* * Are we booted from a PROM Of-type client-interface ? @@ -540,16 +553,41 @@ __start_initialization_multiplatform: mr r29,r9 #endif + /* Get TOC pointer (current runtime address) */ + bl relative_toc + + /* These functions return to the virtual (PAGE_OFFSET) address */ #ifdef CONFIG_PPC_BOOK3E_64 bl start_initialization_book3e #else bl start_initialization_book3s #endif /* CONFIG_PPC_BOOK3E_64 */ + + /* Get TOC pointer, virtual */ + bl relative_toc + + /* find out where we are now */ + + /* OPAL doesn't pass base address in r4, have to derive it. */ + bcl 20,31,$+4 +0: mflr r26 /* r26 = runtime addr here */ + addis r26,r26,(_stext - 0b)@ha + addi r26,r26,(_stext - 0b)@l /* current runtime base addr */ + b __after_prom_start __REF __boot_from_prom: #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE + /* Get TOC pointer, non-virtual */ + bl relative_toc + + /* find out where we are now */ + bcl 20,31,$+4 +0: mflr r26 /* r26 = runtime addr here */ + addis r26,r26,(_stext - 0b)@ha + addi r26,r26,(_stext - 0b)@l /* current runtime base addr */ + /* Save parameters */ mr r31,r3 mr r30,r4 @@ -579,7 +617,7 @@ __boot_from_prom: /* Do all of the interaction with OF client interface */ mr r8,r26 - bl prom_init + bl CFUNC(prom_init) #endif /* #CONFIG_PPC_OF_BOOT_TRAMPOLINE */ /* We never return. We also hit that trap if trying to boot @@ -590,18 +628,11 @@ __boot_from_prom: __after_prom_start: #ifdef CONFIG_RELOCATABLE /* process relocations for the final address of the kernel */ - lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */ - sldi r25,r25,32 -#if defined(CONFIG_PPC_BOOK3E_64) - tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ -#endif lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26) -#if defined(CONFIG_PPC_BOOK3E_64) - tophys(r26,r26) -#endif cmplwi cr0,r7,1 /* flagged to stay where we are ? */ - bne 1f - add r25,r25,r26 + mr r25,r26 /* then use current kernel base */ + beq 1f + LOAD_REG_IMMEDIATE(r25, PAGE_OFFSET) /* else use static kernel base */ 1: mr r3,r25 bl relocate #if defined(CONFIG_PPC_BOOK3E_64) @@ -617,14 +648,8 @@ __after_prom_start: * * Note: This process overwrites the OF exception vectors. */ - li r3,0 /* target addr */ -#ifdef CONFIG_PPC_BOOK3E_64 - tovirt(r3,r3) /* on booke, we already run at PAGE_OFFSET */ -#endif + LOAD_REG_IMMEDIATE(r3, PAGE_OFFSET) mr. r4,r26 /* In some cases the loader may */ -#if defined(CONFIG_PPC_BOOK3E_64) - tovirt(r4,r4) -#endif beq 9f /* have already put us at zero */ li r6,0x100 /* Start offset, the first 0x100 */ /* bytes were copied earlier. */ @@ -635,9 +660,6 @@ __after_prom_start: * variable __run_at_load, if it is set the kernel is treated as relocatable * kernel, otherwise it will be moved to PHYSICAL_START */ -#if defined(CONFIG_PPC_BOOK3E_64) - tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ -#endif lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26) cmplwi cr0,r7,1 bne 3f @@ -756,9 +778,15 @@ _GLOBAL(pmac_secondary_start) sync slbia - /* get TOC pointer (real address) */ + /* Branch to our PAGE_OFFSET address */ + bcl 20,31,$+4 +1: mflr r11 + addi r11,r11,(2f - 1b) + tovirt(r11, r11) + mtctr r11 + bctr +2: bl relative_toc - tovirt(r2,r2) /* Copy some CPU settings from CPU 0 */ bl __restore_cpu_ppc970 @@ -817,7 +845,7 @@ __secondary_start: * can turn it on below. This is a call to C, which is OK, we're still * running on the emergency stack. */ - bl early_setup_secondary + bl CFUNC(early_setup_secondary) /* * The primary has initialized our kernel stack for us in the paca, grab @@ -856,7 +884,7 @@ start_secondary_prolog: LOAD_PACA_TOC() li r3,0 std r3,0(r1) /* Zero the stack frame pointer */ - bl start_secondary + bl CFUNC(start_secondary) b . /* * Reset stack pointer and call start_secondary @@ -867,7 +895,7 @@ _GLOBAL(start_secondary_resume) ld r1,PACAKSAVE(r13) /* Reload kernel stack pointer */ li r3,0 std r3,0(r1) /* Zero the stack frame pointer */ - bl start_secondary + bl CFUNC(start_secondary) b . #endif @@ -897,10 +925,15 @@ SYM_FUNC_END(enable_64b_mode) * TOC in -mcmodel=medium mode. After we relocate to 0 but before * the MMU is on we need our TOC to be a virtual address otherwise * these pointers will be real addresses which may get stored and - * accessed later with the MMU on. We use tovirt() at the call - * sites to handle this. + * accessed later with the MMU on. We branch to the virtual address + * while still in real mode then call relative_toc again to handle + * this. */ _GLOBAL(relative_toc) +#ifdef CONFIG_PPC_KERNEL_PCREL + tdnei r2,-1 + blr +#else mflr r0 bcl 20,31,$+4 0: mflr r11 @@ -911,15 +944,15 @@ _GLOBAL(relative_toc) .balign 8 p_toc: .8byte .TOC. - 0b +#endif /* * This is where the main kernel code starts. */ __REF start_here_multiplatform: - /* set up the TOC */ - bl relative_toc - tovirt(r2,r2) + /* Adjust TOC for moved kernel. Could adjust when moving it instead. */ + bl relative_toc /* Clear out the BSS. It may have been done in prom_init, * already but that's irrelevant since prom_init will soon @@ -972,7 +1005,7 @@ start_here_multiplatform: */ #ifdef CONFIG_KASAN - bl kasan_early_init + bl CFUNC(kasan_early_init) #endif /* Restore parameters passed from prom_init/kexec */ mr r3,r31 @@ -1005,7 +1038,7 @@ start_here_common: stb r0,PACAIRQHAPPENED(r13) /* Generic kernel entry */ - bl start_kernel + bl CFUNC(start_kernel) /* Not reached */ 0: trap diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index 37d43c172676..b6b5b01a173c 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -5,6 +5,7 @@ #include /* for STACK_FRAME_REGS_MARKER */ #include #include +#include /* for THREAD_SHIFT */ #ifdef __ASSEMBLY__ diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index b9a725abc596..b1c0418b25c8 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -107,19 +107,11 @@ static struct ctl_table powersave_nap_ctl_table[] = { }, {} }; -static struct ctl_table powersave_nap_sysctl_root[] = { - { - .procname = "kernel", - .mode = 0555, - .child = powersave_nap_ctl_table, - }, - {} -}; static int __init register_powersave_nap_sysctl(void) { - register_sysctl_table(powersave_nap_sysctl_root); + register_sysctl("kernel", powersave_nap_ctl_table); return 0; } diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index 0ec1581619db..e34c72285b4e 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -95,7 +95,7 @@ static notrace void booke_load_dbcr0(void) #endif } -static void check_return_regs_valid(struct pt_regs *regs) +static notrace void check_return_regs_valid(struct pt_regs *regs) { #ifdef CONFIG_PPC_BOOK3S_64 unsigned long trap, srr0, srr1; diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S index fccc34489add..bd863702d812 100644 --- a/arch/powerpc/kernel/interrupt_64.S +++ b/arch/powerpc/kernel/interrupt_64.S @@ -101,12 +101,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) * state of kernel code. */ SANITIZE_SYSCALL_GPRS() - bl system_call_exception + bl CFUNC(system_call_exception) .Lsyscall_vectored_\name\()_exit: addi r4,r1,STACK_INT_FRAME_REGS li r5,1 /* scv */ - bl syscall_exit_prepare + bl CFUNC(syscall_exit_prepare) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ .Lsyscall_vectored_\name\()_rst_start: lbz r11,PACAIRQHAPPENED(r13) @@ -185,7 +185,7 @@ _ASM_NOKPROBE_SYMBOL(syscall_vectored_\name\()_restart) addi r4,r1,STACK_INT_FRAME_REGS li r11,IRQS_ALL_DISABLED stb r11,PACAIRQSOFTMASK(r13) - bl syscall_exit_restart + bl CFUNC(syscall_exit_restart) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ b .Lsyscall_vectored_\name\()_rst_start 1: @@ -286,12 +286,12 @@ END_BTB_FLUSH_SECTION * state of kernel code. */ SANITIZE_SYSCALL_GPRS() - bl system_call_exception + bl CFUNC(system_call_exception) .Lsyscall_exit: addi r4,r1,STACK_INT_FRAME_REGS li r5,0 /* !scv */ - bl syscall_exit_prepare + bl CFUNC(syscall_exit_prepare) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ #ifdef CONFIG_PPC_BOOK3S .Lsyscall_rst_start: @@ -372,7 +372,7 @@ _ASM_NOKPROBE_SYMBOL(syscall_restart) addi r4,r1,STACK_INT_FRAME_REGS li r11,IRQS_ALL_DISABLED stb r11,PACAIRQSOFTMASK(r13) - bl syscall_exit_restart + bl CFUNC(syscall_exit_restart) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ b .Lsyscall_rst_start 1: @@ -401,7 +401,7 @@ _ASM_NOKPROBE_SYMBOL(fast_interrupt_return_srr) li r3,0 /* 0 return value, no EMULATE_STACK_STORE */ bne+ .Lfast_kernel_interrupt_return_srr addi r3,r1,STACK_INT_FRAME_REGS - bl unrecoverable_exception + bl CFUNC(unrecoverable_exception) b . /* should not get here */ #else bne .Lfast_user_interrupt_return_srr @@ -419,7 +419,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()) interrupt_return_\srr\()_user: /* make backtraces match the _kernel variant */ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_user) addi r3,r1,STACK_INT_FRAME_REGS - bl interrupt_exit_user_prepare + bl CFUNC(interrupt_exit_user_prepare) #ifndef CONFIG_INTERRUPT_SANITIZE_REGISTERS cmpdi r3,0 bne- .Lrestore_nvgprs_\srr @@ -523,7 +523,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_user_restart) addi r3,r1,STACK_INT_FRAME_REGS li r11,IRQS_ALL_DISABLED stb r11,PACAIRQSOFTMASK(r13) - bl interrupt_exit_user_restart + bl CFUNC(interrupt_exit_user_restart) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ b .Linterrupt_return_\srr\()_user_rst_start 1: @@ -536,7 +536,7 @@ RESTART_TABLE(.Linterrupt_return_\srr\()_user_rst_start, .Linterrupt_return_\srr interrupt_return_\srr\()_kernel: _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel) addi r3,r1,STACK_INT_FRAME_REGS - bl interrupt_exit_kernel_prepare + bl CFUNC(interrupt_exit_kernel_prepare) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ .Linterrupt_return_\srr\()_kernel_rst_start: @@ -705,7 +705,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel_restart) addi r3,r1,STACK_INT_FRAME_REGS li r11,IRQS_ALL_DISABLED stb r11,PACAIRQSOFTMASK(r13) - bl interrupt_exit_kernel_restart + bl CFUNC(interrupt_exit_kernel_restart) std r1,PACA_EXIT_SAVE_R1(r13) /* save r1 for restart */ b .Linterrupt_return_\srr\()_kernel_rst_start 1: @@ -727,21 +727,20 @@ DEFINE_FIXED_SYMBOL(__end_soft_masked, text) #ifdef CONFIG_PPC_BOOK3S _GLOBAL(ret_from_fork_scv) - bl schedule_tail - REST_NVGPRS(r1) + bl CFUNC(schedule_tail) + HANDLER_RESTORE_NVGPRS() li r3,0 /* fork() return value */ b .Lsyscall_vectored_common_exit #endif _GLOBAL(ret_from_fork) - bl schedule_tail - REST_NVGPRS(r1) + bl CFUNC(schedule_tail) + HANDLER_RESTORE_NVGPRS() li r3,0 /* fork() return value */ b .Lsyscall_exit -_GLOBAL(ret_from_kernel_thread) - bl schedule_tail - REST_NVGPRS(r1) +_GLOBAL(ret_from_kernel_user_thread) + bl CFUNC(schedule_tail) mtctr r14 mr r3,r15 #ifdef CONFIG_PPC64_ELF_ABI_V2 @@ -749,4 +748,25 @@ _GLOBAL(ret_from_kernel_thread) #endif bctrl li r3,0 + /* + * It does not matter whether this returns via the scv or sc path + * because it returns as execve() and therefore has no calling ABI + * (i.e., it sets registers according to the exec()ed entry point). + */ b .Lsyscall_exit + +_GLOBAL(start_kernel_thread) + bl CFUNC(schedule_tail) + mtctr r14 + mr r3,r15 +#ifdef CONFIG_PPC64_ELF_ABI_V2 + mr r12,r14 +#endif + bctrl + /* + * This must not return. We actually want to BUG here, not WARN, + * because BUG will exit the process which is what the kernel thread + * should have done, which may give some hope of continuing. + */ +100: trap + EMIT_BUG_ENTRY 100b,__FILE__,__LINE__,0 diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index ee95937bdaf1..67f0b01e6ff5 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -35,6 +35,7 @@ #include #include #include +#include #define DBG(...) @@ -517,7 +518,7 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl, /* Convert entry to a dma_addr_t */ entry += tbl->it_offset; dma_addr = entry << tbl->it_page_shift; - dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl)); + dma_addr |= (vaddr & ~IOMMU_PAGE_MASK(tbl)); DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n", npages, entry, dma_addr); @@ -904,6 +905,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, unsigned int order; unsigned int nio_pages, io_order; struct page *page; + int tcesize = (1 << tbl->it_page_shift); size = PAGE_ALIGN(size); order = get_order(size); @@ -930,7 +932,8 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, memset(ret, 0, size); /* Set up tces to cover the allocated range */ - nio_pages = size >> tbl->it_page_shift; + nio_pages = IOMMU_PAGE_ALIGN(size, tbl) >> tbl->it_page_shift; + io_order = get_iommu_order(size, tbl); mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, mask >> tbl->it_page_shift, io_order, 0); @@ -938,7 +941,8 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, free_pages((unsigned long)ret, order); return NULL; } - *dma_handle = mapping; + + *dma_handle = mapping | ((u64)ret & (tcesize - 1)); return ret; } @@ -949,7 +953,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size, unsigned int nio_pages; size = PAGE_ALIGN(size); - nio_pages = size >> tbl->it_page_shift; + nio_pages = IOMMU_PAGE_ALIGN(size, tbl) >> tbl->it_page_shift; iommu_free(tbl, dma_handle, nio_pages); size = PAGE_ALIGN(size); free_pages((unsigned long)vaddr, get_order(size)); @@ -1086,7 +1090,7 @@ void iommu_tce_kill(struct iommu_table *tbl, } EXPORT_SYMBOL_GPL(iommu_tce_kill); -int iommu_take_ownership(struct iommu_table *tbl) +static int iommu_take_ownership(struct iommu_table *tbl) { unsigned long flags, i, sz = (tbl->it_size + 7) >> 3; int ret = 0; @@ -1118,9 +1122,8 @@ int iommu_take_ownership(struct iommu_table *tbl) return ret; } -EXPORT_SYMBOL_GPL(iommu_take_ownership); -void iommu_release_ownership(struct iommu_table *tbl) +static void iommu_release_ownership(struct iommu_table *tbl) { unsigned long flags, i, sz = (tbl->it_size + 7) >> 3; @@ -1137,7 +1140,6 @@ void iommu_release_ownership(struct iommu_table *tbl) spin_unlock(&tbl->pools[i].lock); spin_unlock_irqrestore(&tbl->large_pool.lock, flags); } -EXPORT_SYMBOL_GPL(iommu_release_ownership); int iommu_add_device(struct iommu_table_group *table_group, struct device *dev) { @@ -1158,25 +1160,243 @@ int iommu_add_device(struct iommu_table_group *table_group, struct device *dev) pr_debug("%s: Adding %s to iommu group %d\n", __func__, dev_name(dev), iommu_group_id(table_group->group)); - - return iommu_group_add_device(table_group->group, dev); + /* + * This is still not adding devices via the IOMMU bus notifier because + * of pcibios_init() from arch/powerpc/kernel/pci_64.c which calls + * pcibios_scan_phb() first (and this guy adds devices and triggers + * the notifier) and only then it calls pci_bus_add_devices() which + * configures DMA for buses which also creates PEs and IOMMU groups. + */ + return iommu_probe_device(dev); } EXPORT_SYMBOL_GPL(iommu_add_device); -void iommu_del_device(struct device *dev) +/* + * A simple iommu_table_group_ops which only allows reusing the existing + * iommu_table. This handles VFIO for POWER7 or the nested KVM. + * The ops does not allow creating windows and only allows reusing the existing + * one if it matches table_group->tce32_start/tce32_size/page_shift. + */ +static unsigned long spapr_tce_get_table_size(__u32 page_shift, + __u64 window_size, __u32 levels) { - /* - * Some devices might not have IOMMU table and group - * and we needn't detach them from the associated - * IOMMU groups - */ - if (!device_iommu_mapped(dev)) { - pr_debug("iommu_tce: skipping device %s with no tbl\n", - dev_name(dev)); - return; + unsigned long size; + + if (levels > 1) + return ~0U; + size = window_size >> (page_shift - 3); + return size; +} + +static long spapr_tce_create_table(struct iommu_table_group *table_group, int num, + __u32 page_shift, __u64 window_size, __u32 levels, + struct iommu_table **ptbl) +{ + struct iommu_table *tbl = table_group->tables[0]; + + if (num > 0) + return -EPERM; + + if (tbl->it_page_shift != page_shift || + tbl->it_size != (window_size >> page_shift) || + tbl->it_indirect_levels != levels - 1) + return -EINVAL; + + *ptbl = iommu_tce_table_get(tbl); + return 0; +} + +static long spapr_tce_set_window(struct iommu_table_group *table_group, + int num, struct iommu_table *tbl) +{ + return tbl == table_group->tables[num] ? 0 : -EPERM; +} + +static long spapr_tce_unset_window(struct iommu_table_group *table_group, int num) +{ + return 0; +} + +static long spapr_tce_take_ownership(struct iommu_table_group *table_group) +{ + int i, j, rc = 0; + + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + struct iommu_table *tbl = table_group->tables[i]; + + if (!tbl || !tbl->it_map) + continue; + + rc = iommu_take_ownership(tbl); + if (!rc) + continue; + + for (j = 0; j < i; ++j) + iommu_release_ownership(table_group->tables[j]); + return rc; + } + return 0; +} + +static void spapr_tce_release_ownership(struct iommu_table_group *table_group) +{ + int i; + + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + struct iommu_table *tbl = table_group->tables[i]; + + if (!tbl) + continue; + + iommu_table_clear(tbl); + if (tbl->it_map) + iommu_release_ownership(tbl); + } +} + +struct iommu_table_group_ops spapr_tce_table_group_ops = { + .get_table_size = spapr_tce_get_table_size, + .create_table = spapr_tce_create_table, + .set_window = spapr_tce_set_window, + .unset_window = spapr_tce_unset_window, + .take_ownership = spapr_tce_take_ownership, + .release_ownership = spapr_tce_release_ownership, +}; + +/* + * A simple iommu_ops to allow less cruft in generic VFIO code. + */ +static int spapr_tce_blocking_iommu_attach_dev(struct iommu_domain *dom, + struct device *dev) +{ + struct iommu_group *grp = iommu_group_get(dev); + struct iommu_table_group *table_group; + int ret = -EINVAL; + + if (!grp) + return -ENODEV; + + table_group = iommu_group_get_iommudata(grp); + ret = table_group->ops->take_ownership(table_group); + iommu_group_put(grp); + + return ret; +} + +static void spapr_tce_blocking_iommu_set_platform_dma(struct device *dev) +{ + struct iommu_group *grp = iommu_group_get(dev); + struct iommu_table_group *table_group; + + table_group = iommu_group_get_iommudata(grp); + table_group->ops->release_ownership(table_group); +} + +static const struct iommu_domain_ops spapr_tce_blocking_domain_ops = { + .attach_dev = spapr_tce_blocking_iommu_attach_dev, +}; + +static bool spapr_tce_iommu_capable(struct device *dev, enum iommu_cap cap) +{ + switch (cap) { + case IOMMU_CAP_CACHE_COHERENCY: + return true; + default: + break; } - iommu_group_remove_device(dev); + return false; } -EXPORT_SYMBOL_GPL(iommu_del_device); + +static struct iommu_domain *spapr_tce_iommu_domain_alloc(unsigned int type) +{ + struct iommu_domain *dom; + + if (type != IOMMU_DOMAIN_BLOCKED) + return NULL; + + dom = kzalloc(sizeof(*dom), GFP_KERNEL); + if (!dom) + return NULL; + + dom->ops = &spapr_tce_blocking_domain_ops; + + return dom; +} + +static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev) +{ + struct pci_dev *pdev; + struct pci_controller *hose; + + if (!dev_is_pci(dev)) + return ERR_PTR(-EPERM); + + pdev = to_pci_dev(dev); + hose = pdev->bus->sysdata; + + return &hose->iommu; +} + +static void spapr_tce_iommu_release_device(struct device *dev) +{ +} + +static struct iommu_group *spapr_tce_iommu_device_group(struct device *dev) +{ + struct pci_controller *hose; + struct pci_dev *pdev; + + pdev = to_pci_dev(dev); + hose = pdev->bus->sysdata; + + if (!hose->controller_ops.device_group) + return ERR_PTR(-ENOENT); + + return hose->controller_ops.device_group(hose, pdev); +} + +static const struct iommu_ops spapr_tce_iommu_ops = { + .capable = spapr_tce_iommu_capable, + .domain_alloc = spapr_tce_iommu_domain_alloc, + .probe_device = spapr_tce_iommu_probe_device, + .release_device = spapr_tce_iommu_release_device, + .device_group = spapr_tce_iommu_device_group, + .set_platform_dma_ops = spapr_tce_blocking_iommu_set_platform_dma, +}; + +static struct attribute *spapr_tce_iommu_attrs[] = { + NULL, +}; + +static struct attribute_group spapr_tce_iommu_group = { + .name = "spapr-tce-iommu", + .attrs = spapr_tce_iommu_attrs, +}; + +static const struct attribute_group *spapr_tce_iommu_groups[] = { + &spapr_tce_iommu_group, + NULL, +}; + +/* + * This registers IOMMU devices of PHBs. This needs to happen + * after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and + * before subsys_initcall(iommu_subsys_init). + */ +static int __init spapr_tce_setup_phb_iommus_initcall(void) +{ + struct pci_controller *hose; + + list_for_each_entry(hose, &hose_list, list_node) { + iommu_device_sysfs_add(&hose->iommu, hose->parent, + spapr_tce_iommu_groups, "iommu-phb%04x", + hose->global_number); + iommu_device_register(&hose->iommu, &spapr_tce_iommu_ops, + hose->parent); + } + return 0; +} +postcore_initcall_sync(spapr_tce_setup_phb_iommus_initcall); + #endif /* CONFIG_IOMMU_API */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c9535f2760b5..6f7d4edaa0bc 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -206,7 +206,11 @@ static __always_inline void call_do_softirq(const void *sp) asm volatile ( PPC_STLU " %%r1, %[offset](%[sp]) ;" "mr %%r1, %[sp] ;" +#ifdef CONFIG_PPC_KERNEL_PCREL + "bl %[callee]@notoc ;" +#else "bl %[callee] ;" +#endif PPC_LL " %%r1, 0(%%r1) ;" : // Outputs : // Inputs @@ -259,7 +263,11 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) PPC_STLU " %%r1, %[offset](%[sp]) ;" "mr %%r4, %%r1 ;" "mr %%r1, %[sp] ;" +#ifdef CONFIG_PPC_KERNEL_PCREL + "bl %[callee]@notoc ;" +#else "bl %[callee] ;" +#endif PPC_LL " %%r1, 0(%%r1) ;" : // Outputs "+r" (r3) diff --git a/arch/powerpc/kernel/irq_64.c b/arch/powerpc/kernel/irq_64.c index c788c55512ed..938e66829eae 100644 --- a/arch/powerpc/kernel/irq_64.c +++ b/arch/powerpc/kernel/irq_64.c @@ -348,13 +348,12 @@ EXPORT_SYMBOL(arch_local_irq_restore); * already the case when ppc_md.power_save is called). The function * will return whether to enter power save or just return. * - * In the former case, it will have notified lockdep of interrupts - * being re-enabled and generally sanitized the lazy irq state, - * and in the latter case it will leave with interrupts hard + * In the former case, it will have generally sanitized the lazy irq + * state, and in the latter case it will leave with interrupts hard * disabled and marked as such, so the local_irq_enable() call * in arch_cpu_idle() will properly re-enable everything. */ -bool prep_irq_for_idle(void) +__cpuidle bool prep_irq_for_idle(void) { /* * First we need to hard disable to ensure no interrupt @@ -370,9 +369,6 @@ bool prep_irq_for_idle(void) if (lazy_irq_pending()) return false; - /* Tell lockdep we are about to re-enable */ - trace_hardirqs_on(); - /* * Mark interrupts as soft-enabled and clear the * PACA_IRQ_HARD_DIS from the pending mask since we diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index dc746611ebc0..48e0eaf1ad61 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c @@ -55,80 +55,50 @@ static void remap_isa_base(phys_addr_t pa, unsigned long size) } } -static void pci_process_ISA_OF_ranges(struct device_node *isa_node, - unsigned long phb_io_base_phys) +static int process_ISA_OF_ranges(struct device_node *isa_node, + unsigned long phb_io_base_phys) { - /* We should get some saner parsing here and remove these structs */ - struct pci_address { - u32 a_hi; - u32 a_mid; - u32 a_lo; - }; - - struct isa_address { - u32 a_hi; - u32 a_lo; - }; - - struct isa_range { - struct isa_address isa_addr; - struct pci_address pci_addr; - unsigned int size; - }; - - const struct isa_range *range; - unsigned long pci_addr; - unsigned int isa_addr; unsigned int size; - int rlen = 0; + struct of_range_parser parser; + struct of_range range; - range = of_get_property(isa_node, "ranges", &rlen); - if (range == NULL || (rlen < sizeof(struct isa_range))) + if (of_range_parser_init(&parser, isa_node)) goto inval_range; - /* From "ISA Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 1: an ISA address - * cells 2 - 4: a PCI address - * (size depending on dev->n_addr_cells) - * cell 5: the size of the range - */ - if ((range->isa_addr.a_hi & ISA_SPACE_MASK) != ISA_SPACE_IO) { - range++; - rlen -= sizeof(struct isa_range); - if (rlen < sizeof(struct isa_range)) - goto inval_range; + for_each_of_range(&parser, &range) { + if ((range.flags & ISA_SPACE_MASK) != ISA_SPACE_IO) + continue; + + if (range.cpu_addr == OF_BAD_ADDR) { + pr_err("ISA: Bad CPU mapping: %s\n", __func__); + return -EINVAL; + } + + /* We need page alignment */ + if ((range.bus_addr & ~PAGE_MASK) || (range.cpu_addr & ~PAGE_MASK)) { + pr_warn("ISA: bridge %pOF has non aligned IO range\n", isa_node); + return -EINVAL; + } + + /* Align size and make sure it's cropped to 64K */ + size = PAGE_ALIGN(range.size); + if (size > 0x10000) + size = 0x10000; + + if (!phb_io_base_phys) + phb_io_base_phys = range.cpu_addr; + + remap_isa_base(phb_io_base_phys, size); + return 0; } - if ((range->isa_addr.a_hi & ISA_SPACE_MASK) != ISA_SPACE_IO) - goto inval_range; - - isa_addr = range->isa_addr.a_lo; - pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | - range->pci_addr.a_lo; - - /* Assume these are both zero. Note: We could fix that and - * do a proper parsing instead ... oh well, that will do for - * now as nobody uses fancy mappings for ISA bridges - */ - if ((pci_addr != 0) || (isa_addr != 0)) { - printk(KERN_ERR "unexpected isa to pci mapping: %s\n", - __func__); - return; - } - - /* Align size and make sure it's cropped to 64K */ - size = PAGE_ALIGN(range->size); - if (size > 0x10000) - size = 0x10000; - - remap_isa_base(phb_io_base_phys, size); - return; inval_range: - printk(KERN_ERR "no ISA IO ranges or unexpected isa range, " - "mapping 64k\n"); - remap_isa_base(phb_io_base_phys, 0x10000); + if (phb_io_base_phys) { + pr_err("no ISA IO ranges or unexpected isa range, mapping 64k\n"); + remap_isa_base(phb_io_base_phys, 0x10000); + return 0; + } + return -EINVAL; } @@ -170,7 +140,7 @@ void __init isa_bridge_find_early(struct pci_controller *hose) isa_bridge_devnode = np; /* Now parse the "ranges" property and setup the ISA mapping */ - pci_process_ISA_OF_ranges(np, hose->io_base_phys); + process_ISA_OF_ranges(np, hose->io_base_phys); /* Set the global ISA io base to indicate we have an ISA bridge */ isa_io_base = ISA_IO_BASE; @@ -186,75 +156,15 @@ void __init isa_bridge_find_early(struct pci_controller *hose) */ void __init isa_bridge_init_non_pci(struct device_node *np) { - const __be32 *ranges, *pbasep = NULL; - int rlen, i, rs; - u32 na, ns, pna; - u64 cbase, pbase, size = 0; + int ret; /* If we already have an ISA bridge, bail off */ if (isa_bridge_devnode != NULL) return; - pna = of_n_addr_cells(np); - if (of_property_read_u32(np, "#address-cells", &na) || - of_property_read_u32(np, "#size-cells", &ns)) { - pr_warn("ISA: Non-PCI bridge %pOF is missing address format\n", - np); + ret = process_ISA_OF_ranges(np, 0); + if (ret) return; - } - - /* Check it's a supported address format */ - if (na != 2 || ns != 1) { - pr_warn("ISA: Non-PCI bridge %pOF has unsupported address format\n", - np); - return; - } - rs = na + ns + pna; - - /* Grab the ranges property */ - ranges = of_get_property(np, "ranges", &rlen); - if (ranges == NULL || rlen < rs) { - pr_warn("ISA: Non-PCI bridge %pOF has absent or invalid ranges\n", - np); - return; - } - - /* Parse it. We are only looking for IO space */ - for (i = 0; (i + rs - 1) < rlen; i += rs) { - if (be32_to_cpup(ranges + i) != 1) - continue; - cbase = be32_to_cpup(ranges + i + 1); - size = of_read_number(ranges + i + na + pna, ns); - pbasep = ranges + i + na; - break; - } - - /* Got something ? */ - if (!size || !pbasep) { - pr_warn("ISA: Non-PCI bridge %pOF has no usable IO range\n", - np); - return; - } - - /* Align size and make sure it's cropped to 64K */ - size = PAGE_ALIGN(size); - if (size > 0x10000) - size = 0x10000; - - /* Map pbase */ - pbase = of_translate_address(np, pbasep); - if (pbase == OF_BAD_ADDR) { - pr_warn("ISA: Non-PCI bridge %pOF failed to translate IO base\n", - np); - return; - } - - /* We need page alignment */ - if ((cbase & ~PAGE_MASK) || (pbase & ~PAGE_MASK)) { - pr_warn("ISA: Non-PCI bridge %pOF has non aligned IO range\n", - np); - return; - } /* Got it */ isa_bridge_devnode = np; @@ -263,7 +173,6 @@ void __init isa_bridge_init_non_pci(struct device_node *np) * and map it */ isa_io_base = ISA_IO_BASE; - remap_isa_base(pbase, size); pr_debug("ISA: Non-PCI bridge is %pOF\n", np); } @@ -282,7 +191,7 @@ static void isa_bridge_find_late(struct pci_dev *pdev, isa_bridge_pcidev = pdev; /* Now parse the "ranges" property and setup the ISA mapping */ - pci_process_ISA_OF_ranges(devnode, hose->io_base_phys); + process_ISA_OF_ranges(devnode, hose->io_base_phys); /* Set the global ISA io base to indicate we have an ISA bridge */ isa_io_base = ISA_IO_BASE; diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index f048c424c525..c9ad12461d44 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -171,15 +171,15 @@ static int __init add_legacy_soc_port(struct device_node *np, /* We only support ports that have a clock frequency properly * encoded in the device-tree. */ - if (of_get_property(np, "clock-frequency", NULL) == NULL) + if (!of_property_present(np, "clock-frequency")) return -1; /* if reg-offset don't try to use it */ - if ((of_get_property(np, "reg-offset", NULL) != NULL)) + if (of_property_present(np, "reg-offset")) return -1; /* if rtas uses this device, don't try to use it as well */ - if (of_get_property(np, "used-by-rtas", NULL) != NULL) + if (of_property_read_bool(np, "used-by-rtas")) return -1; /* Get the address */ @@ -237,7 +237,7 @@ static int __init add_legacy_isa_port(struct device_node *np, * Note: Don't even try on P8 lpc, we know it's not directly mapped */ if (!of_device_is_compatible(isa_brg, "ibm,power8-lpc") || - of_get_property(isa_brg, "ranges", NULL)) { + of_property_present(isa_brg, "ranges")) { taddr = of_translate_address(np, reg); if (taddr == OF_BAD_ADDR) taddr = 0; @@ -268,7 +268,7 @@ static int __init add_legacy_pci_port(struct device_node *np, * compatible UARTs on PCI need all sort of quirks (port offsets * etc...) that this code doesn't know about */ - if (of_get_property(np, "clock-frequency", NULL) == NULL) + if (!of_property_present(np, "clock-frequency")) return -1; /* Get the PCI address. Assume BAR 0 */ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index c39c07a4c06e..2c9ac70aaf0c 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -432,7 +432,7 @@ _GLOBAL(kexec_sequence) 1: /* copy dest pages, flush whole dest image */ mr r3,r29 - bl kexec_copy_flush /* (image) */ + bl CFUNC(kexec_copy_flush) /* (image) */ /* turn off mmu now if not done earlier */ cmpdi r26,0 diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index ea6536171778..816a63fd71fb 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -163,8 +163,7 @@ static uint32_t do_plt_call(void *location, pr_debug("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); /* Init, or core PLT? */ - if (location >= mod->core_layout.base - && location < mod->core_layout.base + mod->core_layout.size) + if (within_module_core((unsigned long)location, mod)) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; else entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; @@ -322,14 +321,14 @@ notrace int module_trampoline_target(struct module *mod, unsigned long addr, int module_finalize_ftrace(struct module *module, const Elf_Shdr *sechdrs) { - module->arch.tramp = do_plt_call(module->core_layout.base, + module->arch.tramp = do_plt_call(module->mem[MOD_TEXT].base, (unsigned long)ftrace_caller, sechdrs, module); if (!module->arch.tramp) return -ENOENT; #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS - module->arch.tramp_regs = do_plt_call(module->core_layout.base, + module->arch.tramp_regs = do_plt_call(module->mem[MOD_TEXT].base, (unsigned long)ftrace_regs_caller, sechdrs, module); if (!module->arch.tramp_regs) diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 2ac78d207f77..92570289ce08 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -101,32 +101,45 @@ static unsigned long stub_func_addr(func_desc_t func) /* Like PPC32, we need little trampolines to do > 24-bit jumps (into the kernel itself). But on PPC64, these need to be used for every jump, actually, to reset r2 (TOC+0x8000). */ -struct ppc64_stub_entry -{ - /* 28 byte jump instruction sequence (7 instructions). We only - * need 6 instructions on ABIv2 but we always allocate 7 so - * so we don't have to modify the trampoline load instruction. */ +struct ppc64_stub_entry { + /* + * 28 byte jump instruction sequence (7 instructions) that can + * hold ppc64_stub_insns or stub_insns. Must be 8-byte aligned + * with PCREL kernels that use prefix instructions in the stub. + */ u32 jump[7]; /* Used by ftrace to identify stubs */ u32 magic; /* Data for the above code */ func_desc_t funcdata; +} __aligned(8); + +struct ppc64_got_entry { + u64 addr; }; /* * PPC64 uses 24 bit jumps, but we need to jump into other modules or * the kernel which may be further. So we jump to a stub. * - * For ELFv1 we need to use this to set up the new r2 value (aka TOC - * pointer). For ELFv2 it's the callee's responsibility to set up the - * new r2, but for both we need to save the old r2. + * Target address and TOC are loaded from function descriptor in the + * ppc64_stub_entry. * - * We could simply patch the new r2 value and function pointer into - * the stub, but it's significantly shorter to put these values at the - * end of the stub code, and patch the stub address (32-bits relative - * to the TOC ptr, r2) into the stub. + * r12 is used to generate the target address, which is required for the + * ELFv2 global entry point calling convention. + * + * TOC handling: + * - PCREL does not have a TOC. + * - ELFv2 non-PCREL just has to save r2, the callee is responsible for + * setting its own TOC pointer at the global entry address. + * - ELFv1 must load the new TOC pointer from the function descriptor. */ static u32 ppc64_stub_insns[] = { +#ifdef CONFIG_PPC_KERNEL_PCREL + /* pld r12,addr */ + PPC_PREFIX_8LS | __PPC_PRFX_R(1), + PPC_INST_PLD | ___PPC_RT(_R12), +#else PPC_RAW_ADDIS(_R11, _R2, 0), PPC_RAW_ADDI(_R11, _R11, 0), /* Save current r2 value in magic place on the stack. */ @@ -135,14 +148,18 @@ static u32 ppc64_stub_insns[] = { #ifdef CONFIG_PPC64_ELF_ABI_V1 /* Set up new r2 from function descriptor */ PPC_RAW_LD(_R2, _R11, 40), +#endif #endif PPC_RAW_MTCTR(_R12), PPC_RAW_BCTR(), }; -/* Count how many different 24-bit relocations (different symbol, - different addend) */ -static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num) +/* + * Count how many different r_type relocations (different symbol, + * different addend). + */ +static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num, + unsigned long r_type) { unsigned int i, r_info, r_addend, _count_relocs; @@ -151,8 +168,8 @@ static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num) r_info = 0; r_addend = 0; for (i = 0; i < num; i++) - /* Only count 24-bit relocs, others don't need stubs */ - if (ELF64_R_TYPE(rela[i].r_info) == R_PPC_REL24 && + /* Only count r_type relocs, others don't need stubs */ + if (ELF64_R_TYPE(rela[i].r_info) == r_type && (r_info != ELF64_R_SYM(rela[i].r_info) || r_addend != rela[i].r_addend)) { _count_relocs++; @@ -213,7 +230,14 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, relocs += count_relocs((void *)sechdrs[i].sh_addr, sechdrs[i].sh_size - / sizeof(Elf64_Rela)); + / sizeof(Elf64_Rela), + R_PPC_REL24); +#ifdef CONFIG_PPC_KERNEL_PCREL + relocs += count_relocs((void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size + / sizeof(Elf64_Rela), + R_PPC64_REL24_NOTOC); +#endif } } @@ -230,6 +254,95 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, return relocs * sizeof(struct ppc64_stub_entry); } +#ifdef CONFIG_PPC_KERNEL_PCREL +static int count_pcpu_relocs(const Elf64_Shdr *sechdrs, + const Elf64_Rela *rela, unsigned int num, + unsigned int symindex, unsigned int pcpu) +{ + unsigned int i, r_info, r_addend, _count_relocs; + + _count_relocs = 0; + r_info = 0; + r_addend = 0; + + for (i = 0; i < num; i++) { + Elf64_Sym *sym; + + /* This is the symbol it is referring to */ + sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + + ELF64_R_SYM(rela[i].r_info); + + if (sym->st_shndx == pcpu && + (r_info != ELF64_R_SYM(rela[i].r_info) || + r_addend != rela[i].r_addend)) { + _count_relocs++; + r_info = ELF64_R_SYM(rela[i].r_info); + r_addend = rela[i].r_addend; + } + } + + return _count_relocs; +} + +/* Get size of potential GOT required. */ +static unsigned long get_got_size(const Elf64_Ehdr *hdr, + const Elf64_Shdr *sechdrs, + struct module *me) +{ + /* One extra reloc so it's always 0-addr terminated */ + unsigned long relocs = 1; + unsigned int i, symindex = 0; + + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_type == SHT_SYMTAB) { + symindex = i; + break; + } + } + WARN_ON_ONCE(!symindex); + + /* Every relocated section... */ + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_type == SHT_RELA) { + pr_debug("Found relocations in section %u\n", i); + pr_debug("Ptr: %p. Number: %llu\n", (void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size / sizeof(Elf64_Rela)); + + /* + * Sort the relocation information based on a symbol and + * addend key. This is a stable O(n*log n) complexity + * algorithm but it will reduce the complexity of + * count_relocs() to linear complexity O(n) + */ + sort((void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size / sizeof(Elf64_Rela), + sizeof(Elf64_Rela), relacmp, NULL); + + relocs += count_relocs((void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size + / sizeof(Elf64_Rela), + R_PPC64_GOT_PCREL34); + + /* + * Percpu data access typically gets linked with + * REL34 relocations, but the percpu section gets + * moved at load time and requires that to be + * converted to GOT linkage. + */ + if (IS_ENABLED(CONFIG_SMP) && symindex) + relocs += count_pcpu_relocs(sechdrs, + (void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size + / sizeof(Elf64_Rela), + symindex, me->arch.pcpu_section); + } + } + + pr_debug("Looks like a total of %lu GOT entries, max\n", relocs); + return relocs * sizeof(struct ppc64_got_entry); +} +#else /* CONFIG_PPC_KERNEL_PCREL */ + /* Still needed for ELFv2, for .TOC. */ static void dedotify_versions(struct modversion_info *vers, unsigned long size) @@ -279,6 +392,7 @@ static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs, } return NULL; } +#endif /* CONFIG_PPC_KERNEL_PCREL */ bool module_init_section(const char *name) { @@ -297,6 +411,15 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, for (i = 1; i < hdr->e_shnum; i++) { if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0) me->arch.stubs_section = i; +#ifdef CONFIG_PPC_KERNEL_PCREL + else if (strcmp(secstrings + sechdrs[i].sh_name, ".data..percpu") == 0) + me->arch.pcpu_section = i; + else if (strcmp(secstrings + sechdrs[i].sh_name, ".mygot") == 0) { + me->arch.got_section = i; + if (sechdrs[i].sh_addralign < 8) + sechdrs[i].sh_addralign = 8; + } +#else else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0) { me->arch.toc_section = i; if (sechdrs[i].sh_addralign < 8) @@ -311,6 +434,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, sechdrs[i].sh_size / sizeof(Elf64_Sym), (void *)hdr + sechdrs[sechdrs[i].sh_link].sh_offset); +#endif } if (!me->arch.stubs_section) { @@ -318,26 +442,47 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, return -ENOEXEC; } +#ifdef CONFIG_PPC_KERNEL_PCREL + if (!me->arch.got_section) { + pr_err("%s: doesn't contain .mygot.\n", me->name); + return -ENOEXEC; + } + + /* Override the got size */ + sechdrs[me->arch.got_section].sh_size = get_got_size(hdr, sechdrs, me); +#else /* If we don't have a .toc, just use .stubs. We need to set r2 to some reasonable value in case the module calls out to other functions via a stub, or if a function pointer escapes the module by some means. */ if (!me->arch.toc_section) me->arch.toc_section = me->arch.stubs_section; +#endif /* Override the stubs size */ sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs); + return 0; } #ifdef CONFIG_MPROFILE_KERNEL static u32 stub_insns[] = { +#ifdef CONFIG_PPC_KERNEL_PCREL + PPC_RAW_LD(_R12, _R13, offsetof(struct paca_struct, kernelbase)), + PPC_RAW_NOP(), /* align the prefix insn */ + /* paddi r12,r12,addr */ + PPC_PREFIX_MLS | __PPC_PRFX_R(0), + PPC_INST_PADDI | ___PPC_RT(_R12) | ___PPC_RA(_R12), + PPC_RAW_MTCTR(_R12), + PPC_RAW_BCTR(), +#else PPC_RAW_LD(_R12, _R13, offsetof(struct paca_struct, kernel_toc)), PPC_RAW_ADDIS(_R12, _R12, 0), PPC_RAW_ADDI(_R12, _R12, 0), PPC_RAW_MTCTR(_R12), PPC_RAW_BCTR(), +#endif }; /* @@ -358,18 +503,37 @@ static inline int create_ftrace_stub(struct ppc64_stub_entry *entry, { long reladdr; - memcpy(entry->jump, stub_insns, sizeof(stub_insns)); - - /* Stub uses address relative to kernel toc (from the paca) */ - reladdr = addr - kernel_toc_addr(); - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { - pr_err("%s: Address of %ps out of range of kernel_toc.\n", - me->name, (void *)addr); + if ((unsigned long)entry->jump % 8 != 0) { + pr_err("%s: Address of stub entry is not 8-byte aligned\n", me->name); return 0; } - entry->jump[1] |= PPC_HA(reladdr); - entry->jump[2] |= PPC_LO(reladdr); + BUILD_BUG_ON(sizeof(stub_insns) > sizeof(entry->jump)); + memcpy(entry->jump, stub_insns, sizeof(stub_insns)); + + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + /* Stub uses address relative to kernel base (from the paca) */ + reladdr = addr - local_paca->kernelbase; + if (reladdr > 0x1FFFFFFFFL || reladdr < -0x200000000L) { + pr_err("%s: Address of %ps out of range of 34-bit relative address.\n", + me->name, (void *)addr); + return 0; + } + + entry->jump[2] |= IMM_H18(reladdr); + entry->jump[3] |= IMM_L(reladdr); + } else { + /* Stub uses address relative to kernel toc (from the paca) */ + reladdr = addr - kernel_toc_addr(); + if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { + pr_err("%s: Address of %ps out of range of kernel_toc.\n", + me->name, (void *)addr); + return 0; + } + + entry->jump[1] |= PPC_HA(reladdr); + entry->jump[2] |= PPC_LO(reladdr); + } /* Even though we don't use funcdata in the stub, it's needed elsewhere. */ entry->funcdata = func_desc(addr); @@ -415,7 +579,11 @@ static bool is_mprofile_ftrace_call(const char *name) */ static inline unsigned long my_r2(const Elf64_Shdr *sechdrs, struct module *me) { +#ifndef CONFIG_PPC_KERNEL_PCREL return (sechdrs[me->arch.toc_section].sh_addr & ~0xfful) + 0x8000; +#else + return -1; +#endif } /* Patch stub to reference function and correct r2 value. */ @@ -432,28 +600,53 @@ static inline int create_stub(const Elf64_Shdr *sechdrs, if (is_mprofile_ftrace_call(name)) return create_ftrace_stub(entry, addr, me); + if ((unsigned long)entry->jump % 8 != 0) { + pr_err("%s: Address of stub entry is not 8-byte aligned\n", me->name); + return 0; + } + + BUILD_BUG_ON(sizeof(ppc64_stub_insns) > sizeof(entry->jump)); for (i = 0; i < ARRAY_SIZE(ppc64_stub_insns); i++) { if (patch_instruction(&entry->jump[i], ppc_inst(ppc64_stub_insns[i]))) return 0; } - /* Stub uses address relative to r2. */ - reladdr = (unsigned long)entry - my_r2(sechdrs, me); - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { - pr_err("%s: Address %p of stub out of range of %p.\n", - me->name, (void *)reladdr, (void *)my_r2); - return 0; + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + /* Stub uses address relative to itself! */ + reladdr = 0 + offsetof(struct ppc64_stub_entry, funcdata); + BUILD_BUG_ON(reladdr != 32); + if (reladdr > 0x1FFFFFFFFL || reladdr < -0x200000000L) { + pr_err("%s: Address of %p out of range of 34-bit relative address.\n", + me->name, (void *)reladdr); + return 0; + } + pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr); + + /* May not even need this if we're relative to 0 */ + if (patch_instruction(&entry->jump[0], + ppc_inst_prefix(entry->jump[0] | IMM_H18(reladdr), + entry->jump[1] | IMM_L(reladdr)))) + return 0; + + } else { + /* Stub uses address relative to r2. */ + reladdr = (unsigned long)entry - my_r2(sechdrs, me); + if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { + pr_err("%s: Address %p of stub out of range of %p.\n", + me->name, (void *)reladdr, (void *)my_r2); + return 0; + } + pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr); + + if (patch_instruction(&entry->jump[0], + ppc_inst(entry->jump[0] | PPC_HA(reladdr)))) + return 0; + + if (patch_instruction(&entry->jump[1], + ppc_inst(entry->jump[1] | PPC_LO(reladdr)))) + return 0; } - pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr); - - if (patch_instruction(&entry->jump[0], - ppc_inst(entry->jump[0] | PPC_HA(reladdr)))) - return 0; - - if (patch_instruction(&entry->jump[1], - ppc_inst(entry->jump[1] | PPC_LO(reladdr)))) - return 0; // func_desc_t is 8 bytes if ABIv2, else 16 bytes desc = func_desc(addr); @@ -497,6 +690,37 @@ static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs, return (unsigned long)&stubs[i]; } +#ifdef CONFIG_PPC_KERNEL_PCREL +/* Create GOT to load the location described in this ptr */ +static unsigned long got_for_addr(const Elf64_Shdr *sechdrs, + unsigned long addr, + struct module *me, + const char *name) +{ + struct ppc64_got_entry *got; + unsigned int i, num_got; + + if (!IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + return addr; + + num_got = sechdrs[me->arch.got_section].sh_size / sizeof(*got); + + /* Find this stub, or if that fails, the next avail. entry */ + got = (void *)sechdrs[me->arch.got_section].sh_addr; + for (i = 0; got[i].addr; i++) { + if (WARN_ON(i >= num_got)) + return 0; + + if (got[i].addr == addr) + return (unsigned long)&got[i]; + } + + got[i].addr = addr; + + return (unsigned long)&got[i]; +} +#endif + /* We expect a noop next: if it is, replace it with instruction to restore r2. */ static int restore_r2(const char *name, u32 *instruction, struct module *me) @@ -504,6 +728,9 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me) u32 *prev_insn = instruction - 1; u32 insn_val = *instruction; + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + return 0; + if (is_mprofile_ftrace_call(name)) return 0; @@ -549,6 +776,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, pr_debug("Applying ADD relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); +#ifndef CONFIG_PPC_KERNEL_PCREL /* First time we're called, we can fix up .TOC. */ if (!me->arch.toc_fixed) { sym = find_dot_toc(sechdrs, strtab, symindex); @@ -558,7 +786,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, sym->st_value = my_r2(sechdrs, me); me->arch.toc_fixed = true; } - +#endif for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -586,6 +814,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, *(unsigned long *)location = value; break; +#ifndef CONFIG_PPC_KERNEL_PCREL case R_PPC64_TOC: *(unsigned long *)location = my_r2(sechdrs, me); break; @@ -645,8 +874,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, = (*((uint16_t *) location) & ~0xffff) | (value & 0xffff); break; +#endif case R_PPC_REL24: +#ifdef CONFIG_PPC_KERNEL_PCREL + /* PCREL still generates REL24 for mcount */ + case R_PPC64_REL24_NOTOC: +#endif /* FIXME: Handle weak symbols here --RR */ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_LIVEPATCH) { @@ -694,6 +928,47 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, *(u32 *)location = value; break; +#ifdef CONFIG_PPC_KERNEL_PCREL + case R_PPC64_PCREL34: { + unsigned long absvalue = value; + + /* Convert value to relative */ + value -= (unsigned long)location; + + if (value + 0x200000000 > 0x3ffffffff) { + if (sym->st_shndx != me->arch.pcpu_section) { + pr_err("%s: REL34 %li out of range!\n", + me->name, (long)value); + return -ENOEXEC; + } + + /* + * per-cpu section is special cased because + * it is moved during loading, so has to be + * converted to use GOT. + */ + value = got_for_addr(sechdrs, absvalue, me, + strtab + sym->st_name); + if (!value) + return -ENOENT; + value -= (unsigned long)location; + + /* Turn pla into pld */ + if (patch_instruction((u32 *)location, + ppc_inst_prefix((*(u32 *)location & ~0x02000000), + (*((u32 *)location + 1) & ~0xf8000000) | 0xe4000000))) + return -EFAULT; + } + + if (patch_instruction((u32 *)location, + ppc_inst_prefix((*(u32 *)location & ~0x3ffff) | IMM_H18(value), + (*((u32 *)location + 1) & ~0xffff) | IMM_L(value)))) + return -EFAULT; + + break; + } + +#else case R_PPC64_TOCSAVE: /* * Marker reloc indicates we don't have to save r2. @@ -701,8 +976,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, * it. */ break; +#endif case R_PPC64_ENTRY: + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + break; + /* * Optimize ELFv2 large code model entry point if * the TOC is within 2GB range of current location. @@ -745,6 +1024,20 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | (value & 0xffff); break; +#ifdef CONFIG_PPC_KERNEL_PCREL + case R_PPC64_GOT_PCREL34: + value = got_for_addr(sechdrs, value, me, + strtab + sym->st_name); + if (!value) + return -ENOENT; + value -= (unsigned long)location; + ((uint32_t *)location)[0] = (((uint32_t *)location)[0] & ~0x3ffff) | + ((value >> 16) & 0x3ffff); + ((uint32_t *)location)[1] = (((uint32_t *)location)[1] & ~0xffff) | + (value & 0xffff); + break; +#endif + default: pr_err("%s: Unknown ADD relocation: %lu\n", me->name, diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index be8db402e963..cda4e00b67c1 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -191,7 +191,9 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) #endif new_paca->lock_token = 0x8000; new_paca->paca_index = cpu; +#ifndef CONFIG_PPC_KERNEL_PCREL new_paca->kernel_toc = kernel_toc_addr(); +#endif new_paca->kernelbase = (unsigned long) _stext; /* Only set MSR:IR/DR when MMU is initialized */ new_paca->kernel_msr = MSR_KERNEL & ~(MSR_IR | MSR_DR); diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index fd42059ae2a5..e27342ef128b 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -73,7 +73,7 @@ static int __init pcibios_init(void) return 0; } -subsys_initcall(pcibios_init); +subsys_initcall_sync(pcibios_init); int pcibios_unmap_io_space(struct pci_bus *bus) { diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 4b29ac5ddac6..1fefafb2b29b 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1630,7 +1630,7 @@ void arch_setup_new_exec(void) } #ifdef CONFIG_PPC64 -/** +/* * Assign a TIDR (thread ID) for task @t and set it in the thread * structure. For now, we only support setting TIDR for 'current' task. * @@ -1738,68 +1738,83 @@ static void setup_ksp_vsid(struct task_struct *p, unsigned long sp) */ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { - unsigned long clone_flags = args->flags; - unsigned long usp = args->stack; - unsigned long tls = args->tls; - struct pt_regs *childregs, *kregs; + struct pt_regs *kregs; /* Switch frame regs */ extern void ret_from_fork(void); extern void ret_from_fork_scv(void); - extern void ret_from_kernel_thread(void); + extern void ret_from_kernel_user_thread(void); + extern void start_kernel_thread(void); void (*f)(void); unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; - struct thread_info *ti = task_thread_info(p); #ifdef CONFIG_HAVE_HW_BREAKPOINT int i; #endif klp_init_thread_info(p); - /* Create initial stack frame. */ - sp -= STACK_USER_INT_FRAME_SIZE; - *(unsigned long *)(sp + STACK_INT_FRAME_MARKER) = STACK_FRAME_REGS_MARKER; - - /* Copy registers */ - childregs = (struct pt_regs *)(sp + STACK_INT_FRAME_REGS); - if (unlikely(args->fn)) { + if (unlikely(p->flags & PF_KTHREAD)) { /* kernel thread */ + + /* Create initial minimum stack frame. */ + sp -= STACK_FRAME_MIN_SIZE; ((unsigned long *)sp)[0] = 0; - memset(childregs, 0, sizeof(struct pt_regs)); - childregs->gpr[1] = sp + STACK_USER_INT_FRAME_SIZE; - /* function */ - if (args->fn) - childregs->gpr[14] = ppc_function_entry((void *)args->fn); -#ifdef CONFIG_PPC64 - clear_tsk_thread_flag(p, TIF_32BIT); - childregs->softe = IRQS_ENABLED; -#endif - childregs->gpr[15] = (unsigned long)args->fn_arg; + + f = start_kernel_thread; p->thread.regs = NULL; /* no user register state */ - ti->flags |= _TIF_RESTOREALL; - f = ret_from_kernel_thread; + clear_tsk_compat_task(p); } else { /* user thread */ - struct pt_regs *regs = current_pt_regs(); - *childregs = *regs; - if (usp) - childregs->gpr[1] = usp; - ((unsigned long *)sp)[0] = childregs->gpr[1]; - p->thread.regs = childregs; - /* 64s sets this in ret_from_fork */ - if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64)) - childregs->gpr[3] = 0; /* Result from fork() */ - if (clone_flags & CLONE_SETTLS) { - if (!is_32bit_task()) - childregs->gpr[13] = tls; + struct pt_regs *childregs; + + /* Create initial user return stack frame. */ + sp -= STACK_USER_INT_FRAME_SIZE; + *(unsigned long *)(sp + STACK_INT_FRAME_MARKER) = STACK_FRAME_REGS_MARKER; + + childregs = (struct pt_regs *)(sp + STACK_INT_FRAME_REGS); + + if (unlikely(args->fn)) { + /* + * A user space thread, but it first runs a kernel + * thread, and then returns as though it had called + * execve rather than fork, so user regs will be + * filled in (e.g., by kernel_execve()). + */ + ((unsigned long *)sp)[0] = 0; + memset(childregs, 0, sizeof(struct pt_regs)); +#ifdef CONFIG_PPC64 + childregs->softe = IRQS_ENABLED; +#endif + f = ret_from_kernel_user_thread; + } else { + struct pt_regs *regs = current_pt_regs(); + unsigned long clone_flags = args->flags; + unsigned long usp = args->stack; + + /* Copy registers */ + *childregs = *regs; + if (usp) + childregs->gpr[1] = usp; + ((unsigned long *)sp)[0] = childregs->gpr[1]; +#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG + WARN_ON_ONCE(childregs->softe != IRQS_ENABLED); +#endif + if (clone_flags & CLONE_SETTLS) { + unsigned long tls = args->tls; + + if (!is_32bit_task()) + childregs->gpr[13] = tls; + else + childregs->gpr[2] = tls; + } + + if (trap_is_scv(regs)) + f = ret_from_fork_scv; else - childregs->gpr[2] = tls; + f = ret_from_fork; } - if (trap_is_scv(regs)) - f = ret_from_fork_scv; - else - f = ret_from_fork; + childregs->msr &= ~(MSR_FP|MSR_VEC|MSR_VSX); + p->thread.regs = childregs; } - childregs->msr &= ~(MSR_FP|MSR_VEC|MSR_VSX); /* * The way this works is that at some point in the future @@ -1813,6 +1828,16 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) sp -= STACK_SWITCH_FRAME_SIZE; ((unsigned long *)sp)[0] = sp + STACK_SWITCH_FRAME_SIZE; kregs = (struct pt_regs *)(sp + STACK_SWITCH_FRAME_REGS); + kregs->nip = ppc_function_entry(f); + if (unlikely(args->fn)) { + /* + * Put kthread fn, arg parameters in non-volatile GPRs in the + * switch frame so they are loaded by _switch before it returns + * to ret_from_kernel_thread. + */ + kregs->gpr[14] = ppc_function_entry((void *)args->fn); + kregs->gpr[15] = (unsigned long)args->fn_arg; + } p->thread.ksp = sp; #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -1840,22 +1865,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) p->thread.dscr_inherit = current->thread.dscr_inherit; p->thread.dscr = mfspr(SPRN_DSCR); } - if (cpu_has_feature(CPU_FTR_HAS_PPR)) - childregs->ppr = DEFAULT_PPR; p->thread.tidr = 0; #endif - /* - * Run with the current AMR value of the kernel - */ -#ifdef CONFIG_PPC_PKEY - if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) - kregs->amr = AMR_KUAP_BLOCKED; - - if (mmu_has_feature(MMU_FTR_BOOK3S_KUEP)) - kregs->iamr = AMR_KUEP_BLOCKED; -#endif - kregs->nip = ppc_function_entry(f); return 0; } diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 31175b34856a..c087eeee320f 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,7 @@ struct rtas_filter { * functions are believed to have no users on * ppc64le, and we want to keep it that way. It does * not make sense for this to be set when @filter - * is false. + * is NULL. */ struct rtas_function { s32 token; @@ -453,6 +454,16 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { }, }; +/* + * Nearly all RTAS calls need to be serialized. All uses of the + * default rtas_args block must hold rtas_lock. + * + * Exceptions to the RTAS serialization requirement (e.g. stop-self) + * must use a separate rtas_args structure. + */ +static DEFINE_RAW_SPINLOCK(rtas_lock); +static struct rtas_args rtas_args; + /** * rtas_function_token() - RTAS function token lookup. * @handle: Function handle, e.g. RTAS_FN_EVENT_SCAN. @@ -560,6 +571,9 @@ static void __do_enter_rtas(struct rtas_args *args) static void __do_enter_rtas_trace(struct rtas_args *args) { const char *name = NULL; + + if (args == &rtas_args) + lockdep_assert_held(&rtas_lock); /* * If the tracepoints that consume the function name aren't * active, avoid the lookup. @@ -619,16 +633,6 @@ static void do_enter_rtas(struct rtas_args *args) struct rtas_t rtas; -/* - * Nearly all RTAS calls need to be serialized. All uses of the - * default rtas_args block must hold rtas_lock. - * - * Exceptions to the RTAS serialization requirement (e.g. stop-self) - * must use a separate rtas_args structure. - */ -static DEFINE_RAW_SPINLOCK(rtas_lock); -static struct rtas_args rtas_args; - DEFINE_SPINLOCK(rtas_data_buf_lock); EXPORT_SYMBOL_GPL(rtas_data_buf_lock); @@ -951,6 +955,8 @@ static char *__fetch_rtas_last_error(char *altbuf) u32 bufsz; char *buf = NULL; + lockdep_assert_held(&rtas_lock); + if (token == -1) return NULL; @@ -981,7 +987,7 @@ static char *__fetch_rtas_last_error(char *altbuf) buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); } if (buf) - memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); + memmove(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); } return buf; @@ -1016,6 +1022,23 @@ va_rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, do_enter_rtas(args); } +/** + * rtas_call_unlocked() - Invoke an RTAS firmware function without synchronization. + * @args: RTAS parameter block to be used for the call, must obey RTAS addressing + * constraints. + * @token: Identifies the function being invoked. + * @nargs: Number of input parameters. Does not include token. + * @nret: Number of output parameters, including the call status. + * @....: List of @nargs input parameters. + * + * Invokes the RTAS function indicated by @token, which the caller + * should obtain via rtas_function_token(). + * + * This function is similar to rtas_call(), but must be used with a + * limited set of RTAS calls specifically exempted from the general + * requirement that only one RTAS call may be in progress at any + * time. Examples include stop-self and ibm,nmi-interlock. + */ void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, ...) { va_list list; @@ -1091,6 +1114,7 @@ static bool token_is_restricted_errinjct(s32 token) */ int rtas_call(int token, int nargs, int nret, int *outputs, ...) { + struct pin_cookie cookie; va_list list; int i; unsigned long flags; @@ -1117,6 +1141,8 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) } raw_spin_lock_irqsave(&rtas_lock, flags); + cookie = lockdep_pin_lock(&rtas_lock); + /* We use the global rtas args buffer */ args = &rtas_args; @@ -1134,6 +1160,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) outputs[i] = be32_to_cpu(args->rets[i + 1]); ret = (nret > 0) ? be32_to_cpu(args->rets[0]) : 0; + lockdep_unpin_lock(&rtas_lock, cookie); raw_spin_unlock_irqrestore(&rtas_lock, flags); if (buff_copy) { @@ -1765,6 +1792,7 @@ err: /* We assume to be passed big endian arguments */ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) { + struct pin_cookie cookie; struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; @@ -1833,6 +1861,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) buff_copy = get_errorlog_buffer(); raw_spin_lock_irqsave(&rtas_lock, flags); + cookie = lockdep_pin_lock(&rtas_lock); rtas_args = args; do_enter_rtas(&rtas_args); @@ -1843,6 +1872,7 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) if (be32_to_cpu(args.rets[0]) == -1) errbuf = __fetch_rtas_last_error(buff_copy); + lockdep_unpin_lock(&rtas_lock, cookie); raw_spin_unlock_irqrestore(&rtas_lock, flags); if (buff_copy) { diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index e77734e5a127..d2a446216444 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -630,13 +630,14 @@ static __init void probe_machine(void) for (machine_id = &__machine_desc_start; machine_id < &__machine_desc_end; machine_id++) { - DBG(" %s ...", machine_id->name); + DBG(" %s ...\n", machine_id->name); + if (machine_id->compatible && !of_machine_is_compatible(machine_id->compatible)) + continue; memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls)); - if (ppc_md.probe()) { - DBG(" match !\n"); - break; - } - DBG("\n"); + if (ppc_md.probe && !ppc_md.probe()) + continue; + DBG(" %s match !\n", machine_id->name); + break; } /* What can we do if we didn't find ? */ if (machine_id >= &__machine_desc_end) { diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index b2e0d3ce4261..246201d0d879 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -480,7 +480,7 @@ void early_setup_secondary(void) #endif /* CONFIG_SMP */ -void panic_smp_self_stop(void) +void __noreturn panic_smp_self_stop(void) { hard_irq_disable(); spin_begin(); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 6b90f10a6c81..265801a3e94c 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -61,6 +61,8 @@ #include #include +#include + #ifdef DEBUG #include #define DBG(fmt...) udbg_printf(fmt) @@ -364,12 +366,12 @@ static inline void do_message_pass(int cpu, int msg) #endif } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { if (likely(smp_ops)) do_message_pass(cpu, PPC_MSG_RESCHEDULE); } -EXPORT_SYMBOL_GPL(smp_send_reschedule); +EXPORT_SYMBOL_GPL(arch_smp_send_reschedule); void arch_send_call_function_single_ipi(int cpu) { @@ -1611,7 +1613,7 @@ void start_secondary(void *unused) if (IS_ENABLED(CONFIG_PPC32)) setup_kup(); - mmgrab(&init_mm); + mmgrab_lazy_tlb(&init_mm); current->active_mm = &init_mm; smp_store_cpu_info(cpu); @@ -1752,7 +1754,7 @@ void __cpu_die(unsigned int cpu) smp_ops->cpu_die(cpu); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { /* * Disable on the down path. This will be re-enabled by diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index ef9a61718940..0f39a6b84132 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -217,13 +217,18 @@ static DEVICE_ATTR(dscr_default, 0600, static void __init sysfs_create_dscr_default(void) { if (cpu_has_feature(CPU_FTR_DSCR)) { + struct device *dev_root; int cpu; dscr_default = spr_default_dscr; for_each_possible_cpu(cpu) paca_ptrs[cpu]->dscr_default = dscr_default; - device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + device_create_file(dev_root, &dev_attr_dscr_default); + put_device(dev_root); + } } } #endif /* CONFIG_PPC64 */ @@ -746,7 +751,12 @@ static DEVICE_ATTR(svm, 0444, show_svm, NULL); static void __init create_svm_file(void) { - device_create_file(cpu_subsys.dev_root, &dev_attr_svm); + struct device *dev_root = bus_get_dev_root(&cpu_subsys); + + if (dev_root) { + device_create_file(dev_root, &dev_attr_svm); + put_device(dev_root); + } } #else static void __init create_svm_file(void) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 9d8665910350..df20cf201f74 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -887,7 +887,11 @@ void __init time_init(void) unsigned shift; /* Normal PowerPC with timebase register */ - ppc_md.calibrate_decr(); + if (ppc_md.calibrate_decr) + ppc_md.calibrate_decr(); + else + generic_calibrate_decr(); + printk(KERN_DEBUG "time_init: decrementer frequency = %lu.%.6lu MHz\n", ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n", diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c index 7b85c3b460a3..a47f30373423 100644 --- a/arch/powerpc/kernel/trace/ftrace.c +++ b/arch/powerpc/kernel/trace/ftrace.c @@ -194,6 +194,8 @@ __ftrace_make_nop(struct module *mod, * get corrupted. * * Use a b +8 to jump over the load. + * XXX: could make PCREL depend on MPROFILE_KERNEL + * XXX: check PCREL && MPROFILE_KERNEL calling sequence */ if (IS_ENABLED(CONFIG_MPROFILE_KERNEL) || IS_ENABLED(CONFIG_PPC32)) pop = ppc_inst(PPC_RAW_NOP()); @@ -725,6 +727,15 @@ int __init ftrace_dyn_arch_init(void) { int i; unsigned int *tramp[] = { ftrace_tramp_text, ftrace_tramp_init }; +#ifdef CONFIG_PPC_KERNEL_PCREL + u32 stub_insns[] = { + /* pla r12,addr */ + PPC_PREFIX_MLS | __PPC_PRFX_R(1), + PPC_INST_PADDI | ___PPC_RT(_R12), + PPC_RAW_MTCTR(_R12), + PPC_RAW_BCTR() + }; +#else u32 stub_insns[] = { PPC_RAW_LD(_R12, _R13, PACATOC), PPC_RAW_ADDIS(_R12, _R12, 0), @@ -732,6 +743,8 @@ int __init ftrace_dyn_arch_init(void) PPC_RAW_MTCTR(_R12), PPC_RAW_BCTR() }; +#endif + unsigned long addr; long reladdr; @@ -740,19 +753,36 @@ int __init ftrace_dyn_arch_init(void) else addr = ppc_global_function_entry((void *)ftrace_caller); - reladdr = addr - kernel_toc_addr(); + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + for (i = 0; i < 2; i++) { + reladdr = addr - (unsigned long)tramp[i]; - if (reladdr >= SZ_2G || reladdr < -(long)SZ_2G) { - pr_err("Address of %ps out of range of kernel_toc.\n", + if (reladdr >= (long)SZ_8G || reladdr < -(long)SZ_8G) { + pr_err("Address of %ps out of range of pcrel address.\n", + (void *)addr); + return -1; + } + + memcpy(tramp[i], stub_insns, sizeof(stub_insns)); + tramp[i][0] |= IMM_H18(reladdr); + tramp[i][1] |= IMM_L(reladdr); + add_ftrace_tramp((unsigned long)tramp[i]); + } + } else { + reladdr = addr - kernel_toc_addr(); + + if (reladdr >= (long)SZ_2G || reladdr < -(long)SZ_2G) { + pr_err("Address of %ps out of range of kernel_toc.\n", (void *)addr); - return -1; - } + return -1; + } - for (i = 0; i < 2; i++) { - memcpy(tramp[i], stub_insns, sizeof(stub_insns)); - tramp[i][1] |= PPC_HA(reladdr); - tramp[i][2] |= PPC_LO(reladdr); - add_ftrace_tramp((unsigned long)tramp[i]); + for (i = 0; i < 2; i++) { + memcpy(tramp[i], stub_insns, sizeof(stub_insns)); + tramp[i][1] |= PPC_HA(reladdr); + tramp[i][2] |= PPC_LO(reladdr); + add_ftrace_tramp((unsigned long)tramp[i]); + } } return 0; diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S index 0c4ecc8fec5a..48fc6658053a 100644 --- a/arch/powerpc/kernel/vdso/gettimeofday.S +++ b/arch/powerpc/kernel/vdso/gettimeofday.S @@ -38,7 +38,11 @@ .else addi r4, r5, VDSO_DATA_OFFSET .endif - bl DOTSYM(\funct) +#ifdef __powerpc64__ + bl CFUNC(DOTSYM(\funct)) +#else + bl \funct +#endif PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) #ifdef __powerpc64__ PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index ffe5d90abe17..fcc0ad6d9c7b 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -177,9 +177,15 @@ fpone: fphalf: .quad 0x3fe0000000000000 /* 0.5 */ +#ifdef CONFIG_PPC_KERNEL_PCREL +#define LDCONST(fr, name) \ + pla r11,name@pcrel; \ + lfd fr,0(r11) +#else #define LDCONST(fr, name) \ addis r11,r2,name@toc@ha; \ lfd fr,name@toc@l(r11) +#endif #endif .text /* diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index ee86753e444e..13614f0b269c 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -169,12 +169,18 @@ SECTIONS } #else /* CONFIG_PPC32 */ +#ifndef CONFIG_PPC_KERNEL_PCREL .toc1 : AT(ADDR(.toc1) - LOAD_OFFSET) { *(.toc1) } +#endif .got : AT(ADDR(.got) - LOAD_OFFSET) ALIGN(256) { +#ifdef CONFIG_PPC_KERNEL_PCREL + *(.got) +#else *(.got .toc) +#endif } SOFT_MASK_TABLE(8) diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 57f4e7896d67..686d8d9eda3e 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -188,10 +188,10 @@ void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) } EXPORT_SYMBOL_GPL(kvmppc_book3s_queue_irqprio); -void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_MACHINE_CHECK, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_MACHINE_CHECK, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_machine_check); @@ -201,29 +201,29 @@ void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL(kvmppc_core_queue_syscall); -void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_program); -void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, srr1_flags); } -void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_ALTIVEC, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_ALTIVEC, srr1_flags); } -void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_VSX, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_VSX, srr1_flags); } void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) @@ -278,18 +278,18 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); } -void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar, - ulong flags) +void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong srr1_flags, + ulong dar, ulong dsisr) { kvmppc_set_dar(vcpu, dar); - kvmppc_set_dsisr(vcpu, flags); - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0); + kvmppc_set_dsisr(vcpu, dsisr); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_data_storage); -void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong srr1_flags) { - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_inst_storage); @@ -481,20 +481,42 @@ int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, enum xlate_instdata xlid, return r; } +/* + * Returns prefixed instructions with the prefix in the high 32 bits + * of *inst and suffix in the low 32 bits. This is the same convention + * as used in HEIR, vcpu->arch.last_inst and vcpu->arch.emul_inst. + * Like vcpu->arch.last_inst but unlike vcpu->arch.emul_inst, each + * half of the value needs byte-swapping if the guest endianness is + * different from the host endianness. + */ int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *inst) + enum instruction_fetch_type type, unsigned long *inst) { ulong pc = kvmppc_get_pc(vcpu); int r; + u32 iw; if (type == INST_SC) pc -= 4; - r = kvmppc_ld(vcpu, &pc, sizeof(u32), inst, false); - if (r == EMULATE_DONE) - return r; - else + r = kvmppc_ld(vcpu, &pc, sizeof(u32), &iw, false); + if (r != EMULATE_DONE) return EMULATE_AGAIN; + /* + * If [H]SRR1 indicates that the instruction that caused the + * current interrupt is a prefixed instruction, get the suffix. + */ + if (kvmppc_get_msr(vcpu) & SRR1_PREFIXED) { + u32 suffix; + pc += 4; + r = kvmppc_ld(vcpu, &pc, sizeof(u32), &suffix, false); + if (r != EMULATE_DONE) + return EMULATE_AGAIN; + *inst = ((u64)iw << 32) | suffix; + } else { + *inst = iw; + } + return r; } EXPORT_SYMBOL_GPL(kvmppc_load_last_inst); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 7006bcbc2e37..7f765d5ad436 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -124,9 +124,9 @@ void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info) info->virt, (long)info->order, kvm->arch.lpid); } -long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) +int kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) { - long err = -EBUSY; + int err = -EBUSY; struct kvm_hpt_info info; mutex_lock(&kvm->arch.mmu_setup_lock); @@ -415,20 +415,25 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, * embodied here.) If the instruction isn't a load or store, then * this doesn't return anything useful. */ -static int instruction_is_store(unsigned int instr) +static int instruction_is_store(ppc_inst_t instr) { unsigned int mask; + unsigned int suffix; mask = 0x10000000; - if ((instr & 0xfc000000) == 0x7c000000) + suffix = ppc_inst_val(instr); + if (ppc_inst_prefixed(instr)) + suffix = ppc_inst_suffix(instr); + else if ((suffix & 0xfc000000) == 0x7c000000) mask = 0x100; /* major opcode 31 */ - return (instr & mask) != 0; + return (suffix & mask) != 0; } int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, unsigned long gpa, gva_t ea, int is_store) { - u32 last_inst; + ppc_inst_t last_inst; + bool is_prefixed = !!(kvmppc_get_msr(vcpu) & SRR1_PREFIXED); /* * Fast path - check if the guest physical address corresponds to a @@ -443,7 +448,7 @@ int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, NULL); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (!ret) { - kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); + kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + (is_prefixed ? 8 : 4)); return RESUME_GUEST; } } @@ -458,7 +463,16 @@ int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, /* * WARNING: We do not know for sure whether the instruction we just * read from memory is the same that caused the fault in the first - * place. If the instruction we read is neither an load or a store, + * place. + * + * If the fault is prefixed but the instruction is not or vice + * versa, try again so that we don't advance pc the wrong amount. + */ + if (ppc_inst_prefixed(last_inst) != is_prefixed) + return RESUME_GUEST; + + /* + * If the instruction we read is neither an load or a store, * then it can't access memory, so we don't need to worry about * enforcing access permissions. So, assuming it is a load or * store, we just check that its direction (load or store) is @@ -1468,8 +1482,8 @@ static void resize_hpt_prepare_work(struct work_struct *work) mutex_unlock(&kvm->arch.mmu_setup_lock); } -long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, - struct kvm_ppc_resize_hpt *rhpt) +int kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, + struct kvm_ppc_resize_hpt *rhpt) { unsigned long flags = rhpt->flags; unsigned long shift = rhpt->shift; @@ -1534,13 +1548,13 @@ static void resize_hpt_boot_vcpu(void *opaque) /* Nothing to do, just force a KVM exit */ } -long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, - struct kvm_ppc_resize_hpt *rhpt) +int kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, + struct kvm_ppc_resize_hpt *rhpt) { unsigned long flags = rhpt->flags; unsigned long shift = rhpt->shift; struct kvm_resize_hpt *resize; - long ret; + int ret; if (flags != 0 || kvm_is_radix(kvm)) return -EINVAL; diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 9d3743ca16d5..461307b89c3a 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -954,7 +954,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, if (dsisr & DSISR_BADACCESS) { /* Reflect to the guest as DSI */ pr_err("KVM: Got radix HV page fault with DSISR=%lx\n", dsisr); - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } @@ -979,7 +981,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, * Bad address in guest page table tree, or other * unusual error - reflect it to the guest as DSI. */ - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } return kvmppc_hv_emulate_mmio(vcpu, gpa, ea, writing); @@ -988,8 +992,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, if (memslot->flags & KVM_MEM_READONLY) { if (writing) { /* give the guest a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, DSISR_ISSTORE | - DSISR_PROTFAULT); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } kvm_ro = true; diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 95e738ef9062..93b695b289e9 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -288,8 +288,8 @@ static const struct file_operations kvm_spapr_tce_fops = { .release = kvm_spapr_tce_release, }; -long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, - struct kvm_create_spapr_tce_64 *args) +int kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, + struct kvm_create_spapr_tce_64 *args) { struct kvmppc_spapr_tce_table *stt = NULL; struct kvmppc_spapr_tce_table *siter; diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 6ba68dd6190b..130bafdb1430 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,8 @@ #include #include +#include + #include "book3s.h" #include "book3s_hv.h" @@ -474,7 +477,7 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu) for (r = 0; r < vcpu->arch.slb_max; ++r) pr_err(" ESID = %.16llx VSID = %.16llx\n", vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv); - pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n", + pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.16lx\n", vcpu->arch.vcore->lpcr, vcpu->kvm->arch.sdr1, vcpu->arch.last_inst); } @@ -1412,7 +1415,7 @@ static int kvmppc_hcall_impl_hv(unsigned long cmd) static int kvmppc_emulate_debug_inst(struct kvm_vcpu *vcpu) { - u32 last_inst; + ppc_inst_t last_inst; if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst) != EMULATE_DONE) { @@ -1423,12 +1426,13 @@ static int kvmppc_emulate_debug_inst(struct kvm_vcpu *vcpu) return RESUME_GUEST; } - if (last_inst == KVMPPC_INST_SW_BREAKPOINT) { + if (ppc_inst_val(last_inst) == KVMPPC_INST_SW_BREAKPOINT) { vcpu->run->exit_reason = KVM_EXIT_DEBUG; vcpu->run->debug.arch.address = kvmppc_get_pc(vcpu); return RESUME_HOST; } else { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); return RESUME_GUEST; } } @@ -1476,9 +1480,11 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu) unsigned long arg; struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *tvcpu; + ppc_inst_t pinst; - if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst) != EMULATE_DONE) + if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst) != EMULATE_DONE) return RESUME_GUEST; + inst = ppc_inst_val(pinst); if (get_op(inst) != 31) return EMULATE_FAIL; rb = get_rb(inst); @@ -1630,7 +1636,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * so that it knows that the machine check occurred. */ if (!vcpu->kvm->arch.fwnmi_enabled) { - ulong flags = vcpu->arch.shregs.msr & 0x083c0000; + ulong flags = (vcpu->arch.shregs.msr & 0x083c0000) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); kvmppc_core_queue_machine_check(vcpu, flags); r = RESUME_GUEST; break; @@ -1659,7 +1666,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * as a result of a hypervisor emulation interrupt * (e40) getting turned into a 700 by BML RTAS. */ - flags = vcpu->arch.shregs.msr & 0x1f0000ull; + flags = (vcpu->arch.shregs.msr & 0x1f0000ull) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); kvmppc_core_queue_program(vcpu, flags); r = RESUME_GUEST; break; @@ -1740,6 +1748,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (!(vcpu->arch.fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT))) { kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); r = RESUME_GUEST; break; @@ -1758,6 +1767,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, r = RESUME_PAGE_FAULT; } else { kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, vcpu->arch.fault_dar, err); r = RESUME_GUEST; } @@ -1785,7 +1795,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (!(vcpu->arch.fault_dsisr & SRR1_ISI_NOPT)) { kvmppc_core_queue_inst_storage(vcpu, - vcpu->arch.fault_dsisr); + vcpu->arch.fault_dsisr | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; break; } @@ -1802,7 +1813,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, } else if (err == -1) { r = RESUME_PAGE_FAULT; } else { - kvmppc_core_queue_inst_storage(vcpu, err); + kvmppc_core_queue_inst_storage(vcpu, + err | (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1823,7 +1835,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { r = kvmppc_emulate_debug_inst(vcpu); } else { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1864,7 +1877,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, r = kvmppc_tm_unavailable(vcpu); } if (r == EMULATE_FAIL) { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1994,14 +2008,15 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) */ if (!(vcpu->arch.hfscr_permitted & (1UL << cause)) || (vcpu->arch.nested_hfscr & (1UL << cause))) { + ppc_inst_t pinst; vcpu->arch.trap = BOOK3S_INTERRUPT_H_EMUL_ASSIST; /* * If the fetch failed, return to guest and * try executing it again. */ - r = kvmppc_get_last_inst(vcpu, INST_GENERIC, - &vcpu->arch.emul_inst); + r = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + vcpu->arch.emul_inst = ppc_inst_val(pinst); if (r != EMULATE_DONE) r = RESUME_GUEST; else @@ -2918,13 +2933,18 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) /* * Set the default HFSCR for the guest from the host value. - * This value is only used on POWER9. - * On POWER9, we want to virtualize the doorbell facility, so we + * This value is only used on POWER9 and later. + * On >= POWER9, we want to virtualize the doorbell facility, so we * don't set the HFSCR_MSGP bit, and that causes those instructions * to trap and then we emulate them. */ vcpu->arch.hfscr = HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP; + + /* On POWER10 and later, allow prefixed instructions */ + if (cpu_has_feature(CPU_FTR_ARCH_31)) + vcpu->arch.hfscr |= HFSCR_PREFIX; + if (cpu_has_feature(CPU_FTR_HVMODE)) { vcpu->arch.hfscr &= mfspr(SPRN_HFSCR); #ifdef CONFIG_PPC_TRANSACTIONAL_MEM @@ -5779,12 +5799,12 @@ static void kvmppc_irq_bypass_del_producer_hv(struct irq_bypass_consumer *cons, } #endif -static long kvm_arch_vm_ioctl_hv(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_arch_vm_ioctl_hv(struct file *filp, + unsigned int ioctl, unsigned long arg) { struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; - long r; + int r; switch (ioctl) { diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 5a64a1341e6f..377d0b4a05ee 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -1560,7 +1560,9 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { if (dsisr & (DSISR_PRTABLE_FAULT | DSISR_BADACCESS)) { /* unusual error -> reflect to the guest as a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } @@ -1570,8 +1572,9 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (memslot->flags & KVM_MEM_READONLY) { if (writing) { /* Give the guest a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, - DSISR_ISSTORE | DSISR_PROTFAULT); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } kvm_ro = true; diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index acf80915f406..870110e3d9b1 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -381,7 +381,7 @@ kvm_secondary_got_guest: bne kvm_no_guest li r3,0 /* NULL argument */ - bl hmi_exception_realmode + bl CFUNC(hmi_exception_realmode) /* * At this point we have finished executing in the guest. * We need to wait for hwthread_req to become zero, since @@ -458,7 +458,7 @@ kvm_unsplit_nap: cmpwi r12, BOOK3S_INTERRUPT_HMI bne 55f li r3, 0 /* NULL argument */ - bl hmi_exception_realmode + bl CFUNC(hmi_exception_realmode) 55: /* * Ensure that secondary doesn't nap when it has @@ -502,8 +502,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) * * *****************************************************************************/ -.global kvmppc_hv_entry -kvmppc_hv_entry: +SYM_CODE_START_LOCAL(kvmppc_hv_entry) /* Required state: * @@ -859,7 +858,7 @@ deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */ cmpdi r0, 0 beq 71f mr r3, r4 - bl kvmppc_guest_entry_inject_int + bl CFUNC(kvmppc_guest_entry_inject_int) ld r4, HSTATE_KVM_VCPU(r13) 71: ld r6, VCPU_SRR0(r4) @@ -940,6 +939,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r4, VCPU_GPR(R4)(r4) HRFI_TO_GUEST b . +SYM_CODE_END(kvmppc_hv_entry) secondary_too_late: li r12, 0 @@ -1071,11 +1071,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) /* Save HEIR (HV emulation assist reg) in emul_inst if this is an HEI (HV emulation interrupt, e40) */ li r3,KVM_INST_FETCH_FAILED - stw r3,VCPU_LAST_INST(r9) + std r3,VCPU_LAST_INST(r9) cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST bne 11f mfspr r3,SPRN_HEIR -11: stw r3,VCPU_HEIR(r9) +11: std r3,VCPU_HEIR(r9) /* these are volatile across C function calls */ mfctr r3 @@ -1544,7 +1544,7 @@ kvmppc_guest_external: /* External interrupt, first check for host_ipi. If this is * set, we know the host wants us out so let's do it now */ - bl kvmppc_read_intr + bl CFUNC(kvmppc_read_intr) /* * Restore the active volatile registers after returning from @@ -1626,7 +1626,7 @@ kvmppc_hdsi: /* Search the hash table. */ mr r3, r9 /* vcpu pointer */ li r7, 1 /* data fault */ - bl kvmppc_hpte_hv_fault + bl CFUNC(kvmppc_hpte_hv_fault) ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -1676,7 +1676,7 @@ fast_interrupt_c_return: mtmsrd r3 /* Store the result */ - stw r8, VCPU_LAST_INST(r9) + std r8, VCPU_LAST_INST(r9) /* Unset guest mode. */ li r0, KVM_GUEST_MODE_HOST_HV @@ -1702,7 +1702,7 @@ kvmppc_hisi: mr r4, r10 mr r6, r11 li r7, 0 /* instruction fault */ - bl kvmppc_hpte_hv_fault + bl CFUNC(kvmppc_hpte_hv_fault) ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -2342,7 +2342,7 @@ hmi_realmode: lbz r0, HSTATE_PTID(r13) cmpwi r0, 0 bne guest_exit_cont - bl kvmppc_realmode_hmi_handler + bl CFUNC(kvmppc_realmode_hmi_handler) ld r9, HSTATE_KVM_VCPU(r13) li r12, BOOK3S_INTERRUPT_HMI b guest_exit_cont @@ -2413,7 +2413,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) 7: mflr r0 std r0, PPC_LR_STKOFF(r1) stdu r1, -PPC_MIN_STKFRM(r1) - bl kvmppc_read_intr + bl CFUNC(kvmppc_read_intr) nop li r12, BOOK3S_INTERRUPT_EXTERNAL cmpdi r3, 1 diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c index a11436720a8c..bc39c76c9d9f 100644 --- a/arch/powerpc/kvm/book3s_paired_singles.c +++ b/arch/powerpc/kvm/book3s_paired_singles.c @@ -621,6 +621,7 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc, int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu) { u32 inst; + ppc_inst_t pinst; enum emulation_result emulated = EMULATE_DONE; int ax_rd, ax_ra, ax_rb, ax_rc; short full_d; @@ -632,7 +633,8 @@ int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu) int i; #endif - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + inst = ppc_inst_val(pinst); if (emulated != EMULATE_DONE) return emulated; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 9fc4dd8f66eb..9118242063fb 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -759,7 +759,7 @@ static int kvmppc_handle_pagefault(struct kvm_vcpu *vcpu, flags = DSISR_NOHPTE; if (data) { flags |= vcpu->arch.fault_dsisr & DSISR_ISSTORE; - kvmppc_core_queue_data_storage(vcpu, eaddr, flags); + kvmppc_core_queue_data_storage(vcpu, 0, eaddr, flags); } else { kvmppc_core_queue_inst_storage(vcpu, flags); } @@ -1044,6 +1044,8 @@ void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr) { if (fscr & FSCR_SCV) fscr &= ~FSCR_SCV; /* SCV must not be enabled */ + /* Prohibit prefixed instructions for now */ + fscr &= ~FSCR_PREFIX; if ((vcpu->arch.fscr & FSCR_TAR) && !(fscr & FSCR_TAR)) { /* TAR got dropped, drop it in shadow too */ kvmppc_giveup_fac(vcpu, FSCR_TAR_LG); @@ -1079,7 +1081,7 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) { enum emulation_result er; ulong flags; - u32 last_inst; + ppc_inst_t last_inst; int emul, r; /* @@ -1100,9 +1102,9 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) if (kvmppc_get_msr(vcpu) & MSR_PR) { #ifdef EXIT_DEBUG pr_info("Userspace triggered 0x700 exception at\n 0x%lx (0x%x)\n", - kvmppc_get_pc(vcpu), last_inst); + kvmppc_get_pc(vcpu), ppc_inst_val(last_inst)); #endif - if ((last_inst & 0xff0007ff) != (INS_DCBZ & 0xfffffff7)) { + if ((ppc_inst_val(last_inst) & 0xff0007ff) != (INS_DCBZ & 0xfffffff7)) { kvmppc_core_queue_program(vcpu, flags); return RESUME_GUEST; } @@ -1119,7 +1121,7 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) break; case EMULATE_FAIL: pr_crit("%s: emulation at %lx failed (%08x)\n", - __func__, kvmppc_get_pc(vcpu), last_inst); + __func__, kvmppc_get_pc(vcpu), ppc_inst_val(last_inst)); kvmppc_core_queue_program(vcpu, flags); r = RESUME_GUEST; break; @@ -1236,7 +1238,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) r = kvmppc_handle_pagefault(vcpu, dar, exit_nr); srcu_read_unlock(&vcpu->kvm->srcu, idx); } else { - kvmppc_core_queue_data_storage(vcpu, dar, fault_dsisr); + kvmppc_core_queue_data_storage(vcpu, 0, dar, fault_dsisr); r = RESUME_GUEST; } break; @@ -1281,7 +1283,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) break; case BOOK3S_INTERRUPT_SYSCALL: { - u32 last_sc; + ppc_inst_t last_sc; int emul; /* Get last sc for papr */ @@ -1296,7 +1298,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) } if (vcpu->arch.papr_enabled && - (last_sc == 0x44000022) && + (ppc_inst_val(last_sc) == 0x44000022) && !(kvmppc_get_msr(vcpu) & MSR_PR)) { /* SC 1 papr hypercalls */ ulong cmd = kvmppc_get_gpr(vcpu, 3); @@ -1348,7 +1350,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) { int ext_msr = 0; int emul; - u32 last_inst; + ppc_inst_t last_inst; if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) { /* Do paired single instruction emulation */ @@ -1382,15 +1384,15 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) } case BOOK3S_INTERRUPT_ALIGNMENT: { - u32 last_inst; + ppc_inst_t last_inst; int emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); if (emul == EMULATE_DONE) { u32 dsisr; u64 dar; - dsisr = kvmppc_alignment_dsisr(vcpu, last_inst); - dar = kvmppc_alignment_dar(vcpu, last_inst); + dsisr = kvmppc_alignment_dsisr(vcpu, ppc_inst_val(last_inst)); + dar = kvmppc_alignment_dar(vcpu, ppc_inst_val(last_inst)); kvmppc_set_dsisr(vcpu, dsisr); kvmppc_set_dar(vcpu, dar); @@ -2042,8 +2044,8 @@ static int kvmppc_core_check_processor_compat_pr(void) return 0; } -static long kvm_arch_vm_ioctl_pr(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_arch_vm_ioctl_pr(struct file *filp, + unsigned int ioctl, unsigned long arg) { return -ENOTTY; } diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 03886ca24498..0a557ffca9fe 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -123,6 +123,7 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC kvmppc_handler_skip_ins: /* Patch the IP to the next instruction */ + /* Note that prefixed instructions are disabled in PR KVM for now */ mfsrr0 r12 addi r12, r12, 4 mtsrr0 r12 diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 01adffb24667..6a5be025a8af 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -283,9 +283,10 @@ void kvmppc_core_queue_dtlb_miss(struct kvm_vcpu *vcpu, kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); } -void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, +void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong srr1_flags, ulong dear_flags, ulong esr_flags) { + WARN_ON_ONCE(srr1_flags); vcpu->arch.queued_dear = dear_flags; vcpu->arch.queued_esr = esr_flags; kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE); @@ -316,14 +317,16 @@ void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong esr_flags) kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM); } -void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { + WARN_ON_ONCE(srr1_flags); kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL); } #ifdef CONFIG_ALTIVEC -void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { + WARN_ON_ONCE(srr1_flags); kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL); } #endif @@ -623,7 +626,7 @@ static void arm_next_watchdog(struct kvm_vcpu *vcpu) spin_unlock_irqrestore(&vcpu->arch.wdt_lock, flags); } -void kvmppc_watchdog_func(struct timer_list *t) +static void kvmppc_watchdog_func(struct timer_list *t) { struct kvm_vcpu *vcpu = from_timer(vcpu, t, arch.wdt_timer); u32 tsr, new_tsr; @@ -841,7 +844,7 @@ static int emulation_exit(struct kvm_vcpu *vcpu) return RESUME_GUEST; case EMULATE_FAIL: - printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", + printk(KERN_CRIT "%s: emulation at %lx failed (%08lx)\n", __func__, vcpu->arch.regs.nip, vcpu->arch.last_inst); /* For debugging, encode the failing instruction and * report it to userspace. */ @@ -1000,7 +1003,7 @@ static int kvmppc_resume_inst_load(struct kvm_vcpu *vcpu, } } -/** +/* * kvmppc_handle_exit * * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV) @@ -1012,6 +1015,7 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) int s; int idx; u32 last_inst = KVM_INST_FETCH_FAILED; + ppc_inst_t pinst; enum emulation_result emulated = EMULATE_DONE; /* Fix irq state (pairs with kvmppc_fix_ee_before_entry()) */ @@ -1031,12 +1035,15 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) case BOOKE_INTERRUPT_DATA_STORAGE: case BOOKE_INTERRUPT_DTLB_MISS: case BOOKE_INTERRUPT_HV_PRIV: - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + last_inst = ppc_inst_val(pinst); break; case BOOKE_INTERRUPT_PROGRAM: /* SW breakpoints arrive as illegal instructions on HV */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + last_inst = ppc_inst_val(pinst); + } break; default: break; @@ -1225,7 +1232,7 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) #endif case BOOKE_INTERRUPT_DATA_STORAGE: - kvmppc_core_queue_data_storage(vcpu, vcpu->arch.fault_dear, + kvmppc_core_queue_data_storage(vcpu, 0, vcpu->arch.fault_dear, vcpu->arch.fault_esr); kvmppc_account_exit(vcpu, DSI_EXITS); r = RESUME_GUEST; @@ -1946,7 +1953,8 @@ static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr, dbg_reg->dbcr0 |= DBCR0_IDM; return 0; } -void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, bool set) +static void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, + bool set) { /* XXX: Add similar MSR protection for BookE-PR */ #ifdef CONFIG_KVM_BOOKE_HV diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index be9da96d9f06..9c5b8e76014f 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h @@ -109,4 +109,7 @@ static inline void kvmppc_clear_dbsr(void) { mtspr(SPRN_DBSR, mfspr(SPRN_DBSR)); } + +int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr); + #endif /* __KVM_BOOKE_H__ */ diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index b5fe6fb53c66..8b4a402217ba 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -139,7 +139,7 @@ END_BTB_FLUSH_SECTION * kvmppc_get_last_inst(). */ li r9, KVM_INST_FETCH_FAILED - stw r9, VCPU_LAST_INST(r4) + PPC_STL r9, VCPU_LAST_INST(r4) .endif .if \flags & NEED_ESR diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index 05668e964140..ccb8f16ffe41 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c @@ -623,7 +623,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, #ifdef CONFIG_KVM_BOOKE_HV int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *instr) + enum instruction_fetch_type type, unsigned long *instr) { gva_t geaddr; hpa_t addr; @@ -713,7 +713,7 @@ int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, } #else int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *instr) + enum instruction_fetch_type type, unsigned long *instr) { return EMULATE_AGAIN; } diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index a309138927ff..d58df71ace58 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -168,7 +168,7 @@ static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu) kvmppc_booke_vcpu_put(vcpu); } -int kvmppc_e500mc_check_processor_compat(void) +static int kvmppc_e500mc_check_processor_compat(void) { int r; diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index ee1147c98cd8..355d5206e8aa 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -194,6 +194,7 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) { u32 inst; + ppc_inst_t pinst; int rs, rt, sprn; enum emulation_result emulated; int advance = 1; @@ -201,7 +202,8 @@ int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) /* this default type might be overwritten by subcategories */ kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + inst = ppc_inst_val(pinst); if (emulated != EMULATE_DONE) return emulated; @@ -299,6 +301,10 @@ int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); /* Advance past emulated instruction. */ + /* + * If this ever handles prefixed instructions, the 4 + * will need to become ppc_inst_len(pinst) instead. + */ if (advance) kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); diff --git a/arch/powerpc/kvm/emulate_loadstore.c b/arch/powerpc/kvm/emulate_loadstore.c index cfc9114b87d0..059c08ae0340 100644 --- a/arch/powerpc/kvm/emulate_loadstore.c +++ b/arch/powerpc/kvm/emulate_loadstore.c @@ -28,7 +28,7 @@ static bool kvmppc_check_fp_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_FP)) { - kvmppc_core_queue_fpunavail(vcpu); + kvmppc_core_queue_fpunavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -40,7 +40,7 @@ static bool kvmppc_check_fp_disabled(struct kvm_vcpu *vcpu) static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_VSX)) { - kvmppc_core_queue_vsx_unavail(vcpu); + kvmppc_core_queue_vsx_unavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -52,7 +52,7 @@ static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu) static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_VEC)) { - kvmppc_core_queue_vec_unavail(vcpu); + kvmppc_core_queue_vec_unavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -71,7 +71,7 @@ static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu) */ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) { - u32 inst; + ppc_inst_t inst; enum emulation_result emulated = EMULATE_FAIL; struct instruction_op op; @@ -93,7 +93,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) emulated = EMULATE_FAIL; vcpu->arch.regs.msr = vcpu->arch.shared->msr; - if (analyse_instr(&op, &vcpu->arch.regs, ppc_inst(inst)) == 0) { + if (analyse_instr(&op, &vcpu->arch.regs, inst) == 0) { int type = op.type & INSTR_TYPE_MASK; int size = GETSIZE(op.type); @@ -356,11 +356,11 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) } } - trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); + trace_kvm_ppc_instr(ppc_inst_val(inst), kvmppc_get_pc(vcpu), emulated); /* Advance past emulated instruction. */ if (emulated != EMULATE_FAIL) - kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); + kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + ppc_inst_len(inst)); return emulated; } diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index d23e25e8432d..7197c8256668 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -304,11 +304,11 @@ int kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) break; case EMULATE_FAIL: { - u32 last_inst; + ppc_inst_t last_inst; kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n", - last_inst); + ppc_inst_val(last_inst)); /* * Injecting a Data Storage here is a bit more @@ -321,7 +321,9 @@ int kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) if (vcpu->mmio_is_write) dsisr |= DSISR_ISSTORE; - kvmppc_core_queue_data_storage(vcpu, vcpu->arch.vaddr_accessed, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + vcpu->arch.vaddr_accessed, dsisr); } else { /* * BookE does not send a SIGBUS on a bad @@ -2377,12 +2379,11 @@ static int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp) } #endif -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; - long r; + int r; switch (ioctl) { case KVM_PPC_GET_PVINFO: { diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S index 6812cb19d04a..5d09a029b556 100644 --- a/arch/powerpc/lib/copypage_64.S +++ b/arch/powerpc/lib/copypage_64.S @@ -18,8 +18,18 @@ FTR_SECTION_ELSE #endif ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY) ori r5,r5,PAGE_SIZE@l +#ifdef CONFIG_PPC_KERNEL_PCREL + /* + * Hack for toolchain - prefixed instructions cause label difference to + * be non-constant even if 8 byte alignment is known, so they can not + * be put in FTR sections. + */ + LOAD_REG_ADDR(r10, ppc64_caches) +BEGIN_FTR_SECTION +#else BEGIN_FTR_SECTION LOAD_REG_ADDR(r10, ppc64_caches) +#endif lwz r11,DCACHEL1LOGBLOCKSIZE(r10) /* log2 of cache block size */ lwz r12,DCACHEL1BLOCKSIZE(r10) /* get cache block size */ li r9,0 diff --git a/arch/powerpc/lib/copypage_power7.S b/arch/powerpc/lib/copypage_power7.S index a9844c6353cf..a783973f1215 100644 --- a/arch/powerpc/lib/copypage_power7.S +++ b/arch/powerpc/lib/copypage_power7.S @@ -45,7 +45,7 @@ _GLOBAL(copypage_power7) std r4,-STACKFRAMESIZE+STK_REG(R30)(r1) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl enter_vmx_ops + bl CFUNC(enter_vmx_ops) cmpwi r3,0 ld r0,STACKFRAMESIZE+16(r1) ld r3,STK_REG(R31)(r1) @@ -88,7 +88,7 @@ _GLOBAL(copypage_power7) addi r3,r3,128 bdnz 1b - b exit_vmx_ops /* tail call optimise */ + b CFUNC(exit_vmx_ops) /* tail call optimise */ #else li r0,(PAGE_SIZE/128) diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S index 28f0be523c06..ac41053c3a5a 100644 --- a/arch/powerpc/lib/copyuser_power7.S +++ b/arch/powerpc/lib/copyuser_power7.S @@ -47,7 +47,7 @@ ld r15,STK_REG(R15)(r1) ld r14,STK_REG(R14)(r1) .Ldo_err3: - bl exit_vmx_usercopy + bl CFUNC(exit_vmx_usercopy) ld r0,STACKFRAMESIZE+16(r1) mtlr r0 b .Lexit @@ -272,7 +272,7 @@ err1; stb r0,0(r3) mflr r0 std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl enter_vmx_usercopy + bl CFUNC(enter_vmx_usercopy) cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) ld r3,STK_REG(R31)(r1) @@ -488,7 +488,7 @@ err3; lbz r0,0(r4) err3; stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - b exit_vmx_usercopy /* tail call optimise */ + b CFUNC(exit_vmx_usercopy) /* tail call optimise */ .Lvmx_unaligned_copy: /* Get the destination 16B aligned */ @@ -691,5 +691,5 @@ err3; lbz r0,0(r4) err3; stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE - b exit_vmx_usercopy /* tail call optimise */ + b CFUNC(exit_vmx_usercopy) /* tail call optimise */ #endif /* CONFIG_ALTIVEC */ diff --git a/arch/powerpc/lib/hweight_64.S b/arch/powerpc/lib/hweight_64.S index 6effad901ef7..09af29561314 100644 --- a/arch/powerpc/lib/hweight_64.S +++ b/arch/powerpc/lib/hweight_64.S @@ -14,7 +14,7 @@ _GLOBAL(__arch_hweight8) BEGIN_FTR_SECTION - b __sw_hweight8 + b CFUNC(__sw_hweight8) nop nop FTR_SECTION_ELSE @@ -26,7 +26,7 @@ EXPORT_SYMBOL(__arch_hweight8) _GLOBAL(__arch_hweight16) BEGIN_FTR_SECTION - b __sw_hweight16 + b CFUNC(__sw_hweight16) nop nop nop @@ -49,7 +49,7 @@ EXPORT_SYMBOL(__arch_hweight16) _GLOBAL(__arch_hweight32) BEGIN_FTR_SECTION - b __sw_hweight32 + b CFUNC(__sw_hweight32) nop nop nop @@ -75,7 +75,7 @@ EXPORT_SYMBOL(__arch_hweight32) _GLOBAL(__arch_hweight64) BEGIN_FTR_SECTION - b __sw_hweight64 + b CFUNC(__sw_hweight64) nop nop nop diff --git a/arch/powerpc/lib/memcmp_64.S b/arch/powerpc/lib/memcmp_64.S index 384218df71ba..0b9b1685a33d 100644 --- a/arch/powerpc/lib/memcmp_64.S +++ b/arch/powerpc/lib/memcmp_64.S @@ -44,7 +44,7 @@ std r5,-STACKFRAMESIZE+STK_REG(R29)(r1); \ std r0,16(r1); \ stdu r1,-STACKFRAMESIZE(r1); \ - bl enter_vmx_ops; \ + bl CFUNC(enter_vmx_ops); \ cmpwi cr1,r3,0; \ ld r0,STACKFRAMESIZE+16(r1); \ ld r3,STK_REG(R31)(r1); \ @@ -60,7 +60,7 @@ std r5,-STACKFRAMESIZE+STK_REG(R29)(r1); \ std r0,16(r1); \ stdu r1,-STACKFRAMESIZE(r1); \ - bl exit_vmx_ops; \ + bl CFUNC(exit_vmx_ops); \ ld r0,STACKFRAMESIZE+16(r1); \ ld r3,STK_REG(R31)(r1); \ ld r4,STK_REG(R30)(r1); \ diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index 54f226333c94..9398b2b746c4 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -218,7 +218,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) std r5,-STACKFRAMESIZE+STK_REG(R29)(r1) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) - bl enter_vmx_ops + bl CFUNC(enter_vmx_ops) cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) ld r3,STK_REG(R31)(r1) @@ -433,7 +433,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 15: addi r1,r1,STACKFRAMESIZE ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) - b exit_vmx_ops /* tail call optimise */ + b CFUNC(exit_vmx_ops) /* tail call optimise */ .Lvmx_unaligned_copy: /* Get the destination 16B aligned */ @@ -637,5 +637,5 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 15: addi r1,r1,STACKFRAMESIZE ld r3,-STACKFRAMESIZE+STK_REG(R31)(r1) - b exit_vmx_ops /* tail call optimise */ + b CFUNC(exit_vmx_ops) /* tail call optimise */ #endif /* CONFIG_ALTIVEC */ diff --git a/arch/powerpc/lib/pmem.c b/arch/powerpc/lib/pmem.c index eb2919ddf9b9..4e724c4c01ad 100644 --- a/arch/powerpc/lib/pmem.c +++ b/arch/powerpc/lib/pmem.c @@ -85,10 +85,3 @@ void memcpy_flushcache(void *dest, const void *src, size_t size) clean_pmem_range(start, start + size); } EXPORT_SYMBOL(memcpy_flushcache); - -void memcpy_page_flushcache(char *to, struct page *page, size_t offset, - size_t len) -{ - memcpy_flushcache(to, page_to_virt(page) + offset, len); -} -EXPORT_SYMBOL(memcpy_page_flushcache); diff --git a/arch/powerpc/mm/book3s64/iommu_api.c b/arch/powerpc/mm/book3s64/iommu_api.c index 7fcfba162e0d..81d7185e2ae8 100644 --- a/arch/powerpc/mm/book3s64/iommu_api.c +++ b/arch/powerpc/mm/book3s64/iommu_api.c @@ -97,7 +97,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, } mmap_read_lock(mm); - chunk = (1UL << (PAGE_SHIFT + MAX_ORDER - 1)) / + chunk = (1UL << (PAGE_SHIFT + MAX_ORDER)) / sizeof(struct vm_area_struct *); chunk = min(chunk, entries); for (entry = 0; entry < entries; entry += chunk) { diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index 26245aaf12b8..2297aa764ecd 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -1040,8 +1040,8 @@ void radix__ptep_set_access_flags(struct vm_area_struct *vma, pte_t *ptep, pte_t entry, unsigned long address, int psize) { struct mm_struct *mm = vma->vm_mm; - unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | - _PAGE_RW | _PAGE_EXEC); + unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_SOFT_DIRTY | + _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); unsigned long change = pte_val(entry) ^ pte_val(*ptep); /* diff --git a/arch/powerpc/mm/book3s64/radix_tlb.c b/arch/powerpc/mm/book3s64/radix_tlb.c index e50bc5fc7ddf..ce804b7bf84e 100644 --- a/arch/powerpc/mm/book3s64/radix_tlb.c +++ b/arch/powerpc/mm/book3s64/radix_tlb.c @@ -797,10 +797,10 @@ void exit_lazy_flush_tlb(struct mm_struct *mm, bool always_flush) if (current->active_mm == mm) { WARN_ON_ONCE(current->mm != NULL); /* Is a kernel thread and is using mm as the lazy tlb */ - mmgrab(&init_mm); + mmgrab_lazy_tlb(&init_mm); current->active_mm = &init_mm; switch_mm_irqs_off(mm, &init_mm, current); - mmdrop(mm); + mmdrop_lazy_tlb(mm); } /* diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index af46aa88422b..531177a4ee08 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -474,6 +474,40 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address, if (is_exec) flags |= FAULT_FLAG_INSTRUCTION; +#ifdef CONFIG_PER_VMA_LOCK + if (!(flags & FAULT_FLAG_USER)) + goto lock_mmap; + + vma = lock_vma_under_rcu(mm, address); + if (!vma) + goto lock_mmap; + + if (unlikely(access_pkey_error(is_write, is_exec, + (error_code & DSISR_KEYFAULT), vma))) { + vma_end_read(vma); + goto lock_mmap; + } + + if (unlikely(access_error(is_write, is_exec, vma))) { + vma_end_read(vma); + goto lock_mmap; + } + + fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs); + vma_end_read(vma); + + if (!(fault & VM_FAULT_RETRY)) { + count_vm_vma_lock_event(VMA_LOCK_SUCCESS); + goto done; + } + count_vm_vma_lock_event(VMA_LOCK_RETRY); + + if (fault_signal_pending(fault, regs)) + return user_mode(regs) ? 0 : SIGBUS; + +lock_mmap: +#endif /* CONFIG_PER_VMA_LOCK */ + /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the * kernel and should generate an OOPS. Unfortunately, in the case of an @@ -550,6 +584,9 @@ retry: mmap_read_unlock(current->mm); +#ifdef CONFIG_PER_VMA_LOCK +done: +#endif if (unlikely(fault & VM_FAULT_ERROR)) return mm_fault_error(regs, address, fault); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index f1ba8d1e8c1a..b900933507da 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -615,7 +615,7 @@ void __init gigantic_hugetlb_cma_reserve(void) order = mmu_psize_to_shift(MMU_PAGE_16G) - PAGE_SHIFT; if (order) { - VM_WARN_ON(order < MAX_ORDER); + VM_WARN_ON(order <= MAX_ORDER); hugetlb_cma_reserve(order); } } diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 16cfe56be05b..9f73d089eac1 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1289,23 +1290,15 @@ static int hot_add_node_scn_to_nid(unsigned long scn_addr) int nid = NUMA_NO_NODE; for_each_node_by_type(memory, "memory") { - unsigned long start, size; - int ranges; - const __be32 *memcell_buf; - unsigned int len; + int i = 0; - memcell_buf = of_get_property(memory, "reg", &len); - if (!memcell_buf || len <= 0) - continue; + while (1) { + struct resource res; - /* ranges in cell */ - ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); + if (of_address_to_resource(memory, i++, &res)) + break; - while (ranges--) { - start = read_n_cells(n_mem_addr_cells, &memcell_buf); - size = read_n_cells(n_mem_size_cells, &memcell_buf); - - if ((scn_addr < start) || (scn_addr >= (start + size))) + if ((scn_addr < res.start) || (scn_addr > res.end)) continue; nid = of_node_to_nid_single(memory); diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h index d767e39d5645..72b7bb34fade 100644 --- a/arch/powerpc/net/bpf_jit.h +++ b/arch/powerpc/net/bpf_jit.h @@ -19,6 +19,8 @@ #define FUNCTION_DESCR_SIZE 0 #endif +#define CTX_NIA(ctx) ((unsigned long)ctx->idx * 4) + #define PLANT_INSTR(d, idx, instr) \ do { if (d) { (d)[idx] = instr; } idx++; } while (0) #define EMIT(instr) PLANT_INSTR(image, ctx->idx, instr) @@ -26,7 +28,7 @@ /* Long jump; (unconditional 'branch') */ #define PPC_JMP(dest) \ do { \ - long offset = (long)(dest) - (ctx->idx * 4); \ + long offset = (long)(dest) - CTX_NIA(ctx); \ if ((dest) != 0 && !is_offset_in_branch_range(offset)) { \ pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \ return -ERANGE; \ @@ -40,7 +42,7 @@ /* "cond" here covers BO:BI fields. */ #define PPC_BCC_SHORT(cond, dest) \ do { \ - long offset = (long)(dest) - (ctx->idx * 4); \ + long offset = (long)(dest) - CTX_NIA(ctx); \ if ((dest) != 0 && !is_offset_in_cond_branch_range(offset)) { \ pr_err_ratelimited("Conditional branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \ return -ERANGE; \ @@ -92,12 +94,12 @@ * state. */ #define PPC_BCC(cond, dest) do { \ - if (is_offset_in_cond_branch_range((long)(dest) - (ctx->idx * 4))) { \ + if (is_offset_in_cond_branch_range((long)(dest) - CTX_NIA(ctx))) { \ PPC_BCC_SHORT(cond, dest); \ EMIT(PPC_RAW_NOP()); \ } else { \ /* Flip the 'T or F' bit to invert comparison */ \ - PPC_BCC_SHORT(cond ^ COND_CMP_TRUE, (ctx->idx+2)*4); \ + PPC_BCC_SHORT(cond ^ COND_CMP_TRUE, CTX_NIA(ctx) + 2*4); \ PPC_JMP(dest); \ } } while(0) diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index e93aefcfb83f..37043dfc1add 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -101,6 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) bpf_hdr = jit_data->header; proglen = jit_data->proglen; extra_pass = true; + /* During extra pass, ensure index is reset before repopulating extable entries */ + cgctx.exentry_idx = 0; goto skip_init_ctx; } diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 8dd3cabaa83a..0f8048f6dad6 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -126,8 +126,10 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) { int i; +#ifndef CONFIG_PPC_KERNEL_PCREL if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2)) EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))); +#endif /* * Initialize tail_call_cnt if we do tail calls. @@ -208,16 +210,32 @@ static int bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, u if (WARN_ON_ONCE(!core_kernel_text(func_addr))) return -EINVAL; - reladdr = func_addr - kernel_toc_addr(); - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { - pr_err("eBPF: address of %ps out of range of kernel_toc.\n", (void *)func); - return -ERANGE; - } + if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + reladdr = func_addr - CTX_NIA(ctx); - EMIT(PPC_RAW_ADDIS(_R12, _R2, PPC_HA(reladdr))); - EMIT(PPC_RAW_ADDI(_R12, _R12, PPC_LO(reladdr))); - EMIT(PPC_RAW_MTCTR(_R12)); - EMIT(PPC_RAW_BCTRL()); + if (reladdr >= (long)SZ_8G || reladdr < -(long)SZ_8G) { + pr_err("eBPF: address of %ps out of range of pcrel address.\n", + (void *)func); + return -ERANGE; + } + /* pla r12,addr */ + EMIT(PPC_PREFIX_MLS | __PPC_PRFX_R(1) | IMM_H18(reladdr)); + EMIT(PPC_INST_PADDI | ___PPC_RT(_R12) | IMM_L(reladdr)); + EMIT(PPC_RAW_MTCTR(_R12)); + EMIT(PPC_RAW_BCTR()); + + } else { + reladdr = func_addr - kernel_toc_addr(); + if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { + pr_err("eBPF: address of %ps out of range of kernel_toc.\n", (void *)func); + return -ERANGE; + } + + EMIT(PPC_RAW_ADDIS(_R12, _R2, PPC_HA(reladdr))); + EMIT(PPC_RAW_ADDI(_R12, _R12, PPC_LO(reladdr))); + EMIT(PPC_RAW_MTCTR(_R12)); + EMIT(PPC_RAW_BCTRL()); + } return 0; } diff --git a/arch/powerpc/perf/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c index 552d51a925d3..db451b9aac35 100644 --- a/arch/powerpc/perf/mpc7450-pmu.c +++ b/arch/powerpc/perf/mpc7450-pmu.c @@ -417,9 +417,9 @@ struct power_pmu mpc7450_pmu = { static int __init init_mpc7450_pmu(void) { - unsigned int pvr = mfspr(SPRN_PVR); - - if (PVR_VER(pvr) != PVR_7450) + if (!pvr_version_is(PVR_VER_7450) && !pvr_version_is(PVR_VER_7455) && + !pvr_version_is(PVR_VER_7447) && !pvr_version_is(PVR_VER_7447A) && + !pvr_version_is(PVR_VER_7448)) return -ENODEV; return register_power_pmu(&mpc7450_pmu); diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index dce696c32679..e454e9d2eff1 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -74,5 +74,4 @@ define_machine(ppc40x_simple) { .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c index 5b23aef8bdef..8742a10d9e0c 100644 --- a/arch/powerpc/platforms/44x/canyonlands.c +++ b/arch/powerpc/platforms/44x/canyonlands.c @@ -39,11 +39,9 @@ machine_device_initcall(canyonlands, ppc460ex_device_probe); static int __init ppc460ex_probe(void) { - if (of_machine_is_compatible("amcc,canyonlands")) { - pci_set_flags(PCI_REASSIGN_ALL_RSRC); - return 1; - } - return 0; + pci_set_flags(PCI_REASSIGN_ALL_RSRC); + + return 1; } /* USB PHY fixup code on Canyonlands kit. */ @@ -110,10 +108,10 @@ err_bcsr: machine_device_initcall(canyonlands, ppc460ex_canyonlands_fixup); define_machine(canyonlands) { .name = "Canyonlands", + .compatible = "amcc,canyonlands", .probe = ppc460ex_probe, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index 0d8f202bc45f..4861310c8dc0 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c @@ -45,9 +45,6 @@ machine_device_initcall(ebony, ebony_device_probe); */ static int __init ebony_probe(void) { - if (!of_machine_is_compatible("ibm,ebony")) - return 0; - pci_set_flags(PCI_REASSIGN_ALL_RSRC); return 1; @@ -55,10 +52,10 @@ static int __init ebony_probe(void) define_machine(ebony) { .name = "Ebony", + .compatible = "ibm,ebony", .probe = ebony_probe, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/fsp2.c b/arch/powerpc/platforms/44x/fsp2.c index 56d91dbef577..f6b8d02e08b0 100644 --- a/arch/powerpc/platforms/44x/fsp2.c +++ b/arch/powerpc/platforms/44x/fsp2.c @@ -313,5 +313,4 @@ define_machine(fsp2) { .init_IRQ = fsp2_irq_init, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index c5f82591408c..ef883d97fe15 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -52,7 +52,7 @@ static void __init iss4xx_init_irq(void) /* Find top level interrupt controller */ for_each_node_with_property(np, "interrupt-controller") { - if (of_get_property(np, "interrupts", NULL) == NULL) + if (!of_property_present(np, "interrupts")) break; } if (np == NULL) @@ -140,23 +140,11 @@ static void __init iss4xx_setup_arch(void) iss4xx_smp_init(); } -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init iss4xx_probe(void) -{ - if (!of_machine_is_compatible("ibm,iss-4xx")) - return 0; - - return 1; -} - define_machine(iss4xx) { .name = "ISS-4xx", - .probe = iss4xx_probe, + .compatible = "ibm,iss-4xx", .progress = udbg_progress, .init_IRQ = iss4xx_init_irq, .setup_arch = iss4xx_setup_arch, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 2a0dcdf04b21..971786ff1a7b 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -82,5 +82,4 @@ define_machine(ppc44x_simple) { .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/44x/ppc476.c b/arch/powerpc/platforms/44x/ppc476.c index 7c91ac5a5241..fbc6edad481f 100644 --- a/arch/powerpc/platforms/44x/ppc476.c +++ b/arch/powerpc/platforms/44x/ppc476.c @@ -114,7 +114,8 @@ static int __init ppc47x_device_probe(void) return 0; } -machine_device_initcall(ppc47x, ppc47x_device_probe); +machine_device_initcall(ppc47x_akebono, ppc47x_device_probe); +machine_device_initcall(ppc47x_currituck, ppc47x_device_probe); static void __init ppc47x_init_irq(void) { @@ -122,7 +123,7 @@ static void __init ppc47x_init_irq(void) /* Find top level interrupt controller */ for_each_node_with_property(np, "interrupt-controller") { - if (of_get_property(np, "interrupts", NULL) == NULL) + if (!of_property_present(np, "interrupts")) break; } if (np == NULL) @@ -249,7 +250,8 @@ fail: pr_info("%s: Unable to find board revision\n", __func__); return 0; } -machine_arch_initcall(ppc47x, ppc47x_get_board_rev); +machine_arch_initcall(ppc47x_akebono, ppc47x_get_board_rev); +machine_arch_initcall(ppc47x_currituck, ppc47x_get_board_rev); /* Use USB controller should have been hardware swizzled but it wasn't :( */ static void ppc47x_pci_irq_fixup(struct pci_dev *dev) @@ -268,28 +270,21 @@ static void ppc47x_pci_irq_fixup(struct pci_dev *dev) } } -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init ppc47x_probe(void) -{ - if (of_machine_is_compatible("ibm,akebono")) - return 1; - - if (of_machine_is_compatible("ibm,currituck")) { - ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup; - return 1; - } - - return 0; -} - -define_machine(ppc47x) { - .name = "PowerPC 47x", - .probe = ppc47x_probe, +define_machine(ppc47x_akebono) { + .name = "PowerPC 47x (akebono)", + .compatible = "ibm,akebono", .progress = udbg_progress, .init_IRQ = ppc47x_init_irq, .setup_arch = ppc47x_setup_arch, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, +}; + +define_machine(ppc47x_currituck) { + .name = "PowerPC 47x (currituck)", + .compatible = "ibm,currituck", + .progress = udbg_progress, + .init_IRQ = ppc47x_init_irq, + .pci_irq_fixup = ppc47x_pci_irq_fixup, + .setup_arch = ppc47x_setup_arch, + .restart = ppc4xx_reset_system, }; diff --git a/arch/powerpc/platforms/44x/sam440ep.c b/arch/powerpc/platforms/44x/sam440ep.c index ed854b53877e..5cdaa4068e41 100644 --- a/arch/powerpc/platforms/44x/sam440ep.c +++ b/arch/powerpc/platforms/44x/sam440ep.c @@ -41,9 +41,6 @@ machine_device_initcall(sam440ep, sam440ep_device_probe); static int __init sam440ep_probe(void) { - if (!of_machine_is_compatible("acube,sam440ep")) - return 0; - pci_set_flags(PCI_REASSIGN_ALL_RSRC); return 1; @@ -51,12 +48,12 @@ static int __init sam440ep_probe(void) define_machine(sam440ep) { .name = "Sam440ep", + .compatible = "acube,sam440ep", .probe = sam440ep_probe, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; static struct i2c_board_info sam440ep_rtc_info = { diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index cefa313c09f0..bfeb9bdc3258 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -41,22 +41,13 @@ static int __init warp_device_probe(void) } machine_device_initcall(warp, warp_device_probe); -static int __init warp_probe(void) -{ - if (!of_machine_is_compatible("pika,warp")) - return 0; - - return 1; -} - define_machine(warp) { .name = "Warp", - .probe = warp_probe, + .compatible = "pika,warp", .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, .restart = ppc4xx_reset_system, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/4xx/pci.c b/arch/powerpc/platforms/4xx/pci.c index 07dcc2b8007f..48626615b18b 100644 --- a/arch/powerpc/platforms/4xx/pci.c +++ b/arch/powerpc/platforms/4xx/pci.c @@ -348,7 +348,7 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) } /* Check if primary bridge */ - if (of_get_property(np, "primary", NULL)) + if (of_property_read_bool(np, "primary")) primary = 1; /* Get bus range if any */ @@ -530,7 +530,7 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) struct pci_controller *hose = NULL; void __iomem *reg = NULL; const int *bus_range; - int big_pim = 0, msi = 0, primary = 0; + int big_pim, msi, primary; /* Fetch config space registers address */ if (of_address_to_resource(np, 0, &rsrc_cfg)) { @@ -546,16 +546,13 @@ static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) } /* Check if it supports large PIMs (440GX) */ - if (of_get_property(np, "large-inbound-windows", NULL)) - big_pim = 1; + big_pim = of_property_read_bool(np, "large-inbound-windows"); /* Check if we should enable MSIs inbound hole */ - if (of_get_property(np, "enable-msi-hole", NULL)) - msi = 1; + msi = of_property_read_bool(np, "enable-msi-hole"); /* Check if primary bridge */ - if (of_get_property(np, "primary", NULL)) - primary = 1; + primary = of_property_read_bool(np, "primary"); /* Get bus range if any */ bus_range = of_get_property(np, "bus-range", NULL); @@ -1915,14 +1912,13 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) struct resource dma_window; struct pci_controller *hose = NULL; const int *bus_range; - int primary = 0, busses; + int primary, busses; void __iomem *mbase = NULL, *cfg_data = NULL; const u32 *pval; u32 val; /* Check if primary bridge */ - if (of_get_property(port->node, "primary", NULL)) - primary = 1; + primary = of_property_read_bool(port->node, "primary"); /* Get bus range if any */ bus_range = of_get_property(port->node, "bus-range", NULL); diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c index 42abeba4f698..079cb3627eac 100644 --- a/arch/powerpc/platforms/512x/clock-commonclk.c +++ b/arch/powerpc/platforms/512x/clock-commonclk.c @@ -986,7 +986,7 @@ static void __init mpc5121_clk_provide_migration_support(void) #define NODE_PREP do { \ of_address_to_resource(np, 0, &res); \ - snprintf(devname, sizeof(devname), "%08x.%s", res.start, np->name); \ + snprintf(devname, sizeof(devname), "%pa.%s", &res.start, np->name); \ } while (0) #define NODE_CHK(clkname, clkitem, regnode, regflag) do { \ diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index fc3fb999cd74..80b25ce076bc 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -53,9 +53,6 @@ static void __init mpc5121_ads_init_IRQ(void) */ static int __init mpc5121_ads_probe(void) { - if (!of_machine_is_compatible("fsl,mpc5121ads")) - return 0; - mpc512x_init_early(); return 1; @@ -63,12 +60,12 @@ static int __init mpc5121_ads_probe(void) define_machine(mpc5121_ads) { .name = "MPC5121 ADS", + .compatible = "fsl,mpc5121ads", .probe = mpc5121_ads_probe, .setup_arch = mpc5121_ads_setup_arch, .discover_phbs = mpc5121_ads_setup_pci, .init = mpc512x_init, .init_IRQ = mpc5121_ads_init_IRQ, .get_irq = ipic_get_irq, - .calibrate_decr = generic_calibrate_decr, .restart = mpc512x_restart, }; diff --git a/arch/powerpc/platforms/512x/mpc512x_generic.c b/arch/powerpc/platforms/512x/mpc512x_generic.c index 364564c995bd..97dfaac8f7ff 100644 --- a/arch/powerpc/platforms/512x/mpc512x_generic.c +++ b/arch/powerpc/platforms/512x/mpc512x_generic.c @@ -47,6 +47,5 @@ define_machine(mpc512x_generic) { .setup_arch = mpc512x_setup_arch, .init_IRQ = mpc512x_init_IRQ, .get_irq = ipic_get_irq, - .calibrate_decr = generic_calibrate_decr, .restart = mpc512x_restart, }; diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platforms/512x/pdm360ng.c index 1e911f42697d..4bdec1c25de7 100644 --- a/arch/powerpc/platforms/512x/pdm360ng.c +++ b/arch/powerpc/platforms/512x/pdm360ng.c @@ -108,9 +108,6 @@ void __init pdm360ng_init(void) static int __init pdm360ng_probe(void) { - if (!of_machine_is_compatible("ifm,pdm360ng")) - return 0; - mpc512x_init_early(); return 1; @@ -118,11 +115,11 @@ static int __init pdm360ng_probe(void) define_machine(pdm360ng) { .name = "PDM360NG", + .compatible = "ifm,pdm360ng", .probe = pdm360ng_probe, .setup_arch = mpc512x_setup_arch, .init = pdm360ng_init, .init_IRQ = mpc512x_init_IRQ, .get_irq = ipic_get_irq, - .calibrate_decr = generic_calibrate_decr, .restart = mpc512x_restart, }; diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 61dfec74ff85..aa82e6b437f3 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -226,7 +226,6 @@ define_machine(efika) .get_rtc_time = rtas_get_rtc_time, .progress = rtas_progress, .get_boot_time = rtas_get_boot_time, - .calibrate_decr = generic_calibrate_decr, #ifdef CONFIG_PCI .phys_mem_access_prot = pci_phys_mem_access_prot, #endif diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 7ea9b6ce0591..0fd67b3ffc3e 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -189,5 +189,4 @@ define_machine(lite5200) { .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, .restart = mpc52xx_restart, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index 129313b1d021..ee29b63fca16 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -54,8 +54,7 @@ static int lite5200_pm_prepare(void) { .type = "builtin", .compatible = "mpc5200", }, /* efika */ {} }; - u64 regaddr64 = 0; - const u32 *regaddr_p; + struct resource res; /* deep sleep? let mpc52xx code handle that */ if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) @@ -66,12 +65,10 @@ static int lite5200_pm_prepare(void) /* map registers */ np = of_find_matching_node(NULL, immr_ids); - regaddr_p = of_get_address(np, 0, NULL, NULL); - if (regaddr_p) - regaddr64 = of_translate_address(np, regaddr_p); + of_address_to_resource(np, 0, &res); of_node_put(np); - mbar = ioremap((u32) regaddr64, 0xC000); + mbar = ioremap(res.start, 0xC000); if (!mbar) { printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); return -ENOSYS; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 33a35fff11b5..19626cd42406 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -227,28 +227,13 @@ static void __init media5200_setup_arch(void) } -/* list of the supported boards */ -static const char * const board[] __initconst = { - "fsl,media5200", - NULL -}; - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init media5200_probe(void) -{ - return of_device_compatible_match(of_root, board); -} - define_machine(media5200_platform) { .name = "media5200-platform", - .probe = media5200_probe, + .compatible = "fsl,media5200", .setup_arch = media5200_setup_arch, .discover_phbs = mpc52xx_setup_pci, .init = mpc52xx_declare_of_platform_devices, .init_IRQ = media5200_init_irq, .get_irq = mpc52xx_get_irq, .restart = mpc52xx_restart, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index cc349d579061..f1e85e86f5e5 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -76,5 +76,4 @@ define_machine(mpc5200_simple_platform) { .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, .restart = mpc52xx_restart, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 409c0ec06265..b4938e344f71 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -141,8 +141,8 @@ mpc52xx_map_common_devices(void) * on a gpt0, so check has-wdt property before mapping. */ for_each_matching_node(np, mpc52xx_gpt_ids) { - if (of_get_property(np, "fsl,has-wdt", NULL) || - of_get_property(np, "has-wdt", NULL)) { + if (of_property_read_bool(np, "fsl,has-wdt") || + of_property_read_bool(np, "has-wdt")) { mpc52xx_wdt = of_iomap(np, 0); of_node_put(np); break; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index e43e08d991ea..3fce4e1c3af6 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -735,8 +735,8 @@ static int mpc52xx_gpt_probe(struct platform_device *ofdev) mutex_unlock(&mpc52xx_gpt_list_mutex); /* check if this device could be a watchdog */ - if (of_get_property(ofdev->dev.of_node, "fsl,has-wdt", NULL) || - of_get_property(ofdev->dev.of_node, "has-wdt", NULL)) { + if (of_property_read_bool(ofdev->dev.of_node, "fsl,has-wdt") || + of_property_read_bool(ofdev->dev.of_node, "has-wdt")) { const u32 *on_boot_wdt; gpt->wdt_mode = MPC52xx_GPT_CAN_WDT; diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 1af81de1c4e6..4eb372bdab70 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -5,27 +5,6 @@ menuconfig PPC_82xx if PPC_82xx -config MPC8272_ADS - bool "Freescale MPC8272 ADS" - select DEFAULT_UIMAGE - select PQ2ADS - select 8272 - select 8260 - select FSL_SOC - select PQ2_ADS_PCI_PIC if PCI - help - This option enables support for the MPC8272 ADS board - -config PQ2FADS - bool "Freescale PQ2FADS" - select DEFAULT_UIMAGE - select PQ2ADS - select 8260 - select FSL_SOC - select PQ2_ADS_PCI_PIC if PCI - help - This option enables support for the PQ2FADS board - config EP8248E bool "Embedded Planet EP8248E (a.k.a. CWH-PPC-8248N-VE)" select 8272 @@ -49,9 +28,6 @@ config MGCOGE endif -config PQ2ADS - bool - config 8260 bool depends on PPC_BOOK3S_32 @@ -67,6 +43,3 @@ config 8272 help The MPC8272 CPM has a different internal dpram setup than other CPM2 devices - -config PQ2_ADS_PCI_PIC - bool diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index 8d713c601bf2..4fa43a5cd582 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -2,9 +2,6 @@ # # Makefile for the PowerPC 82xx linux kernel. # -obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o obj-$(CONFIG_CPM2) += pq2.o -obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o -obj-$(CONFIG_PQ2FADS) += pq2fads.o obj-$(CONFIG_EP8248E) += ep8248e.o obj-$(CONFIG_MGCOGE) += km82xx.o diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index 28e627f8a320..8f1856ba692e 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -301,22 +301,13 @@ static int __init declare_of_platform_devices(void) } machine_device_initcall(ep8248e, declare_of_platform_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init ep8248e_probe(void) -{ - return of_machine_is_compatible("fsl,ep8248e"); -} - define_machine(ep8248e) { .name = "Embedded Planet EP8248E", - .probe = ep8248e_probe, + .compatible = "fsl,ep8248e", .setup_arch = ep8248e_setup_arch, .init_IRQ = ep8248e_pic_init, .get_irq = cpm2_get_irq, - .calibrate_decr = generic_calibrate_decr, .restart = pq2_restart, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c index 1c8bbf4251d9..51c9bfd97592 100644 --- a/arch/powerpc/platforms/82xx/km82xx.c +++ b/arch/powerpc/platforms/82xx/km82xx.c @@ -188,22 +188,13 @@ static int __init declare_of_platform_devices(void) } machine_device_initcall(km82xx, declare_of_platform_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init km82xx_probe(void) -{ - return of_machine_is_compatible("keymile,km82xx"); -} - define_machine(km82xx) { .name = "Keymile km82xx", - .probe = km82xx_probe, + .compatible = "keymile,km82xx", .setup_arch = km82xx_setup_arch, .init_IRQ = km82xx_pic_init, .get_irq = cpm2_get_irq, - .calibrate_decr = generic_calibrate_decr, .restart = pq2_restart, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c deleted file mode 100644 index 0b5b9dec16d5..000000000000 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ /dev/null @@ -1,213 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8272 ADS board support - * - * Copyright 2007 Freescale Semiconductor, Inc. - * Author: Scott Wood - * - * Based on code by Vitaly Bordug - * Copyright (c) 2006 MontaVista Software, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include "pq2.h" - -static void __init mpc8272_ads_pic_init(void) -{ - struct device_node *np = of_find_compatible_node(NULL, NULL, - "fsl,cpm2-pic"); - if (!np) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - - cpm2_pic_init(np); - of_node_put(np); - - /* Initialize stuff for the 82xx CPLD IC and install demux */ - pq2ads_pci_init_irq(); -} - -struct cpm_pin { - int port, pin, flags; -}; - -static struct cpm_pin mpc8272_ads_pins[] = { - /* SCC1 */ - {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* SCC4 */ - {3, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {3, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* FCC1 */ - {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, - {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, - {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, - {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, - {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* FCC2 */ - {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* I2C */ - {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, - {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, - - /* USB */ - {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, -}; - -static void __init init_ioports(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mpc8272_ads_pins); i++) { - struct cpm_pin *pin = &mpc8272_ads_pins[i]; - cpm2_set_pin(pin->port, pin->pin, pin->flags); - } - - cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK15, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK16, CPM_CLK_TX); -} - -static void __init mpc8272_ads_setup_arch(void) -{ - struct device_node *np; - __be32 __iomem *bcsr; - - if (ppc_md.progress) - ppc_md.progress("mpc8272_ads_setup_arch()", 0); - - cpm2_reset(); - - np = of_find_compatible_node(NULL, NULL, "fsl,mpc8272ads-bcsr"); - if (!np) { - printk(KERN_ERR "No bcsr in device tree\n"); - return; - } - - bcsr = of_iomap(np, 0); - of_node_put(np); - if (!bcsr) { - printk(KERN_ERR "Cannot map BCSR registers\n"); - return; - } - -#define BCSR1_FETHIEN 0x08000000 -#define BCSR1_FETH_RST 0x04000000 -#define BCSR1_RS232_EN1 0x02000000 -#define BCSR1_RS232_EN2 0x01000000 -#define BCSR3_USB_nEN 0x80000000 -#define BCSR3_FETHIEN2 0x10000000 -#define BCSR3_FETH2_RST 0x08000000 - - clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); - setbits32(&bcsr[1], BCSR1_FETH_RST); - - clrbits32(&bcsr[3], BCSR3_FETHIEN2); - setbits32(&bcsr[3], BCSR3_FETH2_RST); - - clrbits32(&bcsr[3], BCSR3_USB_nEN); - - iounmap(bcsr); - - init_ioports(); - - if (ppc_md.progress) - ppc_md.progress("mpc8272_ads_setup_arch(), finish", 0); -} - -static const struct of_device_id of_bus_ids[] __initconst = { - { .name = "soc", }, - { .name = "cpm", }, - { .name = "localbus", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - return 0; -} -machine_device_initcall(mpc8272_ads, declare_of_platform_devices); - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc8272_ads_probe(void) -{ - return of_machine_is_compatible("fsl,mpc8272ads"); -} - -define_machine(mpc8272_ads) -{ - .name = "Freescale MPC8272 ADS", - .probe = mpc8272_ads_probe, - .setup_arch = mpc8272_ads_setup_arch, - .discover_phbs = pq2_init_pci, - .init_IRQ = mpc8272_ads_pic_init, - .get_irq = cpm2_get_irq, - .calibrate_decr = generic_calibrate_decr, - .restart = pq2_restart, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c deleted file mode 100644 index cf3210042a2e..000000000000 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * PQ2 ADS-style PCI interrupt controller - * - * Copyright 2007 Freescale Semiconductor, Inc. - * Author: Scott Wood - * - * Loosely based on mpc82xx ADS support by Vitaly Bordug - * Copyright (c) 2006 MontaVista Software, Inc. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "pq2.h" - -static DEFINE_RAW_SPINLOCK(pci_pic_lock); - -struct pq2ads_pci_pic { - struct device_node *node; - struct irq_domain *host; - - struct { - u32 stat; - u32 mask; - } __iomem *regs; -}; - -#define NUM_IRQS 32 - -static void pq2ads_pci_mask_irq(struct irq_data *d) -{ - struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; - - if (irq != -1) { - unsigned long flags; - raw_spin_lock_irqsave(&pci_pic_lock, flags); - - setbits32(&priv->regs->mask, 1 << irq); - mb(); - - raw_spin_unlock_irqrestore(&pci_pic_lock, flags); - } -} - -static void pq2ads_pci_unmask_irq(struct irq_data *d) -{ - struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; - - if (irq != -1) { - unsigned long flags; - - raw_spin_lock_irqsave(&pci_pic_lock, flags); - clrbits32(&priv->regs->mask, 1 << irq); - raw_spin_unlock_irqrestore(&pci_pic_lock, flags); - } -} - -static struct irq_chip pq2ads_pci_ic = { - .name = "PQ2 ADS PCI", - .irq_mask = pq2ads_pci_mask_irq, - .irq_mask_ack = pq2ads_pci_mask_irq, - .irq_ack = pq2ads_pci_mask_irq, - .irq_unmask = pq2ads_pci_unmask_irq, - .irq_enable = pq2ads_pci_unmask_irq, - .irq_disable = pq2ads_pci_mask_irq -}; - -static void pq2ads_pci_irq_demux(struct irq_desc *desc) -{ - struct pq2ads_pci_pic *priv = irq_desc_get_handler_data(desc); - u32 stat, mask, pend; - int bit; - - for (;;) { - stat = in_be32(&priv->regs->stat); - mask = in_be32(&priv->regs->mask); - - pend = stat & ~mask; - - if (!pend) - break; - - for (bit = 0; pend != 0; ++bit, pend <<= 1) { - if (pend & 0x80000000) - generic_handle_domain_irq(priv->host, bit); - } - } -} - -static int pci_pic_host_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq); - return 0; -} - -static const struct irq_domain_ops pci_pic_host_ops = { - .map = pci_pic_host_map, -}; - -int __init pq2ads_pci_init_irq(void) -{ - struct pq2ads_pci_pic *priv; - struct irq_domain *host; - struct device_node *np; - int ret = -ENODEV; - int irq; - - np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic"); - if (!np) { - printk(KERN_ERR "No pci pic node in device tree.\n"); - goto out; - } - - irq = irq_of_parse_and_map(np, 0); - if (!irq) { - printk(KERN_ERR "No interrupt in pci pic node.\n"); - goto out_put_node; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out_unmap_irq; - } - - /* PCI interrupt controller registers: status and mask */ - priv->regs = of_iomap(np, 0); - if (!priv->regs) { - printk(KERN_ERR "Cannot map PCI PIC registers.\n"); - goto out_free_kmalloc; - } - - /* mask all PCI interrupts */ - out_be32(&priv->regs->mask, ~0); - mb(); - - host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv); - if (!host) { - ret = -ENOMEM; - goto out_unmap_regs; - } - - priv->host = host; - irq_set_handler_data(irq, priv); - irq_set_chained_handler(irq, pq2ads_pci_irq_demux); - ret = 0; - goto out_put_node; - -out_unmap_regs: - iounmap(priv->regs); -out_free_kmalloc: - kfree(priv); -out_unmap_irq: - irq_dispose_mapping(irq); -out_put_node: - of_node_put(np); -out: - return ret; -} diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h deleted file mode 100644 index 9d0bf744945c..000000000000 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * PQ2/mpc8260 board-specific stuff - * - * A collection of structures, addresses, and values associated with - * the Freescale MPC8260ADS/MPC8266ADS-PCI boards. - * Copied from the RPX-Classic and SBS8260 stuff. - * - * Author: Vitaly Bordug - * - * Originally written by Dan Malek for Motorola MPC8260 family - * - * Copyright (c) 2001 Dan Malek - * Copyright (c) 2006 MontaVista Software, Inc. - */ - -#ifdef __KERNEL__ -#ifndef __MACH_ADS8260_DEFS -#define __MACH_ADS8260_DEFS - -#include - -/* The ADS8260 has 16, 32-bit wide control/status registers, accessed - * only on word boundaries. - * Not all are used (yet), or are interesting to us (yet). - */ - -/* Things of interest in the CSR. - */ -#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */ -#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */ -#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable*/ -#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */ -#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ -#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ -#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ -#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */ - -#endif /* __MACH_ADS8260_DEFS */ -#endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c deleted file mode 100644 index ac9113d524af..000000000000 --- a/arch/powerpc/platforms/82xx/pq2fads.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * PQ2FADS board support - * - * Copyright 2007 Freescale Semiconductor, Inc. - * Author: Scott Wood - * - * Loosely based on mp82xx ADS support by Vitaly Bordug - * Copyright (c) 2006 MontaVista Software, Inc. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "pq2ads.h" -#include "pq2.h" - -static void __init pq2fads_pic_init(void) -{ - struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); - if (!np) { - printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); - return; - } - - cpm2_pic_init(np); - of_node_put(np); - - /* Initialize stuff for the 82xx CPLD IC and install demux */ - pq2ads_pci_init_irq(); -} - -struct cpm_pin { - int port, pin, flags; -}; - -static struct cpm_pin pq2fads_pins[] = { - /* SCC1 */ - {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* SCC2 */ - {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* FCC2 */ - {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, - {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - - /* FCC3 */ - {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, -}; - -static void __init init_ioports(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(pq2fads_pins); i++) { - struct cpm_pin *pin = &pq2fads_pins[i]; - cpm2_set_pin(pin->port, pin->pin, pin->flags); - } - - cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); - cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); -} - -static void __init pq2fads_setup_arch(void) -{ - struct device_node *np; - __be32 __iomem *bcsr; - - if (ppc_md.progress) - ppc_md.progress("pq2fads_setup_arch()", 0); - - cpm2_reset(); - - np = of_find_compatible_node(NULL, NULL, "fsl,pq2fads-bcsr"); - if (!np) { - printk(KERN_ERR "No fsl,pq2fads-bcsr in device tree\n"); - return; - } - - bcsr = of_iomap(np, 0); - of_node_put(np); - if (!bcsr) { - printk(KERN_ERR "Cannot map BCSR registers\n"); - return; - } - - /* Enable the serial and ethernet ports */ - - clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); - setbits32(&bcsr[1], BCSR1_FETH_RST); - - clrbits32(&bcsr[3], BCSR3_FETHIEN2); - setbits32(&bcsr[3], BCSR3_FETH2_RST); - - iounmap(bcsr); - - init_ioports(); - - /* Enable external IRQs */ - clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_siumcr, 0x0c000000); - - if (ppc_md.progress) - ppc_md.progress("pq2fads_setup_arch(), finish", 0); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init pq2fads_probe(void) -{ - return of_machine_is_compatible("fsl,pq2fads"); -} - -static const struct of_device_id of_bus_ids[] __initconst = { - { .name = "soc", }, - { .name = "cpm", }, - { .name = "localbus", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - /* Publish the QE devices */ - of_platform_bus_probe(NULL, of_bus_ids, NULL); - return 0; -} -machine_device_initcall(pq2fads, declare_of_platform_devices); - -define_machine(pq2fads) -{ - .name = "Freescale PQ2FADS", - .probe = pq2fads_probe, - .setup_arch = pq2fads_setup_arch, - .discover_phbs = pq2_init_pci, - .init_IRQ = pq2fads_pic_init, - .get_irq = cpm2_get_irq, - .calibrate_decr = generic_calibrate_decr, - .restart = pq2_restart, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index bee119725f61..d355ad40995f 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -25,13 +25,6 @@ config MPC831x_RDB help This option enables support for the MPC8313 RDB and MPC8315 RDB boards. -config MPC832x_MDS - bool "Freescale MPC832x MDS" - select DEFAULT_UIMAGE - select PPC_MPC832x - help - This option enables support for the MPC832x MDS evaluation board. - config MPC832x_RDB bool "Freescale MPC832x RDB" select DEFAULT_UIMAGE @@ -39,18 +32,6 @@ config MPC832x_RDB help This option enables support for the MPC8323 RDB board. -config MPC834x_MDS - bool "Freescale MPC834x MDS" - select DEFAULT_UIMAGE - select PPC_MPC834x - help - This option enables support for the MPC 834x MDS evaluation board. - - Be aware that PCI buses can only function when MDS board is plugged - into the PIB (Platform IO Board) board from Freescale which provide - 3 PCI slots. The PIBs PCI initialization is the bootloader's - responsibility. - config MPC834x_ITX bool "Freescale MPC834x ITX" select DEFAULT_UIMAGE @@ -61,12 +42,6 @@ config MPC834x_ITX Be aware that PCI initialization is the bootloader's responsibility. -config MPC836x_MDS - bool "Freescale MPC836x MDS" - select DEFAULT_UIMAGE - help - This option enables support for the MPC836x MDS Processor Board. - config MPC836x_RDK bool "Freescale/Logic MPC836x RDK" select DEFAULT_UIMAGE @@ -76,13 +51,6 @@ config MPC836x_RDK This option enables support for the MPC836x RDK Processor Board, also known as ZOOM PowerQUICC Kit. -config MPC837x_MDS - bool "Freescale MPC837x MDS" - select DEFAULT_UIMAGE - select PPC_MPC837x - help - This option enables support for the MPC837x MDS Processor Board. - config MPC837x_RDB bool "Freescale MPC837x RDB/WLAN" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 41cb5f842eff..6b4013e01b3b 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -8,12 +8,8 @@ obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o obj-$(CONFIG_MPC830x_RDB) += mpc830x_rdb.o obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o -obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o -obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o obj-$(CONFIG_MPC836x_RDK) += mpc836x_rdk.o -obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o -obj-$(CONFIG_MPC837x_MDS) += mpc837x_mds.o obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o obj-$(CONFIG_ASP834x) += asp834x.o obj-$(CONFIG_KMETER1) += km83xx.o diff --git a/arch/powerpc/platforms/83xx/asp834x.c b/arch/powerpc/platforms/83xx/asp834x.c index 68061c2a57c1..6870d0c34f1d 100644 --- a/arch/powerpc/platforms/83xx/asp834x.c +++ b/arch/powerpc/platforms/83xx/asp834x.c @@ -32,23 +32,14 @@ static void __init asp834x_setup_arch(void) machine_device_initcall(asp834x, mpc83xx_declare_of_platform_devices); -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init asp834x_probe(void) -{ - return of_machine_is_compatible("analogue-and-micro,asp8347e"); -} - define_machine(asp834x) { .name = "ASP8347E", - .probe = asp834x_probe, + .compatible = "analogue-and-micro,asp8347e", .setup_arch = asp834x_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c index 907acdecc94a..26ddc7136547 100644 --- a/arch/powerpc/platforms/83xx/km83xx.c +++ b/arch/powerpc/platforms/83xx/km83xx.c @@ -184,6 +184,5 @@ define_machine(mpc83xx_km) { .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index 956d4389effa..534bb227480d 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c @@ -53,6 +53,5 @@ define_machine(mpc830x_rdb) { .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index 3b578f080e3b..7b901ab3b864 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -53,6 +53,5 @@ define_machine(mpc831x_rdb) { .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c deleted file mode 100644 index 435344405d2c..000000000000 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. - * - * Description: - * MPC832xE MDS board specific routines. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpc83xx.h" - -#undef DEBUG -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc832x_sys_setup_arch(void) -{ - struct device_node *np; - u8 __iomem *bcsr_regs = NULL; - - mpc83xx_setup_arch(); - - /* Map BCSR area */ - np = of_find_node_by_name(NULL, "bcsr"); - if (np) { - struct resource res; - - of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, resource_size(&res)); - of_node_put(np); - } - -#ifdef CONFIG_QUICC_ENGINE - if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(np, "ucc") - par_io_of_config(np); - } - - if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) - != NULL){ - /* Reset the Ethernet PHYs */ -#define BCSR8_FETH_RST 0x50 - clrbits8(&bcsr_regs[8], BCSR8_FETH_RST); - udelay(1000); - setbits8(&bcsr_regs[8], BCSR8_FETH_RST); - iounmap(bcsr_regs); - of_node_put(np); - } -#endif /* CONFIG_QUICC_ENGINE */ -} - -machine_device_initcall(mpc832x_mds, mpc83xx_declare_of_platform_devices); - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc832x_sys_probe(void) -{ - return of_machine_is_compatible("MPC832xMDS"); -} - -define_machine(mpc832x_mds) { - .name = "MPC832x MDS", - .probe = mpc832x_sys_probe, - .setup_arch = mpc832x_sys_setup_arch, - .discover_phbs = mpc83xx_setup_pci, - .init_IRQ = mpc83xx_ipic_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 4ab1d48cd229..3b4e4173c59e 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -212,23 +212,14 @@ static void __init mpc832x_rdb_setup_arch(void) machine_device_initcall(mpc832x_rdb, mpc83xx_declare_of_platform_devices); -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc832x_rdb_probe(void) -{ - return of_machine_is_compatible("MPC832xRDB"); -} - define_machine(mpc832x_rdb) { .name = "MPC832x RDB", - .probe = mpc832x_rdb_probe, + .compatible = "MPC832xRDB", .setup_arch = mpc832x_rdb_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 6a110f275304..e45b98ff02d8 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -57,23 +57,14 @@ static void __init mpc834x_itx_setup_arch(void) mpc834x_usb_cfg(); } -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc834x_itx_probe(void) -{ - return of_machine_is_compatible("MPC834xMITX"); -} - define_machine(mpc834x_itx) { .name = "MPC834x ITX", - .probe = mpc834x_itx_probe, + .compatible = "MPC834xMITX", .setup_arch = mpc834x_itx_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c deleted file mode 100644 index 7dde5a75332b..000000000000 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/powerpc/platforms/83xx/mpc834x_mds.c - * - * MPC834x MDS board specific routines - * - * Maintainer: Kumar Gala - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpc83xx.h" - -#define BCSR5_INT_USB 0x02 -static int __init mpc834xemds_usb_cfg(void) -{ - struct device_node *np; - void __iomem *bcsr_regs = NULL; - u8 bcsr5; - - mpc834x_usb_cfg(); - /* Map BCSR area */ - np = of_find_node_by_name(NULL, "bcsr"); - if (np) { - struct resource res; - - of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, resource_size(&res)); - of_node_put(np); - } - if (!bcsr_regs) - return -1; - - /* - * if Processor Board is plugged into PIB board, - * force to use the PHY on Processor Board - */ - bcsr5 = in_8(bcsr_regs + 5); - if (!(bcsr5 & BCSR5_INT_USB)) - out_8(bcsr_regs + 5, (bcsr5 | BCSR5_INT_USB)); - iounmap(bcsr_regs); - return 0; -} - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc834x_mds_setup_arch(void) -{ - mpc83xx_setup_arch(); - - mpc834xemds_usb_cfg(); -} - -machine_device_initcall(mpc834x_mds, mpc83xx_declare_of_platform_devices); - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc834x_mds_probe(void) -{ - return of_machine_is_compatible("MPC834xMDS"); -} - -define_machine(mpc834x_mds) { - .name = "MPC834x MDS", - .probe = mpc834x_mds_probe, - .setup_arch = mpc834x_mds_setup_arch, - .discover_phbs = mpc83xx_setup_pci, - .init_IRQ = mpc83xx_ipic_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c deleted file mode 100644 index b1e6665be5d3..000000000000 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ /dev/null @@ -1,210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Li Yang - * Yin Olivia - * - * Description: - * MPC8360E MDS board specific routines. - * - * Changelog: - * Jun 21, 2006 Initial version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpc83xx.h" - -#undef DEBUG -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc836x_mds_setup_arch(void) -{ - struct device_node *np; - u8 __iomem *bcsr_regs = NULL; - - mpc83xx_setup_arch(); - - /* Map BCSR area */ - np = of_find_node_by_name(NULL, "bcsr"); - if (np) { - struct resource res; - - of_address_to_resource(np, 0, &res); - bcsr_regs = ioremap(res.start, resource_size(&res)); - of_node_put(np); - } - -#ifdef CONFIG_QUICC_ENGINE - if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(np, "ucc") - par_io_of_config(np); -#ifdef CONFIG_QE_USB - /* Must fixup Par IO before QE GPIO chips are registered. */ - par_io_config_pin(1, 2, 1, 0, 3, 0); /* USBOE */ - par_io_config_pin(1, 3, 1, 0, 3, 0); /* USBTP */ - par_io_config_pin(1, 8, 1, 0, 1, 0); /* USBTN */ - par_io_config_pin(1, 10, 2, 0, 3, 0); /* USBRXD */ - par_io_config_pin(1, 9, 2, 1, 3, 0); /* USBRP */ - par_io_config_pin(1, 11, 2, 1, 3, 0); /* USBRN */ - par_io_config_pin(2, 20, 2, 0, 1, 0); /* CLK21 */ -#endif /* CONFIG_QE_USB */ - } - - if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) - != NULL){ - uint svid; - - /* Reset the Ethernet PHY */ -#define BCSR9_GETHRST 0x20 - clrbits8(&bcsr_regs[9], BCSR9_GETHRST); - udelay(1000); - setbits8(&bcsr_regs[9], BCSR9_GETHRST); - - /* handle mpc8360ea rev.2.1 erratum 2: RGMII Timing */ - svid = mfspr(SPRN_SVR); - if (svid == 0x80480021) { - void __iomem *immap; - - immap = ioremap(get_immrbase() + 0x14a8, 8); - - /* - * IMMR + 0x14A8[4:5] = 11 (clk delay for UCC 2) - * IMMR + 0x14A8[18:19] = 11 (clk delay for UCC 1) - */ - setbits32(immap, 0x0c003000); - - /* - * IMMR + 0x14AC[20:27] = 10101010 - * (data delay for both UCC's) - */ - clrsetbits_be32(immap + 4, 0xff0, 0xaa0); - - iounmap(immap); - } - - iounmap(bcsr_regs); - of_node_put(np); - } -#endif /* CONFIG_QUICC_ENGINE */ -} - -machine_device_initcall(mpc836x_mds, mpc83xx_declare_of_platform_devices); - -#ifdef CONFIG_QE_USB -static int __init mpc836x_usb_cfg(void) -{ - u8 __iomem *bcsr; - struct device_node *np; - const char *mode; - int ret = 0; - - np = of_find_compatible_node(NULL, NULL, "fsl,mpc8360mds-bcsr"); - if (!np) - return -ENODEV; - - bcsr = of_iomap(np, 0); - of_node_put(np); - if (!bcsr) - return -ENOMEM; - - np = of_find_compatible_node(NULL, NULL, "fsl,mpc8323-qe-usb"); - if (!np) { - ret = -ENODEV; - goto err; - } - -#define BCSR8_TSEC1M_MASK (0x3 << 6) -#define BCSR8_TSEC1M_RGMII (0x0 << 6) -#define BCSR8_TSEC2M_MASK (0x3 << 4) -#define BCSR8_TSEC2M_RGMII (0x0 << 4) - /* - * Default is GMII (2), but we should set it to RGMII (0) if we use - * USB (Eth PHY is in RGMII mode anyway). - */ - clrsetbits_8(&bcsr[8], BCSR8_TSEC1M_MASK | BCSR8_TSEC2M_MASK, - BCSR8_TSEC1M_RGMII | BCSR8_TSEC2M_RGMII); - -#define BCSR13_USBMASK 0x0f -#define BCSR13_nUSBEN 0x08 /* 1 - Disable, 0 - Enable */ -#define BCSR13_USBSPEED 0x04 /* 1 - Full, 0 - Low */ -#define BCSR13_USBMODE 0x02 /* 1 - Host, 0 - Function */ -#define BCSR13_nUSBVCC 0x01 /* 1 - gets VBUS, 0 - supplies VBUS */ - - clrsetbits_8(&bcsr[13], BCSR13_USBMASK, BCSR13_USBSPEED); - - mode = of_get_property(np, "mode", NULL); - if (mode && !strcmp(mode, "peripheral")) { - setbits8(&bcsr[13], BCSR13_nUSBVCC); - qe_usb_clock_set(QE_CLK21, 48000000); - } else { - setbits8(&bcsr[13], BCSR13_USBMODE); - } - - of_node_put(np); -err: - iounmap(bcsr); - return ret; -} -machine_arch_initcall(mpc836x_mds, mpc836x_usb_cfg); -#endif /* CONFIG_QE_USB */ - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc836x_mds_probe(void) -{ - return of_machine_is_compatible("MPC836xMDS"); -} - -define_machine(mpc836x_mds) { - .name = "MPC836x MDS", - .probe = mpc836x_mds_probe, - .setup_arch = mpc836x_mds_setup_arch, - .discover_phbs = mpc83xx_setup_pci, - .init_IRQ = mpc83xx_ipic_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c index 731bc5ce726d..1fc9d1235a7c 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -28,23 +28,14 @@ static void __init mpc836x_rdk_setup_arch(void) mpc83xx_setup_arch(); } -/* - * Called very early, MMU is off, device-tree isn't unflattened. - */ -static int __init mpc836x_rdk_probe(void) -{ - return of_machine_is_compatible("fsl,mpc8360rdk"); -} - define_machine(mpc836x_rdk) { .name = "MPC836x RDK", - .probe = mpc836x_rdk_probe, + .compatible = "fsl,mpc8360rdk", .setup_arch = mpc836x_rdk_setup_arch, .discover_phbs = mpc83xx_setup_pci, .init_IRQ = mpc83xx_ipic_init_IRQ, .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c deleted file mode 100644 index fa3538803af7..000000000000 --- a/arch/powerpc/platforms/83xx/mpc837x_mds.c +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/powerpc/platforms/83xx/mpc837x_mds.c - * - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * MPC837x MDS board specific routines - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mpc83xx.h" - -#define BCSR12_USB_SER_MASK 0x8a -#define BCSR12_USB_SER_PIN 0x80 -#define BCSR12_USB_SER_DEVICE 0x02 - -static int __init mpc837xmds_usb_cfg(void) -{ - struct device_node *np; - const void *phy_type, *mode; - void __iomem *bcsr_regs = NULL; - u8 bcsr12; - int ret; - - ret = mpc837x_usb_cfg(); - if (ret) - return ret; - /* Map BCSR area */ - np = of_find_compatible_node(NULL, NULL, "fsl,mpc837xmds-bcsr"); - if (np) { - bcsr_regs = of_iomap(np, 0); - of_node_put(np); - } - if (!bcsr_regs) - return -1; - - np = of_find_node_by_name(NULL, "usb"); - if (!np) { - ret = -ENODEV; - goto out; - } - phy_type = of_get_property(np, "phy_type", NULL); - if (phy_type && !strcmp(phy_type, "ulpi")) { - clrbits8(bcsr_regs + 12, BCSR12_USB_SER_PIN); - } else if (phy_type && !strcmp(phy_type, "serial")) { - mode = of_get_property(np, "dr_mode", NULL); - bcsr12 = in_8(bcsr_regs + 12) & ~BCSR12_USB_SER_MASK; - bcsr12 |= BCSR12_USB_SER_PIN; - if (mode && !strcmp(mode, "peripheral")) - bcsr12 |= BCSR12_USB_SER_DEVICE; - out_8(bcsr_regs + 12, bcsr12); - } else { - printk(KERN_ERR "USB DR: unsupported PHY\n"); - } - - of_node_put(np); -out: - iounmap(bcsr_regs); - return ret; -} - -/* ************************************************************************ - * - * Setup the architecture - * - */ -static void __init mpc837x_mds_setup_arch(void) -{ - mpc83xx_setup_arch(); - mpc837xmds_usb_cfg(); -} - -machine_device_initcall(mpc837x_mds, mpc83xx_declare_of_platform_devices); - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init mpc837x_mds_probe(void) -{ - return of_machine_is_compatible("fsl,mpc837xmds"); -} - -define_machine(mpc837x_mds) { - .name = "MPC837x MDS", - .probe = mpc837x_mds_probe, - .setup_arch = mpc837x_mds_setup_arch, - .discover_phbs = mpc83xx_setup_pci, - .init_IRQ = mpc83xx_ipic_init_IRQ, - .get_irq = ipic_get_irq, - .restart = mpc83xx_restart, - .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 5d48c6842098..39e78018dd0b 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -78,6 +78,5 @@ define_machine(mpc837x_rdb) { .get_irq = ipic_get_irq, .restart = mpc83xx_restart, .time_init = mpc83xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index b92cb2b4d54d..9315a3b69d6d 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -78,24 +78,37 @@ config MPC8536_DS This option enables support for the MPC8536 DS board config MPC85xx_DS - bool "Freescale MPC8544 DS / MPC8572 DS / P2020 DS" + bool "Freescale MPC8544 DS / MPC8572 DS" select PPC_I8259 select DEFAULT_UIMAGE select FSL_ULI1575 if PCI select SWIOTLB help - This option enables support for the MPC8544 DS, MPC8572 DS and P2020 DS boards + This option enables support for the MPC8544 DS and MPC8572 DS boards config MPC85xx_RDB - bool "Freescale P102x MBG/UTM/RDB and P2020 RDB" + bool "Freescale P102x MBG/UTM/RDB" select PPC_I8259 select DEFAULT_UIMAGE - select FSL_ULI1575 if PCI select SWIOTLB help This option enables support for the P1020 MBG PC, P1020 UTM PC, P1020 RDB PC, P1020 RDB PD, P1020 RDB, P1021 RDB PC, P1024 RDB, - P1025 RDB, P2020 RDB and P2020 RDB PC boards + and P1025 RDB boards + +config PPC_P2020 + bool "Freescale P2020" + default y if MPC85xx_DS || MPC85xx_RDB + select DEFAULT_UIMAGE + select SWIOTLB + imply PPC_I8259 + imply FSL_ULI1575 if PCI + help + This option enables generic unified support for any board with the + Freescale P2020 processor. + + For example: P2020 DS board, P2020 RDB board, P2020 RDB PC board or + CZ.NIC Turris 1.x boards. config P1010_RDB bool "Freescale P1010 RDB" diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 260fbad7967b..e3d977624e33 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -16,13 +16,15 @@ obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o obj-$(CONFIG_MPC8536_DS) += mpc8536_ds.o -obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o +obj8259-$(CONFIG_PPC_I8259) += mpc85xx_8259.o +obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o $(obj8259-y) obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o obj-$(CONFIG_P1010_RDB) += p1010rdb.o obj-$(CONFIG_P1022_DS) += p1022_ds.o obj-$(CONFIG_P1022_RDK) += p1022_rdk.o obj-$(CONFIG_P1023_RDB) += p1023_rdb.o +obj-$(CONFIG_PPC_P2020) += p2020.o $(obj8259-y) obj-$(CONFIG_TWR_P102x) += twr_p102x.o obj-$(CONFIG_CORENET_GENERIC) += corenet_generic.o obj-$(CONFIG_FB_FSL_DIU) += t1042rdb_diu.o diff --git a/arch/powerpc/platforms/85xx/bsc913x_qds.c b/arch/powerpc/platforms/85xx/bsc913x_qds.c index bcbbeb5a972a..a029aa090538 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_qds.c +++ b/arch/powerpc/platforms/85xx/bsc913x_qds.c @@ -50,24 +50,14 @@ static void __init bsc913x_qds_setup_arch(void) machine_arch_initcall(bsc9132_qds, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ - -static int __init bsc9132_qds_probe(void) -{ - return of_machine_is_compatible("fsl,bsc9132qds"); -} - define_machine(bsc9132_qds) { .name = "BSC9132 QDS", - .probe = bsc9132_qds_probe, + .compatible = "fsl,bsc9132qds", .setup_arch = bsc913x_qds_setup_arch, .init_IRQ = bsc913x_qds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/bsc913x_rdb.c b/arch/powerpc/platforms/85xx/bsc913x_rdb.c index f78e5d3deedb..361b4371d073 100644 --- a/arch/powerpc/platforms/85xx/bsc913x_rdb.c +++ b/arch/powerpc/platforms/85xx/bsc913x_rdb.c @@ -40,21 +40,11 @@ static void __init bsc913x_rdb_setup_arch(void) machine_device_initcall(bsc9131_rdb, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ - -static int __init bsc9131_rdb_probe(void) -{ - return of_machine_is_compatible("fsl,bsc9131rdb"); -} - define_machine(bsc9131_rdb) { .name = "BSC9131 RDB", - .probe = bsc9131_rdb_probe, + .compatible = "fsl,bsc9131rdb", .setup_arch = bsc913x_rdb_setup_arch, .init_IRQ = bsc913x_rdb_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/c293pcie.c b/arch/powerpc/platforms/85xx/c293pcie.c index 58a398c89e97..34975708be79 100644 --- a/arch/powerpc/platforms/85xx/c293pcie.c +++ b/arch/powerpc/platforms/85xx/c293pcie.c @@ -45,22 +45,11 @@ static void __init c293_pcie_setup_arch(void) machine_arch_initcall(c293_pcie, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init c293_pcie_probe(void) -{ - if (of_machine_is_compatible("fsl,C293PCIE")) - return 1; - return 0; -} - define_machine(c293_pcie) { .name = "C293 PCIE", - .probe = c293_pcie_probe, + .compatible = "fsl,C293PCIE", .setup_arch = c293_pcie_setup_arch, .init_IRQ = c293_pcie_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index 2c539de2d629..bfde391c42f4 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -198,7 +198,6 @@ define_machine(corenet_generic) { #else .get_irq = mpic_get_coreint_irq, #endif - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .power_save = e500_idle, }; diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c index e3e8f18825a1..3678a1fbf5ad 100644 --- a/arch/powerpc/platforms/85xx/ge_imp3a.c +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -190,19 +190,11 @@ static void ge_imp3a_show_cpuinfo(struct seq_file *m) ge_imp3a_get_cpci_is_syscon() ? "yes" : "no"); } -/* - * Called very early, device-tree isn't unflattened - */ -static int __init ge_imp3a_probe(void) -{ - return of_machine_is_compatible("ge,IMP3A"); -} - machine_arch_initcall(ge_imp3a, mpc85xx_common_publish_devices); define_machine(ge_imp3a) { .name = "GE_IMP3A", - .probe = ge_imp3a_probe, + .compatible = "ge,IMP3A", .setup_arch = ge_imp3a_setup_arch, .init_IRQ = ge_imp3a_pic_init, .show_cpuinfo = ge_imp3a_show_cpuinfo, @@ -211,6 +203,5 @@ define_machine(ge_imp3a) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index a22f02b0fc77..af38c3aec042 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -172,21 +172,12 @@ static void ksi8560_show_cpuinfo(struct seq_file *m) machine_device_initcall(ksi8560, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init ksi8560_probe(void) -{ - return of_machine_is_compatible("emerson,KSI8560"); -} - define_machine(ksi8560) { .name = "KSI8560", - .probe = ksi8560_probe, + .compatible = "emerson,KSI8560", .setup_arch = ksi8560_setup_arch, .init_IRQ = ksi8560_pic_init, .show_cpuinfo = ksi8560_show_cpuinfo, .get_irq = mpic_get_irq, .restart = machine_restart, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index e5d7386ad612..58ab3831913f 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -52,17 +52,9 @@ static void __init mpc8536_ds_setup_arch(void) machine_arch_initcall(mpc8536_ds, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc8536_ds_probe(void) -{ - return of_machine_is_compatible("fsl,mpc8536ds"); -} - define_machine(mpc8536_ds) { .name = "MPC8536 DS", - .probe = mpc8536_ds_probe, + .compatible = "fsl,mpc8536ds", .setup_arch = mpc8536_ds_setup_arch, .init_IRQ = mpc8536_ds_pic_init, #ifdef CONFIG_PCI @@ -70,6 +62,5 @@ define_machine(mpc8536_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index cb84c5c56c36..c764d7551ef1 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -15,4 +15,10 @@ extern void mpc85xx_qe_par_io_init(void); static inline void __init mpc85xx_qe_par_io_init(void) {} #endif +#ifdef CONFIG_PPC_I8259 +void __init mpc85xx_8259_init(void); +#else +static inline void __init mpc85xx_8259_init(void) {} +#endif + #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_8259.c b/arch/powerpc/platforms/85xx/mpc85xx_8259.c new file mode 100644 index 000000000000..cb00d596ad80 --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_8259.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MPC85xx 8259 functions for DS Board Setup + * + * Author Xianghua Xiao (x.xiao@freescale.com) + * Roy Zang + * - Add PCI/PCI Express support + * Copyright 2007 Freescale Semiconductor Inc. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "mpc85xx.h" + +static void mpc85xx_8259_cascade(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq = i8259_irq(); + + if (cascade_irq) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + +void __init mpc85xx_8259_init(void) +{ + struct device_node *np; + struct device_node *cascade_node = NULL; + int cascade_irq; + + /* Initialize the i8259 controller */ + for_each_node_by_type(np, "interrupt-controller") { + if (of_device_is_compatible(np, "chrp,iic")) { + cascade_node = np; + break; + } + } + + if (cascade_node == NULL) { + pr_debug("i8259: Could not find i8259 PIC\n"); + return; + } + + cascade_irq = irq_of_parse_and_map(cascade_node, 0); + if (!cascade_irq) { + pr_err("i8259: Failed to map cascade interrupt\n"); + return; + } + + pr_debug("i8259: cascade mapped to irq %d\n", cascade_irq); + + i8259_init(cascade_node, 0); + of_node_put(cascade_node); + + irq_set_chained_handler(cascade_irq, mpc85xx_8259_cascade); +} diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index a34fc037957d..7c67438e76f8 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -151,21 +151,12 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) machine_arch_initcall(mpc85xx_ads, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc85xx_ads_probe(void) -{ - return of_machine_is_compatible("MPC85xxADS"); -} - define_machine(mpc85xx_ads) { .name = "MPC85xx ADS", - .probe = mpc85xx_ads_probe, + .compatible = "MPC85xxADS", .setup_arch = mpc85xx_ads_setup_arch, .init_IRQ = mpc85xx_ads_pic_init, .show_cpuinfo = mpc85xx_ads_show_cpuinfo, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 0b8f2101c5fb..0e6964c7fdd6 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -370,20 +370,11 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc85xx_cds_probe(void) -{ - return of_machine_is_compatible("MPC85xxCDS"); -} - machine_arch_initcall(mpc85xx_cds, mpc85xx_common_publish_devices); define_machine(mpc85xx_cds) { .name = "MPC85xx CDS", - .probe = mpc85xx_cds_probe, + .compatible = "MPC85xxCDS", .setup_arch = mpc85xx_cds_setup_arch, .init_IRQ = mpc85xx_cds_pic_init, .show_cpuinfo = mpc85xx_cds_show_cpuinfo, @@ -392,6 +383,5 @@ define_machine(mpc85xx_cds) { .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index f8d2c97f39bd..4347d629b567 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -33,113 +34,22 @@ #include "mpc85xx.h" -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) -#else -#define DBG(fmt, args...) -#endif - -#ifdef CONFIG_PPC_I8259 -static void mpc85xx_8259_cascade(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - unsigned int cascade_irq = i8259_irq(); - - if (cascade_irq) { - generic_handle_irq(cascade_irq); - } - chip->irq_eoi(&desc->irq_data); -} -#endif /* CONFIG_PPC_I8259 */ - -void __init mpc85xx_ds_pic_init(void) +static void __init mpc85xx_ds_pic_init(void) { struct mpic *mpic; -#ifdef CONFIG_PPC_I8259 - struct device_node *np; - struct device_node *cascade_node = NULL; - int cascade_irq; -#endif - if (of_machine_is_compatible("fsl,MPC8572DS-CAMP")) { - mpic = mpic_alloc(NULL, 0, - MPIC_NO_RESET | - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } else { - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } + int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU; + + if (of_machine_is_compatible("fsl,MPC8572DS-CAMP")) + flags |= MPIC_NO_RESET; + + mpic = mpic_alloc(NULL, 0, flags, 0, 256, " OpenPIC "); + + if (WARN_ON(!mpic)) + return; - BUG_ON(mpic == NULL); mpic_init(mpic); -#ifdef CONFIG_PPC_I8259 - /* Initialize the i8259 controller */ - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "chrp,iic")) { - cascade_node = np; - break; - } - - if (cascade_node == NULL) { - printk(KERN_DEBUG "Could not find i8259 PIC\n"); - return; - } - - cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (!cascade_irq) { - printk(KERN_ERR "Failed to map cascade interrupt\n"); - return; - } - - DBG("mpc85xxds: cascade mapped to irq %d\n", cascade_irq); - - i8259_init(cascade_node, 0); - of_node_put(cascade_node); - - irq_set_chained_handler(cascade_irq, mpc85xx_8259_cascade); -#endif /* CONFIG_PPC_I8259 */ -} - -#ifdef CONFIG_PCI -extern int uli_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn); - -static struct device_node *pci_with_uli; - -static int mpc85xx_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) -{ - if (hose->dn == pci_with_uli) - return uli_exclude_device(hose, bus, devfn); - - return PCIBIOS_SUCCESSFUL; -} -#endif /* CONFIG_PCI */ - -static void __init mpc85xx_ds_uli_init(void) -{ -#ifdef CONFIG_PCI - struct device_node *node; - - /* See if we have a ULI under the primary */ - - node = of_find_node_by_name(NULL, "uli1575"); - while ((pci_with_uli = of_get_parent(node))) { - of_node_put(node); - node = pci_with_uli; - - if (pci_with_uli == fsl_pci_primary) { - ppc_md.pci_exclude_device = mpc85xx_exclude_device; - break; - } - } -#endif + mpc85xx_8259_init(); } /* @@ -152,43 +62,18 @@ static void __init mpc85xx_ds_setup_arch(void) swiotlb_detect_4g(); fsl_pci_assign_primary(); - mpc85xx_ds_uli_init(); + uli_init(); mpc85xx_smp_init(); - printk("MPC85xx DS board from Freescale Semiconductor\n"); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc8544_ds_probe(void) -{ - return !!of_machine_is_compatible("MPC8544DS"); + pr_info("MPC85xx DS board from Freescale Semiconductor\n"); } machine_arch_initcall(mpc8544_ds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8572_ds, mpc85xx_common_publish_devices); -machine_arch_initcall(p2020_ds, mpc85xx_common_publish_devices); - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc8572_ds_probe(void) -{ - return !!of_machine_is_compatible("fsl,MPC8572DS"); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init p2020_ds_probe(void) -{ - return !!of_machine_is_compatible("fsl,P2020DS"); -} define_machine(mpc8544_ds) { .name = "MPC8544 DS", - .probe = mpc8544_ds_probe, + .compatible = "MPC8544DS", .setup_arch = mpc85xx_ds_setup_arch, .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI @@ -196,13 +81,12 @@ define_machine(mpc8544_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(mpc8572_ds) { .name = "MPC8572 DS", - .probe = mpc8572_ds_probe, + .compatible = "fsl,MPC8572DS", .setup_arch = mpc85xx_ds_setup_arch, .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI @@ -210,20 +94,5 @@ define_machine(mpc8572_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p2020_ds) { - .name = "P2020 DS", - .probe = p2020_ds_probe, - .setup_arch = mpc85xx_ds_setup_arch, - .init_IRQ = mpc85xx_ds_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, - .pcibios_fixup_phb = fsl_pcibios_fixup_phb, -#endif - .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 3a2ac410af18..0546f19416c2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -49,13 +49,6 @@ #include "mpc85xx.h" -#undef DEBUG -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - #if IS_BUILTIN(CONFIG_PHYLIB) #define MV88E1111_SCR 0x10 @@ -339,18 +332,12 @@ static void __init mpc85xx_mds_pic_init(void) mpic_init(mpic); } -static int __init mpc85xx_mds_probe(void) -{ - return of_machine_is_compatible("MPC85xxMDS"); -} - define_machine(mpc8568_mds) { .name = "MPC8568 MDS", - .probe = mpc85xx_mds_probe, + .compatible = "MPC85xxMDS", .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, @@ -358,18 +345,12 @@ define_machine(mpc8568_mds) { #endif }; -static int __init mpc8569_mds_probe(void) -{ - return of_machine_is_compatible("fsl,MPC8569EMDS"); -} - define_machine(mpc8569_mds) { .name = "MPC8569 MDS", - .probe = mpc8569_mds_probe, + .compatible = "fsl,MPC8569EMDS", .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, @@ -377,19 +358,12 @@ define_machine(mpc8569_mds) { #endif }; -static int __init p1021_mds_probe(void) -{ - return of_machine_is_compatible("fsl,P1021MDS"); - -} - define_machine(p1021_mds) { .name = "P1021 MDS", - .probe = p1021_mds_probe, + .compatible = "fsl,P1021MDS", .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index d99aba158235..c42a68da6dfd 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -29,32 +29,19 @@ #include "mpc85xx.h" -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) -#else -#define DBG(fmt, args...) -#endif - - -void __init mpc85xx_rdb_pic_init(void) +static void __init mpc85xx_rdb_pic_init(void) { struct mpic *mpic; + int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU; - if (of_machine_is_compatible("fsl,MPC85XXRDB-CAMP")) { - mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET | - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } else { - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } + if (of_machine_is_compatible("fsl,MPC85XXRDB-CAMP")) + flags |= MPIC_NO_RESET; + + mpic = mpic_alloc(NULL, 0, flags, 0, 256, " OpenPIC "); + + if (WARN_ON(!mpic)) + return; - BUG_ON(mpic == NULL); mpic_init(mpic); } @@ -70,7 +57,6 @@ static void __init mpc85xx_rdb_setup_arch(void) fsl_pci_assign_primary(); -#ifdef CONFIG_QUICC_ENGINE mpc85xx_qe_par_io_init(); #if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) if (machine_is(p1025_rdb)) { @@ -103,13 +89,10 @@ static void __init mpc85xx_rdb_setup_arch(void) } #endif -#endif /* CONFIG_QUICC_ENGINE */ - printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); + pr_info("MPC85xx RDB board from Freescale Semiconductor\n"); } -machine_arch_initcall(p2020_rdb, mpc85xx_common_publish_devices); -machine_arch_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); machine_arch_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); machine_arch_initcall(p1020_rdb, mpc85xx_common_publish_devices); machine_arch_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); @@ -119,84 +102,9 @@ machine_arch_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); machine_arch_initcall(p1025_rdb, mpc85xx_common_publish_devices); machine_arch_initcall(p1024_rdb, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init p2020_rdb_probe(void) -{ - if (of_machine_is_compatible("fsl,P2020RDB")) - return 1; - return 0; -} - -static int __init p1020_rdb_probe(void) -{ - if (of_machine_is_compatible("fsl,P1020RDB")) - return 1; - return 0; -} - -static int __init p1020_rdb_pc_probe(void) -{ - return of_machine_is_compatible("fsl,P1020RDB-PC"); -} - -static int __init p1020_rdb_pd_probe(void) -{ - return of_machine_is_compatible("fsl,P1020RDB-PD"); -} - -static int __init p1021_rdb_pc_probe(void) -{ - if (of_machine_is_compatible("fsl,P1021RDB-PC")) - return 1; - return 0; -} - -static int __init p2020_rdb_pc_probe(void) -{ - if (of_machine_is_compatible("fsl,P2020RDB-PC")) - return 1; - return 0; -} - -static int __init p1025_rdb_probe(void) -{ - return of_machine_is_compatible("fsl,P1025RDB"); -} - -static int __init p1020_mbg_pc_probe(void) -{ - return of_machine_is_compatible("fsl,P1020MBG-PC"); -} - -static int __init p1020_utm_pc_probe(void) -{ - return of_machine_is_compatible("fsl,P1020UTM-PC"); -} - -static int __init p1024_rdb_probe(void) -{ - return of_machine_is_compatible("fsl,P1024RDB"); -} - -define_machine(p2020_rdb) { - .name = "P2020 RDB", - .probe = p2020_rdb_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, - .pcibios_fixup_phb = fsl_pcibios_fixup_phb, -#endif - .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - define_machine(p1020_rdb) { .name = "P1020 RDB", - .probe = p1020_rdb_probe, + .compatible = "fsl,P1020RDB", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -204,13 +112,12 @@ define_machine(p1020_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1021_rdb_pc) { .name = "P1021 RDB-PC", - .probe = p1021_rdb_pc_probe, + .compatible = "fsl,P1021RDB-PC", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -218,27 +125,12 @@ define_machine(p1021_rdb_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p2020_rdb_pc) { - .name = "P2020RDB-PC", - .probe = p2020_rdb_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, - .pcibios_fixup_phb = fsl_pcibios_fixup_phb, -#endif - .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1025_rdb) { .name = "P1025 RDB", - .probe = p1025_rdb_probe, + .compatible = "fsl,P1025RDB", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -246,13 +138,12 @@ define_machine(p1025_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1020_mbg_pc) { .name = "P1020 MBG-PC", - .probe = p1020_mbg_pc_probe, + .compatible = "fsl,P1020MBG-PC", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -260,13 +151,12 @@ define_machine(p1020_mbg_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1020_utm_pc) { .name = "P1020 UTM-PC", - .probe = p1020_utm_pc_probe, + .compatible = "fsl,P1020UTM-PC", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -274,13 +164,12 @@ define_machine(p1020_utm_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1020_rdb_pc) { .name = "P1020RDB-PC", - .probe = p1020_rdb_pc_probe, + .compatible = "fsl,P1020RDB-PC", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -288,13 +177,12 @@ define_machine(p1020_rdb_pc) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1020_rdb_pd) { .name = "P1020RDB-PD", - .probe = p1020_rdb_pd_probe, + .compatible = "fsl,P1020RDB-PD", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -302,13 +190,12 @@ define_machine(p1020_rdb_pd) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(p1024_rdb) { .name = "P1024 RDB", - .probe = p1024_rdb_probe, + .compatible = "fsl,P1024RDB", .setup_arch = mpc85xx_rdb_setup_arch, .init_IRQ = mpc85xx_rdb_pic_init, #ifdef CONFIG_PCI @@ -316,6 +203,5 @@ define_machine(p1024_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mvme2500.c b/arch/powerpc/platforms/85xx/mvme2500.c index 69d5aa082a4b..1b59e45a0c64 100644 --- a/arch/powerpc/platforms/85xx/mvme2500.c +++ b/arch/powerpc/platforms/85xx/mvme2500.c @@ -43,17 +43,9 @@ static void __init mvme2500_setup_arch(void) machine_arch_initcall(mvme2500, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mvme2500_probe(void) -{ - return of_machine_is_compatible("artesyn,MVME2500"); -} - define_machine(mvme2500) { .name = "MVME2500", - .probe = mvme2500_probe, + .compatible = "artesyn,MVME2500", .setup_arch = mvme2500_setup_arch, .init_IRQ = mvme2500_pic_init, #ifdef CONFIG_PCI @@ -61,6 +53,5 @@ define_machine(mvme2500) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 8ba9306a96b6..14ec79a32746 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -73,6 +73,5 @@ define_machine(p1010_rdb) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 537599906146..23d0926298b9 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -549,17 +549,9 @@ static void __init p1022_ds_setup_arch(void) machine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init p1022_ds_probe(void) -{ - return of_machine_is_compatible("fsl,p1022ds"); -} - define_machine(p1022_ds) { .name = "P1022 DS", - .probe = p1022_ds_probe, + .compatible = "fsl,p1022ds", .setup_arch = p1022_ds_setup_arch, .init_IRQ = p1022_ds_pic_init, #ifdef CONFIG_PCI @@ -567,6 +559,5 @@ define_machine(p1022_ds) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c index bc58a99164c9..d1159150c3b5 100644 --- a/arch/powerpc/platforms/85xx/p1022_rdk.c +++ b/arch/powerpc/platforms/85xx/p1022_rdk.c @@ -129,17 +129,9 @@ static void __init p1022_rdk_setup_arch(void) machine_arch_initcall(p1022_rdk, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init p1022_rdk_probe(void) -{ - return of_machine_is_compatible("fsl,p1022rdk"); -} - define_machine(p1022_rdk) { .name = "P1022 RDK", - .probe = p1022_rdk_probe, + .compatible = "fsl,p1022rdk", .setup_arch = p1022_rdk_setup_arch, .init_IRQ = p1022_rdk_pic_init, #ifdef CONFIG_PCI @@ -147,6 +139,5 @@ define_machine(p1022_rdk) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/p1023_rdb.c b/arch/powerpc/platforms/85xx/p1023_rdb.c index c04868eb2eb1..9df0439a9382 100644 --- a/arch/powerpc/platforms/85xx/p1023_rdb.c +++ b/arch/powerpc/platforms/85xx/p1023_rdb.c @@ -37,7 +37,7 @@ * Setup the architecture * */ -static void __init mpc85xx_rdb_setup_arch(void) +static void __init p1023_rdb_setup_arch(void) { struct device_node *np; @@ -83,7 +83,7 @@ static void __init mpc85xx_rdb_setup_arch(void) machine_arch_initcall(p1023_rdb, mpc85xx_common_publish_devices); -static void __init mpc85xx_rdb_pic_init(void) +static void __init p1023_rdb_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, @@ -94,19 +94,12 @@ static void __init mpc85xx_rdb_pic_init(void) mpic_init(mpic); } -static int __init p1023_rdb_probe(void) -{ - return of_machine_is_compatible("fsl,P1023RDB"); - -} - define_machine(p1023_rdb) { .name = "P1023 RDB", - .probe = p1023_rdb_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, + .compatible = "fsl,P1023RDB", + .setup_arch = p1023_rdb_setup_arch, + .init_IRQ = p1023_rdb_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/85xx/p2020.c b/arch/powerpc/platforms/85xx/p2020.c new file mode 100644 index 000000000000..0e4d715145af --- /dev/null +++ b/arch/powerpc/platforms/85xx/p2020.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Freescale P2020 board Setup + * + * Copyright 2007,2009,2012-2013 Freescale Semiconductor Inc. + * Copyright 2022-2023 Pali Rohár + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "smp.h" +#include "mpc85xx.h" + +static void __init p2020_pic_init(void) +{ + struct mpic *mpic; + int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU; + + mpic = mpic_alloc(NULL, 0, flags, 0, 256, " OpenPIC "); + + if (WARN_ON(!mpic)) + return; + + mpic_init(mpic); + mpc85xx_8259_init(); +} + +/* + * Setup the architecture + */ +static void __init p2020_setup_arch(void) +{ + swiotlb_detect_4g(); + fsl_pci_assign_primary(); + uli_init(); + mpc85xx_smp_init(); + mpc85xx_qe_par_io_init(); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init p2020_probe(void) +{ + struct device_node *p2020_cpu; + + /* + * There is no common compatible string for all P2020 boards. + * The only common thing is "PowerPC,P2020@0" cpu node. + * So check for P2020 board via this cpu node. + */ + p2020_cpu = of_find_node_by_path("/cpus/PowerPC,P2020@0"); + of_node_put(p2020_cpu); + + return !!p2020_cpu; +} + +machine_arch_initcall(p2020, mpc85xx_common_publish_devices); + +define_machine(p2020) { + .name = "Freescale P2020", + .probe = p2020_probe, + .setup_arch = p2020_setup_arch, + .init_IRQ = p2020_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, +#endif + .get_irq = mpic_get_irq, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/ppa8548.c b/arch/powerpc/platforms/85xx/ppa8548.c index 0faf2990bf2c..acd19c52ad43 100644 --- a/arch/powerpc/platforms/85xx/ppa8548.c +++ b/arch/powerpc/platforms/85xx/ppa8548.c @@ -72,21 +72,12 @@ static int __init declare_of_platform_devices(void) } machine_device_initcall(ppa8548, declare_of_platform_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init ppa8548_probe(void) -{ - return of_machine_is_compatible("ppa8548"); -} - define_machine(ppa8548) { .name = "ppa8548", - .probe = ppa8548_probe, + .compatible = "ppa8548", .setup_arch = ppa8548_setup_arch, .init_IRQ = ppa8548_pic_init, .show_cpuinfo = ppa8548_show_cpuinfo, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c index 1639e222cc33..6e4b1ddf292b 100644 --- a/arch/powerpc/platforms/85xx/qemu_e500.c +++ b/arch/powerpc/platforms/85xx/qemu_e500.c @@ -46,19 +46,11 @@ static void __init qemu_e500_setup_arch(void) mpc85xx_smp_init(); } -/* - * Called very early, device-tree isn't unflattened - */ -static int __init qemu_e500_probe(void) -{ - return !!of_machine_is_compatible("fsl,qemu-e500"); -} - machine_arch_initcall(qemu_e500, mpc85xx_common_publish_devices); define_machine(qemu_e500) { .name = "QEMU e500", - .probe = qemu_e500_probe, + .compatible = "fsl,qemu-e500", .setup_arch = qemu_e500_setup_arch, .init_IRQ = qemu_e500_pic_init, #ifdef CONFIG_PCI @@ -66,7 +58,6 @@ define_machine(qemu_e500) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_coreint_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .power_save = e500_idle, }; diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 09f64470c765..9fa1338bc002 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -69,23 +69,11 @@ static void __init socrates_setup_arch(void) machine_arch_initcall(socrates, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init socrates_probe(void) -{ - if (of_machine_is_compatible("abb,socrates")) - return 1; - - return 0; -} - define_machine(socrates) { .name = "Socrates", - .probe = socrates_probe, + .compatible = "abb,socrates", .setup_arch = socrates_setup_arch, .init_IRQ = socrates_pic_init, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index 6b1fe7bb3a8c..5e2646b4c039 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -83,21 +83,12 @@ static void stx_gp3_show_cpuinfo(struct seq_file *m) machine_arch_initcall(stx_gp3, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init stx_gp3_probe(void) -{ - return of_machine_is_compatible("stx,gp3-8560"); -} - define_machine(stx_gp3) { .name = "STX GP3", - .probe = stx_gp3_probe, + .compatible = "stx,gp3-8560", .setup_arch = stx_gp3_setup_arch, .init_IRQ = stx_gp3_pic_init, .show_cpuinfo = stx_gp3_show_cpuinfo, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index d187f4b8bff6..80effb028bf4 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -127,6 +127,5 @@ define_machine(tqm85xx) { .init_IRQ = tqm85xx_pic_init, .show_cpuinfo = tqm85xx_show_cpuinfo, .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c index eaec099b4077..b88e23a334a4 100644 --- a/arch/powerpc/platforms/85xx/twr_p102x.c +++ b/arch/powerpc/platforms/85xx/twr_p102x.c @@ -103,20 +103,14 @@ static void __init twr_p1025_setup_arch(void) machine_arch_initcall(twr_p1025, mpc85xx_common_publish_devices); -static int __init twr_p1025_probe(void) -{ - return of_machine_is_compatible("fsl,TWR-P1025"); -} - define_machine(twr_p1025) { .name = "TWR-P1025", - .probe = twr_p1025_probe, + .compatible = "fsl,TWR-P1025", .setup_arch = twr_p1025_setup_arch, .init_IRQ = twr_p1025_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 5836e4ecb7a0..184013e6601e 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -136,27 +136,9 @@ machine_arch_initcall(xes_mpc8572, mpc85xx_common_publish_devices); machine_arch_initcall(xes_mpc8548, mpc85xx_common_publish_devices); machine_arch_initcall(xes_mpc8540, mpc85xx_common_publish_devices); -/* - * Called very early, device-tree isn't unflattened - */ -static int __init xes_mpc8572_probe(void) -{ - return of_machine_is_compatible("xes,MPC8572"); -} - -static int __init xes_mpc8548_probe(void) -{ - return of_machine_is_compatible("xes,MPC8548"); -} - -static int __init xes_mpc8540_probe(void) -{ - return of_machine_is_compatible("xes,MPC8540"); -} - define_machine(xes_mpc8572) { .name = "X-ES MPC8572", - .probe = xes_mpc8572_probe, + .compatible = "xes,MPC8572", .setup_arch = xes_mpc85xx_setup_arch, .init_IRQ = xes_mpc85xx_pic_init, #ifdef CONFIG_PCI @@ -164,13 +146,12 @@ define_machine(xes_mpc8572) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(xes_mpc8548) { .name = "X-ES MPC8548", - .probe = xes_mpc8548_probe, + .compatible = "xes,MPC8548", .setup_arch = xes_mpc85xx_setup_arch, .init_IRQ = xes_mpc85xx_pic_init, #ifdef CONFIG_PCI @@ -178,13 +159,12 @@ define_machine(xes_mpc8548) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; define_machine(xes_mpc8540) { .name = "X-ES MPC8540", - .probe = xes_mpc8540_probe, + .compatible = "xes,MPC8540", .setup_arch = xes_mpc85xx_setup_arch, .init_IRQ = xes_mpc85xx_pic_init, #ifdef CONFIG_PCI @@ -192,6 +172,5 @@ define_machine(xes_mpc8540) { .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif .get_irq = mpic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index be867abebc83..8bfafc9d2bf7 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -10,23 +10,6 @@ menuconfig PPC_86xx if PPC_86xx -config MPC8641_HPCN - bool "Freescale MPC8641 HPCN" - select PPC_I8259 - select DEFAULT_UIMAGE - select FSL_ULI1575 if PCI - select HAVE_RAPIDIO - select SWIOTLB - help - This option enables support for the MPC8641 HPCN board. - -config MPC8610_HPCD - bool "Freescale MPC8610 HPCD" - select DEFAULT_UIMAGE - select FSL_ULI1575 if PCI - help - This option enables support for the MPC8610 HPCD board. - config GEF_PPC9A bool "GE PPC9A" select DEFAULT_UIMAGE @@ -68,7 +51,7 @@ config MPC8641 select FSL_PCI if PCI select PPC_UDBG_16550 select MPIC - default y if MPC8641_HPCN || GEF_SBC610 || GEF_SBC310 || GEF_PPC9A \ + default y if GEF_SBC610 || GEF_SBC310 || GEF_PPC9A \ || MVME7100 config MPC8610 @@ -77,4 +60,3 @@ config MPC8610 select FSL_PCI if PCI select PPC_UDBG_16550 select MPIC - default y if MPC8610_HPCD diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 5bbe1475bf26..dafbc037ff42 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -5,8 +5,6 @@ obj-y := pic.o common.o obj-$(CONFIG_SMP) += mpc86xx_smp.o -obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o -obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 8e358fa0bc41..f0512e51300c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -175,33 +175,16 @@ static void gef_ppc9a_nec_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, gef_ppc9a_nec_fixup); -/* - * Called very early, device-tree isn't unflattened - * - * This function is called to determine whether the BSP is compatible with the - * supplied device-tree, which is assumed to be the correct one for the actual - * board. It is expected that, in the future, a kernel may support multiple - * boards. - */ -static int __init gef_ppc9a_probe(void) -{ - if (of_machine_is_compatible("gef,ppc9a")) - return 1; - - return 0; -} - machine_arch_initcall(gef_ppc9a, mpc86xx_common_publish_devices); define_machine(gef_ppc9a) { .name = "GE PPC9A", - .probe = gef_ppc9a_probe, + .compatible = "gef,ppc9a", .setup_arch = gef_ppc9a_setup_arch, .init_IRQ = gef_ppc9a_init_irq, .show_cpuinfo = gef_ppc9a_show_cpuinfo, .get_irq = mpic_get_irq, .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index b5b2733567cb..1430b524d982 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -162,33 +162,16 @@ static void gef_sbc310_nec_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, gef_sbc310_nec_fixup); -/* - * Called very early, device-tree isn't unflattened - * - * This function is called to determine whether the BSP is compatible with the - * supplied device-tree, which is assumed to be the correct one for the actual - * board. It is expected that, in the future, a kernel may support multiple - * boards. - */ -static int __init gef_sbc310_probe(void) -{ - if (of_machine_is_compatible("gef,sbc310")) - return 1; - - return 0; -} - machine_arch_initcall(gef_sbc310, mpc86xx_common_publish_devices); define_machine(gef_sbc310) { .name = "GE SBC310", - .probe = gef_sbc310_probe, + .compatible = "gef,sbc310", .setup_arch = gef_sbc310_setup_arch, .init_IRQ = gef_sbc310_init_irq, .show_cpuinfo = gef_sbc310_show_cpuinfo, .get_irq = mpic_get_irq, .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index bb4c8e6b44d0..c92af0d964e1 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -152,33 +152,16 @@ static void gef_sbc610_nec_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, gef_sbc610_nec_fixup); -/* - * Called very early, device-tree isn't unflattened - * - * This function is called to determine whether the BSP is compatible with the - * supplied device-tree, which is assumed to be the correct one for the actual - * board. It is expected that, in the future, a kernel may support multiple - * boards. - */ -static int __init gef_sbc610_probe(void) -{ - if (of_machine_is_compatible("gef,sbc610")) - return 1; - - return 0; -} - machine_arch_initcall(gef_sbc610, mpc86xx_common_publish_devices); define_machine(gef_sbc610) { .name = "GE SBC610", - .probe = gef_sbc610_probe, + .compatible = "gef,sbc610", .setup_arch = gef_sbc610_setup_arch, .init_IRQ = gef_sbc610_init_irq, .show_cpuinfo = gef_sbc610_show_cpuinfo, .get_irq = mpic_get_irq, .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c deleted file mode 100644 index b593b9afd30a..000000000000 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC8610 HPCD board specific routines - * - * Initial author: Xianghua Xiao - * Recode: Jason Jin - * York Sun - * - * Rewrite the interrupt routing. remove the 8259PIC support, - * All the integrated device in ULI use sideband interrupt. - * - * Copyright 2008 Freescale Semiconductor Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "mpc86xx.h" - -static struct device_node *pixis_node; -static unsigned char *pixis_bdcfg0, *pixis_arch; - -/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ -#define CLKDVDR_PXCKEN 0x80000000 -#define CLKDVDR_PXCKINV 0x10000000 -#define CLKDVDR_PXCKDLY 0x06000000 -#define CLKDVDR_PXCLK_MASK 0x001F0000 - -#ifdef CONFIG_SUSPEND -static irqreturn_t mpc8610_sw9_irq(int irq, void *data) -{ - pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__); - return IRQ_HANDLED; -} - -static void __init mpc8610_suspend_init(void) -{ - int irq; - int ret; - - if (!pixis_node) - return; - - irq = irq_of_parse_and_map(pixis_node, 0); - if (!irq) { - pr_err("%s: can't map pixis event IRQ.\n", __func__); - return; - } - - ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL); - if (ret) { - pr_err("%s: can't request pixis event IRQ: %d\n", - __func__, ret); - irq_dispose_mapping(irq); - } - - enable_irq_wake(irq); -} -#else -static inline void mpc8610_suspend_init(void) { } -#endif /* CONFIG_SUSPEND */ - -static const struct of_device_id mpc8610_ids[] __initconst = { - { .compatible = "fsl,mpc8610-immr", }, - { .compatible = "fsl,mpc8610-guts", }, - /* So that the DMA channel nodes can be probed individually: */ - { .compatible = "fsl,eloplus-dma", }, - /* PCI controllers */ - { .compatible = "fsl,mpc8610-pci", }, - {} -}; - -static int __init mpc8610_declare_of_platform_devices(void) -{ - /* Enable wakeup on PIXIS' event IRQ. */ - mpc8610_suspend_init(); - - mpc86xx_common_publish_devices(); - - /* Without this call, the SSI device driver won't get probed. */ - of_platform_bus_probe(NULL, mpc8610_ids, NULL); - - return 0; -} -machine_arch_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); - -#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) - -/* - * DIU Area Descriptor - * - * The MPC8610 reference manual shows the bits of the AD register in - * little-endian order, which causes the BLUE_C field to be split into two - * parts. To simplify the definition of the MAKE_AD() macro, we define the - * fields in big-endian order and byte-swap the result. - * - * So even though the registers don't look like they're in the - * same bit positions as they are on the P1022, the same value is written to - * the AD register on the MPC8610 and on the P1022. - */ -#define AD_BYTE_F 0x10000000 -#define AD_ALPHA_C_MASK 0x0E000000 -#define AD_ALPHA_C_SHIFT 25 -#define AD_BLUE_C_MASK 0x01800000 -#define AD_BLUE_C_SHIFT 23 -#define AD_GREEN_C_MASK 0x00600000 -#define AD_GREEN_C_SHIFT 21 -#define AD_RED_C_MASK 0x00180000 -#define AD_RED_C_SHIFT 19 -#define AD_PALETTE 0x00040000 -#define AD_PIXEL_S_MASK 0x00030000 -#define AD_PIXEL_S_SHIFT 16 -#define AD_COMP_3_MASK 0x0000F000 -#define AD_COMP_3_SHIFT 12 -#define AD_COMP_2_MASK 0x00000F00 -#define AD_COMP_2_SHIFT 8 -#define AD_COMP_1_MASK 0x000000F0 -#define AD_COMP_1_SHIFT 4 -#define AD_COMP_0_MASK 0x0000000F -#define AD_COMP_0_SHIFT 0 - -#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ - cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ - (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ - (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ - (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ - (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) - -u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port, - unsigned int bits_per_pixel) -{ - static const u32 pixelformat[][3] = { - { - MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), - MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), - MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0) - }, - { - MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8), - MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0), - MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0) - }, - }; - unsigned int arch_monitor; - - /* The DVI port is mis-wired on revision 1 of this board. */ - arch_monitor = - ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1; - - switch (bits_per_pixel) { - case 32: - return pixelformat[arch_monitor][0]; - case 24: - return pixelformat[arch_monitor][1]; - case 16: - return pixelformat[arch_monitor][2]; - default: - pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); - return 0; - } -} - -void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port, - char *gamma_table_base) -{ - int i; - if (port == FSL_DIU_PORT_DLVDS) { - for (i = 0; i < 256*3; i++) - gamma_table_base[i] = (gamma_table_base[i] << 2) | - ((gamma_table_base[i] >> 6) & 0x03); - } -} - -#define PX_BRDCFG0_DVISEL (1 << 3) -#define PX_BRDCFG0_DLINK (1 << 4) -#define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK) - -void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port) -{ - switch (port) { - case FSL_DIU_PORT_DVI: - clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, - PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK); - break; - case FSL_DIU_PORT_LVDS: - clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, - PX_BRDCFG0_DLINK); - break; - case FSL_DIU_PORT_DLVDS: - clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK); - break; - } -} - -/** - * mpc8610hpcd_set_pixel_clock: program the DIU's clock - * - * @pixclock: the wavelength, in picoseconds, of the clock - */ -void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) -{ - struct device_node *guts_np = NULL; - struct ccsr_guts __iomem *guts; - unsigned long freq; - u64 temp; - u32 pxclk; - - /* Map the global utilities registers. */ - guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); - if (!guts_np) { - pr_err("mpc8610hpcd: missing global utilities device node\n"); - return; - } - - guts = of_iomap(guts_np, 0); - of_node_put(guts_np); - if (!guts) { - pr_err("mpc8610hpcd: could not map global utilities device\n"); - return; - } - - /* Convert pixclock from a wavelength to a frequency */ - temp = 1000000000000ULL; - do_div(temp, pixclock); - freq = temp; - - /* - * 'pxclk' is the ratio of the platform clock to the pixel clock. - * On the MPC8610, the value programmed into CLKDVDR is the ratio - * minus one. The valid range of values is 2-31. - */ - pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1; - pxclk = clamp_t(u32, pxclk, 2, 31); - - /* Disable the pixel clock, and set it to non-inverted and no delay */ - clrbits32(&guts->clkdvdr, - CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); - - /* Enable the clock and set the pxclk */ - setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); - - iounmap(guts); -} - -enum fsl_diu_monitor_port -mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port) -{ - return port; -} - -#endif - -static void __init mpc86xx_hpcd_setup_arch(void) -{ - struct resource r; - unsigned char *pixis; - - if (ppc_md.progress) - ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); - - fsl_pci_assign_primary(); - -#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) - diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; - diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; - diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; - diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; - diu_ops.valid_monitor_port = mpc8610hpcd_valid_monitor_port; -#endif - - pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); - if (pixis_node) { - of_address_to_resource(pixis_node, 0, &r); - of_node_put(pixis_node); - pixis = ioremap(r.start, 32); - if (!pixis) { - printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); - return; - } - pixis_bdcfg0 = pixis + 8; - pixis_arch = pixis + 1; - } else - printk(KERN_ERR "Err: " - "can't find device node 'fsl,fpga-pixis'\n"); - - printk("MPC86xx HPCD board from Freescale Semiconductor\n"); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc86xx_hpcd_probe(void) -{ - if (of_machine_is_compatible("fsl,MPC8610HPCD")) - return 1; /* Looks good */ - - return 0; -} - -define_machine(mpc86xx_hpcd) { - .name = "MPC86xx HPCD", - .probe = mpc86xx_hpcd_probe, - .setup_arch = mpc86xx_hpcd_setup_arch, - .init_IRQ = mpc86xx_init_irq, - .get_irq = mpic_get_irq, - .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif -}; diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c deleted file mode 100644 index 5294394c9c07..000000000000 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * MPC86xx HPCN board specific routines - * - * Recode: ZHANG WEI - * Initial author: Xianghua Xiao - * - * Copyright 2006 Freescale Semiconductor Inc. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "mpc86xx.h" - -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt...) do { printk(KERN_ERR fmt); } while(0) -#else -#define DBG(fmt...) do { } while(0) -#endif - -#ifdef CONFIG_PCI -extern int uli_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn); - -static int mpc86xx_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) -{ - if (hose->dn == fsl_pci_primary) - return uli_exclude_device(hose, bus, devfn); - - return PCIBIOS_SUCCESSFUL; -} -#endif /* CONFIG_PCI */ - - -static void __init -mpc86xx_hpcn_setup_arch(void) -{ - if (ppc_md.progress) - ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); - -#ifdef CONFIG_PCI - ppc_md.pci_exclude_device = mpc86xx_exclude_device; -#endif - - printk("MPC86xx HPCN board from Freescale Semiconductor\n"); - -#ifdef CONFIG_SMP - mpc86xx_smp_init(); -#endif - - fsl_pci_assign_primary(); - - swiotlb_detect_4g(); -} - - -static void -mpc86xx_hpcn_show_cpuinfo(struct seq_file *m) -{ - uint svid = mfspr(SPRN_SVR); - - seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - - seq_printf(m, "SVR\t\t: 0x%x\n", svid); -} - - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc86xx_hpcn_probe(void) -{ - if (of_machine_is_compatible("fsl,mpc8641hpcn")) - return 1; /* Looks good */ - - return 0; -} - -static const struct of_device_id of_bus_ids[] __initconst = { - { .compatible = "fsl,srio", }, - {}, -}; - -static int __init declare_of_platform_devices(void) -{ - mpc86xx_common_publish_devices(); - of_platform_bus_probe(NULL, of_bus_ids, NULL); - - return 0; -} -machine_arch_initcall(mpc86xx_hpcn, declare_of_platform_devices); - -define_machine(mpc86xx_hpcn) { - .name = "MPC86xx HPCN", - .probe = mpc86xx_hpcn_probe, - .setup_arch = mpc86xx_hpcn_setup_arch, - .init_IRQ = mpc86xx_init_irq, - .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, - .get_irq = mpic_get_irq, - .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif -}; diff --git a/arch/powerpc/platforms/86xx/mvme7100.c b/arch/powerpc/platforms/86xx/mvme7100.c index b2cc32a32d0b..c0ac40514361 100644 --- a/arch/powerpc/platforms/86xx/mvme7100.c +++ b/arch/powerpc/platforms/86xx/mvme7100.c @@ -108,7 +108,6 @@ define_machine(mvme7100) { .init_IRQ = mpc86xx_init_irq, .get_irq = mpic_get_irq, .time_init = mpc86xx_time_init, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, diff --git a/arch/powerpc/platforms/8xx/adder875.c b/arch/powerpc/platforms/8xx/adder875.c index 10e6e4fe77fc..7e83eb6746f4 100644 --- a/arch/powerpc/platforms/8xx/adder875.c +++ b/arch/powerpc/platforms/8xx/adder875.c @@ -83,11 +83,6 @@ static void __init adder875_setup(void) init_ioports(); } -static int __init adder875_probe(void) -{ - return of_machine_is_compatible("analogue-and-micro,adder875"); -} - static const struct of_device_id of_bus_ids[] __initconst = { { .compatible = "simple-bus", }, {}, @@ -102,11 +97,10 @@ machine_device_initcall(adder875, declare_of_platform_devices); define_machine(adder875) { .name = "Adder MPC875", - .probe = adder875_probe, + .compatible = "analogue-and-micro,adder875", .setup_arch = adder875_setup, .init_IRQ = mpc8xx_pic_init, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c index b3b22520b435..fc276a29d67f 100644 --- a/arch/powerpc/platforms/8xx/ep88xc.c +++ b/arch/powerpc/platforms/8xx/ep88xc.c @@ -142,11 +142,6 @@ static void __init ep88xc_setup_arch(void) BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); } -static int __init ep88xc_probe(void) -{ - return of_machine_is_compatible("fsl,ep88xc"); -} - static const struct of_device_id of_bus_ids[] __initconst = { { .name = "soc", }, { .name = "cpm", }, @@ -165,7 +160,7 @@ machine_device_initcall(ep88xc, declare_of_platform_devices); define_machine(ep88xc) { .name = "Embedded Planet EP88xC", - .probe = ep88xc_probe, + .compatible = "fsl,ep88xc", .setup_arch = ep88xc_setup_arch, .init_IRQ = mpc8xx_pic_init, .get_irq = mpc8xx_get_irq, diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index 03267e4a44a9..11b3d1116db1 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -117,11 +117,6 @@ static void __init mpc86xads_setup_arch(void) iounmap(bcsr_io); } -static int __init mpc86xads_probe(void) -{ - return of_machine_is_compatible("fsl,mpc866ads"); -} - static const struct of_device_id of_bus_ids[] __initconst = { { .name = "soc", }, { .name = "cpm", }, @@ -139,7 +134,7 @@ machine_device_initcall(mpc86x_ads, declare_of_platform_devices); define_machine(mpc86x_ads) { .name = "MPC86x ADS", - .probe = mpc86xads_probe, + .compatible = "fsl,mpc866ads", .setup_arch = mpc86xads_setup_arch, .init_IRQ = mpc8xx_pic_init, .get_irq = mpc8xx_get_irq, diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index b1e39f96de00..2fc7cacbcd96 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -192,11 +192,6 @@ static void __init mpc885ads_setup_arch(void) } } -static int __init mpc885ads_probe(void) -{ - return of_machine_is_compatible("fsl,mpc885ads"); -} - static const struct of_device_id of_bus_ids[] __initconst = { { .name = "soc", }, { .name = "cpm", }, @@ -215,7 +210,7 @@ machine_device_initcall(mpc885_ads, declare_of_platform_devices); define_machine(mpc885_ads) { .name = "Freescale MPC885 ADS", - .probe = mpc885ads_probe, + .compatible = "fsl,mpc885ads", .setup_arch = mpc885ads_setup_arch, .init_IRQ = mpc8xx_pic_init, .get_irq = mpc8xx_get_irq, diff --git a/arch/powerpc/platforms/8xx/tqm8xx_setup.c b/arch/powerpc/platforms/8xx/tqm8xx_setup.c index ffcfd17a5fa3..7d8eb50bb9cd 100644 --- a/arch/powerpc/platforms/8xx/tqm8xx_setup.c +++ b/arch/powerpc/platforms/8xx/tqm8xx_setup.c @@ -121,11 +121,6 @@ static void __init tqm8xx_setup_arch(void) init_ioports(); } -static int __init tqm8xx_probe(void) -{ - return of_machine_is_compatible("tqc,tqm8xx"); -} - static const struct of_device_id of_bus_ids[] __initconst = { { .name = "soc", }, { .name = "cpm", }, @@ -144,7 +139,7 @@ machine_device_initcall(tqm8xx, declare_of_platform_devices); define_machine(tqm8xx) { .name = "TQM8xx", - .probe = tqm8xx_probe, + .compatible = "tqc,tqm8xx", .setup_arch = tqm8xx_setup_arch, .init_IRQ = mpc8xx_pic_init, .get_irq = mpc8xx_get_irq, diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 8e4bbd19dec5..3e2e252016f7 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -263,7 +263,10 @@ config CPM2 on it (826x, 827x, 8560). config FSL_ULI1575 - bool + bool "ULI1575 PCIe south bridge support" + depends on FSL_SOC_BOOKE || PPC_86xx + depends on PCI + select FSL_PCI select GENERIC_ISA_DMA help Supports for the ULI1575 PCIe south bridge that exists on some diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 046b571496b1..45fd975ef521 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -180,6 +180,8 @@ config POWER10_CPU bool "POWER10" depends on PPC_BOOK3S_64 select ARCH_HAS_FAST_MULTIPLIER + select PPC_HAVE_PREFIXED_SUPPORT + select PPC_HAVE_PCREL_SUPPORT config E5500_CPU bool "Freescale e5500" @@ -454,6 +456,36 @@ config PPC_RADIX_MMU_DEFAULT If you're unsure, say Y. +config PPC_KERNEL_PREFIXED + depends on PPC_HAVE_PREFIXED_SUPPORT + depends on CC_HAS_PREFIXED + default n + bool "Build Kernel with Prefixed Instructions" + help + POWER10 and later CPUs support prefixed instructions, 8 byte + instructions that include large immediate, pc relative addressing, + and various floating point, vector, MMA. + + This option builds the kernel with prefixed instructions, and + allows a pc relative addressing option to be selected. + + Kernel support for prefixed instructions in applications and guests + is not affected by this option. + +config PPC_KERNEL_PCREL + depends on PPC_HAVE_PCREL_SUPPORT + depends on PPC_HAVE_PREFIXED_SUPPORT + depends on CC_HAS_PCREL + default n + select PPC_KERNEL_PREFIXED + bool "Build Kernel with PC-Relative addressing model" + help + POWER10 and later CPUs support pc relative addressing. Recent + compilers have support for an ELF ABI extension for a pc relative + ABI. + + This option builds the kernel with the pc relative ABI model. + config PPC_KUEP bool "Kernel Userspace Execution Prevention" if !40x default y if !40x @@ -490,6 +522,12 @@ config PPC_MMU_NOHASH config PPC_HAVE_PMU_SUPPORT bool +config PPC_HAVE_PREFIXED_SUPPORT + bool + +config PPC_HAVE_PCREL_SUPPORT + bool + config PMU_SYSFS bool "Create PMU SPRs sysfs file" default n diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c index 397ce6a40bd0..6c6e714a7521 100644 --- a/arch/powerpc/platforms/amigaone/setup.c +++ b/arch/powerpc/platforms/amigaone/setup.c @@ -143,30 +143,26 @@ void __noreturn amigaone_restart(char *cmd) static int __init amigaone_probe(void) { - if (of_machine_is_compatible("eyetech,amigaone")) { - /* - * Coherent memory access cause complete system lockup! Thus - * disable this CPU feature, even if the CPU needs it. - */ - cur_cpu_spec->cpu_features &= ~CPU_FTR_NEED_COHERENT; + /* + * Coherent memory access cause complete system lockup! Thus + * disable this CPU feature, even if the CPU needs it. + */ + cur_cpu_spec->cpu_features &= ~CPU_FTR_NEED_COHERENT; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; - return 1; - } - - return 0; + return 1; } define_machine(amigaone) { .name = "AmigaOne", + .compatible = "eyetech,amigaone", .probe = amigaone_probe, .setup_arch = amigaone_setup_arch, .discover_phbs = amigaone_discover_phbs, .show_cpuinfo = amigaone_show_cpuinfo, .init_IRQ = amigaone_init_IRQ, .restart = amigaone_restart, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/book3s/vas-api.c b/arch/powerpc/platforms/book3s/vas-api.c index 36c21648d19a..77ea9335fd04 100644 --- a/arch/powerpc/platforms/book3s/vas-api.c +++ b/arch/powerpc/platforms/book3s/vas-api.c @@ -581,7 +581,7 @@ int vas_register_coproc_api(struct module *mod, enum vas_cop_type cop_type, pr_devel("%s device allocated, dev [%i,%i]\n", name, MAJOR(coproc_device.devt), MINOR(coproc_device.devt)); - coproc_device.class = class_create(mod, name); + coproc_device.class = class_create(name); if (IS_ERR(coproc_device.class)) { rc = PTR_ERR(coproc_device.class); pr_err("Unable to create %s class %d\n", name, rc); diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 0c11aad896c7..106000449d3b 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -460,15 +460,14 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_msic, msic_get, msic_set, "%llu\n"); void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic) { char name[8]; - u64 addr; + struct resource res; - addr = of_translate_address(dn, of_get_property(dn, "reg", NULL)); - if (addr == OF_BAD_ADDR) { - pr_devel("axon_msi: couldn't translate reg property\n"); + if (of_address_to_resource(dn, 0, &res)) { + pr_devel("axon_msi: couldn't get reg property\n"); return; } - msic->trigger = ioremap(addr, 0x4); + msic->trigger = ioremap(res.start, 0x4); if (!msic->trigger) { pr_devel("axon_msi: ioremap failed\n"); return; diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 47eaf75349f2..9e07d101bcee 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -265,7 +265,6 @@ define_machine(cell) { .get_boot_time = rtas_get_boot_time, .get_rtc_time = rtas_get_rtc_time, .set_rtc_time = rtas_set_rtc_time, - .calibrate_decr = generic_calibrate_decr, .progress = cell_progress, .init_IRQ = cell_init_irq, .pci_setup_phb = cell_setup_phb, diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index f1ac4c742069..74567b32c48c 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -402,7 +402,7 @@ static int __init of_has_vicinity(void) struct device_node *dn; for_each_node_by_type(dn, "spe") { - if (of_find_property(dn, "vicinity", NULL)) { + if (of_property_present(dn, "vicinity")) { of_node_put(dn); return 1; } diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index d9049ceb1046..36ee3a5056a1 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -582,6 +582,5 @@ define_machine(chrp) { .time_init = chrp_time_init, .set_rtc_time = chrp_set_rtc_time, .get_rtc_time = chrp_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, .phys_mem_access_prot = pci_phys_mem_access_prot, }; diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index c54786f8461e..a57424d6ef20 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -29,16 +29,6 @@ config STORCENTER Select STORCENTER if configuring for the iomega StorCenter with an 8241 CPU in it. -config MPC7448HPC2 - bool "Freescale MPC7448HPC2(Taiga)" - depends on EMBEDDED6xx - select TSI108_BRIDGE - select DEFAULT_UIMAGE - select PPC_UDBG_16550 - help - Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) - platform - config PPC_HOLLY bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" depends on EMBEDDED6xx diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index e656ae9f23c6..7f2a8154e5a0 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile @@ -2,7 +2,6 @@ # # Makefile for the 6xx/7xx/7xxxx linux kernel. # -obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o obj-$(CONFIG_STORCENTER) += storcenter.o obj-$(CONFIG_PPC_HOLLY) += holly.o diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 609bda2ad5dd..4d9200bdba78 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -145,7 +145,7 @@ static struct irq_domain * __init flipper_pic_init(struct device_node *np) } io_base = ioremap(res.start, resource_size(&res)); - pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base); + pr_info("controller at 0x%pa mapped to 0x%p\n", &res.start, io_base); __flipper_quiesce(io_base); diff --git a/arch/powerpc/platforms/embedded6xx/gamecube.c b/arch/powerpc/platforms/embedded6xx/gamecube.c index 5c2575adcc7e..e3b2c7464732 100644 --- a/arch/powerpc/platforms/embedded6xx/gamecube.c +++ b/arch/powerpc/platforms/embedded6xx/gamecube.c @@ -50,9 +50,6 @@ static void __noreturn gamecube_halt(void) static int __init gamecube_probe(void) { - if (!of_machine_is_compatible("nintendo,gamecube")) - return 0; - pm_power_off = gamecube_power_off; ug_udbg_init(); @@ -67,12 +64,12 @@ static void gamecube_shutdown(void) define_machine(gamecube) { .name = "gamecube", + .compatible = "nintendo,gamecube", .probe = gamecube_probe, .restart = gamecube_restart, .halt = gamecube_halt, .init_IRQ = flipper_pic_probe, .get_irq = flipper_pic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .machine_shutdown = gamecube_shutdown, }; @@ -85,11 +82,8 @@ static const struct of_device_id gamecube_of_bus[] = { static int __init gamecube_device_probe(void) { - if (!machine_is(gamecube)) - return 0; - of_platform_bus_probe(NULL, gamecube_of_bus, NULL); return 0; } -device_initcall(gamecube_device_probe); +machine_device_initcall(gamecube, gamecube_device_probe); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 380b4285cce4..4d2d92de30af 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -171,7 +171,7 @@ static struct irq_domain *__init hlwd_pic_init(struct device_node *np) return NULL; } - pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base); + pr_info("controller at 0x%pa mapped to 0x%p\n", &res.start, io_base); __hlwd_quiesce(io_base); diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index bebc5a972694..02ff260ae1ee 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -205,16 +205,15 @@ static void __noreturn holly_restart(char *cmd) __be32 __iomem *ocn_bar1 = NULL; unsigned long bar; struct device_node *bridge = NULL; - const void *prop; - int size; + struct resource res; phys_addr_t addr = 0xc0000000; local_irq_disable(); bridge = of_find_node_by_type(NULL, "tsi-bridge"); if (bridge) { - prop = of_get_property(bridge, "reg", &size); - addr = of_translate_address(bridge, prop); + of_address_to_resource(bridge, 0, &res); + addr = res.start; of_node_put(bridge); } addr += (TSI108_PB_OFFSET + 0x414); @@ -241,16 +240,6 @@ static void __noreturn holly_restart(char *cmd) for (;;) ; } -/* - * Called very early, device-tree isn't unflattened - */ -static int __init holly_probe(void) -{ - if (!of_machine_is_compatible("ibm,holly")) - return 0; - return 1; -} - static int ppc750_machine_check_exception(struct pt_regs *regs) { const struct exception_table_entry *entry; @@ -267,14 +256,13 @@ static int ppc750_machine_check_exception(struct pt_regs *regs) define_machine(holly){ .name = "PPC750 GX/CL TSI", - .probe = holly_probe, + .compatible = "ibm,holly", .setup_arch = holly_setup_arch, .discover_phbs = holly_init_pci, .init_IRQ = holly_init_IRQ, .show_cpuinfo = holly_show_cpuinfo, .get_irq = mpic_get_irq, .restart = holly_restart, - .calibrate_decr = generic_calibrate_decr, .machine_check_exception = ppc750_machine_check_exception, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 1830e1ac1f8f..9c10aac40c7b 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -143,9 +143,6 @@ static void linkstation_show_cpuinfo(struct seq_file *m) static int __init linkstation_probe(void) { - if (!of_machine_is_compatible("linkstation")) - return 0; - pm_power_off = linkstation_power_off; return 1; @@ -153,6 +150,7 @@ static int __init linkstation_probe(void) define_machine(linkstation){ .name = "Buffalo Linkstation", + .compatible = "linkstation", .probe = linkstation_probe, .setup_arch = linkstation_setup_arch, .discover_phbs = linkstation_setup_pci, @@ -161,5 +159,4 @@ define_machine(linkstation){ .get_irq = mpic_get_irq, .restart = linkstation_restart, .halt = linkstation_halt, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index 4ecbc55b37c0..6c1dbf8ae718 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -114,22 +115,24 @@ static void __init ls_uart_init(void) static int __init ls_uarts_init(void) { struct device_node *avr; - phys_addr_t phys_addr; - int len; + struct resource res; + int len, ret; avr = of_find_node_by_path("/soc10x/serial@80004500"); if (!avr) return -EINVAL; avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len); - phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0]; + if (!avr_clock) + return -EINVAL; + + ret = of_address_to_resource(avr, 0, &res); + if (ret) + return ret; of_node_put(avr); - if (!avr_clock || !phys_addr) - return -EINVAL; - - avr_addr = ioremap(phys_addr, 32); + avr_addr = ioremap(res.start, 32); if (!avr_addr) return -EFAULT; diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c deleted file mode 100644 index ddf0c652af80..000000000000 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * mpc7448_hpc2.c - * - * Board setup routines for the Freescale mpc7448hpc2(taiga) platform - * - * Author: Jacob Pan - * jacob.pan@freescale.com - * Author: Xianghua Xiao - * x.xiao@freescale.com - * Maintainer: Roy Zang - * Add Flat Device Tree support fot mpc7448hpc2 board - * - * Copyright 2004-2006 Freescale Semiconductor, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG -#ifdef DEBUG -#define DBG(fmt...) do { printk(fmt); } while(0) -#else -#define DBG(fmt...) do { } while(0) -#endif - -#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 - -int mpc7448_hpc2_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - else - return PCIBIOS_SUCCESSFUL; -} - -static void __init mpc7448_hpc2_setup_pci(void) -{ -#ifdef CONFIG_PCI - struct device_node *np; - if (ppc_md.progress) - ppc_md.progress("mpc7448_hpc2_setup_pci():set_bridge", 0); - - /* setup PCI host bridge */ - for_each_compatible_node(np, "pci", "tsi108-pci") - tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0); - - ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device; - if (ppc_md.progress) - ppc_md.progress("tsi108: resources set", 0x100); -#endif -} - -static void __init mpc7448_hpc2_setup_arch(void) -{ - tsi108_csr_vir_base = get_vir_csrbase(); - - printk(KERN_INFO "MPC7448HPC2 (TAIGA) Platform\n"); - printk(KERN_INFO - "Jointly ported by Freescale and Tundra Semiconductor\n"); - printk(KERN_INFO - "Enabling L2 cache then enabling the HID0 prefetch engine.\n"); -} - -/* - * Interrupt setup and service. Interrupts on the mpc7448_hpc2 come - * from the four external INT pins, PCI interrupts are routed via - * PCI interrupt control registers, it generates internal IRQ23 - * - * Interrupt routing on the Taiga Board: - * TSI108:PB_INT[0] -> CPU0:INT# - * TSI108:PB_INT[1] -> CPU0:MCP# - * TSI108:PB_INT[2] -> N/C - * TSI108:PB_INT[3] -> N/C - */ -static void __init mpc7448_hpc2_init_IRQ(void) -{ - struct mpic *mpic; -#ifdef CONFIG_PCI - unsigned int cascade_pci_irq; - struct device_node *tsi_pci; - struct device_node *cascade_node = NULL; -#endif - - mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | - MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, 0, - "Tsi108_PIC"); - - BUG_ON(mpic == NULL); - - mpic_assign_isu(mpic, 0, mpic->paddr + 0x100); - - mpic_init(mpic); - -#ifdef CONFIG_PCI - tsi_pci = of_find_node_by_type(NULL, "pci"); - if (tsi_pci == NULL) { - printk("%s: No tsi108 pci node found !\n", __func__); - return; - } - cascade_node = of_find_node_by_type(NULL, "pic-router"); - if (cascade_node == NULL) { - printk("%s: No tsi108 pci cascade node found !\n", __func__); - return; - } - - cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0); - DBG("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, - (u32) cascade_pci_irq); - tsi108_pci_int_init(cascade_node); - irq_set_handler_data(cascade_pci_irq, mpic); - irq_set_chained_handler(cascade_pci_irq, tsi108_irq_cascade); - - of_node_put(tsi_pci); - of_node_put(cascade_node); -#endif - /* Configure MPIC outputs to CPU0 */ - tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0); -} - -void mpc7448_hpc2_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "vendor\t\t: Freescale Semiconductor\n"); -} - -static void __noreturn mpc7448_hpc2_restart(char *cmd) -{ - local_irq_disable(); - - /* Set exception prefix high - to the firmware */ - mtmsr(mfmsr() | MSR_IP); - isync(); - - for (;;) ; /* Spin until reset happens */ -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc7448_hpc2_probe(void) -{ - if (!of_machine_is_compatible("mpc74xx")) - return 0; - return 1; -} - -static int mpc7448_machine_check_exception(struct pt_regs *regs) -{ - const struct exception_table_entry *entry; - - /* Are we prepared to handle this fault */ - if ((entry = search_exception_tables(regs->nip)) != NULL) { - tsi108_clear_pci_cfg_error(); - regs_set_recoverable(regs); - regs_set_return_ip(regs, extable_fixup(entry)); - return 1; - } - return 0; -} - -define_machine(mpc7448_hpc2){ - .name = "MPC7448 HPC2", - .probe = mpc7448_hpc2_probe, - .setup_arch = mpc7448_hpc2_setup_arch, - .discover_phbs = mpc7448_hpc2_setup_pci, - .init_IRQ = mpc7448_hpc2_init_IRQ, - .show_cpuinfo = mpc7448_hpc2_show_cpuinfo, - .get_irq = mpic_get_irq, - .restart = mpc7448_hpc2_restart, - .calibrate_decr = generic_calibrate_decr, - .machine_check_exception= mpc7448_machine_check_exception, - .progress = udbg_progress, -}; diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c index 4854cc592cec..00bec0f051be 100644 --- a/arch/powerpc/platforms/embedded6xx/mvme5100.c +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -186,14 +186,6 @@ static void __noreturn mvme5100_restart(char *cmd) ; } -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mvme5100_probe(void) -{ - return of_machine_is_compatible("MVME5100"); -} - static int __init probe_of_platform_devices(void) { @@ -205,13 +197,12 @@ machine_device_initcall(mvme5100, probe_of_platform_devices); define_machine(mvme5100) { .name = "MVME5100", - .probe = mvme5100_probe, + .compatible = "MVME5100", .setup_arch = mvme5100_setup_arch, .discover_phbs = mvme5100_setup_pci, .init_IRQ = mvme5100_pic_init, .show_cpuinfo = mvme5100_show_cpuinfo, .get_irq = mpic_get_irq, .restart = mvme5100_restart, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index 5f16e80b6ed6..e49880e8dab8 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -110,18 +110,12 @@ static void __noreturn storcenter_restart(char *cmd) for (;;) ; } -static int __init storcenter_probe(void) -{ - return of_machine_is_compatible("iomega,storcenter"); -} - define_machine(storcenter){ .name = "IOMEGA StorCenter", - .probe = storcenter_probe, + .compatible = "iomega,storcenter", .setup_arch = storcenter_setup_arch, .discover_phbs = storcenter_setup_pci, .init_IRQ = storcenter_init_IRQ, .get_irq = mpic_get_irq, .restart = storcenter_restart, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c index e02bdabf358c..221577f32b01 100644 --- a/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c +++ b/arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c @@ -192,24 +192,6 @@ static int ug_udbg_getc_poll(void) return ug_getc(); } -/* - * Retrieves and prepares the virtual address needed to access the hardware. - */ -static void __iomem *__init ug_udbg_setup_exi_io_base(struct device_node *np) -{ - void __iomem *exi_io_base = NULL; - phys_addr_t paddr; - const unsigned int *reg; - - reg = of_get_property(np, "reg", NULL); - if (reg) { - paddr = of_translate_address(np, reg); - if (paddr) - exi_io_base = ioremap(paddr, reg[1]); - } - return exi_io_base; -} - /* * Checks if a USB Gecko adapter is inserted in any memory card slot. */ @@ -246,7 +228,7 @@ void __init ug_udbg_init(void) goto out; } - exi_io_base = ug_udbg_setup_exi_io_base(np); + exi_io_base = of_iomap(np, 0); if (!exi_io_base) { udbg_printf("%s: failed to setup EXI io base\n", __func__); goto done; diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c index f4e654a9d4ff..cb3be6d6e339 100644 --- a/arch/powerpc/platforms/embedded6xx/wii.c +++ b/arch/powerpc/platforms/embedded6xx/wii.c @@ -74,8 +74,8 @@ static void __iomem *__init wii_ioremap_hw_regs(char *name, char *compatible) hw_regs = ioremap(res.start, resource_size(&res)); if (hw_regs) { - pr_info("%s at 0x%08x mapped to 0x%p\n", name, - res.start, hw_regs); + pr_info("%s at 0x%pa mapped to 0x%p\n", name, + &res.start, hw_regs); } out_put: @@ -141,9 +141,6 @@ static void __init wii_pic_probe(void) static int __init wii_probe(void) { - if (!of_machine_is_compatible("nintendo,wii")) - return 0; - pm_power_off = wii_power_off; ug_udbg_init(); @@ -164,23 +161,20 @@ static const struct of_device_id wii_of_bus[] = { static int __init wii_device_probe(void) { - if (!machine_is(wii)) - return 0; - of_platform_populate(NULL, wii_of_bus, NULL, NULL); return 0; } -device_initcall(wii_device_probe); +machine_device_initcall(wii, wii_device_probe); define_machine(wii) { .name = "wii", + .compatible = "nintendo,wii", .probe = wii_probe, .setup_arch = wii_setup_arch, .restart = wii_restart, .halt = wii_halt, .init_IRQ = wii_pic_probe, .get_irq = flipper_pic_get_irq, - .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .machine_shutdown = wii_shutdown, }; diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c index 84afae7a2561..b8d37a9932f1 100644 --- a/arch/powerpc/platforms/fsl_uli1575.c +++ b/arch/powerpc/platforms/fsl_uli1575.c @@ -13,6 +13,9 @@ #include #include +#include + +#include #define ULI_PIRQA 0x08 #define ULI_PIRQB 0x09 @@ -36,7 +39,7 @@ #define ULI_8259_IRQ14 0x0d #define ULI_8259_IRQ15 0x0f -u8 uli_pirq_to_irq[8] = { +static u8 uli_pirq_to_irq[8] = { ULI_8259_IRQ9, /* PIRQA */ ULI_8259_IRQ10, /* PIRQB */ ULI_8259_IRQ11, /* PIRQC */ @@ -341,10 +344,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, hpcd_quirk_uli5288); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, hpcd_quirk_uli5229); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, hpcd_final_uli5288); -int uli_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) +static int uli_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - if (bus == (hose->first_busno + 2)) { + if (hose->dn == fsl_pci_primary && bus == (hose->first_busno + 2)) { /* exclude Modem controller */ if ((PCI_SLOT(devfn) == 29) && (PCI_FUNC(devfn) == 1)) return PCIBIOS_DEVICE_NOT_FOUND; @@ -356,3 +358,22 @@ int uli_exclude_device(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } + +void __init uli_init(void) +{ + struct device_node *node; + struct device_node *pci_with_uli; + + /* See if we have a ULI under the primary */ + + node = of_find_node_by_name(NULL, "uli1575"); + while ((pci_with_uli = of_get_parent(node))) { + of_node_put(node); + node = pci_with_uli; + + if (pci_with_uli == fsl_pci_primary) { + ppc_md.pci_exclude_device = uli_exclude_device; + break; + } + } +} diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 98c8e3603064..a4a79d77eca2 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -235,7 +235,7 @@ static void __init maple_init_IRQ(void) BUG_ON(openpic_addr == 0); /* Check for a big endian MPIC */ - if (of_get_property(np, "big-endian", NULL) != NULL) + if (of_property_read_bool(np, "big-endian")) flags |= MPIC_BIG_ENDIAN; /* XXX Maple specific bits */ @@ -357,7 +357,6 @@ define_machine(maple) { .get_boot_time = maple_get_boot_time, .set_rtc_time = maple_set_rtc_time, .get_rtc_time = maple_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, .progress = maple_progress, .power_save = power4_idle, }; diff --git a/arch/powerpc/platforms/microwatt/setup.c b/arch/powerpc/platforms/microwatt/setup.c index 6b32539395a4..5e1c0997170d 100644 --- a/arch/powerpc/platforms/microwatt/setup.c +++ b/arch/powerpc/platforms/microwatt/setup.c @@ -23,11 +23,6 @@ static void __init microwatt_init_IRQ(void) xics_init(); } -static int __init microwatt_probe(void) -{ - return of_machine_is_compatible("microwatt-soc"); -} - static int __init microwatt_populate(void) { return of_platform_default_populate(NULL, NULL, NULL); @@ -41,9 +36,8 @@ static void __init microwatt_setup_arch(void) define_machine(microwatt) { .name = "microwatt", - .probe = microwatt_probe, + .compatible = "microwatt-soc", .init_IRQ = microwatt_init_IRQ, .setup_arch = microwatt_setup_arch, .progress = udbg_progress, - .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 0a38663d44ed..375487cba874 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -254,7 +254,7 @@ void __init iommu_init_early_pasemi(void) iommu_off = 1; #else iommu_off = of_chosen && - of_get_property(of_chosen, "linux,iommu-off", NULL); + of_property_read_bool(of_chosen, "linux,iommu-off"); #endif if (iommu_off) return; diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 2aef49e04dd4..5c5b4a034f9e 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -449,7 +449,6 @@ define_machine(pasemi) { .get_irq = mpic_get_irq, .restart = pas_restart, .get_boot_time = pas_get_boot_time, - .calibrate_decr = generic_calibrate_decr, .progress = pas_progress, .machine_check_exception = pas_machine_check_handler, }; diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 0382d20b5619..a195d5faa4e5 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2506,7 +2506,7 @@ found: int cpu_count = 1; /* Nap mode not supported on SMP */ - if (of_get_property(np, "flush-on-lock", NULL) || + if (of_property_read_bool(np, "flush-on-lock") || (cpu_count > 1)) { powersave_nap = 0; of_node_put(np); @@ -2545,8 +2545,7 @@ done: */ static void __init probe_uninorth(void) { - const u32 *addrp; - phys_addr_t address; + struct resource res; unsigned long actrl; /* Locate core99 Uni-N */ @@ -2568,18 +2567,15 @@ static void __init probe_uninorth(void) return; } - addrp = of_get_property(uninorth_node, "reg", NULL); - if (addrp == NULL) + if (of_address_to_resource(uninorth_node, 0, &res)) return; - address = of_translate_address(uninorth_node, addrp); - if (address == 0) - return; - uninorth_base = ioremap(address, 0x40000); + + uninorth_base = ioremap(res.start, 0x40000); if (uninorth_base == NULL) return; uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); if (uninorth_maj == 3 || uninorth_maj == 4) { - u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + u3_ht_base = ioremap(res.start + U3_HT_CONFIG_BASE, 0x1000); if (u3_ht_base == NULL) { iounmap(uninorth_base); return; @@ -2589,7 +2585,7 @@ static void __init probe_uninorth(void) printk(KERN_INFO "Found %s memory controller & host bridge" " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" : uninorth_maj == 4 ? "U4" : "UniNorth", - (unsigned int)address, uninorth_rev); + (unsigned int)res.start, uninorth_rev); printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 8c8d8e0a7d13..7135ea1d7db6 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -450,7 +450,7 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); - if (of_get_property(np, "big-endian", NULL)) + if (of_property_read_bool(np, "big-endian")) flags |= MPIC_BIG_ENDIAN; /* Primary Big Endian means HT interrupts. This is quite dodgy @@ -475,8 +475,7 @@ static int __init pmac_pic_probe_mpic(void) /* We can have up to 2 MPICs cascaded */ for_each_node_by_type(np, "open-pic") { - if (master == NULL && - of_get_property(np, "interrupts", NULL) == NULL) + if (master == NULL && !of_property_present(np, "interrupts")) master = of_node_get(np); else if (slave == NULL) slave = of_node_get(np); @@ -528,7 +527,7 @@ void __init pmac_pic_init(void) #ifdef CONFIG_PPC32 if (!pmac_newworld) of_irq_workarounds |= OF_IMAP_OLDWORLD_MAC; - if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL) + if (of_property_read_bool(of_chosen, "linux,bootx")) of_irq_workarounds |= OF_IMAP_NO_PHANDLE; /* If we don't have phandles on a newworld, then try to locate a diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 4f7ee885a78f..193cc9c39422 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -137,7 +137,7 @@ static void pmac_show_cpuinfo(struct seq_file *m) of_get_property(np, "d-cache-size", NULL); seq_printf(m, "L2 cache\t:"); has_l2cache = 1; - if (of_get_property(np, "cache-unified", NULL) && dc) { + if (of_property_read_bool(np, "cache-unified") && dc) { seq_printf(m, " %dK unified", *dc / 1024); } else { if (ic) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 5b26a9012d2e..8be71920e63c 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -706,7 +706,7 @@ static void __init smp_core99_setup(int ncpus) struct device_node *cpus = of_find_node_by_path("/cpus"); if (cpus && - of_get_property(cpus, "platform-cpu-timebase", NULL)) { + of_property_read_bool(cpus, "platform-cpu-timebase")) { pmac_tb_freeze = smp_core99_pfunc_tb_freeze; printk(KERN_INFO "Processor timebase sync using" " platform function\n"); diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index ae248a161b43..70a46acc70d6 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -16,6 +16,7 @@ config PPC_POWERNV select PPC_DOORBELL select MMU_NOTIFIER select FORCE_SMP + select ARCH_SUPPORTS_PER_VMA_LOCK default y config OPAL_PRD diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index 841cb7f31f4f..6dfe8d611164 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -1464,14 +1464,19 @@ static int __init pnv_init_idle_states(void) power7_fastsleep_workaround_entry = false; power7_fastsleep_workaround_exit = false; } else { + struct device *dev_root; /* * OPAL_PM_SLEEP_ENABLED_ER1 is set. It indicates that * workaround is needed to use fastsleep. Provide sysfs * control to choose how this workaround has to be * applied. */ - device_create_file(cpu_subsys.dev_root, - &dev_attr_fastsleep_workaround_applyonce); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + device_create_file(dev_root, + &dev_attr_fastsleep_workaround_applyonce); + put_device(dev_root); + } } update_subcore_sibling_mask(); diff --git a/arch/powerpc/platforms/powernv/opal-lpc.c b/arch/powerpc/platforms/powernv/opal-lpc.c index d129d6d45a50..a16f07cdab26 100644 --- a/arch/powerpc/platforms/powernv/opal-lpc.c +++ b/arch/powerpc/platforms/powernv/opal-lpc.c @@ -403,7 +403,7 @@ void __init opal_lpc_init(void) return; /* Does it support direct mapping ? */ - if (of_get_property(np, "ranges", NULL)) { + if (of_property_present(np, "ranges")) { pr_info("OPAL: Found memory mapped LPC bus on chip %d\n", opal_lpc_chip_id); isa_bridge_init_non_pci(np); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 4f6e20a35aa1..a02e9cdb5b5d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1554,6 +1554,10 @@ found: if (WARN_ON(!tbl)) return; +#ifdef CONFIG_IOMMU_API + pe->table_group.ops = &spapr_tce_table_group_ops; + pe->table_group.pgsizes = SZ_4K; +#endif iommu_register_group(&pe->table_group, phb->hose->global_number, pe->pe_number); pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &pe->table_group); @@ -1740,7 +1744,7 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe) * DMA window can be larger than available memory, which will * cause errors later. */ - const u64 maxblock = 1UL << (PAGE_SHIFT + MAX_ORDER - 1); + const u64 maxblock = 1UL << (PAGE_SHIFT + MAX_ORDER); /* * We create the default window as big as we can. The constraint is @@ -1888,13 +1892,20 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus) } } -static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group) +static long pnv_ioda2_take_ownership(struct iommu_table_group *table_group) { struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe, table_group); /* Store @tbl as pnv_pci_ioda2_unset_window() resets it */ struct iommu_table *tbl = pe->table_group.tables[0]; + /* + * iommu_ops transfers the ownership per a device and we mode + * the group ownership with the first device in the group. + */ + if (!tbl) + return 0; + pnv_pci_ioda2_set_bypass(pe, false); pnv_pci_ioda2_unset_window(&pe->table_group, 0); if (pe->pbus) @@ -1902,6 +1913,8 @@ static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group) else if (pe->pdev) set_iommu_table_base(&pe->pdev->dev, NULL); iommu_tce_table_put(tbl); + + return 0; } static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) @@ -1909,6 +1922,9 @@ static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group) struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe, table_group); + /* See the comment about iommu_ops above */ + if (pe->table_group.tables[0]) + return; pnv_pci_ioda2_setup_default_config(pe); if (pe->pbus) pnv_ioda_setup_bus_dma(pe, pe->pbus); @@ -2915,6 +2931,27 @@ static void pnv_pci_ioda_dma_bus_setup(struct pci_bus *bus) } } +#ifdef CONFIG_IOMMU_API +static struct iommu_group *pnv_pci_device_group(struct pci_controller *hose, + struct pci_dev *pdev) +{ + struct pnv_phb *phb = hose->private_data; + struct pnv_ioda_pe *pe; + + if (WARN_ON(!phb)) + return ERR_PTR(-ENODEV); + + pe = pnv_pci_bdfn_to_pe(phb, pdev->devfn | (pdev->bus->number << 8)); + if (!pe) + return ERR_PTR(-ENODEV); + + if (!pe->table_group.group) + return ERR_PTR(-ENODEV); + + return iommu_group_ref_get(pe->table_group.group); +} +#endif + static const struct pci_controller_ops pnv_pci_ioda_controller_ops = { .dma_dev_setup = pnv_pci_ioda_dma_dev_setup, .dma_bus_setup = pnv_pci_ioda_dma_bus_setup, @@ -2925,6 +2962,9 @@ static const struct pci_controller_ops pnv_pci_ioda_controller_ops = { .setup_bridge = pnv_pci_fixup_bridge_resources, .reset_secondary_bus = pnv_pci_reset_secondary_bus, .shutdown = pnv_pci_ioda_shutdown, +#ifdef CONFIG_IOMMU_API + .device_group = pnv_pci_device_group, +#endif }; static const struct pci_controller_ops pnv_npu_ocapi_ioda_controller_ops = { diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 233a50e65fce..7725492097b6 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -865,28 +865,3 @@ void __init pnv_pci_init(void) /* Configure IOMMU DMA hooks */ set_pci_dma_ops(&dma_iommu_ops); } - -static int pnv_tce_iommu_bus_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - - switch (action) { - case BUS_NOTIFY_DEL_DEVICE: - iommu_del_device(dev); - return 0; - default: - return 0; - } -} - -static struct notifier_block pnv_tce_iommu_bus_nb = { - .notifier_call = pnv_tce_iommu_bus_notifier, -}; - -static int __init pnv_tce_iommu_bus_notifier_init(void) -{ - bus_register_notifier(&pci_bus_type, &pnv_tce_iommu_bus_nb); - return 0; -} -machine_subsys_initcall_sync(powernv, pnv_tce_iommu_bus_notifier_init); diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 61ab2d38ff4b..5e9c6b55809f 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -512,9 +512,6 @@ static void __init pnv_setup_machdep_opal(void) static int __init pnv_probe(void) { - if (!of_machine_is_compatible("ibm,powernv")) - return 0; - if (firmware_has_feature(FW_FEATURE_OPAL)) pnv_setup_machdep_opal(); @@ -578,6 +575,7 @@ static long pnv_machine_check_early(struct pt_regs *regs) define_machine(powernv) { .name = "PowerNV", + .compatible = "ibm,powernv", .probe = pnv_probe, .setup_arch = pnv_setup_arch, .init_IRQ = pnv_init_IRQ, @@ -587,7 +585,6 @@ define_machine(powernv) { .progress = pnv_progress, .machine_shutdown = pnv_shutdown, .power_save = NULL, - .calibrate_decr = generic_calibrate_decr, .machine_check_early = pnv_machine_check_early, #ifdef CONFIG_KEXEC_CORE .kexec_cpu_down = pnv_kexec_cpu_down, diff --git a/arch/powerpc/platforms/powernv/subcore.c b/arch/powerpc/platforms/powernv/subcore.c index 7e98b00ea2e8..191424468f10 100644 --- a/arch/powerpc/platforms/powernv/subcore.c +++ b/arch/powerpc/platforms/powernv/subcore.c @@ -20,6 +20,8 @@ #include #include +#include + #include "subcore.h" #include "powernv.h" @@ -415,7 +417,9 @@ static DEVICE_ATTR(subcores_per_core, 0644, static int subcore_init(void) { + struct device *dev_root; unsigned pvr_ver; + int rc = 0; pvr_ver = PVR_VER(mfspr(SPRN_PVR)); @@ -435,7 +439,11 @@ static int subcore_init(void) set_subcores_per_core(1); - return device_create_file(cpu_subsys.dev_root, - &dev_attr_subcores_per_core); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + rc = device_create_file(dev_root, &dev_attr_subcores_per_core); + put_device(dev_root); + } + return rc; } machine_device_initcall(powernv, subcore_init); diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index d7495785fe47..5144f11359f7 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -264,9 +264,6 @@ static int __init ps3_probe(void) { DBG(" -> %s:%d\n", __func__, __LINE__); - if (!of_machine_is_compatible("sony,ps3")) - return 0; - ps3_os_area_save_params(); pm_power_off = ps3_power_off; @@ -291,6 +288,7 @@ static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) define_machine(ps3) { .name = "PS3", + .compatible = "sony,ps3", .probe = ps3_probe, .setup_arch = ps3_setup_arch, .init_IRQ = ps3_init_IRQ, diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 21b22bf16ce6..4ebf2ef2845d 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -22,6 +22,7 @@ config PPC_PSERIES select HOTPLUG_CPU select FORCE_SMP select SWIOTLB + select ARCH_SUPPORTS_PER_VMA_LOCK default y config PARAVIRT diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 75ffdbcd2865..719c97a155ed 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -512,7 +512,7 @@ static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog) return 0; } -static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, +static ssize_t dlpar_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { struct pseries_hp_errorlog hp_elog; @@ -551,7 +551,7 @@ dlpar_store_out: return rc ? rc : count; } -static ssize_t dlpar_show(struct class *class, struct class_attribute *attr, +static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sprintf(buf, "%s\n", "memory,cpu"); diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 080108d129ed..18447e5fa17d 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -68,6 +68,7 @@ hypertas_fw_features_table[] = { {FW_FEATURE_RPT_INVALIDATE, "hcall-rpt-invalidate"}, {FW_FEATURE_ENERGY_SCALE_INFO, "hcall-energy-scale-info"}, {FW_FEATURE_WATCHDOG, "hcall-watchdog"}, + {FW_FEATURE_PLPKS, "hcall-pks"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 982e5e4b5e06..1a3cb313976a 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -493,7 +493,7 @@ static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index) bool found = false; int rc, index; - if (of_find_property(parent, "ibm,drc-info", NULL)) + if (of_property_present(parent, "ibm,drc-info")) return drc_info_valid_index(parent, drc_index); /* Note that the format of the ibm,drc-indexes array is diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 2e3a317722a8..9c62c2c3b3d0 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -311,11 +311,8 @@ out: static int pseries_remove_mem_node(struct device_node *np) { - const __be32 *prop; - unsigned long base; - unsigned long lmb_size; - int ret = -EINVAL; - int addr_cells, size_cells; + int ret; + struct resource res; /* * Check to see if we are actually removing memory @@ -326,21 +323,11 @@ static int pseries_remove_mem_node(struct device_node *np) /* * Find the base address and size of the memblock */ - prop = of_get_property(np, "reg", NULL); - if (!prop) + ret = of_address_to_resource(np, 0, &res); + if (ret) return ret; - addr_cells = of_n_addr_cells(np); - size_cells = of_n_size_cells(np); - - /* - * "reg" property represents (addr,size) tuple. - */ - base = of_read_number(prop, addr_cells); - prop += addr_cells; - lmb_size = of_read_number(prop, size_cells); - - pseries_remove_memblock(base, lmb_size); + pseries_remove_memblock(res.start, resource_size(&res)); return 0; } @@ -929,11 +916,8 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog) static int pseries_add_mem_node(struct device_node *np) { - const __be32 *prop; - unsigned long base; - unsigned long lmb_size; - int ret = -EINVAL; - int addr_cells, size_cells; + int ret; + struct resource res; /* * Check to see if we are actually adding memory @@ -944,23 +928,14 @@ static int pseries_add_mem_node(struct device_node *np) /* * Find the base and size of the memblock */ - prop = of_get_property(np, "reg", NULL); - if (!prop) + ret = of_address_to_resource(np, 0, &res); + if (ret) return ret; - addr_cells = of_n_addr_cells(np); - size_cells = of_n_size_cells(np); - /* - * "reg" property represents (addr,size) tuple. - */ - base = of_read_number(prop, addr_cells); - prop += addr_cells; - lmb_size = of_read_number(prop, size_cells); - /* * Update memory region to represent the memory add */ - ret = memblock_add(base, lmb_size); + ret = memblock_add(res.start, resource_size(&res)); return (ret < 0) ? -EINVAL : 0; } diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index 783c16ad648b..35254ac7af5e 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -44,7 +44,7 @@ hcall_tracepoint_refcount: std r0,16(r1); \ addi r4,r1,STK_PARAM(FIRST_REG); \ stdu r1,-STACK_FRAME_MIN_SIZE(r1); \ - bl __trace_hcall_entry; \ + bl CFUNC(__trace_hcall_entry); \ ld r3,STACK_FRAME_MIN_SIZE+STK_PARAM(R3)(r1); \ ld r4,STACK_FRAME_MIN_SIZE+STK_PARAM(R4)(r1); \ ld r5,STACK_FRAME_MIN_SIZE+STK_PARAM(R5)(r1); \ @@ -63,7 +63,7 @@ hcall_tracepoint_refcount: std r3,STACK_FRAME_MIN_SIZE+STK_PARAM(R3)(r1); \ mr r4,r3; \ mr r3,r0; \ - bl __trace_hcall_exit; \ + bl CFUNC(__trace_hcall_exit); \ ld r0,STACK_FRAME_MIN_SIZE+16(r1); \ addi r1,r1,STACK_FRAME_MIN_SIZE; \ ld r3,STK_PARAM(R3)(r1); \ diff --git a/arch/powerpc/platforms/pseries/ibmebus.c b/arch/powerpc/platforms/pseries/ibmebus.c index bb9c18682783..44703f13985b 100644 --- a/arch/powerpc/platforms/pseries/ibmebus.c +++ b/arch/powerpc/platforms/pseries/ibmebus.c @@ -267,7 +267,7 @@ static char *ibmebus_chomp(const char *in, size_t count) return out; } -static ssize_t probe_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t probe_store(const struct bus_type *bus, const char *buf, size_t count) { struct device_node *dn = NULL; struct device *dev; @@ -305,7 +305,7 @@ out: } static BUS_ATTR_WO(probe); -static ssize_t remove_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count) { struct device *dev; char *path; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index c74b71d4733d..d59e8a98a200 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,11 @@ static struct iommu_table_group *iommu_pseries_alloc_group(int node) if (!table_group) return NULL; +#ifdef CONFIG_IOMMU_API + table_group->ops = &spapr_tce_table_group_ops; + table_group->pgsizes = SZ_4K; +#endif + table_group->tables[0] = iommu_pseries_alloc_table(node); if (table_group->tables[0]) return table_group; @@ -85,19 +91,24 @@ static struct iommu_table_group *iommu_pseries_alloc_group(int node) static void iommu_pseries_free_group(struct iommu_table_group *table_group, const char *node_name) { - struct iommu_table *tbl; - if (!table_group) return; - tbl = table_group->tables[0]; #ifdef CONFIG_IOMMU_API if (table_group->group) { iommu_group_put(table_group->group); BUG_ON(table_group->group); } #endif - iommu_tce_table_put(tbl); + + /* Default DMA window table is at index 0, while DDW at 1. SR-IOV + * adapters only have table on index 1. + */ + if (table_group->tables[0]) + iommu_tce_table_put(table_group->tables[0]); + + if (table_group->tables[1]) + iommu_tce_table_put(table_group->tables[1]); kfree(table_group); } @@ -306,13 +317,22 @@ static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) { u64 rc; + long rpages = npages; + unsigned long limit; if (!firmware_has_feature(FW_FEATURE_STUFF_TCE)) return tce_free_pSeriesLP(tbl->it_index, tcenum, tbl->it_page_shift, npages); - rc = plpar_tce_stuff((u64)tbl->it_index, - (u64)tcenum << tbl->it_page_shift, 0, npages); + do { + limit = min_t(unsigned long, rpages, 512); + + rc = plpar_tce_stuff((u64)tbl->it_index, + (u64)tcenum << tbl->it_page_shift, 0, limit); + + rpages -= limit; + tcenum += limit; + } while (rpages > 0 && !rc); if (rc && printk_ratelimit()) { printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); @@ -474,7 +494,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, * Set up the page with TCE data, looping through and setting * the values. */ - limit = min_t(long, num_tce, 4096/TCE_ENTRY_SIZE); + limit = min_t(long, num_tce, 4096 / TCE_ENTRY_SIZE); dma_offset = next + be64_to_cpu(maprange->dma_base); for (l = 0; l < limit; l++) { @@ -1111,27 +1131,16 @@ static LIST_HEAD(failed_ddw_pdn_list); static phys_addr_t ddw_memory_hotplug_max(void) { - phys_addr_t max_addr = memory_hotplug_max(); + resource_size_t max_addr = memory_hotplug_max(); struct device_node *memory; for_each_node_by_type(memory, "memory") { - unsigned long start, size; - int n_mem_addr_cells, n_mem_size_cells, len; - const __be32 *memcell_buf; + struct resource res; - memcell_buf = of_get_property(memory, "reg", &len); - if (!memcell_buf || len <= 0) + if (of_address_to_resource(memory, 0, &res)) continue; - n_mem_addr_cells = of_n_addr_cells(memory); - n_mem_size_cells = of_n_size_cells(memory); - - start = of_read_number(memcell_buf, n_mem_addr_cells); - memcell_buf += n_mem_addr_cells; - size = of_read_number(memcell_buf, n_mem_size_cells); - memcell_buf += n_mem_size_cells; - - max_addr = max_t(phys_addr_t, max_addr, start + size); + max_addr = max_t(resource_size_t, max_addr, res.end + 1); } return max_addr; @@ -1700,27 +1709,26 @@ static int __init disable_multitce(char *str) __setup("multitce=", disable_multitce); -static int tce_iommu_bus_notifier(struct notifier_block *nb, - unsigned long action, void *data) +#ifdef CONFIG_SPAPR_TCE_IOMMU +struct iommu_group *pSeries_pci_device_group(struct pci_controller *hose, + struct pci_dev *pdev) { - struct device *dev = data; + struct device_node *pdn, *dn = pdev->dev.of_node; + struct iommu_group *grp; + struct pci_dn *pci; - switch (action) { - case BUS_NOTIFY_DEL_DEVICE: - iommu_del_device(dev); - return 0; - default: - return 0; - } + pdn = pci_dma_find(dn, NULL); + if (!pdn || !PCI_DN(pdn)) + return ERR_PTR(-ENODEV); + + pci = PCI_DN(pdn); + if (!pci->table_group) + return ERR_PTR(-ENODEV); + + grp = pci->table_group->group; + if (!grp) + return ERR_PTR(-ENODEV); + + return iommu_group_ref_get(grp); } - -static struct notifier_block tce_iommu_bus_nb = { - .notifier_call = tce_iommu_bus_notifier, -}; - -static int __init tce_iommu_bus_notifier_init(void) -{ - bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); - return 0; -} -machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init); +#endif diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 643d309d1bd0..6f30113b5468 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -62,18 +62,10 @@ static struct ctl_table nmi_wd_lpm_factor_ctl_table[] = { }, {} }; -static struct ctl_table nmi_wd_lpm_factor_sysctl_root[] = { - { - .procname = "kernel", - .mode = 0555, - .child = nmi_wd_lpm_factor_ctl_table, - }, - {} -}; static int __init register_nmi_wd_lpm_factor_sysctl(void) { - register_sysctl_table(nmi_wd_lpm_factor_sysctl_root); + register_sysctl("kernel", nmi_wd_lpm_factor_ctl_table); return 0; } @@ -787,8 +779,8 @@ int rtas_syscall_dispatch_ibm_suspend_me(u64 handle) return pseries_migrate_partition(handle); } -static ssize_t migration_store(struct class *class, - struct class_attribute *attr, const char *buf, +static ssize_t migration_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t count) { u64 streamid; diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c index 6f7bf3fc3aea..b0658ea3eccb 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -378,7 +378,7 @@ bool plpks_is_available(void) { int rc; - if (!firmware_has_feature(FW_FEATURE_LPAR)) + if (!firmware_has_feature(FW_FEATURE_PLPKS)) return false; rc = _plpks_get_config(); @@ -690,6 +690,9 @@ static __init int pseries_plpks_init(void) { int rc; + if (!firmware_has_feature(FW_FEATURE_PLPKS)) + return -ENODEV; + rc = _plpks_get_config(); if (rc) { diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 1d75b7742ef0..f8bce40ebd0c 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -123,5 +123,9 @@ static inline void pseries_lpar_read_hblkrm_characteristics(void) { } #endif void pseries_rng_init(void); +#ifdef CONFIG_SPAPR_TCE_IOMMU +struct iommu_group *pSeries_pci_device_group(struct pci_controller *hose, + struct pci_dev *pdev); +#endif #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c index 09e98d301db0..2c661b798235 100644 --- a/arch/powerpc/platforms/pseries/pseries_energy.c +++ b/arch/powerpc/platforms/pseries/pseries_energy.c @@ -300,20 +300,22 @@ static struct device_attribute attr_percpu_deactivate_hint = static int __init pseries_energy_init(void) { int cpu, err; - struct device *cpu_dev; + struct device *cpu_dev, *dev_root; if (!firmware_has_feature(FW_FEATURE_BEST_ENERGY)) return 0; /* H_BEST_ENERGY hcall not supported */ /* Create the sysfs files */ - err = device_create_file(cpu_subsys.dev_root, - &attr_cpu_activate_hint_list); - if (!err) - err = device_create_file(cpu_subsys.dev_root, - &attr_cpu_deactivate_hint_list); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + err = device_create_file(dev_root, &attr_cpu_activate_hint_list); + if (!err) + err = device_create_file(dev_root, &attr_cpu_deactivate_hint_list); + put_device(dev_root); + if (err) + return err; + } - if (err) - return err; for_each_possible_cpu(cpu) { cpu_dev = get_cpu_device(cpu); err = device_create_file(cpu_dev, @@ -337,14 +339,18 @@ static int __init pseries_energy_init(void) static void __exit pseries_energy_cleanup(void) { int cpu; - struct device *cpu_dev; + struct device *cpu_dev, *dev_root; if (!sysfs_entries) return; /* Remove the sysfs files */ - device_remove_file(cpu_subsys.dev_root, &attr_cpu_activate_hint_list); - device_remove_file(cpu_subsys.dev_root, &attr_cpu_deactivate_hint_list); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + device_remove_file(dev_root, &attr_cpu_activate_hint_list); + device_remove_file(dev_root, &attr_cpu_deactivate_hint_list); + put_device(dev_root); + } for_each_possible_cpu(cpu) { cpu_dev = get_cpu_device(cpu); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 4a0cec8cf623..e2a57cfa6c83 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -1118,6 +1118,9 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) struct pci_controller_ops pseries_pci_controller_ops = { .probe_mode = pSeries_pci_probe_mode, +#ifdef CONFIG_SPAPR_TCE_IOMMU + .device_group = pSeries_pci_device_group, +#endif }; define_machine(pseries) { @@ -1135,7 +1138,6 @@ define_machine(pseries) { .get_boot_time = rtas_get_boot_time, .get_rtc_time = rtas_get_rtc_time, .set_rtc_time = rtas_set_rtc_time, - .calibrate_decr = generic_calibrate_decr, .progress = rtas_progress, .system_reset_exception = pSeries_system_reset_exception, .machine_check_early = pseries_machine_check_realmode, diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index 1b902cbf85c5..5c43435472cc 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -143,6 +143,7 @@ static const struct platform_suspend_ops pseries_suspend_ops = { **/ static int pseries_suspend_sysfs_register(struct device *dev) { + struct device *dev_root; int rc; if ((rc = subsys_system_register(&suspend_subsys, NULL))) @@ -151,8 +152,13 @@ static int pseries_suspend_sysfs_register(struct device *dev) dev->id = 0; dev->bus = &suspend_subsys; - if ((rc = device_create_file(suspend_subsys.dev_root, &dev_attr_hibernate))) - goto subsys_unregister; + dev_root = bus_get_dev_root(&suspend_subsys); + if (dev_root) { + rc = device_create_file(dev_root, &dev_attr_hibernate); + put_device(dev_root); + if (rc) + goto subsys_unregister; + } return 0; diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 770df9351aaa..2dc9cbc4bcd8 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -1006,7 +1006,7 @@ ATTRIBUTE_GROUPS(vio_cmo_dev); /* sysfs bus functions and data structures for CMO */ #define viobus_cmo_rd_attr(name) \ -static ssize_t cmo_bus_##name##_show(struct bus_type *bt, char *buf) \ +static ssize_t cmo_bus_##name##_show(const struct bus_type *bt, char *buf) \ { \ return sprintf(buf, "%lu\n", vio_cmo.name); \ } \ @@ -1015,7 +1015,7 @@ static struct bus_attribute bus_attr_cmo_bus_##name = \ #define viobus_cmo_pool_rd_attr(name, var) \ static ssize_t \ -cmo_##name##_##var##_show(struct bus_type *bt, char *buf) \ +cmo_##name##_##var##_show(const struct bus_type *bt, char *buf) \ { \ return sprintf(buf, "%lu\n", vio_cmo.name.var); \ } \ @@ -1030,12 +1030,12 @@ viobus_cmo_pool_rd_attr(reserve, size); viobus_cmo_pool_rd_attr(excess, size); viobus_cmo_pool_rd_attr(excess, free); -static ssize_t cmo_high_show(struct bus_type *bt, char *buf) +static ssize_t cmo_high_show(const struct bus_type *bt, char *buf) { return sprintf(buf, "%lu\n", vio_cmo.high); } -static ssize_t cmo_high_store(struct bus_type *bt, const char *buf, +static ssize_t cmo_high_store(const struct bus_type *bt, const char *buf, size_t count) { unsigned long flags; @@ -1381,7 +1381,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) } if (family == PFO) { - if (of_get_property(of_node, "interrupt-controller", NULL)) { + if (of_property_read_bool(of_node, "interrupt-controller")) { pr_debug("%s: Skipping the interrupt controller %pOFn.\n", __func__, of_node); return NULL; @@ -1440,7 +1440,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) viodev->dev.bus = &vio_bus_type; viodev->dev.release = vio_dev_release; - if (of_get_property(viodev->dev.of_node, "ibm,my-dma-window", NULL)) { + if (of_property_present(viodev->dev.of_node, "ibm,my-dma-window")) { if (firmware_has_feature(FW_FEATURE_CMO)) vio_cmo_set_dma_ops(viodev); else diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index 3093f14111e6..70ce66eadff1 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -18,7 +18,7 @@ static struct device_node *find_dcr_parent(struct device_node *node) const u32 *p; for (par = of_node_get(node); par;) { - if (of_get_property(par, "dcr-controller", NULL)) + if (of_property_read_bool(par, "dcr-controller")) break; p = of_get_property(par, "dcr-parent", NULL); tmp = par; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index 00705258ecf9..c7327b836d2b 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -256,7 +256,6 @@ void __init ehv_pic_init(void) { struct device_node *np, *np2; struct ehv_pic *ehv_pic; - int coreint_flag = 1; np = of_find_compatible_node(NULL, NULL, "epapr,hv-pic"); if (!np) { @@ -264,9 +263,6 @@ void __init ehv_pic_init(void) return; } - if (!of_find_property(np, "has-external-proxy", NULL)) - coreint_flag = 0; - ehv_pic = kzalloc(sizeof(struct ehv_pic), GFP_KERNEL); if (!ehv_pic) { of_node_put(np); @@ -292,7 +288,7 @@ void __init ehv_pic_init(void) ehv_pic->hc_irq = ehv_pic_irq_chip; ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity; - ehv_pic->coreint_flag = coreint_flag; + ehv_pic->coreint_flag = of_property_read_bool(np, "has-external-proxy"); global_ehv_pic = ehv_pic; irq_set_default_host(global_ehv_pic->irqhost); diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c index c2baa283e624..ce6c739c51e5 100644 --- a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c +++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c @@ -116,7 +116,8 @@ static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644, static int __init fsl_wakeup_sys_init(void) { - int ret; + struct device *dev_root; + int ret = -EINVAL; fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL); if (!fsl_wakeup) @@ -124,16 +125,26 @@ static int __init fsl_wakeup_sys_init(void) INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource); - ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes); - if (ret) - kfree(fsl_wakeup); + dev_root = bus_get_dev_root(&mpic_subsys); + if (dev_root) { + ret = device_create_file(dev_root, &mpic_attributes); + put_device(dev_root); + if (ret) + kfree(fsl_wakeup); + } return ret; } static void __exit fsl_wakeup_sys_exit(void) { - device_remove_file(mpic_subsys.dev_root, &mpic_attributes); + struct device *dev_root; + + dev_root = bus_get_dev_root(&mpic_subsys); + if (dev_root) { + device_remove_file(dev_root, &mpic_attributes); + put_device(dev_root); + } mutex_lock(&sysfs_lock); diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index c8f044d62fe2..f8e492ee54cc 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -450,7 +450,6 @@ int fsl_rio_setup(struct platform_device *dev) int rc = 0; const u32 *dt_range, *cell, *port_index; u32 active_ports = 0; - struct resource regs, rmu_regs; struct device_node *np, *rmu_node; int rlen; u32 ccsr; @@ -465,17 +464,7 @@ int fsl_rio_setup(struct platform_device *dev) return -ENODEV; } - rc = of_address_to_resource(dev->dev.of_node, 0, ®s); - if (rc) { - dev_err(&dev->dev, "Can't get %pOF property 'reg'\n", - dev->dev.of_node); - return -EFAULT; - } - dev_info(&dev->dev, "Of-device full name %pOF\n", - dev->dev.of_node); - dev_info(&dev->dev, "Regs: %pR\n", ®s); - - rio_regs_win = ioremap(regs.start, resource_size(®s)); + rio_regs_win = of_iomap(dev->dev.of_node, 0); if (!rio_regs_win) { dev_err(&dev->dev, "Unable to map rio register window\n"); rc = -ENOMEM; @@ -509,15 +498,9 @@ int fsl_rio_setup(struct platform_device *dev) rc = -ENOENT; goto err_rmu; } - rc = of_address_to_resource(rmu_node, 0, &rmu_regs); - if (rc) { - dev_err(&dev->dev, "Can't get %pOF property 'reg'\n", - rmu_node); - of_node_put(rmu_node); - goto err_rmu; - } + rmu_regs_win = of_iomap(rmu_node, 0); + of_node_put(rmu_node); - rmu_regs_win = ioremap(rmu_regs.start, resource_size(&rmu_regs)); if (!rmu_regs_win) { dev_err(&dev->dev, "Unable to map rmu register window\n"); rc = -ENOMEM; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 78118c188993..6ebbbca41065 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -174,7 +174,7 @@ static int __init setup_rstcr(void) }; for_each_node_by_name(np, "global-utilities") { - if ((of_get_property(np, "fsl,has-rstcr", NULL))) { + if (of_property_read_bool(np, "fsl,has-rstcr")) { rstcr = of_iomap(np, 0) + 0xb0; if (!rstcr) { printk (KERN_ERR "Error: reset control " diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 9a9381f102d6..ba287abcb008 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1260,11 +1260,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, } /* Read extra device-tree properties into the flags variable */ - if (of_get_property(node, "big-endian", NULL)) + if (of_property_read_bool(node, "big-endian")) flags |= MPIC_BIG_ENDIAN; - if (of_get_property(node, "pic-no-reset", NULL)) + if (of_property_read_bool(node, "pic-no-reset")) flags |= MPIC_NO_RESET; - if (of_get_property(node, "single-cpu-affinity", NULL)) + if (of_property_read_bool(node, "single-cpu-affinity")) flags |= MPIC_SINGLE_DEST_CPU; if (of_device_is_compatible(node, "fsl,mpic")) { flags |= MPIC_FSL | MPIC_LARGE_VECTORS; diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index d75064fb7d12..1a3ac0b5dd89 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -116,7 +116,7 @@ static unsigned int mpic_msgr_number_of_blocks(void) for (;;) { snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count); - if (!of_find_property(aliases, buf, NULL)) + if (!of_property_present(aliases, buf)) break; count += 1; diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index 30051397292f..db520c40cb6f 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c @@ -45,9 +45,9 @@ phys_addr_t get_csrbase(void) tsi = of_find_node_by_type(NULL, "tsi-bridge"); if (tsi) { - unsigned int size; - const void *prop = of_get_property(tsi, "reg", &size); - tsi108_csr_base = of_translate_address(tsi, prop); + struct resource res; + of_address_to_resource(tsi, 0, &res); + tsi108_csr_base = res.start; of_node_put(tsi); } return tsi108_csr_base; @@ -132,7 +132,7 @@ static int __init tsi108_eth_of_init(void) * driver itself to phylib and use a non-misleading * name for the workaround flag - it's not actually to * do with the model of PHY in use */ - if (of_get_property(phy, "txc-rxc-delay-disable", NULL)) + if (of_property_read_bool(phy, "txc-rxc-delay-disable")) tsi_eth_data.phy_type = TSI108_PHY_BCM54XX; of_node_put(phy); diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 5af4c35ff584..0e42f7bad7db 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -217,9 +217,8 @@ int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary) (hose)->ops = &tsi108_direct_pci_ops; - printk(KERN_INFO "Found tsi108 PCI host bridge at 0x%08x. " - "Firmware bus number: %d->%d\n", - rsrc.start, hose->first_busno, hose->last_busno); + pr_info("Found tsi108 PCI host bridge at 0x%pa. Firmware bus number: %d->%d\n", + &rsrc.start, hose->first_busno, hose->last_busno); /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index edc17b6b1cc2..f6ec6dba92dc 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -259,7 +259,7 @@ static int __init icp_native_init_one_node(struct device_node *np, unsigned int ilen; const __be32 *ireg; int i; - int reg_tuple_size; + int num_reg; int num_servers = 0; /* This code does the theorically broken assumption that the interrupt @@ -280,21 +280,14 @@ static int __init icp_native_init_one_node(struct device_node *np, num_servers = of_read_number(ireg + 1, 1); } - ireg = of_get_property(np, "reg", &ilen); - if (!ireg) { - pr_err("icp_native: Can't find interrupt reg property"); - return -1; - } - - reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4; - if (((ilen % reg_tuple_size) != 0) - || (num_servers && (num_servers != (ilen / reg_tuple_size)))) { + num_reg = of_address_count(np); + if (num_servers && (num_servers != num_reg)) { pr_err("icp_native: ICP reg len (%d) != num servers (%d)", - ilen / reg_tuple_size, num_servers); + num_reg, num_servers); return -1; } - for (i = 0; i < (ilen / reg_tuple_size); i++) { + for (i = 0; i < num_reg; i++) { struct resource r; int err; diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index 19d880ebc5e6..9f0af4d795d8 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -599,11 +599,9 @@ bool __init xive_native_init(void) } /* Do we support single escalation */ - if (of_get_property(np, "single-escalation-support", NULL) != NULL) - xive_has_single_esc = true; + xive_has_single_esc = of_property_read_bool(np, "single-escalation-support"); - if (of_get_property(np, "vp-save-restore", NULL)) - xive_has_save_restore = true; + xive_has_save_restore = of_property_read_bool(np, "vp-save-restore"); /* Configure Thread Management areas for KVM */ for_each_possible_cpu(cpu) diff --git a/arch/powerpc/tools/relocs_check.sh b/arch/powerpc/tools/relocs_check.sh index 63792af00417..6b350e75014c 100755 --- a/arch/powerpc/tools/relocs_check.sh +++ b/arch/powerpc/tools/relocs_check.sh @@ -15,21 +15,8 @@ if [ $# -lt 3 ]; then exit 1 fi -# Have Kbuild supply the path to objdump and nm so we handle cross compilation. -objdump="$1" -nm="$2" -vmlinux="$3" - -# Remove from the bad relocations those that match an undefined weak symbol -# which will result in an absolute relocation to 0. -# Weak unresolved symbols are of that form in nm output: -# " w _binary__btf_vmlinux_bin_end" -undef_weak_symbols=$($nm "$vmlinux" | awk '$1 ~ /w/ { print $2 }') - bad_relocs=$( -$objdump -R "$vmlinux" | - # Only look at relocation lines. - grep -E '\ 2 select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE @@ -33,6 +34,7 @@ config RISCV select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_VDSO_DATA select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT select ARCH_STACKWALK @@ -44,22 +46,23 @@ config RISCV select ARCH_USE_QUEUED_RWLOCKS select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_FRAME_POINTERS - select ARCH_WANT_GENERAL_HUGETLB - select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP + select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT select ARCH_WANT_HUGE_PMD_SHARE if 64BIT select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL + select ARCH_WANT_OPTIMIZE_VMEMMAP select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU select BUILDTIME_TABLE_SORT if MMU select CLINT_TIMER if !MMU select CLONE_BACKWARDS select COMMON_CLK - select CPU_PM if CPU_IDLE + select CPU_PM if CPU_IDLE || HIBERNATION select EDAC_SUPPORT select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_EARLY_IOREMAP + select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO select GENERIC_IDLE_POLL_SETUP select GENERIC_IOREMAP if MMU @@ -121,10 +124,10 @@ config RISCV select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select IRQ_FORCED_THREADING + select KASAN_VMALLOC if KASAN select MODULES_USE_ELF_RELA if MODULES select MODULE_SECTIONS if MODULES select OF - select OF_DMA_DEFAULT_COHERENT select OF_EARLY_FLATTREE select OF_IRQ select PCI_DOMAINS_GENERIC if PCI @@ -139,12 +142,23 @@ config RISCV select TRACE_IRQFLAGS_SUPPORT select UACCESS_MEMCPY if !MMU select ZONE_DMA32 if 64BIT - select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && $(cc-option,-fpatchable-function-entry=8) + select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION +config CLANG_SUPPORTS_DYNAMIC_FTRACE + def_bool CC_IS_CLANG + # https://github.com/llvm/llvm-project/commit/6ab8927931851bb42b2c93a00801dc499d7d9b1e + depends on CLANG_VERSION >= 130000 + # https://github.com/ClangBuiltLinux/linux/issues/1817 + depends on AS_IS_GNU || (AS_IS_LLVM && (LD_IS_LLD || LD_VERSION >= 23600)) + +config GCC_SUPPORTS_DYNAMIC_FTRACE + def_bool CC_IS_GCC + depends on $(cc-option,-fpatchable-function-entry=8) + config ARCH_MMAP_RND_BITS_MIN default 18 if 64BIT default 8 @@ -181,8 +195,8 @@ config MMU config PAGE_OFFSET hex - default 0xC0000000 if 32BIT - default 0x80000000 if 64BIT && !MMU + default 0xC0000000 if 32BIT && MMU + default 0x80000000 if !MMU default 0xff60000000000000 if 64BIT config KASAN_SHADOW_OFFSET @@ -249,7 +263,7 @@ config AS_HAS_INSN def_bool $(as-instr,.insn r 51$(comma) 0$(comma) 0$(comma) t0$(comma) t0$(comma) zero) source "arch/riscv/Kconfig.socs" -source "arch/riscv/Kconfig.erratas" +source "arch/riscv/Kconfig.errata" menu "Platform type" @@ -283,7 +297,6 @@ config ARCH_RV32I select GENERIC_LIB_ASHRDI3 select GENERIC_LIB_LSHRDI3 select GENERIC_LIB_UCMPDI2 - select MMU config ARCH_RV64I bool "RV64I" @@ -324,6 +337,14 @@ config SMP If you don't know what to do here, say N. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + config NR_CPUS int "Maximum number of CPUs (2-512)" depends on SMP @@ -382,9 +403,9 @@ config RISCV_ALTERNATIVE depends on !XIP_KERNEL help This Kconfig allows the kernel to automatically patch the - errata required by the execution platform at run time. The - code patching is performed once in the boot stages. It means - that the overhead from this mechanism is just taken once. + erratum or cpufeature required by the execution platform at run + time. The code patching overhead is minimal, as it's only done + once at boot and once on each module load. config RISCV_ALTERNATIVE_EARLY bool @@ -402,13 +423,32 @@ config RISCV_ISA_C If you don't know what to do here, say Y. -config RISCV_ISA_SVPBMT - bool "SVPBMT extension support" +config RISCV_ISA_SVNAPOT + bool "Svnapot extension support for supervisor mode NAPOT pages" depends on 64BIT && MMU depends on RISCV_ALTERNATIVE default y help - Adds support to dynamically detect the presence of the SVPBMT + Allow kernel to detect the Svnapot ISA-extension dynamically at boot + time and enable its usage. + + The Svnapot extension is used to mark contiguous PTEs as a range + of contiguous virtual-to-physical translations for a naturally + aligned power-of-2 (NAPOT) granularity larger than the base 4KB page + size. When HUGETLBFS is also selected this option unconditionally + allocates some memory for each NAPOT page size supported by the kernel. + When optimizing for low memory consumption and for platforms without + the Svnapot extension, it may be better to say N here. + + If you don't know what to do here, say Y. + +config RISCV_ISA_SVPBMT + bool "Svpbmt extension support for supervisor mode page-based memory types" + depends on 64BIT && MMU + depends on RISCV_ALTERNATIVE + default y + help + Adds support to dynamically detect the presence of the Svpbmt ISA-extension (Supervisor-mode: page-based memory types) and enable its usage. @@ -416,7 +456,7 @@ config RISCV_ISA_SVPBMT that indicate the cacheability, idempotency, and ordering properties for access to that page. - The SVPBMT extension is only available on 64Bit cpus. + The Svpbmt extension is only available on 64-bit cpus. If you don't know what to do here, say Y. @@ -460,6 +500,19 @@ config RISCV_ISA_ZICBOM If you don't know what to do here, say Y. +config RISCV_ISA_ZICBOZ + bool "Zicboz extension support for faster zeroing of memory" + depends on MMU + depends on RISCV_ALTERNATIVE + default y + help + Enable the use of the Zicboz extension (cbo.zero instruction) + when available. + + The Zicboz extension is used for faster zeroing of memory. + + If you don't know what to do here, say Y. + config TOOLCHAIN_HAS_ZIHINTPAUSE bool default y @@ -586,6 +639,20 @@ config COMPAT If you want to execute 32-bit userspace applications, say Y. +config RELOCATABLE + bool "Build a relocatable kernel" + depends on MMU && 64BIT && !XIP_KERNEL + help + This builds a kernel as a Position Independent Executable (PIE), + which retains all relocation metadata required to relocate the + kernel binary at runtime to a different virtual address than the + address it was linked at. + Since RISCV uses the RELA relocation format, this requires a + relocation pass at runtime even if the kernel is loaded at the + same address it was linked at. + + If unsure, say N. + endmenu # "Kernel features" menu "Boot options" @@ -732,6 +799,15 @@ menu "Power management options" source "kernel/power/Kconfig" +# Hibernation is only possible on systems where the SBI implementation has +# marked its reserved memory as not accessible from, or does not run +# from the same memory as, Linux +config ARCH_HIBERNATION_POSSIBLE + def_bool NONPORTABLE + +config ARCH_HIBERNATION_HEADER + def_bool HIBERNATION + endmenu # "Power management options" menu "CPU Power Management" diff --git a/arch/riscv/Kconfig.erratas b/arch/riscv/Kconfig.errata similarity index 100% rename from arch/riscv/Kconfig.erratas rename to arch/riscv/Kconfig.errata diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index b05e833a022d..0fb256bf8270 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -7,9 +7,13 @@ # OBJCOPYFLAGS := -O binary -LDFLAGS_vmlinux := +LDFLAGS_vmlinux := -z norelro +ifeq ($(CONFIG_RELOCATABLE),y) + LDFLAGS_vmlinux += -shared -Bsymbolic -z notext --emit-relocs + KBUILD_CFLAGS += -fPIE +endif ifeq ($(CONFIG_DYNAMIC_FTRACE),y) - LDFLAGS_vmlinux := --no-relax + LDFLAGS_vmlinux += --no-relax KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY ifeq ($(CONFIG_RISCV_ISA_C),y) CC_FLAGS_FTRACE := -fpatchable-function-entry=4 @@ -183,3 +187,7 @@ rv64_randconfig: PHONY += rv32_defconfig rv32_defconfig: $(Q)$(MAKE) -f $(srctree)/Makefile defconfig 32-bit.config + +PHONY += rv32_nommu_virt_defconfig +rv32_nommu_virt_defconfig: + $(Q)$(MAKE) -f $(srctree)/Makefile nommu_virt_defconfig 32-bit.config diff --git a/arch/riscv/Makefile.postlink b/arch/riscv/Makefile.postlink new file mode 100644 index 000000000000..a46fc578b30b --- /dev/null +++ b/arch/riscv/Makefile.postlink @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0 +# =========================================================================== +# Post-link riscv pass +# =========================================================================== +# +# Check that vmlinux relocations look sane + +PHONY := __archpost +__archpost: + +-include include/config/auto.conf +include $(srctree)/scripts/Kbuild.include + +quiet_cmd_relocs_check = CHKREL $@ +cmd_relocs_check = \ + $(CONFIG_SHELL) $(srctree)/arch/riscv/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@" + +ifdef CONFIG_RELOCATABLE +quiet_cmd_cp_vmlinux_relocs = CPREL vmlinux.relocs +cmd_cp_vmlinux_relocs = cp vmlinux vmlinux.relocs + +quiet_cmd_relocs_strip = STRIPREL $@ +cmd_relocs_strip = $(OBJCOPY) --remove-section='.rel.*' \ + --remove-section='.rel__*' \ + --remove-section='.rela.*' \ + --remove-section='.rela__*' $@ +endif + +# `@true` prevents complaint when there is nothing to be done + +vmlinux: FORCE + @true +ifdef CONFIG_RELOCATABLE + $(call if_changed,relocs_check) + $(call if_changed,cp_vmlinux_relocs) + $(call if_changed,relocs_strip) +endif + +%.ko: FORCE + @true + +clean: + @true + +PHONY += FORCE clean + +FORCE: + +.PHONY: $(PHONY) diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile index c72de7232abb..22b13947bd13 100644 --- a/arch/riscv/boot/Makefile +++ b/arch/riscv/boot/Makefile @@ -33,7 +33,14 @@ $(obj)/xipImage: vmlinux FORCE endif +ifdef CONFIG_RELOCATABLE +vmlinux.relocs: vmlinux + @ (! [ -f vmlinux.relocs ] && echo "vmlinux.relocs can't be found, please remove vmlinux and try again") || true + +$(obj)/Image: vmlinux.relocs FORCE +else $(obj)/Image: vmlinux FORCE +endif $(call if_changed,objcopy) $(obj)/Image.gz: $(obj)/Image FORCE diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile index a1055965fbee..7b2637c8c332 100644 --- a/arch/riscv/errata/Makefile +++ b/arch/riscv/errata/Makefile @@ -1,2 +1,6 @@ +ifdef CONFIG_RELOCATABLE +KBUILD_CFLAGS += -fno-pie +endif + obj-$(CONFIG_ERRATA_SIFIVE) += sifive/ obj-$(CONFIG_ERRATA_THEAD) += thead/ diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c index 31d2ebea4286..3d9a32d791f7 100644 --- a/arch/riscv/errata/sifive/errata.c +++ b/arch/riscv/errata/sifive/errata.c @@ -14,7 +14,7 @@ #include struct errata_info_t { - char name[ERRATA_STRING_LENGTH_MAX]; + char name[32]; bool (*check_func)(unsigned long arch_id, unsigned long impid); }; @@ -82,11 +82,9 @@ static void __init_or_module warn_miss_errata(u32 miss_errata) pr_warn("----------------------------------------------------------------\n"); } -void __init_or_module sifive_errata_patch_func(struct alt_entry *begin, - struct alt_entry *end, - unsigned long archid, - unsigned long impid, - unsigned int stage) +void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + unsigned long archid, unsigned long impid, + unsigned int stage) { struct alt_entry *alt; u32 cpu_req_errata; @@ -101,12 +99,12 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin, for (alt = begin; alt < end; alt++) { if (alt->vendor_id != SIFIVE_VENDOR_ID) continue; - if (alt->errata_id >= ERRATA_SIFIVE_NUMBER) { - WARN(1, "This errata id:%d is not in kernel errata list", alt->errata_id); + if (alt->patch_id >= ERRATA_SIFIVE_NUMBER) { + WARN(1, "This errata id:%d is not in kernel errata list", alt->patch_id); continue; } - tmp = (1U << alt->errata_id); + tmp = (1U << alt->patch_id); if (cpu_req_errata & tmp) { mutex_lock(&text_mutex); patch_text_nosync(ALT_OLD_PTR(alt), ALT_ALT_PTR(alt), diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c index 3b96a06d3c54..c259dc925ec1 100644 --- a/arch/riscv/errata/thead/errata.c +++ b/arch/riscv/errata/thead/errata.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include #include @@ -81,9 +83,9 @@ static u32 thead_errata_probe(unsigned int stage, return cpu_req_errata; } -void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, - unsigned long archid, unsigned long impid, - unsigned int stage) +void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + unsigned long archid, unsigned long impid, + unsigned int stage) { struct alt_entry *alt; u32 cpu_req_errata = thead_errata_probe(stage, archid, impid); @@ -93,10 +95,10 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al for (alt = begin; alt < end; alt++) { if (alt->vendor_id != THEAD_VENDOR_ID) continue; - if (alt->errata_id >= ERRATA_THEAD_NUMBER) + if (alt->patch_id >= ERRATA_THEAD_NUMBER) continue; - tmp = (1U << alt->errata_id); + tmp = (1U << alt->patch_id); if (cpu_req_errata & tmp) { oldptr = ALT_OLD_PTR(alt); altptr = ALT_ALT_PTR(alt); @@ -115,3 +117,11 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) local_flush_icache_all(); } + +void thead_feature_probe_func(unsigned int cpu, + unsigned long archid, + unsigned long impid) +{ + if ((archid == 0) && (impid == 0)) + per_cpu(misaligned_access_speed, cpu) = RISCV_HWPROBE_MISALIGNED_FAST; +} diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h index 51c6867e02f3..b8c55fb3ab2c 100644 --- a/arch/riscv/include/asm/alternative-macros.h +++ b/arch/riscv/include/asm/alternative-macros.h @@ -6,18 +6,18 @@ #ifdef __ASSEMBLY__ -.macro ALT_ENTRY oldptr newptr vendor_id errata_id new_len +.macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len .4byte \oldptr - . .4byte \newptr - . .2byte \vendor_id .2byte \new_len - .4byte \errata_id + .4byte \patch_id .endm -.macro ALT_NEW_CONTENT vendor_id, errata_id, enable = 1, new_c : vararg +.macro ALT_NEW_CONTENT vendor_id, patch_id, enable = 1, new_c .if \enable .pushsection .alternative, "a" - ALT_ENTRY 886b, 888f, \vendor_id, \errata_id, 889f - 888f + ALT_ENTRY 886b, 888f, \vendor_id, \patch_id, 889f - 888f .popsection .subsection 1 888 : @@ -33,7 +33,7 @@ .endif .endm -.macro ALTERNATIVE_CFG old_c, new_c, vendor_id, errata_id, enable +.macro ALTERNATIVE_CFG old_c, new_c, vendor_id, patch_id, enable 886 : .option push .option norvc @@ -41,13 +41,13 @@ \old_c .option pop 887 : - ALT_NEW_CONTENT \vendor_id, \errata_id, \enable, \new_c + ALT_NEW_CONTENT \vendor_id, \patch_id, \enable, "\new_c" .endm -.macro ALTERNATIVE_CFG_2 old_c, new_c_1, vendor_id_1, errata_id_1, enable_1, \ - new_c_2, vendor_id_2, errata_id_2, enable_2 - ALTERNATIVE_CFG "\old_c", "\new_c_1", \vendor_id_1, \errata_id_1, \enable_1 - ALT_NEW_CONTENT \vendor_id_2, \errata_id_2, \enable_2, \new_c_2 +.macro ALTERNATIVE_CFG_2 old_c, new_c_1, vendor_id_1, patch_id_1, enable_1, \ + new_c_2, vendor_id_2, patch_id_2, enable_2 + ALTERNATIVE_CFG "\old_c", "\new_c_1", \vendor_id_1, \patch_id_1, \enable_1 + ALT_NEW_CONTENT \vendor_id_2, \patch_id_2, \enable_2, "\new_c_2" .endm #define __ALTERNATIVE_CFG(...) ALTERNATIVE_CFG __VA_ARGS__ @@ -58,17 +58,17 @@ #include #include -#define ALT_ENTRY(oldptr, newptr, vendor_id, errata_id, newlen) \ +#define ALT_ENTRY(oldptr, newptr, vendor_id, patch_id, newlen) \ ".4byte ((" oldptr ") - .) \n" \ ".4byte ((" newptr ") - .) \n" \ ".2byte " vendor_id "\n" \ ".2byte " newlen "\n" \ - ".4byte " errata_id "\n" + ".4byte " patch_id "\n" -#define ALT_NEW_CONTENT(vendor_id, errata_id, enable, new_c) \ +#define ALT_NEW_CONTENT(vendor_id, patch_id, enable, new_c) \ ".if " __stringify(enable) " == 1\n" \ ".pushsection .alternative, \"a\"\n" \ - ALT_ENTRY("886b", "888f", __stringify(vendor_id), __stringify(errata_id), "889f - 888f") \ + ALT_ENTRY("886b", "888f", __stringify(vendor_id), __stringify(patch_id), "889f - 888f") \ ".popsection\n" \ ".subsection 1\n" \ "888 :\n" \ @@ -83,7 +83,7 @@ ".previous\n" \ ".endif\n" -#define __ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, enable) \ +#define __ALTERNATIVE_CFG(old_c, new_c, vendor_id, patch_id, enable) \ "886 :\n" \ ".option push\n" \ ".option norvc\n" \ @@ -91,22 +91,22 @@ old_c "\n" \ ".option pop\n" \ "887 :\n" \ - ALT_NEW_CONTENT(vendor_id, errata_id, enable, new_c) + ALT_NEW_CONTENT(vendor_id, patch_id, enable, new_c) -#define __ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, errata_id_1, enable_1, \ - new_c_2, vendor_id_2, errata_id_2, enable_2) \ - __ALTERNATIVE_CFG(old_c, new_c_1, vendor_id_1, errata_id_1, enable_1) \ - ALT_NEW_CONTENT(vendor_id_2, errata_id_2, enable_2, new_c_2) +#define __ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, patch_id_1, enable_1, \ + new_c_2, vendor_id_2, patch_id_2, enable_2) \ + __ALTERNATIVE_CFG(old_c, new_c_1, vendor_id_1, patch_id_1, enable_1) \ + ALT_NEW_CONTENT(vendor_id_2, patch_id_2, enable_2, new_c_2) #endif /* __ASSEMBLY__ */ -#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, CONFIG_k) \ - __ALTERNATIVE_CFG(old_c, new_c, vendor_id, errata_id, IS_ENABLED(CONFIG_k)) +#define _ALTERNATIVE_CFG(old_c, new_c, vendor_id, patch_id, CONFIG_k) \ + __ALTERNATIVE_CFG(old_c, new_c, vendor_id, patch_id, IS_ENABLED(CONFIG_k)) -#define _ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, errata_id_1, CONFIG_k_1, \ - new_c_2, vendor_id_2, errata_id_2, CONFIG_k_2) \ - __ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, errata_id_1, IS_ENABLED(CONFIG_k_1), \ - new_c_2, vendor_id_2, errata_id_2, IS_ENABLED(CONFIG_k_2)) +#define _ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, patch_id_1, CONFIG_k_1, \ + new_c_2, vendor_id_2, patch_id_2, CONFIG_k_2) \ + __ALTERNATIVE_CFG_2(old_c, new_c_1, vendor_id_1, patch_id_1, IS_ENABLED(CONFIG_k_1), \ + new_c_2, vendor_id_2, patch_id_2, IS_ENABLED(CONFIG_k_2)) #else /* CONFIG_RISCV_ALTERNATIVE */ #ifdef __ASSEMBLY__ @@ -137,19 +137,19 @@ /* * Usage: - * ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k) + * ALTERNATIVE(old_content, new_content, vendor_id, patch_id, CONFIG_k) * in the assembly code. Otherwise, - * asm(ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k)); + * asm(ALTERNATIVE(old_content, new_content, vendor_id, patch_id, CONFIG_k)); * * old_content: The old content which is probably replaced with new content. * new_content: The new content. * vendor_id: The CPU vendor ID. - * errata_id: The errata ID. - * CONFIG_k: The Kconfig of this errata. When Kconfig is disabled, the old + * patch_id: The patch ID (erratum ID or cpufeature ID). + * CONFIG_k: The Kconfig of this patch ID. When Kconfig is disabled, the old * content will alwyas be executed. */ -#define ALTERNATIVE(old_content, new_content, vendor_id, errata_id, CONFIG_k) \ - _ALTERNATIVE_CFG(old_content, new_content, vendor_id, errata_id, CONFIG_k) +#define ALTERNATIVE(old_content, new_content, vendor_id, patch_id, CONFIG_k) \ + _ALTERNATIVE_CFG(old_content, new_content, vendor_id, patch_id, CONFIG_k) /* * A vendor wants to replace an old_content, but another vendor has used @@ -158,9 +158,9 @@ * on the following sample code and then replace ALTERNATIVE() with * ALTERNATIVE_2() to append its customized content. */ -#define ALTERNATIVE_2(old_content, new_content_1, vendor_id_1, errata_id_1, CONFIG_k_1, \ - new_content_2, vendor_id_2, errata_id_2, CONFIG_k_2) \ - _ALTERNATIVE_CFG_2(old_content, new_content_1, vendor_id_1, errata_id_1, CONFIG_k_1, \ - new_content_2, vendor_id_2, errata_id_2, CONFIG_k_2) +#define ALTERNATIVE_2(old_content, new_content_1, vendor_id_1, patch_id_1, CONFIG_k_1, \ + new_content_2, vendor_id_2, patch_id_2, CONFIG_k_2) \ + _ALTERNATIVE_CFG_2(old_content, new_content_1, vendor_id_1, patch_id_1, CONFIG_k_1, \ + new_content_2, vendor_id_2, patch_id_2, CONFIG_k_2) #endif diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h index b8648d4f2ac1..6a41537826a7 100644 --- a/arch/riscv/include/asm/alternative.h +++ b/arch/riscv/include/asm/alternative.h @@ -6,8 +6,6 @@ #ifndef __ASM_ALTERNATIVE_H #define __ASM_ALTERNATIVE_H -#define ERRATA_STRING_LENGTH_MAX 32 - #include #ifndef __ASSEMBLY__ @@ -15,10 +13,14 @@ #ifdef CONFIG_RISCV_ALTERNATIVE #include +#include #include #include #include +#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p) +#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p) + #define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */ #define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */ #define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */ @@ -28,6 +30,7 @@ #define ALT_OLD_PTR(a) __ALT_PTR(a, old_offset) #define ALT_ALT_PTR(a) __ALT_PTR(a, alt_offset) +void probe_vendor_features(unsigned int cpu); void __init apply_boot_alternatives(void); void __init apply_early_boot_alternatives(void); void apply_module_alternatives(void *start, size_t length); @@ -38,14 +41,9 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, struct alt_entry { s32 old_offset; /* offset relative to original instruction or data */ s32 alt_offset; /* offset relative to replacement instruction or data */ - u16 vendor_id; /* cpu vendor id */ + u16 vendor_id; /* CPU vendor ID */ u16 alt_len; /* The replacement size */ - u32 errata_id; /* The errata id */ -}; - -struct errata_checkfunc_id { - unsigned long vendor_id; - bool (*func)(struct alt_entry *alt); + u32 patch_id; /* The patch ID (erratum ID or cpufeature ID) */ }; void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, @@ -55,11 +53,15 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned long archid, unsigned long impid, unsigned int stage); +void thead_feature_probe_func(unsigned int cpu, unsigned long archid, + unsigned long impid); + void riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned int stage); #else /* CONFIG_RISCV_ALTERNATIVE */ +static inline void probe_vendor_features(unsigned int cpu) { } static inline void apply_boot_alternatives(void) { } static inline void apply_early_boot_alternatives(void) { } static inline void apply_module_alternatives(void *start, size_t length) { } diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h index ef386fcf3939..61ba8ed43d8f 100644 --- a/arch/riscv/include/asm/asm-prototypes.h +++ b/arch/riscv/include/asm/asm-prototypes.h @@ -27,5 +27,7 @@ DECLARE_DO_ERROR_INFO(do_trap_break); asmlinkage unsigned long get_overflow_stack(void); asmlinkage void handle_bad_stack(struct pt_regs *regs); +asmlinkage void do_page_fault(struct pt_regs *regs); +asmlinkage void do_irq(struct pt_regs *regs); #endif /* _ASM_RISCV_PROTOTYPES_H */ diff --git a/arch/riscv/include/asm/asm.h b/arch/riscv/include/asm/asm.h index 816e753de636..114bbadaef41 100644 --- a/arch/riscv/include/asm/asm.h +++ b/arch/riscv/include/asm/asm.h @@ -69,6 +69,7 @@ #endif #ifdef __ASSEMBLY__ +#include /* Common assembly source macros */ @@ -81,6 +82,66 @@ .endr .endm + /* save all GPs except x1 ~ x5 */ + .macro save_from_x6_to_x31 + REG_S x6, PT_T1(sp) + REG_S x7, PT_T2(sp) + REG_S x8, PT_S0(sp) + REG_S x9, PT_S1(sp) + REG_S x10, PT_A0(sp) + REG_S x11, PT_A1(sp) + REG_S x12, PT_A2(sp) + REG_S x13, PT_A3(sp) + REG_S x14, PT_A4(sp) + REG_S x15, PT_A5(sp) + REG_S x16, PT_A6(sp) + REG_S x17, PT_A7(sp) + REG_S x18, PT_S2(sp) + REG_S x19, PT_S3(sp) + REG_S x20, PT_S4(sp) + REG_S x21, PT_S5(sp) + REG_S x22, PT_S6(sp) + REG_S x23, PT_S7(sp) + REG_S x24, PT_S8(sp) + REG_S x25, PT_S9(sp) + REG_S x26, PT_S10(sp) + REG_S x27, PT_S11(sp) + REG_S x28, PT_T3(sp) + REG_S x29, PT_T4(sp) + REG_S x30, PT_T5(sp) + REG_S x31, PT_T6(sp) + .endm + + /* restore all GPs except x1 ~ x5 */ + .macro restore_from_x6_to_x31 + REG_L x6, PT_T1(sp) + REG_L x7, PT_T2(sp) + REG_L x8, PT_S0(sp) + REG_L x9, PT_S1(sp) + REG_L x10, PT_A0(sp) + REG_L x11, PT_A1(sp) + REG_L x12, PT_A2(sp) + REG_L x13, PT_A3(sp) + REG_L x14, PT_A4(sp) + REG_L x15, PT_A5(sp) + REG_L x16, PT_A6(sp) + REG_L x17, PT_A7(sp) + REG_L x18, PT_S2(sp) + REG_L x19, PT_S3(sp) + REG_L x20, PT_S4(sp) + REG_L x21, PT_S5(sp) + REG_L x22, PT_S6(sp) + REG_L x23, PT_S7(sp) + REG_L x24, PT_S8(sp) + REG_L x25, PT_S9(sp) + REG_L x26, PT_S10(sp) + REG_L x27, PT_S11(sp) + REG_L x28, PT_T3(sp) + REG_L x29, PT_T4(sp) + REG_L x30, PT_T5(sp) + REG_L x31, PT_T6(sp) + .endm + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_ASM_H */ diff --git a/arch/riscv/include/asm/assembler.h b/arch/riscv/include/asm/assembler.h new file mode 100644 index 000000000000..44b1457d3e95 --- /dev/null +++ b/arch/riscv/include/asm/assembler.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * + * Author: Jee Heng Sia + */ + +#ifndef __ASSEMBLY__ +#error "Only include this from assembly code" +#endif + +#ifndef __ASM_ASSEMBLER_H +#define __ASM_ASSEMBLER_H + +#include +#include +#include + +/* + * suspend_restore_csrs - restore CSRs + */ + .macro suspend_restore_csrs + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) + csrw CSR_EPC, t0 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) + csrw CSR_STATUS, t0 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) + csrw CSR_TVAL, t0 + REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) + csrw CSR_CAUSE, t0 + .endm + +/* + * suspend_restore_regs - Restore registers (except A0 and T0-T6) + */ + .macro suspend_restore_regs + REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) + REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) + REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) + REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) + REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) + REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) + REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) + REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) + REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) + REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) + REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) + REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) + REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) + REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) + REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) + REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) + REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) + REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) + REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) + REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) + REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) + REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) + REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) + .endm + +/* + * copy_page - copy 1 page (4KB) of data from source to destination + * @a0 - destination + * @a1 - source + */ + .macro copy_page a0, a1 + lui a2, 0x1 + add a2, a2, a0 +1 : + REG_L t0, 0(a1) + REG_L t1, SZREG(a1) + + REG_S t0, 0(a0) + REG_S t1, SZREG(a0) + + addi a0, a0, 2 * SZREG + addi a1, a1, 2 * SZREG + bne a2, a0, 1b + .endm + +#endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h index 0dfe9d857a76..bba472928b53 100644 --- a/arch/riscv/include/asm/atomic.h +++ b/arch/riscv/include/asm/atomic.h @@ -261,7 +261,7 @@ c_t arch_atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n) \ static __always_inline \ c_t arch_atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n) \ { \ - return __xchg(&(v->counter), n, size); \ + return __arch_xchg(&(v->counter), n, size); \ } \ static __always_inline \ c_t arch_atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v, \ diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 03e3b95ae6da..8091b8bf4883 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -50,7 +50,8 @@ void flush_icache_mm(struct mm_struct *mm, bool local); #endif /* CONFIG_SMP */ extern unsigned int riscv_cbom_block_size; -void riscv_init_cbom_blocksize(void); +extern unsigned int riscv_cboz_block_size; +void riscv_init_cbo_blocksizes(void); #ifdef CONFIG_RISCV_DMA_NONCOHERENT void riscv_noncoherent_supported(void); diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 12debce235e5..2f4726d3cfcc 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -114,7 +114,7 @@ _x_, sizeof(*(ptr))); \ }) -#define __xchg(ptr, new, size) \ +#define __arch_xchg(ptr, new, size) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ __typeof__(new) __new = (new); \ @@ -143,7 +143,7 @@ #define arch_xchg(ptr, x) \ ({ \ __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \ + (__typeof__(*(ptr))) __arch_xchg((ptr), _x_, sizeof(*(ptr))); \ }) #define xchg32(ptr, x) \ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h new file mode 100644 index 000000000000..808d5403f2ac --- /dev/null +++ b/arch/riscv/include/asm/cpufeature.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2022-2023 Rivos, Inc + */ + +#ifndef _ASM_CPUFEATURE_H +#define _ASM_CPUFEATURE_H + +/* + * These are probed via a device_initcall(), via either the SBI or directly + * from the corresponding CSRs. + */ +struct riscv_cpuinfo { + unsigned long mvendorid; + unsigned long marchid; + unsigned long mimpid; +}; + +DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); + +DECLARE_PER_CPU(long, misaligned_access_speed); + +#endif diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 0e571f6483d9..b6acb7ed115f 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -7,7 +7,7 @@ #define _ASM_RISCV_CSR_H #include -#include +#include /* Status register flags */ #define SR_SIE _AC(0x00000002, UL) /* Supervisor Interrupt Enable */ @@ -40,7 +40,6 @@ #define SR_UXL _AC(0x300000000, UL) /* XLEN mask for U-mode */ #define SR_UXL_32 _AC(0x100000000, UL) /* XLEN = 32 for U-mode */ #define SR_UXL_64 _AC(0x200000000, UL) /* XLEN = 64 for U-mode */ -#define SR_UXL_SHIFT 32 #endif /* SATP flags */ @@ -73,7 +72,10 @@ #define IRQ_S_EXT 9 #define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 +#define IRQ_S_GEXT 12 #define IRQ_PMU_OVF 13 +#define IRQ_LOCAL_MAX (IRQ_PMU_OVF + 1) +#define IRQ_LOCAL_MASK GENMASK((IRQ_LOCAL_MAX - 1), 0) /* Exception causes */ #define EXC_INST_MISALIGNED 0 @@ -128,25 +130,25 @@ #define HGATP32_MODE_SHIFT 31 #define HGATP32_VMID_SHIFT 22 -#define HGATP32_VMID_MASK _AC(0x1FC00000, UL) -#define HGATP32_PPN _AC(0x003FFFFF, UL) +#define HGATP32_VMID GENMASK(28, 22) +#define HGATP32_PPN GENMASK(21, 0) #define HGATP64_MODE_SHIFT 60 #define HGATP64_VMID_SHIFT 44 -#define HGATP64_VMID_MASK _AC(0x03FFF00000000000, UL) -#define HGATP64_PPN _AC(0x00000FFFFFFFFFFF, UL) +#define HGATP64_VMID GENMASK(57, 44) +#define HGATP64_PPN GENMASK(43, 0) #define HGATP_PAGE_SHIFT 12 #ifdef CONFIG_64BIT #define HGATP_PPN HGATP64_PPN #define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT -#define HGATP_VMID_MASK HGATP64_VMID_MASK +#define HGATP_VMID HGATP64_VMID #define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT #else #define HGATP_PPN HGATP32_PPN #define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT -#define HGATP_VMID_MASK HGATP32_VMID_MASK +#define HGATP_VMID HGATP32_VMID #define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT #endif @@ -156,6 +158,27 @@ (_AC(1, UL) << IRQ_S_TIMER) | \ (_AC(1, UL) << IRQ_S_EXT)) +/* AIA CSR bits */ +#define TOPI_IID_SHIFT 16 +#define TOPI_IID_MASK GENMASK(11, 0) +#define TOPI_IPRIO_MASK GENMASK(7, 0) +#define TOPI_IPRIO_BITS 8 + +#define TOPEI_ID_SHIFT 16 +#define TOPEI_ID_MASK GENMASK(10, 0) +#define TOPEI_PRIO_MASK GENMASK(10, 0) + +#define ISELECT_IPRIO0 0x30 +#define ISELECT_IPRIO15 0x3f +#define ISELECT_MASK GENMASK(8, 0) + +#define HVICTL_VTI BIT(30) +#define HVICTL_IID GENMASK(27, 16) +#define HVICTL_IID_SHIFT 16 +#define HVICTL_DPR BIT(9) +#define HVICTL_IPRIOM BIT(8) +#define HVICTL_IPRIO GENMASK(7, 0) + /* xENVCFG flags */ #define ENVCFG_STCE (_AC(1, ULL) << 63) #define ENVCFG_PBMTE (_AC(1, ULL) << 62) @@ -250,6 +273,18 @@ #define CSR_STIMECMP 0x14D #define CSR_STIMECMPH 0x15D +/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_SISELECT 0x150 +#define CSR_SIREG 0x151 + +/* Supervisor-Level Interrupts (AIA) */ +#define CSR_STOPEI 0x15c +#define CSR_STOPI 0xdb0 + +/* Supervisor-Level High-Half CSRs (AIA) */ +#define CSR_SIEH 0x114 +#define CSR_SIPH 0x154 + #define CSR_VSSTATUS 0x200 #define CSR_VSIE 0x204 #define CSR_VSTVEC 0x205 @@ -279,8 +314,32 @@ #define CSR_HGATP 0x680 #define CSR_HGEIP 0xe12 +/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ +#define CSR_HVIEN 0x608 +#define CSR_HVICTL 0x609 +#define CSR_HVIPRIO1 0x646 +#define CSR_HVIPRIO2 0x647 + +/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */ +#define CSR_VSISELECT 0x250 +#define CSR_VSIREG 0x251 + +/* VS-Level Interrupts (H-extension with AIA) */ +#define CSR_VSTOPEI 0x25c +#define CSR_VSTOPI 0xeb0 + +/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ +#define CSR_HIDELEGH 0x613 +#define CSR_HVIENH 0x618 +#define CSR_HVIPH 0x655 +#define CSR_HVIPRIO1H 0x656 +#define CSR_HVIPRIO2H 0x657 +#define CSR_VSIEH 0x214 +#define CSR_VSIPH 0x254 + #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 +#define CSR_MIDELEG 0x303 #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MENVCFG 0x30a @@ -297,6 +356,25 @@ #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 +/* Machine-Level Window to Indirectly Accessed Registers (AIA) */ +#define CSR_MISELECT 0x350 +#define CSR_MIREG 0x351 + +/* Machine-Level Interrupts (AIA) */ +#define CSR_MTOPEI 0x35c +#define CSR_MTOPI 0xfb0 + +/* Virtual Interrupts for Supervisor Level (AIA) */ +#define CSR_MVIEN 0x308 +#define CSR_MVIP 0x309 + +/* Machine-Level High-Half CSRs (AIA) */ +#define CSR_MIDELEGH 0x313 +#define CSR_MIEH 0x314 +#define CSR_MVIENH 0x318 +#define CSR_MVIPH 0x319 +#define CSR_MIPH 0x354 + #ifdef CONFIG_RISCV_M_MODE # define CSR_STATUS CSR_MSTATUS # define CSR_IE CSR_MIE @@ -307,6 +385,13 @@ # define CSR_TVAL CSR_MTVAL # define CSR_IP CSR_MIP +# define CSR_IEH CSR_MIEH +# define CSR_ISELECT CSR_MISELECT +# define CSR_IREG CSR_MIREG +# define CSR_IPH CSR_MIPH +# define CSR_TOPEI CSR_MTOPEI +# define CSR_TOPI CSR_MTOPI + # define SR_IE SR_MIE # define SR_PIE SR_MPIE # define SR_PP SR_MPP @@ -324,6 +409,13 @@ # define CSR_TVAL CSR_STVAL # define CSR_IP CSR_SIP +# define CSR_IEH CSR_SIEH +# define CSR_ISELECT CSR_SISELECT +# define CSR_IREG CSR_SIREG +# define CSR_IPH CSR_SIPH +# define CSR_TOPEI CSR_STOPEI +# define CSR_TOPI CSR_STOPI + # define SR_IE SR_SIE # define SR_PIE SR_SPIE # define SR_PP SR_SPP diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h new file mode 100644 index 000000000000..6e4dee49d84b --- /dev/null +++ b/arch/riscv/include/asm/entry-common.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_ENTRY_COMMON_H +#define _ASM_RISCV_ENTRY_COMMON_H + +#include + +void handle_page_fault(struct pt_regs *regs); +void handle_break(struct pt_regs *regs); + +#endif /* _ASM_RISCV_ENTRY_COMMON_H */ diff --git a/arch/riscv/include/asm/hugetlb.h b/arch/riscv/include/asm/hugetlb.h index ec19d6afc896..ce1ebda1a49a 100644 --- a/arch/riscv/include/asm/hugetlb.h +++ b/arch/riscv/include/asm/hugetlb.h @@ -2,7 +2,6 @@ #ifndef _ASM_RISCV_HUGETLB_H #define _ASM_RISCV_HUGETLB_H -#include #include static inline void arch_clear_hugepage_flags(struct page *page) @@ -11,4 +10,40 @@ static inline void arch_clear_hugepage_flags(struct page *page) } #define arch_clear_hugepage_flags arch_clear_hugepage_flags +#ifdef CONFIG_RISCV_ISA_SVNAPOT +#define __HAVE_ARCH_HUGE_PTE_CLEAR +void huge_pte_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, unsigned long sz); + +#define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT +void set_huge_pte_at(struct mm_struct *mm, + unsigned long addr, pte_t *ptep, pte_t pte); + +#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR +pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep); + +#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH +pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep); + +#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT +void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep); + +#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS +int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty); + +#define __HAVE_ARCH_HUGE_PTEP_GET +pte_t huge_ptep_get(pte_t *ptep); + +pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags); +#define arch_make_huge_pte arch_make_huge_pte + +#endif /*CONFIG_RISCV_ISA_SVNAPOT*/ + +#include + #endif /* _ASM_RISCV_HUGETLB_H */ diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 6263a0de1c6a..e0c40a4c63d5 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -42,10 +42,20 @@ #define RISCV_ISA_EXT_ZBB 30 #define RISCV_ISA_EXT_ZICBOM 31 #define RISCV_ISA_EXT_ZIHINTPAUSE 32 +#define RISCV_ISA_EXT_SVNAPOT 33 +#define RISCV_ISA_EXT_ZICBOZ 34 +#define RISCV_ISA_EXT_SMAIA 35 +#define RISCV_ISA_EXT_SSAIA 36 #define RISCV_ISA_EXT_MAX 64 #define RISCV_ISA_EXT_NAME_LEN_MAX 32 +#ifdef CONFIG_RISCV_M_MODE +#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA +#else +#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SSAIA +#endif + #ifndef __ASSEMBLY__ #include diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h new file mode 100644 index 000000000000..78936f4ff513 --- /dev/null +++ b/arch/riscv/include/asm/hwprobe.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright 2023 Rivos, Inc + */ + +#ifndef _ASM_HWPROBE_H +#define _ASM_HWPROBE_H + +#include + +#define RISCV_HWPROBE_MAX_KEY 5 + +#endif diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h index e01ab51f50d2..6960beb75f32 100644 --- a/arch/riscv/include/asm/insn-def.h +++ b/arch/riscv/include/asm/insn-def.h @@ -192,4 +192,8 @@ INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \ RS1(base), SIMM12(2)) +#define CBO_zero(base) \ + INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \ + RS1(base), SIMM12(4)) + #endif /* __ASM_INSN_DEF_H */ diff --git a/arch/riscv/include/asm/kvm_aia.h b/arch/riscv/include/asm/kvm_aia.h new file mode 100644 index 000000000000..1de0717112e5 --- /dev/null +++ b/arch/riscv/include/asm/kvm_aia.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * Copyright (C) 2022 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#ifndef __KVM_RISCV_AIA_H +#define __KVM_RISCV_AIA_H + +#include +#include +#include + +struct kvm_aia { + /* In-kernel irqchip created */ + bool in_kernel; + + /* In-kernel irqchip initialized */ + bool initialized; +}; + +struct kvm_vcpu_aia_csr { + unsigned long vsiselect; + unsigned long hviprio1; + unsigned long hviprio2; + unsigned long vsieh; + unsigned long hviph; + unsigned long hviprio1h; + unsigned long hviprio2h; +}; + +struct kvm_vcpu_aia { + /* CPU AIA CSR context of Guest VCPU */ + struct kvm_vcpu_aia_csr guest_csr; + + /* CPU AIA CSR context upon Guest VCPU reset */ + struct kvm_vcpu_aia_csr guest_reset_csr; +}; + +#define kvm_riscv_aia_initialized(k) ((k)->arch.aia.initialized) + +#define irqchip_in_kernel(k) ((k)->arch.aia.in_kernel) + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available); +#define kvm_riscv_aia_available() \ + static_branch_unlikely(&kvm_riscv_aia_available) + +#define KVM_RISCV_AIA_IMSIC_TOPEI (ISELECT_MASK + 1) +static inline int kvm_riscv_vcpu_aia_imsic_rmw(struct kvm_vcpu *vcpu, + unsigned long isel, + unsigned long *val, + unsigned long new_val, + unsigned long wr_mask) +{ + return 0; +} + +#ifdef CONFIG_32BIT +void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu); +#else +static inline void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu) +{ +} +static inline void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) +{ +} +#endif +bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask); + +void kvm_riscv_vcpu_aia_update_hvip(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_aia_load(struct kvm_vcpu *vcpu, int cpu); +void kvm_riscv_vcpu_aia_put(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *out_val); +int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long val); + +int kvm_riscv_vcpu_aia_rmw_topei(struct kvm_vcpu *vcpu, + unsigned int csr_num, + unsigned long *val, + unsigned long new_val, + unsigned long wr_mask); +int kvm_riscv_vcpu_aia_rmw_ireg(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask); +#define KVM_RISCV_VCPU_AIA_CSR_FUNCS \ +{ .base = CSR_SIREG, .count = 1, .func = kvm_riscv_vcpu_aia_rmw_ireg }, \ +{ .base = CSR_STOPEI, .count = 1, .func = kvm_riscv_vcpu_aia_rmw_topei }, + +static inline int kvm_riscv_vcpu_aia_update(struct kvm_vcpu *vcpu) +{ + return 1; +} + +static inline void kvm_riscv_vcpu_aia_reset(struct kvm_vcpu *vcpu) +{ +} + +static inline int kvm_riscv_vcpu_aia_init(struct kvm_vcpu *vcpu) +{ + return 0; +} + +static inline void kvm_riscv_vcpu_aia_deinit(struct kvm_vcpu *vcpu) +{ +} + +static inline void kvm_riscv_aia_init_vm(struct kvm *kvm) +{ +} + +static inline void kvm_riscv_aia_destroy_vm(struct kvm *kvm) +{ +} + +void kvm_riscv_aia_enable(void); +void kvm_riscv_aia_disable(void); +int kvm_riscv_aia_init(void); +void kvm_riscv_aia_exit(void); + +#endif diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index cc7da66ee0c0..ee0acccb1d3b 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,9 @@ struct kvm_arch { /* Guest Timer */ struct kvm_guest_timer timer; + + /* AIA Guest/VM context */ + struct kvm_aia aia; }; struct kvm_cpu_trap { @@ -200,8 +204,9 @@ struct kvm_vcpu_arch { * in irqs_pending. Our approach is modeled around multiple producer * and single consumer problem where the consumer is the VCPU itself. */ - unsigned long irqs_pending; - unsigned long irqs_pending_mask; +#define KVM_RISCV_VCPU_NR_IRQS 64 + DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); /* VCPU Timer */ struct kvm_vcpu_timer timer; @@ -221,6 +226,9 @@ struct kvm_vcpu_arch { /* SBI context */ struct kvm_vcpu_sbi_context sbi_context; + /* AIA VCPU context */ + struct kvm_vcpu_aia aia_context; + /* Cache pages needed to program page tables with spinlock held */ struct kvm_mmu_memory_cache mmu_page_cache; @@ -327,7 +335,7 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq); int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq); void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu); -bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask); +bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask); void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 8425556af7d1..4278125a38a5 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -16,6 +16,7 @@ struct kvm_vcpu_sbi_context { int return_handled; + bool extension_disabled[KVM_RISCV_SBI_EXT_MAX]; }; struct kvm_vcpu_sbi_return { @@ -45,7 +46,12 @@ void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu, struct kvm_run *run, u32 type, u64 flags); int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run); -const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(unsigned long extid); +int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( + struct kvm_vcpu *vcpu, unsigned long extid); int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run); #ifdef CONFIG_RISCV_SBI_V01 diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 7fed7c431928..b55ba20903ec 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -16,11 +16,6 @@ #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE - 1)) -#ifdef CONFIG_64BIT -#define HUGE_MAX_HSTATE 2 -#else -#define HUGE_MAX_HSTATE 1 -#endif #define HPAGE_SHIFT PMD_SHIFT #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1)) @@ -49,10 +44,14 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_RISCV_ISA_ZICBOZ +void clear_page(void *page); +#else #define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE) +#endif #define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) -#define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE) +#define clear_user_page(pgaddr, vaddr, page) clear_page(pgaddr) #define copy_user_page(vto, vfrom, vaddr, topg) \ memcpy((vto), (vfrom), PAGE_SIZE) @@ -90,9 +89,16 @@ typedef struct page *pgtable_t; #define PTE_FMT "%08lx" #endif +#ifdef CONFIG_64BIT +/* + * We override this value as its generic definition uses __pa too early in + * the boot process (before kernel_map.va_pa_offset is set). + */ +#define MIN_MEMBLOCK_ADDR 0 +#endif + #ifdef CONFIG_MMU -extern unsigned long riscv_pfn_base; -#define ARCH_PFN_OFFSET (riscv_pfn_base) +#define ARCH_PFN_OFFSET (PFN_DOWN((unsigned long)phys_ram_base)) #else #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) #endif /* CONFIG_MMU */ @@ -122,7 +128,11 @@ extern phys_addr_t phys_ram_base; #define is_linear_mapping(x) \ ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE)) +#ifndef CONFIG_DEBUG_VIRTUAL #define linear_mapping_pa_to_va(x) ((void *)((unsigned long)(x) + kernel_map.va_pa_offset)) +#else +void *linear_mapping_pa_to_va(unsigned long x); +#endif #define kernel_mapping_pa_to_va(y) ({ \ unsigned long _y = (unsigned long)(y); \ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < phys_ram_base) ? \ @@ -131,7 +141,11 @@ extern phys_addr_t phys_ram_base; }) #define __pa_to_va_nodebug(x) linear_mapping_pa_to_va(x) +#ifndef CONFIG_DEBUG_VIRTUAL #define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset) +#else +phys_addr_t linear_mapping_va_to_pa(unsigned long x); +#endif #define kernel_mapping_va_to_pa(y) ({ \ unsigned long _y = (unsigned long)(y); \ (IS_ENABLED(CONFIG_XIP_KERNEL) && _y < kernel_map.virt_addr + XIP_OFFSET) ? \ diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index d42c901f9a97..665bbc9b2f84 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -10,4 +10,11 @@ #include #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs + +#define perf_arch_fetch_caller_regs(regs, __ip) { \ + (regs)->epc = (__ip); \ + (regs)->s0 = (unsigned long) __builtin_frame_address(0); \ + (regs)->sp = current_stack_pointer; \ + (regs)->status = SR_PP; \ +} #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 42a042c0e13e..7a5097202e15 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -78,6 +78,40 @@ typedef struct { */ #define _PAGE_PFN_MASK GENMASK(53, 10) +/* + * [63] Svnapot definitions: + * 0 Svnapot disabled + * 1 Svnapot enabled + */ +#define _PAGE_NAPOT_SHIFT 63 +#define _PAGE_NAPOT BIT(_PAGE_NAPOT_SHIFT) +/* + * Only 64KB (order 4) napot ptes supported. + */ +#define NAPOT_CONT_ORDER_BASE 4 +enum napot_cont_order { + NAPOT_CONT64KB_ORDER = NAPOT_CONT_ORDER_BASE, + NAPOT_ORDER_MAX, +}; + +#define for_each_napot_order(order) \ + for (order = NAPOT_CONT_ORDER_BASE; order < NAPOT_ORDER_MAX; order++) +#define for_each_napot_order_rev(order) \ + for (order = NAPOT_ORDER_MAX - 1; \ + order >= NAPOT_CONT_ORDER_BASE; order--) +#define napot_cont_order(val) (__builtin_ctzl((val.pte >> _PAGE_PFN_SHIFT) << 1)) + +#define napot_cont_shift(order) ((order) + PAGE_SHIFT) +#define napot_cont_size(order) BIT(napot_cont_shift(order)) +#define napot_cont_mask(order) (~(napot_cont_size(order) - 1UL)) +#define napot_pte_num(order) BIT(order) + +#ifdef CONFIG_RISCV_ISA_SVNAPOT +#define HUGE_MAX_HSTATE (2 + (NAPOT_ORDER_MAX - NAPOT_CONT_ORDER_BASE)) +#else +#define HUGE_MAX_HSTATE 2 +#endif + /* * [62:61] Svpbmt Memory Type definitions: * diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index f641837ccf31..2258b27173b0 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -268,10 +268,47 @@ static inline pte_t pud_pte(pud_t pud) return __pte(pud_val(pud)); } +#ifdef CONFIG_RISCV_ISA_SVNAPOT + +static __always_inline bool has_svnapot(void) +{ + return riscv_has_extension_likely(RISCV_ISA_EXT_SVNAPOT); +} + +static inline unsigned long pte_napot(pte_t pte) +{ + return pte_val(pte) & _PAGE_NAPOT; +} + +static inline pte_t pte_mknapot(pte_t pte, unsigned int order) +{ + int pos = order - 1 + _PAGE_PFN_SHIFT; + unsigned long napot_bit = BIT(pos); + unsigned long napot_mask = ~GENMASK(pos, _PAGE_PFN_SHIFT); + + return __pte((pte_val(pte) & napot_mask) | napot_bit | _PAGE_NAPOT); +} + +#else + +static __always_inline bool has_svnapot(void) { return false; } + +static inline unsigned long pte_napot(pte_t pte) +{ + return 0; +} + +#endif /* CONFIG_RISCV_ISA_SVNAPOT */ + /* Yields the page frame number (PFN) of a page table entry */ static inline unsigned long pte_pfn(pte_t pte) { - return __page_val_to_pfn(pte_val(pte)); + unsigned long res = __page_val_to_pfn(pte_val(pte)); + + if (has_svnapot() && pte_napot(pte)) + res = res & (res - 1UL); + + return res; } #define pte_page(x) pfn_to_page(pte_pfn(x)) diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 6ecd461129d2..b5b0adcc85c1 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -53,6 +53,9 @@ struct pt_regs { unsigned long orig_a0; }; +#define PTRACE_SYSEMU 0x1f +#define PTRACE_SYSEMU_SINGLESTEP 0x20 + #ifdef CONFIG_64BIT #define REG_FMT "%016lx" #else @@ -121,8 +124,6 @@ extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, unsigned long frame_pointer); -int do_syscall_trace_enter(struct pt_regs *regs); -void do_syscall_trace_exit(struct pt_regs *regs); /** * regs_get_register() - get register value from its offset @@ -172,6 +173,11 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs, return 0; } +static inline int regs_irqs_disabled(struct pt_regs *regs) +{ + return !(regs->status & SR_PIE); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index acab4410ef2a..5b4a1bf5f439 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -295,7 +295,7 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, unsigned long start, unsigned long size, unsigned long asid); -int sbi_probe_extension(int ext); +long sbi_probe_extension(int ext); /* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1(void) diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h index a2c14d4b3993..ec11001c3fe0 100644 --- a/arch/riscv/include/asm/set_memory.h +++ b/arch/riscv/include/asm/set_memory.h @@ -56,4 +56,7 @@ bool kernel_page_present(struct page *page); #define SECTION_ALIGN L1_CACHE_BYTES #endif /* CONFIG_STRICT_KERNEL_RWX */ +#define PECOFF_SECTION_ALIGNMENT 0x1000 +#define PECOFF_FILE_ALIGNMENT 0x200 + #endif /* _ASM_RISCV_SET_MEMORY_H */ diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h index 3450c1912afd..f7e8ef2418b9 100644 --- a/arch/riscv/include/asm/stacktrace.h +++ b/arch/riscv/include/asm/stacktrace.h @@ -16,4 +16,9 @@ extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *re extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task, const char *loglvl); +static inline bool on_thread_stack(void) +{ + return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); +} + #endif /* _ASM_RISCV_STACKTRACE_H */ diff --git a/arch/riscv/include/asm/suspend.h b/arch/riscv/include/asm/suspend.h index 8be391c2aecb..02f87867389a 100644 --- a/arch/riscv/include/asm/suspend.h +++ b/arch/riscv/include/asm/suspend.h @@ -21,6 +21,11 @@ struct suspend_context { #endif }; +/* + * Used by hibernation core and cleared during resume sequence + */ +extern int in_suspend; + /* Low-level CPU suspend entry function */ int __cpu_suspend_enter(struct suspend_context *context); @@ -33,4 +38,21 @@ int cpu_suspend(unsigned long arg, /* Low-level CPU resume entry function */ int __cpu_resume_enter(unsigned long hartid, unsigned long context); +/* Used to save and restore the CSRs */ +void suspend_save_csrs(struct suspend_context *context); +void suspend_restore_csrs(struct suspend_context *context); + +/* Low-level API to support hibernation */ +int swsusp_arch_suspend(void); +int swsusp_arch_resume(void); +int arch_hibernation_header_save(void *addr, unsigned int max_size); +int arch_hibernation_header_restore(void *addr); +int __hibernate_cpu_resume(void); + +/* Used to resume on the CPU we hibernated on */ +int hibernate_resume_nonboot_cpu_disable(void); + +asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp, + unsigned long cpu_resume); +asmlinkage int hibernate_core_restore_code(void); #endif diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index 384a63b86420..0148c6bd9675 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h @@ -10,6 +10,7 @@ #ifndef _ASM_RISCV_SYSCALL_H #define _ASM_RISCV_SYSCALL_H +#include #include #include #include @@ -74,5 +75,29 @@ static inline int syscall_get_arch(struct task_struct *task) #endif } +typedef long (*syscall_t)(ulong, ulong, ulong, ulong, ulong, ulong, ulong); +static inline void syscall_handler(struct pt_regs *regs, ulong syscall) +{ + syscall_t fn; + +#ifdef CONFIG_COMPAT + if ((regs->status & SR_UXL) == SR_UXL_32) + fn = compat_sys_call_table[syscall]; + else +#endif + fn = sys_call_table[syscall]; + + regs->a0 = fn(regs->orig_a0, regs->a1, regs->a2, + regs->a3, regs->a4, regs->a5, regs->a6); +} + +static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs) +{ + return false; +} + asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t); + +asmlinkage long sys_riscv_hwprobe(struct riscv_hwprobe *, size_t, size_t, + unsigned long *, unsigned int); #endif /* _ASM_RISCV_SYSCALL_H */ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index f704c8dd57e0..e0d202134b44 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -67,6 +67,7 @@ struct thread_info { long kernel_sp; /* Kernel stack pointer */ long user_sp; /* User stack pointer */ int cpu; + unsigned long syscall_work; /* SYSCALL_WORK_ flags */ }; /* @@ -89,26 +90,18 @@ struct thread_info { * - pending work-to-be-done flags are in lowest half-word * - other flags in upper half-word(s) */ -#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ -#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ -#define TIF_SYSCALL_AUDIT 7 /* syscall auditing */ -#define TIF_SECCOMP 8 /* syscall secure computing */ #define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */ #define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */ #define TIF_32BIT 11 /* compat-mode 32bit process */ -#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) -#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) -#define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #define _TIF_UPROBE (1 << TIF_UPROBE) @@ -116,8 +109,4 @@ struct thread_info { (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \ _TIF_NOTIFY_SIGNAL | _TIF_UPROBE) -#define _TIF_SYSCALL_WORK \ - (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT | \ - _TIF_SECCOMP) - #endif /* _ASM_RISCV_THREAD_INFO_H */ diff --git a/arch/riscv/include/asm/topology.h b/arch/riscv/include/asm/topology.h new file mode 100644 index 000000000000..e316ab3b77f3 --- /dev/null +++ b/arch/riscv/include/asm/topology.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_TOPOLOGY_H +#define _ASM_RISCV_TOPOLOGY_H + +#include + +/* Replace task scheduler's default frequency-invariant accounting */ +#define arch_scale_freq_tick topology_scale_freq_tick +#define arch_set_freq_scale topology_set_freq_scale +#define arch_scale_freq_capacity topology_get_freq_scale +#define arch_scale_freq_invariant topology_scale_freq_invariant + +/* Replace task scheduler's default cpu-invariant accounting */ +#define arch_scale_cpu_capacity topology_get_cpu_scale + +/* Enable topology flag updates */ +#define arch_update_cpu_topology topology_update_cpu_topology + +#include + +#endif /* _ASM_RISCV_TOPOLOGY_H */ diff --git a/arch/riscv/include/asm/vdso/data.h b/arch/riscv/include/asm/vdso/data.h new file mode 100644 index 000000000000..dc2f76f58b76 --- /dev/null +++ b/arch/riscv/include/asm/vdso/data.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __RISCV_ASM_VDSO_DATA_H +#define __RISCV_ASM_VDSO_DATA_H + +#include +#include +#include + +struct arch_vdso_data { + /* Stash static answers to the hwprobe queries when all CPUs are selected. */ + __u64 all_cpu_hwprobe_values[RISCV_HWPROBE_MAX_KEY + 1]; + + /* Boolean indicating all CPUs have the same static hwprobe values. */ + __u8 homogeneous_cpus; +}; + +#endif /* __RISCV_ASM_VDSO_DATA_H */ diff --git a/arch/riscv/include/asm/vdso/gettimeofday.h b/arch/riscv/include/asm/vdso/gettimeofday.h index 77d9c2f721c4..ba3283cf7acc 100644 --- a/arch/riscv/include/asm/vdso/gettimeofday.h +++ b/arch/riscv/include/asm/vdso/gettimeofday.h @@ -9,6 +9,12 @@ #include #include +/* + * 32-bit land is lacking generic time vsyscalls as well as the legacy 32-bit + * time syscalls like gettimeofday. Skip these definitions since on 32-bit. + */ +#ifdef CONFIG_GENERIC_TIME_VSYSCALL + #define VDSO_HAS_CLOCK_GETRES 1 static __always_inline @@ -60,6 +66,8 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) return ret; } +#endif /* CONFIG_GENERIC_TIME_VSYSCALL */ + static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, const struct vdso_data *vd) { diff --git a/arch/riscv/include/asm/vmalloc.h b/arch/riscv/include/asm/vmalloc.h index 48da5371f1e9..58d3e447f191 100644 --- a/arch/riscv/include/asm/vmalloc.h +++ b/arch/riscv/include/asm/vmalloc.h @@ -17,6 +17,65 @@ static inline bool arch_vmap_pmd_supported(pgprot_t prot) return true; } -#endif +#ifdef CONFIG_RISCV_ISA_SVNAPOT +#include +#define arch_vmap_pte_range_map_size arch_vmap_pte_range_map_size +static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr, unsigned long end, + u64 pfn, unsigned int max_page_shift) +{ + unsigned long map_size = PAGE_SIZE; + unsigned long size, order; + + if (!has_svnapot()) + return map_size; + + for_each_napot_order_rev(order) { + if (napot_cont_shift(order) > max_page_shift) + continue; + + size = napot_cont_size(order); + if (end - addr < size) + continue; + + if (!IS_ALIGNED(addr, size)) + continue; + + if (!IS_ALIGNED(PFN_PHYS(pfn), size)) + continue; + + map_size = size; + break; + } + + return map_size; +} + +#define arch_vmap_pte_supported_shift arch_vmap_pte_supported_shift +static inline int arch_vmap_pte_supported_shift(unsigned long size) +{ + int shift = PAGE_SHIFT; + unsigned long order; + + if (!has_svnapot()) + return shift; + + WARN_ON_ONCE(size >= PMD_SIZE); + + for_each_napot_order_rev(order) { + if (napot_cont_size(order) > size) + continue; + + if (!IS_ALIGNED(size, napot_cont_size(order))) + continue; + + shift = napot_cont_shift(order); + break; + } + + return shift; +} + +#endif /* CONFIG_RISCV_ISA_SVNAPOT */ +#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ #endif /* _ASM_RISCV_VMALLOC_H */ diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h new file mode 100644 index 000000000000..8d745a4ad8a2 --- /dev/null +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright 2023 Rivos, Inc + */ + +#ifndef _UAPI_ASM_HWPROBE_H +#define _UAPI_ASM_HWPROBE_H + +#include + +/* + * Interface for probing hardware capabilities from userspace, see + * Documentation/riscv/hwprobe.rst for more information. + */ +struct riscv_hwprobe { + __s64 key; + __u64 value; +}; + +#define RISCV_HWPROBE_KEY_MVENDORID 0 +#define RISCV_HWPROBE_KEY_MARCHID 1 +#define RISCV_HWPROBE_KEY_MIMPID 2 +#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3 +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#define RISCV_HWPROBE_IMA_FD (1 << 0) +#define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_KEY_CPUPERF_0 5 +#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) +#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) +#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) +#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) +#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) +#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ + +#endif diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 92af6f3f057c..f92790c9481a 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -12,6 +12,7 @@ #ifndef __ASSEMBLY__ #include +#include #include #define __KVM_HAVE_READONLY_MEM @@ -52,6 +53,7 @@ struct kvm_riscv_config { unsigned long mvendorid; unsigned long marchid; unsigned long mimpid; + unsigned long zicboz_block_size; }; /* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ @@ -64,7 +66,7 @@ struct kvm_riscv_core { #define KVM_RISCV_MODE_S 1 #define KVM_RISCV_MODE_U 0 -/* CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +/* General CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ struct kvm_riscv_csr { unsigned long sstatus; unsigned long sie; @@ -78,6 +80,17 @@ struct kvm_riscv_csr { unsigned long scounteren; }; +/* AIA CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +struct kvm_riscv_aia_csr { + unsigned long siselect; + unsigned long iprio1; + unsigned long iprio2; + unsigned long sieh; + unsigned long siph; + unsigned long iprio1h; + unsigned long iprio2h; +}; + /* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ struct kvm_riscv_timer { __u64 frequency; @@ -105,9 +118,29 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_SVINVAL, KVM_RISCV_ISA_EXT_ZIHINTPAUSE, KVM_RISCV_ISA_EXT_ZICBOM, + KVM_RISCV_ISA_EXT_ZICBOZ, + KVM_RISCV_ISA_EXT_ZBB, + KVM_RISCV_ISA_EXT_SSAIA, KVM_RISCV_ISA_EXT_MAX, }; +/* + * SBI extension IDs specific to KVM. This is not the same as the SBI + * extension IDs defined by the RISC-V SBI specification. + */ +enum KVM_RISCV_SBI_EXT_ID { + KVM_RISCV_SBI_EXT_V01 = 0, + KVM_RISCV_SBI_EXT_TIME, + KVM_RISCV_SBI_EXT_IPI, + KVM_RISCV_SBI_EXT_RFENCE, + KVM_RISCV_SBI_EXT_SRST, + KVM_RISCV_SBI_EXT_HSM, + KVM_RISCV_SBI_EXT_PMU, + KVM_RISCV_SBI_EXT_EXPERIMENTAL, + KVM_RISCV_SBI_EXT_VENDOR, + KVM_RISCV_SBI_EXT_MAX, +}; + /* Possible states for kvm_riscv_timer */ #define KVM_RISCV_TIMER_STATE_OFF 0 #define KVM_RISCV_TIMER_STATE_ON 1 @@ -118,6 +151,8 @@ enum KVM_RISCV_ISA_EXT_ID { /* If you need to interpret the index values, here is the key: */ #define KVM_REG_RISCV_TYPE_MASK 0x00000000FF000000 #define KVM_REG_RISCV_TYPE_SHIFT 24 +#define KVM_REG_RISCV_SUBTYPE_MASK 0x0000000000FF0000 +#define KVM_REG_RISCV_SUBTYPE_SHIFT 16 /* Config registers are mapped as type 1 */ #define KVM_REG_RISCV_CONFIG (0x01 << KVM_REG_RISCV_TYPE_SHIFT) @@ -131,8 +166,12 @@ enum KVM_RISCV_ISA_EXT_ID { /* Control and status registers are mapped as type 3 */ #define KVM_REG_RISCV_CSR (0x03 << KVM_REG_RISCV_TYPE_SHIFT) +#define KVM_REG_RISCV_CSR_GENERAL (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_CSR_AIA (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) #define KVM_REG_RISCV_CSR_REG(name) \ (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long)) +#define KVM_REG_RISCV_CSR_AIA_REG(name) \ + (offsetof(struct kvm_riscv_aia_csr, name) / sizeof(unsigned long)) /* Timer registers are mapped as type 4 */ #define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT) @@ -152,6 +191,18 @@ enum KVM_RISCV_ISA_EXT_ID { /* ISA Extension registers are mapped as type 7 */ #define KVM_REG_RISCV_ISA_EXT (0x07 << KVM_REG_RISCV_TYPE_SHIFT) +/* SBI extension registers are mapped as type 8 */ +#define KVM_REG_RISCV_SBI_EXT (0x08 << KVM_REG_RISCV_TYPE_SHIFT) +#define KVM_REG_RISCV_SBI_SINGLE (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_SBI_MULTI_EN (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_SBI_MULTI_DIS (0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_SBI_MULTI_REG(__ext_id) \ + ((__ext_id) / __BITS_PER_LONG) +#define KVM_REG_RISCV_SBI_MULTI_MASK(__ext_id) \ + (1UL << ((__ext_id) % __BITS_PER_LONG)) +#define KVM_REG_RISCV_SBI_MULTI_REG_LAST \ + KVM_REG_RISCV_SBI_MULTI_REG(KVM_RISCV_SBI_EXT_MAX - 1) + #endif #endif /* __LINUX_KVM_RISCV_H */ diff --git a/arch/riscv/include/uapi/asm/unistd.h b/arch/riscv/include/uapi/asm/unistd.h index 73d7cdd2ec49..950ab3fd4409 100644 --- a/arch/riscv/include/uapi/asm/unistd.h +++ b/arch/riscv/include/uapi/asm/unistd.h @@ -43,3 +43,12 @@ #define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) #endif __SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) + +/* + * Allows userspace to query the kernel for CPU architecture and + * microarchitecture details across a given set of CPUs. + */ +#ifndef __NR_riscv_hwprobe +#define __NR_riscv_hwprobe (__NR_arch_specific_syscall + 14) +#endif +__SYSCALL(__NR_riscv_hwprobe, sys_riscv_hwprobe) diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 67f542be1bea..153864e4f399 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -9,6 +9,7 @@ CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_sbi.o = $(CC_FLAGS_FTRACE) endif CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,) +CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,) ifdef CONFIG_KEXEC AFLAGS_kexec_relocate.o := -mcmodel=medany $(call cc-option,-mno-relax) @@ -22,6 +23,10 @@ ifdef CONFIG_FTRACE CFLAGS_REMOVE_alternative.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_cpufeature.o = $(CC_FLAGS_FTRACE) endif +ifdef CONFIG_RELOCATABLE +CFLAGS_alternative.o += -fno-pie +CFLAGS_cpufeature.o += -fno-pie +endif ifdef CONFIG_KASAN KASAN_SANITIZE_alternative.o := n KASAN_SANITIZE_cpufeature.o := n @@ -64,12 +69,11 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o +obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o -obj-$(CONFIG_TRACE_IRQFLAGS) += trace_irq.o - obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o obj-$(CONFIG_RISCV_SBI) += sbi.o @@ -90,3 +94,5 @@ obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_COMPAT) += compat_syscall_table.o obj-$(CONFIG_COMPAT) += compat_signal.o obj-$(CONFIG_COMPAT) += compat_vdso/ + +obj-$(CONFIG_64BIT) += pi/ diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c index 2354c69dc7d1..6b75788c18e6 100644 --- a/arch/riscv/kernel/alternative.c +++ b/arch/riscv/kernel/alternative.c @@ -27,9 +27,11 @@ struct cpu_manufacturer_info_t { void (*patch_func)(struct alt_entry *begin, struct alt_entry *end, unsigned long archid, unsigned long impid, unsigned int stage); + void (*feature_probe_func)(unsigned int cpu, unsigned long archid, + unsigned long impid); }; -static void __init_or_module riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info) +static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info) { #ifdef CONFIG_RISCV_M_MODE cpu_mfr_info->vendor_id = csr_read(CSR_MVENDORID); @@ -41,6 +43,7 @@ static void __init_or_module riscv_fill_cpu_mfr_info(struct cpu_manufacturer_inf cpu_mfr_info->imp_id = sbi_get_mimpid(); #endif + cpu_mfr_info->feature_probe_func = NULL; switch (cpu_mfr_info->vendor_id) { #ifdef CONFIG_ERRATA_SIFIVE case SIFIVE_VENDOR_ID: @@ -50,6 +53,7 @@ static void __init_or_module riscv_fill_cpu_mfr_info(struct cpu_manufacturer_inf #ifdef CONFIG_ERRATA_THEAD case THEAD_VENDOR_ID: cpu_mfr_info->patch_func = thead_errata_patch_func; + cpu_mfr_info->feature_probe_func = thead_feature_probe_func; break; #endif default: @@ -139,6 +143,20 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, } } +/* Called on each CPU as it starts */ +void probe_vendor_features(unsigned int cpu) +{ + struct cpu_manufacturer_info_t cpu_mfr_info; + + riscv_fill_cpu_mfr_info(&cpu_mfr_info); + if (!cpu_mfr_info.feature_probe_func) + return; + + cpu_mfr_info.feature_probe_func(cpu, + cpu_mfr_info.arch_id, + cpu_mfr_info.imp_id); +} + /* * This is called very early in the boot process (directly after we run * a feature detect on the boot CPU). No need to worry about other CPUs @@ -193,6 +211,7 @@ void __init apply_boot_alternatives(void) /* If called on non-boot cpu things could go wrong */ WARN_ON(smp_processor_id() != 0); + probe_vendor_features(0); _apply_alternatives((struct alt_entry *)__alt_start, (struct alt_entry *)__alt_end, RISCV_ALTERNATIVES_BOOT); diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index df9444397908..d6a75aac1d27 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,10 @@ void asm_offsets(void) OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs); + OFFSET(HIBERN_PBE_ADDR, pbe, address); + OFFSET(HIBERN_PBE_ORIG, pbe, orig_address); + OFFSET(HIBERN_PBE_NEXT, pbe, next); + OFFSET(KVM_ARCH_GUEST_ZERO, kvm_vcpu_arch, guest_context.zero); OFFSET(KVM_ARCH_GUEST_RA, kvm_vcpu_arch, guest_context.ra); OFFSET(KVM_ARCH_GUEST_SP, kvm_vcpu_arch, guest_context.sp); diff --git a/arch/riscv/kernel/cacheinfo.c b/arch/riscv/kernel/cacheinfo.c index e3829d2de5d9..09e9b88110d1 100644 --- a/arch/riscv/kernel/cacheinfo.c +++ b/arch/riscv/kernel/cacheinfo.c @@ -63,53 +63,12 @@ uintptr_t get_cache_geometry(u32 level, enum cache_type type) 0; } -static void ci_leaf_init(struct cacheinfo *this_leaf, enum cache_type type, - unsigned int level, unsigned int size, - unsigned int sets, unsigned int line_size) +static void ci_leaf_init(struct cacheinfo *this_leaf, + struct device_node *node, + enum cache_type type, unsigned int level) { this_leaf->level = level; this_leaf->type = type; - this_leaf->size = size; - this_leaf->number_of_sets = sets; - this_leaf->coherency_line_size = line_size; - - /* - * If the cache is fully associative, there is no need to - * check the other properties. - */ - if (sets == 1) - return; - - /* - * Set the ways number for n-ways associative, make sure - * all properties are big than zero. - */ - if (sets > 0 && size > 0 && line_size > 0) - this_leaf->ways_of_associativity = (size / sets) / line_size; -} - -static void fill_cacheinfo(struct cacheinfo **this_leaf, - struct device_node *node, unsigned int level) -{ - unsigned int size, sets, line_size; - - if (!of_property_read_u32(node, "cache-size", &size) && - !of_property_read_u32(node, "cache-block-size", &line_size) && - !of_property_read_u32(node, "cache-sets", &sets)) { - ci_leaf_init((*this_leaf)++, CACHE_TYPE_UNIFIED, level, size, sets, line_size); - } - - if (!of_property_read_u32(node, "i-cache-size", &size) && - !of_property_read_u32(node, "i-cache-sets", &sets) && - !of_property_read_u32(node, "i-cache-block-size", &line_size)) { - ci_leaf_init((*this_leaf)++, CACHE_TYPE_INST, level, size, sets, line_size); - } - - if (!of_property_read_u32(node, "d-cache-size", &size) && - !of_property_read_u32(node, "d-cache-sets", &sets) && - !of_property_read_u32(node, "d-cache-block-size", &line_size)) { - ci_leaf_init((*this_leaf)++, CACHE_TYPE_DATA, level, size, sets, line_size); - } } int populate_cache_leaves(unsigned int cpu) @@ -120,24 +79,29 @@ int populate_cache_leaves(unsigned int cpu) struct device_node *prev = NULL; int levels = 1, level = 1; - /* Level 1 caches in cpu node */ - fill_cacheinfo(&this_leaf, np, level); + if (of_property_read_bool(np, "cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); + if (of_property_read_bool(np, "i-cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); + if (of_property_read_bool(np, "d-cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); - /* Next level caches in cache nodes */ prev = np; while ((np = of_find_next_cache_node(np))) { of_node_put(prev); prev = np; - if (!of_device_is_compatible(np, "cache")) break; if (of_property_read_u32(np, "cache-level", &level)) break; if (level <= levels) break; - - fill_cacheinfo(&this_leaf, np, level); - + if (of_property_read_bool(np, "cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_UNIFIED, level); + if (of_property_read_bool(np, "i-cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_INST, level); + if (of_property_read_bool(np, "d-cache-size")) + ci_leaf_init(this_leaf++, np, CACHE_TYPE_DATA, level); levels = level; } of_node_put(np); diff --git a/arch/riscv/kernel/compat_vdso/Makefile b/arch/riscv/kernel/compat_vdso/Makefile index 7f34f3c7c882..189345773e7e 100644 --- a/arch/riscv/kernel/compat_vdso/Makefile +++ b/arch/riscv/kernel/compat_vdso/Makefile @@ -26,7 +26,7 @@ targets := $(obj-compat_vdso) compat_vdso.so compat_vdso.so.dbg compat_vdso.lds obj-compat_vdso := $(addprefix $(obj)/, $(obj-compat_vdso)) obj-y += compat_vdso.o -CPPFLAGS_compat_vdso.lds += -P -C -U$(ARCH) +CPPFLAGS_compat_vdso.lds += -P -C -DCOMPAT_VDSO -U$(ARCH) # Disable profiling and instrumentation for VDSO code GCOV_PROFILE := n diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c index 39235cf50652..a941adc7cbf2 100644 --- a/arch/riscv/kernel/cpu-hotplug.c +++ b/arch/riscv/kernel/cpu-hotplug.c @@ -72,7 +72,7 @@ void __cpu_die(unsigned int cpu) /* * Called from the idle thread for the CPU which has been shutdown. */ -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { idle_task_exit(); diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 8400f0cc9704..c96aa56cf1c7 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -70,12 +71,7 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid) return -1; } -struct riscv_cpuinfo { - unsigned long mvendorid; - unsigned long marchid; - unsigned long mimpid; -}; -static DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); +DEFINE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); unsigned long riscv_cached_mvendorid(unsigned int cpu_id) { @@ -186,11 +182,15 @@ arch_initcall(riscv_cpuinfo_init); */ static struct riscv_isa_ext_data isa_ext_arr[] = { __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), + __RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), + __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), + __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), + __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), __RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), }; diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c index 8275f237a59d..eb479a88a954 100644 --- a/arch/riscv/kernel/cpu_ops.c +++ b/arch/riscv/kernel/cpu_ops.c @@ -27,7 +27,7 @@ const struct cpu_operations cpu_ops_spinwait = { void __init cpu_set_ops(int cpuid) { #if IS_ENABLED(CONFIG_RISCV_SBI) - if (sbi_probe_extension(SBI_EXT_HSM) > 0) { + if (sbi_probe_extension(SBI_EXT_HSM)) { if (!cpuid) pr_info("SBI HSM extension detected\n"); cpu_ops[cpuid] = &cpu_ops_sbi; diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 59d58ee0f68d..b1d6b7e4b829 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -8,20 +8,16 @@ #include #include -#include #include #include #include #include #include #include -#include +#include #include #include -#include #include -#include -#include #define NUM_ALPHA_EXTS ('z' - 'a' + 1) @@ -30,6 +26,9 @@ unsigned long elf_hwcap __read_mostly; /* Host ISA bitmap */ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly; +/* Performance information */ +DEFINE_PER_CPU(long, misaligned_access_speed); + /** * riscv_isa_extension_base() - Get base extension word * @@ -79,6 +78,15 @@ static bool riscv_isa_extension_check(int id) return false; } return true; + case RISCV_ISA_EXT_ZICBOZ: + if (!riscv_cboz_block_size) { + pr_err("Zicboz detected in ISA string, but no cboz-block-size found\n"); + return false; + } else if (!is_power_of_2(riscv_cboz_block_size)) { + pr_err("cboz-block-size present, but is not a power-of-2\n"); + return false; + } + return true; } return true; @@ -221,12 +229,16 @@ void __init riscv_fill_hwcap(void) } } else { /* sorted alphabetically */ + SET_ISA_EXT_MAP("smaia", RISCV_ISA_EXT_SMAIA); + SET_ISA_EXT_MAP("ssaia", RISCV_ISA_EXT_SSAIA); SET_ISA_EXT_MAP("sscofpmf", RISCV_ISA_EXT_SSCOFPMF); SET_ISA_EXT_MAP("sstc", RISCV_ISA_EXT_SSTC); SET_ISA_EXT_MAP("svinval", RISCV_ISA_EXT_SVINVAL); + SET_ISA_EXT_MAP("svnapot", RISCV_ISA_EXT_SVNAPOT); SET_ISA_EXT_MAP("svpbmt", RISCV_ISA_EXT_SVPBMT); SET_ISA_EXT_MAP("zbb", RISCV_ISA_EXT_ZBB); SET_ISA_EXT_MAP("zicbom", RISCV_ISA_EXT_ZICBOM); + SET_ISA_EXT_MAP("zicboz", RISCV_ISA_EXT_ZICBOZ); SET_ISA_EXT_MAP("zihintpause", RISCV_ISA_EXT_ZIHINTPAUSE); } #undef SET_ISA_EXT_MAP @@ -269,12 +281,46 @@ void __init riscv_fill_hwcap(void) } #ifdef CONFIG_RISCV_ALTERNATIVE +/* + * Alternative patch sites consider 48 bits when determining when to patch + * the old instruction sequence with the new. These bits are broken into a + * 16-bit vendor ID and a 32-bit patch ID. A non-zero vendor ID means the + * patch site is for an erratum, identified by the 32-bit patch ID. When + * the vendor ID is zero, the patch site is for a cpufeature. cpufeatures + * further break down patch ID into two 16-bit numbers. The lower 16 bits + * are the cpufeature ID and the upper 16 bits are used for a value specific + * to the cpufeature and patch site. If the upper 16 bits are zero, then it + * implies no specific value is specified. cpufeatures that want to control + * patching on a per-site basis will provide non-zero values and implement + * checks here. The checks return true when patching should be done, and + * false otherwise. + */ +static bool riscv_cpufeature_patch_check(u16 id, u16 value) +{ + if (!value) + return true; + + switch (id) { + case RISCV_ISA_EXT_ZICBOZ: + /* + * Zicboz alternative applications provide the maximum + * supported block size order, or zero when it doesn't + * matter. If the current block size exceeds the maximum, + * then the alternative cannot be applied. + */ + return riscv_cboz_block_size <= (1U << value); + } + + return false; +} + void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned int stage) { struct alt_entry *alt; void *oldptr, *altptr; + u16 id, value; if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) return; @@ -282,13 +328,19 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, for (alt = begin; alt < end; alt++) { if (alt->vendor_id != 0) continue; - if (alt->errata_id >= RISCV_ISA_EXT_MAX) { - WARN(1, "This extension id:%d is not in ISA extension list", - alt->errata_id); + + id = PATCH_ID_CPUFEATURE_ID(alt->patch_id); + + if (id >= RISCV_ISA_EXT_MAX) { + WARN(1, "This extension id:%d is not in ISA extension list", id); continue; } - if (!__riscv_isa_extension_available(NULL, alt->errata_id)) + if (!__riscv_isa_extension_available(NULL, id)) + continue; + + value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id); + if (!riscv_cpufeature_patch_check(id, value)) continue; oldptr = ALT_OLD_PTR(alt); diff --git a/arch/riscv/kernel/efi-header.S b/arch/riscv/kernel/efi-header.S index 8e733aa48ba6..515b2dfbca75 100644 --- a/arch/riscv/kernel/efi-header.S +++ b/arch/riscv/kernel/efi-header.S @@ -6,6 +6,7 @@ #include #include +#include .macro __EFI_PE_HEADER .long PE_MAGIC @@ -33,7 +34,11 @@ optional_header: .byte 0x02 // MajorLinkerVersion .byte 0x14 // MinorLinkerVersion .long __pecoff_text_end - efi_header_end // SizeOfCode - .long __pecoff_data_virt_size // SizeOfInitializedData +#ifdef __clang__ + .long __pecoff_data_virt_size // SizeOfInitializedData +#else + .long __pecoff_data_virt_end - __pecoff_text_end // SizeOfInitializedData +#endif .long 0 // SizeOfUninitializedData .long __efistub_efi_pe_entry - _start // AddressOfEntryPoint .long efi_header_end - _start // BaseOfCode @@ -91,9 +96,17 @@ section_table: IMAGE_SCN_MEM_EXECUTE // Characteristics .ascii ".data\0\0\0" - .long __pecoff_data_virt_size // VirtualSize +#ifdef __clang__ + .long __pecoff_data_virt_size // VirtualSize +#else + .long __pecoff_data_virt_end - __pecoff_text_end // VirtualSize +#endif .long __pecoff_text_end - _start // VirtualAddress - .long __pecoff_data_raw_size // SizeOfRawData +#ifdef __clang__ + .long __pecoff_data_raw_size // SizeOfRawData +#else + .long __pecoff_data_raw_end - __pecoff_text_end // SizeOfRawData +#endif .long __pecoff_text_end - _start // PointerToRawData .long 0 // PointerToRelocations diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 99d38fdf8b18..3fbb100bc9e4 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -14,11 +14,7 @@ #include #include -#if !IS_ENABLED(CONFIG_PREEMPTION) -.set resume_kernel, restore_all -#endif - -ENTRY(handle_exception) +SYM_CODE_START(handle_exception) /* * If coming from userspace, preserve the user thread pointer and load * the kernel thread pointer. If we came from the kernel, the scratch @@ -46,32 +42,7 @@ _save_context: REG_S x1, PT_RA(sp) REG_S x3, PT_GP(sp) REG_S x5, PT_T0(sp) - REG_S x6, PT_T1(sp) - REG_S x7, PT_T2(sp) - REG_S x8, PT_S0(sp) - REG_S x9, PT_S1(sp) - REG_S x10, PT_A0(sp) - REG_S x11, PT_A1(sp) - REG_S x12, PT_A2(sp) - REG_S x13, PT_A3(sp) - REG_S x14, PT_A4(sp) - REG_S x15, PT_A5(sp) - REG_S x16, PT_A6(sp) - REG_S x17, PT_A7(sp) - REG_S x18, PT_S2(sp) - REG_S x19, PT_S3(sp) - REG_S x20, PT_S4(sp) - REG_S x21, PT_S5(sp) - REG_S x22, PT_S6(sp) - REG_S x23, PT_S7(sp) - REG_S x24, PT_S8(sp) - REG_S x25, PT_S9(sp) - REG_S x26, PT_S10(sp) - REG_S x27, PT_S11(sp) - REG_S x28, PT_T3(sp) - REG_S x29, PT_T4(sp) - REG_S x30, PT_T5(sp) - REG_S x31, PT_T6(sp) + save_from_x6_to_x31 /* * Disable user-mode memory access as it should only be set in the @@ -106,19 +77,8 @@ _save_context: .option norelax la gp, __global_pointer$ .option pop - -#ifdef CONFIG_TRACE_IRQFLAGS - call __trace_hardirqs_off -#endif - -#ifdef CONFIG_CONTEXT_TRACKING_USER - /* If previous state is in user mode, call user_exit_callable(). */ - li a0, SR_PP - and a0, s1, a0 - bnez a0, skip_context_tracking - call user_exit_callable -skip_context_tracking: -#endif + move a0, sp /* pt_regs */ + la ra, ret_from_exception /* * MSB of cause differentiates between @@ -126,38 +86,13 @@ skip_context_tracking: */ bge s4, zero, 1f - la ra, ret_from_exception - /* Handle interrupts */ - move a0, sp /* pt_regs */ - la a1, generic_handle_arch_irq - jr a1 + tail do_irq 1: - /* - * Exceptions run with interrupts enabled or disabled depending on the - * state of SR_PIE in m/sstatus. - */ - andi t0, s1, SR_PIE - beqz t0, 1f - /* kprobes, entered via ebreak, must have interrupts disabled. */ - li t0, EXC_BREAKPOINT - beq s4, t0, 1f -#ifdef CONFIG_TRACE_IRQFLAGS - call __trace_hardirqs_on -#endif - csrs CSR_STATUS, SR_IE - -1: - la ra, ret_from_exception - /* Handle syscalls */ - li t0, EXC_SYSCALL - beq s4, t0, handle_syscall - /* Handle other exceptions */ slli t0, s4, RISCV_LGPTR la t1, excp_vect_table la t2, excp_vect_table_end - move a0, sp /* pt_regs */ add t0, t1, t0 /* Check if exception code lies within bounds */ bgeu t0, t2, 1f @@ -165,95 +100,16 @@ skip_context_tracking: jr t0 1: tail do_trap_unknown +SYM_CODE_END(handle_exception) -handle_syscall: -#ifdef CONFIG_RISCV_M_MODE - /* - * When running is M-Mode (no MMU config), MPIE does not get set. - * As a result, we need to force enable interrupts here because - * handle_exception did not do set SR_IE as it always sees SR_PIE - * being cleared. - */ - csrs CSR_STATUS, SR_IE -#endif -#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING_USER) - /* Recover a0 - a7 for system calls */ - REG_L a0, PT_A0(sp) - REG_L a1, PT_A1(sp) - REG_L a2, PT_A2(sp) - REG_L a3, PT_A3(sp) - REG_L a4, PT_A4(sp) - REG_L a5, PT_A5(sp) - REG_L a6, PT_A6(sp) - REG_L a7, PT_A7(sp) -#endif - /* save the initial A0 value (needed in signal handlers) */ - REG_S a0, PT_ORIG_A0(sp) - /* - * Advance SEPC to avoid executing the original - * scall instruction on sret - */ - addi s2, s2, 0x4 - REG_S s2, PT_EPC(sp) - /* Trace syscalls, but only if requested by the user. */ - REG_L t0, TASK_TI_FLAGS(tp) - andi t0, t0, _TIF_SYSCALL_WORK - bnez t0, handle_syscall_trace_enter -check_syscall_nr: - /* Check to make sure we don't jump to a bogus syscall number. */ - li t0, __NR_syscalls - la s0, sys_ni_syscall - /* - * Syscall number held in a7. - * If syscall number is above allowed value, redirect to ni_syscall. - */ - bgeu a7, t0, 3f -#ifdef CONFIG_COMPAT - REG_L s0, PT_STATUS(sp) - srli s0, s0, SR_UXL_SHIFT - andi s0, s0, (SR_UXL >> SR_UXL_SHIFT) - li t0, (SR_UXL_32 >> SR_UXL_SHIFT) - sub t0, s0, t0 - bnez t0, 1f - - /* Call compat_syscall */ - la s0, compat_sys_call_table - j 2f -1: -#endif - /* Call syscall */ - la s0, sys_call_table -2: - slli t0, a7, RISCV_LGPTR - add s0, s0, t0 - REG_L s0, 0(s0) -3: - jalr s0 - -ret_from_syscall: - /* Set user a0 to kernel a0 */ - REG_S a0, PT_A0(sp) - /* - * We didn't execute the actual syscall. - * Seccomp already set return value for the current task pt_regs. - * (If it was configured with SECCOMP_RET_ERRNO/TRACE) - */ -ret_from_syscall_rejected: -#ifdef CONFIG_DEBUG_RSEQ - move a0, sp - call rseq_syscall -#endif - /* Trace syscalls, but only if requested by the user. */ - REG_L t0, TASK_TI_FLAGS(tp) - andi t0, t0, _TIF_SYSCALL_WORK - bnez t0, handle_syscall_trace_exit - +/* + * The ret_from_exception must be called with interrupt disabled. Here is the + * caller list: + * - handle_exception + * - ret_from_fork + */ SYM_CODE_START_NOALIGN(ret_from_exception) REG_L s0, PT_STATUS(sp) - csrc CSR_STATUS, SR_IE -#ifdef CONFIG_TRACE_IRQFLAGS - call __trace_hardirqs_off -#endif #ifdef CONFIG_RISCV_M_MODE /* the MPP value is too large to be used as an immediate arg for addi */ li t0, SR_MPP @@ -261,17 +117,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception) #else andi s0, s0, SR_SPP #endif - bnez s0, resume_kernel -SYM_CODE_END(ret_from_exception) - - /* Interrupts must be disabled here so flags are checked atomically */ - REG_L s0, TASK_TI_FLAGS(tp) /* current_thread_info->flags */ - andi s1, s0, _TIF_WORK_MASK - bnez s1, resume_userspace_slow -resume_userspace: -#ifdef CONFIG_CONTEXT_TRACKING_USER - call user_enter_callable -#endif + bnez s0, 1f /* Save unwound kernel stack pointer in thread_info */ addi s0, sp, PT_SIZE_ON_STACK @@ -282,18 +128,7 @@ resume_userspace: * structures again. */ csrw CSR_SCRATCH, tp - -restore_all: -#ifdef CONFIG_TRACE_IRQFLAGS - REG_L s1, PT_STATUS(sp) - andi t0, s1, SR_PIE - beqz t0, 1f - call __trace_hardirqs_on - j 2f 1: - call __trace_hardirqs_off -2: -#endif REG_L a0, PT_STATUS(sp) /* * The current load reservation is effectively part of the processor's @@ -322,32 +157,7 @@ restore_all: REG_L x3, PT_GP(sp) REG_L x4, PT_TP(sp) REG_L x5, PT_T0(sp) - REG_L x6, PT_T1(sp) - REG_L x7, PT_T2(sp) - REG_L x8, PT_S0(sp) - REG_L x9, PT_S1(sp) - REG_L x10, PT_A0(sp) - REG_L x11, PT_A1(sp) - REG_L x12, PT_A2(sp) - REG_L x13, PT_A3(sp) - REG_L x14, PT_A4(sp) - REG_L x15, PT_A5(sp) - REG_L x16, PT_A6(sp) - REG_L x17, PT_A7(sp) - REG_L x18, PT_S2(sp) - REG_L x19, PT_S3(sp) - REG_L x20, PT_S4(sp) - REG_L x21, PT_S5(sp) - REG_L x22, PT_S6(sp) - REG_L x23, PT_S7(sp) - REG_L x24, PT_S8(sp) - REG_L x25, PT_S9(sp) - REG_L x26, PT_S10(sp) - REG_L x27, PT_S11(sp) - REG_L x28, PT_T3(sp) - REG_L x29, PT_T4(sp) - REG_L x30, PT_T5(sp) - REG_L x31, PT_T6(sp) + restore_from_x6_to_x31 REG_L x2, PT_SP(sp) @@ -356,47 +166,10 @@ restore_all: #else sret #endif - -#if IS_ENABLED(CONFIG_PREEMPTION) -resume_kernel: - REG_L s0, TASK_TI_PREEMPT_COUNT(tp) - bnez s0, restore_all - REG_L s0, TASK_TI_FLAGS(tp) - andi s0, s0, _TIF_NEED_RESCHED - beqz s0, restore_all - call preempt_schedule_irq - j restore_all -#endif - -resume_userspace_slow: - /* Enter slow path for supplementary processing */ - move a0, sp /* pt_regs */ - move a1, s0 /* current_thread_info->flags */ - call do_work_pending - j resume_userspace - -/* Slow paths for ptrace. */ -handle_syscall_trace_enter: - move a0, sp - call do_syscall_trace_enter - move t0, a0 - REG_L a0, PT_A0(sp) - REG_L a1, PT_A1(sp) - REG_L a2, PT_A2(sp) - REG_L a3, PT_A3(sp) - REG_L a4, PT_A4(sp) - REG_L a5, PT_A5(sp) - REG_L a6, PT_A6(sp) - REG_L a7, PT_A7(sp) - bnez t0, ret_from_syscall_rejected - j check_syscall_nr -handle_syscall_trace_exit: - move a0, sp - call do_syscall_trace_exit - j ret_from_exception +SYM_CODE_END(ret_from_exception) #ifdef CONFIG_VMAP_STACK -handle_kernel_stack_overflow: +SYM_CODE_START_LOCAL(handle_kernel_stack_overflow) /* * Takes the psuedo-spinlock for the shadow stack, in case multiple * harts are concurrently overflowing their kernel stacks. We could @@ -464,32 +237,7 @@ restore_caller_reg: REG_S x1, PT_RA(sp) REG_S x3, PT_GP(sp) REG_S x5, PT_T0(sp) - REG_S x6, PT_T1(sp) - REG_S x7, PT_T2(sp) - REG_S x8, PT_S0(sp) - REG_S x9, PT_S1(sp) - REG_S x10, PT_A0(sp) - REG_S x11, PT_A1(sp) - REG_S x12, PT_A2(sp) - REG_S x13, PT_A3(sp) - REG_S x14, PT_A4(sp) - REG_S x15, PT_A5(sp) - REG_S x16, PT_A6(sp) - REG_S x17, PT_A7(sp) - REG_S x18, PT_S2(sp) - REG_S x19, PT_S3(sp) - REG_S x20, PT_S4(sp) - REG_S x21, PT_S5(sp) - REG_S x22, PT_S6(sp) - REG_S x23, PT_S7(sp) - REG_S x24, PT_S8(sp) - REG_S x25, PT_S9(sp) - REG_S x26, PT_S10(sp) - REG_S x27, PT_S11(sp) - REG_S x28, PT_T3(sp) - REG_S x29, PT_T4(sp) - REG_S x30, PT_T5(sp) - REG_S x31, PT_T6(sp) + save_from_x6_to_x31 REG_L s0, TASK_TI_KERNEL_SP(tp) csrr s1, CSR_STATUS @@ -505,23 +253,20 @@ restore_caller_reg: REG_S s5, PT_TP(sp) move a0, sp tail handle_bad_stack +SYM_CODE_END(handle_kernel_stack_overflow) #endif -END(handle_exception) - -ENTRY(ret_from_fork) - la ra, ret_from_exception - tail schedule_tail -ENDPROC(ret_from_fork) - -ENTRY(ret_from_kernel_thread) +SYM_CODE_START(ret_from_fork) call schedule_tail + beqz s0, 1f /* not from kernel thread */ /* Call fn(arg) */ - la ra, ret_from_exception move a0, s1 - jr s0 -ENDPROC(ret_from_kernel_thread) - + jalr s0 +1: + move a0, sp /* pt_regs */ + la ra, ret_from_exception + tail syscall_exit_to_user_mode +SYM_CODE_END(ret_from_fork) /* * Integer register context switch @@ -533,7 +278,7 @@ ENDPROC(ret_from_kernel_thread) * The value of a0 and a1 must be preserved by this function, as that's how * arguments are passed to schedule_tail. */ -ENTRY(__switch_to) +SYM_FUNC_START(__switch_to) /* Save context into prev->thread */ li a4, TASK_THREAD_RA add a3, a0, a4 @@ -570,7 +315,7 @@ ENTRY(__switch_to) /* The offset of thread_info in task_struct is zero. */ move tp, a1 ret -ENDPROC(__switch_to) +SYM_FUNC_END(__switch_to) #ifndef CONFIG_MMU #define do_page_fault do_trap_unknown @@ -579,7 +324,7 @@ ENDPROC(__switch_to) .section ".rodata" .align LGREG /* Exception vector table */ -ENTRY(excp_vect_table) +SYM_CODE_START(excp_vect_table) RISCV_PTR do_trap_insn_misaligned ALT_INSN_FAULT(RISCV_PTR do_trap_insn_fault) RISCV_PTR do_trap_insn_illegal @@ -588,7 +333,7 @@ ENTRY(excp_vect_table) RISCV_PTR do_trap_load_fault RISCV_PTR do_trap_store_misaligned RISCV_PTR do_trap_store_fault - RISCV_PTR do_trap_ecall_u /* system call, gets intercepted */ + RISCV_PTR do_trap_ecall_u /* system call */ RISCV_PTR do_trap_ecall_s RISCV_PTR do_trap_unknown RISCV_PTR do_trap_ecall_m @@ -598,11 +343,11 @@ ENTRY(excp_vect_table) RISCV_PTR do_trap_unknown RISCV_PTR do_page_fault /* store page fault */ excp_vect_table_end: -END(excp_vect_table) +SYM_CODE_END(excp_vect_table) #ifndef CONFIG_MMU -ENTRY(__user_rt_sigreturn) +SYM_CODE_START(__user_rt_sigreturn) li a7, __NR_rt_sigreturn scall -END(__user_rt_sigreturn) +SYM_CODE_END(__user_rt_sigreturn) #endif diff --git a/arch/riscv/kernel/head.h b/arch/riscv/kernel/head.h index 726731ada534..a556fdaafed9 100644 --- a/arch/riscv/kernel/head.h +++ b/arch/riscv/kernel/head.h @@ -10,7 +10,6 @@ extern atomic_t hart_lottery; -asmlinkage void do_page_fault(struct pt_regs *regs); asmlinkage void __init setup_vm(uintptr_t dtb_pa); #ifdef CONFIG_XIP_KERNEL asmlinkage void __init __copy_data(void); diff --git a/arch/riscv/kernel/hibernate-asm.S b/arch/riscv/kernel/hibernate-asm.S new file mode 100644 index 000000000000..effaf5ca5da0 --- /dev/null +++ b/arch/riscv/kernel/hibernate-asm.S @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Hibernation low level support for RISCV. + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * + * Author: Jee Heng Sia + */ + +#include +#include +#include +#include + +#include + +/* + * int __hibernate_cpu_resume(void) + * Switch back to the hibernated image's page table prior to restoring the CPU + * context. + * + * Always returns 0 + */ +ENTRY(__hibernate_cpu_resume) + /* switch to hibernated image's page table. */ + csrw CSR_SATP, s0 + sfence.vma + + REG_L a0, hibernate_cpu_context + + suspend_restore_csrs + suspend_restore_regs + + /* Return zero value. */ + mv a0, zero + + ret +END(__hibernate_cpu_resume) + +/* + * Prepare to restore the image. + * a0: satp of saved page tables. + * a1: satp of temporary page tables. + * a2: cpu_resume. + */ +ENTRY(hibernate_restore_image) + mv s0, a0 + mv s1, a1 + mv s2, a2 + REG_L s4, restore_pblist + REG_L a1, relocated_restore_code + + jalr a1 +END(hibernate_restore_image) + +/* + * The below code will be executed from a 'safe' page. + * It first switches to the temporary page table, then starts to copy the pages + * back to the original memory location. Finally, it jumps to __hibernate_cpu_resume() + * to restore the CPU context. + */ +ENTRY(hibernate_core_restore_code) + /* switch to temp page table. */ + csrw satp, s1 + sfence.vma +.Lcopy: + /* The below code will restore the hibernated image. */ + REG_L a1, HIBERN_PBE_ADDR(s4) + REG_L a0, HIBERN_PBE_ORIG(s4) + + copy_page a0, a1 + + REG_L s4, HIBERN_PBE_NEXT(s4) + bnez s4, .Lcopy + + jalr s2 +END(hibernate_core_restore_code) diff --git a/arch/riscv/kernel/hibernate.c b/arch/riscv/kernel/hibernate.c new file mode 100644 index 000000000000..264b2dcdd67e --- /dev/null +++ b/arch/riscv/kernel/hibernate.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Hibernation support for RISCV + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * + * Author: Jee Heng Sia + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* The logical cpu number we should resume on, initialised to a non-cpu number. */ +static int sleep_cpu = -EINVAL; + +/* Pointer to the temporary resume page table. */ +static pgd_t *resume_pg_dir; + +/* CPU context to be saved. */ +struct suspend_context *hibernate_cpu_context; +EXPORT_SYMBOL_GPL(hibernate_cpu_context); + +unsigned long relocated_restore_code; +EXPORT_SYMBOL_GPL(relocated_restore_code); + +/** + * struct arch_hibernate_hdr_invariants - container to store kernel build version. + * @uts_version: to save the build number and date so that we do not resume with + * a different kernel. + */ +struct arch_hibernate_hdr_invariants { + char uts_version[__NEW_UTS_LEN + 1]; +}; + +/** + * struct arch_hibernate_hdr - helper parameters that help us to restore the image. + * @invariants: container to store kernel build version. + * @hartid: to make sure same boot_cpu executes the hibernate/restore code. + * @saved_satp: original page table used by the hibernated image. + * @restore_cpu_addr: the kernel's image address to restore the CPU context. + */ +static struct arch_hibernate_hdr { + struct arch_hibernate_hdr_invariants invariants; + unsigned long hartid; + unsigned long saved_satp; + unsigned long restore_cpu_addr; +} resume_hdr; + +static void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i) +{ + memset(i, 0, sizeof(*i)); + memcpy(i->uts_version, init_utsname()->version, sizeof(i->uts_version)); +} + +/* + * Check if the given pfn is in the 'nosave' section. + */ +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = sym_to_pfn(&__nosave_begin); + unsigned long nosave_end_pfn = sym_to_pfn(&__nosave_end - 1); + + return ((pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn)); +} + +void notrace save_processor_state(void) +{ + WARN_ON(num_online_cpus() != 1); +} + +void notrace restore_processor_state(void) +{ +} + +/* + * Helper parameters need to be saved to the hibernation image header. + */ +int arch_hibernation_header_save(void *addr, unsigned int max_size) +{ + struct arch_hibernate_hdr *hdr = addr; + + if (max_size < sizeof(*hdr)) + return -EOVERFLOW; + + arch_hdr_invariants(&hdr->invariants); + + hdr->hartid = cpuid_to_hartid_map(sleep_cpu); + hdr->saved_satp = csr_read(CSR_SATP); + hdr->restore_cpu_addr = (unsigned long)__hibernate_cpu_resume; + + return 0; +} +EXPORT_SYMBOL_GPL(arch_hibernation_header_save); + +/* + * Retrieve the helper parameters from the hibernation image header. + */ +int arch_hibernation_header_restore(void *addr) +{ + struct arch_hibernate_hdr_invariants invariants; + struct arch_hibernate_hdr *hdr = addr; + int ret = 0; + + arch_hdr_invariants(&invariants); + + if (memcmp(&hdr->invariants, &invariants, sizeof(invariants))) { + pr_crit("Hibernate image not generated by this kernel!\n"); + return -EINVAL; + } + + sleep_cpu = riscv_hartid_to_cpuid(hdr->hartid); + if (sleep_cpu < 0) { + pr_crit("Hibernated on a CPU not known to this kernel!\n"); + sleep_cpu = -EINVAL; + return -EINVAL; + } + +#ifdef CONFIG_SMP + ret = bringup_hibernate_cpu(sleep_cpu); + if (ret) { + sleep_cpu = -EINVAL; + return ret; + } +#endif + resume_hdr = *hdr; + + return ret; +} +EXPORT_SYMBOL_GPL(arch_hibernation_header_restore); + +int swsusp_arch_suspend(void) +{ + int ret = 0; + + if (__cpu_suspend_enter(hibernate_cpu_context)) { + sleep_cpu = smp_processor_id(); + suspend_save_csrs(hibernate_cpu_context); + ret = swsusp_save(); + } else { + suspend_restore_csrs(hibernate_cpu_context); + flush_tlb_all(); + flush_icache_all(); + + /* + * Tell the hibernation core that we've just restored the memory. + */ + in_suspend = 0; + sleep_cpu = -EINVAL; + } + + return ret; +} + +static int temp_pgtable_map_pte(pmd_t *dst_pmdp, pmd_t *src_pmdp, unsigned long start, + unsigned long end, pgprot_t prot) +{ + pte_t *src_ptep; + pte_t *dst_ptep; + + if (pmd_none(READ_ONCE(*dst_pmdp))) { + dst_ptep = (pte_t *)get_safe_page(GFP_ATOMIC); + if (!dst_ptep) + return -ENOMEM; + + pmd_populate_kernel(NULL, dst_pmdp, dst_ptep); + } + + dst_ptep = pte_offset_kernel(dst_pmdp, start); + src_ptep = pte_offset_kernel(src_pmdp, start); + + do { + pte_t pte = READ_ONCE(*src_ptep); + + if (pte_present(pte)) + set_pte(dst_ptep, __pte(pte_val(pte) | pgprot_val(prot))); + } while (dst_ptep++, src_ptep++, start += PAGE_SIZE, start < end); + + return 0; +} + +static int temp_pgtable_map_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start, + unsigned long end, pgprot_t prot) +{ + unsigned long next; + unsigned long ret; + pmd_t *src_pmdp; + pmd_t *dst_pmdp; + + if (pud_none(READ_ONCE(*dst_pudp))) { + dst_pmdp = (pmd_t *)get_safe_page(GFP_ATOMIC); + if (!dst_pmdp) + return -ENOMEM; + + pud_populate(NULL, dst_pudp, dst_pmdp); + } + + dst_pmdp = pmd_offset(dst_pudp, start); + src_pmdp = pmd_offset(src_pudp, start); + + do { + pmd_t pmd = READ_ONCE(*src_pmdp); + + next = pmd_addr_end(start, end); + + if (pmd_none(pmd)) + continue; + + if (pmd_leaf(pmd)) { + set_pmd(dst_pmdp, __pmd(pmd_val(pmd) | pgprot_val(prot))); + } else { + ret = temp_pgtable_map_pte(dst_pmdp, src_pmdp, start, next, prot); + if (ret) + return -ENOMEM; + } + } while (dst_pmdp++, src_pmdp++, start = next, start != end); + + return 0; +} + +static int temp_pgtable_map_pud(p4d_t *dst_p4dp, p4d_t *src_p4dp, unsigned long start, + unsigned long end, pgprot_t prot) +{ + unsigned long next; + unsigned long ret; + pud_t *dst_pudp; + pud_t *src_pudp; + + if (p4d_none(READ_ONCE(*dst_p4dp))) { + dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC); + if (!dst_pudp) + return -ENOMEM; + + p4d_populate(NULL, dst_p4dp, dst_pudp); + } + + dst_pudp = pud_offset(dst_p4dp, start); + src_pudp = pud_offset(src_p4dp, start); + + do { + pud_t pud = READ_ONCE(*src_pudp); + + next = pud_addr_end(start, end); + + if (pud_none(pud)) + continue; + + if (pud_leaf(pud)) { + set_pud(dst_pudp, __pud(pud_val(pud) | pgprot_val(prot))); + } else { + ret = temp_pgtable_map_pmd(dst_pudp, src_pudp, start, next, prot); + if (ret) + return -ENOMEM; + } + } while (dst_pudp++, src_pudp++, start = next, start != end); + + return 0; +} + +static int temp_pgtable_map_p4d(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start, + unsigned long end, pgprot_t prot) +{ + unsigned long next; + unsigned long ret; + p4d_t *dst_p4dp; + p4d_t *src_p4dp; + + if (pgd_none(READ_ONCE(*dst_pgdp))) { + dst_p4dp = (p4d_t *)get_safe_page(GFP_ATOMIC); + if (!dst_p4dp) + return -ENOMEM; + + pgd_populate(NULL, dst_pgdp, dst_p4dp); + } + + dst_p4dp = p4d_offset(dst_pgdp, start); + src_p4dp = p4d_offset(src_pgdp, start); + + do { + p4d_t p4d = READ_ONCE(*src_p4dp); + + next = p4d_addr_end(start, end); + + if (p4d_none(p4d)) + continue; + + if (p4d_leaf(p4d)) { + set_p4d(dst_p4dp, __p4d(p4d_val(p4d) | pgprot_val(prot))); + } else { + ret = temp_pgtable_map_pud(dst_p4dp, src_p4dp, start, next, prot); + if (ret) + return -ENOMEM; + } + } while (dst_p4dp++, src_p4dp++, start = next, start != end); + + return 0; +} + +static int temp_pgtable_mapping(pgd_t *pgdp, unsigned long start, unsigned long end, pgprot_t prot) +{ + pgd_t *dst_pgdp = pgd_offset_pgd(pgdp, start); + pgd_t *src_pgdp = pgd_offset_k(start); + unsigned long next; + unsigned long ret; + + do { + pgd_t pgd = READ_ONCE(*src_pgdp); + + next = pgd_addr_end(start, end); + + if (pgd_none(pgd)) + continue; + + if (pgd_leaf(pgd)) { + set_pgd(dst_pgdp, __pgd(pgd_val(pgd) | pgprot_val(prot))); + } else { + ret = temp_pgtable_map_p4d(dst_pgdp, src_pgdp, start, next, prot); + if (ret) + return -ENOMEM; + } + } while (dst_pgdp++, src_pgdp++, start = next, start != end); + + return 0; +} + +static unsigned long relocate_restore_code(void) +{ + void *page = (void *)get_safe_page(GFP_ATOMIC); + + if (!page) + return -ENOMEM; + + copy_page(page, hibernate_core_restore_code); + + /* Make the page containing the relocated code executable. */ + set_memory_x((unsigned long)page, 1); + + return (unsigned long)page; +} + +int swsusp_arch_resume(void) +{ + unsigned long end = (unsigned long)pfn_to_virt(max_low_pfn); + unsigned long start = PAGE_OFFSET; + int ret; + + /* + * Memory allocated by get_safe_page() will be dealt with by the hibernation core, + * we don't need to free it here. + */ + resume_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC); + if (!resume_pg_dir) + return -ENOMEM; + + /* + * Create a temporary page table and map the whole linear region as executable and + * writable. + */ + ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE | _PAGE_EXEC)); + if (ret) + return ret; + + /* Move the restore code to a new page so that it doesn't get overwritten by itself. */ + relocated_restore_code = relocate_restore_code(); + if (relocated_restore_code == -ENOMEM) + return -ENOMEM; + + /* + * Map the __hibernate_cpu_resume() address to the temporary page table so that the + * restore code can jumps to it after finished restore the image. The next execution + * code doesn't find itself in a different address space after switching over to the + * original page table used by the hibernated image. + * The __hibernate_cpu_resume() mapping is unnecessary for RV32 since the kernel and + * linear addresses are identical, but different for RV64. To ensure consistency, we + * map it for both RV32 and RV64 kernels. + * Additionally, we should ensure that the page is writable before restoring the image. + */ + start = (unsigned long)resume_hdr.restore_cpu_addr; + end = start + PAGE_SIZE; + + ret = temp_pgtable_mapping(resume_pg_dir, start, end, __pgprot(_PAGE_WRITE)); + if (ret) + return ret; + + hibernate_restore_image(resume_hdr.saved_satp, (PFN_DOWN(__pa(resume_pg_dir)) | satp_mode), + resume_hdr.restore_cpu_addr); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP_SMP +int hibernate_resume_nonboot_cpu_disable(void) +{ + if (sleep_cpu < 0) { + pr_err("Failing to resume from hibernate on an unknown CPU\n"); + return -ENODEV; + } + + return freeze_secondary_cpus(sleep_cpu); +} +#endif + +static int __init riscv_hibernate_init(void) +{ + hibernate_cpu_context = kzalloc(sizeof(*hibernate_cpu_context), GFP_KERNEL); + + if (WARN_ON(!hibernate_cpu_context)) + return -ENOMEM; + + return 0; +} + +early_initcall(riscv_hibernate_init); diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h index 7e2962ef73f9..15616155008c 100644 --- a/arch/riscv/kernel/image-vars.h +++ b/arch/riscv/kernel/image-vars.h @@ -23,8 +23,6 @@ * linked at. The routines below are all implemented in assembler in a * position independent manner */ -__efistub_strcmp = strcmp; - __efistub__start = _start; __efistub__start_kernel = _start_kernel; __efistub__end = _end; diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 125de818d1ba..669b8697aa38 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -66,66 +66,17 @@ REG_S x3, PT_GP(sp) REG_S x4, PT_TP(sp) REG_S x5, PT_T0(sp) - REG_S x6, PT_T1(sp) - REG_S x7, PT_T2(sp) - REG_S x8, PT_S0(sp) - REG_S x9, PT_S1(sp) - REG_S x10, PT_A0(sp) - REG_S x11, PT_A1(sp) - REG_S x12, PT_A2(sp) - REG_S x13, PT_A3(sp) - REG_S x14, PT_A4(sp) - REG_S x15, PT_A5(sp) - REG_S x16, PT_A6(sp) - REG_S x17, PT_A7(sp) - REG_S x18, PT_S2(sp) - REG_S x19, PT_S3(sp) - REG_S x20, PT_S4(sp) - REG_S x21, PT_S5(sp) - REG_S x22, PT_S6(sp) - REG_S x23, PT_S7(sp) - REG_S x24, PT_S8(sp) - REG_S x25, PT_S9(sp) - REG_S x26, PT_S10(sp) - REG_S x27, PT_S11(sp) - REG_S x28, PT_T3(sp) - REG_S x29, PT_T4(sp) - REG_S x30, PT_T5(sp) - REG_S x31, PT_T6(sp) + save_from_x6_to_x31 .endm .macro RESTORE_ALL - REG_L t0, PT_EPC(sp) REG_L x1, PT_RA(sp) REG_L x2, PT_SP(sp) REG_L x3, PT_GP(sp) REG_L x4, PT_TP(sp) - REG_L x6, PT_T1(sp) - REG_L x7, PT_T2(sp) - REG_L x8, PT_S0(sp) - REG_L x9, PT_S1(sp) - REG_L x10, PT_A0(sp) - REG_L x11, PT_A1(sp) - REG_L x12, PT_A2(sp) - REG_L x13, PT_A3(sp) - REG_L x14, PT_A4(sp) - REG_L x15, PT_A5(sp) - REG_L x16, PT_A6(sp) - REG_L x17, PT_A7(sp) - REG_L x18, PT_S2(sp) - REG_L x19, PT_S3(sp) - REG_L x20, PT_S4(sp) - REG_L x21, PT_S5(sp) - REG_L x22, PT_S6(sp) - REG_L x23, PT_S7(sp) - REG_L x24, PT_S8(sp) - REG_L x25, PT_S9(sp) - REG_L x26, PT_S10(sp) - REG_L x27, PT_S11(sp) - REG_L x28, PT_T3(sp) - REG_L x29, PT_T4(sp) - REG_L x30, PT_T5(sp) - REG_L x31, PT_T6(sp) + /* Restore t0 with PT_EPC */ + REG_L x5, PT_EPC(sp) + restore_from_x6_to_x31 addi sp, sp, PT_SIZE_ON_STACK .endm diff --git a/arch/riscv/kernel/pi/Makefile b/arch/riscv/kernel/pi/Makefile new file mode 100644 index 000000000000..7b593d44c712 --- /dev/null +++ b/arch/riscv/kernel/pi/Makefile @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0 +# This file was copied from arm64/kernel/pi/Makefile. + +KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \ + -Os -DDISABLE_BRANCH_PROFILING $(DISABLE_STACKLEAK_PLUGIN) \ + $(call cc-option,-mbranch-protection=none) \ + -I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \ + -D__DISABLE_EXPORTS -ffreestanding \ + -fno-asynchronous-unwind-tables -fno-unwind-tables \ + $(call cc-option,-fno-addrsig) + +KBUILD_CFLAGS += -mcmodel=medany + +CFLAGS_cmdline_early.o += -D__NO_FORTIFY +CFLAGS_lib-fdt_ro.o += -D__NO_FORTIFY + +GCOV_PROFILE := n +KASAN_SANITIZE := n +KCSAN_SANITIZE := n +UBSAN_SANITIZE := n +KCOV_INSTRUMENT := n + +$(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \ + --remove-section=.note.gnu.property \ + --prefix-alloc-sections=.init.pi +$(obj)/%.pi.o: $(obj)/%.o FORCE + $(call if_changed,objcopy) + +$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE + $(call if_changed_rule,cc_o_c) + +$(obj)/string.o: $(srctree)/lib/string.c FORCE + $(call if_changed_rule,cc_o_c) + +$(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE + $(call if_changed_rule,cc_o_c) + +obj-y := cmdline_early.pi.o string.pi.o ctype.pi.o lib-fdt.pi.o lib-fdt_ro.pi.o +extra-y := $(patsubst %.pi.o,%.o,$(obj-y)) diff --git a/arch/riscv/kernel/pi/cmdline_early.c b/arch/riscv/kernel/pi/cmdline_early.c new file mode 100644 index 000000000000..05652d13c746 --- /dev/null +++ b/arch/riscv/kernel/pi/cmdline_early.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include + +static char early_cmdline[COMMAND_LINE_SIZE]; + +/* + * Declare the functions that are exported (but prefixed) here so that LLVM + * does not complain it lacks the 'static' keyword (which, if added, makes + * LLVM complain because the function is actually unused in this file). + */ +u64 set_satp_mode_from_cmdline(uintptr_t dtb_pa); + +static char *get_early_cmdline(uintptr_t dtb_pa) +{ + const char *fdt_cmdline = NULL; + unsigned int fdt_cmdline_size = 0; + int chosen_node; + + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) { + chosen_node = fdt_path_offset((void *)dtb_pa, "/chosen"); + if (chosen_node >= 0) { + fdt_cmdline = fdt_getprop((void *)dtb_pa, chosen_node, + "bootargs", NULL); + if (fdt_cmdline) { + fdt_cmdline_size = strlen(fdt_cmdline); + strscpy(early_cmdline, fdt_cmdline, + COMMAND_LINE_SIZE); + } + } + } + + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + fdt_cmdline_size == 0 /* CONFIG_CMDLINE_FALLBACK */) { + strncat(early_cmdline, CONFIG_CMDLINE, + COMMAND_LINE_SIZE - fdt_cmdline_size); + } + + return early_cmdline; +} + +static u64 match_noXlvl(char *cmdline) +{ + if (strstr(cmdline, "no4lvl")) + return SATP_MODE_48; + else if (strstr(cmdline, "no5lvl")) + return SATP_MODE_57; + + return 0; +} + +u64 set_satp_mode_from_cmdline(uintptr_t dtb_pa) +{ + char *cmdline = get_early_cmdline(dtb_pa); + + return match_noXlvl(cmdline); +} diff --git a/arch/riscv/kernel/probes/Makefile b/arch/riscv/kernel/probes/Makefile index c40139e9ca47..8265ff497977 100644 --- a/arch/riscv/kernel/probes/Makefile +++ b/arch/riscv/kernel/probes/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_RETHOOK) += rethook.o rethook_trampoline.o obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o obj-$(CONFIG_UPROBES) += uprobes.o decode-insn.o simulate-insn.o CFLAGS_REMOVE_simulate-insn.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_rethook.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_rethook_trampoline.o = $(CC_FLAGS_FTRACE) diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 774ffde386ab..e2a060066730 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -34,7 +34,6 @@ EXPORT_SYMBOL(__stack_chk_guard); #endif extern asmlinkage void ret_from_fork(void); -extern asmlinkage void ret_from_kernel_thread(void); void arch_cpu_idle(void) { @@ -173,7 +172,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) /* Supervisor/Machine, irqs on: */ childregs->status = SR_PP | SR_PIE; - p->thread.ra = (unsigned long)ret_from_kernel_thread; p->thread.s[0] = (unsigned long)args->fn; p->thread.s[1] = (unsigned long)args->fn_arg; } else { @@ -183,8 +181,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) if (clone_flags & CLONE_SETTLS) childregs->tp = tls; childregs->a0 = 0; /* Return value of fork() */ - p->thread.ra = (unsigned long)ret_from_fork; + p->thread.s[0] = 0; } + p->thread.ra = (unsigned long)ret_from_fork; p->thread.sp = (unsigned long)childregs; /* kernel sp */ return 0; } diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 2ae8280ae475..23c48b14a0e7 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -19,9 +19,6 @@ #include #include -#define CREATE_TRACE_POINTS -#include - enum riscv_regset { REGSET_X, #ifdef CONFIG_FPU @@ -212,7 +209,6 @@ unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) void ptrace_disable(struct task_struct *child) { - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } long arch_ptrace(struct task_struct *child, long request, @@ -229,46 +225,6 @@ long arch_ptrace(struct task_struct *child, long request, return ret; } -/* - * Allows PTRACE_SYSCALL to work. These are called from entry.S in - * {handle,ret_from}_syscall. - */ -__visible int do_syscall_trace_enter(struct pt_regs *regs) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - if (ptrace_report_syscall_entry(regs)) - return -1; - - /* - * Do the secure computing after ptrace; failures should be fast. - * If this fails we might have return value in a0 from seccomp - * (via SECCOMP_RET_ERRNO/TRACE). - */ - if (secure_computing() == -1) - return -1; - -#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_enter(regs, syscall_get_nr(current, regs)); -#endif - - audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3); - return 0; -} - -__visible void do_syscall_trace_exit(struct pt_regs *regs) -{ - audit_syscall_exit(regs); - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ptrace_report_syscall_exit(regs, 0); - -#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_exit(regs, regs_return_value(regs)); -#endif -} - #ifdef CONFIG_COMPAT static int compat_riscv_gpr_get(struct task_struct *target, const struct user_regset *regset, diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 92b9b759ab3d..c672c8ba9a2a 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -524,19 +524,18 @@ static void sbi_srst_power_off(void) * sbi_probe_extension() - Check if an SBI extension ID is supported or not. * @extid: The extension ID to be probed. * - * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise. + * Return: 1 or an extension specific nonzero value if yes, 0 otherwise. */ -int sbi_probe_extension(int extid) +long sbi_probe_extension(int extid) { struct sbiret ret; ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid, 0, 0, 0, 0, 0); if (!ret.error) - if (ret.value) - return ret.value; + return ret.value; - return -ENOTSUPP; + return 0; } EXPORT_SYMBOL(sbi_probe_extension); @@ -599,26 +598,26 @@ void __init sbi_init(void) if (!sbi_spec_is_0_1()) { pr_info("SBI implementation ID=0x%lx Version=0x%lx\n", sbi_get_firmware_id(), sbi_get_firmware_version()); - if (sbi_probe_extension(SBI_EXT_TIME) > 0) { + if (sbi_probe_extension(SBI_EXT_TIME)) { __sbi_set_timer = __sbi_set_timer_v02; pr_info("SBI TIME extension detected\n"); } else { __sbi_set_timer = __sbi_set_timer_v01; } - if (sbi_probe_extension(SBI_EXT_IPI) > 0) { + if (sbi_probe_extension(SBI_EXT_IPI)) { __sbi_send_ipi = __sbi_send_ipi_v02; pr_info("SBI IPI extension detected\n"); } else { __sbi_send_ipi = __sbi_send_ipi_v01; } - if (sbi_probe_extension(SBI_EXT_RFENCE) > 0) { + if (sbi_probe_extension(SBI_EXT_RFENCE)) { __sbi_rfence = __sbi_rfence_v02; pr_info("SBI RFENCE extension detected\n"); } else { __sbi_rfence = __sbi_rfence_v01; } if ((sbi_spec_version >= sbi_mk_version(0, 3)) && - (sbi_probe_extension(SBI_EXT_SRST) > 0)) { + sbi_probe_extension(SBI_EXT_SRST)) { pr_info("SBI SRST extension detected\n"); pm_power_off = sbi_srst_power_off; sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot; diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 3020f44dcf58..36b026057503 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -293,7 +293,7 @@ void __init setup_arch(char **cmdline_p) setup_smp(); #endif - riscv_init_cbom_blocksize(); + riscv_init_cbo_blocksizes(); riscv_fill_hwcap(); apply_boot_alternatives(); if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) && diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index dee66c9290cc..9aff9d720590 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -281,7 +282,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) signal_setup_done(ret, ksig, 0); } -static void do_signal(struct pt_regs *regs) +void arch_do_signal_or_restart(struct pt_regs *regs) { struct ksignal ksig; @@ -318,29 +319,3 @@ static void do_signal(struct pt_regs *regs) */ restore_saved_sigmask(); } - -/* - * Handle any pending work on the resume-to-userspace path, as indicated by - * _TIF_WORK_MASK. Entered from assembly with IRQs off. - */ -asmlinkage __visible void do_work_pending(struct pt_regs *regs, - unsigned long thread_info_flags) -{ - do { - if (thread_info_flags & _TIF_NEED_RESCHED) { - schedule(); - } else { - local_irq_enable(); - if (thread_info_flags & _TIF_UPROBE) - uprobe_notify_resume(regs); - /* Handle pending signal delivery */ - if (thread_info_flags & (_TIF_SIGPENDING | - _TIF_NOTIFY_SIGNAL)) - do_signal(regs); - if (thread_info_flags & _TIF_NOTIFY_RESUME) - resume_user_mode_work(regs); - } - local_irq_disable(); - thread_info_flags = read_thread_flags(); - } while (thread_info_flags & _TIF_WORK_MASK); -} diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 5f985a197eff..23e533766a49 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -333,8 +333,8 @@ bool smp_crash_stop_failed(void) } #endif -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { send_ipi_single(cpu, IPI_RESCHEDULE); } -EXPORT_SYMBOL_GPL(smp_send_reschedule); +EXPORT_SYMBOL_GPL(arch_smp_send_reschedule); diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 00b53913d4c6..445a4efee267 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -167,6 +167,7 @@ asmlinkage __visible void smp_callin(void) notify_cpu_starting(curr_cpuid); numa_add_cpu(curr_cpuid); set_cpu_online(curr_cpuid, 1); + probe_vendor_features(curr_cpuid); /* * Remote TLB flushes are ignored while the CPU is offline, so emit diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c index 9ba24fb8cc93..3c89b8ec69c4 100644 --- a/arch/riscv/kernel/suspend.c +++ b/arch/riscv/kernel/suspend.c @@ -8,7 +8,7 @@ #include #include -static void suspend_save_csrs(struct suspend_context *context) +void suspend_save_csrs(struct suspend_context *context) { context->scratch = csr_read(CSR_SCRATCH); context->tvec = csr_read(CSR_TVEC); @@ -29,7 +29,7 @@ static void suspend_save_csrs(struct suspend_context *context) #endif } -static void suspend_restore_csrs(struct suspend_context *context) +void suspend_restore_csrs(struct suspend_context *context) { csr_write(CSR_SCRATCH, context->scratch); csr_write(CSR_TVEC, context->tvec); diff --git a/arch/riscv/kernel/suspend_entry.S b/arch/riscv/kernel/suspend_entry.S index aafcca58c19d..12b52afe09a4 100644 --- a/arch/riscv/kernel/suspend_entry.S +++ b/arch/riscv/kernel/suspend_entry.S @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -83,39 +84,10 @@ ENTRY(__cpu_resume_enter) add a0, a1, zero /* Restore CSRs */ - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0) - csrw CSR_EPC, t0 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0) - csrw CSR_STATUS, t0 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0) - csrw CSR_TVAL, t0 - REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0) - csrw CSR_CAUSE, t0 + suspend_restore_csrs /* Restore registers (except A0 and T0-T6) */ - REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0) - REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0) - REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0) - REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0) - REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0) - REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0) - REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0) - REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0) - REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0) - REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0) - REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0) - REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0) - REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0) - REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0) - REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0) - REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0) - REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0) - REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0) - REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0) - REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0) - REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0) - REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0) - REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0) + suspend_restore_regs /* Return zero value */ add a0, zero, zero diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 5d3f2fbeb33c..5db29683ebee 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -6,9 +6,15 @@ */ #include -#include #include +#include +#include +#include +#include +#include +#include #include +#include static long riscv_sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, @@ -69,3 +75,225 @@ SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, return 0; } + +/* + * The hwprobe interface, for allowing userspace to probe to see which features + * are supported by the hardware. See Documentation/riscv/hwprobe.rst for more + * details. + */ +static void hwprobe_arch_id(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + u64 id = -1ULL; + bool first = true; + int cpu; + + for_each_cpu(cpu, cpus) { + u64 cpu_id; + + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + cpu_id = riscv_cached_mvendorid(cpu); + break; + case RISCV_HWPROBE_KEY_MIMPID: + cpu_id = riscv_cached_mimpid(cpu); + break; + case RISCV_HWPROBE_KEY_MARCHID: + cpu_id = riscv_cached_marchid(cpu); + break; + } + + if (first) { + id = cpu_id; + first = false; + } + + /* + * If there's a mismatch for the given set, return -1 in the + * value. + */ + if (id != cpu_id) { + id = -1ULL; + break; + } + } + + pair->value = id; +} + +static u64 hwprobe_misaligned(const struct cpumask *cpus) +{ + int cpu; + u64 perf = -1ULL; + + for_each_cpu(cpu, cpus) { + int this_perf = per_cpu(misaligned_access_speed, cpu); + + if (perf == -1ULL) + perf = this_perf; + + if (perf != this_perf) { + perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN; + break; + } + } + + if (perf == -1ULL) + return RISCV_HWPROBE_MISALIGNED_UNKNOWN; + + return perf; +} + +static void hwprobe_one_pair(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + case RISCV_HWPROBE_KEY_MARCHID: + case RISCV_HWPROBE_KEY_MIMPID: + hwprobe_arch_id(pair, cpus); + break; + /* + * The kernel already assumes that the base single-letter ISA + * extensions are supported on all harts, and only supports the + * IMA base, so just cheat a bit here and tell that to + * userspace. + */ + case RISCV_HWPROBE_KEY_BASE_BEHAVIOR: + pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA; + break; + + case RISCV_HWPROBE_KEY_IMA_EXT_0: + pair->value = 0; + if (has_fpu()) + pair->value |= RISCV_HWPROBE_IMA_FD; + + if (riscv_isa_extension_available(NULL, c)) + pair->value |= RISCV_HWPROBE_IMA_C; + + break; + + case RISCV_HWPROBE_KEY_CPUPERF_0: + pair->value = hwprobe_misaligned(cpus); + break; + + /* + * For forward compatibility, unknown keys don't fail the whole + * call, but get their element key set to -1 and value set to 0 + * indicating they're unrecognized. + */ + default: + pair->key = -1; + pair->value = 0; + break; + } +} + +static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs, + size_t pair_count, size_t cpu_count, + unsigned long __user *cpus_user, + unsigned int flags) +{ + size_t out; + int ret; + cpumask_t cpus; + + /* Check the reserved flags. */ + if (flags != 0) + return -EINVAL; + + /* + * The interface supports taking in a CPU mask, and returns values that + * are consistent across that mask. Allow userspace to specify NULL and + * 0 as a shortcut to all online CPUs. + */ + cpumask_clear(&cpus); + if (!cpu_count && !cpus_user) { + cpumask_copy(&cpus, cpu_online_mask); + } else { + if (cpu_count > cpumask_size()) + cpu_count = cpumask_size(); + + ret = copy_from_user(&cpus, cpus_user, cpu_count); + if (ret) + return -EFAULT; + + /* + * Userspace must provide at least one online CPU, without that + * there's no way to define what is supported. + */ + cpumask_and(&cpus, &cpus, cpu_online_mask); + if (cpumask_empty(&cpus)) + return -EINVAL; + } + + for (out = 0; out < pair_count; out++, pairs++) { + struct riscv_hwprobe pair; + + if (get_user(pair.key, &pairs->key)) + return -EFAULT; + + pair.value = 0; + hwprobe_one_pair(&pair, &cpus); + ret = put_user(pair.key, &pairs->key); + if (ret == 0) + ret = put_user(pair.value, &pairs->value); + + if (ret) + return -EFAULT; + } + + return 0; +} + +#ifdef CONFIG_MMU + +static int __init init_hwprobe_vdso_data(void) +{ + struct vdso_data *vd = __arch_get_k_vdso_data(); + struct arch_vdso_data *avd = &vd->arch_data; + u64 id_bitsmash = 0; + struct riscv_hwprobe pair; + int key; + + /* + * Initialize vDSO data with the answers for the "all CPUs" case, to + * save a syscall in the common case. + */ + for (key = 0; key <= RISCV_HWPROBE_MAX_KEY; key++) { + pair.key = key; + hwprobe_one_pair(&pair, cpu_online_mask); + + WARN_ON_ONCE(pair.key < 0); + + avd->all_cpu_hwprobe_values[key] = pair.value; + /* + * Smash together the vendor, arch, and impl IDs to see if + * they're all 0 or any negative. + */ + if (key <= RISCV_HWPROBE_KEY_MIMPID) + id_bitsmash |= pair.value; + } + + /* + * If the arch, vendor, and implementation ID are all the same across + * all harts, then assume all CPUs are the same, and allow the vDSO to + * answer queries for arbitrary masks. However if all values are 0 (not + * populated) or any value returns -1 (varies across CPUs), then the + * vDSO should defer to the kernel for exotic cpu masks. + */ + avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1; + return 0; +} + +arch_initcall_sync(init_hwprobe_vdso_data); + +#endif /* CONFIG_MMU */ + +SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs, + size_t, pair_count, size_t, cpu_count, unsigned long __user *, + cpus, unsigned int, flags) +{ + return do_riscv_hwprobe(pairs, pair_count, cpu_count, + cpus, flags); +} diff --git a/arch/riscv/kernel/trace_irq.c b/arch/riscv/kernel/trace_irq.c deleted file mode 100644 index 095ac976d7da..000000000000 --- a/arch/riscv/kernel/trace_irq.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2022 Changbin Du - */ - -#include -#include -#include "trace_irq.h" - -/* - * trace_hardirqs_on/off require the caller to setup frame pointer properly. - * Otherwise, CALLER_ADDR1 might trigger an pagging exception in kernel. - * Here we add one extra level so they can be safely called by low - * level entry code which $fp is used for other purpose. - */ - -void __trace_hardirqs_on(void) -{ - trace_hardirqs_on(); -} -NOKPROBE_SYMBOL(__trace_hardirqs_on); - -void __trace_hardirqs_off(void) -{ - trace_hardirqs_off(); -} -NOKPROBE_SYMBOL(__trace_hardirqs_off); diff --git a/arch/riscv/kernel/trace_irq.h b/arch/riscv/kernel/trace_irq.h deleted file mode 100644 index 99fe67377e5e..000000000000 --- a/arch/riscv/kernel/trace_irq.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2022 Changbin Du - */ -#ifndef __TRACE_IRQ_H -#define __TRACE_IRQ_H - -void __trace_hardirqs_on(void); -void __trace_hardirqs_off(void); - -#endif /* __TRACE_IRQ_H */ diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index f6fda94e8e59..8c258b78c925 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -17,12 +17,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include int show_unhandled_signals = 1; @@ -119,14 +121,22 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code, } #if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_RISCV_ALTERNATIVE) -#define __trap_section __section(".xip.traps") +#define __trap_section __noinstr_section(".xip.traps") #else -#define __trap_section +#define __trap_section noinstr #endif -#define DO_ERROR_INFO(name, signo, code, str) \ -asmlinkage __visible __trap_section void name(struct pt_regs *regs) \ -{ \ - do_trap_error(regs, signo, code, regs->epc, "Oops - " str); \ +#define DO_ERROR_INFO(name, signo, code, str) \ +asmlinkage __visible __trap_section void name(struct pt_regs *regs) \ +{ \ + if (user_mode(regs)) { \ + irqentry_enter_from_user_mode(regs); \ + do_trap_error(regs, signo, code, regs->epc, "Oops - " str); \ + irqentry_exit_to_user_mode(regs); \ + } else { \ + irqentry_state_t state = irqentry_nmi_enter(regs); \ + do_trap_error(regs, signo, code, regs->epc, "Oops - " str); \ + irqentry_nmi_exit(regs, state); \ + } \ } DO_ERROR_INFO(do_trap_unknown, @@ -148,26 +158,50 @@ DO_ERROR_INFO(do_trap_store_misaligned, int handle_misaligned_load(struct pt_regs *regs); int handle_misaligned_store(struct pt_regs *regs); -asmlinkage void __trap_section do_trap_load_misaligned(struct pt_regs *regs) +asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs) { - if (!handle_misaligned_load(regs)) - return; - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - load address misaligned"); + if (user_mode(regs)) { + irqentry_enter_from_user_mode(regs); + + if (handle_misaligned_load(regs)) + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, + "Oops - load address misaligned"); + + irqentry_exit_to_user_mode(regs); + } else { + irqentry_state_t state = irqentry_nmi_enter(regs); + + if (handle_misaligned_load(regs)) + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, + "Oops - load address misaligned"); + + irqentry_nmi_exit(regs, state); + } } -asmlinkage void __trap_section do_trap_store_misaligned(struct pt_regs *regs) +asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs) { - if (!handle_misaligned_store(regs)) - return; - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - store (or AMO) address misaligned"); + if (user_mode(regs)) { + irqentry_enter_from_user_mode(regs); + + if (handle_misaligned_store(regs)) + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, + "Oops - store (or AMO) address misaligned"); + + irqentry_exit_to_user_mode(regs); + } else { + irqentry_state_t state = irqentry_nmi_enter(regs); + + if (handle_misaligned_store(regs)) + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, + "Oops - store (or AMO) address misaligned"); + + irqentry_nmi_exit(regs, state); + } } #endif DO_ERROR_INFO(do_trap_store_fault, SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault"); -DO_ERROR_INFO(do_trap_ecall_u, - SIGILL, ILL_ILLTRP, "environment call from U-mode"); DO_ERROR_INFO(do_trap_ecall_s, SIGILL, ILL_ILLTRP, "environment call from S-mode"); DO_ERROR_INFO(do_trap_ecall_m, @@ -183,7 +217,7 @@ static inline unsigned long get_break_insn_length(unsigned long pc) return GET_INSN_LENGTH(insn); } -asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs) +void handle_break(struct pt_regs *regs) { #ifdef CONFIG_KPROBES if (kprobe_single_step_handler(regs)) @@ -213,7 +247,77 @@ asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs) else die(regs, "Kernel BUG"); } -NOKPROBE_SYMBOL(do_trap_break); + +asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs) +{ + if (user_mode(regs)) { + irqentry_enter_from_user_mode(regs); + + handle_break(regs); + + irqentry_exit_to_user_mode(regs); + } else { + irqentry_state_t state = irqentry_nmi_enter(regs); + + handle_break(regs); + + irqentry_nmi_exit(regs, state); + } +} + +asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs) +{ + if (user_mode(regs)) { + ulong syscall = regs->a7; + + regs->epc += 4; + regs->orig_a0 = regs->a0; + + syscall = syscall_enter_from_user_mode(regs, syscall); + + if (syscall < NR_syscalls) + syscall_handler(regs, syscall); + else + regs->a0 = -ENOSYS; + + syscall_exit_to_user_mode(regs); + } else { + irqentry_state_t state = irqentry_nmi_enter(regs); + + do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->epc, + "Oops - environment call from U-mode"); + + irqentry_nmi_exit(regs, state); + } + +} + +#ifdef CONFIG_MMU +asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + + handle_page_fault(regs); + + local_irq_disable(); + + irqentry_exit(regs, state); +} +#endif + +asmlinkage __visible noinstr void do_irq(struct pt_regs *regs) +{ + struct pt_regs *old_regs; + irqentry_state_t state = irqentry_enter(regs); + + irq_enter_rcu(); + old_regs = set_irq_regs(regs); + handle_arch_irq(regs); + set_irq_regs(old_regs); + irq_exit_rcu(); + + irqentry_exit(regs, state); +} #ifdef CONFIG_GENERIC_BUG int is_valid_bugaddr(unsigned long pc) diff --git a/arch/riscv/kernel/vdso.c b/arch/riscv/kernel/vdso.c index cc2d1e8c8736..9a68e7eaae4d 100644 --- a/arch/riscv/kernel/vdso.c +++ b/arch/riscv/kernel/vdso.c @@ -14,13 +14,7 @@ #include #include #include - -#ifdef CONFIG_GENERIC_TIME_VSYSCALL #include -#else -struct vdso_data { -}; -#endif enum vvar_pages { VVAR_DATA_PAGE_OFFSET, diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index a04b3bc35ca2..6b1dba11bf6d 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -10,6 +10,8 @@ vdso-syms += vgettimeofday endif vdso-syms += getcpu vdso-syms += flush_icache +vdso-syms += hwprobe +vdso-syms += sys_hwprobe # Files to link into the vdso obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o @@ -21,6 +23,8 @@ ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y) endif +CFLAGS_hwprobe.o += -fPIC + # Build rules targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c new file mode 100644 index 000000000000..d40bec6ac078 --- /dev/null +++ b/arch/riscv/kernel/vdso/hwprobe.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 Rivos, Inc + */ + +#include +#include +#include + +extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, + unsigned int flags); + +/* Add a prototype to avoid -Wmissing-prototypes warning. */ +int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, + unsigned int flags); + +int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, + unsigned int flags) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + const struct arch_vdso_data *avd = &vd->arch_data; + bool all_cpus = !cpu_count && !cpus; + struct riscv_hwprobe *p = pairs; + struct riscv_hwprobe *end = pairs + pair_count; + + /* + * Defer to the syscall for exotic requests. The vdso has answers + * stashed away only for the "all cpus" case. If all CPUs are + * homogeneous, then this function can handle requests for arbitrary + * masks. + */ + if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus)) + return riscv_hwprobe(pairs, pair_count, cpu_count, cpus, flags); + + /* This is something we can handle, fill out the pairs. */ + while (p < end) { + if (p->key <= RISCV_HWPROBE_MAX_KEY) { + p->value = avd->all_cpu_hwprobe_values[p->key]; + + } else { + p->key = -1; + p->value = 0; + } + + p++; + } + + return 0; +} diff --git a/arch/riscv/kernel/vdso/sys_hwprobe.S b/arch/riscv/kernel/vdso/sys_hwprobe.S new file mode 100644 index 000000000000..4e704146c77a --- /dev/null +++ b/arch/riscv/kernel/vdso/sys_hwprobe.S @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2023 Rivos, Inc */ + +#include +#include + +.text +ENTRY(riscv_hwprobe) + .cfi_startproc + li a7, __NR_riscv_hwprobe + ecall + ret + + .cfi_endproc +ENDPROC(riscv_hwprobe) diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S index 4a0606633290..82ce64900f3d 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S @@ -82,6 +82,9 @@ VERSION #endif __vdso_getcpu; __vdso_flush_icache; +#ifndef COMPAT_VDSO + __vdso_riscv_hwprobe; +#endif local: *; }; } diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 53a8ad65b255..e5f9f4677bbf 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -27,9 +27,6 @@ ENTRY(_start) jiffies = jiffies_64; -PECOFF_SECTION_ALIGNMENT = 0x1000; -PECOFF_FILE_ALIGNMENT = 0x200; - SECTIONS { /* Beginning of code and text segment */ @@ -86,6 +83,11 @@ SECTIONS /* Start of init data section */ __init_data_begin = .; INIT_DATA_SECTION(16) + + .init.pi : { + *(.init.pi*) + } + .init.bss : { *(.init.bss) /* from the EFI stub */ } @@ -99,8 +101,10 @@ SECTIONS *(.rel.dyn*) } - .rela.dyn : { - *(.rela*) + .rela.dyn : ALIGN(8) { + __rela_dyn_start = .; + *(.rela .rela*) + __rela_dyn_end = .; } __init_data_end = .; @@ -129,9 +133,22 @@ SECTIONS *(.sdata*) } + .got : { *(.got*) } + +#ifdef CONFIG_RELOCATABLE + .data.rel : { *(.data.rel*) } + .plt : { *(.plt) } + .dynamic : { *(.dynamic) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } +#endif + #ifdef CONFIG_EFI .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); } __pecoff_data_raw_size = ABSOLUTE(. - __pecoff_text_end); + __pecoff_data_raw_end = ABSOLUTE(.); #endif /* End of data section */ @@ -142,6 +159,7 @@ SECTIONS #ifdef CONFIG_EFI . = ALIGN(PECOFF_SECTION_ALIGNMENT); __pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end); + __pecoff_data_virt_end = ABSOLUTE(.); #endif _end = .; diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index 5682d8c017b3..28891e583259 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -20,14 +20,14 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)" depends on RISCV_SBI && MMU + select HAVE_KVM_EVENTFD + select HAVE_KVM_VCPU_ASYNC_IOCTL + select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING + select KVM_MMIO + select KVM_XFER_TO_GUEST_WORK select MMU_NOTIFIER select PREEMPT_NOTIFIERS - select KVM_MMIO - select KVM_GENERIC_DIRTYLOG_READ_PROTECT - select KVM_XFER_TO_GUEST_WORK - select HAVE_KVM_VCPU_ASYNC_IOCTL - select HAVE_KVM_EVENTFD help Support hosting virtualized guest machines. diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index 278e97c06e0a..8031b8912a0d 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -26,3 +26,4 @@ kvm-y += vcpu_sbi_replace.o kvm-y += vcpu_sbi_hsm.o kvm-y += vcpu_timer.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o +kvm-y += aia.o diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c new file mode 100644 index 000000000000..4f1286fc7f17 --- /dev/null +++ b/arch/riscv/kvm/aia.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + * Copyright (C) 2022 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include + +DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available); + +static void aia_set_hvictl(bool ext_irq_pending) +{ + unsigned long hvictl; + + /* + * HVICTL.IID == 9 and HVICTL.IPRIO == 0 represents + * no interrupt in HVICTL. + */ + + hvictl = (IRQ_S_EXT << HVICTL_IID_SHIFT) & HVICTL_IID; + hvictl |= ext_irq_pending; + csr_write(CSR_HVICTL, hvictl); +} + +#ifdef CONFIG_32BIT +void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long mask, val; + + if (!kvm_riscv_aia_available()) + return; + + if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) { + mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0); + val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask; + + csr->hviph &= ~mask; + csr->hviph |= val; + } +} + +void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + + if (kvm_riscv_aia_available()) + csr->vsieh = csr_read(CSR_VSIEH); +} +#endif + +bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) +{ + unsigned long seip; + + if (!kvm_riscv_aia_available()) + return false; + +#ifdef CONFIG_32BIT + if (READ_ONCE(vcpu->arch.irqs_pending[1]) & + (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask))) + return true; +#endif + + seip = vcpu->arch.guest_csr.vsie; + seip &= (unsigned long)mask; + seip &= BIT(IRQ_S_EXT); + + if (!kvm_riscv_aia_initialized(vcpu->kvm) || !seip) + return false; + + return false; +} + +void kvm_riscv_vcpu_aia_update_hvip(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + + if (!kvm_riscv_aia_available()) + return; + +#ifdef CONFIG_32BIT + csr_write(CSR_HVIPH, vcpu->arch.aia_context.guest_csr.hviph); +#endif + aia_set_hvictl(!!(csr->hvip & BIT(IRQ_VS_EXT))); +} + +void kvm_riscv_vcpu_aia_load(struct kvm_vcpu *vcpu, int cpu) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + + if (!kvm_riscv_aia_available()) + return; + + csr_write(CSR_VSISELECT, csr->vsiselect); + csr_write(CSR_HVIPRIO1, csr->hviprio1); + csr_write(CSR_HVIPRIO2, csr->hviprio2); +#ifdef CONFIG_32BIT + csr_write(CSR_VSIEH, csr->vsieh); + csr_write(CSR_HVIPH, csr->hviph); + csr_write(CSR_HVIPRIO1H, csr->hviprio1h); + csr_write(CSR_HVIPRIO2H, csr->hviprio2h); +#endif +} + +void kvm_riscv_vcpu_aia_put(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + + if (!kvm_riscv_aia_available()) + return; + + csr->vsiselect = csr_read(CSR_VSISELECT); + csr->hviprio1 = csr_read(CSR_HVIPRIO1); + csr->hviprio2 = csr_read(CSR_HVIPRIO2); +#ifdef CONFIG_32BIT + csr->vsieh = csr_read(CSR_VSIEH); + csr->hviph = csr_read(CSR_HVIPH); + csr->hviprio1h = csr_read(CSR_HVIPRIO1H); + csr->hviprio2h = csr_read(CSR_HVIPRIO2H); +#endif +} + +int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *out_val) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + + if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) + return -EINVAL; + + *out_val = 0; + if (kvm_riscv_aia_available()) + *out_val = ((unsigned long *)csr)[reg_num]; + + return 0; +} + +int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long val) +{ + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + + if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) + return -EINVAL; + + if (kvm_riscv_aia_available()) { + ((unsigned long *)csr)[reg_num] = val; + +#ifdef CONFIG_32BIT + if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) + WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0); +#endif + } + + return 0; +} + +int kvm_riscv_vcpu_aia_rmw_topei(struct kvm_vcpu *vcpu, + unsigned int csr_num, + unsigned long *val, + unsigned long new_val, + unsigned long wr_mask) +{ + /* If AIA not available then redirect trap */ + if (!kvm_riscv_aia_available()) + return KVM_INSN_ILLEGAL_TRAP; + + /* If AIA not initialized then forward to user space */ + if (!kvm_riscv_aia_initialized(vcpu->kvm)) + return KVM_INSN_EXIT_TO_USER_SPACE; + + return kvm_riscv_vcpu_aia_imsic_rmw(vcpu, KVM_RISCV_AIA_IMSIC_TOPEI, + val, new_val, wr_mask); +} + +/* + * External IRQ priority always read-only zero. This means default + * priority order is always preferred for external IRQs unless + * HVICTL.IID == 9 and HVICTL.IPRIO != 0 + */ +static int aia_irq2bitpos[] = { +0, 8, -1, -1, 16, 24, -1, -1, /* 0 - 7 */ +32, -1, -1, -1, -1, 40, 48, 56, /* 8 - 15 */ +64, 72, 80, 88, 96, 104, 112, 120, /* 16 - 23 */ +-1, -1, -1, -1, -1, -1, -1, -1, /* 24 - 31 */ +-1, -1, -1, -1, -1, -1, -1, -1, /* 32 - 39 */ +-1, -1, -1, -1, -1, -1, -1, -1, /* 40 - 47 */ +-1, -1, -1, -1, -1, -1, -1, -1, /* 48 - 55 */ +-1, -1, -1, -1, -1, -1, -1, -1, /* 56 - 63 */ +}; + +static u8 aia_get_iprio8(struct kvm_vcpu *vcpu, unsigned int irq) +{ + unsigned long hviprio; + int bitpos = aia_irq2bitpos[irq]; + + if (bitpos < 0) + return 0; + + switch (bitpos / BITS_PER_LONG) { + case 0: + hviprio = csr_read(CSR_HVIPRIO1); + break; + case 1: +#ifndef CONFIG_32BIT + hviprio = csr_read(CSR_HVIPRIO2); + break; +#else + hviprio = csr_read(CSR_HVIPRIO1H); + break; + case 2: + hviprio = csr_read(CSR_HVIPRIO2); + break; + case 3: + hviprio = csr_read(CSR_HVIPRIO2H); + break; +#endif + default: + return 0; + } + + return (hviprio >> (bitpos % BITS_PER_LONG)) & TOPI_IPRIO_MASK; +} + +static void aia_set_iprio8(struct kvm_vcpu *vcpu, unsigned int irq, u8 prio) +{ + unsigned long hviprio; + int bitpos = aia_irq2bitpos[irq]; + + if (bitpos < 0) + return; + + switch (bitpos / BITS_PER_LONG) { + case 0: + hviprio = csr_read(CSR_HVIPRIO1); + break; + case 1: +#ifndef CONFIG_32BIT + hviprio = csr_read(CSR_HVIPRIO2); + break; +#else + hviprio = csr_read(CSR_HVIPRIO1H); + break; + case 2: + hviprio = csr_read(CSR_HVIPRIO2); + break; + case 3: + hviprio = csr_read(CSR_HVIPRIO2H); + break; +#endif + default: + return; + } + + hviprio &= ~(TOPI_IPRIO_MASK << (bitpos % BITS_PER_LONG)); + hviprio |= (unsigned long)prio << (bitpos % BITS_PER_LONG); + + switch (bitpos / BITS_PER_LONG) { + case 0: + csr_write(CSR_HVIPRIO1, hviprio); + break; + case 1: +#ifndef CONFIG_32BIT + csr_write(CSR_HVIPRIO2, hviprio); + break; +#else + csr_write(CSR_HVIPRIO1H, hviprio); + break; + case 2: + csr_write(CSR_HVIPRIO2, hviprio); + break; + case 3: + csr_write(CSR_HVIPRIO2H, hviprio); + break; +#endif + default: + return; + } +} + +static int aia_rmw_iprio(struct kvm_vcpu *vcpu, unsigned int isel, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask) +{ + int i, first_irq, nirqs; + unsigned long old_val; + u8 prio; + +#ifndef CONFIG_32BIT + if (isel & 0x1) + return KVM_INSN_ILLEGAL_TRAP; +#endif + + nirqs = 4 * (BITS_PER_LONG / 32); + first_irq = (isel - ISELECT_IPRIO0) * 4; + + old_val = 0; + for (i = 0; i < nirqs; i++) { + prio = aia_get_iprio8(vcpu, first_irq + i); + old_val |= (unsigned long)prio << (TOPI_IPRIO_BITS * i); + } + + if (val) + *val = old_val; + + if (wr_mask) { + new_val = (old_val & ~wr_mask) | (new_val & wr_mask); + for (i = 0; i < nirqs; i++) { + prio = (new_val >> (TOPI_IPRIO_BITS * i)) & + TOPI_IPRIO_MASK; + aia_set_iprio8(vcpu, first_irq + i, prio); + } + } + + return KVM_INSN_CONTINUE_NEXT_SEPC; +} + +#define IMSIC_FIRST 0x70 +#define IMSIC_LAST 0xff +int kvm_riscv_vcpu_aia_rmw_ireg(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask) +{ + unsigned int isel; + + /* If AIA not available then redirect trap */ + if (!kvm_riscv_aia_available()) + return KVM_INSN_ILLEGAL_TRAP; + + /* First try to emulate in kernel space */ + isel = csr_read(CSR_VSISELECT) & ISELECT_MASK; + if (isel >= ISELECT_IPRIO0 && isel <= ISELECT_IPRIO15) + return aia_rmw_iprio(vcpu, isel, val, new_val, wr_mask); + else if (isel >= IMSIC_FIRST && isel <= IMSIC_LAST && + kvm_riscv_aia_initialized(vcpu->kvm)) + return kvm_riscv_vcpu_aia_imsic_rmw(vcpu, isel, val, new_val, + wr_mask); + + /* We can't handle it here so redirect to user space */ + return KVM_INSN_EXIT_TO_USER_SPACE; +} + +void kvm_riscv_aia_enable(void) +{ + if (!kvm_riscv_aia_available()) + return; + + aia_set_hvictl(false); + csr_write(CSR_HVIPRIO1, 0x0); + csr_write(CSR_HVIPRIO2, 0x0); +#ifdef CONFIG_32BIT + csr_write(CSR_HVIPH, 0x0); + csr_write(CSR_HIDELEGH, 0x0); + csr_write(CSR_HVIPRIO1H, 0x0); + csr_write(CSR_HVIPRIO2H, 0x0); +#endif +} + +void kvm_riscv_aia_disable(void) +{ + if (!kvm_riscv_aia_available()) + return; + + aia_set_hvictl(false); +} + +int kvm_riscv_aia_init(void) +{ + if (!riscv_isa_extension_available(NULL, SxAIA)) + return -ENODEV; + + /* Enable KVM AIA support */ + static_branch_enable(&kvm_riscv_aia_available); + + return 0; +} + +void kvm_riscv_aia_exit(void) +{ +} diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index 41ad7639a17b..a7112d583637 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -44,11 +44,15 @@ int kvm_arch_hardware_enable(void) csr_write(CSR_HVIP, 0); + kvm_riscv_aia_enable(); + return 0; } void kvm_arch_hardware_disable(void) { + kvm_riscv_aia_disable(); + /* * After clearing the hideleg CSR, the host kernel will receive * spurious interrupts if hvip CSR has pending interrupts and the @@ -63,6 +67,7 @@ void kvm_arch_hardware_disable(void) static int __init riscv_kvm_init(void) { + int rc; const char *str; if (!riscv_isa_extension_available(NULL, h)) { @@ -75,7 +80,7 @@ static int __init riscv_kvm_init(void) return -ENODEV; } - if (sbi_probe_extension(SBI_EXT_RFENCE) <= 0) { + if (!sbi_probe_extension(SBI_EXT_RFENCE)) { kvm_info("require SBI RFENCE extension\n"); return -ENODEV; } @@ -84,6 +89,10 @@ static int __init riscv_kvm_init(void) kvm_riscv_gstage_vmid_detect(); + rc = kvm_riscv_aia_init(); + if (rc && rc != -ENODEV) + return rc; + kvm_info("hypervisor extension available\n"); switch (kvm_riscv_gstage_mode()) { @@ -106,12 +115,23 @@ static int __init riscv_kvm_init(void) kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); - return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); + if (kvm_riscv_aia_available()) + kvm_info("AIA available\n"); + + rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); + if (rc) { + kvm_riscv_aia_exit(); + return rc; + } + + return 0; } module_init(riscv_kvm_init); static void __exit riscv_kvm_exit(void) { + kvm_riscv_aia_exit(); + kvm_exit(); } module_exit(riscv_kvm_exit); diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 78211aed36fa..f2eb47925806 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -628,6 +628,13 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, !(memslot->flags & KVM_MEM_READONLY)) ? true : false; unsigned long vma_pagesize, mmu_seq; + /* We need minimum second+third level pages */ + ret = kvm_mmu_topup_memory_cache(pcache, gstage_pgd_levels); + if (ret) { + kvm_err("Failed to topup G-stage cache\n"); + return ret; + } + mmap_read_lock(current->mm); vma = vma_lookup(current->mm, hva); @@ -648,6 +655,15 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) gfn = (gpa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT; + /* + * Read mmu_invalidate_seq so that KVM can detect if the results of + * vma_lookup() or gfn_to_pfn_prot() become stale priort to acquiring + * kvm->mmu_lock. + * + * Rely on mmap_read_unlock() for an implicit smp_rmb(), which pairs + * with the smp_wmb() in kvm_mmu_invalidate_end(). + */ + mmu_seq = kvm->mmu_invalidate_seq; mmap_read_unlock(current->mm); if (vma_pagesize != PUD_SIZE && @@ -657,15 +673,6 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, return -EFAULT; } - /* We need minimum second+third level pages */ - ret = kvm_mmu_topup_memory_cache(pcache, gstage_pgd_levels); - if (ret) { - kvm_err("Failed to topup G-stage cache\n"); - return ret; - } - - mmu_seq = kvm->mmu_invalidate_seq; - hfn = gfn_to_pfn_prot(kvm, gfn, is_write, &writable); if (hfn == KVM_PFN_ERR_HWPOISON) { send_sig_mceerr(BUS_MCEERR_AR, (void __user *)hva, @@ -748,8 +755,7 @@ void kvm_riscv_gstage_update_hgatp(struct kvm_vcpu *vcpu) unsigned long hgatp = gstage_mode; struct kvm_arch *k = &vcpu->kvm->arch; - hgatp |= (READ_ONCE(k->vmid.vmid) << HGATP_VMID_SHIFT) & - HGATP_VMID_MASK; + hgatp |= (READ_ONCE(k->vmid.vmid) << HGATP_VMID_SHIFT) & HGATP_VMID; hgatp |= (k->pgd_phys >> PAGE_SHIFT) & HGATP_PPN; csr_write(CSR_HGATP, hgatp); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 7d010b0be54e..8bd9f2a8a0b9 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -58,11 +58,14 @@ static const unsigned long kvm_isa_ext_arr[] = { [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, + KVM_ISA_EXT_ARR(SSAIA), KVM_ISA_EXT_ARR(SSTC), KVM_ISA_EXT_ARR(SVINVAL), KVM_ISA_EXT_ARR(SVPBMT), + KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZICBOM), + KVM_ISA_EXT_ARR(ZICBOZ), }; static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) @@ -96,9 +99,11 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_C: case KVM_RISCV_ISA_EXT_I: case KVM_RISCV_ISA_EXT_M: + case KVM_RISCV_ISA_EXT_SSAIA: case KVM_RISCV_ISA_EXT_SSTC: case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: + case KVM_RISCV_ISA_EXT_ZBB: return false; default: break; @@ -135,8 +140,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) kvm_riscv_vcpu_timer_reset(vcpu); - WRITE_ONCE(vcpu->arch.irqs_pending, 0); - WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0); + kvm_riscv_vcpu_aia_reset(vcpu); + + bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); kvm_riscv_vcpu_pmu_reset(vcpu); @@ -157,6 +164,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) { + int rc; struct kvm_cpu_context *cntx; struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr; unsigned long host_isa, i; @@ -199,6 +207,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) /* setup performance monitoring */ kvm_riscv_vcpu_pmu_init(vcpu); + /* Setup VCPU AIA */ + rc = kvm_riscv_vcpu_aia_init(vcpu); + if (rc) + return rc; + /* Reset VCPU */ kvm_riscv_reset_vcpu(vcpu); @@ -218,6 +231,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + /* Cleanup VCPU AIA context */ + kvm_riscv_vcpu_aia_deinit(vcpu); + /* Cleanup VCPU timer */ kvm_riscv_vcpu_timer_deinit(vcpu); @@ -283,6 +299,11 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, return -EINVAL; reg_val = riscv_cbom_block_size; break; + case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + return -EINVAL; + reg_val = riscv_cboz_block_size; + break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): reg_val = vcpu->arch.mvendorid; break; @@ -354,6 +375,8 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): return -EOPNOTSUPP; + case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): + return -EOPNOTSUPP; case KVM_REG_RISCV_CONFIG_REG(mvendorid): if (!vcpu->arch.ran_atleast_once) vcpu->arch.mvendorid = reg_val; @@ -447,27 +470,76 @@ static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu, return 0; } -static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) +static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *out_val) { struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CSR); - unsigned long reg_val; - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) return -EINVAL; if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { kvm_riscv_vcpu_flush_interrupts(vcpu); - reg_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK; + *out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK; + *out_val |= csr->hvip & ~IRQ_LOCAL_MASK; } else - reg_val = ((unsigned long *)csr)[reg_num]; + *out_val = ((unsigned long *)csr)[reg_num]; + + return 0; +} + +static inline int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val) +{ + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -EINVAL; + + if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { + reg_val &= VSIP_VALID_MASK; + reg_val <<= VSIP_TO_HVIP_SHIFT; + } + + ((unsigned long *)csr)[reg_num] = reg_val; + + if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) + WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); + + return 0; +} + +static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + int rc; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CSR); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + switch (reg_subtype) { + case KVM_REG_RISCV_CSR_GENERAL: + rc = kvm_riscv_vcpu_general_get_csr(vcpu, reg_num, ®_val); + break; + case KVM_REG_RISCV_CSR_AIA: + rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, ®_val); + break; + default: + rc = -EINVAL; + break; + } + if (rc) + return rc; if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -478,31 +550,35 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { - struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + int rc; unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_RISCV_CSR); - unsigned long reg_val; + unsigned long reg_val, reg_subtype; if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; - if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) - return -EINVAL; if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) return -EFAULT; - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { - reg_val &= VSIP_VALID_MASK; - reg_val <<= VSIP_TO_HVIP_SHIFT; + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + switch (reg_subtype) { + case KVM_REG_RISCV_CSR_GENERAL: + rc = kvm_riscv_vcpu_general_set_csr(vcpu, reg_num, reg_val); + break; + case KVM_REG_RISCV_CSR_AIA: + rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val); + break; + default: + rc = -EINVAL; + break; } - - ((unsigned long *)csr)[reg_num] = reg_val; - - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) - WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0); + if (rc) + return rc; return 0; } @@ -601,6 +677,8 @@ static int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, KVM_REG_RISCV_FP_D); case KVM_REG_RISCV_ISA_EXT: return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg); + case KVM_REG_RISCV_SBI_EXT: + return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg); default: break; } @@ -628,6 +706,8 @@ static int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, KVM_REG_RISCV_FP_D); case KVM_REG_RISCV_ISA_EXT: return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg); + case KVM_REG_RISCV_SBI_EXT: + return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg); default: break; } @@ -728,13 +808,16 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; unsigned long mask, val; - if (READ_ONCE(vcpu->arch.irqs_pending_mask)) { - mask = xchg_acquire(&vcpu->arch.irqs_pending_mask, 0); - val = READ_ONCE(vcpu->arch.irqs_pending) & mask; + if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) { + mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0); + val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask; csr->hvip &= ~mask; csr->hvip |= val; } + + /* Flush AIA high interrupts */ + kvm_riscv_vcpu_aia_flush_interrupts(vcpu); } void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) @@ -751,29 +834,38 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { if (hvip & (1UL << IRQ_VS_SOFT)) { if (!test_and_set_bit(IRQ_VS_SOFT, - &v->irqs_pending_mask)) - set_bit(IRQ_VS_SOFT, &v->irqs_pending); + v->irqs_pending_mask)) + set_bit(IRQ_VS_SOFT, v->irqs_pending); } else { if (!test_and_set_bit(IRQ_VS_SOFT, - &v->irqs_pending_mask)) - clear_bit(IRQ_VS_SOFT, &v->irqs_pending); + v->irqs_pending_mask)) + clear_bit(IRQ_VS_SOFT, v->irqs_pending); } } + /* Sync-up AIA high interrupts */ + kvm_riscv_vcpu_aia_sync_interrupts(vcpu); + /* Sync-up timer CSRs */ kvm_riscv_vcpu_timer_sync(vcpu); } int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) { - if (irq != IRQ_VS_SOFT && + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts + * defined by RISC-V privilege specification. + */ + if (irq < IRQ_LOCAL_MAX && + irq != IRQ_VS_SOFT && irq != IRQ_VS_TIMER && irq != IRQ_VS_EXT) return -EINVAL; - set_bit(irq, &vcpu->arch.irqs_pending); + set_bit(irq, vcpu->arch.irqs_pending); smp_mb__before_atomic(); - set_bit(irq, &vcpu->arch.irqs_pending_mask); + set_bit(irq, vcpu->arch.irqs_pending_mask); kvm_vcpu_kick(vcpu); @@ -782,24 +874,37 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) { - if (irq != IRQ_VS_SOFT && + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts + * defined by RISC-V privilege specification. + */ + if (irq < IRQ_LOCAL_MAX && + irq != IRQ_VS_SOFT && irq != IRQ_VS_TIMER && irq != IRQ_VS_EXT) return -EINVAL; - clear_bit(irq, &vcpu->arch.irqs_pending); + clear_bit(irq, vcpu->arch.irqs_pending); smp_mb__before_atomic(); - set_bit(irq, &vcpu->arch.irqs_pending_mask); + set_bit(irq, vcpu->arch.irqs_pending_mask); return 0; } -bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, unsigned long mask) +bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) { - unsigned long ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) - << VSIP_TO_HVIP_SHIFT) & mask; + unsigned long ie; - return (READ_ONCE(vcpu->arch.irqs_pending) & ie) ? true : false; + ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) + << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask; + ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & + (unsigned long)mask; + if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie) + return true; + + /* Check AIA high interrupts */ + return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); } void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu) @@ -865,6 +970,9 @@ static void kvm_riscv_vcpu_update_config(const unsigned long *isa) if (riscv_isa_extension_available(isa, ZICBOM)) henvcfg |= (ENVCFG_CBIE | ENVCFG_CBCFE); + if (riscv_isa_extension_available(isa, ZICBOZ)) + henvcfg |= ENVCFG_CBZE; + csr_write(CSR_HENVCFG, henvcfg); #ifdef CONFIG_32BIT csr_write(CSR_HENVCFGH, henvcfg >> 32); @@ -895,6 +1003,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_riscv_vcpu_guest_fp_restore(&vcpu->arch.guest_context, vcpu->arch.isa); + kvm_riscv_vcpu_aia_load(vcpu, cpu); + vcpu->cpu = cpu; } @@ -904,6 +1014,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) vcpu->cpu = -1; + kvm_riscv_vcpu_aia_put(vcpu); + kvm_riscv_vcpu_guest_fp_save(&vcpu->arch.guest_context, vcpu->arch.isa); kvm_riscv_vcpu_host_fp_restore(&vcpu->arch.host_context); @@ -971,6 +1083,7 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu) struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; csr_write(CSR_HVIP, csr->hvip); + kvm_riscv_vcpu_aia_update_hvip(vcpu); } /* @@ -1043,6 +1156,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_riscv_check_vcpu_requests(vcpu); + preempt_disable(); + + /* Update AIA HW state before entering guest */ + ret = kvm_riscv_vcpu_aia_update(vcpu); + if (ret <= 0) { + preempt_enable(); + continue; + } + local_irq_disable(); /* @@ -1071,6 +1193,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) xfer_to_guest_mode_work_pending()) { vcpu->mode = OUTSIDE_GUEST_MODE; local_irq_enable(); + preempt_enable(); kvm_vcpu_srcu_read_lock(vcpu); continue; } @@ -1104,8 +1227,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) /* Syncup interrupts state with HW */ kvm_riscv_vcpu_sync_interrupts(vcpu); - preempt_disable(); - /* * We must ensure that any pending interrupts are taken before * we exit guest timing so that timer ticks are accounted as diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index f689337b78ff..7a6abed41bc1 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -214,6 +214,7 @@ struct csr_func { }; static const struct csr_func csr_funcs[] = { + KVM_RISCV_VCPU_AIA_CSR_FUNCS KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS }; diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 15fde15f9fb8..e52fde504433 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -30,17 +30,52 @@ static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { }; #endif -static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { - &vcpu_sbi_ext_v01, - &vcpu_sbi_ext_base, - &vcpu_sbi_ext_time, - &vcpu_sbi_ext_ipi, - &vcpu_sbi_ext_rfence, - &vcpu_sbi_ext_srst, - &vcpu_sbi_ext_hsm, - &vcpu_sbi_ext_pmu, - &vcpu_sbi_ext_experimental, - &vcpu_sbi_ext_vendor, +struct kvm_riscv_sbi_extension_entry { + enum KVM_RISCV_SBI_EXT_ID dis_idx; + const struct kvm_vcpu_sbi_extension *ext_ptr; +}; + +static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { + { + .dis_idx = KVM_RISCV_SBI_EXT_V01, + .ext_ptr = &vcpu_sbi_ext_v01, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_MAX, /* Can't be disabled */ + .ext_ptr = &vcpu_sbi_ext_base, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_TIME, + .ext_ptr = &vcpu_sbi_ext_time, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_IPI, + .ext_ptr = &vcpu_sbi_ext_ipi, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_RFENCE, + .ext_ptr = &vcpu_sbi_ext_rfence, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_SRST, + .ext_ptr = &vcpu_sbi_ext_srst, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_HSM, + .ext_ptr = &vcpu_sbi_ext_hsm, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_PMU, + .ext_ptr = &vcpu_sbi_ext_pmu, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL, + .ext_ptr = &vcpu_sbi_ext_experimental, + }, + { + .dis_idx = KVM_RISCV_SBI_EXT_VENDOR, + .ext_ptr = &vcpu_sbi_ext_vendor, + }, }; void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run) @@ -99,14 +134,192 @@ int kvm_riscv_vcpu_sbi_return(struct kvm_vcpu *vcpu, struct kvm_run *run) return 0; } -const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(unsigned long extid) +static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val) { - int i = 0; + unsigned long i; + const struct kvm_riscv_sbi_extension_entry *sext = NULL; + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + + if (reg_num >= KVM_RISCV_SBI_EXT_MAX || + (reg_val != 1 && reg_val != 0)) + return -EINVAL; for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { - if (sbi_ext[i]->extid_start <= extid && - sbi_ext[i]->extid_end >= extid) - return sbi_ext[i]; + if (sbi_ext[i].dis_idx == reg_num) { + sext = &sbi_ext[i]; + break; + } + } + if (!sext) + return -ENOENT; + + scontext->extension_disabled[sext->dis_idx] = !reg_val; + + return 0; +} + +static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *reg_val) +{ + unsigned long i; + const struct kvm_riscv_sbi_extension_entry *sext = NULL; + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + + if (reg_num >= KVM_RISCV_SBI_EXT_MAX) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + if (sbi_ext[i].dis_idx == reg_num) { + sext = &sbi_ext[i]; + break; + } + } + if (!sext) + return -ENOENT; + + *reg_val = !scontext->extension_disabled[sext->dis_idx]; + + return 0; +} + +static int riscv_vcpu_set_sbi_ext_multi(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val, bool enable) +{ + unsigned long i, ext_id; + + if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST) + return -EINVAL; + + for_each_set_bit(i, ®_val, BITS_PER_LONG) { + ext_id = i + reg_num * BITS_PER_LONG; + if (ext_id >= KVM_RISCV_SBI_EXT_MAX) + break; + + riscv_vcpu_set_sbi_ext_single(vcpu, ext_id, enable); + } + + return 0; +} + +static int riscv_vcpu_get_sbi_ext_multi(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *reg_val) +{ + unsigned long i, ext_id, ext_val; + + if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST) + return -EINVAL; + + for (i = 0; i < BITS_PER_LONG; i++) { + ext_id = i + reg_num * BITS_PER_LONG; + if (ext_id >= KVM_RISCV_SBI_EXT_MAX) + break; + + ext_val = 0; + riscv_vcpu_get_sbi_ext_single(vcpu, ext_id, &ext_val); + if (ext_val) + *reg_val |= KVM_REG_RISCV_SBI_MULTI_MASK(ext_id); + } + + return 0; +} + +int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_SBI_EXT); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (vcpu->arch.ran_atleast_once) + return -EBUSY; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_SINGLE: + return riscv_vcpu_set_sbi_ext_single(vcpu, reg_num, reg_val); + case KVM_REG_RISCV_SBI_MULTI_EN: + return riscv_vcpu_set_sbi_ext_multi(vcpu, reg_num, reg_val, true); + case KVM_REG_RISCV_SBI_MULTI_DIS: + return riscv_vcpu_set_sbi_ext_multi(vcpu, reg_num, reg_val, false); + default: + return -EINVAL; + } + + return 0; +} + +int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + int rc; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_SBI_EXT); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + reg_val = 0; + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_SINGLE: + rc = riscv_vcpu_get_sbi_ext_single(vcpu, reg_num, ®_val); + break; + case KVM_REG_RISCV_SBI_MULTI_EN: + case KVM_REG_RISCV_SBI_MULTI_DIS: + rc = riscv_vcpu_get_sbi_ext_multi(vcpu, reg_num, ®_val); + if (!rc && reg_subtype == KVM_REG_RISCV_SBI_MULTI_DIS) + reg_val = ~reg_val; + break; + default: + rc = -EINVAL; + } + if (rc) + return rc; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( + struct kvm_vcpu *vcpu, unsigned long extid) +{ + int i; + const struct kvm_riscv_sbi_extension_entry *sext; + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + sext = &sbi_ext[i]; + if (sext->ext_ptr->extid_start <= extid && + sext->ext_ptr->extid_end >= extid) { + if (sext->dis_idx < KVM_RISCV_SBI_EXT_MAX && + scontext->extension_disabled[sext->dis_idx]) + return NULL; + return sbi_ext[i].ext_ptr; + } } return NULL; @@ -126,7 +339,7 @@ int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run) }; bool ext_is_v01 = false; - sbi_ext = kvm_vcpu_sbi_find_ext(cp->a7); + sbi_ext = kvm_vcpu_sbi_find_ext(vcpu, cp->a7); if (sbi_ext && sbi_ext->handler) { #ifdef CONFIG_RISCV_SBI_V01 if (cp->a7 >= SBI_EXT_0_1_SET_TIMER && diff --git a/arch/riscv/kvm/vcpu_sbi_base.c b/arch/riscv/kvm/vcpu_sbi_base.c index 9945aff34c14..5bc570b984f4 100644 --- a/arch/riscv/kvm/vcpu_sbi_base.c +++ b/arch/riscv/kvm/vcpu_sbi_base.c @@ -44,7 +44,7 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, kvm_riscv_vcpu_sbi_forward(vcpu, run); retdata->uexit = true; } else { - sbi_ext = kvm_vcpu_sbi_find_ext(cp->a0); + sbi_ext = kvm_vcpu_sbi_find_ext(vcpu, cp->a0); *out_val = sbi_ext && sbi_ext->probe ? sbi_ext->probe(vcpu) : !!sbi_ext; } diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c index 65a964d7e70d..6ef15f78e80f 100644 --- a/arch/riscv/kvm/vm.c +++ b/arch/riscv/kvm/vm.c @@ -41,6 +41,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) return r; } + kvm_riscv_aia_init_vm(kvm); + kvm_riscv_guest_timer_init(kvm); return 0; @@ -49,6 +51,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) void kvm_arch_destroy_vm(struct kvm *kvm) { kvm_destroy_vcpus(kvm); + + kvm_riscv_aia_destroy_vm(kvm); } int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) @@ -87,8 +91,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) return r; } -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { return -EINVAL; } diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c index 5246da1c9167..ddc98714ce8e 100644 --- a/arch/riscv/kvm/vmid.c +++ b/arch/riscv/kvm/vmid.c @@ -26,9 +26,9 @@ void __init kvm_riscv_gstage_vmid_detect(void) /* Figure-out number of VMID bits in HW */ old = csr_read(CSR_HGATP); - csr_write(CSR_HGATP, old | HGATP_VMID_MASK); + csr_write(CSR_HGATP, old | HGATP_VMID); vmid_bits = csr_read(CSR_HGATP); - vmid_bits = (vmid_bits & HGATP_VMID_MASK) >> HGATP_VMID_SHIFT; + vmid_bits = (vmid_bits & HGATP_VMID) >> HGATP_VMID_SHIFT; vmid_bits = fls_long(vmid_bits); csr_write(CSR_HGATP, old); diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 6c74b0bedd60..26cb2502ecf8 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -8,5 +8,6 @@ lib-y += strlen.o lib-y += strncmp.o lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_64BIT) += tishift.o +lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/riscv/lib/clear_page.S b/arch/riscv/lib/clear_page.S new file mode 100644 index 000000000000..d7a256eb53f4 --- /dev/null +++ b/arch/riscv/lib/clear_page.S @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Ventana Micro Systems Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CBOZ_ALT(order, old, new) \ + ALTERNATIVE(old, new, 0, \ + ((order) << 16) | RISCV_ISA_EXT_ZICBOZ, \ + CONFIG_RISCV_ISA_ZICBOZ) + +/* void clear_page(void *page) */ +SYM_FUNC_START(clear_page) + li a2, PAGE_SIZE + + /* + * If Zicboz isn't present, or somehow has a block + * size larger than 4K, then fallback to memset. + */ + CBOZ_ALT(12, "j .Lno_zicboz", "nop") + + lw a1, riscv_cboz_block_size + add a2, a0, a2 +.Lzero_loop: + CBO_zero(a0) + add a0, a0, a1 + CBOZ_ALT(11, "bltu a0, a2, .Lzero_loop; ret", "nop; nop") + CBO_zero(a0) + add a0, a0, a1 + CBOZ_ALT(10, "bltu a0, a2, .Lzero_loop; ret", "nop; nop") + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBOZ_ALT(9, "bltu a0, a2, .Lzero_loop; ret", "nop; nop") + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBOZ_ALT(8, "bltu a0, a2, .Lzero_loop; ret", "nop; nop") + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + CBO_zero(a0) + add a0, a0, a1 + bltu a0, a2, .Lzero_loop + ret +.Lno_zicboz: + li a1, 0 + tail __memset +SYM_FUNC_END(clear_page) +EXPORT_SYMBOL(clear_page) diff --git a/arch/riscv/lib/memcpy.S b/arch/riscv/lib/memcpy.S index 51ab716253fa..1a40d01a9543 100644 --- a/arch/riscv/lib/memcpy.S +++ b/arch/riscv/lib/memcpy.S @@ -106,3 +106,5 @@ WEAK(memcpy) 6: ret END(__memcpy) +SYM_FUNC_ALIAS(__pi_memcpy, __memcpy) +SYM_FUNC_ALIAS(__pi___memcpy, __memcpy) diff --git a/arch/riscv/lib/memmove.S b/arch/riscv/lib/memmove.S index e0609e1f0864..838ff2022fe3 100644 --- a/arch/riscv/lib/memmove.S +++ b/arch/riscv/lib/memmove.S @@ -314,3 +314,5 @@ return_from_memmove: SYM_FUNC_END(memmove) SYM_FUNC_END(__memmove) +SYM_FUNC_ALIAS(__pi_memmove, __memmove) +SYM_FUNC_ALIAS(__pi___memmove, __memmove) diff --git a/arch/riscv/lib/strcmp.S b/arch/riscv/lib/strcmp.S index c42a8412547f..687b2bea5c43 100644 --- a/arch/riscv/lib/strcmp.S +++ b/arch/riscv/lib/strcmp.S @@ -2,9 +2,8 @@ #include #include -#include #include -#include +#include /* int strcmp(const char *cs, const char *ct) */ SYM_FUNC_START(strcmp) diff --git a/arch/riscv/lib/strlen.S b/arch/riscv/lib/strlen.S index 15bb8f3aa959..8ae3064e45ff 100644 --- a/arch/riscv/lib/strlen.S +++ b/arch/riscv/lib/strlen.S @@ -2,9 +2,8 @@ #include #include -#include #include -#include +#include /* int strlen(const char *s) */ SYM_FUNC_START(strlen) @@ -131,3 +130,4 @@ strlen_zbb: .option pop #endif SYM_FUNC_END(strlen) +SYM_FUNC_ALIAS(__pi_strlen, strlen) diff --git a/arch/riscv/lib/strncmp.S b/arch/riscv/lib/strncmp.S index 7ac2f667285a..aba5b3148621 100644 --- a/arch/riscv/lib/strncmp.S +++ b/arch/riscv/lib/strncmp.S @@ -2,9 +2,8 @@ #include #include -#include #include -#include +#include /* int strncmp(const char *cs, const char *ct, size_t count) */ SYM_FUNC_START(strncmp) diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 2ac177c05352..b85e9e82f082 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only CFLAGS_init.o := -mcmodel=medany +ifdef CONFIG_RELOCATABLE +CFLAGS_init.o += -fno-pie +endif + ifdef CONFIG_FTRACE CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_cacheflush.o = $(CC_FLAGS_FTRACE) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index 20cec5e7cdbf..fca532ddf3ec 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -101,36 +101,48 @@ void flush_icache_pte(pte_t pte) unsigned int riscv_cbom_block_size; EXPORT_SYMBOL_GPL(riscv_cbom_block_size); -void riscv_init_cbom_blocksize(void) +unsigned int riscv_cboz_block_size; +EXPORT_SYMBOL_GPL(riscv_cboz_block_size); + +static void cbo_get_block_size(struct device_node *node, + const char *name, u32 *block_size, + unsigned long *first_hartid) { + unsigned long hartid; + u32 val; + + if (riscv_of_processor_hartid(node, &hartid)) + return; + + if (of_property_read_u32(node, name, &val)) + return; + + if (!*block_size) { + *block_size = val; + *first_hartid = hartid; + } else if (*block_size != val) { + pr_warn("%s mismatched between harts %lu and %lu\n", + name, *first_hartid, hartid); + } +} + +void riscv_init_cbo_blocksizes(void) +{ + unsigned long cbom_hartid, cboz_hartid; + u32 cbom_block_size = 0, cboz_block_size = 0; struct device_node *node; - unsigned long cbom_hartid; - u32 val, probed_block_size; - int ret; - probed_block_size = 0; for_each_of_cpu_node(node) { - unsigned long hartid; - - ret = riscv_of_processor_hartid(node, &hartid); - if (ret) - continue; - - /* set block-size for cbom extension if available */ - ret = of_property_read_u32(node, "riscv,cbom-block-size", &val); - if (ret) - continue; - - if (!probed_block_size) { - probed_block_size = val; - cbom_hartid = hartid; - } else { - if (probed_block_size != val) - pr_warn("cbom-block-size mismatched between harts %lu and %lu\n", - cbom_hartid, hartid); - } + /* set block-size for cbom and/or cboz extension if available */ + cbo_get_block_size(node, "riscv,cbom-block-size", + &cbom_block_size, &cbom_hartid); + cbo_get_block_size(node, "riscv,cboz-block-size", + &cboz_block_size, &cboz_hartid); } - if (probed_block_size) - riscv_cbom_block_size = probed_block_size; + if (cbom_block_size) + riscv_cbom_block_size = cbom_block_size; + + if (cboz_block_size) + riscv_cboz_block_size = cboz_block_size; } diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index d5f3e501dffb..8685f85a7474 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -209,7 +210,7 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma) * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. */ -asmlinkage void do_page_fault(struct pt_regs *regs) +void handle_page_fault(struct pt_regs *regs) { struct task_struct *tsk; struct vm_area_struct *vma; @@ -256,7 +257,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs) } #endif /* Enable interrupts if they were enabled in the parent context. */ - if (likely(regs->status & SR_PIE)) + if (!regs_irqs_disabled(regs)) local_irq_enable(); /* @@ -361,4 +362,3 @@ good_area: } return; } -NOKPROBE_SYMBOL(do_page_fault); diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c index 932dadfdca54..e0ef56dc57b9 100644 --- a/arch/riscv/mm/hugetlbpage.c +++ b/arch/riscv/mm/hugetlbpage.c @@ -2,6 +2,333 @@ #include #include +#ifdef CONFIG_RISCV_ISA_SVNAPOT +pte_t huge_ptep_get(pte_t *ptep) +{ + unsigned long pte_num; + int i; + pte_t orig_pte = ptep_get(ptep); + + if (!pte_present(orig_pte) || !pte_napot(orig_pte)) + return orig_pte; + + pte_num = napot_pte_num(napot_cont_order(orig_pte)); + + for (i = 0; i < pte_num; i++, ptep++) { + pte_t pte = ptep_get(ptep); + + if (pte_dirty(pte)) + orig_pte = pte_mkdirty(orig_pte); + + if (pte_young(pte)) + orig_pte = pte_mkyoung(orig_pte); + } + + return orig_pte; +} + +pte_t *huge_pte_alloc(struct mm_struct *mm, + struct vm_area_struct *vma, + unsigned long addr, + unsigned long sz) +{ + unsigned long order; + pte_t *pte = NULL; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, addr); + p4d = p4d_alloc(mm, pgd, addr); + if (!p4d) + return NULL; + + pud = pud_alloc(mm, p4d, addr); + if (!pud) + return NULL; + + if (sz == PUD_SIZE) { + pte = (pte_t *)pud; + goto out; + } + + if (sz == PMD_SIZE) { + if (want_pmd_share(vma, addr) && pud_none(*pud)) + pte = huge_pmd_share(mm, vma, addr, pud); + else + pte = (pte_t *)pmd_alloc(mm, pud, addr); + goto out; + } + + pmd = pmd_alloc(mm, pud, addr); + if (!pmd) + return NULL; + + for_each_napot_order(order) { + if (napot_cont_size(order) == sz) { + pte = pte_alloc_map(mm, pmd, addr & napot_cont_mask(order)); + break; + } + } + +out: + WARN_ON_ONCE(pte && pte_present(*pte) && !pte_huge(*pte)); + return pte; +} + +pte_t *huge_pte_offset(struct mm_struct *mm, + unsigned long addr, + unsigned long sz) +{ + unsigned long order; + pte_t *pte = NULL; + pgd_t *pgd; + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) + return NULL; + + p4d = p4d_offset(pgd, addr); + if (!p4d_present(*p4d)) + return NULL; + + pud = pud_offset(p4d, addr); + if (sz == PUD_SIZE) + /* must be pud huge, non-present or none */ + return (pte_t *)pud; + + if (!pud_present(*pud)) + return NULL; + + pmd = pmd_offset(pud, addr); + if (sz == PMD_SIZE) + /* must be pmd huge, non-present or none */ + return (pte_t *)pmd; + + if (!pmd_present(*pmd)) + return NULL; + + for_each_napot_order(order) { + if (napot_cont_size(order) == sz) { + pte = pte_offset_kernel(pmd, addr & napot_cont_mask(order)); + break; + } + } + return pte; +} + +static pte_t get_clear_contig(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + unsigned long pte_num) +{ + pte_t orig_pte = ptep_get(ptep); + unsigned long i; + + for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) { + pte_t pte = ptep_get_and_clear(mm, addr, ptep); + + if (pte_dirty(pte)) + orig_pte = pte_mkdirty(orig_pte); + + if (pte_young(pte)) + orig_pte = pte_mkyoung(orig_pte); + } + + return orig_pte; +} + +static pte_t get_clear_contig_flush(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + unsigned long pte_num) +{ + pte_t orig_pte = get_clear_contig(mm, addr, ptep, pte_num); + struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0); + bool valid = !pte_none(orig_pte); + + if (valid) + flush_tlb_range(&vma, addr, addr + (PAGE_SIZE * pte_num)); + + return orig_pte; +} + +pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags) +{ + unsigned long order; + + for_each_napot_order(order) { + if (shift == napot_cont_shift(order)) { + entry = pte_mknapot(entry, order); + break; + } + } + if (order == NAPOT_ORDER_MAX) + entry = pte_mkhuge(entry); + + return entry; +} + +void set_huge_pte_at(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + pte_t pte) +{ + int i, pte_num; + + if (!pte_napot(pte)) { + set_pte_at(mm, addr, ptep, pte); + return; + } + + pte_num = napot_pte_num(napot_cont_order(pte)); + for (i = 0; i < pte_num; i++, ptep++, addr += PAGE_SIZE) + set_pte_at(mm, addr, ptep, pte); +} + +int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, + pte_t *ptep, + pte_t pte, + int dirty) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long order; + pte_t orig_pte; + int i, pte_num; + + if (!pte_napot(pte)) + return ptep_set_access_flags(vma, addr, ptep, pte, dirty); + + order = napot_cont_order(pte); + pte_num = napot_pte_num(order); + ptep = huge_pte_offset(mm, addr, napot_cont_size(order)); + orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num); + + if (pte_dirty(orig_pte)) + pte = pte_mkdirty(pte); + + if (pte_young(orig_pte)) + pte = pte_mkyoung(pte); + + for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) + set_pte_at(mm, addr, ptep, pte); + + return true; +} + +pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep) +{ + pte_t orig_pte = ptep_get(ptep); + int pte_num; + + if (!pte_napot(orig_pte)) + return ptep_get_and_clear(mm, addr, ptep); + + pte_num = napot_pte_num(napot_cont_order(orig_pte)); + + return get_clear_contig(mm, addr, ptep, pte_num); +} + +void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep) +{ + pte_t pte = ptep_get(ptep); + unsigned long order; + pte_t orig_pte; + int i, pte_num; + + if (!pte_napot(pte)) { + ptep_set_wrprotect(mm, addr, ptep); + return; + } + + order = napot_cont_order(pte); + pte_num = napot_pte_num(order); + ptep = huge_pte_offset(mm, addr, napot_cont_size(order)); + orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num); + + orig_pte = pte_wrprotect(orig_pte); + + for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) + set_pte_at(mm, addr, ptep, orig_pte); +} + +pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, + pte_t *ptep) +{ + pte_t pte = ptep_get(ptep); + int pte_num; + + if (!pte_napot(pte)) + return ptep_clear_flush(vma, addr, ptep); + + pte_num = napot_pte_num(napot_cont_order(pte)); + + return get_clear_contig_flush(vma->vm_mm, addr, ptep, pte_num); +} + +void huge_pte_clear(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, + unsigned long sz) +{ + pte_t pte = READ_ONCE(*ptep); + int i, pte_num; + + if (!pte_napot(pte)) { + pte_clear(mm, addr, ptep); + return; + } + + pte_num = napot_pte_num(napot_cont_order(pte)); + for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++) + pte_clear(mm, addr, ptep); +} + +static __init bool is_napot_size(unsigned long size) +{ + unsigned long order; + + if (!has_svnapot()) + return false; + + for_each_napot_order(order) { + if (size == napot_cont_size(order)) + return true; + } + return false; +} + +static __init int napot_hugetlbpages_init(void) +{ + if (has_svnapot()) { + unsigned long order; + + for_each_napot_order(order) + hugetlb_add_hstate(order); + } + return 0; +} +arch_initcall(napot_hugetlbpages_init); + +#else + +static __init bool is_napot_size(unsigned long size) +{ + return false; +} + +#endif /*CONFIG_RISCV_ISA_SVNAPOT*/ + int pud_huge(pud_t pud) { return pud_leaf(pud); @@ -18,6 +345,8 @@ bool __init arch_hugetlb_valid_size(unsigned long size) return true; else if (IS_ENABLED(CONFIG_64BIT) && size == PUD_SIZE) return true; + else if (is_napot_size(size)) + return true; else return false; } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 0f14f4a8d179..c6bb966e4123 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -20,6 +20,9 @@ #include #include #include +#ifdef CONFIG_RELOCATABLE +#include +#endif #include #include @@ -145,7 +148,7 @@ static void __init print_vm_layout(void) print_ml("kasan", KASAN_SHADOW_START, KASAN_SHADOW_END); #endif - print_ml("kernel", (unsigned long)KERNEL_LINK_ADDR, + print_ml("kernel", (unsigned long)kernel_map.virt_addr, (unsigned long)ADDRESS_SPACE_END); } } @@ -212,6 +215,14 @@ static void __init setup_bootmem(void) phys_ram_end = memblock_end_of_DRAM(); if (!IS_ENABLED(CONFIG_XIP_KERNEL)) phys_ram_base = memblock_start_of_DRAM(); + + /* + * In 64-bit, any use of __va/__pa before this point is wrong as we + * did not know the start of DRAM before. + */ + if (IS_ENABLED(CONFIG_64BIT)) + kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base; + /* * memblock allocator is not aware of the fact that last 4K bytes of * the addressable memory can not be mapped because of IS_ERR_VALUE @@ -261,9 +272,6 @@ static void __init setup_bootmem(void) #ifdef CONFIG_MMU struct pt_alloc_ops pt_ops __initdata; -unsigned long riscv_pfn_base __ro_after_init; -EXPORT_SYMBOL(riscv_pfn_base); - pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; @@ -272,7 +280,6 @@ pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); #ifdef CONFIG_XIP_KERNEL #define pt_ops (*(struct pt_alloc_ops *)XIP_FIXUP(&pt_ops)) -#define riscv_pfn_base (*(unsigned long *)XIP_FIXUP(&riscv_pfn_base)) #define trampoline_pg_dir ((pgd_t *)XIP_FIXUP(trampoline_pg_dir)) #define fixmap_pte ((pte_t *)XIP_FIXUP(fixmap_pte)) #define early_pg_dir ((pgd_t *)XIP_FIXUP(early_pg_dir)) @@ -654,9 +661,16 @@ void __init create_pgd_mapping(pgd_t *pgdp, static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size) { - /* Upgrade to PMD_SIZE mappings whenever possible */ - base &= PMD_SIZE - 1; - if (!base && size >= PMD_SIZE) + if (!(base & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE) + return PGDIR_SIZE; + + if (!(base & (P4D_SIZE - 1)) && size >= P4D_SIZE) + return P4D_SIZE; + + if (!(base & (PUD_SIZE - 1)) && size >= PUD_SIZE) + return PUD_SIZE; + + if (!(base & (PMD_SIZE - 1)) && size >= PMD_SIZE) return PMD_SIZE; return PAGE_SIZE; @@ -715,6 +729,8 @@ static __init pgprot_t pgprot_from_va(uintptr_t va) #endif /* CONFIG_STRICT_KERNEL_RWX */ #if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL) +u64 __pi_set_satp_mode_from_cmdline(uintptr_t dtb_pa); + static void __init disable_pgtable_l5(void) { pgtable_l5_enabled = false; @@ -729,17 +745,39 @@ static void __init disable_pgtable_l4(void) satp_mode = SATP_MODE_39; } +static int __init print_no4lvl(char *p) +{ + pr_info("Disabled 4-level and 5-level paging"); + return 0; +} +early_param("no4lvl", print_no4lvl); + +static int __init print_no5lvl(char *p) +{ + pr_info("Disabled 5-level paging"); + return 0; +} +early_param("no5lvl", print_no5lvl); + /* * There is a simple way to determine if 4-level is supported by the * underlying hardware: establish 1:1 mapping in 4-level page table mode * then read SATP to see if the configuration was taken into account * meaning sv48 is supported. */ -static __init void set_satp_mode(void) +static __init void set_satp_mode(uintptr_t dtb_pa) { u64 identity_satp, hw_satp; uintptr_t set_satp_mode_pmd = ((unsigned long)set_satp_mode) & PMD_MASK; - bool check_l4 = false; + u64 satp_mode_cmdline = __pi_set_satp_mode_from_cmdline(dtb_pa); + + if (satp_mode_cmdline == SATP_MODE_57) { + disable_pgtable_l5(); + } else if (satp_mode_cmdline == SATP_MODE_48) { + disable_pgtable_l5(); + disable_pgtable_l4(); + return; + } create_p4d_mapping(early_p4d, set_satp_mode_pmd, (uintptr_t)early_pud, @@ -758,7 +796,8 @@ static __init void set_satp_mode(void) retry: create_pgd_mapping(early_pg_dir, set_satp_mode_pmd, - check_l4 ? (uintptr_t)early_pud : (uintptr_t)early_p4d, + pgtable_l5_enabled ? + (uintptr_t)early_p4d : (uintptr_t)early_pud, PGDIR_SIZE, PAGE_TABLE); identity_satp = PFN_DOWN((uintptr_t)&early_pg_dir) | satp_mode; @@ -769,9 +808,8 @@ retry: local_flush_tlb_all(); if (hw_satp != identity_satp) { - if (!check_l4) { + if (pgtable_l5_enabled) { disable_pgtable_l5(); - check_l4 = true; memset(early_pg_dir, 0, PAGE_SIZE); goto retry; } @@ -803,6 +841,44 @@ retry: #error "setup_vm() is called from head.S before relocate so it should not use absolute addressing." #endif +#ifdef CONFIG_RELOCATABLE +extern unsigned long __rela_dyn_start, __rela_dyn_end; + +static void __init relocate_kernel(void) +{ + Elf64_Rela *rela = (Elf64_Rela *)&__rela_dyn_start; + /* + * This holds the offset between the linked virtual address and the + * relocated virtual address. + */ + uintptr_t reloc_offset = kernel_map.virt_addr - KERNEL_LINK_ADDR; + /* + * This holds the offset between kernel linked virtual address and + * physical address. + */ + uintptr_t va_kernel_link_pa_offset = KERNEL_LINK_ADDR - kernel_map.phys_addr; + + for ( ; rela < (Elf64_Rela *)&__rela_dyn_end; rela++) { + Elf64_Addr addr = (rela->r_offset - va_kernel_link_pa_offset); + Elf64_Addr relocated_addr = rela->r_addend; + + if (rela->r_info != R_RISCV_RELATIVE) + continue; + + /* + * Make sure to not relocate vdso symbols like rt_sigreturn + * which are linked from the address 0 in vmlinux since + * vdso symbol addresses are actually used as an offset from + * mm->context.vdso in VDSO_OFFSET macro. + */ + if (relocated_addr >= KERNEL_LINK_ADDR) + relocated_addr += reloc_offset; + + *(Elf64_Addr *)addr = relocated_addr; + } +} +#endif /* CONFIG_RELOCATABLE */ + #ifdef CONFIG_XIP_KERNEL static void __init create_kernel_page_table(pgd_t *pgdir, __always_unused bool early) @@ -843,13 +919,12 @@ static void __init create_kernel_page_table(pgd_t *pgdir, bool early) * this means 2 PMD entries whereas for 32-bit kernel, this is only 1 PGDIR * entry. */ -static void __init create_fdt_early_page_table(pgd_t *pgdir, - uintptr_t fix_fdt_va, +static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va, uintptr_t dtb_pa) { +#ifndef CONFIG_BUILTIN_DTB uintptr_t pa = dtb_pa & ~(PMD_SIZE - 1); -#ifndef CONFIG_BUILTIN_DTB /* Make sure the fdt fixmap address is always aligned on PMD size */ BUILD_BUG_ON(FIX_FDT % (PMD_SIZE / PAGE_SIZE)); @@ -958,14 +1033,25 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) #endif #if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL) - set_satp_mode(); + set_satp_mode(dtb_pa); #endif - kernel_map.va_pa_offset = PAGE_OFFSET - kernel_map.phys_addr; + /* + * In 64-bit, we defer the setup of va_pa_offset to setup_bootmem, + * where we have the system memory layout: this allows us to align + * the physical and virtual mappings and then make use of PUD/P4D/PGD + * for the linear mapping. This is only possible because the kernel + * mapping lies outside the linear mapping. + * In 32-bit however, as the kernel resides in the linear mapping, + * setup_vm_final can not change the mapping established here, + * otherwise the same kernel addresses would get mapped to different + * physical addresses (if the start of dram is different from the + * kernel physical address start). + */ + kernel_map.va_pa_offset = IS_ENABLED(CONFIG_64BIT) ? + 0UL : PAGE_OFFSET - kernel_map.phys_addr; kernel_map.va_kernel_pa_offset = kernel_map.virt_addr - kernel_map.phys_addr; - riscv_pfn_base = PFN_DOWN(kernel_map.phys_addr); - /* * The default maximal physical memory size is KERN_VIRT_SIZE for 32-bit * kernel, whereas for 64-bit kernel, the end of the virtual address @@ -986,6 +1072,17 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) BUG_ON((kernel_map.virt_addr + kernel_map.size) > ADDRESS_SPACE_END - SZ_4K); #endif +#ifdef CONFIG_RELOCATABLE + /* + * Early page table uses only one PUD, which makes it possible + * to map PUD_SIZE aligned on PUD_SIZE: if the relocation offset + * makes the kernel cross over a PUD_SIZE boundary, raise a bug + * since a part of the kernel would not get mapped. + */ + BUG_ON(PUD_SIZE - (kernel_map.virt_addr & (PUD_SIZE - 1)) < kernel_map.size); + relocate_kernel(); +#endif + apply_early_boot_alternatives(); pt_ops_set_early(); @@ -1034,8 +1131,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) create_kernel_page_table(early_pg_dir, true); /* Setup early mapping for FDT early scan */ - create_fdt_early_page_table(early_pg_dir, - __fix_to_virt(FIX_FDT), dtb_pa); + create_fdt_early_page_table(__fix_to_virt(FIX_FDT), dtb_pa); /* * Bootime fixmap only can handle PMD_SIZE mapping. Thus, boot-ioremap @@ -1070,12 +1166,62 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) pt_ops_set_fixmap(); } -static void __init setup_vm_final(void) +static void __init create_linear_mapping_range(phys_addr_t start, + phys_addr_t end) { + phys_addr_t pa; uintptr_t va, map_size; - phys_addr_t pa, start, end; + + for (pa = start; pa < end; pa += map_size) { + va = (uintptr_t)__va(pa); + map_size = best_map_size(pa, end - pa); + + create_pgd_mapping(swapper_pg_dir, va, pa, map_size, + pgprot_from_va(va)); + } +} + +static void __init create_linear_mapping_page_table(void) +{ + phys_addr_t start, end; u64 i; +#ifdef CONFIG_STRICT_KERNEL_RWX + phys_addr_t ktext_start = __pa_symbol(_start); + phys_addr_t ktext_size = __init_data_begin - _start; + phys_addr_t krodata_start = __pa_symbol(__start_rodata); + phys_addr_t krodata_size = _data - __start_rodata; + + /* Isolate kernel text and rodata so they don't get mapped with a PUD */ + memblock_mark_nomap(ktext_start, ktext_size); + memblock_mark_nomap(krodata_start, krodata_size); +#endif + + /* Map all memory banks in the linear mapping */ + for_each_mem_range(i, &start, &end) { + if (start >= end) + break; + if (start <= __pa(PAGE_OFFSET) && + __pa(PAGE_OFFSET) < end) + start = __pa(PAGE_OFFSET); + if (end >= __pa(PAGE_OFFSET) + memory_limit) + end = __pa(PAGE_OFFSET) + memory_limit; + + create_linear_mapping_range(start, end); + } + +#ifdef CONFIG_STRICT_KERNEL_RWX + create_linear_mapping_range(ktext_start, ktext_start + ktext_size); + create_linear_mapping_range(krodata_start, + krodata_start + krodata_size); + + memblock_clear_nomap(ktext_start, ktext_size); + memblock_clear_nomap(krodata_start, krodata_size); +#endif +} + +static void __init setup_vm_final(void) +{ /* Setup swapper PGD for fixmap */ #if !defined(CONFIG_64BIT) /* @@ -1091,24 +1237,8 @@ static void __init setup_vm_final(void) __pa_symbol(fixmap_pgd_next), PGDIR_SIZE, PAGE_TABLE); - /* Map all memory banks in the linear mapping */ - for_each_mem_range(i, &start, &end) { - if (start >= end) - break; - if (start <= __pa(PAGE_OFFSET) && - __pa(PAGE_OFFSET) < end) - start = __pa(PAGE_OFFSET); - if (end >= __pa(PAGE_OFFSET) + memory_limit) - end = __pa(PAGE_OFFSET) + memory_limit; - - for (pa = start; pa < end; pa += map_size) { - va = (uintptr_t)__va(pa); - map_size = best_map_size(pa, end - pa); - - create_pgd_mapping(swapper_pg_dir, va, pa, map_size, - pgprot_from_va(va)); - } - } + /* Map the linear mapping */ + create_linear_mapping_page_table(); /* Map the kernel */ if (IS_ENABLED(CONFIG_64BIT)) diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c index e1226709490f..8fc0efcf905c 100644 --- a/arch/riscv/mm/kasan_init.c +++ b/arch/riscv/mm/kasan_init.c @@ -18,58 +18,48 @@ * For sv39, the region is aligned on PGDIR_SIZE so we only need to populate * the page global directory with kasan_early_shadow_pmd. * - * For sv48 and sv57, the region is not aligned on PGDIR_SIZE so the mapping - * must be divided as follows: - * - the first PGD entry, although incomplete, is populated with - * kasan_early_shadow_pud/p4d - * - the PGD entries in the middle are populated with kasan_early_shadow_pud/p4d - * - the last PGD entry is shared with the kernel mapping so populated at the - * lower levels pud/p4d - * - * In addition, when shallow populating a kasan region (for example vmalloc), - * this region may also not be aligned on PGDIR size, so we must go down to the - * pud level too. + * For sv48 and sv57, the region start is aligned on PGDIR_SIZE whereas the end + * region is not and then we have to go down to the PUD level. */ extern pgd_t early_pg_dir[PTRS_PER_PGD]; +pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss; +p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss; +pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss; static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end) { phys_addr_t phys_addr; - pte_t *ptep, *base_pte; + pte_t *ptep, *p; - if (pmd_none(*pmd)) - base_pte = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); - else - base_pte = (pte_t *)pmd_page_vaddr(*pmd); + if (pmd_none(*pmd)) { + p = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); + set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE)); + } - ptep = base_pte + pte_index(vaddr); + ptep = pte_offset_kernel(pmd, vaddr); do { if (pte_none(*ptep)) { phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE); } } while (ptep++, vaddr += PAGE_SIZE, vaddr != end); - - set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(base_pte)), PAGE_TABLE)); } static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned long end) { phys_addr_t phys_addr; - pmd_t *pmdp, *base_pmd; + pmd_t *pmdp, *p; unsigned long next; if (pud_none(*pud)) { - base_pmd = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); - } else { - base_pmd = (pmd_t *)pud_pgtable(*pud); - if (base_pmd == lm_alias(kasan_early_shadow_pmd)) - base_pmd = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); + p = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); + set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); } - pmdp = base_pmd + pmd_index(vaddr); + pmdp = pmd_offset(pud, vaddr); do { next = pmd_addr_end(vaddr, end); @@ -78,157 +68,77 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE); if (phys_addr) { set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, PMD_SIZE); continue; } } kasan_populate_pte(pmdp, vaddr, next); } while (pmdp++, vaddr = next, vaddr != end); - - /* - * Wait for the whole PGD to be populated before setting the PGD in - * the page table, otherwise, if we did set the PGD before populating - * it entirely, memblock could allocate a page at a physical address - * where KASAN is not populated yet and then we'd get a page fault. - */ - set_pud(pud, pfn_pud(PFN_DOWN(__pa(base_pmd)), PAGE_TABLE)); } -static void __init kasan_populate_pud(pgd_t *pgd, - unsigned long vaddr, unsigned long end, - bool early) +static void __init kasan_populate_pud(p4d_t *p4d, + unsigned long vaddr, unsigned long end) { phys_addr_t phys_addr; - pud_t *pudp, *base_pud; + pud_t *pudp, *p; unsigned long next; - if (early) { - /* - * We can't use pgd_page_vaddr here as it would return a linear - * mapping address but it is not mapped yet, but when populating - * early_pg_dir, we need the physical address and when populating - * swapper_pg_dir, we need the kernel virtual address so use - * pt_ops facility. - */ - base_pud = pt_ops.get_pud_virt(pfn_to_phys(_pgd_pfn(*pgd))); - } else if (pgd_none(*pgd)) { - base_pud = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); - memcpy(base_pud, (void *)kasan_early_shadow_pud, - sizeof(pud_t) * PTRS_PER_PUD); - } else { - base_pud = (pud_t *)pgd_page_vaddr(*pgd); - if (base_pud == lm_alias(kasan_early_shadow_pud)) { - base_pud = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); - memcpy(base_pud, (void *)kasan_early_shadow_pud, - sizeof(pud_t) * PTRS_PER_PUD); - } + if (p4d_none(*p4d)) { + p = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); + set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); } - pudp = base_pud + pud_index(vaddr); + pudp = pud_offset(p4d, vaddr); do { next = pud_addr_end(vaddr, end); if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { - if (early) { - phys_addr = __pa(((uintptr_t)kasan_early_shadow_pmd)); - set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE)); + phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE); + if (phys_addr) { + set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, PUD_SIZE); continue; - } else { - phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE); - if (phys_addr) { - set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL)); - continue; - } } } kasan_populate_pmd(pudp, vaddr, next); } while (pudp++, vaddr = next, vaddr != end); - - /* - * Wait for the whole PGD to be populated before setting the PGD in - * the page table, otherwise, if we did set the PGD before populating - * it entirely, memblock could allocate a page at a physical address - * where KASAN is not populated yet and then we'd get a page fault. - */ - if (!early) - set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_pud)), PAGE_TABLE)); } static void __init kasan_populate_p4d(pgd_t *pgd, - unsigned long vaddr, unsigned long end, - bool early) + unsigned long vaddr, unsigned long end) { phys_addr_t phys_addr; - p4d_t *p4dp, *base_p4d; + p4d_t *p4dp, *p; unsigned long next; - if (early) { - /* - * We can't use pgd_page_vaddr here as it would return a linear - * mapping address but it is not mapped yet, but when populating - * early_pg_dir, we need the physical address and when populating - * swapper_pg_dir, we need the kernel virtual address so use - * pt_ops facility. - */ - base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgd))); - } else { - base_p4d = (p4d_t *)pgd_page_vaddr(*pgd); - if (base_p4d == lm_alias(kasan_early_shadow_p4d)) { - base_p4d = memblock_alloc(PTRS_PER_PUD * sizeof(p4d_t), PAGE_SIZE); - memcpy(base_p4d, (void *)kasan_early_shadow_p4d, - sizeof(p4d_t) * PTRS_PER_P4D); - } + if (pgd_none(*pgd)) { + p = memblock_alloc(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE); + set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); } - p4dp = base_p4d + p4d_index(vaddr); + p4dp = p4d_offset(pgd, vaddr); do { next = p4d_addr_end(vaddr, end); if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) { - if (early) { - phys_addr = __pa(((uintptr_t)kasan_early_shadow_pud)); - set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE)); + phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE); + if (phys_addr) { + set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, P4D_SIZE); continue; - } else { - phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE); - if (phys_addr) { - set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL)); - continue; - } } } - kasan_populate_pud((pgd_t *)p4dp, vaddr, next, early); + kasan_populate_pud(p4dp, vaddr, next); } while (p4dp++, vaddr = next, vaddr != end); - - /* - * Wait for the whole P4D to be populated before setting the P4D in - * the page table, otherwise, if we did set the P4D before populating - * it entirely, memblock could allocate a page at a physical address - * where KASAN is not populated yet and then we'd get a page fault. - */ - if (!early) - set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_p4d)), PAGE_TABLE)); } -#define kasan_early_shadow_pgd_next (pgtable_l5_enabled ? \ - (uintptr_t)kasan_early_shadow_p4d : \ - (pgtable_l4_enabled ? \ - (uintptr_t)kasan_early_shadow_pud : \ - (uintptr_t)kasan_early_shadow_pmd)) -#define kasan_populate_pgd_next(pgdp, vaddr, next, early) \ - (pgtable_l5_enabled ? \ - kasan_populate_p4d(pgdp, vaddr, next, early) : \ - (pgtable_l4_enabled ? \ - kasan_populate_pud(pgdp, vaddr, next, early) : \ - kasan_populate_pmd((pud_t *)pgdp, vaddr, next))) - static void __init kasan_populate_pgd(pgd_t *pgdp, - unsigned long vaddr, unsigned long end, - bool early) + unsigned long vaddr, unsigned long end) { phys_addr_t phys_addr; unsigned long next; @@ -236,29 +146,174 @@ static void __init kasan_populate_pgd(pgd_t *pgdp, do { next = pgd_addr_end(vaddr, end); - if (IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) { - if (early) { - phys_addr = __pa((uintptr_t)kasan_early_shadow_pgd_next); - set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE)); + if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + (next - vaddr) >= PGDIR_SIZE) { + phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); + if (phys_addr) { + set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL)); + memset(__va(phys_addr), KASAN_SHADOW_INIT, PGDIR_SIZE); continue; - } else if (pgd_page_vaddr(*pgdp) == - (unsigned long)lm_alias(kasan_early_shadow_pgd_next)) { - /* - * pgdp can't be none since kasan_early_init - * initialized all KASAN shadow region with - * kasan_early_shadow_pud: if this is still the - * case, that means we can try to allocate a - * hugepage as a replacement. - */ - phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); - if (phys_addr) { - set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL)); - continue; - } } } - kasan_populate_pgd_next(pgdp, vaddr, next, early); + kasan_populate_p4d(pgdp, vaddr, next); + } while (pgdp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_clear_pud(p4d_t *p4dp, + unsigned long vaddr, unsigned long end) +{ + pud_t *pudp, *base_pud; + unsigned long next; + + if (!pgtable_l4_enabled) { + pudp = (pud_t *)p4dp; + } else { + base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); + pudp = base_pud + pud_index(vaddr); + } + + do { + next = pud_addr_end(vaddr, end); + + if (IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { + pud_clear(pudp); + continue; + } + + BUG(); + } while (pudp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_clear_p4d(pgd_t *pgdp, + unsigned long vaddr, unsigned long end) +{ + p4d_t *p4dp, *base_p4d; + unsigned long next; + + if (!pgtable_l5_enabled) { + p4dp = (p4d_t *)pgdp; + } else { + base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); + p4dp = base_p4d + p4d_index(vaddr); + } + + do { + next = p4d_addr_end(vaddr, end); + + if (pgtable_l4_enabled && IS_ALIGNED(vaddr, P4D_SIZE) && + (next - vaddr) >= P4D_SIZE) { + p4d_clear(p4dp); + continue; + } + + kasan_early_clear_pud(p4dp, vaddr, next); + } while (p4dp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_clear_pgd(pgd_t *pgdp, + unsigned long vaddr, unsigned long end) +{ + unsigned long next; + + do { + next = pgd_addr_end(vaddr, end); + + if (pgtable_l5_enabled && IS_ALIGNED(vaddr, PGDIR_SIZE) && + (next - vaddr) >= PGDIR_SIZE) { + pgd_clear(pgdp); + continue; + } + + kasan_early_clear_p4d(pgdp, vaddr, next); + } while (pgdp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_populate_pud(p4d_t *p4dp, + unsigned long vaddr, + unsigned long end) +{ + pud_t *pudp, *base_pud; + phys_addr_t phys_addr; + unsigned long next; + + if (!pgtable_l4_enabled) { + pudp = (pud_t *)p4dp; + } else { + base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); + pudp = base_pud + pud_index(vaddr); + } + + do { + next = pud_addr_end(vaddr, end); + + if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && + (next - vaddr) >= PUD_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd); + set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE)); + continue; + } + + BUG(); + } while (pudp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_populate_p4d(pgd_t *pgdp, + unsigned long vaddr, + unsigned long end) +{ + p4d_t *p4dp, *base_p4d; + phys_addr_t phys_addr; + unsigned long next; + + /* + * We can't use pgd_page_vaddr here as it would return a linear + * mapping address but it is not mapped yet, but when populating + * early_pg_dir, we need the physical address and when populating + * swapper_pg_dir, we need the kernel virtual address so use + * pt_ops facility. + * Note that this test is then completely equivalent to + * p4dp = p4d_offset(pgdp, vaddr) + */ + if (!pgtable_l5_enabled) { + p4dp = (p4d_t *)pgdp; + } else { + base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); + p4dp = base_p4d + p4d_index(vaddr); + } + + do { + next = p4d_addr_end(vaddr, end); + + if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && + (next - vaddr) >= P4D_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_pud); + set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE)); + continue; + } + + kasan_early_populate_pud(p4dp, vaddr, next); + } while (p4dp++, vaddr = next, vaddr != end); +} + +static void __init kasan_early_populate_pgd(pgd_t *pgdp, + unsigned long vaddr, + unsigned long end) +{ + phys_addr_t phys_addr; + unsigned long next; + + do { + next = pgd_addr_end(vaddr, end); + + if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + (next - vaddr) >= PGDIR_SIZE) { + phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d); + set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE)); + continue; + } + + kasan_early_populate_p4d(pgdp, vaddr, next); } while (pgdp++, vaddr = next, vaddr != end); } @@ -295,16 +350,16 @@ asmlinkage void __init kasan_early_init(void) PAGE_TABLE)); } - kasan_populate_pgd(early_pg_dir + pgd_index(KASAN_SHADOW_START), - KASAN_SHADOW_START, KASAN_SHADOW_END, true); + kasan_early_populate_pgd(early_pg_dir + pgd_index(KASAN_SHADOW_START), + KASAN_SHADOW_START, KASAN_SHADOW_END); local_flush_tlb_all(); } void __init kasan_swapper_init(void) { - kasan_populate_pgd(pgd_offset_k(KASAN_SHADOW_START), - KASAN_SHADOW_START, KASAN_SHADOW_END, true); + kasan_early_populate_pgd(pgd_offset_k(KASAN_SHADOW_START), + KASAN_SHADOW_START, KASAN_SHADOW_END); local_flush_tlb_all(); } @@ -314,118 +369,65 @@ static void __init kasan_populate(void *start, void *end) unsigned long vaddr = (unsigned long)start & PAGE_MASK; unsigned long vend = PAGE_ALIGN((unsigned long)end); - kasan_populate_pgd(pgd_offset_k(vaddr), vaddr, vend, false); - - local_flush_tlb_all(); - memset(start, KASAN_SHADOW_INIT, end - start); + kasan_populate_pgd(pgd_offset_k(vaddr), vaddr, vend); } -static void __init kasan_shallow_populate_pmd(pgd_t *pgdp, +static void __init kasan_shallow_populate_pud(p4d_t *p4d, unsigned long vaddr, unsigned long end) { unsigned long next; - pmd_t *pmdp, *base_pmd; - bool is_kasan_pte; - - base_pmd = (pmd_t *)pgd_page_vaddr(*pgdp); - pmdp = base_pmd + pmd_index(vaddr); - - do { - next = pmd_addr_end(vaddr, end); - is_kasan_pte = (pmd_pgtable(*pmdp) == lm_alias(kasan_early_shadow_pte)); - - if (is_kasan_pte) - pmd_clear(pmdp); - } while (pmdp++, vaddr = next, vaddr != end); -} - -static void __init kasan_shallow_populate_pud(pgd_t *pgdp, - unsigned long vaddr, unsigned long end) -{ - unsigned long next; - pud_t *pudp, *base_pud; - pmd_t *base_pmd; - bool is_kasan_pmd; - - base_pud = (pud_t *)pgd_page_vaddr(*pgdp); - pudp = base_pud + pud_index(vaddr); + void *p; + pud_t *pud_k = pud_offset(p4d, vaddr); do { next = pud_addr_end(vaddr, end); - is_kasan_pmd = (pud_pgtable(*pudp) == lm_alias(kasan_early_shadow_pmd)); - if (!is_kasan_pmd) + if (pud_none(*pud_k)) { + p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); continue; + } - base_pmd = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - set_pud(pudp, pfn_pud(PFN_DOWN(__pa(base_pmd)), PAGE_TABLE)); - - if (IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) - continue; - - memcpy(base_pmd, (void *)kasan_early_shadow_pmd, PAGE_SIZE); - kasan_shallow_populate_pmd((pgd_t *)pudp, vaddr, next); - } while (pudp++, vaddr = next, vaddr != end); + BUG(); + } while (pud_k++, vaddr = next, vaddr != end); } -static void __init kasan_shallow_populate_p4d(pgd_t *pgdp, +static void __init kasan_shallow_populate_p4d(pgd_t *pgd, unsigned long vaddr, unsigned long end) { unsigned long next; - p4d_t *p4dp, *base_p4d; - pud_t *base_pud; - bool is_kasan_pud; - - base_p4d = (p4d_t *)pgd_page_vaddr(*pgdp); - p4dp = base_p4d + p4d_index(vaddr); + void *p; + p4d_t *p4d_k = p4d_offset(pgd, vaddr); do { next = p4d_addr_end(vaddr, end); - is_kasan_pud = (p4d_pgtable(*p4dp) == lm_alias(kasan_early_shadow_pud)); - if (!is_kasan_pud) + if (p4d_none(*p4d_k)) { + p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); + set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); continue; + } - base_pud = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - set_p4d(p4dp, pfn_p4d(PFN_DOWN(__pa(base_pud)), PAGE_TABLE)); - - if (IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) - continue; - - memcpy(base_pud, (void *)kasan_early_shadow_pud, PAGE_SIZE); - kasan_shallow_populate_pud((pgd_t *)p4dp, vaddr, next); - } while (p4dp++, vaddr = next, vaddr != end); + kasan_shallow_populate_pud(p4d_k, vaddr, end); + } while (p4d_k++, vaddr = next, vaddr != end); } -#define kasan_shallow_populate_pgd_next(pgdp, vaddr, next) \ - (pgtable_l5_enabled ? \ - kasan_shallow_populate_p4d(pgdp, vaddr, next) : \ - (pgtable_l4_enabled ? \ - kasan_shallow_populate_pud(pgdp, vaddr, next) : \ - kasan_shallow_populate_pmd(pgdp, vaddr, next))) - static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long end) { unsigned long next; void *p; pgd_t *pgd_k = pgd_offset_k(vaddr); - bool is_kasan_pgd_next; do { next = pgd_addr_end(vaddr, end); - is_kasan_pgd_next = (pgd_page_vaddr(*pgd_k) == - (unsigned long)lm_alias(kasan_early_shadow_pgd_next)); - if (is_kasan_pgd_next) { + if (pgd_none(*pgd_k)) { p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); + continue; } - if (IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) - continue; - - memcpy(p, (void *)kasan_early_shadow_pgd_next, PAGE_SIZE); - kasan_shallow_populate_pgd_next(pgd_k, vaddr, next); + kasan_shallow_populate_p4d(pgd_k, vaddr, next); } while (pgd_k++, vaddr = next, vaddr != end); } @@ -435,7 +437,37 @@ static void __init kasan_shallow_populate(void *start, void *end) unsigned long vend = PAGE_ALIGN((unsigned long)end); kasan_shallow_populate_pgd(vaddr, vend); - local_flush_tlb_all(); +} + +static void create_tmp_mapping(void) +{ + void *ptr; + p4d_t *base_p4d; + + /* + * We need to clean the early mapping: this is hard to achieve "in-place", + * so install a temporary mapping like arm64 and x86 do. + */ + memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(pgd_t) * PTRS_PER_PGD); + + /* Copy the last p4d since it is shared with the kernel mapping. */ + if (pgtable_l5_enabled) { + ptr = (p4d_t *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END)); + memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D); + set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)], + pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE)); + base_p4d = tmp_p4d; + } else { + base_p4d = (p4d_t *)tmp_pg_dir; + } + + /* Copy the last pud since it is shared with the kernel mapping. */ + if (pgtable_l4_enabled) { + ptr = (pud_t *)p4d_page_vaddr(*(base_p4d + p4d_index(KASAN_SHADOW_END))); + memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD); + set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)], + pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE)); + } } void __init kasan_init(void) @@ -443,10 +475,27 @@ void __init kasan_init(void) phys_addr_t p_start, p_end; u64 i; - if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) + create_tmp_mapping(); + csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode); + + kasan_early_clear_pgd(pgd_offset_k(KASAN_SHADOW_START), + KASAN_SHADOW_START, KASAN_SHADOW_END); + + kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)FIXADDR_START), + (void *)kasan_mem_to_shadow((void *)VMALLOC_START)); + + if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { kasan_shallow_populate( (void *)kasan_mem_to_shadow((void *)VMALLOC_START), (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); + /* Shallow populate modules and BPF which are vmalloc-allocated */ + kasan_shallow_populate( + (void *)kasan_mem_to_shadow((void *)MODULES_VADDR), + (void *)kasan_mem_to_shadow((void *)MODULES_END)); + } else { + kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)VMALLOC_START), + (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); + } /* Populate the linear mapping */ for_each_mem_range(i, &p_start, &p_end) { @@ -459,8 +508,8 @@ void __init kasan_init(void) kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); } - /* Populate kernel, BPF, modules mapping */ - kasan_populate(kasan_mem_to_shadow((const void *)MODULES_VADDR), + /* Populate kernel */ + kasan_populate(kasan_mem_to_shadow((const void *)MODULES_END), kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G)); for (i = 0; i < PTRS_PER_PTE; i++) @@ -471,4 +520,7 @@ void __init kasan_init(void) memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); init_task.kasan_depth = 0; + + csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | satp_mode); + local_flush_tlb_all(); } diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index 86c56616e5de..ea3d61de065b 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -217,18 +217,26 @@ bool kernel_page_present(struct page *page) pgd = pgd_offset_k(addr); if (!pgd_present(*pgd)) return false; + if (pgd_leaf(*pgd)) + return true; p4d = p4d_offset(pgd, addr); if (!p4d_present(*p4d)) return false; + if (p4d_leaf(*p4d)) + return true; pud = pud_offset(p4d, addr); if (!pud_present(*pud)) return false; + if (pud_leaf(*pud)) + return true; pmd = pmd_offset(pud, addr); if (!pmd_present(*pmd)) return false; + if (pmd_leaf(*pmd)) + return true; pte = pte_offset_kernel(pmd, addr); return pte_present(*pte); diff --git a/arch/riscv/mm/physaddr.c b/arch/riscv/mm/physaddr.c index 9b18bda74154..18706f457da7 100644 --- a/arch/riscv/mm/physaddr.c +++ b/arch/riscv/mm/physaddr.c @@ -33,3 +33,19 @@ phys_addr_t __phys_addr_symbol(unsigned long x) return __va_to_pa_nodebug(x); } EXPORT_SYMBOL(__phys_addr_symbol); + +phys_addr_t linear_mapping_va_to_pa(unsigned long x) +{ + BUG_ON(!kernel_map.va_pa_offset); + + return ((unsigned long)(x) - kernel_map.va_pa_offset); +} +EXPORT_SYMBOL(linear_mapping_va_to_pa); + +void *linear_mapping_pa_to_va(unsigned long x) +{ + BUG_ON(!kernel_map.va_pa_offset); + + return ((void *)((unsigned long)(x) + kernel_map.va_pa_offset)); +} +EXPORT_SYMBOL(linear_mapping_pa_to_va); diff --git a/arch/riscv/mm/ptdump.c b/arch/riscv/mm/ptdump.c index 830e7de65e3a..20a9f991a6d7 100644 --- a/arch/riscv/mm/ptdump.c +++ b/arch/riscv/mm/ptdump.c @@ -59,10 +59,6 @@ struct ptd_mm_info { }; enum address_markers_idx { -#ifdef CONFIG_KASAN - KASAN_SHADOW_START_NR, - KASAN_SHADOW_END_NR, -#endif FIXMAP_START_NR, FIXMAP_END_NR, PCI_IO_START_NR, @@ -74,6 +70,10 @@ enum address_markers_idx { VMALLOC_START_NR, VMALLOC_END_NR, PAGE_OFFSET_NR, +#ifdef CONFIG_KASAN + KASAN_SHADOW_START_NR, + KASAN_SHADOW_END_NR, +#endif #ifdef CONFIG_64BIT MODULES_MAPPING_NR, KERNEL_MAPPING_NR, @@ -82,10 +82,6 @@ enum address_markers_idx { }; static struct addr_marker address_markers[] = { -#ifdef CONFIG_KASAN - {0, "Kasan shadow start"}, - {0, "Kasan shadow end"}, -#endif {0, "Fixmap start"}, {0, "Fixmap end"}, {0, "PCI I/O start"}, @@ -97,6 +93,10 @@ static struct addr_marker address_markers[] = { {0, "vmalloc() area"}, {0, "vmalloc() end"}, {0, "Linear mapping"}, +#ifdef CONFIG_KASAN + {0, "Kasan shadow start"}, + {0, "Kasan shadow end"}, +#endif #ifdef CONFIG_64BIT {0, "Modules/BPF mapping"}, {0, "Kernel mapping"}, @@ -362,10 +362,6 @@ static int __init ptdump_init(void) { unsigned int i, j; -#ifdef CONFIG_KASAN - address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START; - address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END; -#endif address_markers[FIXMAP_START_NR].start_address = FIXADDR_START; address_markers[FIXMAP_END_NR].start_address = FIXADDR_TOP; address_markers[PCI_IO_START_NR].start_address = PCI_IO_START; @@ -377,6 +373,10 @@ static int __init ptdump_init(void) address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; address_markers[VMALLOC_END_NR].start_address = VMALLOC_END; address_markers[PAGE_OFFSET_NR].start_address = PAGE_OFFSET; +#ifdef CONFIG_KASAN + address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START; + address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END; +#endif #ifdef CONFIG_64BIT address_markers[MODULES_MAPPING_NR].start_address = MODULES_VADDR; address_markers[KERNEL_MAPPING_NR].start_address = kernel_map.virt_addr; diff --git a/arch/riscv/tools/relocs_check.sh b/arch/riscv/tools/relocs_check.sh new file mode 100755 index 000000000000..baeb2e7b2290 --- /dev/null +++ b/arch/riscv/tools/relocs_check.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Based on powerpc relocs_check.sh + +# This script checks the relocations of a vmlinux for "suspicious" +# relocations. + +if [ $# -lt 3 ]; then + echo "$0 [path to objdump] [path to nm] [path to vmlinux]" 1>&2 + exit 1 +fi + +bad_relocs=$( +${srctree}/scripts/relocs_check.sh "$@" | + # These relocations are okay + # R_RISCV_RELATIVE + grep -F -w -v 'R_RISCV_RELATIVE' +) + +if [ -z "$bad_relocs" ]; then + exit 0 +fi + +num_bad=$(echo "$bad_relocs" | wc -l) +echo "WARNING: $num_bad bad relocations" +echo "$bad_relocs" diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 9809c74e1240..6dab9c1be508 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -26,10 +26,6 @@ config GENERIC_BUG config GENERIC_BUG_RELATIVE_POINTERS def_bool y -config GENERIC_CSUM - bool - default y if KASAN - config GENERIC_LOCKBREAK def_bool y if PREEMPTION @@ -76,10 +72,12 @@ config S390 select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE select ARCH_HAS_KCOV + select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME + select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_MEMORY select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX @@ -120,18 +118,21 @@ config S390 select ARCH_SUPPORTS_DEBUG_PAGEALLOC select ARCH_SUPPORTS_HUGETLBFS select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_USE_SYM_ANNOTATIONS select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANTS_NO_INSTR select ARCH_WANT_DEFAULT_BPF_JIT - select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP select ARCH_WANT_IPC_PARSE_VERSION + select ARCH_WANT_OPTIMIZE_VMEMMAP select BUILDTIME_TABLE_SORT select CLONE_BACKWARDS2 select DMA_OPS if PCI select DYNAMIC_FTRACE if FUNCTION_TRACER - select GCC12_NO_ARRAY_BOUNDS + select FUNCTION_ALIGNMENT_8B if CC_IS_GCC + select FUNCTION_ALIGNMENT_16B if !CC_IS_GCC select GENERIC_ALLOCATOR select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_VULNERABILITIES @@ -152,6 +153,7 @@ config S390 select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SOFT_DIRTY + select HAVE_ARCH_STACKLEAK select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_ARCH_VMAP_STACK @@ -467,19 +469,11 @@ config SCHED_SMT config SCHED_MC def_bool n -config SCHED_BOOK - def_bool n - -config SCHED_DRAWER - def_bool n - config SCHED_TOPOLOGY def_bool y prompt "Topology scheduler support" select SCHED_SMT select SCHED_MC - select SCHED_BOOK - select SCHED_DRAWER help Topology scheduler support improves the CPU scheduler's decision making when dealing with machines that have multi-threading, @@ -714,7 +708,6 @@ config EADM_SCH config VFIO_CCW def_tristate n prompt "Support for VFIO-CCW subchannels" - depends on S390_CCW_IOMMU depends on VFIO select VFIO_MDEV help @@ -726,7 +719,7 @@ config VFIO_CCW config VFIO_AP def_tristate n prompt "VFIO support for AP devices" - depends on S390_AP_IOMMU && KVM + depends on KVM depends on VFIO depends on ZCRYPT select VFIO_MDEV diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index c0fd29133f27..b07b0610950e 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -66,16 +66,6 @@ static struct ctl_table appldata_table[] = { { }, }; -static struct ctl_table appldata_dir_table[] = { - { - .procname = appldata_proc_name, - .maxlen = 0, - .mode = S_IRUGO | S_IXUGO, - .child = appldata_table, - }, - { }, -}; - /* * Timer */ @@ -291,7 +281,7 @@ appldata_generic_handler(struct ctl_table *ctl, int write, mutex_lock(&appldata_ops_mutex); list_for_each(lh, &appldata_ops_list) { tmp_ops = list_entry(lh, struct appldata_ops, list); - if (&tmp_ops->ctl_table[2] == ctl) { + if (&tmp_ops->ctl_table[0] == ctl) { found = 1; } } @@ -361,7 +351,8 @@ int appldata_register_ops(struct appldata_ops *ops) if (ops->size > APPLDATA_MAX_REC_SIZE) return -EINVAL; - ops->ctl_table = kcalloc(4, sizeof(struct ctl_table), GFP_KERNEL); + /* The last entry must be an empty one */ + ops->ctl_table = kcalloc(2, sizeof(struct ctl_table), GFP_KERNEL); if (!ops->ctl_table) return -ENOMEM; @@ -369,17 +360,12 @@ int appldata_register_ops(struct appldata_ops *ops) list_add(&ops->list, &appldata_ops_list); mutex_unlock(&appldata_ops_mutex); - ops->ctl_table[0].procname = appldata_proc_name; - ops->ctl_table[0].maxlen = 0; - ops->ctl_table[0].mode = S_IRUGO | S_IXUGO; - ops->ctl_table[0].child = &ops->ctl_table[2]; + ops->ctl_table[0].procname = ops->name; + ops->ctl_table[0].mode = S_IRUGO | S_IWUSR; + ops->ctl_table[0].proc_handler = appldata_generic_handler; + ops->ctl_table[0].data = ops; - ops->ctl_table[2].procname = ops->name; - ops->ctl_table[2].mode = S_IRUGO | S_IWUSR; - ops->ctl_table[2].proc_handler = appldata_generic_handler; - ops->ctl_table[2].data = ops; - - ops->sysctl_header = register_sysctl_table(ops->ctl_table); + ops->sysctl_header = register_sysctl(appldata_proc_name, ops->ctl_table); if (!ops->sysctl_header) goto out; return 0; @@ -422,7 +408,7 @@ static int __init appldata_init(void) appldata_wq = alloc_ordered_workqueue("appldata", 0); if (!appldata_wq) return -ENOMEM; - appldata_sysctl_header = register_sysctl_table(appldata_dir_table); + appldata_sysctl_header = register_sysctl(appldata_proc_name, appldata_table); return 0; } diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index cebd4ca16916..c7c81e5f9218 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile @@ -35,7 +35,7 @@ endif CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char -obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o vmem.o +obj-y := head.o als.o startup.o physmem_info.o ipl_parm.o ipl_report.o vmem.o obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o obj-y += version.o pgm_check_info.o ctype.o ipl_data.o machine_kexec_reloc.o obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) += uv.o diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 58ce701d6110..222c6886acf6 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h @@ -8,6 +8,8 @@ #ifndef __ASSEMBLY__ +#include + struct machine_info { unsigned char has_edat1 : 1; unsigned char has_edat2 : 1; @@ -30,24 +32,46 @@ struct vmlinux_info { unsigned long init_mm_off; unsigned long swapper_pg_dir_off; unsigned long invalid_pg_dir_off; +#ifdef CONFIG_KASAN + unsigned long kasan_early_shadow_page_off; + unsigned long kasan_early_shadow_pte_off; + unsigned long kasan_early_shadow_pmd_off; + unsigned long kasan_early_shadow_pud_off; + unsigned long kasan_early_shadow_p4d_off; +#endif }; void startup_kernel(void); -unsigned long detect_memory(unsigned long *safe_addr); -void mem_detect_set_usable_limit(unsigned long limit); +unsigned long detect_max_physmem_end(void); +void detect_physmem_online_ranges(unsigned long max_physmem_end); +void physmem_set_usable_limit(unsigned long limit); +void physmem_reserve(enum reserved_range_type type, unsigned long addr, unsigned long size); +void physmem_free(enum reserved_range_type type); +/* for continuous/multiple allocations per type */ +unsigned long physmem_alloc_top_down(enum reserved_range_type type, unsigned long size, + unsigned long align); +/* for single allocations, 1 per type */ +unsigned long physmem_alloc_range(enum reserved_range_type type, unsigned long size, + unsigned long align, unsigned long min, unsigned long max, + bool die_on_oom); +unsigned long get_physmem_alloc_pos(void); +bool ipl_report_certs_intersects(unsigned long addr, unsigned long size, + unsigned long *intersection_start); bool is_ipl_block_dump(void); void store_ipl_parmblock(void); -unsigned long read_ipl_report(unsigned long safe_addr); +int read_ipl_report(void); +void save_ipl_cert_comp_list(void); void setup_boot_command_line(void); void parse_boot_command_line(void); void verify_facilities(void); void print_missing_facilities(void); void sclp_early_setup_buffer(void); void print_pgm_check_info(void); -unsigned long get_random_base(unsigned long safe_addr); +unsigned long randomize_within_range(unsigned long size, unsigned long align, + unsigned long min, unsigned long max); void setup_vmem(unsigned long asce_limit); -unsigned long vmem_estimate_memory_needs(unsigned long online_mem_total); void __printf(1, 2) decompressor_printk(const char *fmt, ...); +void print_stacktrace(unsigned long sp); void error(char *m); extern struct machine_info machine; @@ -57,12 +81,11 @@ extern const char kernel_version[]; extern unsigned long memory_limit; extern unsigned long vmalloc_size; extern int vmalloc_size_set; -extern int kaslr_enabled; extern char __boot_data_start[], __boot_data_end[]; extern char __boot_data_preserved_start[], __boot_data_preserved_end[]; extern char _decompressor_syms_start[], _decompressor_syms_end[]; extern char _stack_start[], _stack_end[]; -extern char _end[]; +extern char _end[], _decompressor_end[]; extern unsigned char _compressed_start[]; extern unsigned char _compressed_end[]; extern struct vmlinux_info _vmlinux_info; @@ -70,5 +93,10 @@ extern struct vmlinux_info _vmlinux_info; #define __abs_lowcore_pa(x) (((unsigned long)(x) - __abs_lowcore) % sizeof(struct lowcore)) +static inline bool intersects(unsigned long addr0, unsigned long size0, + unsigned long addr1, unsigned long size1) +{ + return addr0 + size0 > addr1 && addr1 + size1 > addr0; +} #endif /* __ASSEMBLY__ */ #endif /* BOOT_BOOT_H */ diff --git a/arch/s390/boot/install.sh b/arch/s390/boot/install.sh index 616ba1660f08..a13dd2f2aa1c 100755 --- a/arch/s390/boot/install.sh +++ b/arch/s390/boot/install.sh @@ -17,8 +17,8 @@ echo "Warning: '${INSTALLKERNEL}' command not available - additional " \ "bootloader config required" >&2 -if [ -f $4/vmlinuz-$1 ]; then mv $4/vmlinuz-$1 $4/vmlinuz-$1.old; fi -if [ -f $4/System.map-$1 ]; then mv $4/System.map-$1 $4/System.map-$1.old; fi +if [ -f "$4/vmlinuz-$1" ]; then mv -- "$4/vmlinuz-$1" "$4/vmlinuz-$1.old"; fi +if [ -f "$4/System.map-$1" ]; then mv -- "$4/System.map-$1" "$4/System.map-$1.old"; fi -cat $2 > $4/vmlinuz-$1 -cp $3 $4/System.map-$1 +cat -- "$2" > "$4/vmlinuz-$1" +cp -- "$3" "$4/System.map-$1" diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index c1f8f7999fed..8753cb0339e5 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -24,11 +24,11 @@ int __bootdata(noexec_disabled); unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL; struct ipl_parameter_block __bootdata_preserved(ipl_block); int __bootdata_preserved(ipl_block_valid); +int __bootdata_preserved(__kaslr_enabled); unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE; unsigned long memory_limit; int vmalloc_size_set; -int kaslr_enabled; static inline int __diag308(unsigned long subcode, void *addr) { @@ -264,7 +264,7 @@ void parse_boot_command_line(void) char *args; int rc; - kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE); + __kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE); args = strcpy(command_line_buf, early_command_line); while (*args) { args = next_arg(args, ¶m, &val); @@ -300,7 +300,7 @@ void parse_boot_command_line(void) modify_fac_list(val); if (!strcmp(param, "nokaslr")) - kaslr_enabled = 0; + __kaslr_enabled = 0; #if IS_ENABLED(CONFIG_KVM) if (!strcmp(param, "prot_virt")) { diff --git a/arch/s390/boot/ipl_report.c b/arch/s390/boot/ipl_report.c index 74b5cd264862..1803035e68d2 100644 --- a/arch/s390/boot/ipl_report.c +++ b/arch/s390/boot/ipl_report.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "boot.h" @@ -16,20 +17,16 @@ unsigned long __bootdata_preserved(ipl_cert_list_size); unsigned long __bootdata(early_ipl_comp_list_addr); unsigned long __bootdata(early_ipl_comp_list_size); +static struct ipl_rb_certificates *certs; +static struct ipl_rb_components *comps; +static bool ipl_report_needs_saving; + #define for_each_rb_entry(entry, rb) \ for (entry = rb->entries; \ (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \ entry++) -static inline bool intersects(unsigned long addr0, unsigned long size0, - unsigned long addr1, unsigned long size1) -{ - return addr0 + size0 > addr1 && addr1 + size1 > addr0; -} - -static unsigned long find_bootdata_space(struct ipl_rb_components *comps, - struct ipl_rb_certificates *certs, - unsigned long safe_addr) +static unsigned long get_cert_comp_list_size(void) { struct ipl_rb_certificate_entry *cert; struct ipl_rb_component_entry *comp; @@ -44,44 +41,27 @@ static unsigned long find_bootdata_space(struct ipl_rb_components *comps, ipl_cert_list_size = 0; for_each_rb_entry(cert, certs) ipl_cert_list_size += sizeof(unsigned int) + cert->len; - size = ipl_cert_list_size + early_ipl_comp_list_size; - - /* - * Start from safe_addr to find a free memory area large - * enough for the IPL report boot data. This area is used - * for ipl_cert_list_addr/ipl_cert_list_size and - * early_ipl_comp_list_addr/early_ipl_comp_list_size. It must - * not overlap with any component or any certificate. - */ -repeat: - if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_data.start && initrd_data.size && - intersects(initrd_data.start, initrd_data.size, safe_addr, size)) - safe_addr = initrd_data.start + initrd_data.size; - if (intersects(safe_addr, size, (unsigned long)comps, comps->len)) { - safe_addr = (unsigned long)comps + comps->len; - goto repeat; - } - for_each_rb_entry(comp, comps) - if (intersects(safe_addr, size, comp->addr, comp->len)) { - safe_addr = comp->addr + comp->len; - goto repeat; - } - if (intersects(safe_addr, size, (unsigned long)certs, certs->len)) { - safe_addr = (unsigned long)certs + certs->len; - goto repeat; - } - for_each_rb_entry(cert, certs) - if (intersects(safe_addr, size, cert->addr, cert->len)) { - safe_addr = cert->addr + cert->len; - goto repeat; - } - early_ipl_comp_list_addr = safe_addr; - ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size; - - return safe_addr + size; + return ipl_cert_list_size + early_ipl_comp_list_size; } -static void copy_components_bootdata(struct ipl_rb_components *comps) +bool ipl_report_certs_intersects(unsigned long addr, unsigned long size, + unsigned long *intersection_start) +{ + struct ipl_rb_certificate_entry *cert; + + if (!ipl_report_needs_saving) + return false; + + for_each_rb_entry(cert, certs) { + if (intersects(addr, size, cert->addr, cert->len)) { + *intersection_start = cert->addr; + return true; + } + } + return false; +} + +static void copy_components_bootdata(void) { struct ipl_rb_component_entry *comp, *ptr; @@ -90,7 +70,7 @@ static void copy_components_bootdata(struct ipl_rb_components *comps) memcpy(ptr++, comp, sizeof(*ptr)); } -static void copy_certificates_bootdata(struct ipl_rb_certificates *certs) +static void copy_certificates_bootdata(void) { struct ipl_rb_certificate_entry *cert; void *ptr; @@ -104,10 +84,8 @@ static void copy_certificates_bootdata(struct ipl_rb_certificates *certs) } } -unsigned long read_ipl_report(unsigned long safe_addr) +int read_ipl_report(void) { - struct ipl_rb_certificates *certs; - struct ipl_rb_components *comps; struct ipl_pl_hdr *pl_hdr; struct ipl_rl_hdr *rl_hdr; struct ipl_rb_hdr *rb_hdr; @@ -120,7 +98,7 @@ unsigned long read_ipl_report(unsigned long safe_addr) */ if (!ipl_block_valid || !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR)) - return safe_addr; + return -1; ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL); /* * There is an IPL report, to find it load the pointer to the @@ -158,16 +136,30 @@ unsigned long read_ipl_report(unsigned long safe_addr) * With either the component list or the certificate list * missing the kernel will stay ignorant of secure IPL. */ - if (!comps || !certs) - return safe_addr; + if (!comps || !certs) { + certs = NULL; + return -1; + } - /* - * Copy component and certificate list to a safe area - * where the decompressed kernel can find them. - */ - safe_addr = find_bootdata_space(comps, certs, safe_addr); - copy_components_bootdata(comps); - copy_certificates_bootdata(certs); - - return safe_addr; + ipl_report_needs_saving = true; + physmem_reserve(RR_IPLREPORT, (unsigned long)pl_hdr, + (unsigned long)rl_end - (unsigned long)pl_hdr); + return 0; +} + +void save_ipl_cert_comp_list(void) +{ + unsigned long size; + + if (!ipl_report_needs_saving) + return; + + size = get_cert_comp_list_size(); + early_ipl_comp_list_addr = physmem_alloc_top_down(RR_CERT_COMP_LIST, size, sizeof(int)); + ipl_cert_list_addr = early_ipl_comp_list_addr + early_ipl_comp_list_size; + + copy_components_bootdata(); + copy_certificates_bootdata(); + physmem_free(RR_IPLREPORT); + ipl_report_needs_saving = false; } diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c index 3e3d846400b4..90602101e2ae 100644 --- a/arch/s390/boot/kaslr.c +++ b/arch/s390/boot/kaslr.c @@ -3,7 +3,7 @@ * Copyright IBM Corp. 2019 */ #include -#include +#include #include #include #include @@ -91,113 +91,108 @@ static int get_random(unsigned long limit, unsigned long *value) return 0; } +static void sort_reserved_ranges(struct reserved_range *res, unsigned long size) +{ + struct reserved_range tmp; + int i, j; + + for (i = 1; i < size; i++) { + tmp = res[i]; + for (j = i - 1; j >= 0 && res[j].start > tmp.start; j--) + res[j + 1] = res[j]; + res[j + 1] = tmp; + } +} + +static unsigned long iterate_valid_positions(unsigned long size, unsigned long align, + unsigned long _min, unsigned long _max, + struct reserved_range *res, size_t res_count, + bool pos_count, unsigned long find_pos) +{ + unsigned long start, end, tmp_end, range_pos, pos = 0; + struct reserved_range *res_end = res + res_count; + struct reserved_range *skip_res; + int i; + + align = max(align, 8UL); + _min = round_up(_min, align); + for_each_physmem_usable_range(i, &start, &end) { + if (_min >= end) + continue; + start = round_up(start, align); + if (start >= _max) + break; + start = max(_min, start); + end = min(_max, end); + + while (start + size <= end) { + /* skip reserved ranges below the start */ + while (res && res->end <= start) { + res++; + if (res >= res_end) + res = NULL; + } + skip_res = NULL; + tmp_end = end; + /* has intersecting reserved range */ + if (res && res->start < end) { + skip_res = res; + tmp_end = res->start; + } + if (start + size <= tmp_end) { + range_pos = (tmp_end - start - size) / align + 1; + if (pos_count) { + pos += range_pos; + } else { + if (range_pos >= find_pos) + return start + (find_pos - 1) * align; + find_pos -= range_pos; + } + } + if (!skip_res) + break; + start = round_up(skip_res->end, align); + } + } + + return pos_count ? pos : 0; +} + /* - * To randomize kernel base address we have to consider several facts: - * 1. physical online memory might not be continuous and have holes. mem_detect - * info contains list of online memory ranges we should consider. - * 2. we have several memory regions which are occupied and we should not - * overlap and destroy them. Currently safe_addr tells us the border below - * which all those occupied regions are. We are safe to use anything above - * safe_addr. - * 3. the upper limit might apply as well, even if memory above that limit is - * online. Currently those limitations are: - * 3.1. Limit set by "mem=" kernel command line option - * 3.2. memory reserved at the end for kasan initialization. - * 4. kernel base address must be aligned to THREAD_SIZE (kernel stack size). - * Which is required for CONFIG_CHECK_STACK. Currently THREAD_SIZE is 4 pages - * (16 pages when the kernel is built with kasan enabled) - * Assumptions: - * 1. kernel size (including .bss size) and upper memory limit are page aligned. - * 2. mem_detect memory region start is THREAD_SIZE aligned / end is PAGE_SIZE - * aligned (in practice memory configurations granularity on z/VM and LPAR - * is 1mb). + * Two types of decompressor memory allocations/reserves are considered + * differently. * - * To guarantee uniform distribution of kernel base address among all suitable - * addresses we generate random value just once. For that we need to build a - * continuous range in which every value would be suitable. We can build this - * range by simply counting all suitable addresses (let's call them positions) - * which would be valid as kernel base address. To count positions we iterate - * over online memory ranges. For each range which is big enough for the - * kernel image we count all suitable addresses we can put the kernel image at - * that is - * (end - start - kernel_size) / THREAD_SIZE + 1 - * Two functions count_valid_kernel_positions and position_to_address help - * to count positions in memory range given and then convert position back - * to address. + * "Static" or "single" allocations are done via physmem_alloc_range() and + * physmem_reserve(), and they are listed in physmem_info.reserved[]. Each + * type of "static" allocation can only have one allocation per type and + * cannot have chains. + * + * On the other hand, "dynamic" or "repetitive" allocations are done via + * physmem_alloc_top_down(). These allocations are tightly packed together + * top down from the end of online memory. physmem_alloc_pos represents + * current position where those allocations start. + * + * Functions randomize_within_range() and iterate_valid_positions() + * only consider "dynamic" allocations by never looking above + * physmem_alloc_pos. "Static" allocations, however, are explicitly + * considered by checking the "res" (reserves) array. The first + * reserved_range of a "dynamic" allocation may also be checked along the + * way, but it will always be above the maximum value anyway. */ -static unsigned long count_valid_kernel_positions(unsigned long kernel_size, - unsigned long _min, - unsigned long _max) +unsigned long randomize_within_range(unsigned long size, unsigned long align, + unsigned long min, unsigned long max) { - unsigned long start, end, pos = 0; - int i; + struct reserved_range res[RR_MAX]; + unsigned long max_pos, pos; - for_each_mem_detect_usable_block(i, &start, &end) { - if (_min >= end) - continue; - if (start >= _max) - break; - start = max(_min, start); - end = min(_max, end); - if (end - start < kernel_size) - continue; - pos += (end - start - kernel_size) / THREAD_SIZE + 1; - } + memcpy(res, physmem_info.reserved, sizeof(res)); + sort_reserved_ranges(res, ARRAY_SIZE(res)); + max = min(max, get_physmem_alloc_pos()); - return pos; -} - -static unsigned long position_to_address(unsigned long pos, unsigned long kernel_size, - unsigned long _min, unsigned long _max) -{ - unsigned long start, end; - int i; - - for_each_mem_detect_usable_block(i, &start, &end) { - if (_min >= end) - continue; - if (start >= _max) - break; - start = max(_min, start); - end = min(_max, end); - if (end - start < kernel_size) - continue; - if ((end - start - kernel_size) / THREAD_SIZE + 1 >= pos) - return start + (pos - 1) * THREAD_SIZE; - pos -= (end - start - kernel_size) / THREAD_SIZE + 1; - } - - return 0; -} - -unsigned long get_random_base(unsigned long safe_addr) -{ - unsigned long usable_total = get_mem_detect_usable_total(); - unsigned long memory_limit = get_mem_detect_end(); - unsigned long base_pos, max_pos, kernel_size; - int i; - - /* - * Avoid putting kernel in the end of physical memory - * which vmem and kasan code will use for shadow memory and - * pgtable mapping allocations. - */ - memory_limit -= kasan_estimate_memory_needs(usable_total); - memory_limit -= vmem_estimate_memory_needs(usable_total); - - safe_addr = ALIGN(safe_addr, THREAD_SIZE); - kernel_size = vmlinux.image_size + vmlinux.bss_size; - if (safe_addr + kernel_size > memory_limit) + max_pos = iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), true, 0); + if (!max_pos) return 0; - - max_pos = count_valid_kernel_positions(kernel_size, safe_addr, memory_limit); - if (!max_pos) { - sclp_early_printk("KASLR disabled: not enough memory\n"); + if (get_random(max_pos, &pos)) return 0; - } - - /* we need a value in the range [1, base_pos] inclusive */ - if (get_random(max_pos, &base_pos)) - return 0; - return position_to_address(base_pos + 1, kernel_size, safe_addr, memory_limit); + return iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), false, pos + 1); } diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c deleted file mode 100644 index 35f4ba11f7fd..000000000000 --- a/arch/s390/boot/mem_detect.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include "decompressor.h" -#include "boot.h" - -struct mem_detect_info __bootdata(mem_detect); - -/* up to 256 storage elements, 1020 subincrements each */ -#define ENTRIES_EXTENDED_MAX \ - (256 * (1020 / 2) * sizeof(struct mem_detect_block)) - -static struct mem_detect_block *__get_mem_detect_block_ptr(u32 n) -{ - if (n < MEM_INLINED_ENTRIES) - return &mem_detect.entries[n]; - return &mem_detect.entries_extended[n - MEM_INLINED_ENTRIES]; -} - -/* - * sequential calls to add_mem_detect_block with adjacent memory areas - * are merged together into single memory block. - */ -void add_mem_detect_block(u64 start, u64 end) -{ - struct mem_detect_block *block; - - if (mem_detect.count) { - block = __get_mem_detect_block_ptr(mem_detect.count - 1); - if (block->end == start) { - block->end = end; - return; - } - } - - block = __get_mem_detect_block_ptr(mem_detect.count); - block->start = start; - block->end = end; - mem_detect.count++; -} - -static int __diag260(unsigned long rx1, unsigned long rx2) -{ - unsigned long reg1, reg2, ry; - union register_pair rx; - psw_t old; - int rc; - - rx.even = rx1; - rx.odd = rx2; - ry = 0x10; /* storage configuration */ - rc = -1; /* fail */ - asm volatile( - " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" - " epsw %[reg1],%[reg2]\n" - " st %[reg1],0(%[psw_pgm])\n" - " st %[reg2],4(%[psw_pgm])\n" - " larl %[reg1],1f\n" - " stg %[reg1],8(%[psw_pgm])\n" - " diag %[rx],%[ry],0x260\n" - " ipm %[rc]\n" - " srl %[rc],28\n" - "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : [reg1] "=&d" (reg1), - [reg2] "=&a" (reg2), - [rc] "+&d" (rc), - [ry] "+&d" (ry), - "+Q" (S390_lowcore.program_new_psw), - "=Q" (old) - : [rx] "d" (rx.pair), - [psw_old] "a" (&old), - [psw_pgm] "a" (&S390_lowcore.program_new_psw) - : "cc", "memory"); - return rc == 0 ? ry : -1; -} - -static int diag260(void) -{ - int rc, i; - - struct { - unsigned long start; - unsigned long end; - } storage_extents[8] __aligned(16); /* VM supports up to 8 extends */ - - memset(storage_extents, 0, sizeof(storage_extents)); - rc = __diag260((unsigned long)storage_extents, sizeof(storage_extents)); - if (rc == -1) - return -1; - - for (i = 0; i < min_t(int, rc, ARRAY_SIZE(storage_extents)); i++) - add_mem_detect_block(storage_extents[i].start, storage_extents[i].end + 1); - return 0; -} - -static int tprot(unsigned long addr) -{ - unsigned long reg1, reg2; - int rc = -EFAULT; - psw_t old; - - asm volatile( - " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" - " epsw %[reg1],%[reg2]\n" - " st %[reg1],0(%[psw_pgm])\n" - " st %[reg2],4(%[psw_pgm])\n" - " larl %[reg1],1f\n" - " stg %[reg1],8(%[psw_pgm])\n" - " tprot 0(%[addr]),0\n" - " ipm %[rc]\n" - " srl %[rc],28\n" - "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : [reg1] "=&d" (reg1), - [reg2] "=&a" (reg2), - [rc] "+&d" (rc), - "=Q" (S390_lowcore.program_new_psw.addr), - "=Q" (old) - : [psw_old] "a" (&old), - [psw_pgm] "a" (&S390_lowcore.program_new_psw), - [addr] "a" (addr) - : "cc", "memory"); - return rc; -} - -static unsigned long search_mem_end(void) -{ - unsigned long range = 1 << (MAX_PHYSMEM_BITS - 20); /* in 1MB blocks */ - unsigned long offset = 0; - unsigned long pivot; - - while (range > 1) { - range >>= 1; - pivot = offset + range; - if (!tprot(pivot << 20)) - offset = pivot; - } - return (offset + 1) << 20; -} - -unsigned long detect_memory(unsigned long *safe_addr) -{ - unsigned long max_physmem_end = 0; - - sclp_early_get_memsize(&max_physmem_end); - mem_detect.entries_extended = (struct mem_detect_block *)ALIGN(*safe_addr, sizeof(u64)); - - if (!sclp_early_read_storage_info()) { - mem_detect.info_source = MEM_DETECT_SCLP_STOR_INFO; - } else if (!diag260()) { - mem_detect.info_source = MEM_DETECT_DIAG260; - max_physmem_end = max_physmem_end ?: get_mem_detect_end(); - } else if (max_physmem_end) { - add_mem_detect_block(0, max_physmem_end); - mem_detect.info_source = MEM_DETECT_SCLP_READ_INFO; - } else { - max_physmem_end = search_mem_end(); - add_mem_detect_block(0, max_physmem_end); - mem_detect.info_source = MEM_DETECT_BIN_SEARCH; - } - - if (mem_detect.count > MEM_INLINED_ENTRIES) { - *safe_addr += (mem_detect.count - MEM_INLINED_ENTRIES) * - sizeof(struct mem_detect_block); - } - - return max_physmem_end; -} - -void mem_detect_set_usable_limit(unsigned long limit) -{ - struct mem_detect_block *block; - int i; - - /* make sure mem_detect.usable ends up within online memory block */ - for (i = 0; i < mem_detect.count; i++) { - block = __get_mem_detect_block_ptr(i); - if (block->start >= limit) - break; - if (block->end >= limit) { - mem_detect.usable = limit; - break; - } - mem_detect.usable = block->end; - } -} diff --git a/arch/s390/boot/pgm_check_info.c b/arch/s390/boot/pgm_check_info.c index c2a1defc79da..97244cd7a206 100644 --- a/arch/s390/boot/pgm_check_info.c +++ b/arch/s390/boot/pgm_check_info.c @@ -123,11 +123,10 @@ out: sclp_early_printk(buf); } -static noinline void print_stacktrace(void) +void print_stacktrace(unsigned long sp) { struct stack_info boot_stack = { STACK_TYPE_TASK, (unsigned long)_stack_start, (unsigned long)_stack_end }; - unsigned long sp = S390_lowcore.gpregs_save_area[15]; bool first = true; decompressor_printk("Call Trace:\n"); @@ -154,7 +153,7 @@ void print_pgm_check_info(void) decompressor_printk("Kernel command line: %s\n", early_command_line); decompressor_printk("Kernel fault: interruption code %04x ilc:%x\n", S390_lowcore.pgm_code, S390_lowcore.pgm_ilc >> 1); - if (kaslr_enabled) + if (kaslr_enabled()) decompressor_printk("Kernel random base: %lx\n", __kaslr_offset); decompressor_printk("PSW : %016lx %016lx (%pS)\n", S390_lowcore.psw_save_area.mask, @@ -173,7 +172,7 @@ void print_pgm_check_info(void) gpregs[8], gpregs[9], gpregs[10], gpregs[11]); decompressor_printk(" %016lx %016lx %016lx %016lx\n", gpregs[12], gpregs[13], gpregs[14], gpregs[15]); - print_stacktrace(); + print_stacktrace(S390_lowcore.gpregs_save_area[15]); decompressor_printk("Last Breaking-Event-Address:\n"); decompressor_printk(" [<%016lx>] %pS\n", (unsigned long)S390_lowcore.pgm_last_break, (void *)S390_lowcore.pgm_last_break); diff --git a/arch/s390/boot/physmem_info.c b/arch/s390/boot/physmem_info.c new file mode 100644 index 000000000000..0cf79826eef9 --- /dev/null +++ b/arch/s390/boot/physmem_info.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "decompressor.h" +#include "boot.h" + +struct physmem_info __bootdata(physmem_info); +static unsigned int physmem_alloc_ranges; +static unsigned long physmem_alloc_pos; + +/* up to 256 storage elements, 1020 subincrements each */ +#define ENTRIES_EXTENDED_MAX \ + (256 * (1020 / 2) * sizeof(struct physmem_range)) + +static struct physmem_range *__get_physmem_range_ptr(u32 n) +{ + if (n < MEM_INLINED_ENTRIES) + return &physmem_info.online[n]; + if (unlikely(!physmem_info.online_extended)) { + physmem_info.online_extended = (struct physmem_range *)physmem_alloc_range( + RR_MEM_DETECT_EXTENDED, ENTRIES_EXTENDED_MAX, sizeof(long), 0, + physmem_alloc_pos, true); + } + return &physmem_info.online_extended[n - MEM_INLINED_ENTRIES]; +} + +/* + * sequential calls to add_physmem_online_range with adjacent memory ranges + * are merged together into single memory range. + */ +void add_physmem_online_range(u64 start, u64 end) +{ + struct physmem_range *range; + + if (physmem_info.range_count) { + range = __get_physmem_range_ptr(physmem_info.range_count - 1); + if (range->end == start) { + range->end = end; + return; + } + } + + range = __get_physmem_range_ptr(physmem_info.range_count); + range->start = start; + range->end = end; + physmem_info.range_count++; +} + +static int __diag260(unsigned long rx1, unsigned long rx2) +{ + unsigned long reg1, reg2, ry; + union register_pair rx; + psw_t old; + int rc; + + rx.even = rx1; + rx.odd = rx2; + ry = 0x10; /* storage configuration */ + rc = -1; /* fail */ + asm volatile( + " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" + " epsw %[reg1],%[reg2]\n" + " st %[reg1],0(%[psw_pgm])\n" + " st %[reg2],4(%[psw_pgm])\n" + " larl %[reg1],1f\n" + " stg %[reg1],8(%[psw_pgm])\n" + " diag %[rx],%[ry],0x260\n" + " ipm %[rc]\n" + " srl %[rc],28\n" + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" + : [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), + [rc] "+&d" (rc), + [ry] "+&d" (ry), + "+Q" (S390_lowcore.program_new_psw), + "=Q" (old) + : [rx] "d" (rx.pair), + [psw_old] "a" (&old), + [psw_pgm] "a" (&S390_lowcore.program_new_psw) + : "cc", "memory"); + return rc == 0 ? ry : -1; +} + +static int diag260(void) +{ + int rc, i; + + struct { + unsigned long start; + unsigned long end; + } storage_extents[8] __aligned(16); /* VM supports up to 8 extends */ + + memset(storage_extents, 0, sizeof(storage_extents)); + rc = __diag260((unsigned long)storage_extents, sizeof(storage_extents)); + if (rc == -1) + return -1; + + for (i = 0; i < min_t(int, rc, ARRAY_SIZE(storage_extents)); i++) + add_physmem_online_range(storage_extents[i].start, storage_extents[i].end + 1); + return 0; +} + +static int tprot(unsigned long addr) +{ + unsigned long reg1, reg2; + int rc = -EFAULT; + psw_t old; + + asm volatile( + " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" + " epsw %[reg1],%[reg2]\n" + " st %[reg1],0(%[psw_pgm])\n" + " st %[reg2],4(%[psw_pgm])\n" + " larl %[reg1],1f\n" + " stg %[reg1],8(%[psw_pgm])\n" + " tprot 0(%[addr]),0\n" + " ipm %[rc]\n" + " srl %[rc],28\n" + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" + : [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), + [rc] "+&d" (rc), + "=Q" (S390_lowcore.program_new_psw.addr), + "=Q" (old) + : [psw_old] "a" (&old), + [psw_pgm] "a" (&S390_lowcore.program_new_psw), + [addr] "a" (addr) + : "cc", "memory"); + return rc; +} + +static unsigned long search_mem_end(void) +{ + unsigned long range = 1 << (MAX_PHYSMEM_BITS - 20); /* in 1MB blocks */ + unsigned long offset = 0; + unsigned long pivot; + + while (range > 1) { + range >>= 1; + pivot = offset + range; + if (!tprot(pivot << 20)) + offset = pivot; + } + return (offset + 1) << 20; +} + +unsigned long detect_max_physmem_end(void) +{ + unsigned long max_physmem_end = 0; + + if (!sclp_early_get_memsize(&max_physmem_end)) { + physmem_info.info_source = MEM_DETECT_SCLP_READ_INFO; + } else { + max_physmem_end = search_mem_end(); + physmem_info.info_source = MEM_DETECT_BIN_SEARCH; + } + return max_physmem_end; +} + +void detect_physmem_online_ranges(unsigned long max_physmem_end) +{ + if (!sclp_early_read_storage_info()) { + physmem_info.info_source = MEM_DETECT_SCLP_STOR_INFO; + } else if (!diag260()) { + physmem_info.info_source = MEM_DETECT_DIAG260; + } else if (max_physmem_end) { + add_physmem_online_range(0, max_physmem_end); + } +} + +void physmem_set_usable_limit(unsigned long limit) +{ + physmem_info.usable = limit; + physmem_alloc_pos = limit; +} + +static void die_oom(unsigned long size, unsigned long align, unsigned long min, unsigned long max) +{ + unsigned long start, end, total_mem = 0, total_reserved_mem = 0; + struct reserved_range *range; + enum reserved_range_type t; + int i; + + decompressor_printk("Linux version %s\n", kernel_version); + if (!is_prot_virt_guest() && early_command_line[0]) + decompressor_printk("Kernel command line: %s\n", early_command_line); + decompressor_printk("Out of memory allocating %lx bytes %lx aligned in range %lx:%lx\n", + size, align, min, max); + decompressor_printk("Reserved memory ranges:\n"); + for_each_physmem_reserved_range(t, range, &start, &end) { + decompressor_printk("%016lx %016lx %s\n", start, end, get_rr_type_name(t)); + total_reserved_mem += end - start; + } + decompressor_printk("Usable online memory ranges (info source: %s [%x]):\n", + get_physmem_info_source(), physmem_info.info_source); + for_each_physmem_usable_range(i, &start, &end) { + decompressor_printk("%016lx %016lx\n", start, end); + total_mem += end - start; + } + decompressor_printk("Usable online memory total: %lx Reserved: %lx Free: %lx\n", + total_mem, total_reserved_mem, + total_mem > total_reserved_mem ? total_mem - total_reserved_mem : 0); + print_stacktrace(current_frame_address()); + sclp_early_printk("\n\n -- System halted\n"); + disabled_wait(); +} + +void physmem_reserve(enum reserved_range_type type, unsigned long addr, unsigned long size) +{ + physmem_info.reserved[type].start = addr; + physmem_info.reserved[type].end = addr + size; +} + +void physmem_free(enum reserved_range_type type) +{ + physmem_info.reserved[type].start = 0; + physmem_info.reserved[type].end = 0; +} + +static bool __physmem_alloc_intersects(unsigned long addr, unsigned long size, + unsigned long *intersection_start) +{ + unsigned long res_addr, res_size; + int t; + + for (t = 0; t < RR_MAX; t++) { + if (!get_physmem_reserved(t, &res_addr, &res_size)) + continue; + if (intersects(addr, size, res_addr, res_size)) { + *intersection_start = res_addr; + return true; + } + } + return ipl_report_certs_intersects(addr, size, intersection_start); +} + +static unsigned long __physmem_alloc_range(unsigned long size, unsigned long align, + unsigned long min, unsigned long max, + unsigned int from_ranges, unsigned int *ranges_left, + bool die_on_oom) +{ + unsigned int nranges = from_ranges ?: physmem_info.range_count; + unsigned long range_start, range_end; + unsigned long intersection_start; + unsigned long addr, pos = max; + + align = max(align, 8UL); + while (nranges) { + __get_physmem_range(nranges - 1, &range_start, &range_end, false); + pos = min(range_end, pos); + + if (round_up(min, align) + size > pos) + break; + addr = round_down(pos - size, align); + if (range_start > addr) { + nranges--; + continue; + } + if (__physmem_alloc_intersects(addr, size, &intersection_start)) { + pos = intersection_start; + continue; + } + + if (ranges_left) + *ranges_left = nranges; + return addr; + } + if (die_on_oom) + die_oom(size, align, min, max); + return 0; +} + +unsigned long physmem_alloc_range(enum reserved_range_type type, unsigned long size, + unsigned long align, unsigned long min, unsigned long max, + bool die_on_oom) +{ + unsigned long addr; + + max = min(max, physmem_alloc_pos); + addr = __physmem_alloc_range(size, align, min, max, 0, NULL, die_on_oom); + if (addr) + physmem_reserve(type, addr, size); + return addr; +} + +unsigned long physmem_alloc_top_down(enum reserved_range_type type, unsigned long size, + unsigned long align) +{ + struct reserved_range *range = &physmem_info.reserved[type]; + struct reserved_range *new_range; + unsigned int ranges_left; + unsigned long addr; + + addr = __physmem_alloc_range(size, align, 0, physmem_alloc_pos, physmem_alloc_ranges, + &ranges_left, true); + /* if not a consecutive allocation of the same type or first allocation */ + if (range->start != addr + size) { + if (range->end) { + physmem_alloc_pos = __physmem_alloc_range( + sizeof(struct reserved_range), 0, 0, physmem_alloc_pos, + physmem_alloc_ranges, &ranges_left, true); + new_range = (struct reserved_range *)physmem_alloc_pos; + *new_range = *range; + range->chain = new_range; + addr = __physmem_alloc_range(size, align, 0, physmem_alloc_pos, + ranges_left, &ranges_left, true); + } + range->end = addr + size; + } + range->start = addr; + physmem_alloc_pos = addr; + physmem_alloc_ranges = ranges_left; + return addr; +} + +unsigned long get_physmem_alloc_pos(void) +{ + return physmem_alloc_pos; +} diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 11413f0baabc..64bd7ac3e35d 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "decompressor.h" #include "boot.h" #include "uv.h" @@ -21,7 +21,6 @@ unsigned long __bootdata_preserved(__kaslr_offset); unsigned long __bootdata_preserved(__abs_lowcore); unsigned long __bootdata_preserved(__memcpy_real_area); pte_t *__bootdata_preserved(memcpy_real_ptep); -unsigned long __bootdata(__amode31_base); unsigned long __bootdata_preserved(VMALLOC_START); unsigned long __bootdata_preserved(VMALLOC_END); struct page *__bootdata_preserved(vmemmap); @@ -29,8 +28,6 @@ unsigned long __bootdata_preserved(vmemmap_size); unsigned long __bootdata_preserved(MODULES_VADDR); unsigned long __bootdata_preserved(MODULES_END); unsigned long __bootdata(ident_map_size); -int __bootdata(is_full_image) = 1; -struct initrd_data __bootdata(initrd_data); u64 __bootdata_preserved(stfle_fac_list[16]); u64 __bootdata_preserved(alt_stfle_fac_list[16]); @@ -76,17 +73,20 @@ unsigned long mem_safe_offset(void) } #endif -static unsigned long rescue_initrd(unsigned long safe_addr) +static void rescue_initrd(unsigned long min, unsigned long max) { + unsigned long old_addr, addr, size; + if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) - return safe_addr; - if (!initrd_data.start || !initrd_data.size) - return safe_addr; - if (initrd_data.start < safe_addr) { - memmove((void *)safe_addr, (void *)initrd_data.start, initrd_data.size); - initrd_data.start = safe_addr; - } - return initrd_data.start + initrd_data.size; + return; + if (!get_physmem_reserved(RR_INITRD, &addr, &size)) + return; + if (addr >= min && addr + size <= max) + return; + old_addr = addr; + physmem_free(RR_INITRD); + addr = physmem_alloc_top_down(RR_INITRD, size, 0); + memmove((void *)addr, (void *)old_addr, size); } static void copy_bootdata(void) @@ -140,7 +140,7 @@ static void handle_relocs(unsigned long offset) * * Consider the following factors: * 1. max_physmem_end - end of physical memory online or standby. - * Always <= end of the last online memory block (get_mem_detect_end()). + * Always >= end of the last online memory range (get_physmem_online_end()). * 2. CONFIG_MAX_PHYSMEM_BITS - the maximum size of physical memory the * kernel is able to support. * 3. "mem=" kernel command line option which limits physical memory usage. @@ -160,10 +160,10 @@ static void setup_ident_map_size(unsigned long max_physmem_end) #ifdef CONFIG_CRASH_DUMP if (oldmem_data.start) { - kaslr_enabled = 0; + __kaslr_enabled = 0; ident_map_size = min(ident_map_size, oldmem_data.size); } else if (ipl_block_valid && is_ipl_block_dump()) { - kaslr_enabled = 0; + __kaslr_enabled = 0; if (!sclp_early_get_hsa_size(&hsa_size) && hsa_size) ident_map_size = min(ident_map_size, hsa_size); } @@ -235,9 +235,9 @@ static unsigned long setup_kernel_memory_layout(void) /* * This function clears the BSS section of the decompressed Linux kernel and NOT the decompressor's. */ -static void clear_bss_section(void) +static void clear_bss_section(unsigned long vmlinux_lma) { - memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size); + memset((void *)vmlinux_lma + vmlinux.image_size, 0, vmlinux.bss_size); } /* @@ -256,7 +256,6 @@ static void setup_vmalloc_size(void) static void offset_vmlinux_info(unsigned long offset) { - vmlinux.default_lma += offset; *(unsigned long *)(&vmlinux.entry) += offset; vmlinux.bootdata_off += offset; vmlinux.bootdata_preserved_off += offset; @@ -266,60 +265,83 @@ static void offset_vmlinux_info(unsigned long offset) vmlinux.init_mm_off += offset; vmlinux.swapper_pg_dir_off += offset; vmlinux.invalid_pg_dir_off += offset; -} - -static unsigned long reserve_amode31(unsigned long safe_addr) -{ - __amode31_base = PAGE_ALIGN(safe_addr); - return __amode31_base + vmlinux.amode31_size; +#ifdef CONFIG_KASAN + vmlinux.kasan_early_shadow_page_off += offset; + vmlinux.kasan_early_shadow_pte_off += offset; + vmlinux.kasan_early_shadow_pmd_off += offset; + vmlinux.kasan_early_shadow_pud_off += offset; + vmlinux.kasan_early_shadow_p4d_off += offset; +#endif } void startup_kernel(void) { unsigned long max_physmem_end; - unsigned long random_lma; - unsigned long safe_addr; + unsigned long vmlinux_lma = 0; + unsigned long amode31_lma = 0; unsigned long asce_limit; + unsigned long safe_addr; void *img; psw_t psw; - initrd_data.start = parmarea.initrd_start; - initrd_data.size = parmarea.initrd_size; + setup_lpp(); + safe_addr = mem_safe_offset(); + /* + * reserve decompressor memory together with decompression heap, buffer and + * memory which might be occupied by uncompressed kernel at default 1Mb + * position (if KASLR is off or failed). + */ + physmem_reserve(RR_DECOMPRESSOR, 0, safe_addr); + if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && parmarea.initrd_size) + physmem_reserve(RR_INITRD, parmarea.initrd_start, parmarea.initrd_size); oldmem_data.start = parmarea.oldmem_base; oldmem_data.size = parmarea.oldmem_size; - setup_lpp(); store_ipl_parmblock(); - safe_addr = mem_safe_offset(); - safe_addr = reserve_amode31(safe_addr); - safe_addr = read_ipl_report(safe_addr); + read_ipl_report(); uv_query_info(); - safe_addr = rescue_initrd(safe_addr); sclp_early_read_info(); setup_boot_command_line(); parse_boot_command_line(); detect_facilities(); sanitize_prot_virt_host(); - max_physmem_end = detect_memory(&safe_addr); + max_physmem_end = detect_max_physmem_end(); setup_ident_map_size(max_physmem_end); setup_vmalloc_size(); asce_limit = setup_kernel_memory_layout(); - mem_detect_set_usable_limit(ident_map_size); + /* got final ident_map_size, physmem allocations could be performed now */ + physmem_set_usable_limit(ident_map_size); + detect_physmem_online_ranges(max_physmem_end); + save_ipl_cert_comp_list(); + rescue_initrd(safe_addr, ident_map_size); - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_enabled) { - random_lma = get_random_base(safe_addr); - if (random_lma) { - __kaslr_offset = random_lma - vmlinux.default_lma; - img = (void *)vmlinux.default_lma; + if (kaslr_enabled()) { + vmlinux_lma = randomize_within_range(vmlinux.image_size + vmlinux.bss_size, + THREAD_SIZE, vmlinux.default_lma, + ident_map_size); + if (vmlinux_lma) { + __kaslr_offset = vmlinux_lma - vmlinux.default_lma; offset_vmlinux_info(__kaslr_offset); } } + vmlinux_lma = vmlinux_lma ?: vmlinux.default_lma; + physmem_reserve(RR_VMLINUX, vmlinux_lma, vmlinux.image_size + vmlinux.bss_size); if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { img = decompress_kernel(); - memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); - } else if (__kaslr_offset) - memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size); + memmove((void *)vmlinux_lma, img, vmlinux.image_size); + } else if (__kaslr_offset) { + img = (void *)vmlinux.default_lma; + memmove((void *)vmlinux_lma, img, vmlinux.image_size); + memset(img, 0, vmlinux.image_size); + } + + /* vmlinux decompression is done, shrink reserved low memory */ + physmem_reserve(RR_DECOMPRESSOR, 0, (unsigned long)_decompressor_end); + if (kaslr_enabled()) + amode31_lma = randomize_within_range(vmlinux.amode31_size, PAGE_SIZE, 0, SZ_2G); + amode31_lma = amode31_lma ?: vmlinux.default_lma - vmlinux.amode31_size; + physmem_reserve(RR_AMODE31, amode31_lma, vmlinux.amode31_size); /* * The order of the following operations is important: @@ -334,21 +356,16 @@ void startup_kernel(void) * - copy_bootdata() must follow setup_vmem() to propagate changes to * bootdata made by setup_vmem() */ - clear_bss_section(); + clear_bss_section(vmlinux_lma); handle_relocs(__kaslr_offset); setup_vmem(asce_limit); copy_bootdata(); - if (__kaslr_offset) { - /* - * Save KASLR offset for early dumps, before vmcore_info is set. - * Mark as uneven to distinguish from real vmcore_info pointer. - */ - S390_lowcore.vmcore_info = __kaslr_offset | 0x1UL; - /* Clear non-relocated kernel */ - if (IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) - memset(img, 0, vmlinux.image_size); - } + /* + * Save KASLR offset for early dumps, before vmcore_info is set. + * Mark as uneven to distinguish from real vmcore_info pointer. + */ + S390_lowcore.vmcore_info = __kaslr_offset ? __kaslr_offset | 0x1UL : 0; /* * Jump to the decompressed kernel entry point and switch DAT mode on. diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c index 4d1d0d8e99cb..acb1f8b53105 100644 --- a/arch/s390/boot/vmem.c +++ b/arch/s390/boot/vmem.c @@ -1,19 +1,202 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include #include -#include +#include #include #include #include "decompressor.h" #include "boot.h" +unsigned long __bootdata_preserved(s390_invalid_asce); + +#ifdef CONFIG_PROC_FS +atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); +#endif + #define init_mm (*(struct mm_struct *)vmlinux.init_mm_off) #define swapper_pg_dir vmlinux.swapper_pg_dir_off #define invalid_pg_dir vmlinux.invalid_pg_dir_off +enum populate_mode { + POPULATE_NONE, + POPULATE_DIRECT, + POPULATE_ABS_LOWCORE, +#ifdef CONFIG_KASAN + POPULATE_KASAN_MAP_SHADOW, + POPULATE_KASAN_ZERO_SHADOW, + POPULATE_KASAN_SHALLOW +#endif +}; + +static void pgtable_populate(unsigned long addr, unsigned long end, enum populate_mode mode); + +#ifdef CONFIG_KASAN + +#define kasan_early_shadow_page vmlinux.kasan_early_shadow_page_off +#define kasan_early_shadow_pte ((pte_t *)vmlinux.kasan_early_shadow_pte_off) +#define kasan_early_shadow_pmd ((pmd_t *)vmlinux.kasan_early_shadow_pmd_off) +#define kasan_early_shadow_pud ((pud_t *)vmlinux.kasan_early_shadow_pud_off) +#define kasan_early_shadow_p4d ((p4d_t *)vmlinux.kasan_early_shadow_p4d_off) +#define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) + +static pte_t pte_z; + +static void kasan_populate_shadow(void) +{ + pmd_t pmd_z = __pmd(__pa(kasan_early_shadow_pte) | _SEGMENT_ENTRY); + pud_t pud_z = __pud(__pa(kasan_early_shadow_pmd) | _REGION3_ENTRY); + p4d_t p4d_z = __p4d(__pa(kasan_early_shadow_pud) | _REGION2_ENTRY); + unsigned long untracked_end; + unsigned long start, end; + int i; + + pte_z = __pte(__pa(kasan_early_shadow_page) | pgprot_val(PAGE_KERNEL_RO)); + if (!machine.has_nx) + pte_z = clear_pte_bit(pte_z, __pgprot(_PAGE_NOEXEC)); + crst_table_init((unsigned long *)kasan_early_shadow_p4d, p4d_val(p4d_z)); + crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z)); + crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z)); + memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE); + + /* + * Current memory layout: + * +- 0 -------------+ +- shadow start -+ + * |1:1 ident mapping| /|1/8 of ident map| + * | | / | | + * +-end of ident map+ / +----------------+ + * | ... gap ... | / | kasan | + * | | / | zero page | + * +- vmalloc area -+ / | mapping | + * | vmalloc_size | / | (untracked) | + * +- modules vaddr -+ / +----------------+ + * | 2Gb |/ | unmapped | allocated per module + * +- shadow start -+ +----------------+ + * | 1/8 addr space | | zero pg mapping| (untracked) + * +- shadow end ----+---------+- shadow end ---+ + * + * Current memory layout (KASAN_VMALLOC): + * +- 0 -------------+ +- shadow start -+ + * |1:1 ident mapping| /|1/8 of ident map| + * | | / | | + * +-end of ident map+ / +----------------+ + * | ... gap ... | / | kasan zero page| (untracked) + * | | / | mapping | + * +- vmalloc area -+ / +----------------+ + * | vmalloc_size | / |shallow populate| + * +- modules vaddr -+ / +----------------+ + * | 2Gb |/ |shallow populate| + * +- shadow start -+ +----------------+ + * | 1/8 addr space | | zero pg mapping| (untracked) + * +- shadow end ----+---------+- shadow end ---+ + */ + + for_each_physmem_usable_range(i, &start, &end) + pgtable_populate(__sha(start), __sha(end), POPULATE_KASAN_MAP_SHADOW); + if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { + untracked_end = VMALLOC_START; + /* shallowly populate kasan shadow for vmalloc and modules */ + pgtable_populate(__sha(VMALLOC_START), __sha(MODULES_END), POPULATE_KASAN_SHALLOW); + } else { + untracked_end = MODULES_VADDR; + } + /* populate kasan shadow for untracked memory */ + pgtable_populate(__sha(ident_map_size), __sha(untracked_end), POPULATE_KASAN_ZERO_SHADOW); + pgtable_populate(__sha(MODULES_END), __sha(_REGION1_SIZE), POPULATE_KASAN_ZERO_SHADOW); +} + +static bool kasan_pgd_populate_zero_shadow(pgd_t *pgd, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + if (mode == POPULATE_KASAN_ZERO_SHADOW && + IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { + pgd_populate(&init_mm, pgd, kasan_early_shadow_p4d); + return true; + } + return false; +} + +static bool kasan_p4d_populate_zero_shadow(p4d_t *p4d, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + if (mode == POPULATE_KASAN_ZERO_SHADOW && + IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { + p4d_populate(&init_mm, p4d, kasan_early_shadow_pud); + return true; + } + return false; +} + +static bool kasan_pud_populate_zero_shadow(pud_t *pud, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + if (mode == POPULATE_KASAN_ZERO_SHADOW && + IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { + pud_populate(&init_mm, pud, kasan_early_shadow_pmd); + return true; + } + return false; +} + +static bool kasan_pmd_populate_zero_shadow(pmd_t *pmd, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + if (mode == POPULATE_KASAN_ZERO_SHADOW && + IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { + pmd_populate(&init_mm, pmd, kasan_early_shadow_pte); + return true; + } + return false; +} + +static bool kasan_pte_populate_zero_shadow(pte_t *pte, enum populate_mode mode) +{ + pte_t entry; + + if (mode == POPULATE_KASAN_ZERO_SHADOW) { + set_pte(pte, pte_z); + return true; + } + return false; +} +#else + +static inline void kasan_populate_shadow(void) {} + +static inline bool kasan_pgd_populate_zero_shadow(pgd_t *pgd, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + return false; +} + +static inline bool kasan_p4d_populate_zero_shadow(p4d_t *p4d, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + return false; +} + +static inline bool kasan_pud_populate_zero_shadow(pud_t *pud, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + return false; +} + +static inline bool kasan_pmd_populate_zero_shadow(pmd_t *pmd, unsigned long addr, + unsigned long end, enum populate_mode mode) +{ + return false; +} + +static bool kasan_pte_populate_zero_shadow(pte_t *pte, enum populate_mode mode) +{ + return false; +} + +#endif + /* * Mimic virt_to_kpte() in lack of init_mm symbol. Skip pmd NULL check though. */ @@ -22,60 +205,13 @@ static inline pte_t *__virt_to_kpte(unsigned long va) return pte_offset_kernel(pmd_offset(pud_offset(p4d_offset(pgd_offset_k(va), va), va), va), va); } -unsigned long __bootdata_preserved(s390_invalid_asce); -unsigned long __bootdata(pgalloc_pos); -unsigned long __bootdata(pgalloc_end); -unsigned long __bootdata(pgalloc_low); - -enum populate_mode { - POPULATE_NONE, - POPULATE_ONE2ONE, - POPULATE_ABS_LOWCORE, -}; - -static void boot_check_oom(void) -{ - if (pgalloc_pos < pgalloc_low) - error("out of memory on boot\n"); -} - -static void pgtable_populate_init(void) -{ - unsigned long initrd_end; - unsigned long kernel_end; - - kernel_end = vmlinux.default_lma + vmlinux.image_size + vmlinux.bss_size; - pgalloc_low = round_up(kernel_end, PAGE_SIZE); - if (IS_ENABLED(CONFIG_BLK_DEV_INITRD)) { - initrd_end = round_up(initrd_data.start + initrd_data.size, _SEGMENT_SIZE); - pgalloc_low = max(pgalloc_low, initrd_end); - } - - pgalloc_end = round_down(get_mem_detect_end(), PAGE_SIZE); - pgalloc_pos = pgalloc_end; - - boot_check_oom(); -} - -static void *boot_alloc_pages(unsigned int order) -{ - unsigned long size = PAGE_SIZE << order; - - pgalloc_pos -= size; - pgalloc_pos = round_down(pgalloc_pos, size); - - boot_check_oom(); - - return (void *)pgalloc_pos; -} - static void *boot_crst_alloc(unsigned long val) { + unsigned long size = PAGE_SIZE << CRST_ALLOC_ORDER; unsigned long *table; - table = boot_alloc_pages(CRST_ALLOC_ORDER); - if (table) - crst_table_init(table, val); + table = (unsigned long *)physmem_alloc_top_down(RR_VMEM, size, size); + crst_table_init(table, val); return table; } @@ -84,28 +220,37 @@ static pte_t *boot_pte_alloc(void) static void *pte_leftover; pte_t *pte; - BUILD_BUG_ON(_PAGE_TABLE_SIZE * 2 != PAGE_SIZE); - + /* + * handling pte_leftovers this way helps to avoid memory fragmentation + * during POPULATE_KASAN_MAP_SHADOW when EDAT is off + */ if (!pte_leftover) { - pte_leftover = boot_alloc_pages(0); + pte_leftover = (void *)physmem_alloc_top_down(RR_VMEM, PAGE_SIZE, PAGE_SIZE); pte = pte_leftover + _PAGE_TABLE_SIZE; } else { pte = pte_leftover; pte_leftover = NULL; } + memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE); return pte; } -static unsigned long _pa(unsigned long addr, enum populate_mode mode) +static unsigned long _pa(unsigned long addr, unsigned long size, enum populate_mode mode) { switch (mode) { case POPULATE_NONE: return -1; - case POPULATE_ONE2ONE: + case POPULATE_DIRECT: return addr; case POPULATE_ABS_LOWCORE: return __abs_lowcore_pa(addr); +#ifdef CONFIG_KASAN + case POPULATE_KASAN_MAP_SHADOW: + addr = physmem_alloc_top_down(RR_VMEM, size, size); + memset((void *)addr, 0, size); + return addr; +#endif default: return -1; } @@ -126,23 +271,28 @@ static bool can_large_pmd(pmd_t *pm_dir, unsigned long addr, unsigned long end) static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end, enum populate_mode mode) { - unsigned long next; + unsigned long pages = 0; pte_t *pte, entry; pte = pte_offset_kernel(pmd, addr); for (; addr < end; addr += PAGE_SIZE, pte++) { if (pte_none(*pte)) { - entry = __pte(_pa(addr, mode)); + if (kasan_pte_populate_zero_shadow(pte, mode)) + continue; + entry = __pte(_pa(addr, PAGE_SIZE, mode)); entry = set_pte_bit(entry, PAGE_KERNEL_EXEC); set_pte(pte, entry); + pages++; } } + if (mode == POPULATE_DIRECT) + update_page_count(PG_DIRECT_MAP_4K, pages); } static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long end, enum populate_mode mode) { - unsigned long next; + unsigned long next, pages = 0; pmd_t *pmd, entry; pte_t *pte; @@ -150,10 +300,13 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e for (; addr < end; addr = next, pmd++) { next = pmd_addr_end(addr, end); if (pmd_none(*pmd)) { + if (kasan_pmd_populate_zero_shadow(pmd, addr, next, mode)) + continue; if (can_large_pmd(pmd, addr, next)) { - entry = __pmd(_pa(addr, mode)); + entry = __pmd(_pa(addr, _SEGMENT_SIZE, mode)); entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC); set_pmd(pmd, entry); + pages++; continue; } pte = boot_pte_alloc(); @@ -163,12 +316,14 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e } pgtable_pte_populate(pmd, addr, next, mode); } + if (mode == POPULATE_DIRECT) + update_page_count(PG_DIRECT_MAP_1M, pages); } static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long end, enum populate_mode mode) { - unsigned long next; + unsigned long next, pages = 0; pud_t *pud, entry; pmd_t *pmd; @@ -176,10 +331,13 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e for (; addr < end; addr = next, pud++) { next = pud_addr_end(addr, end); if (pud_none(*pud)) { + if (kasan_pud_populate_zero_shadow(pud, addr, next, mode)) + continue; if (can_large_pud(pud, addr, next)) { - entry = __pud(_pa(addr, mode)); + entry = __pud(_pa(addr, _REGION3_SIZE, mode)); entry = set_pud_bit(entry, REGION3_KERNEL_EXEC); set_pud(pud, entry); + pages++; continue; } pmd = boot_crst_alloc(_SEGMENT_ENTRY_EMPTY); @@ -189,6 +347,8 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e } pgtable_pmd_populate(pud, addr, next, mode); } + if (mode == POPULATE_DIRECT) + update_page_count(PG_DIRECT_MAP_2G, pages); } static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long end, @@ -202,6 +362,8 @@ static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long e for (; addr < end; addr = next, p4d++) { next = p4d_addr_end(addr, end); if (p4d_none(*p4d)) { + if (kasan_p4d_populate_zero_shadow(p4d, addr, next, mode)) + continue; pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY); p4d_populate(&init_mm, p4d, pud); } @@ -219,9 +381,15 @@ static void pgtable_populate(unsigned long addr, unsigned long end, enum populat for (; addr < end; addr = next, pgd++) { next = pgd_addr_end(addr, end); if (pgd_none(*pgd)) { + if (kasan_pgd_populate_zero_shadow(pgd, addr, next, mode)) + continue; p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY); pgd_populate(&init_mm, pgd, p4d); } +#ifdef CONFIG_KASAN + if (mode == POPULATE_KASAN_SHALLOW) + continue; +#endif pgtable_p4d_populate(pgd, addr, next, mode); } } @@ -250,16 +418,17 @@ void setup_vmem(unsigned long asce_limit) * To prevent creation of a large page at address 0 first map * the lowcore and create the identity mapping only afterwards. */ - pgtable_populate_init(); - pgtable_populate(0, sizeof(struct lowcore), POPULATE_ONE2ONE); - for_each_mem_detect_usable_block(i, &start, &end) - pgtable_populate(start, end, POPULATE_ONE2ONE); + pgtable_populate(0, sizeof(struct lowcore), POPULATE_DIRECT); + for_each_physmem_usable_range(i, &start, &end) + pgtable_populate(start, end, POPULATE_DIRECT); pgtable_populate(__abs_lowcore, __abs_lowcore + sizeof(struct lowcore), POPULATE_ABS_LOWCORE); pgtable_populate(__memcpy_real_area, __memcpy_real_area + PAGE_SIZE, POPULATE_NONE); memcpy_real_ptep = __virt_to_kpte(__memcpy_real_area); + kasan_populate_shadow(); + S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits; S390_lowcore.user_asce = s390_invalid_asce; @@ -269,10 +438,3 @@ void setup_vmem(unsigned long asce_limit) init_mm.context.asce = S390_lowcore.kernel_asce; } - -unsigned long vmem_estimate_memory_needs(unsigned long online_mem_total) -{ - unsigned long pages = DIV_ROUND_UP(online_mem_total, PAGE_SIZE); - - return DIV_ROUND_UP(pages, _PAGE_ENTRIES) * _PAGE_TABLE_SIZE * 2; -} diff --git a/arch/s390/boot/vmlinux.lds.S b/arch/s390/boot/vmlinux.lds.S index fa9d33b01b85..389df0e0d9e5 100644 --- a/arch/s390/boot/vmlinux.lds.S +++ b/arch/s390/boot/vmlinux.lds.S @@ -93,6 +93,8 @@ SECTIONS _decompressor_syms_end = .; } + _decompressor_end = .; + #ifdef CONFIG_KERNEL_UNCOMPRESSED . = 0x100000; #else diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 4ccf66d29fc2..be3bf03bf361 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -591,8 +591,6 @@ CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_INPUT=y CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m -CONFIG_S390_CCW_IOMMU=y -CONFIG_S390_AP_IOMMU=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y @@ -703,6 +701,7 @@ CONFIG_IMA_DEFAULT_HASH_SHA256=y CONFIG_IMA_WRITE_POLICY=y CONFIG_IMA_APPRAISE=y CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" +CONFIG_INIT_STACK_NONE=y CONFIG_CRYPTO_USER=m # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_PCRYPT=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 693297a2e897..769c7eed8b6a 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -580,8 +580,6 @@ CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_INPUT=y CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m -CONFIG_S390_CCW_IOMMU=y -CONFIG_S390_AP_IOMMU=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y @@ -686,6 +684,7 @@ CONFIG_IMA_DEFAULT_HASH_SHA256=y CONFIG_IMA_WRITE_POLICY=y CONFIG_IMA_APPRAISE=y CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" +CONFIG_INIT_STACK_NONE=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_USER=m # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 33a232bb68af..6f68b39817ef 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -67,6 +67,7 @@ CONFIG_ZFCP=y # CONFIG_MISC_FILESYSTEMS is not set # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_LSM="yama,loadpin,safesetid,integrity" +CONFIG_INIT_STACK_NONE=y # CONFIG_ZLIB_DFLTCC is not set CONFIG_XZ_DEC_MICROLZMA=y CONFIG_PRINTK_TIME=y diff --git a/arch/s390/crypto/chacha-glue.c b/arch/s390/crypto/chacha-glue.c index 7752bd314558..5fae187f947a 100644 --- a/arch/s390/crypto/chacha-glue.c +++ b/arch/s390/crypto/chacha-glue.c @@ -82,7 +82,7 @@ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, * it cannot handle a block of data or less, but otherwise * it can handle data of arbitrary size */ - if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20) + if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20 || !MACHINE_HAS_VX) chacha_crypt_generic(state, dst, src, bytes, nrounds); else chacha20_crypt_s390(state, dst, src, bytes, diff --git a/arch/s390/crypto/chacha-s390.S b/arch/s390/crypto/chacha-s390.S index 9b033622191c..37cb63f25b17 100644 --- a/arch/s390/crypto/chacha-s390.S +++ b/arch/s390/crypto/chacha-s390.S @@ -13,27 +13,28 @@ #define SP %r15 #define FRAME (16 * 8 + 4 * 8) -.data -.align 32 + .data + .balign 32 -.Lsigma: -.long 0x61707865,0x3320646e,0x79622d32,0x6b206574 # endian-neutral -.long 1,0,0,0 -.long 2,0,0,0 -.long 3,0,0,0 -.long 0x03020100,0x07060504,0x0b0a0908,0x0f0e0d0c # byte swap +SYM_DATA_START_LOCAL(sigma) + .long 0x61707865,0x3320646e,0x79622d32,0x6b206574 # endian-neutral + .long 1,0,0,0 + .long 2,0,0,0 + .long 3,0,0,0 + .long 0x03020100,0x07060504,0x0b0a0908,0x0f0e0d0c # byte swap -.long 0,1,2,3 -.long 0x61707865,0x61707865,0x61707865,0x61707865 # smashed sigma -.long 0x3320646e,0x3320646e,0x3320646e,0x3320646e -.long 0x79622d32,0x79622d32,0x79622d32,0x79622d32 -.long 0x6b206574,0x6b206574,0x6b206574,0x6b206574 + .long 0,1,2,3 + .long 0x61707865,0x61707865,0x61707865,0x61707865 # smashed sigma + .long 0x3320646e,0x3320646e,0x3320646e,0x3320646e + .long 0x79622d32,0x79622d32,0x79622d32,0x79622d32 + .long 0x6b206574,0x6b206574,0x6b206574,0x6b206574 +SYM_DATA_END(sigma) -.previous + .previous GEN_BR_THUNK %r14 -.text + .text ############################################################################# # void chacha20_vx_4x(u8 *out, counst u8 *inp, size_t len, @@ -78,10 +79,10 @@ #define XT2 %v29 #define XT3 %v30 -ENTRY(chacha20_vx_4x) +SYM_FUNC_START(chacha20_vx_4x) stmg %r6,%r7,6*8(SP) - larl %r7,.Lsigma + larl %r7,sigma lhi %r0,10 lhi %r1,0 @@ -403,7 +404,7 @@ ENTRY(chacha20_vx_4x) lmg %r6,%r7,6*8(SP) BR_EX %r14 -ENDPROC(chacha20_vx_4x) +SYM_FUNC_END(chacha20_vx_4x) #undef OUT #undef INP @@ -471,7 +472,7 @@ ENDPROC(chacha20_vx_4x) #define T2 %v29 #define T3 %v30 -ENTRY(chacha20_vx) +SYM_FUNC_START(chacha20_vx) clgfi LEN,256 jle chacha20_vx_4x stmg %r6,%r7,6*8(SP) @@ -481,7 +482,7 @@ ENTRY(chacha20_vx) la SP,0(%r1,SP) stg %r0,0(SP) # back-chain - larl %r7,.Lsigma + larl %r7,sigma lhi %r0,10 VLM K1,K2,0,KEY,0 # load key @@ -902,6 +903,6 @@ ENTRY(chacha20_vx) lmg %r6,%r7,FRAME+6*8(SP) la SP,FRAME(SP) BR_EX %r14 -ENDPROC(chacha20_vx) +SYM_FUNC_END(chacha20_vx) .previous diff --git a/arch/s390/crypto/crc32be-vx.S b/arch/s390/crypto/crc32be-vx.S index 6b3d1009c392..6ea17628ea10 100644 --- a/arch/s390/crypto/crc32be-vx.S +++ b/arch/s390/crypto/crc32be-vx.S @@ -24,8 +24,8 @@ #define CONST_RU_POLY %v13 #define CONST_CRC_POLY %v14 -.data -.align 8 + .data + .balign 8 /* * The CRC-32 constant block contains reduction constants to fold and @@ -58,19 +58,20 @@ * P'(x) = 0xEDB88320 */ -.Lconstants_CRC_32_BE: +SYM_DATA_START_LOCAL(constants_CRC_32_BE) .quad 0x08833794c, 0x0e6228b11 # R1, R2 .quad 0x0c5b9cd4c, 0x0e8a45605 # R3, R4 .quad 0x0f200aa66, 1 << 32 # R5, x32 .quad 0x0490d678d, 1 # R6, 1 .quad 0x104d101df, 0 # u .quad 0x104C11DB7, 0 # P(x) +SYM_DATA_END(constants_CRC_32_BE) -.previous + .previous GEN_BR_THUNK %r14 -.text + .text /* * The CRC-32 function(s) use these calling conventions: * @@ -90,9 +91,9 @@ * * V9..V14: CRC-32 constants. */ -ENTRY(crc32_be_vgfm_16) +SYM_FUNC_START(crc32_be_vgfm_16) /* Load CRC-32 constants */ - larl %r5,.Lconstants_CRC_32_BE + larl %r5,constants_CRC_32_BE VLM CONST_R1R2,CONST_CRC_POLY,0,%r5 /* Load the initial CRC value into the leftmost word of V0. */ @@ -207,6 +208,6 @@ ENTRY(crc32_be_vgfm_16) .Ldone: VLGVF %r2,%v2,3 BR_EX %r14 -ENDPROC(crc32_be_vgfm_16) +SYM_FUNC_END(crc32_be_vgfm_16) .previous diff --git a/arch/s390/crypto/crc32le-vx.S b/arch/s390/crypto/crc32le-vx.S index 71caf0f4ec08..5a819ae09a0b 100644 --- a/arch/s390/crypto/crc32le-vx.S +++ b/arch/s390/crypto/crc32le-vx.S @@ -25,8 +25,8 @@ #define CONST_RU_POLY %v13 #define CONST_CRC_POLY %v14 -.data -.align 8 + .data + .balign 8 /* * The CRC-32 constant block contains reduction constants to fold and @@ -59,27 +59,29 @@ * P'(x) = 0x82F63B78 */ -.Lconstants_CRC_32_LE: +SYM_DATA_START_LOCAL(constants_CRC_32_LE) .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask .quad 0x1c6e41596, 0x154442bd4 # R2, R1 .quad 0x0ccaa009e, 0x1751997d0 # R4, R3 .octa 0x163cd6124 # R5 .octa 0x1F7011641 # u' .octa 0x1DB710641 # P'(x) << 1 +SYM_DATA_END(constants_CRC_32_LE) -.Lconstants_CRC_32C_LE: +SYM_DATA_START_LOCAL(constants_CRC_32C_LE) .octa 0x0F0E0D0C0B0A09080706050403020100 # BE->LE mask .quad 0x09e4addf8, 0x740eef02 # R2, R1 .quad 0x14cd00bd6, 0xf20c0dfe # R4, R3 .octa 0x0dd45aab8 # R5 .octa 0x0dea713f1 # u' .octa 0x105ec76f0 # P'(x) << 1 +SYM_DATA_END(constants_CRC_32C_LE) -.previous + .previous GEN_BR_THUNK %r14 -.text + .text /* * The CRC-32 functions use these calling conventions: @@ -102,17 +104,17 @@ * V10..V14: CRC-32 constants. */ -ENTRY(crc32_le_vgfm_16) - larl %r5,.Lconstants_CRC_32_LE +SYM_FUNC_START(crc32_le_vgfm_16) + larl %r5,constants_CRC_32_LE j crc32_le_vgfm_generic -ENDPROC(crc32_le_vgfm_16) +SYM_FUNC_END(crc32_le_vgfm_16) -ENTRY(crc32c_le_vgfm_16) - larl %r5,.Lconstants_CRC_32C_LE +SYM_FUNC_START(crc32c_le_vgfm_16) + larl %r5,constants_CRC_32C_LE j crc32_le_vgfm_generic -ENDPROC(crc32c_le_vgfm_16) +SYM_FUNC_END(crc32c_le_vgfm_16) -ENTRY(crc32_le_vgfm_generic) +SYM_FUNC_START(crc32_le_vgfm_generic) /* Load CRC-32 constants */ VLM CONST_PERM_LE2BE,CONST_CRC_POLY,0,%r5 @@ -268,6 +270,6 @@ ENTRY(crc32_le_vgfm_generic) .Ldone: VLGVF %r2,%v2,2 BR_EX %r14 -ENDPROC(crc32_le_vgfm_generic) +SYM_FUNC_END(crc32_le_vgfm_generic) .previous diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index c699f251a464..d5d967166bac 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -43,10 +43,11 @@ struct ap_queue_status { unsigned int queue_empty : 1; unsigned int replies_waiting : 1; unsigned int queue_full : 1; - unsigned int _pad1 : 4; + unsigned int : 3; + unsigned int async : 1; unsigned int irq_enabled : 1; unsigned int response_code : 8; - unsigned int _pad2 : 16; + unsigned int : 16; }; /* @@ -86,6 +87,42 @@ static inline bool ap_instructions_available(void) return reg1 != 0; } +/* TAPQ register GR2 response struct */ +struct ap_tapq_gr2 { + union { + unsigned long value; + struct { + unsigned int fac : 32; /* facility bits */ + unsigned int apinfo : 32; /* ap type, ... */ + }; + struct { + unsigned int s : 1; /* APSC */ + unsigned int m : 1; /* AP4KM */ + unsigned int c : 1; /* AP4KC */ + unsigned int mode : 3; + unsigned int n : 1; /* APXA */ + unsigned int : 1; + unsigned int class : 8; + unsigned int bs : 2; /* SE bind/assoc */ + unsigned int : 14; + unsigned int at : 8; /* ap type */ + unsigned int nd : 8; /* nr of domains */ + unsigned int : 4; + unsigned int ml : 4; /* apxl ml */ + unsigned int : 4; + unsigned int qd : 4; /* queue depth */ + }; + }; +}; + +/* + * Convenience defines to be used with the bs field from struct ap_tapq_gr2 + */ +#define AP_BS_Q_USABLE 0 +#define AP_BS_Q_USABLE_NO_SECURE_KEY 1 +#define AP_BS_Q_AVAIL_FOR_BINDING 2 +#define AP_BS_Q_UNUSABLE 3 + /** * ap_tapq(): Test adjunct processor queue. * @qid: The AP queue number @@ -93,7 +130,7 @@ static inline bool ap_instructions_available(void) * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *info) { union ap_queue_status_reg reg1; unsigned long reg2; @@ -108,7 +145,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) : [qid] "d" (qid) : "cc", "0", "1", "2"); if (info) - *info = reg2; + info->value = reg2; return reg1.status; } @@ -116,13 +153,12 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number * @tbit: Test facilities bit - * @info: Pointer to queue descriptor + * @info: Ptr to tapq gr2 struct * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, - int tbit, - unsigned long *info) +static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit, + struct ap_tapq_gr2 *info) { if (tbit) qid |= 1UL << 23; /* set T bit*/ @@ -132,14 +168,18 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, /** * ap_pqap_rapq(): Reset adjunct processor queue. * @qid: The AP queue number + * @fbit: if != 0 set F bit * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_rapq(ap_qid_t qid) +static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit) { unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */ union ap_queue_status_reg reg1; + if (fbit) + reg0 |= 1UL << 22; + asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */ @@ -153,14 +193,18 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid) /** * ap_pqap_zapq(): Reset and zeroize adjunct processor queue. * @qid: The AP queue number + * @fbit: if != 0 set F bit * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_zapq(ap_qid_t qid) +static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit) { unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */ union ap_queue_status_reg reg1; + if (fbit) + reg0 |= 1UL << 22; + asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */ @@ -180,15 +224,16 @@ struct ap_config_info { unsigned int apxa : 1; /* N bit */ unsigned int qact : 1; /* C bit */ unsigned int rc8a : 1; /* R bit */ - unsigned char _reserved1 : 4; - unsigned char _reserved2[3]; - unsigned char Na; /* max # of APs - 1 */ - unsigned char Nd; /* max # of Domains - 1 */ - unsigned char _reserved3[10]; + unsigned int : 4; + unsigned int apsb : 1; /* B bit */ + unsigned int : 23; + unsigned char na; /* max # of APs - 1 */ + unsigned char nd; /* max # of Domains - 1 */ + unsigned char _reserved0[10]; unsigned int apm[8]; /* AP ID mask */ unsigned int aqm[8]; /* AP (usage) queue mask */ unsigned int adm[8]; /* AP (control) domain mask */ - unsigned char _reserved4[16]; + unsigned char _reserved1[16]; } __aligned(8); /** @@ -318,6 +363,59 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, return reg1.status; } +/* + * ap_bapq(): SE bind AP queue. + * @qid: The AP queue number + * + * Returns AP queue status structure. + * + * Invoking this function in a non-SE environment + * may case a specification exception. + */ +static inline struct ap_queue_status ap_bapq(ap_qid_t qid) +{ + unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */ + union ap_queue_status_reg reg1; + + asm volatile( + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1.value) + : [reg0] "d" (reg0) + : "cc", "0", "1"); + + return reg1.status; +} + +/* + * ap_aapq(): SE associate AP queue. + * @qid: The AP queue number + * @sec_idx: The secret index + * + * Returns AP queue status structure. + * + * Invoking this function in a non-SE environment + * may case a specification exception. + */ +static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx) +{ + unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */ + unsigned long reg2 = sec_idx; + union ap_queue_status_reg reg1; + + asm volatile( + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " lgr 2,%[reg2]\n" /* secret index into gr2 */ + " .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1.value) + : [reg0] "d" (reg0), [reg2] "d" (reg2) + : "cc", "0", "1", "2"); + + return reg1.status; +} + /** * ap_nqap(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -359,10 +457,11 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * ap_dqap(): Receive message from adjunct processor queue. * @qid: The AP queue number * @psmid: Pointer to program supplied message identifier - * @msg: The message text - * @length: The message length - * @reslength: Resitual length on return - * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content + * @msg: Pointer to message buffer + * @msglen: Message buffer size + * @length: Pointer to length of actually written bytes + * @reslength: Residual length on return + * @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content * * Returns AP queue status structure. * Condition code 1 on DQAP means the receive has taken place @@ -386,8 +485,9 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * *resgr0 is to be used instead of qid to further process this entry. */ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, - unsigned long long *psmid, - void *msg, size_t length, + unsigned long *psmid, + void *msg, size_t msglen, + size_t *length, size_t *reslength, unsigned long *resgr0) { @@ -399,7 +499,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, rp1.even = 0UL; rp1.odd = 0UL; rp2.even = (unsigned long)msg; - rp2.odd = (unsigned long)length; + rp2.odd = (unsigned long)msglen; asm volatile( " lgr 0,%[reg0]\n" /* qid param into gr0 */ @@ -429,11 +529,15 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, if (resgr0) *resgr0 = reg0; } else { - *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd; + *psmid = (rp1.even << 32) + rp1.odd; if (resgr0) *resgr0 = 0; } + /* update *length with the nr of bytes stored into the msg buffer */ + if (length) + *length = msglen - rp2.odd; + return reg1.status; } diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h index d977a3a2f619..69837eec2ff5 100644 --- a/arch/s390/include/asm/checksum.h +++ b/arch/s390/include/asm/checksum.h @@ -12,13 +12,7 @@ #ifndef _S390_CHECKSUM_H #define _S390_CHECKSUM_H -#ifdef CONFIG_GENERIC_CSUM - -#include - -#else /* CONFIG_GENERIC_CSUM */ - -#include +#include #include /* @@ -40,6 +34,7 @@ static inline __wsum csum_partial(const void *buff, int len, __wsum sum) .odd = (unsigned long) len, }; + kasan_check_read(buff, len); asm volatile( "0: cksm %[sum],%[rp]\n" " jo 0b\n" @@ -135,5 +130,4 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, return csum_fold((__force __wsum)(sum >> 32)); } -#endif /* CONFIG_GENERIC_CSUM */ #endif /* _S390_CHECKSUM_H */ diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 3f26416c2ad8..06e0e42f4eec 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -14,8 +14,8 @@ void __xchg_called_with_bad_pointer(void); -static __always_inline unsigned long __xchg(unsigned long x, - unsigned long address, int size) +static __always_inline unsigned long +__arch_xchg(unsigned long x, unsigned long address, int size) { unsigned long old; int shift; @@ -77,8 +77,8 @@ static __always_inline unsigned long __xchg(unsigned long x, __typeof__(*(ptr)) __ret; \ \ __ret = (__typeof__(*(ptr))) \ - __xchg((unsigned long)(x), (unsigned long)(ptr), \ - sizeof(*(ptr))); \ + __arch_xchg((unsigned long)(x), (unsigned long)(ptr), \ + sizeof(*(ptr))); \ __ret; \ }) diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index a386070f1d56..3cb9d813f022 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -112,7 +112,7 @@ struct compat_statfs64 { u32 f_namelen; u32 f_frsize; u32 f_flags; - u32 f_spare[4]; + u32 f_spare[5]; }; /* diff --git a/arch/s390/include/asm/diag.h b/arch/s390/include/asm/diag.h index 674a939f16ee..902e0330dd91 100644 --- a/arch/s390/include/asm/diag.h +++ b/arch/s390/include/asm/diag.h @@ -90,7 +90,7 @@ struct diag8c { u8 num_partitions; u16 width; u16 height; - u8 data[0]; + u8 data[]; } __packed __aligned(4); extern int diag8c(struct diag8c *out, struct ccw_dev_id *devno); diff --git a/arch/s390/include/asm/entry-common.h b/arch/s390/include/asm/entry-common.h index 000de2b1e67a..fdd319a622b0 100644 --- a/arch/s390/include/asm/entry-common.h +++ b/arch/s390/include/asm/entry-common.h @@ -60,9 +60,4 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare -static inline bool on_thread_stack(void) -{ - return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); -} - #endif diff --git a/arch/s390/include/asm/fcx.h b/arch/s390/include/asm/fcx.h index b8a028a36173..29784b4b44f6 100644 --- a/arch/s390/include/asm/fcx.h +++ b/arch/s390/include/asm/fcx.h @@ -286,7 +286,7 @@ struct tccb_tcat { */ struct tccb { struct tccb_tcah tcah; - u8 tca[0]; + u8 tca[]; } __attribute__ ((packed, aligned(8))); struct tcw *tcw_get_intrg(struct tcw *tcw); diff --git a/arch/s390/include/asm/kasan.h b/arch/s390/include/asm/kasan.h index e5cfc81d5b61..0cffead0f2f2 100644 --- a/arch/s390/include/asm/kasan.h +++ b/arch/s390/include/asm/kasan.h @@ -2,7 +2,7 @@ #ifndef __ASM_KASAN_H #define __ASM_KASAN_H -#include +#include #ifdef CONFIG_KASAN @@ -13,35 +13,6 @@ #define KASAN_SHADOW_START KASAN_SHADOW_OFFSET #define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) -extern void kasan_early_init(void); - -/* - * Estimate kasan memory requirements, which it will reserve - * at the very end of available physical memory. To estimate - * that, we take into account that kasan would require - * 1/8 of available physical memory (for shadow memory) + - * creating page tables for the shadow memory region. - * To keep page tables estimates simple take the double of - * combined ptes size. - * - * physmem parameter has to be already adjusted if not entire physical memory - * would be used (e.g. due to effect of "mem=" option). - */ -static inline unsigned long kasan_estimate_memory_needs(unsigned long physmem) -{ - unsigned long kasan_needs; - unsigned long pages; - /* for shadow memory */ - kasan_needs = round_up(physmem / 8, PAGE_SIZE); - /* for paging structures */ - pages = DIV_ROUND_UP(kasan_needs, PAGE_SIZE); - kasan_needs += DIV_ROUND_UP(pages, _PAGE_ENTRIES) * _PAGE_TABLE_SIZE * 2; - - return kasan_needs; -} -#else -static inline void kasan_early_init(void) { } -static inline unsigned long kasan_estimate_memory_needs(unsigned long physmem) { return 0; } #endif #endif diff --git a/arch/s390/include/asm/linkage.h b/arch/s390/include/asm/linkage.h index c76777b15fec..df3fb7d8227b 100644 --- a/arch/s390/include/asm/linkage.h +++ b/arch/s390/include/asm/linkage.h @@ -4,7 +4,7 @@ #include -#define __ALIGN .align 16, 0x07 +#define __ALIGN .balign CONFIG_FUNCTION_ALIGNMENT, 0x07 #define __ALIGN_STR __stringify(__ALIGN) #endif diff --git a/arch/s390/include/asm/mem_detect.h b/arch/s390/include/asm/mem_detect.h deleted file mode 100644 index f9e7354036d2..000000000000 --- a/arch/s390/include/asm/mem_detect.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_S390_MEM_DETECT_H -#define _ASM_S390_MEM_DETECT_H - -#include - -enum mem_info_source { - MEM_DETECT_NONE = 0, - MEM_DETECT_SCLP_STOR_INFO, - MEM_DETECT_DIAG260, - MEM_DETECT_SCLP_READ_INFO, - MEM_DETECT_BIN_SEARCH -}; - -struct mem_detect_block { - u64 start; - u64 end; -}; - -/* - * Storage element id is defined as 1 byte (up to 256 storage elements). - * In practise only storage element id 0 and 1 are used). - * According to architecture one storage element could have as much as - * 1020 subincrements. 255 mem_detect_blocks are embedded in mem_detect_info. - * If more mem_detect_blocks are required, a block of memory from already - * known mem_detect_block is taken (entries_extended points to it). - */ -#define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ - -struct mem_detect_info { - u32 count; - u8 info_source; - unsigned long usable; - struct mem_detect_block entries[MEM_INLINED_ENTRIES]; - struct mem_detect_block *entries_extended; -}; -extern struct mem_detect_info mem_detect; - -void add_mem_detect_block(u64 start, u64 end); - -static inline int __get_mem_detect_block(u32 n, unsigned long *start, - unsigned long *end, bool respect_usable_limit) -{ - if (n >= mem_detect.count) { - *start = 0; - *end = 0; - return -1; - } - - if (n < MEM_INLINED_ENTRIES) { - *start = (unsigned long)mem_detect.entries[n].start; - *end = (unsigned long)mem_detect.entries[n].end; - } else { - *start = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].start; - *end = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].end; - } - - if (respect_usable_limit && mem_detect.usable) { - if (*start >= mem_detect.usable) - return -1; - if (*end > mem_detect.usable) - *end = mem_detect.usable; - } - return 0; -} - -/** - * for_each_mem_detect_usable_block - early online memory range iterator - * @i: an integer used as loop variable - * @p_start: ptr to unsigned long for start address of the range - * @p_end: ptr to unsigned long for end address of the range - * - * Walks over detected online memory ranges below usable limit. - */ -#define for_each_mem_detect_usable_block(i, p_start, p_end) \ - for (i = 0; !__get_mem_detect_block(i, p_start, p_end, true); i++) - -/* Walks over all detected online memory ranges disregarding usable limit. */ -#define for_each_mem_detect_block(i, p_start, p_end) \ - for (i = 0; !__get_mem_detect_block(i, p_start, p_end, false); i++) - -static inline unsigned long get_mem_detect_usable_total(void) -{ - unsigned long start, end, total = 0; - int i; - - for_each_mem_detect_usable_block(i, &start, &end) - total += end - start; - - return total; -} - -static inline void get_mem_detect_reserved(unsigned long *start, - unsigned long *size) -{ - *start = (unsigned long)mem_detect.entries_extended; - if (mem_detect.count > MEM_INLINED_ENTRIES) - *size = (mem_detect.count - MEM_INLINED_ENTRIES) * sizeof(struct mem_detect_block); - else - *size = 0; -} - -static inline unsigned long get_mem_detect_end(void) -{ - unsigned long start; - unsigned long end; - - if (mem_detect.usable) - return mem_detect.usable; - if (mem_detect.count) { - __get_mem_detect_block(mem_detect.count - 1, &start, &end, false); - return end; - } - return 0; -} - -#endif diff --git a/arch/s390/include/asm/nospec-insn.h b/arch/s390/include/asm/nospec-insn.h index 7e9e99523e95..7a946c42ad13 100644 --- a/arch/s390/include/asm/nospec-insn.h +++ b/arch/s390/include/asm/nospec-insn.h @@ -2,6 +2,7 @@ #ifndef _ASM_S390_NOSPEC_ASM_H #define _ASM_S390_NOSPEC_ASM_H +#include #include #ifdef __ASSEMBLY__ @@ -16,7 +17,7 @@ .macro __THUNK_PROLOG_NAME name #ifdef CONFIG_EXPOLINE_EXTERN .pushsection .text,"ax",@progbits - .align 16,0x07 + __ALIGN #else .pushsection .text.\name,"axG",@progbits,\name,comdat #endif diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index b9da71632827..9917e2717b2b 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h @@ -60,7 +60,6 @@ struct perf_sf_sde_regs { #define PERF_CPUM_SF_DIAG_MODE 0x0002 /* Diagnostic-sampling flag */ #define PERF_CPUM_SF_MODE_MASK (PERF_CPUM_SF_BASIC_MODE| \ PERF_CPUM_SF_DIAG_MODE) -#define PERF_CPUM_SF_FULL_BLOCKS 0x0004 /* Process full SDBs only */ #define PERF_CPUM_SF_FREQ_MODE 0x0008 /* Sampling with frequency */ #define REG_NONE 0 @@ -71,7 +70,6 @@ struct perf_sf_sde_regs { #define SAMPL_RATE(hwc) ((hwc)->event_base) #define SAMPL_FLAGS(hwc) ((hwc)->config_base) #define SAMPL_DIAG_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_DIAG_MODE) -#define SDB_FULL_BLOCKS(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FULL_BLOCKS) #define SAMPLE_FREQ_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FREQ_MODE) #define perf_arch_fetch_caller_regs(regs, __ip) do { \ diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 2c70b4d1263d..6822a11c2c8a 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -34,7 +34,7 @@ enum { PG_DIRECT_MAP_MAX }; -extern atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX]; +extern atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); static inline void update_page_count(int level, long count) { @@ -1239,7 +1239,8 @@ static inline int pte_allow_rdp(pte_t old, pte_t new) } static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma, - unsigned long address) + unsigned long address, + pte_t *ptep) { /* * RDP might not have propagated the PTE protection reset to all CPUs, @@ -1247,11 +1248,12 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma, * NOTE: This will also be called when a racing pagetable update on * another thread already installed the correct PTE. Both cases cannot * really be distinguished. - * Therefore, only do the local TLB flush when RDP can be used, to avoid - * unnecessary overhead. + * Therefore, only do the local TLB flush when RDP can be used, and the + * PTE does not have _PAGE_PROTECT set, to avoid unnecessary overhead. + * A local RDP can be used to do the flush. */ - if (MACHINE_HAS_RDP) - asm volatile("ptlb" : : : "memory"); + if (MACHINE_HAS_RDP && !(pte_val(*ptep) & _PAGE_PROTECT)) + __ptep_rdp(address, ptep, 0, 0, 1); } #define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault diff --git a/arch/s390/include/asm/physmem_info.h b/arch/s390/include/asm/physmem_info.h new file mode 100644 index 000000000000..8e9c582592b3 --- /dev/null +++ b/arch/s390/include/asm/physmem_info.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_MEM_DETECT_H +#define _ASM_S390_MEM_DETECT_H + +#include + +enum physmem_info_source { + MEM_DETECT_NONE = 0, + MEM_DETECT_SCLP_STOR_INFO, + MEM_DETECT_DIAG260, + MEM_DETECT_SCLP_READ_INFO, + MEM_DETECT_BIN_SEARCH +}; + +struct physmem_range { + u64 start; + u64 end; +}; + +enum reserved_range_type { + RR_DECOMPRESSOR, + RR_INITRD, + RR_VMLINUX, + RR_AMODE31, + RR_IPLREPORT, + RR_CERT_COMP_LIST, + RR_MEM_DETECT_EXTENDED, + RR_VMEM, + RR_MAX +}; + +struct reserved_range { + unsigned long start; + unsigned long end; + struct reserved_range *chain; +}; + +/* + * Storage element id is defined as 1 byte (up to 256 storage elements). + * In practise only storage element id 0 and 1 are used). + * According to architecture one storage element could have as much as + * 1020 subincrements. 255 physmem_ranges are embedded in physmem_info. + * If more physmem_ranges are required, a block of memory from already + * known physmem_range is taken (online_extended points to it). + */ +#define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ + +struct physmem_info { + u32 range_count; + u8 info_source; + unsigned long usable; + struct reserved_range reserved[RR_MAX]; + struct physmem_range online[MEM_INLINED_ENTRIES]; + struct physmem_range *online_extended; +}; + +extern struct physmem_info physmem_info; + +void add_physmem_online_range(u64 start, u64 end); + +static inline int __get_physmem_range(u32 n, unsigned long *start, + unsigned long *end, bool respect_usable_limit) +{ + if (n >= physmem_info.range_count) { + *start = 0; + *end = 0; + return -1; + } + + if (n < MEM_INLINED_ENTRIES) { + *start = (unsigned long)physmem_info.online[n].start; + *end = (unsigned long)physmem_info.online[n].end; + } else { + *start = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].start; + *end = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].end; + } + + if (respect_usable_limit && physmem_info.usable) { + if (*start >= physmem_info.usable) + return -1; + if (*end > physmem_info.usable) + *end = physmem_info.usable; + } + return 0; +} + +/** + * for_each_physmem_usable_range - early online memory range iterator + * @i: an integer used as loop variable + * @p_start: ptr to unsigned long for start address of the range + * @p_end: ptr to unsigned long for end address of the range + * + * Walks over detected online memory ranges below usable limit. + */ +#define for_each_physmem_usable_range(i, p_start, p_end) \ + for (i = 0; !__get_physmem_range(i, p_start, p_end, true); i++) + +/* Walks over all detected online memory ranges disregarding usable limit. */ +#define for_each_physmem_online_range(i, p_start, p_end) \ + for (i = 0; !__get_physmem_range(i, p_start, p_end, false); i++) + +static inline const char *get_physmem_info_source(void) +{ + switch (physmem_info.info_source) { + case MEM_DETECT_SCLP_STOR_INFO: + return "sclp storage info"; + case MEM_DETECT_DIAG260: + return "diag260"; + case MEM_DETECT_SCLP_READ_INFO: + return "sclp read info"; + case MEM_DETECT_BIN_SEARCH: + return "binary search"; + } + return "none"; +} + +#define RR_TYPE_NAME(t) case RR_ ## t: return #t +static inline const char *get_rr_type_name(enum reserved_range_type t) +{ + switch (t) { + RR_TYPE_NAME(DECOMPRESSOR); + RR_TYPE_NAME(INITRD); + RR_TYPE_NAME(VMLINUX); + RR_TYPE_NAME(AMODE31); + RR_TYPE_NAME(IPLREPORT); + RR_TYPE_NAME(CERT_COMP_LIST); + RR_TYPE_NAME(MEM_DETECT_EXTENDED); + RR_TYPE_NAME(VMEM); + default: + return "UNKNOWN"; + } +} + +#define for_each_physmem_reserved_type_range(t, range, p_start, p_end) \ + for (range = &physmem_info.reserved[t], *p_start = range->start, *p_end = range->end; \ + range && range->end; range = range->chain, \ + *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) + +static inline struct reserved_range *__physmem_reserved_next(enum reserved_range_type *t, + struct reserved_range *range) +{ + if (!range) { + range = &physmem_info.reserved[*t]; + if (range->end) + return range; + } + if (range->chain) + return range->chain; + while (++*t < RR_MAX) { + range = &physmem_info.reserved[*t]; + if (range->end) + return range; + } + return NULL; +} + +#define for_each_physmem_reserved_range(t, range, p_start, p_end) \ + for (t = 0, range = __physmem_reserved_next(&t, NULL), \ + *p_start = range ? range->start : 0, *p_end = range ? range->end : 0; \ + range; range = __physmem_reserved_next(&t, range), \ + *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) + +static inline unsigned long get_physmem_reserved(enum reserved_range_type type, + unsigned long *addr, unsigned long *size) +{ + *addr = physmem_info.reserved[type].start; + *size = physmem_info.reserved[type].end - physmem_info.reserved[type].start; + return *size; +} + +#endif diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index e98d9650764b..dc17896a001a 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -99,7 +99,6 @@ void cpu_detect_mhz_feature(void); extern const struct seq_operations cpuinfo_op; extern void execve_tail(void); -extern void __bpon(void); unsigned long vdso_size(void); /* @@ -119,6 +118,41 @@ unsigned long vdso_size(void); #define HAVE_ARCH_PICK_MMAP_LAYOUT +#define __stackleak_poison __stackleak_poison +static __always_inline void __stackleak_poison(unsigned long erase_low, + unsigned long erase_high, + unsigned long poison) +{ + unsigned long tmp, count; + + count = erase_high - erase_low; + if (!count) + return; + asm volatile( + " cghi %[count],8\n" + " je 2f\n" + " aghi %[count],-(8+1)\n" + " srlg %[tmp],%[count],8\n" + " ltgr %[tmp],%[tmp]\n" + " jz 1f\n" + "0: stg %[poison],0(%[addr])\n" + " mvc 8(256-8,%[addr]),0(%[addr])\n" + " la %[addr],256(%[addr])\n" + " brctg %[tmp],0b\n" + "1: stg %[poison],0(%[addr])\n" + " larl %[tmp],3f\n" + " ex %[count],0(%[tmp])\n" + " j 4f\n" + "2: stg %[poison],0(%[addr])\n" + " j 4f\n" + "3: mvc 8(1,%[addr]),0(%[addr])\n" + "4:\n" + : [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp) + : [poison] "d" (poison) + : "memory", "cc" + ); +} + /* * Thread structure */ @@ -227,6 +261,13 @@ static __always_inline unsigned long __current_stack_pointer(void) return sp; } +static __always_inline bool on_thread_stack(void) +{ + unsigned long ksp = S390_lowcore.kernel_stack; + + return !((ksp ^ current_stack_pointer) & ~(THREAD_SIZE - 1)); +} + static __always_inline unsigned short stap(void) { unsigned short cpu_address; @@ -329,9 +370,6 @@ static __always_inline void __noreturn disabled_wait(void) #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL -extern int s390_isolate_bp(void); -extern int s390_isolate_bp_guest(void); - static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) { return arch_irqs_disabled_flags(regs->psw.mask); diff --git a/arch/s390/include/asm/set_memory.h b/arch/s390/include/asm/set_memory.h index 950d87bd997a..7a3eefd7a242 100644 --- a/arch/s390/include/asm/set_memory.h +++ b/arch/s390/include/asm/set_memory.h @@ -6,11 +6,23 @@ extern struct mutex cpa_mutex; -#define SET_MEMORY_RO 1UL -#define SET_MEMORY_RW 2UL -#define SET_MEMORY_NX 4UL -#define SET_MEMORY_X 8UL -#define SET_MEMORY_4K 16UL +enum { + _SET_MEMORY_RO_BIT, + _SET_MEMORY_RW_BIT, + _SET_MEMORY_NX_BIT, + _SET_MEMORY_X_BIT, + _SET_MEMORY_4K_BIT, + _SET_MEMORY_INV_BIT, + _SET_MEMORY_DEF_BIT, +}; + +#define SET_MEMORY_RO BIT(_SET_MEMORY_RO_BIT) +#define SET_MEMORY_RW BIT(_SET_MEMORY_RW_BIT) +#define SET_MEMORY_NX BIT(_SET_MEMORY_NX_BIT) +#define SET_MEMORY_X BIT(_SET_MEMORY_X_BIT) +#define SET_MEMORY_4K BIT(_SET_MEMORY_4K_BIT) +#define SET_MEMORY_INV BIT(_SET_MEMORY_INV_BIT) +#define SET_MEMORY_DEF BIT(_SET_MEMORY_DEF_BIT) int __set_memory(unsigned long addr, int numpages, unsigned long flags); @@ -34,9 +46,23 @@ static inline int set_memory_x(unsigned long addr, int numpages) return __set_memory(addr, numpages, SET_MEMORY_X); } +#define set_memory_rox set_memory_rox +static inline int set_memory_rox(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_RO | SET_MEMORY_X); +} + +static inline int set_memory_rwnx(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, SET_MEMORY_RW | SET_MEMORY_NX); +} + static inline int set_memory_4k(unsigned long addr, int numpages) { return __set_memory(addr, numpages, SET_MEMORY_4K); } +int set_direct_map_invalid_noflush(struct page *page); +int set_direct_map_default_noflush(struct page *page); + #endif diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 3a1f8825bc7d..f191255c60db 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -74,10 +74,6 @@ extern unsigned int zlib_dfltcc_support; extern int noexec_disabled; extern unsigned long ident_map_size; -extern unsigned long pgalloc_pos; -extern unsigned long pgalloc_end; -extern unsigned long pgalloc_low; -extern unsigned long __amode31_base; /* The Write Back bit position in the physaddr is given by the SLPC PCI */ extern unsigned long mio_wb_bit_mask; @@ -150,13 +146,13 @@ static inline unsigned long kaslr_offset(void) return __kaslr_offset; } -extern int is_full_image; - -struct initrd_data { - unsigned long start; - unsigned long size; -}; -extern struct initrd_data initrd_data; +extern int __kaslr_enabled; +static inline int kaslr_enabled(void) +{ + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) + return __kaslr_enabled; + return 0; +} struct oldmem_data { unsigned long start; @@ -164,7 +160,7 @@ struct oldmem_data { }; extern struct oldmem_data oldmem_data; -static inline u32 gen_lpswe(unsigned long addr) +static __always_inline u32 gen_lpswe(unsigned long addr) { BUILD_BUG_ON(addr > 0xfff); return 0xb2b20000 | addr; diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index 1802be5abb5d..78f7b729b65f 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -189,17 +189,53 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task, (rettype)r2; \ }) -#define call_on_stack_noreturn(fn, stack) \ +/* + * Use call_nodat() to call a function with DAT disabled. + * Proper sign and zero extension of function arguments is done. + * Usage: + * + * rc = call_nodat(nr, rettype, fn, t1, a1, t2, a2, ...) + * + * - nr specifies the number of function arguments of fn. + * - fn is the function to be called, where fn is a physical address. + * - rettype is the return type of fn. + * - t1, a1, ... are pairs, where t1 must match the type of the first + * argument of fn, t2 the second, etc. a1 is the corresponding + * first function argument (not name), etc. + * + * fn() is called with standard C function call ABI, with the exception + * that no useful stackframe or stackpointer is passed via register 15. + * Therefore the called function must not use r15 to access the stack. + */ +#define call_nodat(nr, rettype, fn, ...) \ ({ \ - void (*__fn)(void) = fn; \ + rettype (*__fn)(CALL_PARM_##nr(__VA_ARGS__)) = (fn); \ + /* aligned since psw_leave must not cross page boundary */ \ + psw_t __aligned(16) psw_leave; \ + psw_t psw_enter; \ + CALL_LARGS_##nr(__VA_ARGS__); \ + CALL_REGS_##nr; \ \ + CALL_TYPECHECK_##nr(__VA_ARGS__); \ + psw_enter.mask = PSW_KERNEL_BITS & ~PSW_MASK_DAT; \ + psw_enter.addr = (unsigned long)__fn; \ asm volatile( \ - " la 15,0(%[_stack])\n" \ - " xc %[_bc](8,15),%[_bc](15)\n" \ - " brasl 14,%[_fn]\n" \ - ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \ - [_stack] "a" (stack), [_fn] "X" (__fn)); \ - BUG(); \ + " epsw 0,1\n" \ + " risbg 1,0,0,31,32\n" \ + " larl 7,1f\n" \ + " stg 1,%[psw_leave]\n" \ + " stg 7,8+%[psw_leave]\n" \ + " la 7,%[psw_leave]\n" \ + " lra 7,0(7)\n" \ + " larl 1,0f\n" \ + " lra 14,0(1)\n" \ + " lpswe %[psw_enter]\n" \ + "0: lpswe 0(7)\n" \ + "1:\n" \ + : CALL_FMT_##nr, [psw_leave] "=Q" (psw_leave) \ + : [psw_enter] "Q" (psw_enter) \ + : "7", CALL_CLOBBER_##nr); \ + (rettype)r2; \ }) #endif /* _ASM_S390_STACKTRACE_H */ diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index 3fae93ddb322..351685de53d2 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -55,18 +55,6 @@ char *strstr(const char *s1, const char *s2); #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) -extern void *__memcpy(void *dest, const void *src, size_t n); -extern void *__memset(void *s, int c, size_t n); -extern void *__memmove(void *dest, const void *src, size_t n); - -/* - * For files that are not instrumented (e.g. mm/slub.c) we - * should use not instrumented version of mem* functions. - */ - -#define memcpy(dst, src, len) __memcpy(dst, src, len) -#define memmove(dst, src, len) __memmove(dst, src, len) -#define memset(s, c, n) __memset(s, c, n) #define strlen(s) __strlen(s) #define __no_sanitize_prefix_strfunc(x) __##x @@ -79,6 +67,9 @@ extern void *__memmove(void *dest, const void *src, size_t n); #define __no_sanitize_prefix_strfunc(x) x #endif /* defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) */ +void *__memcpy(void *dest, const void *src, size_t n); +void *__memset(void *s, int c, size_t n); +void *__memmove(void *dest, const void *src, size_t n); void *__memset16(uint16_t *s, uint16_t v, size_t count); void *__memset32(uint32_t *s, uint32_t v, size_t count); void *__memset64(uint64_t *s, uint64_t v, size_t count); diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index b2ffcb4fe000..c7c97921ed8d 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -9,6 +9,9 @@ #define _ASM_THREAD_INFO_H #include +#ifndef ASM_OFFSETS_C +#include +#endif /* * General size of kernel stacks @@ -21,13 +24,12 @@ #define BOOT_STACK_SIZE (PAGE_SIZE << 2) #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) +#define STACK_INIT_OFFSET (THREAD_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE) + #ifndef __ASSEMBLY__ #include #include -#define STACK_INIT_OFFSET \ - (THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs)) - /* * low level task data that entry.S needs immediate access to * - this struct should fit entirely inside of one cache line @@ -70,7 +72,6 @@ void arch_setup_new_exec(void); #define TIF_PATCH_PENDING 5 /* pending live patching update */ #define TIF_PGSTE 6 /* New mm's will use 4K page tables */ #define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */ -#define TIF_ISOLATE_BP 8 /* Run process with isolated BP */ #define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */ #define TIF_PER_TRAP 10 /* Need to handle PER trap on exit to usermode */ @@ -94,7 +95,6 @@ void arch_setup_new_exec(void); #define _TIF_UPROBE BIT(TIF_UPROBE) #define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE) #define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING) -#define _TIF_ISOLATE_BP BIT(TIF_ISOLATE_BP) #define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST) #define _TIF_PER_TRAP BIT(TIF_PER_TRAP) diff --git a/arch/s390/include/uapi/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h index 72604f7792c3..f85b50723dd3 100644 --- a/arch/s390/include/uapi/asm/statfs.h +++ b/arch/s390/include/uapi/asm/statfs.h @@ -30,7 +30,7 @@ struct statfs { unsigned int f_namelen; unsigned int f_frsize; unsigned int f_flags; - unsigned int f_spare[4]; + unsigned int f_spare[5]; }; struct statfs64 { @@ -45,7 +45,7 @@ struct statfs64 { unsigned int f_namelen; unsigned int f_frsize; unsigned int f_flags; - unsigned int f_spare[4]; + unsigned int f_spare[5]; }; #endif diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 8983837b3565..6b2a051e1f8a 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -10,6 +10,7 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) # Do not trace early setup code CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_rethook.o = $(CC_FLAGS_FTRACE) endif diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index b376f0377a2c..a85e0c3e7027 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -60,7 +60,7 @@ typedef struct { * except of floats, and long long (32 bit) * */ - long args[0]; + long args[]; } debug_sprintf_entry_t; /* internal function prototyes */ @@ -981,16 +981,6 @@ static struct ctl_table s390dbf_table[] = { { } }; -static struct ctl_table s390dbf_dir_table[] = { - { - .procname = "s390dbf", - .maxlen = 0, - .mode = S_IRUGO | S_IXUGO, - .child = s390dbf_table, - }, - { } -}; - static struct ctl_table_header *s390dbf_sysctl_header; /** @@ -1574,7 +1564,7 @@ out: */ static int __init debug_init(void) { - s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); + s390dbf_sysctl_header = register_sysctl("s390dbf", s390dbf_table); mutex_lock(&debug_mutex); debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT, NULL); initialized = 1; diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index 1e3233eb510a..d2012635b093 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c @@ -41,60 +41,50 @@ const char *stack_type_name(enum stack_type type) EXPORT_SYMBOL_GPL(stack_type_name); static inline bool in_stack(unsigned long sp, struct stack_info *info, - enum stack_type type, unsigned long low, - unsigned long high) + enum stack_type type, unsigned long stack) { - if (sp < low || sp >= high) + if (sp < stack || sp >= stack + THREAD_SIZE) return false; info->type = type; - info->begin = low; - info->end = high; + info->begin = stack; + info->end = stack + THREAD_SIZE; return true; } static bool in_task_stack(unsigned long sp, struct task_struct *task, struct stack_info *info) { - unsigned long stack; + unsigned long stack = (unsigned long)task_stack_page(task); - stack = (unsigned long) task_stack_page(task); - return in_stack(sp, info, STACK_TYPE_TASK, stack, stack + THREAD_SIZE); + return in_stack(sp, info, STACK_TYPE_TASK, stack); } static bool in_irq_stack(unsigned long sp, struct stack_info *info) { - unsigned long frame_size, top; + unsigned long stack = S390_lowcore.async_stack - STACK_INIT_OFFSET; - frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - top = S390_lowcore.async_stack + frame_size; - return in_stack(sp, info, STACK_TYPE_IRQ, top - THREAD_SIZE, top); + return in_stack(sp, info, STACK_TYPE_IRQ, stack); } static bool in_nodat_stack(unsigned long sp, struct stack_info *info) { - unsigned long frame_size, top; + unsigned long stack = S390_lowcore.nodat_stack - STACK_INIT_OFFSET; - frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - top = S390_lowcore.nodat_stack + frame_size; - return in_stack(sp, info, STACK_TYPE_NODAT, top - THREAD_SIZE, top); + return in_stack(sp, info, STACK_TYPE_NODAT, stack); } static bool in_mcck_stack(unsigned long sp, struct stack_info *info) { - unsigned long frame_size, top; + unsigned long stack = S390_lowcore.mcck_stack - STACK_INIT_OFFSET; - frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - top = S390_lowcore.mcck_stack + frame_size; - return in_stack(sp, info, STACK_TYPE_MCCK, top - THREAD_SIZE, top); + return in_stack(sp, info, STACK_TYPE_MCCK, stack); } static bool in_restart_stack(unsigned long sp, struct stack_info *info) { - unsigned long frame_size, top; + unsigned long stack = S390_lowcore.restart_stack - STACK_INIT_OFFSET; - frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); - top = S390_lowcore.restart_stack + frame_size; - return in_stack(sp, info, STACK_TYPE_RESTART, top - THREAD_SIZE, top); + return in_stack(sp, info, STACK_TYPE_RESTART, stack); } int get_stack_info(unsigned long sp, struct task_struct *task, @@ -152,7 +142,13 @@ void show_stack(struct task_struct *task, unsigned long *stack, static void show_last_breaking_event(struct pt_regs *regs) { printk("Last Breaking-Event-Address:\n"); - printk(" [<%016lx>] %pSR\n", regs->last_break, (void *)regs->last_break); + printk(" [<%016lx>] ", regs->last_break); + if (user_mode(regs)) { + print_vma_addr(KERN_CONT, regs->last_break); + pr_cont("\n"); + } else { + pr_cont("%pSR\n", (void *)regs->last_break); + } } void show_registers(struct pt_regs *regs) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index d26f02495636..2dd5976a55ac 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -34,8 +34,6 @@ #include #include "entry.h" -int __bootdata(is_full_image); - #define decompressor_handled_param(param) \ static int __init ignore_decompressor_param_##param(char *s) \ { \ @@ -53,6 +51,14 @@ decompressor_handled_param(nokaslr); decompressor_handled_param(prot_virt); #endif +static void __init kasan_early_init(void) +{ +#ifdef CONFIG_KASAN + init_task.kasan_depth = 0; + sclp_early_printk("KernelAddressSanitizer initialized\n"); +#endif +} + static void __init reset_tod_clock(void) { union tod_clock clk; @@ -288,17 +294,6 @@ static void __init setup_boot_command_line(void) strscpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE); } -static void __init check_image_bootable(void) -{ - if (is_full_image) - return; - - sclp_early_printk("Linux kernel boot failure: An attempt to boot a vmlinux ELF image failed.\n"); - sclp_early_printk("This image does not contain all parts necessary for starting up. Use\n"); - sclp_early_printk("bzImage or arch/s390/boot/compressed/vmlinux instead.\n"); - disabled_wait(); -} - static void __init sort_amode31_extable(void) { sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table); @@ -306,8 +301,8 @@ static void __init sort_amode31_extable(void) void __init startup_init(void) { + kasan_early_init(); reset_tod_clock(); - check_image_bootable(); time_early_init(); init_kernel_storage_key(); lockdep_off(); diff --git a/arch/s390/kernel/earlypgm.S b/arch/s390/kernel/earlypgm.S index f521c6da37b8..c634871f0d90 100644 --- a/arch/s390/kernel/earlypgm.S +++ b/arch/s390/kernel/earlypgm.S @@ -7,7 +7,7 @@ #include #include -ENTRY(early_pgm_check_handler) +SYM_CODE_START(early_pgm_check_handler) stmg %r8,%r15,__LC_SAVE_AREA_SYNC aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) la %r11,STACK_FRAME_OVERHEAD(%r15) @@ -20,4 +20,4 @@ ENTRY(early_pgm_check_handler) mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) lpswe __LC_RETURN_PSW -ENDPROC(early_pgm_check_handler) +SYM_CODE_END(early_pgm_check_handler) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 76a06f3d3671..e5b6c1369e8e 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -29,10 +29,6 @@ #include #include -STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER -STACK_SIZE = 1 << STACK_SHIFT -STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE - _LPP_OFFSET = __LC_LPP .macro STBEAR address @@ -53,7 +49,7 @@ _LPP_OFFSET = __LC_LPP .macro CHECK_STACK savearea #ifdef CONFIG_CHECK_STACK - tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + tml %r15,THREAD_SIZE - CONFIG_STACK_GUARD lghi %r14,\savearea jz stack_overflow #endif @@ -62,8 +58,8 @@ _LPP_OFFSET = __LC_LPP .macro CHECK_VMAP_STACK savearea,oklabel #ifdef CONFIG_VMAP_STACK lgr %r14,%r15 - nill %r14,0x10000 - STACK_SIZE - oill %r14,STACK_INIT + nill %r14,0x10000 - THREAD_SIZE + oill %r14,STACK_INIT_OFFSET clg %r14,__LC_KERNEL_STACK je \oklabel clg %r14,__LC_ASYNC_STACK @@ -154,26 +150,26 @@ _LPP_OFFSET = __LC_LPP .endm #endif + .macro STACKLEAK_ERASE +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK + brasl %r14,stackleak_erase_on_task_stack +#endif + .endm + GEN_BR_THUNK %r14 .section .kprobes.text, "ax" .Ldummy: /* - * This nop exists only in order to avoid that __bpon starts at - * the beginning of the kprobes text section. In that case we would - * have several symbols at the same address. E.g. objdump would take - * an arbitrary symbol name when disassembling this code. - * With the added nop in between the __bpon symbol is unique - * again. + * The following nop exists only in order to avoid that the next + * symbol starts at the beginning of the kprobes text section. + * In that case there would be several symbols at the same address. + * E.g. objdump would take an arbitrary symbol when disassembling + * the code. + * With the added nop in between this cannot happen. */ nop 0 -ENTRY(__bpon) - .globl __bpon - BPON - BR_EX %r14 -ENDPROC(__bpon) - /* * Scheduler resume function, called by switch_to * gpr2 = (task_struct *) prev @@ -181,11 +177,11 @@ ENDPROC(__bpon) * Returns: * gpr2 = prev */ -ENTRY(__switch_to) +SYM_FUNC_START(__switch_to) stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task lghi %r4,__TASK_stack lghi %r1,__TASK_thread - llill %r5,STACK_INIT + llill %r5,STACK_INIT_OFFSET stg %r15,__THREAD_ksp(%r1,%r2) # store kernel stack of prev lg %r15,0(%r4,%r3) # start of kernel stack of next agr %r15,%r5 # end of kernel stack of next @@ -197,7 +193,7 @@ ENTRY(__switch_to) lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 BR_EX %r14 -ENDPROC(__switch_to) +SYM_FUNC_END(__switch_to) #if IS_ENABLED(CONFIG_KVM) /* @@ -206,7 +202,7 @@ ENDPROC(__switch_to) * %r3 pointer to sie control block virt * %r4 guest register save area */ -ENTRY(__sie64a) +SYM_FUNC_START(__sie64a) stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers lg %r12,__LC_CURRENT stg %r2,__SF_SIE_CONTROL_PHYS(%r15) # save sie block physical.. @@ -227,7 +223,7 @@ ENTRY(__sie64a) TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed lg %r14,__SF_SIE_CONTROL_PHYS(%r15) # get sie block phys addr - BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + BPEXIT __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST .Lsie_entry: sie 0(%r14) # Let the next instruction be NOP to avoid triggering a machine check @@ -235,7 +231,7 @@ ENTRY(__sie64a) nopr 7 .Lsie_leave: BPOFF - BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST .Lsie_skip: lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE @@ -252,8 +248,7 @@ ENTRY(__sie64a) nopr 7 .Lrewind_pad2: nopr 7 - .globl sie_exit -sie_exit: +SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL) lg %r14,__SF_SIE_SAVEAREA(%r15) # load guest register save area stmg %r0,%r13,0(%r14) # save guest gprs 0-13 xgr %r0,%r0 # clear guest registers to @@ -273,7 +268,7 @@ sie_exit: EX_TABLE(.Lrewind_pad4,.Lsie_fault) EX_TABLE(.Lrewind_pad2,.Lsie_fault) EX_TABLE(sie_exit,.Lsie_fault) -ENDPROC(__sie64a) +SYM_FUNC_END(__sie64a) EXPORT_SYMBOL(__sie64a) EXPORT_SYMBOL(sie_exit) #endif @@ -283,7 +278,7 @@ EXPORT_SYMBOL(sie_exit) * are entered with interrupts disabled. */ -ENTRY(system_call) +SYM_CODE_START(system_call) stpt __LC_SYS_ENTER_TIMER stmg %r8,%r15,__LC_SAVE_AREA_SYNC BPOFF @@ -291,11 +286,9 @@ ENTRY(system_call) .Lsysc_per: STBEAR __LC_LAST_BREAK lctlg %c1,%c1,__LC_KERNEL_ASCE - lg %r12,__LC_CURRENT lg %r15,__LC_KERNEL_STACK xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) stmg %r0,%r7,STACK_FRAME_OVERHEAD+__PT_R0(%r15) - BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP # clear user controlled register to prevent speculative use xgr %r0,%r0 xgr %r1,%r1 @@ -312,39 +305,40 @@ ENTRY(system_call) MBEAR %r2 lgr %r3,%r14 brasl %r14,__do_syscall + STACKLEAK_ERASE lctlg %c1,%c1,__LC_USER_ASCE mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) - BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP + BPON LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) stpt __LC_EXIT_TIMER LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE -ENDPROC(system_call) +SYM_CODE_END(system_call) # # a new process exits the kernel with ret_from_fork # -ENTRY(ret_from_fork) +SYM_CODE_START(ret_from_fork) lgr %r3,%r11 brasl %r14,__ret_from_fork + STACKLEAK_ERASE lctlg %c1,%c1,__LC_USER_ASCE mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) - BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP + BPON LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15) lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) stpt __LC_EXIT_TIMER LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE -ENDPROC(ret_from_fork) +SYM_CODE_END(ret_from_fork) /* * Program check handler routine */ -ENTRY(pgm_check_handler) +SYM_CODE_START(pgm_check_handler) stpt __LC_SYS_ENTER_TIMER BPOFF stmg %r8,%r15,__LC_SAVE_AREA_SYNC - lg %r12,__LC_CURRENT lghi %r10,0 lmg %r8,%r9,__LC_PGM_OLD_PSW tmhh %r8,0x0001 # coming from user space? @@ -355,6 +349,7 @@ ENTRY(pgm_check_handler) #if IS_ENABLED(CONFIG_KVM) # cleanup critical section for program checks in __sie64a OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f + BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST SIEEXIT lghi %r10,_PIF_GUEST_FAULT #endif @@ -366,8 +361,7 @@ ENTRY(pgm_check_handler) aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) # CHECK_VMAP_STACK branches to stack_overflow or 4f CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f -3: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP - lg %r15,__LC_KERNEL_STACK +3: lg %r15,__LC_KERNEL_STACK 4: la %r11,STACK_FRAME_OVERHEAD(%r15) stg %r10,__PT_FLAGS(%r11) xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) @@ -388,8 +382,9 @@ ENTRY(pgm_check_handler) brasl %r14,__do_pgm_check tmhh %r8,0x0001 # returning to user space? jno .Lpgm_exit_kernel + STACKLEAK_ERASE lctlg %c1,%c1,__LC_USER_ASCE - BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP + BPON stpt __LC_EXIT_TIMER .Lpgm_exit_kernel: mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) @@ -407,32 +402,30 @@ ENTRY(pgm_check_handler) lghi %r14,1 LBEAR __LC_PGM_LAST_BREAK LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE # branch to .Lsysc_per -ENDPROC(pgm_check_handler) +SYM_CODE_END(pgm_check_handler) /* * Interrupt handler macro used for external and IO interrupts. */ .macro INT_HANDLER name,lc_old_psw,handler -ENTRY(\name) +SYM_CODE_START(\name) stckf __LC_INT_CLOCK stpt __LC_SYS_ENTER_TIMER STBEAR __LC_LAST_BREAK BPOFF stmg %r8,%r15,__LC_SAVE_AREA_ASYNC - lg %r12,__LC_CURRENT lmg %r8,%r9,\lc_old_psw tmhh %r8,0x0001 # interrupting from user ? jnz 1f #if IS_ENABLED(CONFIG_KVM) OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f - BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST SIEEXIT #endif 0: CHECK_STACK __LC_SAVE_AREA_ASYNC aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) j 2f -1: BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP - lctlg %c1,%c1,__LC_KERNEL_ASCE +1: lctlg %c1,%c1,__LC_KERNEL_ASCE lg %r15,__LC_KERNEL_STACK 2: xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) la %r11,STACK_FRAME_OVERHEAD(%r15) @@ -455,13 +448,14 @@ ENTRY(\name) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) tmhh %r8,0x0001 # returning to user ? jno 2f + STACKLEAK_ERASE lctlg %c1,%c1,__LC_USER_ASCE - BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP + BPON stpt __LC_EXIT_TIMER 2: LBEAR __PT_LAST_BREAK(%r11) lmg %r0,%r15,__PT_R0(%r11) LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE -ENDPROC(\name) +SYM_CODE_END(\name) .endm INT_HANDLER ext_int_handler,__LC_EXT_OLD_PSW,do_ext_irq @@ -470,7 +464,7 @@ INT_HANDLER io_int_handler,__LC_IO_OLD_PSW,do_io_irq /* * Load idle PSW. */ -ENTRY(psw_idle) +SYM_FUNC_START(psw_idle) stg %r14,(__SF_GPRS+8*8)(%r15) stg %r3,__SF_EMPTY(%r15) larl %r1,psw_idle_exit @@ -486,29 +480,26 @@ ENTRY(psw_idle) stckf __CLOCK_IDLE_ENTER(%r2) stpt __TIMER_IDLE_ENTER(%r2) lpswe __SF_EMPTY(%r15) -.globl psw_idle_exit -psw_idle_exit: +SYM_INNER_LABEL(psw_idle_exit, SYM_L_GLOBAL) BR_EX %r14 -ENDPROC(psw_idle) +SYM_FUNC_END(psw_idle) /* * Machine check handler routines */ -ENTRY(mcck_int_handler) +SYM_CODE_START(mcck_int_handler) stckf __LC_MCCK_CLOCK BPOFF la %r1,4095 # validate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer LBEAR __LC_LAST_BREAK_SAVE_AREA-4095(%r1) # validate bear - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs - lg %r12,__LC_CURRENT + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA # validate gprs lmg %r8,%r9,__LC_MCK_OLD_PSW TSTMSK __LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE jo .Lmcck_panic # yes -> rest of mcck code invalid TSTMSK __LC_MCCK_CODE,MCCK_CODE_CR_VALID jno .Lmcck_panic # control registers invalid -> panic - la %r14,4095 - lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs + lctlg %c0,%c15,__LC_CREGS_SAVE_AREA # validate ctl regs ptlb lghi %r14,__LC_CPU_TIMER_SAVE_AREA mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) @@ -530,16 +521,13 @@ ENTRY(mcck_int_handler) TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID jno .Lmcck_panic #if IS_ENABLED(CONFIG_KVM) - OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack + OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_user OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST -4: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) +4: BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST SIEEXIT - j .Lmcck_stack #endif .Lmcck_user: - BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP -.Lmcck_stack: lg %r15,__LC_MCCK_STACK la %r11,STACK_FRAME_OVERHEAD(%r15) stctg %c1,%c1,__PT_CR1(%r11) @@ -567,7 +555,7 @@ ENTRY(mcck_int_handler) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f - BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP + BPON stpt __LC_EXIT_TIMER 0: ALTERNATIVE "nop", __stringify(lghi %r12,__LC_LAST_BREAK_SAVE_AREA),193 LBEAR 0(%r12) @@ -583,10 +571,10 @@ ENTRY(mcck_int_handler) */ lhi %r5,0 lhi %r6,1 - larl %r7,.Lstop_lock + larl %r7,stop_lock cs %r5,%r6,0(%r7) # single CPU-stopper only jnz 4f - larl %r7,.Lthis_cpu + larl %r7,this_cpu stap 0(%r7) # this CPU address lh %r4,0(%r7) nilh %r4,0 @@ -602,16 +590,15 @@ ENTRY(mcck_int_handler) 3: sigp %r1,%r4,SIGP_STOP # stop this CPU brc SIGP_CC_BUSY,3b 4: j 4b -ENDPROC(mcck_int_handler) +SYM_CODE_END(mcck_int_handler) -ENTRY(restart_int_handler) +SYM_CODE_START(restart_int_handler) ALTERNATIVE "nop", "lpp _LPP_OFFSET", 40 stg %r15,__LC_SAVE_AREA_RESTART TSTMSK __LC_RESTART_FLAGS,RESTART_FLAG_CTLREGS,4 jz 0f - la %r15,4095 - lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r15) -0: larl %r15,.Lstosm_tmp + lctlg %c0,%c15,__LC_CREGS_SAVE_AREA +0: larl %r15,stosm_tmp stosm 0(%r15),0x04 # turn dat on, keep irqs off lg %r15,__LC_RESTART_STACK xc STACK_FRAME_OVERHEAD(__PT_SIZE,%r15),STACK_FRAME_OVERHEAD(%r15) @@ -632,7 +619,7 @@ ENTRY(restart_int_handler) 2: sigp %r4,%r3,SIGP_STOP # sigp stop to current cpu brc 2,2b 3: j 3b -ENDPROC(restart_int_handler) +SYM_CODE_END(restart_int_handler) .section .kprobes.text, "ax" @@ -642,7 +629,7 @@ ENDPROC(restart_int_handler) * No need to properly save the registers, we are going to panic anyway. * Setup a pt_regs so that show_trace can provide a good call trace. */ -ENTRY(stack_overflow) +SYM_CODE_START(stack_overflow) lg %r15,__LC_NODAT_STACK # change to panic stack la %r11,STACK_FRAME_OVERHEAD(%r15) stmg %r0,%r7,__PT_R0(%r11) @@ -652,26 +639,27 @@ ENTRY(stack_overflow) xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) lgr %r2,%r11 # pass pointer to pt_regs jg kernel_stack_overflow -ENDPROC(stack_overflow) +SYM_CODE_END(stack_overflow) #endif .section .data, "aw" - .align 4 -.Lstop_lock: .long 0 -.Lthis_cpu: .short 0 -.Lstosm_tmp: .byte 0 + .balign 4 +SYM_DATA_LOCAL(stop_lock, .long 0) +SYM_DATA_LOCAL(this_cpu, .short 0) +SYM_DATA_LOCAL(stosm_tmp, .byte 0) + .section .rodata, "a" #define SYSCALL(esame,emu) .quad __s390x_ ## esame - .globl sys_call_table -sys_call_table: +SYM_DATA_START(sys_call_table) #include "asm/syscall_table.h" +SYM_DATA_END(sys_call_table) #undef SYSCALL #ifdef CONFIG_COMPAT #define SYSCALL(esame,emu) .quad __s390_ ## emu - .globl sys_call_table_emu -sys_call_table_emu: +SYM_DATA_START(sys_call_table_emu) #include "asm/syscall_table.h" +SYM_DATA_END(sys_call_table_emu) #undef SYSCALL #endif diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 416b5a94353d..c46381ea04ec 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -49,26 +49,6 @@ struct ftrace_insn { s32 disp; } __packed; -asm( - " .align 16\n" - "ftrace_shared_hotpatch_trampoline_br:\n" - " lmg %r0,%r1,2(%r1)\n" - " br %r1\n" - "ftrace_shared_hotpatch_trampoline_br_end:\n" -); - -#ifdef CONFIG_EXPOLINE -asm( - " .align 16\n" - "ftrace_shared_hotpatch_trampoline_exrl:\n" - " lmg %r0,%r1,2(%r1)\n" - " exrl %r0,0f\n" - " j .\n" - "0: br %r1\n" - "ftrace_shared_hotpatch_trampoline_exrl_end:\n" -); -#endif /* CONFIG_EXPOLINE */ - #ifdef CONFIG_MODULES static char *ftrace_plt; #endif /* CONFIG_MODULES */ @@ -246,7 +226,7 @@ static int __init ftrace_plt_init(void) start = ftrace_shared_hotpatch_trampoline(&end); memcpy(ftrace_plt, start, end - start); - set_memory_ro((unsigned long)ftrace_plt, 1); + set_memory_rox((unsigned long)ftrace_plt, 1); return 0; } device_initcall(ftrace_plt_init); diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 3b3bf8329e6c..df77ba102096 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -16,7 +16,7 @@ #include __HEAD -ENTRY(startup_continue) +SYM_CODE_START(startup_continue) larl %r1,tod_clock_base mvc 0(16,%r1),__LC_BOOT_CLOCK # @@ -24,19 +24,17 @@ ENTRY(startup_continue) # larl %r14,init_task stg %r14,__LC_CURRENT - larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD-__PT_SIZE + larl %r15,init_thread_union+STACK_INIT_OFFSET + stg %r15,__LC_KERNEL_STACK brasl %r14,sclp_early_adjust_va # allow sclp_early_printk -#ifdef CONFIG_KASAN - brasl %r14,kasan_early_init -#endif brasl %r14,startup_init # s390 specific early init brasl %r14,start_kernel # common init code # # We returned from start_kernel ?!? PANIK # basr %r13,0 - lpswe .Ldw-.(%r13) # load disabled wait psw + lpswe dw_psw-.(%r13) # load disabled wait psw +SYM_CODE_END(startup_continue) .align 16 -.LPG1: -.Ldw: .quad 0x0002000180000000,0x0000000000000000 +SYM_DATA_LOCAL(dw_psw, .quad 0x0002000180000000,0x0000000000000000) diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c index 38e267c7bff7..e7239aaf428b 100644 --- a/arch/s390/kernel/idle.c +++ b/arch/s390/kernel/idle.c @@ -88,7 +88,7 @@ void arch_cpu_idle_exit(void) { } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { cpu_die(); } diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 5f0f5c86963a..f44f70de9661 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -176,11 +176,11 @@ static bool reipl_fcp_clear; static bool reipl_ccw_clear; static bool reipl_eckd_clear; -static inline int __diag308(unsigned long subcode, void *addr) +static inline int __diag308(unsigned long subcode, unsigned long addr) { union register_pair r1; - r1.even = (unsigned long) addr; + r1.even = addr; r1.odd = 0; asm volatile( " diag %[r1],%[subcode],0x308\n" @@ -195,7 +195,7 @@ static inline int __diag308(unsigned long subcode, void *addr) int diag308(unsigned long subcode, void *addr) { diag_stat_inc(DIAG_STAT_X308); - return __diag308(subcode, addr); + return __diag308(subcode, addr ? virt_to_phys(addr) : 0); } EXPORT_SYMBOL_GPL(diag308); @@ -649,7 +649,6 @@ static struct kset *ipl_kset; static void __ipl_run(void *unused) { - __bpon(); diag308(DIAG308_LOAD_CLEAR, NULL); } @@ -1936,14 +1935,13 @@ static struct shutdown_action __refdata dump_action = { static void dump_reipl_run(struct shutdown_trigger *trigger) { - unsigned long ipib = (unsigned long) reipl_block_actual; struct lowcore *abs_lc; unsigned int csum; csum = (__force unsigned int) csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); abs_lc = get_abs_lowcore(); - abs_lc->ipib = ipib; + abs_lc->ipib = __pa(reipl_block_actual); abs_lc->ipib_checksum = csum; put_abs_lowcore(abs_lc); dump_run(trigger); diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 7b41ceecbb25..d4b863ed0aa7 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -41,7 +41,7 @@ void *alloc_insn_page(void) page = module_alloc(PAGE_SIZE); if (!page) return NULL; - __set_memory((unsigned long) page, 1, SET_MEMORY_RO | SET_MEMORY_X); + set_memory_rox((unsigned long)page, 1); return page; } diff --git a/arch/s390/kernel/kprobes_insn_page.S b/arch/s390/kernel/kprobes_insn_page.S index f6cb022ef8c8..b6335296dcd8 100644 --- a/arch/s390/kernel/kprobes_insn_page.S +++ b/arch/s390/kernel/kprobes_insn_page.S @@ -14,9 +14,9 @@ */ .section .kprobes.text, "ax" .align 4096 -ENTRY(kprobes_insn_page) +SYM_CODE_START(kprobes_insn_page) .rept 2048 .word 0x07fe .endr -ENDPROC(kprobes_insn_page) +SYM_CODE_END(kprobes_insn_page) .previous diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 2a8e73266428..6d9276c096a6 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -29,8 +29,8 @@ #include #include -typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long, - unsigned long); +typedef void (*relocate_kernel_t)(unsigned long, unsigned long, unsigned long); +typedef int (*purgatory_t)(int); extern const unsigned char relocate_kernel[]; extern const unsigned long long relocate_kernel_len; @@ -41,11 +41,14 @@ extern const unsigned long long relocate_kernel_len; * Reset the system, copy boot CPU registers to absolute zero, * and jump to the kdump image */ -static void __do_machine_kdump(void *image) +static void __do_machine_kdump(void *data) { - int (*start_kdump)(int); + struct kimage *image = data; + purgatory_t purgatory; unsigned long prefix; + purgatory = (purgatory_t)image->start; + /* store_status() saved the prefix register to lowcore */ prefix = (unsigned long) S390_lowcore.prefixreg_save_area; @@ -58,13 +61,11 @@ static void __do_machine_kdump(void *image) * prefix register of this CPU to zero */ memcpy(absolute_pointer(__LC_FPREGS_SAVE_AREA), - (void *)(prefix + __LC_FPREGS_SAVE_AREA), 512); + phys_to_virt(prefix + __LC_FPREGS_SAVE_AREA), 512); - __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); - start_kdump = (void *)((struct kimage *) image)->start; - start_kdump(1); + call_nodat(1, int, purgatory, int, 1); - /* Die if start_kdump returns */ + /* Die if kdump returns */ disabled_wait(); } @@ -111,18 +112,6 @@ static noinline void __machine_kdump(void *image) store_status(__do_machine_kdump, image); } -static unsigned long do_start_kdump(unsigned long addr) -{ - struct kimage *image = (struct kimage *) addr; - int (*start_kdump)(int) = (void *)image->start; - int rc; - - __arch_local_irq_stnsm(0xfb); /* disable DAT */ - rc = start_kdump(0); - __arch_local_irq_stosm(0x04); /* enable DAT */ - return rc; -} - #endif /* CONFIG_CRASH_DUMP */ /* @@ -131,12 +120,10 @@ static unsigned long do_start_kdump(unsigned long addr) static bool kdump_csum_valid(struct kimage *image) { #ifdef CONFIG_CRASH_DUMP + purgatory_t purgatory = (purgatory_t)image->start; int rc; - preempt_disable(); - rc = call_on_stack(1, S390_lowcore.nodat_stack, unsigned long, do_start_kdump, - unsigned long, (unsigned long)image); - preempt_enable(); + rc = call_nodat(1, int, purgatory, int, 0); return rc == 0; #else return false; @@ -210,7 +197,7 @@ int machine_kexec_prepare(struct kimage *image) return -EINVAL; /* Get the destination where the assembler code should be copied to.*/ - reboot_code_buffer = (void *) page_to_phys(image->control_code_page); + reboot_code_buffer = page_to_virt(image->control_code_page); /* Then copy it */ memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); @@ -250,19 +237,20 @@ void machine_crash_shutdown(struct pt_regs *regs) */ static void __do_machine_kexec(void *data) { - unsigned long diag308_subcode; - relocate_kernel_t data_mover; + unsigned long data_mover, entry, diag308_subcode; struct kimage *image = data; - s390_reset_system(); - data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); - - __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */ - /* Call the moving routine */ + data_mover = page_to_phys(image->control_code_page); + entry = virt_to_phys(&image->head); diag308_subcode = DIAG308_CLEAR_RESET; if (sclp.has_iplcc) diag308_subcode |= DIAG308_FLAG_EI; - (*data_mover)(&image->head, image->start, diag308_subcode); + s390_reset_system(); + + call_nodat(3, void, (relocate_kernel_t)data_mover, + unsigned long, entry, + unsigned long, image->start, + unsigned long, diag308_subcode); /* Die if kexec returns */ disabled_wait(); diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 6c10da43b538..dbece2803c50 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -28,9 +28,9 @@ .section .kprobes.text, "ax" -ENTRY(ftrace_stub) +SYM_FUNC_START(ftrace_stub) BR_EX %r14 -ENDPROC(ftrace_stub) +SYM_FUNC_END(ftrace_stub) SYM_CODE_START(ftrace_stub_direct_tramp) lgr %r1, %r0 @@ -140,10 +140,25 @@ SYM_FUNC_END(return_to_handler) #endif #endif /* CONFIG_FUNCTION_TRACER */ +SYM_CODE_START(ftrace_shared_hotpatch_trampoline_br) + lmg %r0,%r1,2(%r1) + br %r1 +SYM_INNER_LABEL(ftrace_shared_hotpatch_trampoline_br_end, SYM_L_GLOBAL) +SYM_CODE_END(ftrace_shared_hotpatch_trampoline_br) + +#ifdef CONFIG_EXPOLINE +SYM_CODE_START(ftrace_shared_hotpatch_trampoline_exrl) + lmg %r0,%r1,2(%r1) + exrl %r0,0f + j . +0: br %r1 +SYM_INNER_LABEL(ftrace_shared_hotpatch_trampoline_exrl_end, SYM_L_GLOBAL) +SYM_CODE_END(ftrace_shared_hotpatch_trampoline_exrl) +#endif /* CONFIG_EXPOLINE */ + #ifdef CONFIG_RETHOOK -SYM_FUNC_START(arch_rethook_trampoline) - +SYM_CODE_START(arch_rethook_trampoline) stg %r14,(__SF_GPRS+8*8)(%r15) lay %r15,-STACK_FRAME_SIZE(%r15) stmg %r0,%r14,STACK_PTREGS_GPRS(%r15) @@ -166,7 +181,6 @@ SYM_FUNC_START(arch_rethook_trampoline) mvc __SF_EMPTY(16,%r7),STACK_PTREGS_PSW(%r15) lmg %r0,%r15,STACK_PTREGS_GPRS(%r15) lpswe __SF_EMPTY(%r15) - -SYM_FUNC_END(arch_rethook_trampoline) +SYM_CODE_END(arch_rethook_trampoline) #endif /* CONFIG_RETHOOK */ diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 2d159b32885b..f1b35dcdf3eb 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -26,6 +26,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -35,6 +36,24 @@ #define PLT_ENTRY_SIZE 22 +static unsigned long get_module_load_offset(void) +{ + static DEFINE_MUTEX(module_kaslr_mutex); + static unsigned long module_load_offset; + + if (!kaslr_enabled()) + return 0; + /* + * Calculate the module_load_offset the first time this code + * is called. Once calculated it stays the same until reboot. + */ + mutex_lock(&module_kaslr_mutex); + if (!module_load_offset) + module_load_offset = get_random_u32_inclusive(1, 1024) * PAGE_SIZE; + mutex_unlock(&module_kaslr_mutex); + return module_load_offset; +} + void *module_alloc(unsigned long size) { gfp_t gfp_mask = GFP_KERNEL; @@ -42,9 +61,11 @@ void *module_alloc(unsigned long size) if (PAGE_ALIGN(size) > MODULES_LEN) return NULL; - p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_END, - gfp_mask, PAGE_KERNEL_EXEC, VM_DEFER_KMEMLEAK, NUMA_NO_NODE, - __builtin_return_address(0)); + p = __vmalloc_node_range(size, MODULE_ALIGN, + MODULES_VADDR + get_module_load_offset(), + MODULES_END, gfp_mask, PAGE_KERNEL, + VM_FLUSH_RESET_PERMS | VM_DEFER_KMEMLEAK, + NUMA_NO_NODE, __builtin_return_address(0)); if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) { vfree(p); return NULL; @@ -126,6 +147,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, Elf_Rela *rela; char *strings; int nrela, i, j; + struct module_memory *mod_mem; /* Find symbol table and string table. */ symtab = NULL; @@ -173,14 +195,15 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, /* Increase core size by size of got & plt and set start offsets for got and plt. */ - me->core_layout.size = ALIGN(me->core_layout.size, 4); - me->arch.got_offset = me->core_layout.size; - me->core_layout.size += me->arch.got_size; - me->arch.plt_offset = me->core_layout.size; + mod_mem = &me->mem[MOD_TEXT]; + mod_mem->size = ALIGN(mod_mem->size, 4); + me->arch.got_offset = mod_mem->size; + mod_mem->size += me->arch.got_size; + me->arch.plt_offset = mod_mem->size; if (me->arch.plt_size) { if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) me->arch.plt_size += PLT_ENTRY_SIZE; - me->core_layout.size += me->arch.plt_size; + mod_mem->size += me->arch.plt_size; } return 0; } @@ -304,7 +327,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, case R_390_GOTPLT64: /* 64 bit offset to jump slot. */ case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */ if (info->got_initialized == 0) { - Elf_Addr *gotent = me->core_layout.base + + Elf_Addr *gotent = me->mem[MOD_TEXT].base + me->arch.got_offset + info->got_offset; @@ -329,7 +352,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, rc = apply_rela_bits(loc, val, 0, 64, 0, write); else if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) { - val += (Elf_Addr) me->core_layout.base - loc; + val += (Elf_Addr) me->mem[MOD_TEXT].base - loc; rc = apply_rela_bits(loc, val, 1, 32, 1, write); } break; @@ -345,7 +368,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, char *plt_base; char *ip; - plt_base = me->core_layout.base + me->arch.plt_offset; + plt_base = me->mem[MOD_TEXT].base + me->arch.plt_offset; ip = plt_base + info->plt_offset; *(int *)insn = 0x0d10e310; /* basr 1,0 */ *(int *)&insn[4] = 0x100c0004; /* lg 1,12(1) */ @@ -375,7 +398,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, val - loc + 0xffffUL < 0x1ffffeUL) || (r_type == R_390_PLT32DBL && val - loc + 0xffffffffULL < 0x1fffffffeULL))) - val = (Elf_Addr) me->core_layout.base + + val = (Elf_Addr) me->mem[MOD_TEXT].base + me->arch.plt_offset + info->plt_offset; val += rela->r_addend - loc; @@ -397,7 +420,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF64: /* 64 bit offset to GOT. */ val = val + rela->r_addend - - ((Elf_Addr) me->core_layout.base + me->arch.got_offset); + ((Elf_Addr) me->mem[MOD_TEXT].base + me->arch.got_offset); if (r_type == R_390_GOTOFF16) rc = apply_rela_bits(loc, val, 0, 16, 0, write); else if (r_type == R_390_GOTOFF32) @@ -407,7 +430,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, break; case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ - val = (Elf_Addr) me->core_layout.base + me->arch.got_offset + + val = (Elf_Addr) me->mem[MOD_TEXT].base + me->arch.got_offset + rela->r_addend - loc; if (r_type == R_390_GOTPC) rc = apply_rela_bits(loc, val, 1, 32, 0, write); @@ -489,7 +512,7 @@ static int module_alloc_ftrace_hotpatch_trampolines(struct module *me, start = module_alloc(numpages * PAGE_SIZE); if (!start) return -ENOMEM; - set_memory_ro((unsigned long)start, numpages); + set_memory_rox((unsigned long)start, numpages); end = start + size; me->arch.trampolines_start = (struct ftrace_hotpatch_trampoline *)start; @@ -515,7 +538,7 @@ int module_finalize(const Elf_Ehdr *hdr, !nospec_disable && me->arch.plt_size) { unsigned int *ij; - ij = me->core_layout.base + me->arch.plt_offset + + ij = me->mem[MOD_TEXT].base + me->arch.plt_offset + me->arch.plt_size - PLT_ENTRY_SIZE; ij[0] = 0xc6000000; /* exrl %r0,.+10 */ ij[1] = 0x0005a7f4; /* j . */ diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index c9ab971498d6..cf1b6e8a708d 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -76,7 +76,6 @@ static inline int ctr_stcctm(enum cpumf_ctr_set set, u64 range, u64 *dest) } struct cpu_cf_events { - struct cpumf_ctr_info info; atomic_t ctr_set[CPUMF_CTR_SET_MAX]; u64 state; /* For perf_event_open SVC */ u64 dev_state; /* For /dev/hwctr */ @@ -95,6 +94,15 @@ static DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events); static unsigned int cfdiag_cpu_speed; /* CPU speed for CF_DIAG trailer */ static debug_info_t *cf_dbg; +/* + * The CPU Measurement query counter information instruction contains + * information which varies per machine generation, but is constant and + * does not change when running on a particular machine, such as counter + * first and second version number. This is needed to determine the size + * of counter sets. Extract this information at device driver initialization. + */ +static struct cpumf_ctr_info cpumf_ctr_info; + #define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ /* interval in seconds */ @@ -167,11 +175,10 @@ struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */ /* Create the trailer data at the end of a page. */ static void cfdiag_trailer(struct cf_trailer_entry *te) { - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct cpuid cpuid; - te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */ - te->csvn = cpuhw->info.csvn; + te->cfvn = cpumf_ctr_info.cfvn; /* Counter version numbers */ + te->csvn = cpumf_ctr_info.csvn; get_cpu_id(&cpuid); /* Machine type */ te->mach_type = cpuid.machine; @@ -184,50 +191,60 @@ static void cfdiag_trailer(struct cf_trailer_entry *te) } /* - * Return the maximum possible counter set size (in number of 8 byte counters) - * depending on type and model number. + * The number of counters per counter set varies between machine generations, + * but is constant when running on a particular machine generation. + * Determine each counter set size at device driver initialization and + * retrieve it later. */ -static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset, - struct cpumf_ctr_info *info) +static size_t cpumf_ctr_setsizes[CPUMF_CTR_SET_MAX]; +static void cpum_cf_make_setsize(enum cpumf_ctr_set ctrset) { size_t ctrset_size = 0; switch (ctrset) { case CPUMF_CTR_SET_BASIC: - if (info->cfvn >= 1) + if (cpumf_ctr_info.cfvn >= 1) ctrset_size = 6; break; case CPUMF_CTR_SET_USER: - if (info->cfvn == 1) + if (cpumf_ctr_info.cfvn == 1) ctrset_size = 6; - else if (info->cfvn >= 3) + else if (cpumf_ctr_info.cfvn >= 3) ctrset_size = 2; break; case CPUMF_CTR_SET_CRYPTO: - if (info->csvn >= 1 && info->csvn <= 5) + if (cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5) ctrset_size = 16; - else if (info->csvn == 6 || info->csvn == 7) + else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7) ctrset_size = 20; break; case CPUMF_CTR_SET_EXT: - if (info->csvn == 1) + if (cpumf_ctr_info.csvn == 1) ctrset_size = 32; - else if (info->csvn == 2) + else if (cpumf_ctr_info.csvn == 2) ctrset_size = 48; - else if (info->csvn >= 3 && info->csvn <= 5) + else if (cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5) ctrset_size = 128; - else if (info->csvn == 6 || info->csvn == 7) + else if (cpumf_ctr_info.csvn == 6 || cpumf_ctr_info.csvn == 7) ctrset_size = 160; break; case CPUMF_CTR_SET_MT_DIAG: - if (info->csvn > 3) + if (cpumf_ctr_info.csvn > 3) ctrset_size = 48; break; case CPUMF_CTR_SET_MAX: break; } + cpumf_ctr_setsizes[ctrset] = ctrset_size; +} - return ctrset_size; +/* + * Return the maximum possible counter set size (in number of 8 byte counters) + * depending on type and model number. + */ +static size_t cpum_cf_read_setsize(enum cpumf_ctr_set ctrset) +{ + return cpumf_ctr_setsizes[ctrset]; } /* Read a counter set. The counter set number determines the counter set and @@ -248,14 +265,13 @@ static size_t cpum_cf_ctrset_size(enum cpumf_ctr_set ctrset, static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, size_t room, bool error_ok) { - struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); size_t ctrset_size, need = 0; int rc = 3; /* Assume write failure */ ctrdata->def = CF_DIAG_CTRSET_DEF; ctrdata->set = ctrset; ctrdata->res1 = 0; - ctrset_size = cpum_cf_ctrset_size(ctrset, &cpuhw->info); + ctrset_size = cpum_cf_read_setsize(ctrset); if (ctrset_size) { /* Save data */ need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); @@ -269,10 +285,6 @@ static size_t cfdiag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, need = 0; } - debug_sprintf_event(cf_dbg, 3, - "%s ctrset %d ctrset_size %zu cfvn %d csvn %d" - " need %zd rc %d\n", __func__, ctrset, ctrset_size, - cpuhw->info.cfvn, cpuhw->info.csvn, need, rc); return need; } @@ -377,40 +389,35 @@ static enum cpumf_ctr_set get_counter_set(u64 event) return set; } -static int validate_ctr_version(const struct hw_perf_event *hwc, - enum cpumf_ctr_set set) +static int validate_ctr_version(const u64 config, enum cpumf_ctr_set set) { - struct cpu_cf_events *cpuhw; - int err = 0; u16 mtdiag_ctl; - - cpuhw = &get_cpu_var(cpu_cf_events); + int err = 0; /* check required version for counter sets */ switch (set) { case CPUMF_CTR_SET_BASIC: case CPUMF_CTR_SET_USER: - if (cpuhw->info.cfvn < 1) + if (cpumf_ctr_info.cfvn < 1) err = -EOPNOTSUPP; break; case CPUMF_CTR_SET_CRYPTO: - if ((cpuhw->info.csvn >= 1 && cpuhw->info.csvn <= 5 && - hwc->config > 79) || - (cpuhw->info.csvn >= 6 && hwc->config > 83)) + if ((cpumf_ctr_info.csvn >= 1 && cpumf_ctr_info.csvn <= 5 && + config > 79) || (cpumf_ctr_info.csvn >= 6 && config > 83)) err = -EOPNOTSUPP; break; case CPUMF_CTR_SET_EXT: - if (cpuhw->info.csvn < 1) + if (cpumf_ctr_info.csvn < 1) err = -EOPNOTSUPP; - if ((cpuhw->info.csvn == 1 && hwc->config > 159) || - (cpuhw->info.csvn == 2 && hwc->config > 175) || - (cpuhw->info.csvn >= 3 && cpuhw->info.csvn <= 5 - && hwc->config > 255) || - (cpuhw->info.csvn >= 6 && hwc->config > 287)) + if ((cpumf_ctr_info.csvn == 1 && config > 159) || + (cpumf_ctr_info.csvn == 2 && config > 175) || + (cpumf_ctr_info.csvn >= 3 && cpumf_ctr_info.csvn <= 5 && + config > 255) || + (cpumf_ctr_info.csvn >= 6 && config > 287)) err = -EOPNOTSUPP; break; case CPUMF_CTR_SET_MT_DIAG: - if (cpuhw->info.csvn <= 3) + if (cpumf_ctr_info.csvn <= 3) err = -EOPNOTSUPP; /* * MT-diagnostic counters are read-only. The counter set @@ -425,35 +432,15 @@ static int validate_ctr_version(const struct hw_perf_event *hwc, * counter set is enabled and active. */ mtdiag_ctl = cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG]; - if (!((cpuhw->info.auth_ctl & mtdiag_ctl) && - (cpuhw->info.enable_ctl & mtdiag_ctl) && - (cpuhw->info.act_ctl & mtdiag_ctl))) + if (!((cpumf_ctr_info.auth_ctl & mtdiag_ctl) && + (cpumf_ctr_info.enable_ctl & mtdiag_ctl) && + (cpumf_ctr_info.act_ctl & mtdiag_ctl))) err = -EOPNOTSUPP; break; case CPUMF_CTR_SET_MAX: err = -EOPNOTSUPP; } - put_cpu_var(cpu_cf_events); - return err; -} - -static int validate_ctr_auth(const struct hw_perf_event *hwc) -{ - struct cpu_cf_events *cpuhw; - int err = 0; - - cpuhw = &get_cpu_var(cpu_cf_events); - - /* Check authorization for cpu counter sets. - * If the particular CPU counter set is not authorized, - * return with -ENOENT in order to fall back to other - * PMUs that might suffice the event request. - */ - if (!(hwc->config_base & cpuhw->info.auth_ctl)) - err = -ENOENT; - - put_cpu_var(cpu_cf_events); return err; } @@ -471,13 +458,10 @@ static void cpumf_pmu_enable(struct pmu *pmu) return; err = lcctl(cpuhw->state | cpuhw->dev_state); - if (err) { - pr_err("Enabling the performance measuring unit " - "failed with rc=%x\n", err); - return; - } - - cpuhw->flags |= PMU_F_ENABLED; + if (err) + pr_err("Enabling the performance measuring unit failed with rc=%x\n", err); + else + cpuhw->flags |= PMU_F_ENABLED; } /* @@ -497,13 +481,10 @@ static void cpumf_pmu_disable(struct pmu *pmu) inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); inactive |= cpuhw->dev_state; err = lcctl(inactive); - if (err) { - pr_err("Disabling the performance measuring unit " - "failed with rc=%x\n", err); - return; - } - - cpuhw->flags &= ~PMU_F_ENABLED; + if (err) + pr_err("Disabling the performance measuring unit failed with rc=%x\n", err); + else + cpuhw->flags &= ~PMU_F_ENABLED; } #define PMC_INIT 0UL @@ -515,8 +496,6 @@ static void cpum_cf_setup_cpu(void *flags) switch ((unsigned long)flags) { case PMC_INIT: - memset(&cpuhw->info, 0, sizeof(cpuhw->info)); - qctri(&cpuhw->info); cpuhw->flags |= PMU_F_RESERVED; break; @@ -602,7 +581,6 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) struct perf_event_attr *attr = &event->attr; struct hw_perf_event *hwc = &event->hw; enum cpumf_ctr_set set; - int err = 0; u64 ev; switch (type) { @@ -678,12 +656,15 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) cpumf_hw_inuse(); event->destroy = hw_perf_event_destroy; - /* Finally, validate version and authorization of the counter set */ - err = validate_ctr_auth(hwc); - if (!err) - err = validate_ctr_version(hwc, set); - - return err; + /* + * Finally, validate version and authorization of the counter set. + * If the particular CPU counter set is not authorized, + * return with -ENOENT in order to fall back to other + * PMUs that might suffice the event request. + */ + if (!(hwc->config_base & cpumf_ctr_info.auth_ctl)) + return -ENOENT; + return validate_ctr_version(hwc->config, set); } /* Events CPU_CYLCES and INSTRUCTIONS can be submitted with two different @@ -983,7 +964,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, /* counter authorization change alert */ if (alert & CPU_MF_INT_CF_CACA) - qctri(&cpuhw->info); + qctri(&cpumf_ctr_info); /* loss of counter data alert */ if (alert & CPU_MF_INT_CF_LCDA) @@ -1000,9 +981,14 @@ static int __init cpumf_pmu_init(void) { int rc; - if (!cpum_cf_avail()) + /* Extract counter measurement facility information */ + if (!cpum_cf_avail() || qctri(&cpumf_ctr_info)) return -ENODEV; + /* Determine and store counter set sizes for later reference */ + for (rc = CPUMF_CTR_SET_BASIC; rc < CPUMF_CTR_SET_MAX; ++rc) + cpum_cf_make_setsize(rc); + /* * Clear bit 15 of cr0 to unauthorize problem-state to * extract measurement counters @@ -1269,28 +1255,26 @@ static int cfset_all_start(struct cfset_request *req) */ static size_t cfset_needspace(unsigned int sets) { - struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events); size_t bytes = 0; int i; for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { if (!(sets & cpumf_ctr_ctl[i])) continue; - bytes += cpum_cf_ctrset_size(i, &cpuhw->info) * sizeof(u64) + + bytes += cpum_cf_read_setsize(i) * sizeof(u64) + sizeof(((struct s390_ctrset_setdata *)0)->set) + sizeof(((struct s390_ctrset_setdata *)0)->no_cnts); } bytes = sizeof(((struct s390_ctrset_read *)0)->no_cpus) + nr_cpu_ids * (bytes + sizeof(((struct s390_ctrset_cpudata *)0)->cpu_nr) + sizeof(((struct s390_ctrset_cpudata *)0)->no_sets)); - put_cpu_ptr(&cpu_cf_events); return bytes; } static int cfset_all_copy(unsigned long arg, cpumask_t *mask) { struct s390_ctrset_read __user *ctrset_read; - unsigned int cpu, cpus, rc; + unsigned int cpu, cpus, rc = 0; void __user *uptr; ctrset_read = (struct s390_ctrset_read __user *)arg; @@ -1304,17 +1288,20 @@ static int cfset_all_copy(unsigned long arg, cpumask_t *mask) rc |= put_user(cpuhw->sets, &ctrset_cpudata->no_sets); rc |= copy_to_user(ctrset_cpudata->data, cpuhw->data, cpuhw->used); - if (rc) - return -EFAULT; + if (rc) { + rc = -EFAULT; + goto out; + } uptr += sizeof(struct s390_ctrset_cpudata) + cpuhw->used; cond_resched(); } cpus = cpumask_weight(mask); if (put_user(cpus, &ctrset_read->no_cpus)) - return -EFAULT; - debug_sprintf_event(cf_dbg, 4, "%s copied %ld\n", __func__, + rc = -EFAULT; +out: + debug_sprintf_event(cf_dbg, 4, "%s rc %d copied %ld\n", __func__, rc, uptr - (void __user *)ctrset_read->data); - return 0; + return rc; } static size_t cfset_cpuset_read(struct s390_ctrset_setdata *p, int ctrset, @@ -1354,7 +1341,7 @@ static void cfset_cpu_read(void *parm) if (!(p->sets & cpumf_ctr_ctl[set])) continue; /* Counter set not in list */ - set_size = cpum_cf_ctrset_size(set, &cpuhw->info); + set_size = cpum_cf_read_setsize(set); space = sizeof(cpuhw->data) - cpuhw->used; space = cfset_cpuset_read(sp, set, set_size, space); if (space) { @@ -1385,14 +1372,10 @@ static int cfset_all_read(unsigned long arg, struct cfset_request *req) static long cfset_ioctl_read(unsigned long arg, struct cfset_request *req) { - struct s390_ctrset_read read; int ret = -ENODATA; - if (req && req->ctrset) { - if (copy_from_user(&read, (char __user *)arg, sizeof(read))) - return -EFAULT; + if (req && req->ctrset) ret = cfset_all_read(arg, req); - } return ret; } @@ -1569,16 +1552,13 @@ static void cfdiag_read(struct perf_event *event) static int get_authctrsets(void) { - struct cpu_cf_events *cpuhw; unsigned long auth = 0; enum cpumf_ctr_set i; - cpuhw = &get_cpu_var(cpu_cf_events); for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) + if (cpumf_ctr_info.auth_ctl & cpumf_ctr_ctl[i]) auth |= cpumf_ctr_ctl[i]; } - put_cpu_var(cpu_cf_events); return auth; } @@ -1716,7 +1696,7 @@ static size_t cfdiag_maxsize(struct cpumf_ctr_info *info) enum cpumf_ctr_set i; for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { - size_t size = cpum_cf_ctrset_size(i, info); + size_t size = cpum_cf_read_setsize(i); if (size) max_size += size * sizeof(u64) + @@ -1750,16 +1730,12 @@ static void cfdiag_get_cpu_speed(void) static int cfset_init(void) { - struct cpumf_ctr_info info; size_t need; int rc; - if (qctri(&info)) - return -ENODEV; - cfdiag_get_cpu_speed(); /* Make sure the counter set data fits into predefined buffer. */ - need = cfdiag_maxsize(&info); + need = cfdiag_maxsize(&cpumf_ctr_info); if (need > sizeof(((struct cpu_cf_events *)0)->start)) { pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", need); diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index e7b867e2f73f..7ef72f5ff52e 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -882,10 +882,6 @@ static int __hw_perf_event_init(struct perf_event *event) SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_DIAG_MODE; } - /* Check and set other sampling flags */ - if (attr->config1 & PERF_CPUM_SF_FULL_BLOCKS) - SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_FULL_BLOCKS; - err = __hw_perf_event_init_rate(event, &si); if (err) goto out; @@ -1293,11 +1289,8 @@ static inline __uint128_t __cdsg(__uint128_t *ptr, __uint128_t old, __uint128_t * The sampling buffer position are retrieved and saved in the TEAR_REG * register of the specified perf event. * - * Only full sample-data-blocks are processed. Specify the flash_all flag - * to also walk through partially filled sample-data-blocks. It is ignored - * if PERF_CPUM_SF_FULL_BLOCKS is set. The PERF_CPUM_SF_FULL_BLOCKS flag - * enforces the processing of full sample-data-blocks only (trailer entries - * with the block-full-indicator bit set). + * Only full sample-data-blocks are processed. Specify the flush_all flag + * to also walk through partially filled sample-data-blocks. */ static void hw_perf_event_update(struct perf_event *event, int flush_all) { @@ -1315,9 +1308,6 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) if (SAMPL_DIAG_MODE(&event->hw)) return; - if (flush_all && SDB_FULL_BLOCKS(hwc)) - flush_all = 0; - sdbt = (unsigned long *) TEAR_REG(hwc); done = event_overflow = sampl_overflow = num_sdb = 0; while (!done) { diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 67df64ef4839..87ca3a727604 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -136,12 +136,12 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) p->thread.last_break = 1; frame->sf.back_chain = 0; - frame->sf.gprs[5] = (unsigned long)frame + sizeof(struct stack_frame); - frame->sf.gprs[6] = (unsigned long)p; + frame->sf.gprs[11 - 6] = (unsigned long)&frame->childregs; + frame->sf.gprs[12 - 6] = (unsigned long)p; /* new return point is ret_from_fork */ - frame->sf.gprs[8] = (unsigned long)ret_from_fork; + frame->sf.gprs[14 - 6] = (unsigned long)ret_from_fork; /* fake return stack for resume(), don't go back to schedule */ - frame->sf.gprs[9] = (unsigned long)frame; + frame->sf.gprs[15 - 6] = (unsigned long)frame; /* Store access registers to kernel stack of new process. */ if (unlikely(args->fn)) { @@ -149,8 +149,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) memset(&frame->childregs, 0, sizeof(struct pt_regs)); frame->childregs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; - frame->childregs.psw.addr = - (unsigned long)__ret_from_fork; frame->childregs.gprs[9] = (unsigned long)args->fn; frame->childregs.gprs[10] = (unsigned long)args->fn_arg; frame->childregs.orig_gpr2 = -1; diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index a194611ba88c..0a999c8226d7 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -364,21 +364,3 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; - -int s390_isolate_bp(void) -{ - if (!test_facility(82)) - return -EOPNOTSUPP; - set_thread_flag(TIF_ISOLATE_BP); - return 0; -} -EXPORT_SYMBOL(s390_isolate_bp); - -int s390_isolate_bp_guest(void) -{ - if (!test_facility(82)) - return -EOPNOTSUPP; - set_thread_flag(TIF_ISOLATE_BP_GUEST); - return 0; -} -EXPORT_SYMBOL(s390_isolate_bp_guest); diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 4a22163962eb..88087a32ebc6 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -19,7 +19,7 @@ # r2 = Function to be called after store status # r3 = Parameter for function # -ENTRY(store_status) +SYM_CODE_START(store_status) /* Save register one and load save area base */ stg %r1,__LC_SAVE_AREA_RESTART /* General purpose registers */ @@ -61,7 +61,7 @@ ENTRY(store_status) stpx 0(%r1) /* Clock comparator - seven bytes */ lghi %r1,__LC_CLOCK_COMP_SAVE_AREA - larl %r4,.Lclkcmp + larl %r4,clkcmp stckc 0(%r4) mvc 1(7,%r1),1(%r4) /* Program status word */ @@ -73,9 +73,9 @@ ENTRY(store_status) lgr %r9,%r2 lgr %r2,%r3 BR_EX %r9 -ENDPROC(store_status) +SYM_CODE_END(store_status) .section .bss - .align 8 -.Lclkcmp: .quad 0x0000000000000000 + .balign 8 +SYM_DATA_LOCAL(clkcmp, .quad 0x0000000000000000) .previous diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index a9a1a6f45375..0ae297c82afd 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S @@ -26,53 +26,51 @@ */ .text -ENTRY(relocate_kernel) - basr %r13,0 # base address - .base: - lghi %r7,PAGE_SIZE # load PAGE_SIZE in r7 - lghi %r9,PAGE_SIZE # load PAGE_SIZE in r9 - lg %r5,0(%r2) # read another word for indirection page - aghi %r2,8 # increment pointer - tml %r5,0x1 # is it a destination page? - je .indir_check # NO, goto "indir_check" - lgr %r6,%r5 # r6 = r5 - nill %r6,0xf000 # mask it out and... - j .base # ...next iteration - .indir_check: - tml %r5,0x2 # is it a indirection page? - je .done_test # NO, goto "done_test" - nill %r5,0xf000 # YES, mask out, - lgr %r2,%r5 # move it into the right register, - j .base # and read next... - .done_test: - tml %r5,0x4 # is it the done indicator? - je .source_test # NO! Well, then it should be the source indicator... - j .done # ok, lets finish it here... - .source_test: - tml %r5,0x8 # it should be a source indicator... - je .base # NO, ignore it... - lgr %r8,%r5 # r8 = r5 - nill %r8,0xf000 # masking - 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 - jo 0b - j .base - .done: - lgr %r0,%r4 # subcode - cghi %r3,0 - je .diag - la %r4,load_psw-.base(%r13) # load psw-address into the register - o %r3,4(%r4) # or load address into psw - st %r3,4(%r4) - mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 - .diag: - diag %r0,%r0,0x308 -ENDPROC(relocate_kernel) +SYM_CODE_START(relocate_kernel) + basr %r13,0 # base address +.base: + lghi %r7,PAGE_SIZE # load PAGE_SIZE in r7 + lghi %r9,PAGE_SIZE # load PAGE_SIZE in r9 + lg %r5,0(%r2) # read another word for indirection page + aghi %r2,8 # increment pointer + tml %r5,0x1 # is it a destination page? + je .indir_check # NO, goto "indir_check" + lgr %r6,%r5 # r6 = r5 + nill %r6,0xf000 # mask it out and... + j .base # ...next iteration +.indir_check: + tml %r5,0x2 # is it a indirection page? + je .done_test # NO, goto "done_test" + nill %r5,0xf000 # YES, mask out, + lgr %r2,%r5 # move it into the right register, + j .base # and read next... +.done_test: + tml %r5,0x4 # is it the done indicator? + je .source_test # NO! Well, then it should be the source indicator... + j .done # ok, lets finish it here... +.source_test: + tml %r5,0x8 # it should be a source indicator... + je .base # NO, ignore it... + lgr %r8,%r5 # r8 = r5 + nill %r8,0xf000 # masking +0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 + jo 0b + j .base +.done: + lgr %r0,%r4 # subcode + cghi %r3,0 + je .diag + la %r4,load_psw-.base(%r13) # load psw-address into the register + o %r3,4(%r4) # or load address into psw + st %r3,4(%r4) + mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 +.diag: + diag %r0,%r0,0x308 +SYM_CODE_END(relocate_kernel) - .align 8 - load_psw: - .long 0x00080000,0x80000000 - relocate_kernel_end: - .align 8 - .globl relocate_kernel_len - relocate_kernel_len: - .quad relocate_kernel_end - relocate_kernel + .balign 8 +SYM_DATA_START_LOCAL(load_psw) + .long 0x00080000,0x80000000 +SYM_DATA_END_LABEL(load_psw, SYM_L_LOCAL, relocate_kernel_end) + .balign 8 +SYM_DATA(relocate_kernel_len, .quad relocate_kernel_end - relocate_kernel) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 8ec5cdf9dadc..fe10da1a271e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -74,7 +74,7 @@ #include #include #include -#include +#include #include #include #include @@ -147,14 +147,10 @@ static u32 __amode31_ref *__ctl_duct = __ctl_duct_amode31; int __bootdata(noexec_disabled); unsigned long __bootdata(ident_map_size); -struct mem_detect_info __bootdata(mem_detect); -struct initrd_data __bootdata(initrd_data); -unsigned long __bootdata(pgalloc_pos); -unsigned long __bootdata(pgalloc_end); -unsigned long __bootdata(pgalloc_low); +struct physmem_info __bootdata(physmem_info); unsigned long __bootdata_preserved(__kaslr_offset); -unsigned long __bootdata(__amode31_base); +int __bootdata_preserved(__kaslr_enabled); unsigned int __bootdata_preserved(zlib_dfltcc_support); EXPORT_SYMBOL(zlib_dfltcc_support); u64 __bootdata_preserved(stfle_fac_list[16]); @@ -385,39 +381,27 @@ void stack_free(unsigned long stack) #endif } -int __init arch_early_irq_init(void) +void __init __noreturn arch_call_rest_init(void) { - unsigned long stack; - - stack = __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); - if (!stack) - panic("Couldn't allocate async stack"); - S390_lowcore.async_stack = stack + STACK_INIT_OFFSET; - return 0; + smp_reinit_ipl_cpu(); + rest_init(); } -void __init arch_call_rest_init(void) +static unsigned long __init stack_alloc_early(void) { unsigned long stack; - smp_reinit_ipl_cpu(); - stack = stack_alloc(); - if (!stack) - panic("Couldn't allocate kernel stack"); - current->stack = (void *) stack; -#ifdef CONFIG_VMAP_STACK - current->stack_vm_area = (void *) stack; -#endif - set_task_stack_end_magic(current); - stack += STACK_INIT_OFFSET; - S390_lowcore.kernel_stack = stack; - call_on_stack_noreturn(rest_init, stack); + stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE); + if (!stack) { + panic("%s: Failed to allocate %lu bytes align=0x%lx\n", + __func__, THREAD_SIZE, THREAD_SIZE); + } + return stack; } static void __init setup_lowcore(void) { struct lowcore *lc, *abs_lc; - unsigned long mcck_stack; /* * Setup lowcore for boot cpu @@ -441,8 +425,6 @@ static void __init setup_lowcore(void) lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; lc->io_new_psw.addr = (unsigned long) io_int_handler; lc->clock_comparator = clock_comparator_max; - lc->nodat_stack = ((unsigned long) &init_thread_union) - + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); lc->current_task = (unsigned long)&init_task; lc->lpp = LPP_MAGIC; lc->machine_flags = S390_lowcore.machine_flags; @@ -455,17 +437,15 @@ static void __init setup_lowcore(void) lc->steal_timer = S390_lowcore.steal_timer; lc->last_update_timer = S390_lowcore.last_update_timer; lc->last_update_clock = S390_lowcore.last_update_clock; - /* * Allocate the global restart stack which is the same for - * all CPUs in cast *one* of them does a PSW restart. + * all CPUs in case *one* of them does a PSW restart. */ - restart_stack = memblock_alloc(THREAD_SIZE, THREAD_SIZE); - if (!restart_stack) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, THREAD_SIZE, THREAD_SIZE); - restart_stack += STACK_INIT_OFFSET; - + restart_stack = (void *)(stack_alloc_early() + STACK_INIT_OFFSET); + lc->mcck_stack = stack_alloc_early() + STACK_INIT_OFFSET; + lc->async_stack = stack_alloc_early() + STACK_INIT_OFFSET; + lc->nodat_stack = stack_alloc_early() + STACK_INIT_OFFSET; + lc->kernel_stack = S390_lowcore.kernel_stack; /* * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant * restart data to the absolute zero lowcore. This is necessary if @@ -476,13 +456,6 @@ static void __init setup_lowcore(void) lc->restart_data = 0; lc->restart_source = -1U; __ctl_store(lc->cregs_save_area, 0, 15); - - mcck_stack = (unsigned long)memblock_alloc(THREAD_SIZE, THREAD_SIZE); - if (!mcck_stack) - panic("%s: Failed to allocate %lu bytes align=0x%lx\n", - __func__, THREAD_SIZE, THREAD_SIZE); - lc->mcck_stack = mcck_stack + STACK_INIT_OFFSET; - lc->spinlock_lockval = arch_spin_lockval(0); lc->spinlock_index = 0; arch_spin_lock_setup(0); @@ -635,7 +608,11 @@ static struct notifier_block kdump_mem_nb = { */ static void __init reserve_pgtables(void) { - memblock_reserve(pgalloc_pos, pgalloc_end - pgalloc_pos); + unsigned long start, end; + struct reserved_range *range; + + for_each_physmem_reserved_type_range(RR_VMEM, range, &start, &end) + memblock_reserve(start, end - start); } /* @@ -712,13 +689,13 @@ static void __init reserve_crashkernel(void) */ static void __init reserve_initrd(void) { -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_data.start || !initrd_data.size) + unsigned long addr, size; + + if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || !get_physmem_reserved(RR_INITRD, &addr, &size)) return; - initrd_start = (unsigned long)__va(initrd_data.start); - initrd_end = initrd_start + initrd_data.size; - memblock_reserve(initrd_data.start, initrd_data.size); -#endif + initrd_start = (unsigned long)__va(addr); + initrd_end = initrd_start + size; + memblock_reserve(addr, size); } /* @@ -730,71 +707,39 @@ static void __init reserve_certificate_list(void) memblock_reserve(ipl_cert_list_addr, ipl_cert_list_size); } -static void __init reserve_mem_detect_info(void) +static void __init reserve_physmem_info(void) { - unsigned long start, size; + unsigned long addr, size; - get_mem_detect_reserved(&start, &size); - if (size) - memblock_reserve(start, size); + if (get_physmem_reserved(RR_MEM_DETECT_EXTENDED, &addr, &size)) + memblock_reserve(addr, size); } -static void __init free_mem_detect_info(void) +static void __init free_physmem_info(void) { - unsigned long start, size; + unsigned long addr, size; - get_mem_detect_reserved(&start, &size); - if (size) - memblock_phys_free(start, size); + if (get_physmem_reserved(RR_MEM_DETECT_EXTENDED, &addr, &size)) + memblock_phys_free(addr, size); } -static const char * __init get_mem_info_source(void) -{ - switch (mem_detect.info_source) { - case MEM_DETECT_SCLP_STOR_INFO: - return "sclp storage info"; - case MEM_DETECT_DIAG260: - return "diag260"; - case MEM_DETECT_SCLP_READ_INFO: - return "sclp read info"; - case MEM_DETECT_BIN_SEARCH: - return "binary search"; - } - return "none"; -} - -static void __init memblock_add_mem_detect_info(void) +static void __init memblock_add_physmem_info(void) { unsigned long start, end; int i; pr_debug("physmem info source: %s (%hhd)\n", - get_mem_info_source(), mem_detect.info_source); + get_physmem_info_source(), physmem_info.info_source); /* keep memblock lists close to the kernel */ memblock_set_bottom_up(true); - for_each_mem_detect_usable_block(i, &start, &end) + for_each_physmem_usable_range(i, &start, &end) memblock_add(start, end - start); - for_each_mem_detect_block(i, &start, &end) + for_each_physmem_online_range(i, &start, &end) memblock_physmem_add(start, end - start); memblock_set_bottom_up(false); memblock_set_node(0, ULONG_MAX, &memblock.memory, 0); } -/* - * Check for initrd being in usable memory - */ -static void __init check_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_data.start && initrd_data.size && - !memblock_is_region_memory(initrd_data.start, initrd_data.size)) { - pr_err("The initial RAM disk does not fit into the memory\n"); - memblock_phys_free(initrd_data.start, initrd_data.size); - initrd_start = initrd_end = 0; - } -#endif -} - /* * Reserve memory used for lowcore/command line/kernel image. */ @@ -803,7 +748,7 @@ static void __init reserve_kernel(void) memblock_reserve(0, STARTUP_NORMAL_OFFSET); memblock_reserve(OLDMEM_BASE, sizeof(unsigned long)); memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long)); - memblock_reserve(__amode31_base, __eamode31 - __samode31); + memblock_reserve(physmem_info.reserved[RR_AMODE31].start, __eamode31 - __samode31); memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP); memblock_reserve(__pa(_stext), _end - _stext); } @@ -825,13 +770,13 @@ static void __init setup_memory(void) static void __init relocate_amode31_section(void) { unsigned long amode31_size = __eamode31 - __samode31; - long amode31_offset = __amode31_base - __samode31; + long amode31_offset = physmem_info.reserved[RR_AMODE31].start - __samode31; long *ptr; pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size); /* Move original AMODE31 section to the new one */ - memmove((void *)__amode31_base, (void *)__samode31, amode31_size); + memmove((void *)physmem_info.reserved[RR_AMODE31].start, (void *)__samode31, amode31_size); /* Zero out the old AMODE31 section to catch invalid accesses within it */ memset((void *)__samode31, 0, amode31_size); @@ -997,14 +942,14 @@ void __init setup_arch(char **cmdline_p) reserve_kernel(); reserve_initrd(); reserve_certificate_list(); - reserve_mem_detect_info(); + reserve_physmem_info(); memblock_set_current_limit(ident_map_size); memblock_allow_resize(); /* Get information about *all* installed memory */ - memblock_add_mem_detect_info(); + memblock_add_physmem_info(); - free_mem_detect_info(); + free_physmem_info(); setup_memory_end(); memblock_dump_all(); setup_memory(); @@ -1017,7 +962,6 @@ void __init setup_arch(char **cmdline_p) if (MACHINE_HAS_EDAT2) hugetlb_cma_reserve(PUD_SHIFT - PAGE_SHIFT); - check_initrd(); reserve_crashkernel(); #ifdef CONFIG_CRASH_DUMP /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index d4888453bbf8..726de4f4df01 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -280,9 +280,8 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) cpu = pcpu - pcpu_devices; lc = lowcore_ptr[cpu]; - lc->kernel_stack = (unsigned long) task_stack_page(tsk) - + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs); - lc->current_task = (unsigned long) tsk; + lc->kernel_stack = (unsigned long)task_stack_page(tsk) + STACK_INIT_OFFSET; + lc->current_task = (unsigned long)tsk; lc->lpp = LPP_MAGIC; lc->current_pid = tsk->pid; lc->user_timer = tsk->thread.user_timer; @@ -348,7 +347,6 @@ static void pcpu_delegate(struct pcpu *pcpu, abs_lc->restart_source = source_cpu; put_abs_lowcore(abs_lc); } - __bpon(); asm volatile( "0: sigp 0,%0,%2 # sigp restart to target cpu\n" " brc 2,0b # busy, try again\n" @@ -553,7 +551,7 @@ void arch_send_call_function_single_ipi(int cpu) * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { pcpu_ec_call(pcpu_devices + cpu, ec_schedule); } @@ -986,7 +984,6 @@ void __cpu_die(unsigned int cpu) void __noreturn cpu_die(void) { idle_task_exit(); - __bpon(); pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); for (;;) ; } @@ -1227,11 +1224,17 @@ static DEVICE_ATTR_WO(rescan); static int __init s390_smp_init(void) { + struct device *dev_root; int cpu, rc = 0; - rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan); - if (rc) - return rc; + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + rc = device_create_file(dev_root, &dev_attr_rescan); + put_device(dev_root); + if (rc) + return rc; + } + for_each_present_cpu(cpu) { rc = smp_add_present_cpu(cpu); if (rc) @@ -1296,9 +1299,9 @@ int __init smp_reinit_ipl_cpu(void) local_mcck_enable(); local_irq_restore(flags); - free_pages(lc_ipl->async_stack - STACK_INIT_OFFSET, THREAD_SIZE_ORDER); memblock_free_late(__pa(lc_ipl->mcck_stack - STACK_INIT_OFFSET), THREAD_SIZE); + memblock_free_late(__pa(lc_ipl->async_stack - STACK_INIT_OFFSET), THREAD_SIZE); + memblock_free_late(__pa(lc_ipl->nodat_stack - STACK_INIT_OFFSET), THREAD_SIZE); memblock_free_late(__pa(lc_ipl), sizeof(*lc_ipl)); - return 0; } diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index 799147658dee..b68f47541169 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl @@ -449,7 +449,7 @@ 444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset 445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule 446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self -# 447 reserved for memfd_secret +447 common memfd_secret sys_memfd_secret sys_memfd_secret 448 common process_mrelease sys_process_mrelease sys_process_mrelease 449 common futex_waitv sys_futex_waitv sys_futex_waitv 450 common set_mempolicy_home_node sys_set_mempolicy_home_node sys_set_mempolicy_home_node diff --git a/arch/s390/kernel/text_amode31.S b/arch/s390/kernel/text_amode31.S index e0f01ce251f5..14c6d25c035f 100644 --- a/arch/s390/kernel/text_amode31.S +++ b/arch/s390/kernel/text_amode31.S @@ -27,7 +27,7 @@ /* * int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode) */ -ENTRY(_diag14_amode31) +SYM_FUNC_START(_diag14_amode31) lgr %r1,%r2 lgr %r2,%r3 lgr %r3,%r4 @@ -42,12 +42,12 @@ ENTRY(_diag14_amode31) lgfr %r2,%r5 BR_EX_AMODE31_r14 EX_TABLE_AMODE31(.Ldiag14_ex, .Ldiag14_fault) -ENDPROC(_diag14_amode31) +SYM_FUNC_END(_diag14_amode31) /* * int _diag210_amode31(struct diag210 *addr) */ -ENTRY(_diag210_amode31) +SYM_FUNC_START(_diag210_amode31) lgr %r1,%r2 lhi %r2,-1 sam31 @@ -60,12 +60,12 @@ ENTRY(_diag210_amode31) lgfr %r2,%r2 BR_EX_AMODE31_r14 EX_TABLE_AMODE31(.Ldiag210_ex, .Ldiag210_fault) -ENDPROC(_diag210_amode31) +SYM_FUNC_END(_diag210_amode31) /* * int diag8c(struct diag8c *addr, struct ccw_dev_id *devno, size_t len) */ -ENTRY(_diag8c_amode31) +SYM_FUNC_START(_diag8c_amode31) llgf %r3,0(%r3) sam31 diag %r2,%r4,0x8c @@ -74,11 +74,11 @@ ENTRY(_diag8c_amode31) lgfr %r2,%r3 BR_EX_AMODE31_r14 EX_TABLE_AMODE31(.Ldiag8c_ex, .Ldiag8c_ex) -ENDPROC(_diag8c_amode31) +SYM_FUNC_END(_diag8c_amode31) /* * int _diag26c_amode31(void *req, void *resp, enum diag26c_sc subcode) */ -ENTRY(_diag26c_amode31) +SYM_FUNC_START(_diag26c_amode31) lghi %r5,-EOPNOTSUPP sam31 diag %r2,%r4,0x26c @@ -87,42 +87,42 @@ ENTRY(_diag26c_amode31) lgfr %r2,%r5 BR_EX_AMODE31_r14 EX_TABLE_AMODE31(.Ldiag26c_ex, .Ldiag26c_ex) -ENDPROC(_diag26c_amode31) +SYM_FUNC_END(_diag26c_amode31) /* * void _diag0c_amode31(struct hypfs_diag0c_entry *entry) */ -ENTRY(_diag0c_amode31) +SYM_FUNC_START(_diag0c_amode31) sam31 diag %r2,%r2,0x0c sam64 BR_EX_AMODE31_r14 -ENDPROC(_diag0c_amode31) +SYM_FUNC_END(_diag0c_amode31) /* * void _diag308_reset_amode31(void) * * Calls diag 308 subcode 1 and continues execution */ -ENTRY(_diag308_reset_amode31) - larl %r4,.Lctlregs # Save control registers +SYM_FUNC_START(_diag308_reset_amode31) + larl %r4,ctlregs # Save control registers stctg %c0,%c15,0(%r4) lg %r2,0(%r4) # Disable lowcore protection nilh %r2,0xefff - larl %r4,.Lctlreg0 + larl %r4,ctlreg0 stg %r2,0(%r4) lctlg %c0,%c0,0(%r4) - larl %r4,.Lfpctl # Floating point control register + larl %r4,fpctl # Floating point control register stfpc 0(%r4) - larl %r4,.Lprefix # Save prefix register + larl %r4,prefix # Save prefix register stpx 0(%r4) - larl %r4,.Lprefix_zero # Set prefix register to 0 + larl %r4,prefix_zero # Set prefix register to 0 spx 0(%r4) - larl %r4,.Lcontinue_psw # Save PSW flags + larl %r4,continue_psw # Save PSW flags epsw %r2,%r3 stm %r2,%r3,0(%r4) larl %r4,.Lrestart_part2 # Setup restart PSW at absolute 0 - larl %r3,.Lrestart_diag308_psw + larl %r3,restart_diag308_psw og %r4,0(%r3) # Save PSW lghi %r3,0 sturg %r4,%r3 # Use sturg, because of large pages @@ -134,39 +134,26 @@ ENTRY(_diag308_reset_amode31) lhi %r1,2 # Use mode 2 = ESAME (dump) sigp %r1,%r0,SIGP_SET_ARCHITECTURE # Switch to ESAME mode sam64 # Switch to 64 bit addressing mode - larl %r4,.Lctlregs # Restore control registers + larl %r4,ctlregs # Restore control registers lctlg %c0,%c15,0(%r4) - larl %r4,.Lfpctl # Restore floating point ctl register + larl %r4,fpctl # Restore floating point ctl register lfpc 0(%r4) - larl %r4,.Lprefix # Restore prefix register + larl %r4,prefix # Restore prefix register spx 0(%r4) - larl %r4,.Lcontinue_psw # Restore PSW flags + larl %r4,continue_psw # Restore PSW flags larl %r2,.Lcontinue stg %r2,8(%r4) lpswe 0(%r4) .Lcontinue: BR_EX_AMODE31_r14 -ENDPROC(_diag308_reset_amode31) +SYM_FUNC_END(_diag308_reset_amode31) .section .amode31.data,"aw",@progbits -.align 8 -.Lrestart_diag308_psw: - .long 0x00080000,0x80000000 - -.align 8 -.Lcontinue_psw: - .quad 0,0 - -.align 8 -.Lctlreg0: - .quad 0 -.Lctlregs: - .rept 16 - .quad 0 - .endr -.Lfpctl: - .long 0 -.Lprefix: - .long 0 -.Lprefix_zero: - .long 0 + .balign 8 +SYM_DATA_LOCAL(restart_diag308_psw, .long 0x00080000,0x80000000) +SYM_DATA_LOCAL(continue_psw, .quad 0,0) +SYM_DATA_LOCAL(ctlreg0, .quad 0) +SYM_DATA_LOCAL(ctlregs, .fill 16,8,0) +SYM_DATA_LOCAL(fpctl, .long 0) +SYM_DATA_LOCAL(prefix, .long 0) +SYM_DATA_LOCAL(prefix_zero, .long 0) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index c6eecd4a5302..68adf1de8888 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -95,7 +95,7 @@ out: static void cpu_thread_map(cpumask_t *dst, unsigned int cpu) { static cpumask_t mask; - int i; + unsigned int max_cpu; cpumask_clear(&mask); if (!cpumask_test_cpu(cpu, &cpu_setup_mask)) @@ -104,9 +104,10 @@ static void cpu_thread_map(cpumask_t *dst, unsigned int cpu) if (topology_mode != TOPOLOGY_MODE_HW) goto out; cpu -= cpu % (smp_cpu_mtid + 1); - for (i = 0; i <= smp_cpu_mtid; i++) { - if (cpumask_test_cpu(cpu + i, &cpu_setup_mask)) - cpumask_set_cpu(cpu + i, &mask); + max_cpu = min(cpu + smp_cpu_mtid, nr_cpu_ids - 1); + for (; cpu <= max_cpu; cpu++) { + if (cpumask_test_cpu(cpu, &cpu_setup_mask)) + cpumask_set_cpu(cpu, &mask); } out: cpumask_copy(dst, &mask); @@ -123,25 +124,26 @@ static void add_cpus_to_mask(struct topology_core *tl_core, unsigned int core; for_each_set_bit(core, &tl_core->mask, TOPOLOGY_CORE_BITS) { - unsigned int rcore; - int lcpu, i; + unsigned int max_cpu, rcore; + int cpu; rcore = TOPOLOGY_CORE_BITS - 1 - core + tl_core->origin; - lcpu = smp_find_processor_id(rcore << smp_cpu_mt_shift); - if (lcpu < 0) + cpu = smp_find_processor_id(rcore << smp_cpu_mt_shift); + if (cpu < 0) continue; - for (i = 0; i <= smp_cpu_mtid; i++) { - topo = &cpu_topology[lcpu + i]; + max_cpu = min(cpu + smp_cpu_mtid, nr_cpu_ids - 1); + for (; cpu <= max_cpu; cpu++) { + topo = &cpu_topology[cpu]; topo->drawer_id = drawer->id; topo->book_id = book->id; topo->socket_id = socket->id; topo->core_id = rcore; - topo->thread_id = lcpu + i; + topo->thread_id = cpu; topo->dedicated = tl_core->d; - cpumask_set_cpu(lcpu + i, &drawer->mask); - cpumask_set_cpu(lcpu + i, &book->mask); - cpumask_set_cpu(lcpu + i, &socket->mask); - smp_cpu_set_polarization(lcpu + i, tl_core->pp); + cpumask_set_cpu(cpu, &drawer->mask); + cpumask_set_cpu(cpu, &book->mask); + cpumask_set_cpu(cpu, &socket->mask); + smp_cpu_set_polarization(cpu, tl_core->pp); } } } @@ -637,24 +639,23 @@ static struct ctl_table topology_ctl_table[] = { { }, }; -static struct ctl_table topology_dir_table[] = { - { - .procname = "s390", - .maxlen = 0, - .mode = 0555, - .child = topology_ctl_table, - }, - { }, -}; - static int __init topology_init(void) { + struct device *dev_root; + int rc = 0; + timer_setup(&topology_timer, topology_timer_fn, TIMER_DEFERRABLE); if (MACHINE_HAS_TOPOLOGY) set_topology_timer(); else topology_update_polarization_simple(); - register_sysctl_table(topology_dir_table); - return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); + register_sysctl("s390", topology_ctl_table); + + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + rc = device_create_file(dev_root, &dev_attr_dispatching); + put_device(dev_root); + } + return rc; } device_initcall(topology_init); diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 9f18a4af9c13..cb2ee06df286 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -192,21 +192,10 @@ static int expected_page_refs(struct page *page) return res; } -static int make_secure_pte(pte_t *ptep, unsigned long addr, - struct page *exp_page, struct uv_cb_header *uvcb) +static int make_page_secure(struct page *page, struct uv_cb_header *uvcb) { - pte_t entry = READ_ONCE(*ptep); - struct page *page; int expected, cc = 0; - if (!pte_present(entry)) - return -ENXIO; - if (pte_val(entry) & _PAGE_INVALID) - return -ENXIO; - - page = pte_page(entry); - if (page != exp_page) - return -ENXIO; if (PageWriteback(page)) return -EAGAIN; expected = expected_page_refs(page); @@ -304,17 +293,18 @@ again: goto out; rc = -ENXIO; - page = follow_page(vma, uaddr, FOLL_WRITE); - if (IS_ERR_OR_NULL(page)) - goto out; - - lock_page(page); ptep = get_locked_pte(gmap->mm, uaddr, &ptelock); - if (should_export_before_import(uvcb, gmap->mm)) - uv_convert_from_secure(page_to_phys(page)); - rc = make_secure_pte(ptep, uaddr, page, uvcb); + if (pte_present(*ptep) && !(pte_val(*ptep) & _PAGE_INVALID) && pte_write(*ptep)) { + page = pte_page(*ptep); + rc = -EAGAIN; + if (trylock_page(page)) { + if (should_export_before_import(uvcb, gmap->mm)) + uv_convert_from_secure(page_to_phys(page)); + rc = make_page_secure(page, uvcb); + unlock_page(page); + } + } pte_unmap_unlock(ptep, ptelock); - unlock_page(page); out: mmap_read_unlock(gmap->mm); diff --git a/arch/s390/kernel/vdso32/vdso_user_wrapper.S b/arch/s390/kernel/vdso32/vdso_user_wrapper.S index 3f42f27f978c..2e645003fdaf 100644 --- a/arch/s390/kernel/vdso32/vdso_user_wrapper.S +++ b/arch/s390/kernel/vdso32/vdso_user_wrapper.S @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include #include #include .macro vdso_syscall func,syscall .globl __kernel_compat_\func .type __kernel_compat_\func,@function - .align 8 + __ALIGN __kernel_compat_\func: CFI_STARTPROC svc \syscall diff --git a/arch/s390/kernel/vdso64/vdso_user_wrapper.S b/arch/s390/kernel/vdso64/vdso_user_wrapper.S index 97f0c0a669a5..57f62596e53b 100644 --- a/arch/s390/kernel/vdso64/vdso_user_wrapper.S +++ b/arch/s390/kernel/vdso64/vdso_user_wrapper.S @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include #include #include #include @@ -16,7 +17,7 @@ .macro vdso_func func .globl __kernel_\func .type __kernel_\func,@function - .align 8 + __ALIGN __kernel_\func: CFI_STARTPROC aghi %r15,-WRAPPER_FRAME_SIZE @@ -41,7 +42,7 @@ vdso_func getcpu .macro vdso_syscall func,syscall .globl __kernel_\func .type __kernel_\func,@function - .align 8 + __ALIGN __kernel_\func: CFI_STARTPROC svc \syscall diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index b653ba8d51e6..2ae201ebf90b 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -14,6 +14,8 @@ #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) \ *(.bss..invalid_pg_dir) +#define RO_EXCEPTION_TABLE_ALIGN 16 + /* Handle ro_after_init data on our own. */ #define RO_AFTER_INIT_DATA @@ -66,7 +68,6 @@ SECTIONS *(.data..ro_after_init) JUMP_TABLE_DATA } :data - EXCEPTION_TABLE(16) . = ALIGN(PAGE_SIZE); __end_ro_after_init = .; @@ -219,6 +220,13 @@ SECTIONS QUAD(init_mm) QUAD(swapper_pg_dir) QUAD(invalid_pg_dir) +#ifdef CONFIG_KASAN + QUAD(kasan_early_shadow_page) + QUAD(kasan_early_shadow_pte) + QUAD(kasan_early_shadow_pmd) + QUAD(kasan_early_shadow_pud) + QUAD(kasan_early_shadow_p4d) +#endif } :NONE /* Debugging sections. */ diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 9250fde1f97d..da6dac36e959 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -305,7 +305,7 @@ static inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi) static inline int gisa_in_alert_list(struct kvm_s390_gisa *gisa) { - return READ_ONCE(gisa->next_alert) != (u32)(u64)gisa; + return READ_ONCE(gisa->next_alert) != (u32)virt_to_phys(gisa); } static inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) @@ -3168,7 +3168,7 @@ void kvm_s390_gisa_init(struct kvm *kvm) hrtimer_init(&gi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); gi->timer.function = gisa_vcpu_kicker; memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); - gi->origin->next_alert = (u32)(u64)gi->origin; + gi->origin->next_alert = (u32)virt_to_phys(gi->origin); VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 1eeb9ae57879..17b81659cdb2 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1990,7 +1990,7 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) return ret; } -static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) +static int kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) { uint8_t *keys; uint64_t hva; @@ -2038,7 +2038,7 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) return r; } -static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) +static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) { uint8_t *keys; uint64_t hva; @@ -2899,8 +2899,7 @@ static int kvm_s390_vm_mem_op(struct kvm *kvm, struct kvm_s390_mem_op *mop) } } -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; void __user *argp = (void __user *)arg; diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index b124d586db55..7dab00f1e833 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -112,7 +112,7 @@ static int zpci_reset_aipb(u8 nisc) return -EINVAL; aift->sbv = zpci_aif_sbv; - aift->gait = (struct zpci_gaite *)zpci_aipb->aipb.gait; + aift->gait = phys_to_virt(zpci_aipb->aipb.gait); return 0; } diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index e032ebbf51b9..3ce5f4351156 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -314,6 +314,11 @@ int kvm_s390_pv_set_aside(struct kvm *kvm, u16 *rc, u16 *rrc) */ if (kvm->arch.pv.set_aside) return -EINVAL; + + /* Guest with segment type ASCE, refuse to destroy asynchronously */ + if ((kvm->arch.gmap->asce & _ASCE_TYPE_MASK) == _ASCE_TYPE_SEGMENT) + return -EINVAL; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index b6a0219e470a..8d6b765abf29 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -138,11 +138,15 @@ static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) } /* Copy to APCB FORMAT1 from APCB FORMAT0 */ static int setup_apcb10(struct kvm_vcpu *vcpu, struct kvm_s390_apcb1 *apcb_s, - unsigned long apcb_o, struct kvm_s390_apcb1 *apcb_h) + unsigned long crycb_gpa, struct kvm_s390_apcb1 *apcb_h) { struct kvm_s390_apcb0 tmp; + unsigned long apcb_gpa; - if (read_guest_real(vcpu, apcb_o, &tmp, sizeof(struct kvm_s390_apcb0))) + apcb_gpa = crycb_gpa + offsetof(struct kvm_s390_crypto_cb, apcb0); + + if (read_guest_real(vcpu, apcb_gpa, &tmp, + sizeof(struct kvm_s390_apcb0))) return -EFAULT; apcb_s->apm[0] = apcb_h->apm[0] & tmp.apm[0]; @@ -157,15 +161,19 @@ static int setup_apcb10(struct kvm_vcpu *vcpu, struct kvm_s390_apcb1 *apcb_s, * setup_apcb00 - Copy to APCB FORMAT0 from APCB FORMAT0 * @vcpu: pointer to the virtual CPU * @apcb_s: pointer to start of apcb in the shadow crycb - * @apcb_o: pointer to start of original apcb in the guest2 + * @crycb_gpa: guest physical address to start of original guest crycb * @apcb_h: pointer to start of apcb in the guest1 * * Returns 0 and -EFAULT on error reading guest apcb */ static int setup_apcb00(struct kvm_vcpu *vcpu, unsigned long *apcb_s, - unsigned long apcb_o, unsigned long *apcb_h) + unsigned long crycb_gpa, unsigned long *apcb_h) { - if (read_guest_real(vcpu, apcb_o, apcb_s, + unsigned long apcb_gpa; + + apcb_gpa = crycb_gpa + offsetof(struct kvm_s390_crypto_cb, apcb0); + + if (read_guest_real(vcpu, apcb_gpa, apcb_s, sizeof(struct kvm_s390_apcb0))) return -EFAULT; @@ -178,16 +186,20 @@ static int setup_apcb00(struct kvm_vcpu *vcpu, unsigned long *apcb_s, * setup_apcb11 - Copy the FORMAT1 APCB from the guest to the shadow CRYCB * @vcpu: pointer to the virtual CPU * @apcb_s: pointer to start of apcb in the shadow crycb - * @apcb_o: pointer to start of original guest apcb + * @crycb_gpa: guest physical address to start of original guest crycb * @apcb_h: pointer to start of apcb in the host * * Returns 0 and -EFAULT on error reading guest apcb */ static int setup_apcb11(struct kvm_vcpu *vcpu, unsigned long *apcb_s, - unsigned long apcb_o, + unsigned long crycb_gpa, unsigned long *apcb_h) { - if (read_guest_real(vcpu, apcb_o, apcb_s, + unsigned long apcb_gpa; + + apcb_gpa = crycb_gpa + offsetof(struct kvm_s390_crypto_cb, apcb1); + + if (read_guest_real(vcpu, apcb_gpa, apcb_s, sizeof(struct kvm_s390_apcb1))) return -EFAULT; @@ -200,7 +212,7 @@ static int setup_apcb11(struct kvm_vcpu *vcpu, unsigned long *apcb_s, * setup_apcb - Create a shadow copy of the apcb. * @vcpu: pointer to the virtual CPU * @crycb_s: pointer to shadow crycb - * @crycb_o: pointer to original guest crycb + * @crycb_gpa: guest physical address of original guest crycb * @crycb_h: pointer to the host crycb * @fmt_o: format of the original guest crycb. * @fmt_h: format of the host crycb. @@ -211,50 +223,46 @@ static int setup_apcb11(struct kvm_vcpu *vcpu, unsigned long *apcb_s, * Return 0 or an error number if the guest and host crycb are incompatible. */ static int setup_apcb(struct kvm_vcpu *vcpu, struct kvm_s390_crypto_cb *crycb_s, - const u32 crycb_o, + const u32 crycb_gpa, struct kvm_s390_crypto_cb *crycb_h, int fmt_o, int fmt_h) { - struct kvm_s390_crypto_cb *crycb; - - crycb = (struct kvm_s390_crypto_cb *) (unsigned long)crycb_o; - switch (fmt_o) { case CRYCB_FORMAT2: - if ((crycb_o & PAGE_MASK) != ((crycb_o + 256) & PAGE_MASK)) + if ((crycb_gpa & PAGE_MASK) != ((crycb_gpa + 256) & PAGE_MASK)) return -EACCES; if (fmt_h != CRYCB_FORMAT2) return -EINVAL; return setup_apcb11(vcpu, (unsigned long *)&crycb_s->apcb1, - (unsigned long) &crycb->apcb1, + crycb_gpa, (unsigned long *)&crycb_h->apcb1); case CRYCB_FORMAT1: switch (fmt_h) { case CRYCB_FORMAT2: return setup_apcb10(vcpu, &crycb_s->apcb1, - (unsigned long) &crycb->apcb0, + crycb_gpa, &crycb_h->apcb1); case CRYCB_FORMAT1: return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, - (unsigned long) &crycb->apcb0, + crycb_gpa, (unsigned long *) &crycb_h->apcb0); } break; case CRYCB_FORMAT0: - if ((crycb_o & PAGE_MASK) != ((crycb_o + 32) & PAGE_MASK)) + if ((crycb_gpa & PAGE_MASK) != ((crycb_gpa + 32) & PAGE_MASK)) return -EACCES; switch (fmt_h) { case CRYCB_FORMAT2: return setup_apcb10(vcpu, &crycb_s->apcb1, - (unsigned long) &crycb->apcb0, + crycb_gpa, &crycb_h->apcb1); case CRYCB_FORMAT1: case CRYCB_FORMAT0: return setup_apcb00(vcpu, (unsigned long *) &crycb_s->apcb0, - (unsigned long) &crycb->apcb0, + crycb_gpa, (unsigned long *) &crycb_h->apcb0); } } diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index dc0874f2e203..5a9a55de2e10 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -14,8 +14,7 @@ /* * void *memmove(void *dest, const void *src, size_t n) */ -WEAK(memmove) -ENTRY(__memmove) +SYM_FUNC_START(__memmove) ltgr %r4,%r4 lgr %r1,%r2 jz .Lmemmove_exit @@ -48,7 +47,10 @@ ENTRY(__memmove) BR_EX %r14 .Lmemmove_mvc: mvc 0(1,%r1),0(%r3) -ENDPROC(__memmove) +SYM_FUNC_END(__memmove) +EXPORT_SYMBOL(__memmove) + +SYM_FUNC_ALIAS(memmove, __memmove) EXPORT_SYMBOL(memmove) /* @@ -66,8 +68,7 @@ EXPORT_SYMBOL(memmove) * return __builtin_memset(s, c, n); * } */ -WEAK(memset) -ENTRY(__memset) +SYM_FUNC_START(__memset) ltgr %r4,%r4 jz .Lmemset_exit ltgr %r3,%r3 @@ -111,7 +112,10 @@ ENTRY(__memset) xc 0(1,%r1),0(%r1) .Lmemset_mvc: mvc 1(1,%r1),0(%r1) -ENDPROC(__memset) +SYM_FUNC_END(__memset) +EXPORT_SYMBOL(__memset) + +SYM_FUNC_ALIAS(memset, __memset) EXPORT_SYMBOL(memset) /* @@ -119,8 +123,7 @@ EXPORT_SYMBOL(memset) * * void *memcpy(void *dest, const void *src, size_t n) */ -WEAK(memcpy) -ENTRY(__memcpy) +SYM_FUNC_START(__memcpy) ltgr %r4,%r4 jz .Lmemcpy_exit aghi %r4,-1 @@ -141,7 +144,10 @@ ENTRY(__memcpy) j .Lmemcpy_remainder .Lmemcpy_mvc: mvc 0(1,%r1),0(%r3) -ENDPROC(__memcpy) +SYM_FUNC_END(__memcpy) +EXPORT_SYMBOL(__memcpy) + +SYM_FUNC_ALIAS(memcpy, __memcpy) EXPORT_SYMBOL(memcpy) /* @@ -152,7 +158,7 @@ EXPORT_SYMBOL(memcpy) * void *__memset64(uint64_t *s, uint64_t v, size_t count) */ .macro __MEMSET bits,bytes,insn -ENTRY(__memset\bits) +SYM_FUNC_START(__memset\bits) ltgr %r4,%r4 jz .L__memset_exit\bits cghi %r4,\bytes @@ -178,7 +184,7 @@ ENTRY(__memset\bits) BR_EX %r14 .L__memset_mvc\bits: mvc \bytes(1,%r1),0(%r1) -ENDPROC(__memset\bits) +SYM_FUNC_END(__memset\bits) .endm __MEMSET 16,2,sth diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c index d44214072779..e4a13d7cab6e 100644 --- a/arch/s390/lib/uaccess.c +++ b/arch/s390/lib/uaccess.c @@ -27,14 +27,13 @@ void debug_user_asce(int exit) "kernel: %016llx user: %016llx\n", exit ? "exit" : "entry", cr1, cr7, S390_lowcore.kernel_asce, S390_lowcore.user_asce); - } #endif /*CONFIG_DEBUG_ENTRY */ static unsigned long raw_copy_from_user_key(void *to, const void __user *from, unsigned long size, unsigned long key) { - unsigned long tmp1, tmp2; + unsigned long rem; union oac spec = { .oac2.key = key, .oac2.as = PSW_BITS_AS_SECONDARY, @@ -42,28 +41,30 @@ static unsigned long raw_copy_from_user_key(void *to, const void __user *from, .oac2.a = 1, }; - tmp1 = -4096UL; asm volatile( - " lr 0,%[spec]\n" - "0: mvcos 0(%2),0(%1),%0\n" - "6: jz 4f\n" - "1: algr %0,%3\n" - " slgr %1,%3\n" - " slgr %2,%3\n" - " j 0b\n" - "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ - " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ - " slgr %4,%1\n" - " clgr %0,%4\n" /* copy crosses next page boundary? */ - " jnh 5f\n" - "3: mvcos 0(%2),0(%1),%4\n" - "7: slgr %0,%4\n" - " j 5f\n" - "4: slgr %0,%0\n" - "5:\n" - EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) - : "+a" (size), "+a" (from), "+a" (to), "+a" (tmp1), "=a" (tmp2) - : [spec] "d" (spec.val) + " lr 0,%[spec]\n" + "0: mvcos 0(%[to]),0(%[from]),%[size]\n" + "1: jz 5f\n" + " algr %[size],%[val]\n" + " slgr %[from],%[val]\n" + " slgr %[to],%[val]\n" + " j 0b\n" + "2: la %[rem],4095(%[from])\n" /* rem = from + 4095 */ + " nr %[rem],%[val]\n" /* rem = (from + 4095) & -4096 */ + " slgr %[rem],%[from]\n" + " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ + " jnh 6f\n" + "3: mvcos 0(%[to]),0(%[from]),%[rem]\n" + "4: slgr %[size],%[rem]\n" + " j 6f\n" + "5: slgr %[size],%[size]\n" + "6:\n" + EX_TABLE(0b, 2b) + EX_TABLE(1b, 2b) + EX_TABLE(3b, 6b) + EX_TABLE(4b, 6b) + : [size] "+&a" (size), [from] "+&a" (from), [to] "+&a" (to), [rem] "=&a" (rem) + : [val] "a" (-4096UL), [spec] "d" (spec.val) : "cc", "memory", "0"); return size; } @@ -94,7 +95,7 @@ EXPORT_SYMBOL(_copy_from_user_key); static unsigned long raw_copy_to_user_key(void __user *to, const void *from, unsigned long size, unsigned long key) { - unsigned long tmp1, tmp2; + unsigned long rem; union oac spec = { .oac1.key = key, .oac1.as = PSW_BITS_AS_SECONDARY, @@ -102,28 +103,30 @@ static unsigned long raw_copy_to_user_key(void __user *to, const void *from, .oac1.a = 1, }; - tmp1 = -4096UL; asm volatile( - " lr 0,%[spec]\n" - "0: mvcos 0(%1),0(%2),%0\n" - "6: jz 4f\n" - "1: algr %0,%3\n" - " slgr %1,%3\n" - " slgr %2,%3\n" - " j 0b\n" - "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ - " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ - " slgr %4,%1\n" - " clgr %0,%4\n" /* copy crosses next page boundary? */ - " jnh 5f\n" - "3: mvcos 0(%1),0(%2),%4\n" - "7: slgr %0,%4\n" - " j 5f\n" - "4: slgr %0,%0\n" - "5:\n" - EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b) - : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2) - : [spec] "d" (spec.val) + " lr 0,%[spec]\n" + "0: mvcos 0(%[to]),0(%[from]),%[size]\n" + "1: jz 5f\n" + " algr %[size],%[val]\n" + " slgr %[to],%[val]\n" + " slgr %[from],%[val]\n" + " j 0b\n" + "2: la %[rem],4095(%[to])\n" /* rem = to + 4095 */ + " nr %[rem],%[val]\n" /* rem = (to + 4095) & -4096 */ + " slgr %[rem],%[to]\n" + " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ + " jnh 6f\n" + "3: mvcos 0(%[to]),0(%[from]),%[rem]\n" + "4: slgr %[size],%[rem]\n" + " j 6f\n" + "5: slgr %[size],%[size]\n" + "6:\n" + EX_TABLE(0b, 2b) + EX_TABLE(1b, 2b) + EX_TABLE(3b, 6b) + EX_TABLE(4b, 6b) + : [size] "+&a" (size), [to] "+&a" (to), [from] "+&a" (from), [rem] "=&a" (rem) + : [val] "a" (-4096UL), [spec] "d" (spec.val) : "cc", "memory", "0"); return size; } @@ -147,33 +150,35 @@ EXPORT_SYMBOL(_copy_to_user_key); unsigned long __clear_user(void __user *to, unsigned long size) { - unsigned long tmp1, tmp2; + unsigned long rem; union oac spec = { .oac1.as = PSW_BITS_AS_SECONDARY, .oac1.a = 1, }; - tmp1 = -4096UL; asm volatile( - " lr 0,%[spec]\n" - "0: mvcos 0(%1),0(%4),%0\n" - "6: jz 4f\n" - "1: algr %0,%2\n" - " slgr %1,%2\n" - " j 0b\n" - "2: la %3,4095(%1)\n"/* %4 = to + 4095 */ - " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */ - " slgr %3,%1\n" - " clgr %0,%3\n" /* copy crosses next page boundary? */ - " jnh 5f\n" - "3: mvcos 0(%1),0(%4),%3\n" - "7: slgr %0,%3\n" - " j 5f\n" - "4: slgr %0,%0\n" - "5:\n" - EX_TABLE(0b,2b) EX_TABLE(6b,2b) EX_TABLE(3b,5b) EX_TABLE(7b,5b) - : "+&a" (size), "+&a" (to), "+a" (tmp1), "=&a" (tmp2) - : "a" (empty_zero_page), [spec] "d" (spec.val) + " lr 0,%[spec]\n" + "0: mvcos 0(%[to]),0(%[zeropg]),%[size]\n" + "1: jz 5f\n" + " algr %[size],%[val]\n" + " slgr %[to],%[val]\n" + " j 0b\n" + "2: la %[rem],4095(%[to])\n" /* rem = to + 4095 */ + " nr %[rem],%[val]\n" /* rem = (to + 4095) & -4096 */ + " slgr %[rem],%[to]\n" + " clgr %[size],%[rem]\n" /* copy crosses next page boundary? */ + " jnh 6f\n" + "3: mvcos 0(%[to]),0(%[zeropg]),%[rem]\n" + "4: slgr %[size],%[rem]\n" + " j 6f\n" + "5: slgr %[size],%[size]\n" + "6:\n" + EX_TABLE(0b, 2b) + EX_TABLE(1b, 2b) + EX_TABLE(3b, 6b) + EX_TABLE(4b, 6b) + : [size] "+&a" (size), [to] "+&a" (to), [rem] "=&a" (rem) + : [val] "a" (-4096UL), [zeropg] "a" (empty_zero_page), [spec] "d" (spec.val) : "cc", "memory", "0"); return size; } diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index 57e4f3a24829..d90db06a8af5 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile @@ -10,6 +10,3 @@ obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o obj-$(CONFIG_PGSTE) += gmap.o - -KASAN_SANITIZE_kasan_init.o := n -obj-$(CONFIG_KASAN) += kasan_init.o diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 9141ed4c52e9..5300c6867d5e 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -335,16 +335,6 @@ static struct ctl_table cmm_table[] = { { } }; -static struct ctl_table cmm_dir_table[] = { - { - .procname = "vm", - .maxlen = 0, - .mode = 0555, - .child = cmm_table, - }, - { } -}; - #ifdef CONFIG_CMM_IUCV #define SMSG_PREFIX "CMM" static void cmm_smsg_target(const char *from, char *msg) @@ -389,7 +379,7 @@ static int __init cmm_init(void) { int rc = -ENOMEM; - cmm_sysctl_header = register_sysctl_table(cmm_dir_table); + cmm_sysctl_header = register_sysctl("vm", cmm_table); if (!cmm_sysctl_header) goto out_sysctl; #ifdef CONFIG_CMM_IUCV diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a2632fd97d00..b65144c392b0 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -407,6 +407,30 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access) access = VM_WRITE; if (access == VM_WRITE) flags |= FAULT_FLAG_WRITE; +#ifdef CONFIG_PER_VMA_LOCK + if (!(flags & FAULT_FLAG_USER)) + goto lock_mmap; + vma = lock_vma_under_rcu(mm, address); + if (!vma) + goto lock_mmap; + if (!(vma->vm_flags & access)) { + vma_end_read(vma); + goto lock_mmap; + } + fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs); + vma_end_read(vma); + if (!(fault & VM_FAULT_RETRY)) { + count_vm_vma_lock_event(VMA_LOCK_SUCCESS); + goto out; + } + count_vm_vma_lock_event(VMA_LOCK_RETRY); + /* Quick path to respond to signals */ + if (fault_signal_pending(fault, regs)) { + fault = VM_FAULT_SIGNAL; + goto out; + } +lock_mmap: +#endif /* CONFIG_PER_VMA_LOCK */ mmap_read_lock(mm); gmap = NULL; diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 5a716bdcba05..dc90d1eb0d55 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2585,23 +2585,12 @@ EXPORT_SYMBOL_GPL(s390_enable_sie); int gmap_mark_unmergeable(void) { - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long vm_flags; - int ret; - VMA_ITERATOR(vmi, mm, 0); - - for_each_vma(vmi, vma) { - /* Copy vm_flags to avoid partial modifications in ksm_madvise */ - vm_flags = vma->vm_flags; - ret = ksm_madvise(vma, vma->vm_start, vma->vm_end, - MADV_UNMERGEABLE, &vm_flags); - if (ret) - return ret; - vm_flags_reset(vma, vm_flags); - } - mm->def_flags &= ~VM_MERGEABLE; - return 0; + /* + * Make sure to disable KSM (if enabled for the whole process or + * individual VMAs). Note that nothing currently hinders user space + * from re-enabling it. + */ + return ksm_disable(current->mm); } EXPORT_SYMBOL_GPL(gmap_mark_unmergeable); @@ -2833,6 +2822,9 @@ EXPORT_SYMBOL_GPL(s390_unlist_old_asce); * s390_replace_asce - Try to replace the current ASCE of a gmap with a copy * @gmap: the gmap whose ASCE needs to be replaced * + * If the ASCE is a SEGMENT type then this function will return -EINVAL, + * otherwise the pointers in the host_to_guest radix tree will keep pointing + * to the wrong pages, causing use-after-free and memory corruption. * If the allocation of the new top level page table fails, the ASCE is not * replaced. * In any case, the old ASCE is always removed from the gmap CRST list. @@ -2847,6 +2839,10 @@ int s390_replace_asce(struct gmap *gmap) s390_unlist_old_asce(gmap); + /* Replacing segment type ASCEs would cause serious issues */ + if ((gmap->asce & _ASCE_TYPE_MASK) == _ASCE_TYPE_SEGMENT) + return -EINVAL; + page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); if (!page) return -ENOMEM; diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index c299a18273ff..c718f2a0de94 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -273,7 +273,7 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = max(PAGE_SIZE, mmap_min_addr); + info.low_limit = PAGE_SIZE; info.high_limit = current->mm->mmap_base; info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 144447d5cb4c..8d94e29adcdb 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -176,9 +176,8 @@ void __init mem_init(void) void free_initmem(void) { - __set_memory((unsigned long)_sinittext, - (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT, - SET_MEMORY_RW | SET_MEMORY_NX); + set_memory_rwnx((unsigned long)_sinittext, + (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT); free_initmem_default(POISON_FREE_INITMEM); } diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c deleted file mode 100644 index ef89a5f26853..000000000000 --- a/arch/s390/mm/kasan_init.c +++ /dev/null @@ -1,301 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned long segment_pos __initdata; -static unsigned long segment_low __initdata; -static bool has_edat __initdata; -static bool has_nx __initdata; - -#define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) - -static void __init kasan_early_panic(const char *reason) -{ - sclp_early_printk("The Linux kernel failed to boot with the KernelAddressSanitizer:\n"); - sclp_early_printk(reason); - disabled_wait(); -} - -static void * __init kasan_early_alloc_segment(void) -{ - segment_pos -= _SEGMENT_SIZE; - - if (segment_pos < segment_low) - kasan_early_panic("out of memory during initialisation\n"); - - return __va(segment_pos); -} - -static void * __init kasan_early_alloc_pages(unsigned int order) -{ - pgalloc_pos -= (PAGE_SIZE << order); - - if (pgalloc_pos < pgalloc_low) - kasan_early_panic("out of memory during initialisation\n"); - - return __va(pgalloc_pos); -} - -static void * __init kasan_early_crst_alloc(unsigned long val) -{ - unsigned long *table; - - table = kasan_early_alloc_pages(CRST_ALLOC_ORDER); - if (table) - crst_table_init(table, val); - return table; -} - -static pte_t * __init kasan_early_pte_alloc(void) -{ - static void *pte_leftover; - pte_t *pte; - - BUILD_BUG_ON(_PAGE_TABLE_SIZE * 2 != PAGE_SIZE); - - if (!pte_leftover) { - pte_leftover = kasan_early_alloc_pages(0); - pte = pte_leftover + _PAGE_TABLE_SIZE; - } else { - pte = pte_leftover; - pte_leftover = NULL; - } - memset64((u64 *)pte, _PAGE_INVALID, PTRS_PER_PTE); - return pte; -} - -enum populate_mode { - POPULATE_MAP, - POPULATE_ZERO_SHADOW, - POPULATE_SHALLOW -}; - -static inline pgprot_t pgprot_clear_bit(pgprot_t pgprot, unsigned long bit) -{ - return __pgprot(pgprot_val(pgprot) & ~bit); -} - -static void __init kasan_early_pgtable_populate(unsigned long address, - unsigned long end, - enum populate_mode mode) -{ - pgprot_t pgt_prot_zero = PAGE_KERNEL_RO; - pgprot_t pgt_prot = PAGE_KERNEL; - pgprot_t sgt_prot = SEGMENT_KERNEL; - pgd_t *pg_dir; - p4d_t *p4_dir; - pud_t *pu_dir; - pmd_t *pm_dir; - pte_t *pt_dir; - pmd_t pmd; - pte_t pte; - - if (!has_nx) { - pgt_prot_zero = pgprot_clear_bit(pgt_prot_zero, _PAGE_NOEXEC); - pgt_prot = pgprot_clear_bit(pgt_prot, _PAGE_NOEXEC); - sgt_prot = pgprot_clear_bit(sgt_prot, _SEGMENT_ENTRY_NOEXEC); - } - - while (address < end) { - pg_dir = pgd_offset_k(address); - if (pgd_none(*pg_dir)) { - if (mode == POPULATE_ZERO_SHADOW && - IS_ALIGNED(address, PGDIR_SIZE) && - end - address >= PGDIR_SIZE) { - pgd_populate(&init_mm, pg_dir, - kasan_early_shadow_p4d); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - continue; - } - p4_dir = kasan_early_crst_alloc(_REGION2_ENTRY_EMPTY); - pgd_populate(&init_mm, pg_dir, p4_dir); - } - - if (mode == POPULATE_SHALLOW) { - address = (address + P4D_SIZE) & P4D_MASK; - continue; - } - - p4_dir = p4d_offset(pg_dir, address); - if (p4d_none(*p4_dir)) { - if (mode == POPULATE_ZERO_SHADOW && - IS_ALIGNED(address, P4D_SIZE) && - end - address >= P4D_SIZE) { - p4d_populate(&init_mm, p4_dir, - kasan_early_shadow_pud); - address = (address + P4D_SIZE) & P4D_MASK; - continue; - } - pu_dir = kasan_early_crst_alloc(_REGION3_ENTRY_EMPTY); - p4d_populate(&init_mm, p4_dir, pu_dir); - } - - pu_dir = pud_offset(p4_dir, address); - if (pud_none(*pu_dir)) { - if (mode == POPULATE_ZERO_SHADOW && - IS_ALIGNED(address, PUD_SIZE) && - end - address >= PUD_SIZE) { - pud_populate(&init_mm, pu_dir, - kasan_early_shadow_pmd); - address = (address + PUD_SIZE) & PUD_MASK; - continue; - } - pm_dir = kasan_early_crst_alloc(_SEGMENT_ENTRY_EMPTY); - pud_populate(&init_mm, pu_dir, pm_dir); - } - - pm_dir = pmd_offset(pu_dir, address); - if (pmd_none(*pm_dir)) { - if (IS_ALIGNED(address, PMD_SIZE) && - end - address >= PMD_SIZE) { - if (mode == POPULATE_ZERO_SHADOW) { - pmd_populate(&init_mm, pm_dir, kasan_early_shadow_pte); - address = (address + PMD_SIZE) & PMD_MASK; - continue; - } else if (has_edat) { - void *page = kasan_early_alloc_segment(); - - memset(page, 0, _SEGMENT_SIZE); - pmd = __pmd(__pa(page)); - pmd = set_pmd_bit(pmd, sgt_prot); - set_pmd(pm_dir, pmd); - address = (address + PMD_SIZE) & PMD_MASK; - continue; - } - } - pt_dir = kasan_early_pte_alloc(); - pmd_populate(&init_mm, pm_dir, pt_dir); - } else if (pmd_large(*pm_dir)) { - address = (address + PMD_SIZE) & PMD_MASK; - continue; - } - - pt_dir = pte_offset_kernel(pm_dir, address); - if (pte_none(*pt_dir)) { - void *page; - - switch (mode) { - case POPULATE_MAP: - page = kasan_early_alloc_pages(0); - memset(page, 0, PAGE_SIZE); - pte = __pte(__pa(page)); - pte = set_pte_bit(pte, pgt_prot); - set_pte(pt_dir, pte); - break; - case POPULATE_ZERO_SHADOW: - page = kasan_early_shadow_page; - pte = __pte(__pa(page)); - pte = set_pte_bit(pte, pgt_prot_zero); - set_pte(pt_dir, pte); - break; - case POPULATE_SHALLOW: - /* should never happen */ - break; - } - } - address += PAGE_SIZE; - } -} - -static void __init kasan_early_detect_facilities(void) -{ - if (test_facility(8)) { - has_edat = true; - __ctl_set_bit(0, 23); - } - if (!noexec_disabled && test_facility(130)) { - has_nx = true; - __ctl_set_bit(0, 20); - } -} - -void __init kasan_early_init(void) -{ - pte_t pte_z = __pte(__pa(kasan_early_shadow_page) | pgprot_val(PAGE_KERNEL_RO)); - pmd_t pmd_z = __pmd(__pa(kasan_early_shadow_pte) | _SEGMENT_ENTRY); - pud_t pud_z = __pud(__pa(kasan_early_shadow_pmd) | _REGION3_ENTRY); - p4d_t p4d_z = __p4d(__pa(kasan_early_shadow_pud) | _REGION2_ENTRY); - unsigned long untracked_end = MODULES_VADDR; - unsigned long shadow_alloc_size; - unsigned long start, end; - int i; - - kasan_early_detect_facilities(); - if (!has_nx) - pte_z = clear_pte_bit(pte_z, __pgprot(_PAGE_NOEXEC)); - - BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, P4D_SIZE)); - BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, P4D_SIZE)); - - /* init kasan zero shadow */ - crst_table_init((unsigned long *)kasan_early_shadow_p4d, p4d_val(p4d_z)); - crst_table_init((unsigned long *)kasan_early_shadow_pud, pud_val(pud_z)); - crst_table_init((unsigned long *)kasan_early_shadow_pmd, pmd_val(pmd_z)); - memset64((u64 *)kasan_early_shadow_pte, pte_val(pte_z), PTRS_PER_PTE); - - if (has_edat) { - shadow_alloc_size = get_mem_detect_usable_total() >> KASAN_SHADOW_SCALE_SHIFT; - segment_pos = round_down(pgalloc_pos, _SEGMENT_SIZE); - segment_low = segment_pos - shadow_alloc_size; - segment_low = round_down(segment_low, _SEGMENT_SIZE); - pgalloc_pos = segment_low; - } - /* - * Current memory layout: - * +- 0 -------------+ +- shadow start -+ - * |1:1 ident mapping| /|1/8 of ident map| - * | | / | | - * +-end of ident map+ / +----------------+ - * | ... gap ... | / | kasan | - * | | / | zero page | - * +- vmalloc area -+ / | mapping | - * | vmalloc_size | / | (untracked) | - * +- modules vaddr -+ / +----------------+ - * | 2Gb |/ | unmapped | allocated per module - * +- shadow start -+ +----------------+ - * | 1/8 addr space | | zero pg mapping| (untracked) - * +- shadow end ----+---------+- shadow end ---+ - * - * Current memory layout (KASAN_VMALLOC): - * +- 0 -------------+ +- shadow start -+ - * |1:1 ident mapping| /|1/8 of ident map| - * | | / | | - * +-end of ident map+ / +----------------+ - * | ... gap ... | / | kasan zero page| (untracked) - * | | / | mapping | - * +- vmalloc area -+ / +----------------+ - * | vmalloc_size | / |shallow populate| - * +- modules vaddr -+ / +----------------+ - * | 2Gb |/ |shallow populate| - * +- shadow start -+ +----------------+ - * | 1/8 addr space | | zero pg mapping| (untracked) - * +- shadow end ----+---------+- shadow end ---+ - */ - /* populate kasan shadow (for identity mapping and zero page mapping) */ - for_each_mem_detect_usable_block(i, &start, &end) - kasan_early_pgtable_populate(__sha(start), __sha(end), POPULATE_MAP); - if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { - untracked_end = VMALLOC_START; - /* shallowly populate kasan shadow for vmalloc and modules */ - kasan_early_pgtable_populate(__sha(VMALLOC_START), __sha(MODULES_END), - POPULATE_SHALLOW); - } - /* populate kasan shadow for untracked memory */ - kasan_early_pgtable_populate(__sha(ident_map_size), __sha(untracked_end), - POPULATE_ZERO_SHADOW); - kasan_early_pgtable_populate(__sha(MODULES_END), __sha(_REGION1_SIZE), - POPULATE_ZERO_SHADOW); - /* enable kasan */ - init_task.kasan_depth = 0; - sclp_early_printk("KernelAddressSanitizer initialized\n"); -} diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 3327c47bc181..fc9a7dc26c5e 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -136,7 +136,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long ad info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = max(PAGE_SIZE, mmap_min_addr); + info.low_limit = PAGE_SIZE; info.high_limit = mm->mmap_base; if (filp || (flags & MAP_SHARED)) info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT; diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 85195c18b2e8..5ba3bd8a7b12 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -4,6 +4,7 @@ * Author(s): Jan Glauber */ #include +#include #include #include #include @@ -41,7 +42,7 @@ void __storage_key_init_range(unsigned long start, unsigned long end) } #ifdef CONFIG_PROC_FS -atomic_long_t direct_pages_count[PG_DIRECT_MAP_MAX]; +atomic_long_t __bootdata_preserved(direct_pages_count[PG_DIRECT_MAP_MAX]); void arch_report_meminfo(struct seq_file *m) { @@ -101,6 +102,14 @@ static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end, new = set_pte_bit(new, __pgprot(_PAGE_NOEXEC)); else if (flags & SET_MEMORY_X) new = clear_pte_bit(new, __pgprot(_PAGE_NOEXEC)); + if (flags & SET_MEMORY_INV) { + new = set_pte_bit(new, __pgprot(_PAGE_INVALID)); + } else if (flags & SET_MEMORY_DEF) { + new = __pte(pte_val(new) & PAGE_MASK); + new = set_pte_bit(new, PAGE_KERNEL); + if (!MACHINE_HAS_NX) + new = clear_pte_bit(new, __pgprot(_PAGE_NOEXEC)); + } pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE); ptep++; addr += PAGE_SIZE; @@ -151,6 +160,14 @@ static void modify_pmd_page(pmd_t *pmdp, unsigned long addr, new = set_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); else if (flags & SET_MEMORY_X) new = clear_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); + if (flags & SET_MEMORY_INV) { + new = set_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_INVALID)); + } else if (flags & SET_MEMORY_DEF) { + new = __pmd(pmd_val(new) & PMD_MASK); + new = set_pmd_bit(new, SEGMENT_KERNEL); + if (!MACHINE_HAS_NX) + new = clear_pmd_bit(new, __pgprot(_SEGMENT_ENTRY_NOEXEC)); + } pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); } @@ -232,6 +249,14 @@ static void modify_pud_page(pud_t *pudp, unsigned long addr, new = set_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); else if (flags & SET_MEMORY_X) new = clear_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); + if (flags & SET_MEMORY_INV) { + new = set_pud_bit(new, __pgprot(_REGION_ENTRY_INVALID)); + } else if (flags & SET_MEMORY_DEF) { + new = __pud(pud_val(new) & PUD_MASK); + new = set_pud_bit(new, REGION3_KERNEL); + if (!MACHINE_HAS_NX) + new = clear_pud_bit(new, __pgprot(_REGION_ENTRY_NOEXEC)); + } pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); } @@ -298,11 +323,6 @@ static int change_page_attr(unsigned long addr, unsigned long end, int rc = -EINVAL; pgd_t *pgdp; - if (addr == end) - return 0; - if (end >= MODULES_END) - return -EINVAL; - mutex_lock(&cpa_mutex); pgdp = pgd_offset_k(addr); do { if (pgd_none(*pgdp)) @@ -313,18 +333,76 @@ static int change_page_attr(unsigned long addr, unsigned long end, break; cond_resched(); } while (pgdp++, addr = next, addr < end && !rc); - mutex_unlock(&cpa_mutex); + return rc; +} + +static int change_page_attr_alias(unsigned long addr, unsigned long end, + unsigned long flags) +{ + unsigned long alias, offset, va_start, va_end; + struct vm_struct *area; + int rc = 0; + + /* + * Changes to read-only permissions on kernel VA mappings are also + * applied to the kernel direct mapping. Execute permissions are + * intentionally not transferred to keep all allocated pages within + * the direct mapping non-executable. + */ + flags &= SET_MEMORY_RO | SET_MEMORY_RW; + if (!flags) + return 0; + area = NULL; + while (addr < end) { + if (!area) + area = find_vm_area((void *)addr); + if (!area || !(area->flags & VM_ALLOC)) + return 0; + va_start = (unsigned long)area->addr; + va_end = va_start + area->nr_pages * PAGE_SIZE; + offset = (addr - va_start) >> PAGE_SHIFT; + alias = (unsigned long)page_address(area->pages[offset]); + rc = change_page_attr(alias, alias + PAGE_SIZE, flags); + if (rc) + break; + addr += PAGE_SIZE; + if (addr >= va_end) + area = NULL; + } return rc; } int __set_memory(unsigned long addr, int numpages, unsigned long flags) { + unsigned long end; + int rc; + if (!MACHINE_HAS_NX) flags &= ~(SET_MEMORY_NX | SET_MEMORY_X); if (!flags) return 0; + if (!numpages) + return 0; addr &= PAGE_MASK; - return change_page_attr(addr, addr + numpages * PAGE_SIZE, flags); + end = addr + numpages * PAGE_SIZE; + mutex_lock(&cpa_mutex); + rc = change_page_attr(addr, end, flags); + if (rc) + goto out; + rc = change_page_attr_alias(addr, end, flags); +out: + mutex_unlock(&cpa_mutex); + return rc; +} + +int set_direct_map_invalid_noflush(struct page *page) +{ + return __set_memory((unsigned long)page_to_virt(page), 1, SET_MEMORY_INV); +} + +int set_direct_map_default_noflush(struct page *page) +{ + return __set_memory((unsigned long)page_to_virt(page), 1, SET_MEMORY_DEF); } #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index 2de48b2c1b04..66ab68db9842 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -33,19 +33,9 @@ static struct ctl_table page_table_sysctl[] = { { } }; -static struct ctl_table page_table_sysctl_dir[] = { - { - .procname = "vm", - .maxlen = 0, - .mode = 0555, - .child = page_table_sysctl, - }, - { } -}; - static int __init page_table_register_sysctl(void) { - return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM; + return register_sysctl("vm", page_table_sysctl) ? 0 : -ENOMEM; } __initcall(page_table_register_sysctl); @@ -143,13 +133,7 @@ err_p4d: static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) { - unsigned int old, new; - - do { - old = atomic_read(v); - new = old ^ bits; - } while (atomic_cmpxchg(v, old, new) != old); - return new; + return atomic_fetch_xor(bits, v) ^ bits; } #ifdef CONFIG_PGSTE diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 4113a7ffa149..5b22c6e24528 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -664,6 +665,9 @@ static void __init memblock_region_swap(void *a, void *b, int size) swap(*(struct memblock_region *)a, *(struct memblock_region *)b); } +#ifdef CONFIG_KASAN +#define __sha(x) ((unsigned long)kasan_mem_to_shadow((void *)x)) +#endif /* * map whole physical memory to virtual memory (identity mapping) * we reserve enough space in the vmalloc area for vmemmap to hotplug @@ -728,23 +732,24 @@ void __init vmem_map_init(void) memblock_region_cmp, memblock_region_swap); __for_each_mem_range(i, &memblock.memory, &memory_rwx, NUMA_NO_NODE, MEMBLOCK_NONE, &base, &end, NULL) { - __set_memory((unsigned long)__va(base), - (end - base) >> PAGE_SHIFT, - SET_MEMORY_RW | SET_MEMORY_NX); + set_memory_rwnx((unsigned long)__va(base), + (end - base) >> PAGE_SHIFT); } - __set_memory((unsigned long)_stext, - (unsigned long)(_etext - _stext) >> PAGE_SHIFT, - SET_MEMORY_RO | SET_MEMORY_X); - __set_memory((unsigned long)_etext, - (unsigned long)(__end_rodata - _etext) >> PAGE_SHIFT, - SET_MEMORY_RO); - __set_memory((unsigned long)_sinittext, - (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT, - SET_MEMORY_RO | SET_MEMORY_X); - __set_memory(__stext_amode31, - (__etext_amode31 - __stext_amode31) >> PAGE_SHIFT, - SET_MEMORY_RO | SET_MEMORY_X); +#ifdef CONFIG_KASAN + for_each_mem_range(i, &base, &end) { + set_memory_rwnx(__sha(base), + (__sha(end) - __sha(base)) >> PAGE_SHIFT); + } +#endif + set_memory_rox((unsigned long)_stext, + (unsigned long)(_etext - _stext) >> PAGE_SHIFT); + set_memory_ro((unsigned long)_etext, + (unsigned long)(__end_rodata - _etext) >> PAGE_SHIFT); + set_memory_rox((unsigned long)_sinittext, + (unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT); + set_memory_rox(__stext_amode31, + (__etext_amode31 - __stext_amode31) >> PAGE_SHIFT); /* lowcore must be executable for LPSWE */ if (static_key_enabled(&cpu_has_bear)) diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index e16afacc8fd1..afc3f33788da 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -874,32 +874,15 @@ bool zpci_is_device_configured(struct zpci_dev *zdev) * @fh: The general function handle supplied by the platform * * Given a device in the configuration state Configured, enables, scans and - * adds it to the common code PCI subsystem if possible. If the PCI device is - * parked because we can not yet create a PCI bus because we have not seen - * function 0, it is ignored but will be scanned once function 0 appears. - * If any failure occurs, the zpci_dev is left disabled. + * adds it to the common code PCI subsystem if possible. If any failure occurs, + * the zpci_dev is left disabled. * * Return: 0 on success, or an error code otherwise */ int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh) { - int rc; - zpci_update_fh(zdev, fh); - /* the PCI function will be scanned once function 0 appears */ - if (!zdev->zbus->bus) - return 0; - - /* For function 0 on a multi-function bus scan whole bus as we might - * have to pick up existing functions waiting for it to allow creating - * the PCI bus - */ - if (zdev->devfn == 0 && zdev->zbus->multifunction) - rc = zpci_bus_scan_bus(zdev->zbus); - else - rc = zpci_bus_scan_device(zdev); - - return rc; + return zpci_bus_scan_device(zdev); } /** diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c index a99926af2b69..32245b970a0c 100644 --- a/arch/s390/pci/pci_bus.c +++ b/arch/s390/pci/pci_bus.c @@ -85,9 +85,8 @@ int zpci_bus_scan_device(struct zpci_dev *zdev) if (!pdev) return -ENODEV; - pci_bus_add_device(pdev); pci_lock_rescan_remove(); - pci_bus_add_devices(zdev->zbus->bus); + pci_bus_add_device(pdev); pci_unlock_rescan_remove(); return 0; @@ -130,11 +129,8 @@ void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error) * @zbus: the zbus to be scanned * * Enables and scans all PCI functions on the bus making them available to the - * common PCI code. If there is no function 0 on the zbus nothing is scanned. If - * a function does not have a slot yet because it was added to the zbus before - * function 0 the slot is created. If a PCI function fails to be initialized - * an error will be returned but attempts will still be made for all other - * functions on the bus. + * common PCI code. If a PCI function fails to be initialized an error will be + * returned but attempts will still be made for all other functions on the bus. * * Return: 0 on success, an error value otherwise */ @@ -211,7 +207,6 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s } zbus->bus = bus; - pci_bus_add_devices(bus); return 0; } diff --git a/arch/s390/purgatory/head.S b/arch/s390/purgatory/head.S index 6f835124ee82..e5bd1a503528 100644 --- a/arch/s390/purgatory/head.S +++ b/arch/s390/purgatory/head.S @@ -76,9 +76,9 @@ diag %r0,%r1,0x308 .endm -.text -.align PAGE_SIZE -ENTRY(purgatory_start) + .text + .balign PAGE_SIZE +SYM_CODE_START(purgatory_start) /* The purgatory might be called after a diag308 so better set * architecture and addressing mode. */ @@ -245,45 +245,21 @@ ENTRY(purgatory_start) /* start crash kernel */ START_NEXT_KERNEL .base_dst 1 +SYM_CODE_END(purgatory_start) - -load_psw_mask: - .long 0x00080000,0x80000000 - - .align 8 -disabled_wait_psw: - .quad 0x0002000180000000 - .quad 0x0000000000000000 + .do_checksum_verification - -gprregs: - .rept 10 - .quad 0 - .endr - -/* Macro to define a global variable with name and size (in bytes) to be - * shared with C code. - * - * Add the .size and .type attribute to satisfy checks on the Elf_Sym during - * purgatory load. - */ -.macro GLOBAL_VARIABLE name,size -\name: - .global \name - .size \name,\size - .type \name,object - .skip \size,0 -.endm - -GLOBAL_VARIABLE purgatory_sha256_digest,32 -GLOBAL_VARIABLE purgatory_sha_regions,16*__KEXEC_SHA_REGION_SIZE -GLOBAL_VARIABLE kernel_entry,8 -GLOBAL_VARIABLE kernel_type,8 -GLOBAL_VARIABLE crash_start,8 -GLOBAL_VARIABLE crash_size,8 - - .align PAGE_SIZE -stack: +SYM_DATA_LOCAL(load_psw_mask, .long 0x00080000,0x80000000) + .balign 8 +SYM_DATA_LOCAL(disabled_wait_psw, .quad 0x0002000180000000,.do_checksum_verification) +SYM_DATA_LOCAL(gprregs, .fill 10,8,0) +SYM_DATA(purgatory_sha256_digest, .skip 32) +SYM_DATA(purgatory_sha_regions, .skip 16*__KEXEC_SHA_REGION_SIZE) +SYM_DATA(kernel_entry, .skip 8) +SYM_DATA(kernel_type, .skip 8) +SYM_DATA(crash_start, .skip 8) +SYM_DATA(crash_size, .skip 8) + .balign PAGE_SIZE +SYM_DATA_START_LOCAL(stack) /* The buffer to move this code must be as big as the code. */ .skip stack-purgatory_start - .align PAGE_SIZE -purgatory_end: + .balign PAGE_SIZE +SYM_DATA_END_LABEL(stack, SYM_L_LOCAL, purgatory_end) diff --git a/arch/s390/purgatory/kexec-purgatory.S b/arch/s390/purgatory/kexec-purgatory.S index 8293753100ae..25f512b1de12 100644 --- a/arch/s390/purgatory/kexec-purgatory.S +++ b/arch/s390/purgatory/kexec-purgatory.S @@ -1,14 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include .section .rodata, "a" - .align 8 -kexec_purgatory: - .globl kexec_purgatory + .balign 8 +SYM_DATA_START(kexec_purgatory) .incbin "arch/s390/purgatory/purgatory.ro" -.Lkexec_purgatroy_end: +SYM_DATA_END_LABEL(kexec_purgatory, SYM_L_LOCAL, kexec_purgatory_end) - .align 8 -kexec_purgatory_size: - .globl kexec_purgatory_size - .quad .Lkexec_purgatroy_end - kexec_purgatory + .balign 8 +SYM_DATA(kexec_purgatory_size, .quad kexec_purgatory_end-kexec_purgatory) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index d49a5a7aa10d..9652d367fc37 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -20,6 +20,9 @@ config SUPERH select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_SHOW + select GENERIC_LIB_ASHLDI3 + select GENERIC_LIB_ASHRDI3 + select GENERIC_LIB_LSHRDI3 select GENERIC_PCI_IOMAP if PCI select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 10290e5c1f43..c449e7c1b20f 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -15,7 +15,7 @@ config SH_STANDARD_BIOS config STACK_DEBUG bool "Check for stack overflows" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && PRINTK help This option will cause messages to be printed if free stack space drops below a certain limit. Saying Y here will add overhead to diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 83bcb6d2daca..fafe15d3ba1d 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -358,7 +358,6 @@ config SH_SH2007 intended for embedded applications. It has an Ethernet interface (SMC9118), direct connected Compact Flash socket, two serial ports and PC-104 bus. - More information at . config SH_APSH4A3A bool "AP-SH4A-3A" diff --git a/arch/sh/boot/compressed/ashldi3.c b/arch/sh/boot/compressed/ashldi3.c index 7cebd646df83..7c1212170230 100644 --- a/arch/sh/boot/compressed/ashldi3.c +++ b/arch/sh/boot/compressed/ashldi3.c @@ -1,2 +1,2 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include "../../lib/ashldi3.c" +// SPDX-License-Identifier: GPL-2.0-or-later +#include "../../../../lib/ashldi3.c" diff --git a/arch/sh/configs/ecovec24_defconfig b/arch/sh/configs/ecovec24_defconfig index b52e14ccb450..4d655e8d4d74 100644 --- a/arch/sh/configs/ecovec24_defconfig +++ b/arch/sh/configs/ecovec24_defconfig @@ -8,7 +8,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_CPU_SUBTYPE_SH7724=y -CONFIG_ARCH_FORCE_MAX_ORDER=12 +CONFIG_ARCH_FORCE_MAX_ORDER=11 CONFIG_MEMORY_SIZE=0x10000000 CONFIG_FLATMEM_MANUAL=y CONFIG_SH_ECOVEC=y diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index 8ef318150f84..431bc18f0a41 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c @@ -45,13 +45,19 @@ static DEVICE_ATTR(devices, S_IRUGO, dma_show_devices, NULL); static int __init dma_subsys_init(void) { + struct device *dev_root; int ret; ret = subsys_system_register(&dma_subsys, NULL); if (unlikely(ret)) return ret; - return device_create_file(dma_subsys.dev_root, &dev_attr_devices); + dev_root = bus_get_dev_root(&dma_subsys); + if (dev_root) { + ret = device_create_file(dev_root, &dev_attr_devices); + put_device(dev_root); + } + return ret; } postcore_initcall(dma_subsys_init); diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index 4f5e49f10805..a78b9a935585 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -31,7 +31,6 @@ struct sh7786_pcie_port { static struct sh7786_pcie_port *sh7786_pcie_ports; static unsigned int nr_ports; -static unsigned long dma_pfn_offset; size_t memsize; u64 memstart; diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h index 0ed9b3f4a577..288f6f38d98f 100644 --- a/arch/sh/include/asm/cmpxchg.h +++ b/arch/sh/include/asm/cmpxchg.h @@ -22,7 +22,7 @@ extern void __xchg_called_with_bad_pointer(void); -#define __xchg(ptr, x, size) \ +#define __arch_xchg(ptr, x, size) \ ({ \ unsigned long __xchg__res; \ volatile void *__xchg_ptr = (ptr); \ @@ -46,7 +46,7 @@ extern void __xchg_called_with_bad_pointer(void); }) #define arch_xchg(ptr,x) \ - ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) + ((__typeof__(*(ptr)))__arch_xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) /* This function doesn't exist, so you'll get a linker error * if something tries to do an invalid cmpxchg(). */ diff --git a/arch/sh/include/asm/smp-ops.h b/arch/sh/include/asm/smp-ops.h index e27702130eb6..97331fcb7b85 100644 --- a/arch/sh/include/asm/smp-ops.h +++ b/arch/sh/include/asm/smp-ops.h @@ -24,9 +24,10 @@ static inline void plat_smp_setup(void) mp_ops->smp_setup(); } -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { mp_ops->play_dead(); + BUG(); } extern void register_smp_ops(struct plat_smp_ops *ops); @@ -42,7 +43,7 @@ static inline void register_smp_ops(struct plat_smp_ops *ops) { } -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { BUG(); } diff --git a/arch/sh/include/asm/types.h b/arch/sh/include/asm/types.h index 68eb24ad2013..9b3fc923ee28 100644 --- a/arch/sh/include/asm/types.h +++ b/arch/sh/include/asm/types.h @@ -2,7 +2,7 @@ #ifndef __ASM_SH_TYPES_H #define __ASM_SH_TYPES_H -#include +#include /* * These aren't exported outside the kernel to avoid name space clashes diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 27f2e3da5aa2..d289e99dc118 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -372,7 +372,6 @@ static struct subsys_interface sq_interface = { static int __init sq_api_init(void) { unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT; - unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG; int ret = -ENOMEM; printk(KERN_NOTICE "sq: Registering store queue API.\n"); @@ -382,7 +381,7 @@ static int __init sq_api_init(void) if (unlikely(!sq_cache)) return ret; - sq_bitmap = kzalloc(size, GFP_KERNEL); + sq_bitmap = bitmap_zalloc(nr_pages, GFP_KERNEL); if (unlikely(!sq_bitmap)) goto out; @@ -393,7 +392,7 @@ static int __init sq_api_init(void) return 0; out: - kfree(sq_bitmap); + bitmap_free(sq_bitmap); kmem_cache_destroy(sq_cache); return ret; @@ -402,7 +401,7 @@ out: static void __exit sq_api_exit(void) { subsys_interface_unregister(&sq_interface); - kfree(sq_bitmap); + bitmap_free(sq_bitmap); kmem_cache_destroy(sq_cache); } diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 4adbd4ade319..b603b7968b38 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S @@ -64,7 +64,7 @@ ENTRY(_stext) ldc r0, r6_bank #endif -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE mov r4, r12 ! Store device tree blob pointer in r12 #endif @@ -315,7 +315,7 @@ ENTRY(_stext) 10: #endif -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE mov.l 8f, r0 ! Make flat device tree available early. jsr @r0 mov r12, r4 @@ -346,7 +346,7 @@ ENTRY(stack_start) 5: .long start_kernel 6: .long cpu_init 7: .long init_thread_union -#if defined(CONFIG_OF_FLATTREE) +#if defined(CONFIG_OF_EARLY_FLATTREE) 8: .long sh_fdt_init #endif diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 3418c40f0099..d662503b0665 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c @@ -4,6 +4,7 @@ * * Copyright (C) 2002 - 2009 Paul Mundt */ +#include #include #include #include @@ -29,7 +30,7 @@ void default_idle(void) clear_bl_bit(); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { play_dead(); } diff --git a/arch/sh/kernel/nmi_debug.c b/arch/sh/kernel/nmi_debug.c index 11777867c6f5..a212b645b4cf 100644 --- a/arch/sh/kernel/nmi_debug.c +++ b/arch/sh/kernel/nmi_debug.c @@ -49,7 +49,7 @@ static int __init nmi_debug_setup(char *str) register_die_notifier(&nmi_debug_nb); if (*str != '=') - return 0; + return 1; for (p = str + 1; *p; p = sep + 1) { sep = strchr(p, ','); @@ -70,6 +70,6 @@ static int __init nmi_debug_setup(char *str) break; } - return 0; + return 1; } __setup("nmi_debug", nmi_debug_setup); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 1fcb6659822a..af977ec4ca5e 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -244,7 +244,7 @@ void __init __weak plat_early_device_setup(void) { } -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE void __ref sh_fdt_init(phys_addr_t dt_phys) { static int done = 0; @@ -326,7 +326,7 @@ void __init setup_arch(char **cmdline_p) /* Let earlyprintk output early console messages */ sh_early_platform_driver_probe("earlyprintk", 1, 1); -#ifdef CONFIG_OF_FLATTREE +#ifdef CONFIG_OF_EARLY_FLATTREE #ifdef CONFIG_USE_BUILTIN_DTB unflatten_and_copy_device_tree(); #else diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 65924d9ec245..5cf35a774dc7 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -256,7 +256,7 @@ void __init smp_cpus_done(unsigned int max_cpus) (bogosum / (5000/HZ)) % 100); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { mp_ops->send_ipi(cpu, SMP_MSG_RESCHEDULE); } diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index eb473d373ca4..d20a0768b31f 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile @@ -7,9 +7,7 @@ lib-y = delay.o memmove.o memchr.o \ checksum.o strlen.o div64.o div64-generic.o # Extracted from libgcc -obj-y += movmem.o ashldi3.o ashrdi3.o lshrdi3.o \ - ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o \ - udiv_qrnnd.o +obj-y += movmem.o ashlsi3.o ashrsi3.o ashiftrt.o lshrsi3.o udiv_qrnnd.o udivsi3-y := udivsi3_i4i-Os.o diff --git a/arch/sh/lib/ashldi3.c b/arch/sh/lib/ashldi3.c deleted file mode 100644 index e5afe0935847..000000000000 --- a/arch/sh/lib/ashldi3.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __ashldi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - w.s.low = 0; - w.s.high = (unsigned int) uu.s.low << -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.low >> bm; - - w.s.low = (unsigned int) uu.s.low << b; - w.s.high = ((unsigned int) uu.s.high << b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__ashldi3); diff --git a/arch/sh/lib/ashrdi3.c b/arch/sh/lib/ashrdi3.c deleted file mode 100644 index ae263fbf2538..000000000000 --- a/arch/sh/lib/ashrdi3.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __ashrdi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - /* w.s.high = 1..1 or 0..0 */ - w.s.high = - uu.s.high >> 31; - w.s.low = uu.s.high >> -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.high << bm; - - w.s.high = uu.s.high >> b; - w.s.low = ((unsigned int) uu.s.low >> b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/sh/lib/lshrdi3.c b/arch/sh/lib/lshrdi3.c deleted file mode 100644 index 33eaa1edbc3c..000000000000 --- a/arch/sh/lib/lshrdi3.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#include "libgcc.h" - -long long __lshrdi3(long long u, word_type b) -{ - DWunion uu, w; - word_type bm; - - if (b == 0) - return u; - - uu.ll = u; - bm = 32 - b; - - if (bm <= 0) { - w.s.high = 0; - w.s.low = (unsigned int) uu.s.high >> -bm; - } else { - const unsigned int carries = (unsigned int) uu.s.high << bm; - - w.s.high = (unsigned int) uu.s.high >> b; - w.s.low = ((unsigned int) uu.s.low >> b) | carries; - } - - return w.ll; -} - -EXPORT_SYMBOL(__lshrdi3); diff --git a/arch/sh/math-emu/sfp-util.h b/arch/sh/math-emu/sfp-util.h index 784f541344f3..bda50762b3d3 100644 --- a/arch/sh/math-emu/sfp-util.h +++ b/arch/sh/math-emu/sfp-util.h @@ -67,7 +67,3 @@ } while (0) #define abort() return 0 - -#define __BYTE_ORDER __LITTLE_ENDIAN - - diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 411fdc0901f7..511c17aede4a 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -19,28 +19,24 @@ config PAGE_OFFSET default "0x00000000" config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - range 9 64 if PAGE_SIZE_16KB - default "9" if PAGE_SIZE_16KB - range 7 64 if PAGE_SIZE_64KB - default "7" if PAGE_SIZE_64KB - range 11 64 - default "14" if !MMU - default "11" + int "Order of maximal physically contiguous allocations" + default "8" if PAGE_SIZE_16KB + default "6" if PAGE_SIZE_64KB + default "13" if !MMU + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. - - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. The page size is not necessarily 4KB. Keep this in mind when choosing a value for this option. + Don't change if unsure. + config MEMORY_START hex "Physical memory start address" default "0x08000000" diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index d4c1d96f85cd..8535e19062f6 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -271,18 +271,17 @@ config ARCH_SPARSEMEM_DEFAULT def_bool y if SPARC64 config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - default "13" + int "Order of maximal physically contiguous allocations" + default "12" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. - This config option is actually maximum order plus one. For example, - a value of 13 means that the largest free memory block is 2^12 pages. + Don't change if unsure. if SPARC64 || COMPILE_TEST source "kernel/power/Kconfig" diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index a4ea5b05f288..74be90529a18 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -83,18 +83,11 @@ vdso_install: KBUILD_IMAGE := $(boot)/zImage # Don't use tabs in echo arguments. -ifeq ($(ARCH),sparc) define archhelp - echo '* image - kernel image ($(boot)/image)' - echo '* zImage - stripped kernel image ($(boot)/zImage)' + echo '* vmlinux - standard SPARC kernel' + echo ' image - kernel image ($(boot)/image)' + echo '* zImage - stripped/compressed kernel image ($(boot)/zImage)' echo ' uImage - U-Boot SPARC32 Image (only for LEON)' + echo ' vmlinux.aout - a.out kernel for SPARC64' echo ' tftpboot.img - image prepared for tftp' endef -else -define archhelp - echo '* vmlinux - standard sparc64 kernel' - echo '* zImage - stripped and compressed sparc64 kernel ($(boot)/zImage)' - echo ' vmlinux.aout - a.out kernel for sparc64' - echo ' tftpboot.img - image prepared for tftp' -endef -endif diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index 27a57a3a7597..7a1339533d1d 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h @@ -15,7 +15,7 @@ unsigned long __xchg_u32(volatile u32 *m, u32 new); void __xchg_called_with_bad_pointer(void); -static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) +static inline unsigned long __arch_xchg(unsigned long x, __volatile__ void * ptr, int size) { switch (size) { case 4: @@ -25,7 +25,7 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int return x; } -#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));}) +#define arch_xchg(ptr,x) ({(__typeof__(*(ptr)))__arch_xchg((unsigned long)(x),(ptr),sizeof(*(ptr)));}) /* Emulate cmpxchg() the same way we emulate atomics, * by hashing the object address and indexing into an array diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index 12d00a42c0a3..66cd61dde9ec 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h @@ -55,7 +55,7 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long #define arch_xchg(ptr,x) \ ({ __typeof__(*(ptr)) __ret; \ __ret = (__typeof__(*(ptr))) \ - __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \ + __arch_xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \ __ret; \ }) @@ -87,8 +87,8 @@ xchg16(__volatile__ unsigned short *m, unsigned short val) return (load32 & mask) >> bit_shift; } -static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, - int size) +static inline unsigned long +__arch_xchg(unsigned long x, __volatile__ void * ptr, int size) { switch (size) { case 2: diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 7a8380c63aab..799e797c5cdd 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -185,6 +185,12 @@ static inline void finish_arch_post_lock_switch(void) } } +#define mm_untag_mask mm_untag_mask +static inline unsigned long mm_untag_mask(struct mm_struct *mm) +{ + return -1UL >> adi_nbits(); +} + #include #endif /* !(__ASSEMBLY__) */ diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 2dc8d4641734..5563efa1a19f 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -357,6 +357,42 @@ static inline pgprot_t pgprot_noncached(pgprot_t prot) */ #define pgprot_noncached pgprot_noncached +static inline unsigned long pte_dirty(pte_t pte) +{ + unsigned long mask; + + __asm__ __volatile__( + "\n661: mov %1, %0\n" + " nop\n" + " .section .sun4v_2insn_patch, \"ax\"\n" + " .word 661b\n" + " sethi %%uhi(%2), %0\n" + " sllx %0, 32, %0\n" + " .previous\n" + : "=r" (mask) + : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); + + return (pte_val(pte) & mask); +} + +static inline unsigned long pte_write(pte_t pte) +{ + unsigned long mask; + + __asm__ __volatile__( + "\n661: mov %1, %0\n" + " nop\n" + " .section .sun4v_2insn_patch, \"ax\"\n" + " .word 661b\n" + " sethi %%uhi(%2), %0\n" + " sllx %0, 32, %0\n" + " .previous\n" + : "=r" (mask) + : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); + + return (pte_val(pte) & mask); +} + #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags); #define arch_make_huge_pte arch_make_huge_pte @@ -418,28 +454,43 @@ static inline bool is_hugetlb_pte(pte_t pte) } #endif +static inline pte_t __pte_mkhwwrite(pte_t pte) +{ + unsigned long val = pte_val(pte); + + /* + * Note: we only want to set the HW writable bit if the SW writable bit + * and the SW dirty bit are set. + */ + __asm__ __volatile__( + "\n661: or %0, %2, %0\n" + " .section .sun4v_1insn_patch, \"ax\"\n" + " .word 661b\n" + " or %0, %3, %0\n" + " .previous\n" + : "=r" (val) + : "0" (val), "i" (_PAGE_W_4U), "i" (_PAGE_W_4V)); + + return __pte(val); +} + static inline pte_t pte_mkdirty(pte_t pte) { - unsigned long val = pte_val(pte), tmp; + unsigned long val = pte_val(pte), mask; __asm__ __volatile__( - "\n661: or %0, %3, %0\n" - " nop\n" - "\n662: nop\n" + "\n661: mov %1, %0\n" " nop\n" " .section .sun4v_2insn_patch, \"ax\"\n" " .word 661b\n" - " sethi %%uhi(%4), %1\n" - " sllx %1, 32, %1\n" - " .word 662b\n" - " or %1, %%lo(%4), %1\n" - " or %0, %1, %0\n" + " sethi %%uhi(%2), %0\n" + " sllx %0, 32, %0\n" " .previous\n" - : "=r" (val), "=r" (tmp) - : "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U), - "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V)); + : "=r" (mask) + : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); - return __pte(val); + pte = __pte(val | mask); + return pte_write(pte) ? __pte_mkhwwrite(pte) : pte; } static inline pte_t pte_mkclean(pte_t pte) @@ -481,7 +532,8 @@ static inline pte_t pte_mkwrite(pte_t pte) : "=r" (mask) : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); - return __pte(val | mask); + pte = __pte(val | mask); + return pte_dirty(pte) ? __pte_mkhwwrite(pte) : pte; } static inline pte_t pte_wrprotect(pte_t pte) @@ -584,42 +636,6 @@ static inline unsigned long pte_young(pte_t pte) return (pte_val(pte) & mask); } -static inline unsigned long pte_dirty(pte_t pte) -{ - unsigned long mask; - - __asm__ __volatile__( - "\n661: mov %1, %0\n" - " nop\n" - " .section .sun4v_2insn_patch, \"ax\"\n" - " .word 661b\n" - " sethi %%uhi(%2), %0\n" - " sllx %0, 32, %0\n" - " .previous\n" - : "=r" (mask) - : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); - - return (pte_val(pte) & mask); -} - -static inline unsigned long pte_write(pte_t pte) -{ - unsigned long mask; - - __asm__ __volatile__( - "\n661: mov %1, %0\n" - " nop\n" - " .section .sun4v_2insn_patch, \"ax\"\n" - " .word 661b\n" - " sethi %%uhi(%2), %0\n" - " sllx %0, 32, %0\n" - " .previous\n" - : "=r" (mask) - : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); - - return (pte_val(pte) & mask); -} - static inline unsigned long pte_exec(pte_t pte) { unsigned long mask; diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h index e75783b6abc4..505b6700805d 100644 --- a/arch/sparc/include/asm/smp_64.h +++ b/arch/sparc/include/asm/smp_64.h @@ -49,7 +49,7 @@ int hard_smp_processor_id(void); void smp_fill_in_cpu_possible_map(void); void smp_fill_in_sib_core_maps(void); -void cpu_play_dead(void); +void __noreturn cpu_play_dead(void); void smp_fetch_global_regs(void); void smp_fetch_global_pmu(void); diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index 94266a5c5b04..b825a5dd0210 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -8,8 +8,10 @@ #include #include +#include #include #include +#include #include #include diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 384480971805..7d91ca6aa675 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -193,7 +193,7 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, size = IO_PAGE_ALIGN(size); order = get_order(size); - if (unlikely(order >= MAX_ORDER)) + if (unlikely(order > MAX_ORDER)) return NULL; npages = size >> IO_PAGE_SHIFT; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 91c2b8124527..b51d8fb0ecdc 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -95,7 +95,7 @@ void arch_cpu_idle(void) } #ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { sched_preempt_enable_no_resched(); cpu_play_dead(); diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index ad8094d955eb..87eaa7719fa2 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -120,7 +120,7 @@ void cpu_panic(void) struct linux_prom_registers smp_penguin_ctable = { 0 }; -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { /* * CPU model dependent way of implementing IPI generation targeting diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index a55295d1b924..e5964d1d8b37 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1430,7 +1430,7 @@ static unsigned long send_cpu_poke(int cpu) return hv_err; } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { if (cpu == smp_processor_id()) { WARN_ON_ONCE(preemptible()); diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 5b4de4a89dec..08ffd17d5ec3 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -897,7 +897,7 @@ void __init cheetah_ecache_flush_init(void) /* Now allocate error trap reporting scoreboard. */ sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info)); - for (order = 0; order < MAX_ORDER; order++) { + for (order = 0; order <= MAX_ORDER; order++) { if ((PAGE_SIZE << order) >= sz) break; } diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 912205787161..5e2931a18409 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -402,8 +402,8 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) unsigned long new_rss_limit; gfp_t gfp_flags; - if (max_tsb_size > (PAGE_SIZE << MAX_ORDER)) - max_tsb_size = (PAGE_SIZE << MAX_ORDER); + if (max_tsb_size > PAGE_SIZE << MAX_ORDER) + max_tsb_size = PAGE_SIZE << MAX_ORDER; new_cache_index = 0; for (new_size = 8192; new_size < max_tsb_size; new_size <<= 1UL) { diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index dee6f66353b3..a461a950f051 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -16,7 +16,8 @@ mconsole-objs := mconsole_kern.o mconsole_user.o hostaudio-objs := hostaudio_kern.o ubd-objs := ubd_kern.o ubd_user.o port-objs := port_kern.o port_user.o -harddog-objs := harddog_kern.o harddog_user.o +harddog-objs := harddog_kern.o +harddog-builtin-$(CONFIG_UML_WATCHDOG) := harddog_user.o harddog_user_exp.o rtc-objs := rtc_kern.o rtc_user.o LDFLAGS_pcap.o = $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libpcap.a) @@ -60,6 +61,7 @@ obj-$(CONFIG_PTY_CHAN) += pty.o obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o +obj-y += $(harddog-builtin-y) $(harddog-builtin-m) obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-$(CONFIG_UML_RANDOM) += random.o obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o diff --git a/arch/um/drivers/harddog.h b/arch/um/drivers/harddog.h new file mode 100644 index 000000000000..6d9ea60e7133 --- /dev/null +++ b/arch/um/drivers/harddog.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef UM_WATCHDOG_H +#define UM_WATCHDOG_H + +int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); +void stop_watchdog(int in_fd, int out_fd); +int ping_watchdog(int fd); + +#endif /* UM_WATCHDOG_H */ diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index e6d4f43deba8..60d1c6cab8a9 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -47,6 +47,7 @@ #include #include #include "mconsole.h" +#include "harddog.h" MODULE_LICENSE("GPL"); @@ -60,8 +61,6 @@ static int harddog_out_fd = -1; * Allow only one person to hold it open */ -extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); - static int harddog_open(struct inode *inode, struct file *file) { int err = -EBUSY; @@ -92,8 +91,6 @@ err: return err; } -extern void stop_watchdog(int in_fd, int out_fd); - static int harddog_release(struct inode *inode, struct file *file) { /* @@ -112,8 +109,6 @@ static int harddog_release(struct inode *inode, struct file *file) return 0; } -extern int ping_watchdog(int fd); - static ssize_t harddog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index 070468d22e39..9ed89304975e 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -7,6 +7,7 @@ #include #include #include +#include "harddog.h" struct dog_data { int stdin_fd; diff --git a/arch/um/drivers/harddog_user_exp.c b/arch/um/drivers/harddog_user_exp.c new file mode 100644 index 000000000000..c74d4b815d14 --- /dev/null +++ b/arch/um/drivers/harddog_user_exp.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "harddog.h" + +#if IS_MODULE(CONFIG_UML_WATCHDOG) +EXPORT_SYMBOL(start_watchdog); +EXPORT_SYMBOL(stop_watchdog); +EXPORT_SYMBOL(ping_watchdog); +#endif diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h index 9a0bd648d872..9ec3015bc5e2 100644 --- a/arch/um/include/shared/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -23,7 +23,8 @@ #define STUB_START stub_start #define STUB_CODE STUB_START #define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE) -#define STUB_END (STUB_DATA + UM_KERN_PAGE_SIZE) +#define STUB_DATA_PAGES 1 /* must be a power of two */ +#define STUB_END (STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE) #ifndef __ASSEMBLY__ diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index ff5061f29167..62435187dda4 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -24,11 +24,12 @@ void __attribute__ ((__section__ (".__syscall_stub"))) stub_clone_handler(void) { - struct stub_data *data = get_stub_page(); + struct stub_data *data = get_stub_data(); long err; err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, - (unsigned long)data + UM_KERN_PAGE_SIZE / 2); + (unsigned long)data + + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE / 2); if (err) { data->parent_err = err; goto done; diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 125df465e8ea..656fe16c9b63 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -21,7 +21,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) unsigned long stack = 0; int ret = -ENOMEM; - stack = get_zeroed_page(GFP_KERNEL); + stack = __get_free_pages(GFP_KERNEL | __GFP_ZERO, ilog2(STUB_DATA_PAGES)); if (stack == 0) goto out; @@ -52,7 +52,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) out_free: if (to_mm->id.stack != 0) - free_page(to_mm->id.stack); + free_pages(to_mm->id.stack, ilog2(STUB_DATA_PAGES)); out: return ret; } @@ -74,6 +74,6 @@ void destroy_context(struct mm_struct *mm) } os_kill_ptraced_process(mmu->id.u.pid, 1); - free_page(mmu->id.stack); + free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES)); free_ldt(mmu); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 8dcda617b8bf..0a23a98d4ca0 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -326,9 +326,13 @@ int __init linux_main(int argc, char **argv) add_arg(DEFAULT_COMMAND_LINE_CONSOLE); host_task_size = os_get_top_address(); - /* reserve two pages for the stubs */ - host_task_size -= 2 * PAGE_SIZE; - stub_start = host_task_size; + /* reserve a few pages for the stubs (taking care of data alignment) */ + /* align the data portion */ + BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES)); + stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1); + /* another page for the code portion */ + stub_start -= PAGE_SIZE; + host_task_size = stub_start; /* * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 77a9321379b7..344ac403fb5d 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -2,7 +2,7 @@ /* * arch/um/kernel/elf_aux.c * - * Scan the Elf auxiliary vector provided by the host to extract + * Scan the ELF auxiliary vector provided by the host to extract * information about vsyscall-page, etc. * * Copyright (C) 2004 Fujitsu Siemens Computers GmbH diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index b1ea53285af1..9464833e741a 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -262,7 +262,7 @@ static int userspace_tramp(void *stack) if (stack != NULL) { fd = phys_mapping(uml_to_phys(stack), &offset); addr = mmap((void *) STUB_DATA, - UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, offset); if (addr == MAP_FAILED) { printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n", @@ -277,7 +277,7 @@ static int userspace_tramp(void *stack) (unsigned long) stub_segv_handler - (unsigned long) __syscall_stub_start; - set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); + set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; sa.sa_sigaction = (void *) v; @@ -515,7 +515,7 @@ static int __init init_thread_regs(void) thread_regs[REGS_IP_INDEX] = STUB_CODE + (unsigned long) stub_clone_handler - (unsigned long) __syscall_stub_start; - thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - + thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - sizeof(void *); #ifdef __SIGNAL_FRAMESIZE thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index fd575ecbcaec..9b62a9d352b3 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -3,112 +3,40 @@ #include #include -/* Some of this are builtin function (some are not but could in the future), - * so I *must* declare good prototypes for them and then EXPORT them. - * The kernel code uses the macro defined by include/linux/string.h, - * so I undef macros; the userspace code does not include that and I - * add an EXPORT for the glibc one. +/* + * This file exports some critical string functions and compiler + * built-in functions (where calls are emitted by the compiler + * itself that we cannot avoid even in kernel code) to modules. + * + * "_user.c" code that previously used exports here such as hostfs + * really should be considered part of the 'hypervisor' and define + * its own API boundary like hostfs does now; don't add exports to + * this file for such cases. */ -#undef strlen -#undef strstr -#undef memcpy -#undef memset - -extern size_t strlen(const char *); -extern void *memmove(void *, const void *, size_t); -extern void *memset(void *, int, size_t); -extern int printf(const char *, ...); - /* If it's not defined, the export is included in lib/string.c.*/ #ifdef __HAVE_ARCH_STRSTR +#undef strstr EXPORT_SYMBOL(strstr); #endif #ifndef __x86_64__ +#undef memcpy extern void *memcpy(void *, const void *, size_t); EXPORT_SYMBOL(memcpy); +extern void *memmove(void *, const void *, size_t); EXPORT_SYMBOL(memmove); +#undef memset +extern void *memset(void *, int, size_t); EXPORT_SYMBOL(memset); #endif -EXPORT_SYMBOL(printf); - -/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. - * However, the modules will use the CRC defined *here*, no matter if it is - * good; so the versions of these symbols will always match - */ -#define EXPORT_SYMBOL_PROTO(sym) \ - int sym(void); \ - EXPORT_SYMBOL(sym); - -extern void readdir64(void) __attribute__((weak)); -EXPORT_SYMBOL(readdir64); -extern void truncate64(void) __attribute__((weak)); -EXPORT_SYMBOL(truncate64); - #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA +/* needed for __access_ok() */ EXPORT_SYMBOL(vsyscall_ehdr); EXPORT_SYMBOL(vsyscall_end); #endif -EXPORT_SYMBOL_PROTO(__errno_location); - -EXPORT_SYMBOL_PROTO(access); -EXPORT_SYMBOL_PROTO(open); -EXPORT_SYMBOL_PROTO(open64); -EXPORT_SYMBOL_PROTO(close); -EXPORT_SYMBOL_PROTO(read); -EXPORT_SYMBOL_PROTO(write); -EXPORT_SYMBOL_PROTO(dup2); -EXPORT_SYMBOL_PROTO(__xstat); -EXPORT_SYMBOL_PROTO(__lxstat); -EXPORT_SYMBOL_PROTO(__lxstat64); -EXPORT_SYMBOL_PROTO(__fxstat64); -EXPORT_SYMBOL_PROTO(lseek); -EXPORT_SYMBOL_PROTO(lseek64); -EXPORT_SYMBOL_PROTO(chown); -EXPORT_SYMBOL_PROTO(fchown); -EXPORT_SYMBOL_PROTO(truncate); -EXPORT_SYMBOL_PROTO(ftruncate64); -EXPORT_SYMBOL_PROTO(utime); -EXPORT_SYMBOL_PROTO(utimes); -EXPORT_SYMBOL_PROTO(futimes); -EXPORT_SYMBOL_PROTO(chmod); -EXPORT_SYMBOL_PROTO(fchmod); -EXPORT_SYMBOL_PROTO(rename); -EXPORT_SYMBOL_PROTO(__xmknod); - -EXPORT_SYMBOL_PROTO(symlink); -EXPORT_SYMBOL_PROTO(link); -EXPORT_SYMBOL_PROTO(unlink); -EXPORT_SYMBOL_PROTO(readlink); - -EXPORT_SYMBOL_PROTO(mkdir); -EXPORT_SYMBOL_PROTO(rmdir); -EXPORT_SYMBOL_PROTO(opendir); -EXPORT_SYMBOL_PROTO(readdir); -EXPORT_SYMBOL_PROTO(closedir); -EXPORT_SYMBOL_PROTO(seekdir); -EXPORT_SYMBOL_PROTO(telldir); - -EXPORT_SYMBOL_PROTO(ioctl); - -EXPORT_SYMBOL_PROTO(pread64); -EXPORT_SYMBOL_PROTO(pwrite64); - -EXPORT_SYMBOL_PROTO(statfs); -EXPORT_SYMBOL_PROTO(statfs64); - -EXPORT_SYMBOL_PROTO(getuid); - -EXPORT_SYMBOL_PROTO(fsync); -EXPORT_SYMBOL_PROTO(fdatasync); - -EXPORT_SYMBOL_PROTO(lstat64); -EXPORT_SYMBOL_PROTO(fstat64); -EXPORT_SYMBOL_PROTO(mknod); - /* Export symbols used by GCC for the stack protector. */ extern void __stack_smash_handler(void *) __attribute__((weak)); EXPORT_SYMBOL(__stack_smash_handler); @@ -117,6 +45,6 @@ extern long __guard __attribute__((weak)); EXPORT_SYMBOL(__guard); #ifdef _FORTIFY_SOURCE -extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); +extern int __sprintf_chk(char *str, int flag, size_t len, const char *format); EXPORT_SYMBOL(__sprintf_chk); #endif diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index a4dfa7d7636e..a8b7d9dab0a6 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -4,8 +4,8 @@ # =========================================================================== USER_SINGLE_OBJS := \ - $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) -USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) + $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs)) +USER_OBJS += $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS:.o=.%): \ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 442eccc00960..53bab123a8ee 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -27,6 +27,7 @@ config X86_64 # Options that are inherently 64-bit kernel only: select ARCH_HAS_GIGANTIC_PAGE select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 + select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_USE_CMPXCHG_LOCKREF select HAVE_ARCH_SOFT_DIRTY select MODULES_USE_ELF_RELA @@ -125,8 +126,8 @@ config X86 select ARCH_WANTS_NO_INSTR select ARCH_WANT_GENERAL_HUGETLB select ARCH_WANT_HUGE_PMD_SHARE - select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP if X86_64 select ARCH_WANT_LD_ORPHAN_WARN + select ARCH_WANT_OPTIMIZE_VMEMMAP if X86_64 select ARCH_WANTS_THP_SWAP if X86_64 select ARCH_HAS_PARANOID_L1D_FLUSH select BUILDTIME_TABLE_SORT @@ -2289,6 +2290,17 @@ config RANDOMIZE_MEMORY_PHYSICAL_PADDING If unsure, leave at the default value. +config ADDRESS_MASKING + bool "Linear Address Masking support" + depends on X86_64 + help + Linear Address Masking (LAM) modifies the checking that is applied + to 64-bit linear addresses, allowing software to use of the + untranslated address bits for metadata. + + The capability can be used for efficient address sanitizers (ASAN) + implementation and for optimizations in JITs. + config HOTPLUG_CPU def_bool y depends on SMP diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c index 321a5011042d..bcc956c17872 100644 --- a/arch/x86/boot/compressed/ident_map_64.c +++ b/arch/x86/boot/compressed/ident_map_64.c @@ -8,14 +8,6 @@ * Copyright (C) 2016 Kees Cook */ -/* - * Since we're dealing with identity mappings, physical and virtual - * addresses are the same, so override these defines which are ultimately - * used by the headers in misc.h. - */ -#define __pa(x) ((unsigned long)(x)) -#define __va(x) ((void *)((unsigned long)(x))) - /* No PAGE_TABLE_ISOLATION support needed either: */ #undef CONFIG_PAGE_TABLE_ISOLATION diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 20118fb7c53b..2f155a0e3041 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -19,6 +19,15 @@ /* cpu_feature_enabled() cannot be used this early */ #define USE_EARLY_PGTABLE_L5 +/* + * Boot stub deals with identity mappings, physical and virtual addresses are + * the same, so override these defines. + * + * will not define them if they are already defined. + */ +#define __pa(x) ((unsigned long)(x)) +#define __va(x) ((void *)((unsigned long)(x))) + #include #include #include diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c index d63ad8f99f83..014b89c89088 100644 --- a/arch/x86/boot/compressed/sev.c +++ b/arch/x86/boot/compressed/sev.c @@ -104,9 +104,7 @@ static enum es_result vc_read_mem(struct es_em_ctxt *ctxt, } #undef __init -#undef __pa #define __init -#define __pa(x) ((unsigned long)(x)) #define __BOOT_COMPRESSED diff --git a/arch/x86/boot/compressed/tdx.c b/arch/x86/boot/compressed/tdx.c index 918a7606f53c..2d81d3cc72a1 100644 --- a/arch/x86/boot/compressed/tdx.c +++ b/arch/x86/boot/compressed/tdx.c @@ -26,7 +26,7 @@ static inline unsigned int tdx_io_in(int size, u16 port) .r14 = port, }; - if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) + if (__tdx_hypercall_ret(&args)) return UINT_MAX; return args.r11; @@ -43,7 +43,7 @@ static inline void tdx_io_out(int size, u16 port, u32 value) .r15 = value, }; - __tdx_hypercall(&args, 0); + __tdx_hypercall(&args); } static inline u8 tdx_inb(u16 port) diff --git a/arch/x86/coco/tdx/tdcall.S b/arch/x86/coco/tdx/tdcall.S index 6a255e6809bc..b193c0a1d8db 100644 --- a/arch/x86/coco/tdx/tdcall.S +++ b/arch/x86/coco/tdx/tdcall.S @@ -85,12 +85,12 @@ SYM_FUNC_START(__tdx_module_call) SYM_FUNC_END(__tdx_module_call) /* - * __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf - * of TDCALL instruction + * TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL + * instruction * * Transforms values in function call argument struct tdx_hypercall_args @args * into the TDCALL register ABI. After TDCALL operation, VMM output is saved - * back in @args. + * back in @args, if \ret is 1. * *------------------------------------------------------------------------- * TD VMCALL ABI: @@ -105,26 +105,18 @@ SYM_FUNC_END(__tdx_module_call) * specification. Non zero value indicates vendor * specific ABI. * R11 - VMCALL sub function number - * RBX, RBP, RDI, RSI - Used to pass VMCALL sub function specific arguments. + * RBX, RDX, RDI, RSI - Used to pass VMCALL sub function specific arguments. * R8-R9, R12-R15 - Same as above. * * Output Registers: * * RAX - TDCALL instruction status (Not related to hypercall * output). - * R10 - Hypercall output error code. - * R11-R15 - Hypercall sub function specific output values. + * RBX, RDX, RDI, RSI - Hypercall sub function specific output values. + * R8-R15 - Same as above. * - *------------------------------------------------------------------------- - * - * __tdx_hypercall() function ABI: - * - * @args (RDI) - struct tdx_hypercall_args for input and output - * @flags (RSI) - TDX_HCALL_* flags - * - * On successful completion, return the hypercall error code. */ -SYM_FUNC_START(__tdx_hypercall) +.macro TDX_HYPERCALL ret:req FRAME_BEGIN /* Save callee-saved GPRs as mandated by the x86_64 ABI */ @@ -134,9 +126,8 @@ SYM_FUNC_START(__tdx_hypercall) push %r12 push %rbx - /* Free RDI and RSI to be used as TDVMCALL arguments */ + /* Free RDI to be used as TDVMCALL arguments */ movq %rdi, %rax - push %rsi /* Copy hypercall registers from arg struct: */ movq TDX_HYPERCALL_r8(%rax), %r8 @@ -171,14 +162,11 @@ SYM_FUNC_START(__tdx_hypercall) * and are handled by callers. */ testq %rax, %rax - jne .Lpanic + jne .Lpanic\@ pop %rax - /* Copy hypercall result registers to arg struct if needed */ - testq $TDX_HCALL_HAS_OUTPUT, (%rsp) - jz .Lout - + .if \ret movq %r8, TDX_HYPERCALL_r8(%rax) movq %r9, TDX_HYPERCALL_r9(%rax) movq %r10, TDX_HYPERCALL_r10(%rax) @@ -191,7 +179,8 @@ SYM_FUNC_START(__tdx_hypercall) movq %rsi, TDX_HYPERCALL_rsi(%rax) movq %rbx, TDX_HYPERCALL_rbx(%rax) movq %rdx, TDX_HYPERCALL_rdx(%rax) -.Lout: + .endif + /* TDVMCALL leaf return code is in R10 */ movq %r10, %rax @@ -208,9 +197,6 @@ SYM_FUNC_START(__tdx_hypercall) xor %rdi, %rdi xor %rdx, %rdx - /* Remove TDX_HCALL_* flags from the stack */ - pop %rsi - /* Restore callee-saved GPRs as mandated by the x86_64 ABI */ pop %rbx pop %r12 @@ -221,9 +207,33 @@ SYM_FUNC_START(__tdx_hypercall) FRAME_END RET -.Lpanic: +.Lpanic\@: call __tdx_hypercall_failed /* __tdx_hypercall_failed never returns */ REACHABLE - jmp .Lpanic + jmp .Lpanic\@ +.endm + +/* + * + * __tdx_hypercall() function ABI: + * + * @args (RDI) - struct tdx_hypercall_args for input + * + * On successful completion, return the hypercall error code. + */ +SYM_FUNC_START(__tdx_hypercall) + TDX_HYPERCALL ret=0 SYM_FUNC_END(__tdx_hypercall) + +/* + * + * __tdx_hypercall_ret() function ABI: + * + * @args (RDI) - struct tdx_hypercall_args for input and output + * + * On successful completion, return the hypercall error code. + */ +SYM_FUNC_START(__tdx_hypercall_ret) + TDX_HYPERCALL ret=1 +SYM_FUNC_END(__tdx_hypercall_ret) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 055300e08fb3..e146b599260f 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -66,7 +66,7 @@ static inline u64 _tdx_hypercall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15) .r15 = r15, }; - return __tdx_hypercall(&args, 0); + return __tdx_hypercall(&args); } /* Called from __tdx_hypercall() for unrecoverable failure */ @@ -99,7 +99,7 @@ long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, unsigned long p2, .r14 = p4, }; - return __tdx_hypercall(&args, 0); + return __tdx_hypercall(&args); } EXPORT_SYMBOL_GPL(tdx_kvm_hypercall); #endif @@ -179,7 +179,7 @@ static void __noreturn tdx_panic(const char *msg) * happens to return. */ while (1) - __tdx_hypercall(&args, 0); + __tdx_hypercall(&args); } static void tdx_parse_tdinfo(u64 *cc_mask) @@ -289,7 +289,7 @@ static u64 __cpuidle __halt(const bool irq_disabled) * can keep the vCPU in virtual HLT, even if an IRQ is * pending, without hanging/breaking the guest. */ - return __tdx_hypercall(&args, 0); + return __tdx_hypercall(&args); } static int handle_halt(struct ve_info *ve) @@ -326,7 +326,7 @@ static int read_msr(struct pt_regs *regs, struct ve_info *ve) * can be found in TDX Guest-Host-Communication Interface * (GHCI), section titled "TDG.VP.VMCALL". */ - if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) + if (__tdx_hypercall_ret(&args)) return -EIO; regs->ax = lower_32_bits(args.r11); @@ -348,7 +348,7 @@ static int write_msr(struct pt_regs *regs, struct ve_info *ve) * can be found in TDX Guest-Host-Communication Interface * (GHCI) section titled "TDG.VP.VMCALL". */ - if (__tdx_hypercall(&args, 0)) + if (__tdx_hypercall(&args)) return -EIO; return ve_instr_len(ve); @@ -380,7 +380,7 @@ static int handle_cpuid(struct pt_regs *regs, struct ve_info *ve) * ABI can be found in TDX Guest-Host-Communication Interface * (GHCI), section titled "VP.VMCALL". */ - if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) + if (__tdx_hypercall_ret(&args)) return -EIO; /* @@ -407,7 +407,7 @@ static bool mmio_read(int size, unsigned long addr, unsigned long *val) .r15 = *val, }; - if (__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT)) + if (__tdx_hypercall_ret(&args)) return false; *val = args.r11; return true; @@ -541,7 +541,7 @@ static bool handle_in(struct pt_regs *regs, int size, int port) * in TDX Guest-Host-Communication Interface (GHCI) section titled * "TDG.VP.VMCALL". */ - success = !__tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT); + success = !__tdx_hypercall_ret(&args); /* Update part of the register affected by the emulated instruction */ regs->ax &= ~mask; diff --git a/arch/x86/crypto/aria-aesni-avx-asm_64.S b/arch/x86/crypto/aria-aesni-avx-asm_64.S index 7c1abc513f34..9556dacd9841 100644 --- a/arch/x86/crypto/aria-aesni-avx-asm_64.S +++ b/arch/x86/crypto/aria-aesni-avx-asm_64.S @@ -773,8 +773,6 @@ .octa 0x3F893781E95FE1576CDA64D2BA0CB204 #ifdef CONFIG_AS_GFNI -.section .rodata.cst8, "aM", @progbits, 8 -.align 8 /* AES affine: */ #define tf_aff_const BV8(1, 1, 0, 0, 0, 1, 1, 0) .Ltf_aff_bitmatrix: diff --git a/arch/x86/crypto/blake2s-glue.c b/arch/x86/crypto/blake2s-glue.c index aaba21230528..0313f9673f56 100644 --- a/arch/x86/crypto/blake2s-glue.c +++ b/arch/x86/crypto/blake2s-glue.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -72,6 +71,4 @@ static int __init blake2s_mod_init(void) return 0; } -module_init(blake2s_mod_init); - -MODULE_LICENSE("GPL v2"); +subsys_initcall(blake2s_mod_init); diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index d94d361f506f..f31e286c2977 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -205,7 +205,7 @@ syscall_return_via_sysret: */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK pushq RSP-RDI(%rdi) /* RSP */ pushq (%rdi) /* RDI */ @@ -286,7 +286,7 @@ SYM_FUNC_END(__switch_to_asm) .pushsection .text, "ax" __FUNC_ALIGN SYM_CODE_START_NOALIGN(ret_from_fork) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // copy_thread CALL_DEPTH_ACCOUNT movq %rax, %rdi @@ -303,7 +303,7 @@ SYM_CODE_START_NOALIGN(ret_from_fork) 1: /* kernel thread */ - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK movq %r12, %rdi CALL_NOSPEC rbx /* @@ -388,9 +388,9 @@ SYM_CODE_START(\asmsym) .if \vector == X86_TRAP_BP /* #BP advances %rip to the next instruction */ - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 signal=0 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 signal=0 .else - UNWIND_HINT_IRET_REGS offset=\has_error_code*8 + UNWIND_HINT_IRET_ENTRY offset=\has_error_code*8 .endif ENDBR @@ -461,7 +461,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_mce_db vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld @@ -518,7 +518,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_vc vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR ASM_CLAC cld @@ -582,7 +582,7 @@ SYM_CODE_END(\asmsym) */ .macro idtentry_df vector asmsym cfunc SYM_CODE_START(\asmsym) - UNWIND_HINT_IRET_REGS offset=8 + UNWIND_HINT_IRET_ENTRY offset=8 ENDBR ASM_CLAC cld @@ -643,7 +643,7 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) */ movq %rsp, %rdi movq PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Copy the IRET frame to the trampoline stack. */ pushq 6*8(%rdi) /* SS */ @@ -869,7 +869,7 @@ SYM_CODE_END(exc_xen_hypervisor_callback) */ __FUNC_ALIGN SYM_CODE_START_NOALIGN(xen_failsafe_callback) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR movl %ds, %ecx cmpw %cx, 0x10(%rsp) @@ -1027,7 +1027,7 @@ SYM_CODE_START_LOCAL(paranoid_exit) * * NB to anyone to try to optimize this code: this code does * not execute at all for exceptions from user mode. Those - * exceptions go through error_exit instead. + * exceptions go through error_return instead. */ RESTORE_CR3 scratch_reg=%rax save_reg=%r14 @@ -1107,7 +1107,7 @@ SYM_CODE_START(error_entry) FENCE_SWAPGS_KERNEL_ENTRY CALL_DEPTH_ACCOUNT leaq 8(%rsp), %rax /* return pt_regs pointer */ - ANNOTATE_UNRET_END + VALIDATE_UNRET_END RET .Lbstep_iret: @@ -1153,7 +1153,7 @@ SYM_CODE_END(error_return) * when PAGE_TABLE_ISOLATION is in use. Do not clobber. */ SYM_CODE_START(asm_exc_nmi) - UNWIND_HINT_IRET_REGS + UNWIND_HINT_IRET_ENTRY ENDBR /* @@ -1520,7 +1520,7 @@ SYM_CODE_END(asm_exc_nmi) * MSRs to fully disable 32-bit SYSCALL. */ SYM_CODE_START(ignore_sysret) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR mov $-ENOSYS, %eax sysretl diff --git a/arch/x86/entry/vdso/vdso32-setup.c b/arch/x86/entry/vdso/vdso32-setup.c index 3b300a773c7e..f3b3cacbcbb0 100644 --- a/arch/x86/entry/vdso/vdso32-setup.c +++ b/arch/x86/entry/vdso/vdso32-setup.c @@ -70,18 +70,9 @@ static struct ctl_table abi_table2[] = { {} }; -static struct ctl_table abi_root_table2[] = { - { - .procname = "abi", - .mode = 0555, - .child = abi_table2 - }, - {} -}; - static __init int ia32_binfmt_init(void) { - register_sysctl_table(abi_root_table2); + register_sysctl("abi", abi_table2); return 0; } __initcall(ia32_binfmt_init); diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index d234ca797e4a..e0ca8120aea8 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -317,7 +317,7 @@ static struct vm_area_struct gate_vma __ro_after_init = { struct vm_area_struct *get_gate_vma(struct mm_struct *mm) { #ifdef CONFIG_COMPAT - if (!mm || !(mm->context.flags & MM_CONTEXT_HAS_VSYSCALL)) + if (!mm || !test_bit(MM_CONTEXT_HAS_VSYSCALL, &mm->context.flags)) return NULL; #endif if (vsyscall_mode == NONE) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index d096b04bf80e..9d248703cbdd 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1703,10 +1703,8 @@ int x86_pmu_handle_irq(struct pt_regs *regs) perf_sample_data_init(&data, 0, event->hw.last_period); - if (has_branch_stack(event)) { - data.br_stack = &cpuc->lbr_stack; - data.sample_flags |= PERF_SAMPLE_BRANCH_STACK; - } + if (has_branch_stack(event)) + perf_sample_save_brstack(&data, event, &cpuc->lbr_stack); if (perf_event_overflow(event, &data, regs)) x86_pmu_stop(event, 0); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index a3fb996a86a1..89b9c1cebb61 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4074,7 +4074,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) if (x86_pmu.intel_cap.pebs_baseline) { arr[(*nr)++] = (struct perf_guest_switch_msr){ .msr = MSR_PEBS_DATA_CFG, - .host = cpuc->pebs_data_cfg, + .host = cpuc->active_pebs_data_cfg, .guest = kvm_pmu->pebs_data_cfg, }; } @@ -5469,6 +5469,15 @@ pebs_is_visible(struct kobject *kobj, struct attribute *attr, int i) return x86_pmu.pebs ? attr->mode : 0; } +static umode_t +mem_is_visible(struct kobject *kobj, struct attribute *attr, int i) +{ + if (attr == &event_attr_mem_ld_aux.attr.attr) + return x86_pmu.flags & PMU_FL_MEM_LOADS_AUX ? attr->mode : 0; + + return pebs_is_visible(kobj, attr, i); +} + static umode_t lbr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { @@ -5496,7 +5505,7 @@ static struct attribute_group group_events_td = { static struct attribute_group group_events_mem = { .name = "events", - .is_visible = pebs_is_visible, + .is_visible = mem_is_visible, }; static struct attribute_group group_events_tsx = { @@ -6486,6 +6495,10 @@ __init int intel_pmu_init(void) case INTEL_FAM6_SAPPHIRERAPIDS_X: case INTEL_FAM6_EMERALDRAPIDS_X: + x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX; + fallthrough; + case INTEL_FAM6_GRANITERAPIDS_X: + case INTEL_FAM6_GRANITERAPIDS_D: pmem = true; x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, spr_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -6502,7 +6515,6 @@ __init int intel_pmu_init(void) x86_pmu.flags |= PMU_FL_HAS_RSP_1; x86_pmu.flags |= PMU_FL_NO_HT_SHARING; x86_pmu.flags |= PMU_FL_INSTR_LATENCY; - x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX; x86_pmu.hw_config = hsw_hw_config; x86_pmu.get_event_constraints = spr_get_event_constraints; diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 551741e79e03..835862c548cc 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -678,6 +678,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &icx_cstates), X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &icx_cstates), X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &icx_cstates), + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X, &icx_cstates), + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_D, &icx_cstates), X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &icl_cstates), X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &icl_cstates), diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index a2e566e53076..df88576d6b2a 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1229,12 +1229,14 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, struct perf_event *event, bool add) { struct pmu *pmu = event->pmu; + /* * Make sure we get updated with the first PEBS * event. It will trigger also during removal, but * that does not hurt: */ - bool update = cpuc->n_pebs == 1; + if (cpuc->n_pebs == 1) + cpuc->pebs_data_cfg = PEBS_UPDATE_DS_SW; if (needed_cb != pebs_needs_sched_cb(cpuc)) { if (!needed_cb) @@ -1242,7 +1244,7 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, else perf_sched_cb_dec(pmu); - update = true; + cpuc->pebs_data_cfg |= PEBS_UPDATE_DS_SW; } /* @@ -1252,24 +1254,13 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, if (x86_pmu.intel_cap.pebs_baseline && add) { u64 pebs_data_cfg; - /* Clear pebs_data_cfg and pebs_record_size for first PEBS. */ - if (cpuc->n_pebs == 1) { - cpuc->pebs_data_cfg = 0; - cpuc->pebs_record_size = sizeof(struct pebs_basic); - } - pebs_data_cfg = pebs_update_adaptive_cfg(event); - - /* Update pebs_record_size if new event requires more data. */ - if (pebs_data_cfg & ~cpuc->pebs_data_cfg) { - cpuc->pebs_data_cfg |= pebs_data_cfg; - adaptive_pebs_record_size_update(); - update = true; - } + /* + * Be sure to update the thresholds when we change the record. + */ + if (pebs_data_cfg & ~cpuc->pebs_data_cfg) + cpuc->pebs_data_cfg |= pebs_data_cfg | PEBS_UPDATE_DS_SW; } - - if (update) - pebs_update_threshold(cpuc); } void intel_pmu_pebs_add(struct perf_event *event) @@ -1326,9 +1317,17 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event) wrmsrl(base + idx, value); } +static inline void intel_pmu_drain_large_pebs(struct cpu_hw_events *cpuc) +{ + if (cpuc->n_pebs == cpuc->n_large_pebs && + cpuc->n_pebs != cpuc->n_pebs_via_pt) + intel_pmu_drain_pebs_buffer(); +} + void intel_pmu_pebs_enable(struct perf_event *event) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + u64 pebs_data_cfg = cpuc->pebs_data_cfg & ~PEBS_UPDATE_DS_SW; struct hw_perf_event *hwc = &event->hw; struct debug_store *ds = cpuc->ds; unsigned int idx = hwc->idx; @@ -1344,11 +1343,22 @@ void intel_pmu_pebs_enable(struct perf_event *event) if (x86_pmu.intel_cap.pebs_baseline) { hwc->config |= ICL_EVENTSEL_ADAPTIVE; - if (cpuc->pebs_data_cfg != cpuc->active_pebs_data_cfg) { - wrmsrl(MSR_PEBS_DATA_CFG, cpuc->pebs_data_cfg); - cpuc->active_pebs_data_cfg = cpuc->pebs_data_cfg; + if (pebs_data_cfg != cpuc->active_pebs_data_cfg) { + /* + * drain_pebs() assumes uniform record size; + * hence we need to drain when changing said + * size. + */ + intel_pmu_drain_large_pebs(cpuc); + adaptive_pebs_record_size_update(); + wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg); + cpuc->active_pebs_data_cfg = pebs_data_cfg; } } + if (cpuc->pebs_data_cfg & PEBS_UPDATE_DS_SW) { + cpuc->pebs_data_cfg = pebs_data_cfg; + pebs_update_threshold(cpuc); + } if (idx >= INTEL_PMC_IDX_FIXED) { if (x86_pmu.intel_cap.pebs_format < 5) @@ -1391,9 +1401,7 @@ void intel_pmu_pebs_disable(struct perf_event *event) struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; - if (cpuc->n_pebs == cpuc->n_large_pebs && - cpuc->n_pebs != cpuc->n_pebs_via_pt) - intel_pmu_drain_pebs_buffer(); + intel_pmu_drain_large_pebs(cpuc); cpuc->pebs_enabled &= ~(1ULL << hwc->idx); diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index 7d1199554fe3..d49e90dc04a4 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -6068,6 +6068,17 @@ static struct intel_uncore_ops spr_uncore_mmio_ops = { .read_counter = uncore_mmio_read_counter, }; +static struct uncore_event_desc spr_uncore_imc_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x01,umask=0x00"), + INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x05,umask=0xcf"), + INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"), + INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"), + INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x05,umask=0xf0"), + INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"), + INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"), + { /* end: all zeroes */ }, +}; + static struct intel_uncore_type spr_uncore_imc = { SPR_UNCORE_COMMON_FORMAT(), .name = "imc", @@ -6075,6 +6086,7 @@ static struct intel_uncore_type spr_uncore_imc = { .fixed_ctr = SNR_IMC_MMIO_PMON_FIXED_CTR, .fixed_ctl = SNR_IMC_MMIO_PMON_FIXED_CTL, .ops = &spr_uncore_mmio_ops, + .event_descs = spr_uncore_imc_events, }; static void spr_uncore_pci_enable_event(struct intel_uncore_box *box, @@ -6138,6 +6150,7 @@ static struct intel_uncore_type spr_uncore_mdf = { }; #define UNCORE_SPR_NUM_UNCORE_TYPES 12 +#define UNCORE_SPR_CHA 0 #define UNCORE_SPR_IIO 1 #define UNCORE_SPR_IMC 6 #define UNCORE_SPR_UPI 8 @@ -6448,12 +6461,22 @@ static int uncore_type_max_boxes(struct intel_uncore_type **types, return max + 1; } +#define SPR_MSR_UNC_CBO_CONFIG 0x2FFE + void spr_uncore_cpu_init(void) { + struct intel_uncore_type *type; + u64 num_cbo; + uncore_msr_uncores = uncore_get_uncores(UNCORE_ACCESS_MSR, UNCORE_SPR_MSR_EXTRA_UNCORES, spr_msr_uncores); + type = uncore_find_type_by_id(uncore_msr_uncores, UNCORE_SPR_CHA); + if (type) { + rdmsrl(SPR_MSR_UNC_CBO_CONFIG, num_cbo); + type->num_boxes = num_cbo; + } spr_uncore_iio_free_running.num_boxes = uncore_type_max_boxes(uncore_msr_uncores, UNCORE_SPR_IIO); } diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index c65d8906cbcf..0feaaa571303 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -70,6 +70,8 @@ static bool test_intel(int idx, void *data) case INTEL_FAM6_BROADWELL_X: case INTEL_FAM6_SAPPHIRERAPIDS_X: case INTEL_FAM6_EMERALDRAPIDS_X: + case INTEL_FAM6_GRANITERAPIDS_X: + case INTEL_FAM6_GRANITERAPIDS_D: case INTEL_FAM6_ATOM_SILVERMONT: case INTEL_FAM6_ATOM_SILVERMONT_D: diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile index 5d2de10809ae..3a1548054b48 100644 --- a/arch/x86/hyperv/Makefile +++ b/arch/x86/hyperv/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o +obj-$(CONFIG_HYPERV_VTL_MODE) += hv_vtl.o ifdef CONFIG_X86_64 obj-$(CONFIG_PARAVIRT_SPINLOCKS) += hv_spinlock.o diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index fb8b2c088681..1fbda2f94184 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -96,6 +96,11 @@ static void hv_apic_eoi_write(u32 reg, u32 val) wrmsr(HV_X64_MSR_EOI, val, 0); } +static bool cpu_is_self(int cpu) +{ + return cpu == smp_processor_id(); +} + /* * IPI implementation on Hyper-V. */ @@ -128,10 +133,9 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, */ if (!cpumask_equal(mask, cpu_present_mask) || exclude_self) { ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K; - if (exclude_self) - nr_bank = cpumask_to_vpset_noself(&(ipi_arg->vp_set), mask); - else - nr_bank = cpumask_to_vpset(&(ipi_arg->vp_set), mask); + + nr_bank = cpumask_to_vpset_skip(&(ipi_arg->vp_set), mask, + exclude_self ? cpu_is_self : NULL); /* * 'nr_bank <= 0' means some CPUs in cpumask can't be diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index edbc67ec1f3e..a5f9474f08e1 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -63,7 +63,10 @@ static int hyperv_init_ghcb(void) * memory boundary and map it here. */ rdmsrl(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa); - ghcb_va = memremap(ghcb_gpa, HV_HYP_PAGE_SIZE, MEMREMAP_WB); + + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + ghcb_gpa &= ~ms_hyperv.shared_gpa_boundary; + ghcb_va = (void *)ioremap_cache(ghcb_gpa, HV_HYP_PAGE_SIZE); if (!ghcb_va) return -ENOMEM; @@ -217,7 +220,7 @@ static int hv_cpu_die(unsigned int cpu) if (hv_ghcb_pg) { ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg); if (*ghcb_va) - memunmap(*ghcb_va); + iounmap(*ghcb_va); *ghcb_va = NULL; } diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c new file mode 100644 index 000000000000..1ba5d3b99b16 --- /dev/null +++ b/arch/x86/hyperv/hv_vtl.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Microsoft Corporation. + * + * Author: + * Saurabh Sengar + */ + +#include +#include +#include +#include +#include +#include + +extern struct boot_params boot_params; +static struct real_mode_header hv_vtl_real_mode_header; + +void __init hv_vtl_init_platform(void) +{ + pr_info("Linux runs in Hyper-V Virtual Trust Level\n"); + + x86_init.irqs.pre_vector_init = x86_init_noop; + x86_init.timers.timer_init = x86_init_noop; + + x86_platform.get_wallclock = get_rtc_noop; + x86_platform.set_wallclock = set_rtc_noop; + x86_platform.get_nmi_reason = hv_get_nmi_reason; + + x86_platform.legacy.i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT; + x86_platform.legacy.rtc = 0; + x86_platform.legacy.warm_reset = 0; + x86_platform.legacy.reserve_bios_regions = 0; + x86_platform.legacy.devices.pnpbios = 0; +} + +static inline u64 hv_vtl_system_desc_base(struct ldttss_desc *desc) +{ + return ((u64)desc->base3 << 32) | ((u64)desc->base2 << 24) | + (desc->base1 << 16) | desc->base0; +} + +static inline u32 hv_vtl_system_desc_limit(struct ldttss_desc *desc) +{ + return ((u32)desc->limit1 << 16) | (u32)desc->limit0; +} + +typedef void (*secondary_startup_64_fn)(void*, void*); +static void hv_vtl_ap_entry(void) +{ + ((secondary_startup_64_fn)secondary_startup_64)(&boot_params, &boot_params); +} + +static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) +{ + u64 status; + int ret = 0; + struct hv_enable_vp_vtl *input; + unsigned long irq_flags; + + struct desc_ptr gdt_ptr; + struct desc_ptr idt_ptr; + + struct ldttss_desc *tss; + struct ldttss_desc *ldt; + struct desc_struct *gdt; + + u64 rsp = current->thread.sp; + u64 rip = (u64)&hv_vtl_ap_entry; + + native_store_gdt(&gdt_ptr); + store_idt(&idt_ptr); + + gdt = (struct desc_struct *)((void *)(gdt_ptr.address)); + tss = (struct ldttss_desc *)(gdt + GDT_ENTRY_TSS); + ldt = (struct ldttss_desc *)(gdt + GDT_ENTRY_LDT); + + local_irq_save(irq_flags); + + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(input, 0, sizeof(*input)); + + input->partition_id = HV_PARTITION_ID_SELF; + input->vp_index = target_vp_index; + input->target_vtl.target_vtl = HV_VTL_MGMT; + + /* + * The x86_64 Linux kernel follows the 16-bit -> 32-bit -> 64-bit + * mode transition sequence after waking up an AP with SIPI whose + * vector points to the 16-bit AP startup trampoline code. Here in + * VTL2, we can't perform that sequence as the AP has to start in + * the 64-bit mode. + * + * To make this happen, we tell the hypervisor to load a valid 64-bit + * context (most of which is just magic numbers from the CPU manual) + * so that AP jumps right to the 64-bit entry of the kernel, and the + * control registers are loaded with values that let the AP fetch the + * code and data and carry on with work it gets assigned. + */ + + input->vp_context.rip = rip; + input->vp_context.rsp = rsp; + input->vp_context.rflags = 0x0000000000000002; + input->vp_context.efer = __rdmsr(MSR_EFER); + input->vp_context.cr0 = native_read_cr0(); + input->vp_context.cr3 = __native_read_cr3(); + input->vp_context.cr4 = native_read_cr4(); + input->vp_context.msr_cr_pat = __rdmsr(MSR_IA32_CR_PAT); + input->vp_context.idtr.limit = idt_ptr.size; + input->vp_context.idtr.base = idt_ptr.address; + input->vp_context.gdtr.limit = gdt_ptr.size; + input->vp_context.gdtr.base = gdt_ptr.address; + + /* Non-system desc (64bit), long, code, present */ + input->vp_context.cs.selector = __KERNEL_CS; + input->vp_context.cs.base = 0; + input->vp_context.cs.limit = 0xffffffff; + input->vp_context.cs.attributes = 0xa09b; + /* Non-system desc (64bit), data, present, granularity, default */ + input->vp_context.ss.selector = __KERNEL_DS; + input->vp_context.ss.base = 0; + input->vp_context.ss.limit = 0xffffffff; + input->vp_context.ss.attributes = 0xc093; + + /* System desc (128bit), present, LDT */ + input->vp_context.ldtr.selector = GDT_ENTRY_LDT * 8; + input->vp_context.ldtr.base = hv_vtl_system_desc_base(ldt); + input->vp_context.ldtr.limit = hv_vtl_system_desc_limit(ldt); + input->vp_context.ldtr.attributes = 0x82; + + /* System desc (128bit), present, TSS, 0x8b - busy, 0x89 -- default */ + input->vp_context.tr.selector = GDT_ENTRY_TSS * 8; + input->vp_context.tr.base = hv_vtl_system_desc_base(tss); + input->vp_context.tr.limit = hv_vtl_system_desc_limit(tss); + input->vp_context.tr.attributes = 0x8b; + + status = hv_do_hypercall(HVCALL_ENABLE_VP_VTL, input, NULL); + + if (!hv_result_success(status) && + hv_result(status) != HV_STATUS_VTL_ALREADY_ENABLED) { + pr_err("HVCALL_ENABLE_VP_VTL failed for VP : %d ! [Err: %#llx\n]", + target_vp_index, status); + ret = -EINVAL; + goto free_lock; + } + + status = hv_do_hypercall(HVCALL_START_VP, input, NULL); + + if (!hv_result_success(status)) { + pr_err("HVCALL_START_VP failed for VP : %d ! [Err: %#llx]\n", + target_vp_index, status); + ret = -EINVAL; + } + +free_lock: + local_irq_restore(irq_flags); + + return ret; +} + +static int hv_vtl_apicid_to_vp_id(u32 apic_id) +{ + u64 control; + u64 status; + unsigned long irq_flags; + struct hv_get_vp_from_apic_id_in *input; + u32 *output, ret; + + local_irq_save(irq_flags); + + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(input, 0, sizeof(*input)); + input->partition_id = HV_PARTITION_ID_SELF; + input->apic_ids[0] = apic_id; + + output = (u32 *)input; + + control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_ID_FROM_APIC_ID; + status = hv_do_hypercall(control, input, output); + ret = output[0]; + + local_irq_restore(irq_flags); + + if (!hv_result_success(status)) { + pr_err("failed to get vp id from apic id %d, status %#llx\n", + apic_id, status); + return -EINVAL; + } + + return ret; +} + +static int hv_vtl_wakeup_secondary_cpu(int apicid, unsigned long start_eip) +{ + int vp_id; + + pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid); + vp_id = hv_vtl_apicid_to_vp_id(apicid); + + if (vp_id < 0) { + pr_err("Couldn't find CPU with APIC ID %d\n", apicid); + return -EINVAL; + } + if (vp_id > ms_hyperv.max_vp_index) { + pr_err("Invalid CPU id %d for APIC ID %d\n", vp_id, apicid); + return -EINVAL; + } + + return hv_vtl_bringup_vcpu(vp_id, start_eip); +} + +static int __init hv_vtl_early_init(void) +{ + /* + * `boot_cpu_has` returns the runtime feature support, + * and here is the earliest it can be used. + */ + if (cpu_feature_enabled(X86_FEATURE_XSAVE)) + panic("XSAVE has to be disabled as it is not supported by this module.\n" + "Please add 'noxsave' to the kernel command line.\n"); + + real_mode_header = &hv_vtl_real_mode_header; + apic->wakeup_secondary_cpu_64 = hv_vtl_wakeup_secondary_cpu; + + return 0; +} +early_initcall(hv_vtl_early_init); diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index f6a020cb1a24..cc92388b7a99 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -129,7 +129,7 @@ static enum es_result hv_ghcb_hv_call(struct ghcb *ghcb, u64 exit_code, return ES_OK; } -void hv_ghcb_terminate(unsigned int set, unsigned int reason) +void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason) { u64 val = GHCB_MSR_TERM_REQ; @@ -376,34 +376,6 @@ void __init hv_vtom_init(void) #endif /* CONFIG_AMD_MEM_ENCRYPT */ -/* - * hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM. - */ -void *hv_map_memory(void *addr, unsigned long size) -{ - unsigned long *pfns = kcalloc(size / PAGE_SIZE, - sizeof(unsigned long), GFP_KERNEL); - void *vaddr; - int i; - - if (!pfns) - return NULL; - - for (i = 0; i < size / PAGE_SIZE; i++) - pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) + - (ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT); - - vaddr = vmap_pfn(pfns, size / PAGE_SIZE, pgprot_decrypted(PAGE_KERNEL)); - kfree(pfns); - - return vaddr; -} - -void hv_unmap_memory(void *addr) -{ - vunmap(addr); -} - enum hv_isolation_type hv_get_isolation_type(void) { if (!(ms_hyperv.priv_high & HV_ISOLATION)) diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index 0ad2378fe6ad..8460bd35e10c 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -52,6 +52,11 @@ static inline int fill_gva_list(u64 gva_list[], int offset, return gva_n - offset; } +static bool cpu_is_lazy(int cpu) +{ + return per_cpu(cpu_tlbstate_shared.is_lazy, cpu); +} + static void hyperv_flush_tlb_multi(const struct cpumask *cpus, const struct flush_tlb_info *info) { @@ -60,6 +65,7 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, struct hv_tlb_flush *flush; u64 status; unsigned long flags; + bool do_lazy = !info->freed_tables; trace_hyperv_mmu_flush_tlb_multi(cpus, info); @@ -112,6 +118,8 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, goto do_ex_hypercall; for_each_cpu(cpu, cpus) { + if (do_lazy && cpu_is_lazy(cpu)) + continue; vcpu = hv_cpu_number_to_vp_number(cpu); if (vcpu == VP_INVAL) { local_irq_restore(flags); @@ -198,7 +206,8 @@ static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus, flush->hv_vp_set.valid_bank_mask = 0; flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K; - nr_bank = cpumask_to_vpset(&(flush->hv_vp_set), cpus); + nr_bank = cpumask_to_vpset_skip(&flush->hv_vp_set, cpus, + info->freed_tables ? NULL : cpu_is_lazy); if (nr_bank < 0) return HV_STATUS_INVALID_PARAMETER; diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index 94fbe6ae7431..540573f515b7 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -221,9 +221,15 @@ extern void __add_wrong_size(void) #define __try_cmpxchg(ptr, pold, new, size) \ __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) +#define __try_cmpxchg_local(ptr, pold, new, size) \ + __raw_try_cmpxchg((ptr), (pold), (new), (size), "") + #define arch_try_cmpxchg(ptr, pold, new) \ __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr))) +#define arch_try_cmpxchg_local(ptr, pold, new) \ + __try_cmpxchg_local((ptr), (pold), (new), sizeof(*(ptr))) + /* * xadd() adds "inc" to "*ptr" and atomically returns the previous * value of "*ptr". diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 73c9672c123b..cb8ca46213be 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -226,10 +226,9 @@ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ -#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ -#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ -#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ -#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 1) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+ 2) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+ 3) /* Intel Virtual Processor ID */ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ @@ -321,6 +320,7 @@ #define X86_FEATURE_LKGS (12*32+18) /* "" Load "kernel" (userspace) GS */ #define X86_FEATURE_AMX_FP16 (12*32+21) /* "" AMX fp16 Support */ #define X86_FEATURE_AVX_IFMA (12*32+23) /* "" Support for VPMADD52[H,L]UQ */ +#define X86_FEATURE_LAM (12*32+26) /* Linear Address Masking */ /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */ #define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */ @@ -337,6 +337,7 @@ #define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ #define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */ #define X86_FEATURE_CPPC (13*32+27) /* Collaborative Processor Performance Control */ +#define X86_FEATURE_AMD_PSFD (13*32+28) /* "" Predictive Store Forwarding Disable */ #define X86_FEATURE_BTC_NO (13*32+29) /* "" Not vulnerable to Branch Type Confusion */ #define X86_FEATURE_BRS (13*32+31) /* Branch Sampling available */ @@ -369,6 +370,7 @@ #define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ #define X86_FEATURE_X2AVIC (15*32+18) /* Virtual x2apic */ #define X86_FEATURE_V_SPEC_CTRL (15*32+20) /* Virtual SPEC_CTRL */ +#define X86_FEATURE_VNMI (15*32+25) /* Virtual NMI */ #define X86_FEATURE_SVME_ADDR_CHK (15*32+28) /* "" SVME addr check */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */ diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index 5dfa4fb76f4b..fafe9be7a6f4 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -75,6 +75,12 @@ # define DISABLE_CALL_DEPTH_TRACKING (1 << (X86_FEATURE_CALL_DEPTH & 31)) #endif +#ifdef CONFIG_ADDRESS_MASKING +# define DISABLE_LAM 0 +#else +# define DISABLE_LAM (1 << (X86_FEATURE_LAM & 31)) +#endif + #ifdef CONFIG_INTEL_IOMMU_SVM # define DISABLE_ENQCMD 0 #else @@ -115,7 +121,7 @@ #define DISABLED_MASK10 0 #define DISABLED_MASK11 (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET| \ DISABLE_CALL_DEPTH_TRACKING) -#define DISABLED_MASK12 0 +#define DISABLED_MASK12 (DISABLE_LAM) #define DISABLED_MASK13 0 #define DISABLED_MASK14 0 #define DISABLED_MASK15 0 diff --git a/arch/x86/include/asm/fpu/sched.h b/arch/x86/include/asm/fpu/sched.h index c2d6cd78ed0c..78fcde7b1f07 100644 --- a/arch/x86/include/asm/fpu/sched.h +++ b/arch/x86/include/asm/fpu/sched.h @@ -39,7 +39,7 @@ extern void fpu_flush_thread(void); static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu) { if (cpu_feature_enabled(X86_FEATURE_FPU) && - !(current->flags & (PF_KTHREAD | PF_IO_WORKER))) { + !(current->flags & (PF_KTHREAD | PF_USER_WORKER))) { save_fpregs_to_fpstate(old_fpu); /* * The save operation preserved register state, so the diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index 0b73a809e9e1..cea95dcd27c2 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -122,6 +122,9 @@ /* Recommend using enlightened VMCS */ #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED BIT(14) +/* Use hypercalls for MMIO config space access */ +#define HV_X64_USE_MMIO_HYPERCALLS BIT(21) + /* * CPU management features identification. * These are HYPERV_CPUID_CPU_MANAGEMENT_FEATURES.EAX bits. @@ -713,6 +716,81 @@ union hv_msi_entry { } __packed; }; +struct hv_x64_segment_register { + u64 base; + u32 limit; + u16 selector; + union { + struct { + u16 segment_type : 4; + u16 non_system_segment : 1; + u16 descriptor_privilege_level : 2; + u16 present : 1; + u16 reserved : 4; + u16 available : 1; + u16 _long : 1; + u16 _default : 1; + u16 granularity : 1; + } __packed; + u16 attributes; + }; +} __packed; + +struct hv_x64_table_register { + u16 pad[3]; + u16 limit; + u64 base; +} __packed; + +struct hv_init_vp_context { + u64 rip; + u64 rsp; + u64 rflags; + + struct hv_x64_segment_register cs; + struct hv_x64_segment_register ds; + struct hv_x64_segment_register es; + struct hv_x64_segment_register fs; + struct hv_x64_segment_register gs; + struct hv_x64_segment_register ss; + struct hv_x64_segment_register tr; + struct hv_x64_segment_register ldtr; + + struct hv_x64_table_register idtr; + struct hv_x64_table_register gdtr; + + u64 efer; + u64 cr0; + u64 cr3; + u64 cr4; + u64 msr_cr_pat; +} __packed; + +union hv_input_vtl { + u8 as_uint8; + struct { + u8 target_vtl: 4; + u8 use_target_vtl: 1; + u8 reserved_z: 3; + }; +} __packed; + +struct hv_enable_vp_vtl { + u64 partition_id; + u32 vp_index; + union hv_input_vtl target_vtl; + u8 mbz0; + u16 mbz1; + struct hv_init_vp_context vp_context; +} __packed; + +struct hv_get_vp_from_apic_id_in { + u64 partition_id; + union hv_input_vtl target_vtl; + u8 res[7]; + u32 apic_ids[]; +} __packed; + #include #endif diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index c201083b34f6..a3abdcd89a32 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -20,25 +20,4 @@ extern void intel_mid_pwr_power_off(void); extern int intel_mid_pwr_get_lss_id(struct pci_dev *pdev); -#ifdef CONFIG_X86_INTEL_MID - -extern void intel_scu_devices_create(void); -extern void intel_scu_devices_destroy(void); - -#else /* !CONFIG_X86_INTEL_MID */ - -static inline void intel_scu_devices_create(void) { } -static inline void intel_scu_devices_destroy(void) { } - -#endif /* !CONFIG_X86_INTEL_MID */ - -/* Bus Select SoC Fuse value */ -#define BSEL_SOC_FUSE_MASK 0x7 -/* FSB 133MHz */ -#define BSEL_SOC_FUSE_001 0x1 -/* FSB 100MHz */ -#define BSEL_SOC_FUSE_101 0x5 -/* FSB 83MHz */ -#define BSEL_SOC_FUSE_111 0x7 - #endif /* _ASM_X86_INTEL_MID_H */ diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index a3760ca796aa..5b77bbc28f96 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -200,9 +200,6 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, const Elf_Shdr *symtab); #define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add -void *arch_kexec_kernel_image_load(struct kimage *image); -#define arch_kexec_kernel_image_load arch_kexec_kernel_image_load - int arch_kimage_file_post_load_cleanup(struct kimage *image); #define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup #endif diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 8dc345cc6318..13bc212cd4bc 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -54,8 +54,8 @@ KVM_X86_OP(set_rflags) KVM_X86_OP(get_if_flag) KVM_X86_OP(flush_tlb_all) KVM_X86_OP(flush_tlb_current) -KVM_X86_OP_OPTIONAL(tlb_remote_flush) -KVM_X86_OP_OPTIONAL(tlb_remote_flush_with_range) +KVM_X86_OP_OPTIONAL(flush_remote_tlbs) +KVM_X86_OP_OPTIONAL(flush_remote_tlbs_range) KVM_X86_OP(flush_tlb_gva) KVM_X86_OP(flush_tlb_guest) KVM_X86_OP(vcpu_pre_run) @@ -68,6 +68,8 @@ KVM_X86_OP(get_interrupt_shadow) KVM_X86_OP(patch_hypercall) KVM_X86_OP(inject_irq) KVM_X86_OP(inject_nmi) +KVM_X86_OP_OPTIONAL_RET0(is_vnmi_pending) +KVM_X86_OP_OPTIONAL_RET0(set_vnmi_pending) KVM_X86_OP(inject_exception) KVM_X86_OP(cancel_injection) KVM_X86_OP(interrupt_allowed) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 808c292ad3f4..fb9d1f2d6136 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -420,6 +420,10 @@ struct kvm_mmu_root_info { #define KVM_MMU_NUM_PREV_ROOTS 3 +#define KVM_MMU_ROOT_CURRENT BIT(0) +#define KVM_MMU_ROOT_PREVIOUS(i) BIT(1+i) +#define KVM_MMU_ROOTS_ALL (BIT(1 + KVM_MMU_NUM_PREV_ROOTS) - 1) + #define KVM_HAVE_MMU_RWLOCK struct kvm_mmu_page; @@ -439,9 +443,8 @@ struct kvm_mmu { gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t gva_or_gpa, u64 access, struct x86_exception *exception); - int (*sync_page)(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp); - void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva, hpa_t root_hpa); + int (*sync_spte)(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, int i); struct kvm_mmu_root_info root; union kvm_cpu_role cpu_role; union kvm_mmu_page_role root_role; @@ -479,11 +482,6 @@ struct kvm_mmu { u64 pdptrs[4]; /* pae */ }; -struct kvm_tlb_range { - u64 start_gfn; - u64 pages; -}; - enum pmc_type { KVM_PMC_GP = 0, KVM_PMC_FIXED, @@ -515,6 +513,7 @@ struct kvm_pmc { #define MSR_ARCH_PERFMON_FIXED_CTR_MAX (MSR_ARCH_PERFMON_FIXED_CTR0 + KVM_PMC_MAX_FIXED - 1) #define KVM_AMD_PMC_MAX_GENERIC 6 struct kvm_pmu { + u8 version; unsigned nr_arch_gp_counters; unsigned nr_arch_fixed_counters; unsigned available_event_types; @@ -527,7 +526,6 @@ struct kvm_pmu { u64 global_ovf_ctrl_mask; u64 reserved_bits; u64 raw_event_mask; - u8 version; struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC]; struct kvm_pmc fixed_counters[KVM_PMC_MAX_FIXED]; struct irq_work irq_work; @@ -876,7 +874,8 @@ struct kvm_vcpu_arch { u64 tsc_scaling_ratio; /* current scaling ratio */ atomic_t nmi_queued; /* unprocessed asynchronous NMIs */ - unsigned nmi_pending; /* NMI queued after currently running handler */ + /* Number of NMIs pending injection, not including hardware vNMIs. */ + unsigned int nmi_pending; bool nmi_injected; /* Trying to inject an NMI this entry */ bool smi_pending; /* SMI queued after currently running handler */ u8 handling_intr_from_guest; @@ -947,23 +946,6 @@ struct kvm_vcpu_arch { u64 msr_kvm_poll_control; - /* - * Indicates the guest is trying to write a gfn that contains one or - * more of the PTEs used to translate the write itself, i.e. the access - * is changing its own translation in the guest page tables. KVM exits - * to userspace if emulation of the faulting instruction fails and this - * flag is set, as KVM cannot make forward progress. - * - * If emulation fails for a write to guest page tables, KVM unprotects - * (zaps) the shadow page for the target gfn and resumes the guest to - * retry the non-emulatable instruction (on hardware). Unprotecting the - * gfn doesn't allow forward progress for a self-changing access because - * doing so also zaps the translation for the gfn, i.e. retrying the - * instruction will hit a !PRESENT fault, which results in a new shadow - * page and sends KVM back to square one. - */ - bool write_fault_to_shadow_pgtable; - /* set at EPT violation at this point */ unsigned long exit_qualification; @@ -1602,9 +1584,9 @@ struct kvm_x86_ops { void (*flush_tlb_all)(struct kvm_vcpu *vcpu); void (*flush_tlb_current)(struct kvm_vcpu *vcpu); - int (*tlb_remote_flush)(struct kvm *kvm); - int (*tlb_remote_flush_with_range)(struct kvm *kvm, - struct kvm_tlb_range *range); + int (*flush_remote_tlbs)(struct kvm *kvm); + int (*flush_remote_tlbs_range)(struct kvm *kvm, gfn_t gfn, + gfn_t nr_pages); /* * Flush any TLB entries associated with the given GVA. @@ -1638,6 +1620,13 @@ struct kvm_x86_ops { int (*nmi_allowed)(struct kvm_vcpu *vcpu, bool for_injection); bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked); + /* Whether or not a virtual NMI is pending in hardware. */ + bool (*is_vnmi_pending)(struct kvm_vcpu *vcpu); + /* + * Attempt to pend a virtual NMI in harware. Returns %true on success + * to allow using static_call_ret0 as the fallback. + */ + bool (*set_vnmi_pending)(struct kvm_vcpu *vcpu); void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); @@ -1808,8 +1797,8 @@ void kvm_arch_free_vm(struct kvm *kvm); #define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLB static inline int kvm_arch_flush_remote_tlb(struct kvm *kvm) { - if (kvm_x86_ops.tlb_remote_flush && - !static_call(kvm_x86_tlb_remote_flush)(kvm)) + if (kvm_x86_ops.flush_remote_tlbs && + !static_call(kvm_x86_flush_remote_tlbs)(kvm)) return 0; else return -ENOTSUPP; @@ -1907,6 +1896,25 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); * EMULTYPE_COMPLETE_USER_EXIT - Set when the emulator should update interruptibility * state and inject single-step #DBs after skipping * an instruction (after completing userspace I/O). + * + * EMULTYPE_WRITE_PF_TO_SP - Set when emulating an intercepted page fault that + * is attempting to write a gfn that contains one or + * more of the PTEs used to translate the write itself, + * and the owning page table is being shadowed by KVM. + * If emulation of the faulting instruction fails and + * this flag is set, KVM will exit to userspace instead + * of retrying emulation as KVM cannot make forward + * progress. + * + * If emulation fails for a write to guest page tables, + * KVM unprotects (zaps) the shadow page for the target + * gfn and resumes the guest to retry the non-emulatable + * instruction (on hardware). Unprotecting the gfn + * doesn't allow forward progress for a self-changing + * access because doing so also zaps the translation for + * the gfn, i.e. retrying the instruction will hit a + * !PRESENT fault, which results in a new shadow page + * and sends KVM back to square one. */ #define EMULTYPE_NO_DECODE (1 << 0) #define EMULTYPE_TRAP_UD (1 << 1) @@ -1916,6 +1924,7 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); #define EMULTYPE_VMWARE_GP (1 << 5) #define EMULTYPE_PF (1 << 6) #define EMULTYPE_COMPLETE_USER_EXIT (1 << 7) +#define EMULTYPE_WRITE_PF_TO_SP (1 << 8) int kvm_emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type); int kvm_emulate_instruction_from_buffer(struct kvm_vcpu *vcpu, @@ -1994,14 +2003,11 @@ static inline int __kvm_irq_line_state(unsigned long *irq_state, return !!(*irq_state); } -#define KVM_MMU_ROOT_CURRENT BIT(0) -#define KVM_MMU_ROOT_PREVIOUS(i) BIT(1+i) -#define KVM_MMU_ROOTS_ALL (~0UL) - int kvm_pic_set_irq(struct kvm_pic *pic, int irq, int irq_source_id, int level); void kvm_pic_clear_all(struct kvm_pic *pic, int irq_source_id); void kvm_inject_nmi(struct kvm_vcpu *vcpu); +int kvm_get_nr_pending_nmis(struct kvm_vcpu *vcpu); void kvm_update_dr7(struct kvm_vcpu *vcpu); @@ -2041,8 +2047,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 error_code, void *insn, int insn_len); void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva); -void kvm_mmu_invalidate_gva(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gva_t gva, hpa_t root_hpa); +void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, + u64 addr, unsigned long roots); void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid); void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd); @@ -2204,4 +2210,11 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages); KVM_X86_QUIRK_FIX_HYPERCALL_INSN | \ KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS) +/* + * KVM previously used a u32 field in kvm_run to indicate the hypercall was + * initiated from long mode. KVM now sets bit 0 to indicate long mode, but the + * remaining 31 lower bits must be 0 to preserve ABI. + */ +#define KVM_EXIT_HYPERCALL_MBZ GENMASK_ULL(31, 1) + #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h index dd9b8118f784..0953aa32a324 100644 --- a/arch/x86/include/asm/linkage.h +++ b/arch/x86/include/asm/linkage.h @@ -99,7 +99,7 @@ /* SYM_TYPED_FUNC_START -- use for indirectly called globals, w/ CFI type */ #define SYM_TYPED_FUNC_START(name) \ - SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \ + SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_F_ALIGN) \ ENDBR /* SYM_FUNC_START -- use for global functions */ diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 349a47acaa4a..56d4ef604b91 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h @@ -120,8 +120,17 @@ static inline long local_sub_return(long i, local_t *l) #define local_inc_return(l) (local_add_return(1, l)) #define local_dec_return(l) (local_sub_return(1, l)) -#define local_cmpxchg(l, o, n) \ - (cmpxchg_local(&((l)->a.counter), (o), (n))) +static inline long local_cmpxchg(local_t *l, long old, long new) +{ + return cmpxchg_local(&l->a.counter, old, new); +} + +static inline bool local_try_cmpxchg(local_t *l, long *old, long new) +{ + typeof(l->a.counter) *__old = (typeof(l->a.counter) *) old; + return try_cmpxchg_local(&l->a.counter, __old, new); +} + /* Always has a lock prefix */ #define local_xchg(l, n) (xchg(&((l)->a.counter), (n))) diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 5d7494631ea9..0da5c227f490 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -9,9 +9,13 @@ #include /* Uprobes on this MM assume 32-bit code */ -#define MM_CONTEXT_UPROBE_IA32 BIT(0) +#define MM_CONTEXT_UPROBE_IA32 0 /* vsyscall page is accessible on this MM */ -#define MM_CONTEXT_HAS_VSYSCALL BIT(1) +#define MM_CONTEXT_HAS_VSYSCALL 1 +/* Do not allow changing LAM mode */ +#define MM_CONTEXT_LOCK_LAM 2 +/* Allow LAM and SVA coexisting */ +#define MM_CONTEXT_FORCE_TAGGED_SVA 3 /* * x86 has arch-specific MMU state beyond what lives in mm_struct. @@ -39,7 +43,15 @@ typedef struct { #endif #ifdef CONFIG_X86_64 - unsigned short flags; + unsigned long flags; +#endif + +#ifdef CONFIG_ADDRESS_MASKING + /* Active LAM mode: X86_CR3_LAM_U48 or X86_CR3_LAM_U57 or 0 (disabled) */ + unsigned long lam_cr3_mask; + + /* Significant bits of the virtual address. Excludes tag bits. */ + u64 untag_mask; #endif struct mutex lock; diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index c3ad8a526378..1d29dc791f5a 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -85,6 +85,51 @@ static inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next) } #endif +#ifdef CONFIG_ADDRESS_MASKING +static inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm) +{ + return mm->context.lam_cr3_mask; +} + +static inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm) +{ + mm->context.lam_cr3_mask = oldmm->context.lam_cr3_mask; + mm->context.untag_mask = oldmm->context.untag_mask; +} + +#define mm_untag_mask mm_untag_mask +static inline unsigned long mm_untag_mask(struct mm_struct *mm) +{ + return mm->context.untag_mask; +} + +static inline void mm_reset_untag_mask(struct mm_struct *mm) +{ + mm->context.untag_mask = -1UL; +} + +#define arch_pgtable_dma_compat arch_pgtable_dma_compat +static inline bool arch_pgtable_dma_compat(struct mm_struct *mm) +{ + return !mm_lam_cr3_mask(mm) || + test_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &mm->context.flags); +} +#else + +static inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm) +{ + return 0; +} + +static inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm) +{ +} + +static inline void mm_reset_untag_mask(struct mm_struct *mm) +{ +} +#endif + #define enter_lazy_tlb enter_lazy_tlb extern void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk); @@ -109,6 +154,7 @@ static inline int init_new_context(struct task_struct *tsk, mm->context.execute_only_pkey = -1; } #endif + mm_reset_untag_mask(mm); init_new_context_ldt(mm); return 0; } @@ -162,6 +208,7 @@ static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { arch_dup_pkeys(oldmm, mm); paravirt_enter_mmap(mm); + dup_lam(oldmm, mm); return ldt_dup_context(oldmm, mm); } @@ -175,7 +222,7 @@ static inline void arch_exit_mmap(struct mm_struct *mm) static inline bool is_64bit_mm(struct mm_struct *mm) { return !IS_ENABLED(CONFIG_IA32_EMULATION) || - !(mm->context.flags & MM_CONTEXT_UPROBE_IA32); + !test_bit(MM_CONTEXT_UPROBE_IA32, &mm->context.flags); } #else static inline bool is_64bit_mm(struct mm_struct *mm) diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index e3cef98a0142..49bb4f2bd300 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -19,6 +19,10 @@ */ #define HV_IOAPIC_BASE_ADDRESS 0xfec00000 +#define HV_VTL_NORMAL 0x0 +#define HV_VTL_SECURE 0x1 +#define HV_VTL_MGMT 0x2 + union hv_ghcb; DECLARE_STATIC_KEY_FALSE(isolation_type_snp); @@ -29,6 +33,11 @@ typedef int (*hyperv_fill_flush_list_func)( void hyperv_vector_handler(struct pt_regs *regs); +static inline unsigned char hv_get_nmi_reason(void) +{ + return 0; +} + #if IS_ENABLED(CONFIG_HYPERV) extern int hyperv_init_cpuhp; @@ -219,7 +228,7 @@ int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); void hv_ghcb_msr_write(u64 msr, u64 value); void hv_ghcb_msr_read(u64 msr, u64 *value); bool hv_ghcb_negotiate_protocol(void); -void hv_ghcb_terminate(unsigned int set, unsigned int reason); +void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason); void hv_vtom_init(void); #else static inline void hv_ghcb_msr_write(u64 msr, u64 value) {} @@ -271,6 +280,12 @@ static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; } #endif /* CONFIG_HYPERV */ +#ifdef CONFIG_HYPERV_VTL_MODE +void __init hv_vtl_init_platform(void); +#else +static inline void __init hv_vtl_init_platform(void) {} +#endif + #include #endif diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 3ef70e54a858..edb2b0cb8efe 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -194,9 +194,9 @@ * builds. */ .macro ANNOTATE_RETPOLINE_SAFE - .Lannotate_\@: +.Lhere_\@: .pushsection .discard.retpoline_safe - _ASM_PTR .Lannotate_\@ + .long .Lhere_\@ - . .popsection .endm @@ -210,8 +210,8 @@ * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should * eventually turn into it's own annotation. */ -.macro ANNOTATE_UNRET_END -#ifdef CONFIG_DEBUG_ENTRY +.macro VALIDATE_UNRET_END +#if defined(CONFIG_NOINSTR_VALIDATION) && defined(CONFIG_CPU_UNRET_ENTRY) ANNOTATE_RETPOLINE_SAFE nop #endif @@ -286,7 +286,7 @@ .macro UNTRAIN_RET #if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ defined(CONFIG_CALL_DEPTH_TRACKING) - ANNOTATE_UNRET_END + VALIDATE_UNRET_END ALTERNATIVE_3 "", \ CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ @@ -297,7 +297,7 @@ .macro UNTRAIN_RET_FROM_CALL #if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY) || \ defined(CONFIG_CALL_DEPTH_TRACKING) - ANNOTATE_UNRET_END + VALIDATE_UNRET_END ALTERNATIVE_3 "", \ CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET, \ "call entry_ibpb", X86_FEATURE_ENTRY_IBPB, \ @@ -318,7 +318,7 @@ #define ANNOTATE_RETPOLINE_SAFE \ "999:\n\t" \ ".pushsection .discard.retpoline_safe\n\t" \ - _ASM_PTR " 999b\n\t" \ + ".long 999b - .\n\t" \ ".popsection\n\t" typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE]; diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h index 1343a62106de..46d7e06763c9 100644 --- a/arch/x86/include/asm/orc_types.h +++ b/arch/x86/include/asm/orc_types.h @@ -39,6 +39,12 @@ #define ORC_REG_SP_INDIRECT 9 #define ORC_REG_MAX 15 +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4 + #ifndef __ASSEMBLY__ #include @@ -56,16 +62,14 @@ struct orc_entry { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned sp_reg:4; unsigned bp_reg:4; - unsigned type:2; + unsigned type:3; unsigned signal:1; - unsigned end:1; #elif defined(__BIG_ENDIAN_BITFIELD) unsigned bp_reg:4; unsigned sp_reg:4; unsigned unused:4; - unsigned end:1; unsigned signal:1; - unsigned type:2; + unsigned type:3; #endif } __packed; diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 8fc15ed5e60b..abf09882f58b 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -121,6 +121,9 @@ #define PEBS_DATACFG_LBRS BIT_ULL(3) #define PEBS_DATACFG_LBR_SHIFT 24 +/* Steal the highest bit of pebs_data_cfg for SW usage */ +#define PEBS_UPDATE_DS_SW BIT_ULL(63) + /* * Intel "Architectural Performance Monitoring" CPUID * detection/enumeration details: diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 7425f32e5293..15ae4d6ba476 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -1097,7 +1097,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, clear_bit(_PAGE_BIT_RW, (unsigned long *)&ptep->pte); } -#define flush_tlb_fix_spurious_fault(vma, address) do { } while (0) +#define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0) #define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h index a7f3d9100adb..d8cccadc83a6 100644 --- a/arch/x86/include/asm/processor-flags.h +++ b/arch/x86/include/asm/processor-flags.h @@ -28,6 +28,8 @@ * On systems with SME, one bit (in a variable position!) is stolen to indicate * that the top-level paging structure is encrypted. * + * On systemms with LAM, bits 61 and 62 are used to indicate LAM mode. + * * All of the remaining bits indicate the physical address of the top-level * paging structure. * diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index bc5b4d788c08..9177b4354c3f 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -28,7 +28,6 @@ void __noreturn machine_real_restart(unsigned int type); void cpu_emergency_disable_virtualization(void); typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); -void nmi_panic_self_stop(struct pt_regs *regs); void nmi_shootdown_cpus(nmi_shootdown_cb callback); void run_crash_ipi_callback(struct pt_regs *regs); diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index f37cbff7354c..f3495623ac99 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -125,11 +125,11 @@ void clear_bss(void); #ifdef __i386__ -asmlinkage void __init i386_start_kernel(void); +asmlinkage void __init __noreturn i386_start_kernel(void); #else -asmlinkage void __init x86_64_start_kernel(char *real_mode); -asmlinkage void __init x86_64_start_reservations(char *real_mode_data); +asmlinkage void __init __noreturn x86_64_start_kernel(char *real_mode); +asmlinkage void __init __noreturn x86_64_start_reservations(char *real_mode_data); #endif /* __i386__ */ #endif /* _SETUP */ diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h index 4a03993e0785..2631e01f6e0f 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -7,8 +7,6 @@ #define TDX_HYPERCALL_STANDARD 0 -#define TDX_HCALL_HAS_OUTPUT BIT(0) - #define TDX_CPUID_LEAF_ID 0x21 #define TDX_IDENT "IntelTDX " @@ -36,7 +34,8 @@ struct tdx_hypercall_args { }; /* Used to request services from the VMM */ -u64 __tdx_hypercall(struct tdx_hypercall_args *args, unsigned long flags); +u64 __tdx_hypercall(struct tdx_hypercall_args *args); +u64 __tdx_hypercall_ret(struct tdx_hypercall_args *args); /* Called from __tdx_hypercall() for unrecoverable failure */ void __tdx_hypercall_failed(void); diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index bf2c51df9e0b..4e91054c84be 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -93,12 +93,13 @@ static inline void __cpu_die(unsigned int cpu) smp_ops.cpu_die(cpu); } -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { smp_ops.play_dead(); + BUG(); } -static inline void smp_send_reschedule(int cpu) +static inline void arch_smp_send_reschedule(int cpu) { smp_ops.smp_send_reschedule(cpu); } @@ -124,7 +125,7 @@ int native_cpu_up(unsigned int cpunum, struct task_struct *tidle); int native_cpu_disable(void); int common_cpu_die(unsigned int cpu); void native_cpu_die(unsigned int cpu); -void hlt_play_dead(void); +void __noreturn hlt_play_dead(void); void native_play_dead(void); void play_dead_common(void); void wbinvd_on_cpu(int cpu); diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h index c1e14cee0722..857d364b9888 100644 --- a/arch/x86/include/asm/string_64.h +++ b/arch/x86/include/asm/string_64.h @@ -15,24 +15,18 @@ #endif #define __HAVE_ARCH_MEMCPY 1 -#if defined(__SANITIZE_MEMORY__) && defined(__NO_FORTIFY) -#undef memcpy -#define memcpy __msan_memcpy -#else extern void *memcpy(void *to, const void *from, size_t len); -#endif extern void *__memcpy(void *to, const void *from, size_t len); #define __HAVE_ARCH_MEMSET -#if defined(__SANITIZE_MEMORY__) && defined(__NO_FORTIFY) -extern void *__msan_memset(void *s, int c, size_t n); -#undef memset -#define memset __msan_memset -#else void *memset(void *s, int c, size_t n); -#endif void *__memset(void *s, int c, size_t n); +/* + * KMSAN needs to instrument as much code as possible. Use C versions of + * memsetXX() from lib/string.c under KMSAN. + */ +#if !defined(CONFIG_KMSAN) #define __HAVE_ARCH_MEMSET16 static inline void *memset16(uint16_t *s, uint16_t v, size_t n) { @@ -68,15 +62,10 @@ static inline void *memset64(uint64_t *s, uint64_t v, size_t n) : "memory"); return s; } +#endif #define __HAVE_ARCH_MEMMOVE -#if defined(__SANITIZE_MEMORY__) && defined(__NO_FORTIFY) -#undef memmove -void *__msan_memmove(void *dest, const void *src, size_t len); -#define memmove __msan_memmove -#else void *memmove(void *dest, const void *src, size_t count); -#endif void *__memmove(void *dest, const void *src, size_t count); int memcmp(const void *cs, const void *ct, size_t count); diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 770dcf75eaa9..e7c7379d6ac7 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -183,6 +183,12 @@ struct __attribute__ ((__packed__)) vmcb_control_area { #define V_GIF_SHIFT 9 #define V_GIF_MASK (1 << V_GIF_SHIFT) +#define V_NMI_PENDING_SHIFT 11 +#define V_NMI_PENDING_MASK (1 << V_NMI_PENDING_SHIFT) + +#define V_NMI_BLOCKING_SHIFT 12 +#define V_NMI_BLOCKING_MASK (1 << V_NMI_BLOCKING_SHIFT) + #define V_INTR_PRIO_SHIFT 16 #define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) @@ -197,6 +203,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { #define V_GIF_ENABLE_SHIFT 25 #define V_GIF_ENABLE_MASK (1 << V_GIF_ENABLE_SHIFT) +#define V_NMI_ENABLE_SHIFT 26 +#define V_NMI_ENABLE_MASK (1 << V_NMI_ENABLE_SHIFT) + #define AVIC_ENABLE_SHIFT 31 #define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT) @@ -278,7 +287,6 @@ static_assert((AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == AVIC_MAX_ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_MAX_PHYSICAL_ID); #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF) -#define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL struct vmcb_seg { diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index cda3118f3b27..75bfaa421030 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -2,7 +2,7 @@ #ifndef _ASM_X86_TLBFLUSH_H #define _ASM_X86_TLBFLUSH_H -#include +#include #include #include @@ -12,6 +12,7 @@ #include #include #include +#include void __flush_tlb_all(void); @@ -53,6 +54,15 @@ static inline void cr4_clear_bits(unsigned long mask) local_irq_restore(flags); } +#ifdef CONFIG_ADDRESS_MASKING +DECLARE_PER_CPU(u64, tlbstate_untag_mask); + +static inline u64 current_untag_mask(void) +{ + return this_cpu_read(tlbstate_untag_mask); +} +#endif + #ifndef MODULE /* * 6 because 6 should be plenty and struct tlb_state will fit in two cache @@ -101,6 +111,16 @@ struct tlb_state { */ bool invalidate_other; +#ifdef CONFIG_ADDRESS_MASKING + /* + * Active LAM mode. + * + * X86_CR3_LAM_U57/U48 shifted right by X86_CR3_LAM_U57_BIT or 0 if LAM + * disabled. + */ + u8 lam; +#endif + /* * Mask that contains TLB_NR_DYN_ASIDS+1 bits to indicate * the corresponding user PCID needs a flush next time we @@ -357,6 +377,32 @@ static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd) } #define huge_pmd_needs_flush huge_pmd_needs_flush +#ifdef CONFIG_ADDRESS_MASKING +static inline u64 tlbstate_lam_cr3_mask(void) +{ + u64 lam = this_cpu_read(cpu_tlbstate.lam); + + return lam << X86_CR3_LAM_U57_BIT; +} + +static inline void set_tlbstate_lam_mode(struct mm_struct *mm) +{ + this_cpu_write(cpu_tlbstate.lam, + mm->context.lam_cr3_mask >> X86_CR3_LAM_U57_BIT); + this_cpu_write(tlbstate_untag_mask, mm->context.untag_mask); +} + +#else + +static inline u64 tlbstate_lam_cr3_mask(void) +{ + return 0; +} + +static inline void set_tlbstate_lam_mode(struct mm_struct *mm) +{ +} +#endif #endif /* !MODULE */ static inline void __native_tlb_flush_global(unsigned long cr4) diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 1cc756eafa44..8bae40a66282 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -7,43 +7,21 @@ #include #include #include +#include #include +#include #include #include #include #include +#include -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP -static inline bool pagefault_disabled(void); -# define WARN_ON_IN_IRQ() \ - WARN_ON_ONCE(!in_task() && !pagefault_disabled()) +#ifdef CONFIG_X86_32 +# include #else -# define WARN_ON_IN_IRQ() +# include #endif -/** - * access_ok - Checks if a user space pointer is valid - * @addr: User space pointer to start of block to check - * @size: Size of block to check - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * Checks if a pointer to a block of memory in user space is valid. - * - * Note that, depending on architecture, this function probably just - * checks that the pointer is in the user space range - after calling - * this function, memory access functions may still return -EFAULT. - * - * Return: true (nonzero) if the memory block may be valid, false (zero) - * if it is definitely invalid. - */ -#define access_ok(addr, size) \ -({ \ - WARN_ON_IN_IRQ(); \ - likely(__access_ok(addr, size)); \ -}) - #include extern int __get_user_1(void); @@ -532,14 +510,6 @@ extern struct movsl_mask { #define ARCH_HAS_NOCACHE_UACCESS 1 -#ifdef CONFIG_X86_32 -unsigned long __must_check clear_user(void __user *mem, unsigned long len); -unsigned long __must_check __clear_user(void __user *mem, unsigned long len); -# include -#else -# include -#endif - /* * The "unsafe" user accesses aren't really "unsafe", but the naming * is a big fat warning: you have to not only do the access_ok() diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 388a40660c7b..40379a1adbb8 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -33,4 +33,7 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from, return __copy_from_user_ll_nocache_nozero(to, from, n); } +unsigned long __must_check clear_user(void __user *mem, unsigned long len); +unsigned long __must_check __clear_user(void __user *mem, unsigned long len); + #endif /* _ASM_X86_UACCESS_32_H */ diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 0a49a8de9f3c..81b826d3b753 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -12,6 +12,87 @@ #include #include +#ifdef CONFIG_ADDRESS_MASKING +/* + * Mask out tag bits from the address. + */ +static inline unsigned long __untagged_addr(unsigned long addr) +{ + /* + * Refer tlbstate_untag_mask directly to avoid RIP-relative relocation + * in alternative instructions. The relocation gets wrong when gets + * copied to the target place. + */ + asm (ALTERNATIVE("", + "and %%gs:tlbstate_untag_mask, %[addr]\n\t", X86_FEATURE_LAM) + : [addr] "+r" (addr) : "m" (tlbstate_untag_mask)); + + return addr; +} + +#define untagged_addr(addr) ({ \ + unsigned long __addr = (__force unsigned long)(addr); \ + (__force __typeof__(addr))__untagged_addr(__addr); \ +}) + +static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, + unsigned long addr) +{ + mmap_assert_locked(mm); + return addr & (mm)->context.untag_mask; +} + +#define untagged_addr_remote(mm, addr) ({ \ + unsigned long __addr = (__force unsigned long)(addr); \ + (__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \ +}) + +#endif + +/* + * The virtual address space space is logically divided into a kernel + * half and a user half. When cast to a signed type, user pointers + * are positive and kernel pointers are negative. + */ +#define valid_user_address(x) ((long)(x) >= 0) + +/* + * User pointers can have tag bits on x86-64. This scheme tolerates + * arbitrary values in those bits rather then masking them off. + * + * Enforce two rules: + * 1. 'ptr' must be in the user half of the address space + * 2. 'ptr+size' must not overflow into kernel addresses + * + * Note that addresses around the sign change are not valid addresses, + * and will GP-fault even with LAM enabled if the sign bit is set (see + * "CR3.LAM_SUP" that can narrow the canonicality check if we ever + * enable it, but not remove it entirely). + * + * So the "overflow into kernel addresses" does not imply some sudden + * exact boundary at the sign bit, and we can allow a lot of slop on the + * size check. + * + * In fact, we could probably remove the size check entirely, since + * any kernel accesses will be in increasing address order starting + * at 'ptr', and even if the end might be in kernel space, we'll + * hit the GP faults for non-canonical accesses before we ever get + * there. + * + * That's a separate optimization, for now just handle the small + * constant case. + */ +static inline bool __access_ok(const void __user *ptr, unsigned long size) +{ + if (__builtin_constant_p(size <= PAGE_SIZE) && size <= PAGE_SIZE) { + return valid_user_address(ptr); + } else { + unsigned long sum = size + (unsigned long)ptr; + return valid_user_address(sum) && sum >= (unsigned long)ptr; + } +} +#define __access_ok __access_ok + /* * Copy To/From Userspace */ @@ -54,8 +135,6 @@ raw_copy_to_user(void __user *dst, const void *src, unsigned long size) extern long __copy_user_nocache(void *dst, const void __user *src, unsigned size); extern long __copy_user_flushcache(void *dst, const void __user *src, unsigned size); -extern void memcpy_page_flushcache(char *to, struct page *page, size_t offset, - size_t len); static inline int __copy_from_user_inatomic_nocache(void *dst, const void __user *src, @@ -108,7 +187,7 @@ static __always_inline __must_check unsigned long __clear_user(void __user *addr static __always_inline unsigned long clear_user(void __user *to, unsigned long n) { - if (access_ok(to, n)) + if (__access_ok(to, n)) return __clear_user(to, n); return n; } diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h index e7c71750b309..01cb9692b160 100644 --- a/arch/x86/include/asm/unwind_hints.h +++ b/arch/x86/include/asm/unwind_hints.h @@ -7,12 +7,17 @@ #ifdef __ASSEMBLY__ -.macro UNWIND_HINT_EMPTY - UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1 +.macro UNWIND_HINT_END_OF_STACK + UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK +.endm + +.macro UNWIND_HINT_UNDEFINED + UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED .endm .macro UNWIND_HINT_ENTRY - UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1 + VALIDATE_UNRET_BEGIN + UNWIND_HINT_END_OF_STACK .endm .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1 @@ -52,6 +57,11 @@ UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal .endm +.macro UNWIND_HINT_IRET_ENTRY base=%rsp offset=0 signal=1 + VALIDATE_UNRET_BEGIN + UNWIND_HINT_IRET_REGS base=\base offset=\offset signal=\signal +.endm + .macro UNWIND_HINT_FUNC UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC .endm @@ -67,7 +77,7 @@ #else #define UNWIND_HINT_FUNC \ - UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0) + UNWIND_HINT(UNWIND_HINT_TYPE_FUNC, ORC_REG_SP, 8, 0) #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 498dc600bd5c..0d02c4aafa6f 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -13,7 +13,9 @@ #include +#include #include + #include #include diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index acc20ae4079d..88085f369ff6 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -330,5 +330,7 @@ extern void x86_init_uint_noop(unsigned int unused); extern bool bool_x86_init_noop(void); extern void x86_op_int_noop(int cpu); extern bool x86_pnpbios_disabled(void); +extern int set_rtc_noop(const struct timespec64 *now); +extern void get_rtc_noop(struct timespec64 *now); #endif diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 7f467fe05d42..1a6a1f987949 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -559,4 +559,7 @@ struct kvm_pmu_event_filter { #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */ #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ +/* x86-specific KVM_EXIT_HYPERCALL flags. */ +#define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0) + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h index 500b96e71f18..e8d7ebbca1a4 100644 --- a/arch/x86/include/uapi/asm/prctl.h +++ b/arch/x86/include/uapi/asm/prctl.h @@ -16,8 +16,16 @@ #define ARCH_GET_XCOMP_GUEST_PERM 0x1024 #define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 +#define ARCH_XCOMP_TILECFG 17 +#define ARCH_XCOMP_TILEDATA 18 + #define ARCH_MAP_VDSO_X32 0x2001 #define ARCH_MAP_VDSO_32 0x2002 #define ARCH_MAP_VDSO_64 0x2003 +#define ARCH_GET_UNTAG_MASK 0x4001 +#define ARCH_ENABLE_TAGGED_ADDR 0x4002 +#define ARCH_GET_MAX_TAG_BITS 0x4003 +#define ARCH_FORCE_TAGGED_SVA 0x4004 + #endif /* _ASM_X86_PRCTL_H */ diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h index c47cc7f2feeb..d898432947ff 100644 --- a/arch/x86/include/uapi/asm/processor-flags.h +++ b/arch/x86/include/uapi/asm/processor-flags.h @@ -82,6 +82,10 @@ #define X86_CR3_PCID_BITS 12 #define X86_CR3_PCID_MASK (_AC((1UL << X86_CR3_PCID_BITS) - 1, UL)) +#define X86_CR3_LAM_U57_BIT 61 /* Activate LAM for userspace, 62:57 bits masked */ +#define X86_CR3_LAM_U57 _BITULL(X86_CR3_LAM_U57_BIT) +#define X86_CR3_LAM_U48_BIT 62 /* Activate LAM for userspace, 62:48 bits masked */ +#define X86_CR3_LAM_U48 _BITULL(X86_CR3_LAM_U48_BIT) #define X86_CR3_PCID_NOFLUSH_BIT 63 /* Preserve old PCID */ #define X86_CR3_PCID_NOFLUSH _BITULL(X86_CR3_PCID_NOFLUSH_BIT) @@ -132,6 +136,8 @@ #define X86_CR4_PKE _BITUL(X86_CR4_PKE_BIT) #define X86_CR4_CET_BIT 23 /* enable Control-flow Enforcement Technology */ #define X86_CR4_CET _BITUL(X86_CR4_CET_BIT) +#define X86_CR4_LAM_SUP_BIT 28 /* LAM for supervisor pointers */ +#define X86_CR4_LAM_SUP _BITUL(X86_CR4_LAM_SUP_BIT) /* * x86-64 Task Priority Register, CR8 diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index dd61752f4c96..4070a01c11b7 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -17,6 +17,7 @@ CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_early_printk.o = -pg CFLAGS_REMOVE_head64.o = -pg CFLAGS_REMOVE_sev.o = -pg +CFLAGS_REMOVE_rethook.o = -pg endif KASAN_SANITIZE_head$(BITS).o := n diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 4266b64631a4..7e331e8f3692 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -36,6 +36,7 @@ #define PCI_DEVICE_ID_AMD_19H_M50H_DF_F4 0x166e #define PCI_DEVICE_ID_AMD_19H_M60H_DF_F4 0x14e4 #define PCI_DEVICE_ID_AMD_19H_M70H_DF_F4 0x14f4 +#define PCI_DEVICE_ID_AMD_19H_M78H_DF_F4 0x12fc /* Protect the PCI config register pairs used for SMN. */ static DEFINE_MUTEX(smn_mutex); @@ -79,6 +80,7 @@ static const struct pci_device_id amd_nb_misc_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F3) }, {} }; diff --git a/arch/x86/kernel/callthunks.c b/arch/x86/kernel/callthunks.c index ffea98f9064b..22ab13966427 100644 --- a/arch/x86/kernel/callthunks.c +++ b/arch/x86/kernel/callthunks.c @@ -330,8 +330,8 @@ void noinline callthunks_patch_module_calls(struct callthunk_sites *cs, struct module *mod) { struct core_text ct = { - .base = (unsigned long)mod->core_layout.base, - .end = (unsigned long)mod->core_layout.base + mod->core_layout.size, + .base = (unsigned long)mod->mem[MOD_TEXT].base, + .end = (unsigned long)mod->mem[MOD_TEXT].base + mod->mem[MOD_TEXT].size, .name = mod->name, }; diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 1c648b09e053..1c4639588ff9 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -1177,7 +1177,7 @@ static const struct { static struct ratelimit_state bld_ratelimit; static unsigned int sysctl_sld_mitigate = 1; -static DEFINE_SEMAPHORE(buslock_sem); +static DEFINE_SEMAPHORE(buslock_sem, 1); #ifdef CONFIG_PROC_SYSCTL static struct ctl_table sld_sysctls[] = { diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 7a329e561354..3afcf3de0dd4 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -632,6 +632,7 @@ static const struct attribute_group cpu_root_microcode_group = { static int __init microcode_init(void) { + struct device *dev_root; struct cpuinfo_x86 *c = &boot_cpu_data; int error; @@ -652,10 +653,14 @@ static int __init microcode_init(void) if (IS_ERR(microcode_pdev)) return PTR_ERR(microcode_pdev); - error = sysfs_create_group(&cpu_subsys.dev_root->kobj, &cpu_root_microcode_group); - if (error) { - pr_err("Error creating microcode group!\n"); - goto out_pdev; + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + error = sysfs_create_group(&dev_root->kobj, &cpu_root_microcode_group); + put_device(dev_root); + if (error) { + pr_err("Error creating microcode group!\n"); + goto out_pdev; + } } /* Do per-CPU setup */ diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 315fc358e584..c7969e806c64 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -249,11 +248,6 @@ static uint32_t __init ms_hyperv_platform(void) return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; } -static unsigned char hv_get_nmi_reason(void) -{ - return 0; -} - #ifdef CONFIG_X86_LOCAL_APIC /* * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes @@ -408,12 +402,8 @@ static void __init ms_hyperv_init_platform(void) pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); - if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) { + if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) static_branch_enable(&isolation_type_snp); -#ifdef CONFIG_SWIOTLB - swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary; -#endif - } } if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { @@ -524,6 +514,7 @@ static void __init ms_hyperv_init_platform(void) /* Register Hyper-V specific clocksource */ hv_init_clocksource(); + hv_vtl_init_platform(); #endif /* * TSC should be marked as unstable only after Hyper-V diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 0e7b6afe2fa6..ded1fc7cb7cb 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -383,41 +383,36 @@ void free_rmid(u32 rmid) list_add_tail(&entry->list, &rmid_free_lru); } +static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 rmid, + enum resctrl_event_id evtid) +{ + switch (evtid) { + case QOS_L3_MBM_TOTAL_EVENT_ID: + return &d->mbm_total[rmid]; + case QOS_L3_MBM_LOCAL_EVENT_ID: + return &d->mbm_local[rmid]; + default: + return NULL; + } +} + static int __mon_event_count(u32 rmid, struct rmid_read *rr) { struct mbm_state *m; u64 tval = 0; - if (rr->first) + if (rr->first) { resctrl_arch_reset_rmid(rr->r, rr->d, rmid, rr->evtid); + m = get_mbm_state(rr->d, rmid, rr->evtid); + if (m) + memset(m, 0, sizeof(struct mbm_state)); + return 0; + } rr->err = resctrl_arch_rmid_read(rr->r, rr->d, rmid, rr->evtid, &tval); if (rr->err) return rr->err; - switch (rr->evtid) { - case QOS_L3_OCCUP_EVENT_ID: - rr->val += tval; - return 0; - case QOS_L3_MBM_TOTAL_EVENT_ID: - m = &rr->d->mbm_total[rmid]; - break; - case QOS_L3_MBM_LOCAL_EVENT_ID: - m = &rr->d->mbm_local[rmid]; - break; - default: - /* - * Code would never reach here because an invalid - * event id would fail in resctrl_arch_rmid_read(). - */ - return -EINVAL; - } - - if (rr->first) { - memset(m, 0, sizeof(struct mbm_state)); - return 0; - } - rr->val += tval; return 0; diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c index 524f8ff3e69c..458cb7419502 100644 --- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c +++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c @@ -1580,7 +1580,7 @@ int rdt_pseudo_lock_init(void) pseudo_lock_major = ret; - pseudo_lock_class = class_create(THIS_MODULE, "pseudo_lock"); + pseudo_lock_class = class_create("pseudo_lock"); if (IS_ERR(pseudo_lock_class)) { ret = PTR_ERR(pseudo_lock_class); unregister_chrdev(pseudo_lock_major, "pseudo_lock"); diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c index 5e868b62a7c4..0270925fe013 100644 --- a/arch/x86/kernel/cpu/topology.c +++ b/arch/x86/kernel/cpu/topology.c @@ -79,7 +79,7 @@ int detect_extended_topology_early(struct cpuinfo_x86 *c) * initial apic id, which also represents 32-bit extended x2apic id. */ c->initial_apicid = edx; - smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); + smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx)); #endif return 0; } @@ -109,7 +109,8 @@ int detect_extended_topology(struct cpuinfo_x86 *c) */ cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx); c->initial_apicid = edx; - core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); + core_level_siblings = LEVEL_MAX_SIBLINGS(ebx); + smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx)); core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); die_level_siblings = LEVEL_MAX_SIBLINGS(ebx); pkg_mask_width = die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); diff --git a/arch/x86/kernel/cpu/umwait.c b/arch/x86/kernel/cpu/umwait.c index ec8064c0ae03..2293efd6ffa6 100644 --- a/arch/x86/kernel/cpu/umwait.c +++ b/arch/x86/kernel/cpu/umwait.c @@ -232,7 +232,11 @@ static int __init umwait_init(void) * Add umwait control interface. Ignore failure, so at least the * default values are set up in case the machine manages to boot. */ - dev = cpu_subsys.dev_root; - return sysfs_create_group(&dev->kobj, &umwait_attr_group); + dev = bus_get_dev_root(&cpu_subsys); + if (dev) { + ret = sysfs_create_group(&dev->kobj, &umwait_attr_group); + put_device(dev); + } + return ret; } device_initcall(umwait_init); diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 621ba9c0f17a..bdc0d5539b57 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -154,7 +154,7 @@ static int __init cpuid_init(void) CPUID_MAJOR); return -EBUSY; } - cpuid_class = class_create(THIS_MODULE, "cpuid"); + cpuid_class = class_create("cpuid"); if (IS_ERR(cpuid_class)) { err = PTR_ERR(cpuid_class); goto out_chrdev; diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 0bf6779187dd..f18ca44c904b 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -195,7 +195,6 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, printk("%sCall Trace:\n", log_lvl); unwind_start(&state, task, regs, stack); - stack = stack ? : get_stack_pointer(task, regs); regs = unwind_get_entry_regs(&state, &partial); /* @@ -214,9 +213,13 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, * - hardirq stack * - entry stack */ - for ( ; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { + for (stack = stack ?: get_stack_pointer(task, regs); + stack; + stack = stack_info.next_sp) { const char *stack_name; + stack = PTR_ALIGN(stack, sizeof(long)); + if (get_stack_info(stack, task, &stack_info, &visit_mask)) { /* * We weren't on a valid stack. It's possible that diff --git a/arch/x86/kernel/fpu/context.h b/arch/x86/kernel/fpu/context.h index 9fcfa5c4dad7..af5cbdd9bd29 100644 --- a/arch/x86/kernel/fpu/context.h +++ b/arch/x86/kernel/fpu/context.h @@ -57,7 +57,7 @@ static inline void fpregs_restore_userregs(void) struct fpu *fpu = ¤t->thread.fpu; int cpu = smp_processor_id(); - if (WARN_ON_ONCE(current->flags & (PF_KTHREAD | PF_IO_WORKER))) + if (WARN_ON_ONCE(current->flags & (PF_KTHREAD | PF_USER_WORKER))) return; if (!fpregs_state_valid(fpu, cpu)) { diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index caf33486dc5e..1015af1ae562 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -426,7 +426,7 @@ void kernel_fpu_begin_mask(unsigned int kfpu_mask) this_cpu_write(in_kernel_fpu, true); - if (!(current->flags & (PF_KTHREAD | PF_IO_WORKER)) && + if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER)) && !test_thread_flag(TIF_NEED_FPU_LOAD)) { set_thread_flag(TIF_NEED_FPU_LOAD); save_fpregs_to_fpstate(¤t->thread.fpu); diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S index 970d8445fdc4..b8c720b5dab2 100644 --- a/arch/x86/kernel/ftrace_64.S +++ b/arch/x86/kernel/ftrace_64.S @@ -346,7 +346,7 @@ STACK_FRAME_NON_STANDARD_FP(__fentry__) #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_CODE_START(return_to_handler) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR subq $16, %rsp diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index ec6fefbfd3c0..10c27b4261eb 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -29,7 +29,7 @@ static void __init i386_default_early_setup(void) x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; } -asmlinkage __visible void __init i386_start_kernel(void) +asmlinkage __visible void __init __noreturn i386_start_kernel(void) { /* Make sure IDT is set up before any exception happens */ idt_setup_early_handler(); diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 387e4b12e823..49f7629b17f7 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -471,7 +471,7 @@ static void __init copy_bootdata(char *real_mode_data) sme_unmap_bootdata(real_mode_data); } -asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) +asmlinkage __visible void __init __noreturn x86_64_start_kernel(char * real_mode_data) { /* * Build-time sanity checks on the kernel image and module @@ -537,7 +537,7 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) x86_64_start_reservations(real_mode_data); } -void __init x86_64_start_reservations(char *real_mode_data) +void __init __noreturn x86_64_start_reservations(char *real_mode_data) { /* version is always not zero if it is copied */ if (!boot_params.hdr.version) diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 6a8238702eab..a5df3e994f04 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -42,7 +42,7 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map) __HEAD .code64 SYM_CODE_START_NOALIGN(startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, * and someone has loaded an identity mapped page table @@ -97,7 +97,7 @@ SYM_CODE_START_NOALIGN(startup_64) lretq .Lon_kernel_cs: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Sanitize CPU configuration */ call verify_cpu @@ -119,7 +119,7 @@ SYM_CODE_START_NOALIGN(startup_64) SYM_CODE_END(startup_64) SYM_CODE_START(secondary_startup_64) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 0, @@ -148,7 +148,7 @@ SYM_CODE_START(secondary_startup_64) * verify_cpu() above to make sure NX is enabled. */ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* @@ -230,7 +230,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) ANNOTATE_RETPOLINE_SAFE jmp *%rax 1: - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // above #ifdef CONFIG_SMP @@ -383,7 +383,7 @@ SYM_CODE_END(secondary_startup_64) */ SYM_CODE_START(start_cpu0) ANNOTATE_NOENDBR - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* Find the idle task stack */ movq PER_CPU_VAR(pcpu_hot) + X86_current_task, %rcx @@ -406,8 +406,6 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS @@ -460,7 +458,6 @@ SYM_CODE_END(early_idt_handler_array) SYM_CODE_START_LOCAL(early_idt_handler_common) UNWIND_HINT_IRET_REGS offset=16 - ANNOTATE_UNRET_END /* * The stack is the hardware frame, an error code or zero, and the * vector number. @@ -510,8 +507,6 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb) UNWIND_HINT_IRET_REGS offset=8 ENDBR - ANNOTATE_UNRET_END - /* Build pt_regs */ PUSH_AND_CLEAR_REGS diff --git a/arch/x86/kernel/itmt.c b/arch/x86/kernel/itmt.c index 9ff480e94511..670eb08b972a 100644 --- a/arch/x86/kernel/itmt.c +++ b/arch/x86/kernel/itmt.c @@ -77,15 +77,6 @@ static struct ctl_table itmt_kern_table[] = { {} }; -static struct ctl_table itmt_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = itmt_kern_table, - }, - {} -}; - static struct ctl_table_header *itmt_sysctl_header; /** @@ -114,7 +105,7 @@ int sched_set_itmt_support(void) return 0; } - itmt_sysctl_header = register_sysctl_table(itmt_root_table); + itmt_sysctl_header = register_sysctl("kernel", itmt_kern_table); if (!itmt_sysctl_header) { mutex_unlock(&itmt_update_mutex); return -ENOMEM; diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 0611fd83858e..1a3e2c05a8a5 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -374,17 +374,6 @@ void machine_kexec(struct kimage *image) /* arch-dependent functionality related to kexec file-based syscall */ #ifdef CONFIG_KEXEC_FILE -void *arch_kexec_kernel_image_load(struct kimage *image) -{ - if (!image->fops || !image->fops->load) - return ERR_PTR(-ENOEXEC); - - return image->fops->load(image, image->kernel_buf, - image->kernel_buf_len, image->initrd_buf, - image->initrd_buf_len, image->cmdline_buf, - image->cmdline_buf_len); -} - /* * Apply purgatory relocations. * diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 84ad0e61ba6e..b05f62ee2344 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -362,8 +362,8 @@ int module_finalize(const Elf_Ehdr *hdr, } if (locks) { void *lseg = (void *)locks->sh_addr; - void *text = me->core_layout.base; - void *text_end = text + me->core_layout.text_size; + void *text = me->mem[MOD_TEXT].base; + void *text_end = text + me->mem[MOD_TEXT].size; alternatives_smp_module_add(me, me->name, lseg, lseg + locks->sh_size, text, text_end); diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 708751311786..7bb17d37db01 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -263,7 +263,7 @@ static int __init msr_init(void) pr_err("unable to get major %d for msr\n", MSR_MAJOR); return -EBUSY; } - msr_class = class_create(THIS_MODULE, "msr"); + msr_class = class_create("msr"); if (IS_ERR(msr_class)) { err = PTR_ERR(msr_class); goto out_chrdev; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b650cde3f64d..dac41a0072ea 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include "process.h" @@ -162,6 +164,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) savesegment(es, p->thread.es); savesegment(ds, p->thread.ds); + + if (p->mm && (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM) + set_bit(MM_CONTEXT_LOCK_LAM, &p->mm->context.flags); #else p->thread.sp0 = (unsigned long) (childregs + 1); savesegment(gs, p->thread.gs); @@ -368,6 +373,8 @@ void arch_setup_new_exec(void) task_clear_spec_ssb_noexec(current); speculation_ctrl_update(read_thread_flags()); } + + mm_reset_untag_mask(current->mm); } #ifdef CONFIG_X86_IOPL_IOPERM @@ -715,7 +722,7 @@ static bool x86_idle_set(void) } #ifndef CONFIG_SMP -static inline void play_dead(void) +static inline void __noreturn play_dead(void) { BUG(); } @@ -727,7 +734,7 @@ void arch_cpu_idle_enter(void) local_touch_nmi(); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { play_dead(); } diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index bb65a68b4b49..3d181c16a2f6 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -671,7 +672,7 @@ void set_personality_64bit(void) task_pt_regs(current)->orig_ax = __NR_execve; current_thread_info()->status &= ~TS_COMPAT; if (current->mm) - current->mm->context.flags = MM_CONTEXT_HAS_VSYSCALL; + __set_bit(MM_CONTEXT_HAS_VSYSCALL, ¤t->mm->context.flags); /* TBD: overwrites user setup. Should have two bits. But 64bit processes have always behaved this way, @@ -708,7 +709,7 @@ static void __set_personality_ia32(void) * uprobes applied to this MM need to know this and * cannot use user_64bit_mode() at that time. */ - current->mm->context.flags = MM_CONTEXT_UPROBE_IA32; + __set_bit(MM_CONTEXT_UPROBE_IA32, ¤t->mm->context.flags); } current->personality |= force_personality32; @@ -743,6 +744,52 @@ static long prctl_map_vdso(const struct vdso_image *image, unsigned long addr) } #endif +#ifdef CONFIG_ADDRESS_MASKING + +#define LAM_U57_BITS 6 + +static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits) +{ + if (!cpu_feature_enabled(X86_FEATURE_LAM)) + return -ENODEV; + + /* PTRACE_ARCH_PRCTL */ + if (current->mm != mm) + return -EINVAL; + + if (mm_valid_pasid(mm) && + !test_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &mm->context.flags)) + return -EINVAL; + + if (mmap_write_lock_killable(mm)) + return -EINTR; + + if (test_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags)) { + mmap_write_unlock(mm); + return -EBUSY; + } + + if (!nr_bits) { + mmap_write_unlock(mm); + return -EINVAL; + } else if (nr_bits <= LAM_U57_BITS) { + mm->context.lam_cr3_mask = X86_CR3_LAM_U57; + mm->context.untag_mask = ~GENMASK(62, 57); + } else { + mmap_write_unlock(mm); + return -EINVAL; + } + + write_cr3(__read_cr3() | mm->context.lam_cr3_mask); + set_tlbstate_lam_mode(mm); + set_bit(MM_CONTEXT_LOCK_LAM, &mm->context.flags); + + mmap_write_unlock(mm); + + return 0; +} +#endif + long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2) { int ret = 0; @@ -830,7 +877,23 @@ long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2) case ARCH_MAP_VDSO_64: return prctl_map_vdso(&vdso_image_64, arg2); #endif - +#ifdef CONFIG_ADDRESS_MASKING + case ARCH_GET_UNTAG_MASK: + return put_user(task->mm->context.untag_mask, + (unsigned long __user *)arg2); + case ARCH_ENABLE_TAGGED_ADDR: + return prctl_enable_tagged_addr(task->mm, arg2); + case ARCH_FORCE_TAGGED_SVA: + if (current != task) + return -EINVAL; + set_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &task->mm->context.flags); + return 0; + case ARCH_GET_MAX_TAG_BITS: + if (!cpu_feature_enabled(X86_FEATURE_LAM)) + return put_user(0, (unsigned long __user *)arg2); + else + return put_user(LAM_U57_BITS, (unsigned long __user *)arg2); +#endif default: ret = -EINVAL; break; diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d03c551defcc..3adbe97015c1 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -920,7 +920,7 @@ void run_crash_ipi_callback(struct pt_regs *regs) } /* Override the weak function in kernel/panic.c */ -void nmi_panic_self_stop(struct pt_regs *regs) +void __noreturn nmi_panic_self_stop(struct pt_regs *regs) { while (1) { /* If no CPU is preparing crash dump, we simply loop here. */ diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index 4a73351f87f8..56cab1bb25f5 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -43,7 +43,7 @@ .code64 SYM_CODE_START_NOALIGN(relocate_range) SYM_CODE_START_NOALIGN(relocate_kernel) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR /* * %rdi indirection_page @@ -113,7 +113,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel) SYM_CODE_END(relocate_kernel) SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK /* set return address to 0 if not preserving context */ pushq $0 /* store the start address on the stack */ @@ -231,7 +231,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped) SYM_CODE_END(identity_mapped) SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR // RET target, above movq RSP(%r8), %rsp movq CR4(%r8), %rax @@ -256,8 +256,8 @@ SYM_CODE_END(virtual_mapped) /* Do the copies */ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) - UNWIND_HINT_EMPTY - movq %rdi, %rcx /* Put the page_list in %rcx */ + UNWIND_HINT_END_OF_STACK + movq %rdi, %rcx /* Put the page_list in %rcx */ xorl %edi, %edi xorl %esi, %esi jmp 1f diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 851477f7d728..352f0ce1ece4 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1824,7 +1824,7 @@ static inline void mwait_play_dead(void) } } -void hlt_play_dead(void) +void __noreturn hlt_play_dead(void) { if (__this_cpu_read(cpu_info.x86) >= 4) wbinvd(); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index d317dc3d06a3..58b1f208eff5 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include @@ -671,15 +671,15 @@ static bool try_fixup_enqcmd_gp(void) if (!cpu_feature_enabled(X86_FEATURE_ENQCMD)) return false; - pasid = current->mm->pasid; - /* * If the mm has not been allocated a * PASID, the #GP can not be fixed up. */ - if (!pasid_valid(pasid)) + if (!mm_valid_pasid(current->mm)) return false; + pasid = current->mm->pasid; + /* * Did this thread already have its PASID activated? * If so, the #GP must be from something else. diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 37307b40f8da..3ac50b7298d1 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -133,7 +133,7 @@ static struct orc_entry null_orc_entry = { .sp_offset = sizeof(long), .sp_reg = ORC_REG_SP, .bp_reg = ORC_REG_UNDEFINED, - .type = UNWIND_HINT_TYPE_CALL + .type = ORC_TYPE_CALL }; #ifdef CONFIG_CALL_THUNKS @@ -153,12 +153,11 @@ static struct orc_entry *orc_callthunk_find(unsigned long ip) /* Fake frame pointer entry -- used as a fallback for generated code */ static struct orc_entry orc_fp_entry = { - .type = UNWIND_HINT_TYPE_CALL, + .type = ORC_TYPE_CALL, .sp_reg = ORC_REG_BP, .sp_offset = 16, .bp_reg = ORC_REG_PREV_SP, .bp_offset = -16, - .end = 0, }; static struct orc_entry *orc_find(unsigned long ip) @@ -250,13 +249,13 @@ static int orc_sort_cmp(const void *_a, const void *_b) return -1; /* - * The "weak" section terminator entries need to always be on the left + * The "weak" section terminator entries need to always be first * to ensure the lookup code skips them in favor of real entries. * These terminator entries exist to handle any gaps created by * whitelisted .o files which didn't get objtool generation. */ orc_a = cur_orc_table + (a - cur_orc_ip_table); - return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; + return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1; } void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size, @@ -474,14 +473,12 @@ bool unwind_next_frame(struct unwind_state *state) */ orc = &orc_fp_entry; state->error = true; - } - - /* End-of-stack check for kernel threads: */ - if (orc->sp_reg == ORC_REG_UNDEFINED) { - if (!orc->end) + } else { + if (orc->type == ORC_TYPE_UNDEFINED) goto err; - goto the_end; + if (orc->type == ORC_TYPE_END_OF_STACK) + goto the_end; } state->signal = orc->signal; @@ -554,7 +551,7 @@ bool unwind_next_frame(struct unwind_state *state) /* Find IP, SP and possibly regs: */ switch (orc->type) { - case UNWIND_HINT_TYPE_CALL: + case ORC_TYPE_CALL: ip_p = sp - sizeof(long); if (!deref_stack_reg(state, ip_p, &state->ip)) @@ -567,7 +564,7 @@ bool unwind_next_frame(struct unwind_state *state) state->prev_regs = NULL; break; - case UNWIND_HINT_TYPE_REGS: + case ORC_TYPE_REGS: if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) { orc_warn_current("can't access registers at %pB\n", (void *)orig_ip); @@ -590,13 +587,13 @@ bool unwind_next_frame(struct unwind_state *state) state->full_regs = true; break; - case UNWIND_HINT_TYPE_REGS_PARTIAL: + case ORC_TYPE_REGS_PARTIAL: if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) { orc_warn_current("can't access iret registers at %pB\n", (void *)orig_ip); goto err; } - /* See UNWIND_HINT_TYPE_REGS case comment. */ + /* See ORC_TYPE_REGS case comment. */ state->ip = unwind_recover_rethook(state, state->ip, (unsigned long *)(state->sp - sizeof(long))); diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index ecdeb0974a87..d82f4fa2f1bf 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -33,8 +33,8 @@ static int __init iommu_init_noop(void) { return 0; } static void iommu_shutdown_noop(void) { } bool __init bool_x86_init_noop(void) { return false; } void x86_op_int_noop(int cpu) { } -static int set_rtc_noop(const struct timespec64 *now) { return -EINVAL; } -static void get_rtc_noop(struct timespec64 *now) { } +int set_rtc_noop(const struct timespec64 *now) { return -EINVAL; } +void get_rtc_noop(struct timespec64 *now) { } static __initconst const struct of_device_id of_cmos_match[] = { { .compatible = "motorola,mc146818" }, diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 599aebec2d52..0c9660a07b23 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -60,12 +60,6 @@ u32 xstate_required_size(u64 xstate_bv, bool compacted) return ret; } -/* - * This one is tied to SSB in the user API, and not - * visible in /proc/cpuinfo. - */ -#define KVM_X86_FEATURE_AMD_PSFD (13*32+28) /* Predictive Store Forwarding Disable */ - #define F feature_bit /* Scattered Flag - For features that are scattered by cpufeatures.h. */ @@ -259,14 +253,13 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e int nent) { struct kvm_cpuid_entry2 *best; - u64 guest_supported_xcr0 = cpuid_get_supported_xcr0(entries, nent); best = cpuid_entry2_find(entries, nent, 1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) { /* Update OSXSAVE bit */ if (boot_cpu_has(X86_FEATURE_XSAVE)) cpuid_entry_change(best, X86_FEATURE_OSXSAVE, - kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE)); + kvm_is_cr4_bit_set(vcpu, X86_CR4_OSXSAVE)); cpuid_entry_change(best, X86_FEATURE_APIC, vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE); @@ -275,7 +268,7 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best = cpuid_entry2_find(entries, nent, 7, 0); if (best && boot_cpu_has(X86_FEATURE_PKU) && best->function == 0x7) cpuid_entry_change(best, X86_FEATURE_OSPKE, - kvm_read_cr4_bits(vcpu, X86_CR4_PKE)); + kvm_is_cr4_bit_set(vcpu, X86_CR4_PKE)); best = cpuid_entry2_find(entries, nent, 0xD, 0); if (best) @@ -298,21 +291,6 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e vcpu->arch.ia32_misc_enable_msr & MSR_IA32_MISC_ENABLE_MWAIT); } - - /* - * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate - * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's - * requested XCR0 value. The enclave's XFRM must be a subset of XCRO - * at the time of EENTER, thus adjust the allowed XFRM by the guest's - * supported XCR0. Similar to XCR0 handling, FP and SSE are forced to - * '1' even on CPUs that don't support XSAVE. - */ - best = cpuid_entry2_find(entries, nent, 0x12, 0x1); - if (best) { - best->ecx &= guest_supported_xcr0 & 0xffffffff; - best->edx &= guest_supported_xcr0 >> 32; - best->ecx |= XFEATURE_MASK_FPSSE; - } } void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) @@ -420,7 +398,7 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2, * KVM_SET_CPUID{,2} again. To support this legacy behavior, check * whether the supplied CPUID data is equal to what's already set. */ - if (vcpu->arch.last_vmentry_cpu != -1) { + if (kvm_vcpu_has_run(vcpu)) { r = kvm_cpuid_check_equal(vcpu, e2, nent); if (r) return r; @@ -653,7 +631,7 @@ void kvm_set_cpu_caps(void) F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) | F(MD_CLEAR) | F(AVX512_VP2INTERSECT) | F(FSRM) | F(SERIALIZE) | F(TSXLDTRK) | F(AVX512_FP16) | - F(AMX_TILE) | F(AMX_INT8) | F(AMX_BF16) + F(AMX_TILE) | F(AMX_INT8) | F(AMX_BF16) | F(FLUSH_L1D) ); /* TSC_ADJUST and ARCH_CAPABILITIES are emulated in software. */ @@ -715,7 +693,7 @@ void kvm_set_cpu_caps(void) F(CLZERO) | F(XSAVEERPTR) | F(WBNOINVD) | F(AMD_IBPB) | F(AMD_IBRS) | F(AMD_SSBD) | F(VIRT_SSBD) | F(AMD_SSB_NO) | F(AMD_STIBP) | F(AMD_STIBP_ALWAYS_ON) | - __feature_bit(KVM_X86_FEATURE_AMD_PSFD) + F(AMD_PSFD) ); /* @@ -1002,7 +980,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) entry->eax = entry->ebx = entry->ecx = 0; break; case 0xd: { - u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm(); + u64 permitted_xcr0 = kvm_get_filtered_xcr0(); u64 permitted_xss = kvm_caps.supported_xss; entry->eax &= permitted_xcr0; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index a20bec931764..936a397a08cd 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1640,6 +1640,14 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, goto exception; break; case VCPU_SREG_CS: + /* + * KVM uses "none" when loading CS as part of emulating Real + * Mode exceptions and IRET (handled above). In all other + * cases, loading CS without a control transfer is a KVM bug. + */ + if (WARN_ON_ONCE(transfer == X86_TRANSFER_NONE)) + goto exception; + if (!(seg_desc.type & 8)) goto exception; diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index 4c91f626c058..75eae9c4998a 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -4,7 +4,7 @@ #include -#define KVM_POSSIBLE_CR0_GUEST_BITS X86_CR0_TS +#define KVM_POSSIBLE_CR0_GUEST_BITS (X86_CR0_TS | X86_CR0_WP) #define KVM_POSSIBLE_CR4_GUEST_BITS \ (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR \ | X86_CR4_OSXMMEXCPT | X86_CR4_PGE | X86_CR4_TSD | X86_CR4_FSGSBASE) @@ -157,6 +157,14 @@ static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask) return vcpu->arch.cr0 & mask; } +static __always_inline bool kvm_is_cr0_bit_set(struct kvm_vcpu *vcpu, + unsigned long cr0_bit) +{ + BUILD_BUG_ON(!is_power_of_2(cr0_bit)); + + return !!kvm_read_cr0_bits(vcpu, cr0_bit); +} + static inline ulong kvm_read_cr0(struct kvm_vcpu *vcpu) { return kvm_read_cr0_bits(vcpu, ~0UL); @@ -171,6 +179,14 @@ static inline ulong kvm_read_cr4_bits(struct kvm_vcpu *vcpu, ulong mask) return vcpu->arch.cr4 & mask; } +static __always_inline bool kvm_is_cr4_bit_set(struct kvm_vcpu *vcpu, + unsigned long cr4_bit) +{ + BUILD_BUG_ON(!is_power_of_2(cr4_bit)); + + return !!kvm_read_cr4_bits(vcpu, cr4_bit); +} + static inline ulong kvm_read_cr3(struct kvm_vcpu *vcpu) { if (!kvm_register_is_available(vcpu, VCPU_EXREG_CR3)) diff --git a/arch/x86/kvm/kvm_onhyperv.c b/arch/x86/kvm/kvm_onhyperv.c index 482d6639ef88..ded0bd688c65 100644 --- a/arch/x86/kvm/kvm_onhyperv.c +++ b/arch/x86/kvm/kvm_onhyperv.c @@ -10,17 +10,22 @@ #include "hyperv.h" #include "kvm_onhyperv.h" +struct kvm_hv_tlb_range { + u64 start_gfn; + u64 pages; +}; + static int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush, void *data) { - struct kvm_tlb_range *range = data; + struct kvm_hv_tlb_range *range = data; return hyperv_fill_flush_guest_mapping_list(flush, range->start_gfn, range->pages); } static inline int hv_remote_flush_root_tdp(hpa_t root_tdp, - struct kvm_tlb_range *range) + struct kvm_hv_tlb_range *range) { if (range) return hyperv_flush_guest_mapping_range(root_tdp, @@ -29,8 +34,8 @@ static inline int hv_remote_flush_root_tdp(hpa_t root_tdp, return hyperv_flush_guest_mapping(root_tdp); } -int hv_remote_flush_tlb_with_range(struct kvm *kvm, - struct kvm_tlb_range *range) +static int __hv_flush_remote_tlbs_range(struct kvm *kvm, + struct kvm_hv_tlb_range *range) { struct kvm_arch *kvm_arch = &kvm->arch; struct kvm_vcpu *vcpu; @@ -86,19 +91,29 @@ int hv_remote_flush_tlb_with_range(struct kvm *kvm, spin_unlock(&kvm_arch->hv_root_tdp_lock); return ret; } -EXPORT_SYMBOL_GPL(hv_remote_flush_tlb_with_range); -int hv_remote_flush_tlb(struct kvm *kvm) +int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t start_gfn, gfn_t nr_pages) { - return hv_remote_flush_tlb_with_range(kvm, NULL); + struct kvm_hv_tlb_range range = { + .start_gfn = start_gfn, + .pages = nr_pages, + }; + + return __hv_flush_remote_tlbs_range(kvm, &range); } -EXPORT_SYMBOL_GPL(hv_remote_flush_tlb); +EXPORT_SYMBOL_GPL(hv_flush_remote_tlbs_range); + +int hv_flush_remote_tlbs(struct kvm *kvm) +{ + return __hv_flush_remote_tlbs_range(kvm, NULL); +} +EXPORT_SYMBOL_GPL(hv_flush_remote_tlbs); void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp) { struct kvm_arch *kvm_arch = &vcpu->kvm->arch; - if (kvm_x86_ops.tlb_remote_flush == hv_remote_flush_tlb) { + if (kvm_x86_ops.flush_remote_tlbs == hv_flush_remote_tlbs) { spin_lock(&kvm_arch->hv_root_tdp_lock); vcpu->arch.hv_root_tdp = root_tdp; if (root_tdp != kvm_arch->hv_root_tdp) diff --git a/arch/x86/kvm/kvm_onhyperv.h b/arch/x86/kvm/kvm_onhyperv.h index 6272dabec02d..f9ca3e7432b2 100644 --- a/arch/x86/kvm/kvm_onhyperv.h +++ b/arch/x86/kvm/kvm_onhyperv.h @@ -7,12 +7,11 @@ #define __ARCH_X86_KVM_KVM_ONHYPERV_H__ #if IS_ENABLED(CONFIG_HYPERV) -int hv_remote_flush_tlb_with_range(struct kvm *kvm, - struct kvm_tlb_range *range); -int hv_remote_flush_tlb(struct kvm *kvm); +int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages); +int hv_flush_remote_tlbs(struct kvm *kvm); void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp); #else /* !CONFIG_HYPERV */ -static inline int hv_remote_flush_tlb(struct kvm *kvm) +static inline int hv_flush_remote_tlbs(struct kvm *kvm) { return -EOPNOTSUPP; } diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e542cf285b51..3c300a196bdf 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -228,6 +228,23 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new, u32 xapic_id = kvm_xapic_id(apic); u32 physical_id; + /* + * For simplicity, KVM always allocates enough space for all possible + * xAPIC IDs. Yell, but don't kill the VM, as KVM can continue on + * without the optimized map. + */ + if (WARN_ON_ONCE(xapic_id > new->max_apic_id)) + return -EINVAL; + + /* + * Bail if a vCPU was added and/or enabled its APIC between allocating + * the map and doing the actual calculations for the map. Note, KVM + * hardcodes the x2APIC ID to vcpu_id, i.e. there's no TOCTOU bug if + * the compiler decides to reload x2apic_id after this check. + */ + if (x2apic_id > new->max_apic_id) + return -E2BIG; + /* * Deliberately truncate the vCPU ID when detecting a mismatched APIC * ID to avoid false positives if the vCPU ID, i.e. x2APIC ID, is a @@ -253,8 +270,7 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new, */ if (vcpu->kvm->arch.x2apic_format) { /* See also kvm_apic_match_physical_addr(). */ - if ((apic_x2apic_mode(apic) || x2apic_id > 0xff) && - x2apic_id <= new->max_apic_id) + if (apic_x2apic_mode(apic) || x2apic_id > 0xff) new->phys_map[x2apic_id] = apic; if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id]) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 168c46fd8dd1..92d5a1924fc1 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -113,6 +113,8 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu); int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code, u64 fault_address, char *insn, int insn_len); +void __kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu, + struct kvm_mmu *mmu); int kvm_mmu_load(struct kvm_vcpu *vcpu); void kvm_mmu_unload(struct kvm_vcpu *vcpu); @@ -132,7 +134,7 @@ static inline unsigned long kvm_get_pcid(struct kvm_vcpu *vcpu, gpa_t cr3) { BUILD_BUG_ON((X86_CR3_PCID_MASK & PAGE_MASK) != 0); - return kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE) + return kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE) ? cr3 & X86_CR3_PCID_MASK : 0; } @@ -153,6 +155,24 @@ static inline void kvm_mmu_load_pgd(struct kvm_vcpu *vcpu) vcpu->arch.mmu->root_role.level); } +static inline void kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu, + struct kvm_mmu *mmu) +{ + /* + * When EPT is enabled, KVM may passthrough CR0.WP to the guest, i.e. + * @mmu's snapshot of CR0.WP and thus all related paging metadata may + * be stale. Refresh CR0.WP and the metadata on-demand when checking + * for permission faults. Exempt nested MMUs, i.e. MMUs for shadowing + * nEPT and nNPT, as CR0.WP is ignored in both cases. Note, KVM does + * need to refresh nested_mmu, a.k.a. the walker used to translate L2 + * GVAs to GPAs, as that "MMU" needs to honor L2's CR0.WP. + */ + if (!tdp_enabled || mmu == &vcpu->arch.guest_mmu) + return; + + __kvm_mmu_refresh_passthrough_bits(vcpu, mmu); +} + /* * Check if a given access (described through the I/D, W/R and U/S bits of a * page fault error code pfec) causes a permission fault with the given PTE @@ -184,8 +204,12 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, u64 implicit_access = access & PFERR_IMPLICIT_ACCESS; bool not_smap = ((rflags & X86_EFLAGS_AC) | implicit_access) == X86_EFLAGS_AC; int index = (pfec + (not_smap << PFERR_RSVD_BIT)) >> 1; - bool fault = (mmu->permissions[index] >> pte_access) & 1; u32 errcode = PFERR_PRESENT_MASK; + bool fault; + + kvm_mmu_refresh_passthrough_bits(vcpu, mmu); + + fault = (mmu->permissions[index] >> pte_access) & 1; WARN_ON(pfec & (PFERR_PK_MASK | PFERR_RSVD_MASK)); if (unlikely(mmu->pkru_mask)) { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c8ebe542c565..6eaa3d6994ae 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -125,17 +125,31 @@ module_param(dbg, bool, 0644); #define PTE_LIST_EXT 14 /* - * Slight optimization of cacheline layout, by putting `more' and `spte_count' - * at the start; then accessing it will only use one single cacheline for - * either full (entries==PTE_LIST_EXT) case or entries<=6. + * struct pte_list_desc is the core data structure used to implement a custom + * list for tracking a set of related SPTEs, e.g. all the SPTEs that map a + * given GFN when used in the context of rmaps. Using a custom list allows KVM + * to optimize for the common case where many GFNs will have at most a handful + * of SPTEs pointing at them, i.e. allows packing multiple SPTEs into a small + * memory footprint, which in turn improves runtime performance by exploiting + * cache locality. + * + * A list is comprised of one or more pte_list_desc objects (descriptors). + * Each individual descriptor stores up to PTE_LIST_EXT SPTEs. If a descriptor + * is full and a new SPTEs needs to be added, a new descriptor is allocated and + * becomes the head of the list. This means that by definitions, all tail + * descriptors are full. + * + * Note, the meta data fields are deliberately placed at the start of the + * structure to optimize the cacheline layout; accessing the descriptor will + * touch only a single cacheline so long as @spte_count<=6 (or if only the + * descriptors metadata is accessed). */ struct pte_list_desc { struct pte_list_desc *more; - /* - * Stores number of entries stored in the pte_list_desc. No need to be - * u64 but just for easier alignment. When PTE_LIST_EXT, means full. - */ - u64 spte_count; + /* The number of PTEs stored in _this_ descriptor. */ + u32 spte_count; + /* The number of PTEs stored in all tails of this descriptor. */ + u32 tail_count; u64 *sptes[PTE_LIST_EXT]; }; @@ -242,34 +256,37 @@ static struct kvm_mmu_role_regs vcpu_to_role_regs(struct kvm_vcpu *vcpu) return regs; } -static inline bool kvm_available_flush_tlb_with_range(void) +static unsigned long get_guest_cr3(struct kvm_vcpu *vcpu) { - return kvm_x86_ops.tlb_remote_flush_with_range; + return kvm_read_cr3(vcpu); } -static void kvm_flush_remote_tlbs_with_range(struct kvm *kvm, - struct kvm_tlb_range *range) +static inline unsigned long kvm_mmu_get_guest_pgd(struct kvm_vcpu *vcpu, + struct kvm_mmu *mmu) { - int ret = -ENOTSUPP; + if (IS_ENABLED(CONFIG_RETPOLINE) && mmu->get_guest_pgd == get_guest_cr3) + return kvm_read_cr3(vcpu); - if (range && kvm_x86_ops.tlb_remote_flush_with_range) - ret = static_call(kvm_x86_tlb_remote_flush_with_range)(kvm, range); + return mmu->get_guest_pgd(vcpu); +} +static inline bool kvm_available_flush_remote_tlbs_range(void) +{ + return kvm_x86_ops.flush_remote_tlbs_range; +} + +void kvm_flush_remote_tlbs_range(struct kvm *kvm, gfn_t start_gfn, + gfn_t nr_pages) +{ + int ret = -EOPNOTSUPP; + + if (kvm_x86_ops.flush_remote_tlbs_range) + ret = static_call(kvm_x86_flush_remote_tlbs_range)(kvm, start_gfn, + nr_pages); if (ret) kvm_flush_remote_tlbs(kvm); } -void kvm_flush_remote_tlbs_with_address(struct kvm *kvm, - u64 start_gfn, u64 pages) -{ - struct kvm_tlb_range range; - - range.start_gfn = start_gfn; - range.pages = pages; - - kvm_flush_remote_tlbs_with_range(kvm, &range); -} - static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index); /* Flush the range of guest memory mapped by the given SPTE. */ @@ -888,9 +905,9 @@ static void unaccount_nx_huge_page(struct kvm *kvm, struct kvm_mmu_page *sp) untrack_possible_nx_huge_page(kvm, sp); } -static struct kvm_memory_slot * -gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t gfn, - bool no_dirty_log) +static struct kvm_memory_slot *gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, + gfn_t gfn, + bool no_dirty_log) { struct kvm_memory_slot *slot; @@ -929,53 +946,69 @@ static int pte_list_add(struct kvm_mmu_memory_cache *cache, u64 *spte, desc->sptes[0] = (u64 *)rmap_head->val; desc->sptes[1] = spte; desc->spte_count = 2; + desc->tail_count = 0; rmap_head->val = (unsigned long)desc | 1; ++count; } else { rmap_printk("%p %llx many->many\n", spte, *spte); desc = (struct pte_list_desc *)(rmap_head->val & ~1ul); - while (desc->spte_count == PTE_LIST_EXT) { - count += PTE_LIST_EXT; - if (!desc->more) { - desc->more = kvm_mmu_memory_cache_alloc(cache); - desc = desc->more; - desc->spte_count = 0; - break; - } - desc = desc->more; + count = desc->tail_count + desc->spte_count; + + /* + * If the previous head is full, allocate a new head descriptor + * as tail descriptors are always kept full. + */ + if (desc->spte_count == PTE_LIST_EXT) { + desc = kvm_mmu_memory_cache_alloc(cache); + desc->more = (struct pte_list_desc *)(rmap_head->val & ~1ul); + desc->spte_count = 0; + desc->tail_count = count; + rmap_head->val = (unsigned long)desc | 1; } - count += desc->spte_count; desc->sptes[desc->spte_count++] = spte; } return count; } -static void -pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head, - struct pte_list_desc *desc, int i, - struct pte_list_desc *prev_desc) +static void pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head, + struct pte_list_desc *desc, int i) { - int j = desc->spte_count - 1; + struct pte_list_desc *head_desc = (struct pte_list_desc *)(rmap_head->val & ~1ul); + int j = head_desc->spte_count - 1; - desc->sptes[i] = desc->sptes[j]; - desc->sptes[j] = NULL; - desc->spte_count--; - if (desc->spte_count) + /* + * The head descriptor should never be empty. A new head is added only + * when adding an entry and the previous head is full, and heads are + * removed (this flow) when they become empty. + */ + BUG_ON(j < 0); + + /* + * Replace the to-be-freed SPTE with the last valid entry from the head + * descriptor to ensure that tail descriptors are full at all times. + * Note, this also means that tail_count is stable for each descriptor. + */ + desc->sptes[i] = head_desc->sptes[j]; + head_desc->sptes[j] = NULL; + head_desc->spte_count--; + if (head_desc->spte_count) return; - if (!prev_desc && !desc->more) + + /* + * The head descriptor is empty. If there are no tail descriptors, + * nullify the rmap head to mark the list as emtpy, else point the rmap + * head at the next descriptor, i.e. the new head. + */ + if (!head_desc->more) rmap_head->val = 0; else - if (prev_desc) - prev_desc->more = desc->more; - else - rmap_head->val = (unsigned long)desc->more | 1; - mmu_free_pte_list_desc(desc); + rmap_head->val = (unsigned long)head_desc->more | 1; + mmu_free_pte_list_desc(head_desc); } static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc; - struct pte_list_desc *prev_desc; int i; if (!rmap_head->val) { @@ -991,16 +1024,13 @@ static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) } else { rmap_printk("%p many->many\n", spte); desc = (struct pte_list_desc *)(rmap_head->val & ~1ul); - prev_desc = NULL; while (desc) { for (i = 0; i < desc->spte_count; ++i) { if (desc->sptes[i] == spte) { - pte_list_desc_remove_entry(rmap_head, - desc, i, prev_desc); + pte_list_desc_remove_entry(rmap_head, desc, i); return; } } - prev_desc = desc; desc = desc->more; } pr_err("%s: %p many->many\n", __func__, spte); @@ -1047,7 +1077,6 @@ out: unsigned int pte_list_count(struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc; - unsigned int count = 0; if (!rmap_head->val) return 0; @@ -1055,13 +1084,7 @@ unsigned int pte_list_count(struct kvm_rmap_head *rmap_head) return 1; desc = (struct pte_list_desc *)(rmap_head->val & ~1ul); - - while (desc) { - count += desc->spte_count; - desc = desc->more; - } - - return count; + return desc->tail_count + desc->spte_count; } static struct kvm_rmap_head *gfn_to_rmap(gfn_t gfn, int level, @@ -1073,14 +1096,6 @@ static struct kvm_rmap_head *gfn_to_rmap(gfn_t gfn, int level, return &slot->arch.rmap[level - PG_LEVEL_4K][idx]; } -static bool rmap_can_add(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu_memory_cache *mc; - - mc = &vcpu->arch.mmu_pte_list_desc_cache; - return kvm_mmu_memory_cache_nr_free_objects(mc); -} - static void rmap_remove(struct kvm *kvm, u64 *spte) { struct kvm_memslots *slots; @@ -1479,7 +1494,7 @@ restart: } } - if (need_flush && kvm_available_flush_tlb_with_range()) { + if (need_flush && kvm_available_flush_remote_tlbs_range()) { kvm_flush_remote_tlbs_gfn(kvm, gfn, level); return false; } @@ -1504,8 +1519,8 @@ struct slot_rmap_walk_iterator { struct kvm_rmap_head *end_rmap; }; -static void -rmap_walk_init_level(struct slot_rmap_walk_iterator *iterator, int level) +static void rmap_walk_init_level(struct slot_rmap_walk_iterator *iterator, + int level) { iterator->level = level; iterator->gfn = iterator->start_gfn; @@ -1513,10 +1528,10 @@ rmap_walk_init_level(struct slot_rmap_walk_iterator *iterator, int level) iterator->end_rmap = gfn_to_rmap(iterator->end_gfn, level, iterator->slot); } -static void -slot_rmap_walk_init(struct slot_rmap_walk_iterator *iterator, - const struct kvm_memory_slot *slot, int start_level, - int end_level, gfn_t start_gfn, gfn_t end_gfn) +static void slot_rmap_walk_init(struct slot_rmap_walk_iterator *iterator, + const struct kvm_memory_slot *slot, + int start_level, int end_level, + gfn_t start_gfn, gfn_t end_gfn) { iterator->slot = slot; iterator->start_level = start_level; @@ -1789,12 +1804,6 @@ static void mark_unsync(u64 *spte) kvm_mmu_mark_parents_unsync(sp); } -static int nonpaging_sync_page(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp) -{ - return -1; -} - #define KVM_PAGE_ARRAY_NR 16 struct kvm_mmu_pages { @@ -1914,10 +1923,79 @@ static bool sp_has_gptes(struct kvm_mmu_page *sp) &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)]) \ if ((_sp)->gfn != (_gfn) || !sp_has_gptes(_sp)) {} else +static bool kvm_sync_page_check(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) +{ + union kvm_mmu_page_role root_role = vcpu->arch.mmu->root_role; + + /* + * Ignore various flags when verifying that it's safe to sync a shadow + * page using the current MMU context. + * + * - level: not part of the overall MMU role and will never match as the MMU's + * level tracks the root level + * - access: updated based on the new guest PTE + * - quadrant: not part of the overall MMU role (similar to level) + */ + const union kvm_mmu_page_role sync_role_ign = { + .level = 0xf, + .access = 0x7, + .quadrant = 0x3, + .passthrough = 0x1, + }; + + /* + * Direct pages can never be unsync, and KVM should never attempt to + * sync a shadow page for a different MMU context, e.g. if the role + * differs then the memslot lookup (SMM vs. non-SMM) will be bogus, the + * reserved bits checks will be wrong, etc... + */ + if (WARN_ON_ONCE(sp->role.direct || !vcpu->arch.mmu->sync_spte || + (sp->role.word ^ root_role.word) & ~sync_role_ign.word)) + return false; + + return true; +} + +static int kvm_sync_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int i) +{ + if (!sp->spt[i]) + return 0; + + return vcpu->arch.mmu->sync_spte(vcpu, sp, i); +} + +static int __kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) +{ + int flush = 0; + int i; + + if (!kvm_sync_page_check(vcpu, sp)) + return -1; + + for (i = 0; i < SPTE_ENT_PER_PAGE; i++) { + int ret = kvm_sync_spte(vcpu, sp, i); + + if (ret < -1) + return -1; + flush |= ret; + } + + /* + * Note, any flush is purely for KVM's correctness, e.g. when dropping + * an existing SPTE or clearing W/A/D bits to ensure an mmu_notifier + * unmap or dirty logging event doesn't fail to flush. The guest is + * responsible for flushing the TLB to ensure any changes in protection + * bits are recognized, i.e. until the guest flushes or page faults on + * a relevant address, KVM is architecturally allowed to let vCPUs use + * cached translations with the old protection bits. + */ + return flush; +} + static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, struct list_head *invalid_list) { - int ret = vcpu->arch.mmu->sync_page(vcpu, sp); + int ret = __kvm_sync_page(vcpu, sp); if (ret < 0) kvm_mmu_prepare_zap_page(vcpu->kvm, sp, invalid_list); @@ -3304,9 +3382,9 @@ static bool page_fault_can_be_fast(struct kvm_page_fault *fault) * Returns true if the SPTE was fixed successfully. Otherwise, * someone else modified the SPTE from its original value. */ -static bool -fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, - u64 *sptep, u64 old_spte, u64 new_spte) +static bool fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault, + u64 *sptep, u64 old_spte, u64 new_spte) { /* * Theoretically we could also set dirty bit (and flush TLB) here in @@ -3513,6 +3591,8 @@ void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, LIST_HEAD(invalid_list); bool free_active_root; + WARN_ON_ONCE(roots_to_free & ~KVM_MMU_ROOTS_ALL); + BUILD_BUG_ON(KVM_MMU_NUM_PREV_ROOTS >= BITS_PER_LONG); /* Before acquiring the MMU lock, see if we need to do any real work. */ @@ -3731,7 +3811,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) int quadrant, i, r; hpa_t root; - root_pgd = mmu->get_guest_pgd(vcpu); + root_pgd = kvm_mmu_get_guest_pgd(vcpu, mmu); root_gfn = root_pgd >> PAGE_SHIFT; if (mmu_check_root(vcpu, root_gfn)) @@ -4181,7 +4261,7 @@ static bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, arch.token = alloc_apf_token(vcpu); arch.gfn = gfn; arch.direct_map = vcpu->arch.mmu->root_role.direct; - arch.cr3 = vcpu->arch.mmu->get_guest_pgd(vcpu); + arch.cr3 = kvm_mmu_get_guest_pgd(vcpu, vcpu->arch.mmu); return kvm_setup_async_pf(vcpu, cr2_or_gpa, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch); @@ -4200,10 +4280,10 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) return; if (!vcpu->arch.mmu->root_role.direct && - work->arch.cr3 != vcpu->arch.mmu->get_guest_pgd(vcpu)) + work->arch.cr3 != kvm_mmu_get_guest_pgd(vcpu, vcpu->arch.mmu)) return; - kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true); + kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true, NULL); } static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) @@ -4469,8 +4549,7 @@ static void nonpaging_init_context(struct kvm_mmu *context) { context->page_fault = nonpaging_page_fault; context->gva_to_gpa = nonpaging_gva_to_gpa; - context->sync_page = nonpaging_sync_page; - context->invlpg = NULL; + context->sync_spte = NULL; } static inline bool is_root_usable(struct kvm_mmu_root_info *root, gpa_t pgd, @@ -4604,11 +4683,6 @@ void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd) } EXPORT_SYMBOL_GPL(kvm_mmu_new_pgd); -static unsigned long get_cr3(struct kvm_vcpu *vcpu) -{ - return kvm_read_cr3(vcpu); -} - static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, unsigned int access) { @@ -4638,10 +4712,9 @@ static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, #include "paging_tmpl.h" #undef PTTYPE -static void -__reset_rsvds_bits_mask(struct rsvd_bits_validate *rsvd_check, - u64 pa_bits_rsvd, int level, bool nx, bool gbpages, - bool pse, bool amd) +static void __reset_rsvds_bits_mask(struct rsvd_bits_validate *rsvd_check, + u64 pa_bits_rsvd, int level, bool nx, + bool gbpages, bool pse, bool amd) { u64 gbpages_bit_rsvd = 0; u64 nonleaf_bit8_rsvd = 0; @@ -4754,9 +4827,9 @@ static void reset_guest_rsvds_bits_mask(struct kvm_vcpu *vcpu, guest_cpuid_is_amd_or_hygon(vcpu)); } -static void -__reset_rsvds_bits_mask_ept(struct rsvd_bits_validate *rsvd_check, - u64 pa_bits_rsvd, bool execonly, int huge_page_level) +static void __reset_rsvds_bits_mask_ept(struct rsvd_bits_validate *rsvd_check, + u64 pa_bits_rsvd, bool execonly, + int huge_page_level) { u64 high_bits_rsvd = pa_bits_rsvd & rsvd_bits(0, 51); u64 large_1g_rsvd = 0, large_2m_rsvd = 0; @@ -4856,8 +4929,7 @@ static inline bool boot_cpu_is_amd(void) * the direct page table on host, use as much mmu features as * possible, however, kvm currently does not do execution-protection. */ -static void -reset_tdp_shadow_zero_bits_mask(struct kvm_mmu *context) +static void reset_tdp_shadow_zero_bits_mask(struct kvm_mmu *context) { struct rsvd_bits_validate *shadow_zero_check; int i; @@ -5060,20 +5132,18 @@ static void paging64_init_context(struct kvm_mmu *context) { context->page_fault = paging64_page_fault; context->gva_to_gpa = paging64_gva_to_gpa; - context->sync_page = paging64_sync_page; - context->invlpg = paging64_invlpg; + context->sync_spte = paging64_sync_spte; } static void paging32_init_context(struct kvm_mmu *context) { context->page_fault = paging32_page_fault; context->gva_to_gpa = paging32_gva_to_gpa; - context->sync_page = paging32_sync_page; - context->invlpg = paging32_invlpg; + context->sync_spte = paging32_sync_spte; } -static union kvm_cpu_role -kvm_calc_cpu_role(struct kvm_vcpu *vcpu, const struct kvm_mmu_role_regs *regs) +static union kvm_cpu_role kvm_calc_cpu_role(struct kvm_vcpu *vcpu, + const struct kvm_mmu_role_regs *regs) { union kvm_cpu_role role = {0}; @@ -5112,6 +5182,21 @@ kvm_calc_cpu_role(struct kvm_vcpu *vcpu, const struct kvm_mmu_role_regs *regs) return role; } +void __kvm_mmu_refresh_passthrough_bits(struct kvm_vcpu *vcpu, + struct kvm_mmu *mmu) +{ + const bool cr0_wp = kvm_is_cr0_bit_set(vcpu, X86_CR0_WP); + + BUILD_BUG_ON((KVM_MMU_CR0_ROLE_BITS & KVM_POSSIBLE_CR0_GUEST_BITS) != X86_CR0_WP); + BUILD_BUG_ON((KVM_MMU_CR4_ROLE_BITS & KVM_POSSIBLE_CR4_GUEST_BITS)); + + if (is_cr0_wp(mmu) == cr0_wp) + return; + + mmu->cpu_role.base.cr0_wp = cr0_wp; + reset_guest_paging_metadata(vcpu, mmu); +} + static inline int kvm_mmu_get_tdp_level(struct kvm_vcpu *vcpu) { /* tdp_root_level is architecture forced level, use it if nonzero */ @@ -5157,9 +5242,8 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu, context->cpu_role.as_u64 = cpu_role.as_u64; context->root_role.word = root_role.word; context->page_fault = kvm_tdp_page_fault; - context->sync_page = nonpaging_sync_page; - context->invlpg = NULL; - context->get_guest_pgd = get_cr3; + context->sync_spte = NULL; + context->get_guest_pgd = get_guest_cr3; context->get_pdptr = kvm_pdptr_read; context->inject_page_fault = kvm_inject_page_fault; @@ -5289,8 +5373,7 @@ void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly, context->page_fault = ept_page_fault; context->gva_to_gpa = ept_gva_to_gpa; - context->sync_page = ept_sync_page; - context->invlpg = ept_invlpg; + context->sync_spte = ept_sync_spte; update_permission_bitmask(context, true); context->pkru_mask = 0; @@ -5309,7 +5392,7 @@ static void init_kvm_softmmu(struct kvm_vcpu *vcpu, kvm_init_shadow_mmu(vcpu, cpu_role); - context->get_guest_pgd = get_cr3; + context->get_guest_pgd = get_guest_cr3; context->get_pdptr = kvm_pdptr_read; context->inject_page_fault = kvm_inject_page_fault; } @@ -5323,7 +5406,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu, return; g_context->cpu_role.as_u64 = new_mode.as_u64; - g_context->get_guest_pgd = get_cr3; + g_context->get_guest_pgd = get_guest_cr3; g_context->get_pdptr = kvm_pdptr_read; g_context->inject_page_fault = kvm_inject_page_fault; @@ -5331,7 +5414,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu, * L2 page tables are never shadowed, so there is no need to sync * SPTEs. */ - g_context->invlpg = NULL; + g_context->sync_spte = NULL; /* * Note that arch.mmu->gva_to_gpa translates l2_gpa to l1_gpa using @@ -5393,7 +5476,7 @@ void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu) * Changing guest CPUID after KVM_RUN is forbidden, see the comment in * kvm_arch_vcpu_ioctl(). */ - KVM_BUG_ON(vcpu->arch.last_vmentry_cpu != -1, vcpu->kvm); + KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm); } void kvm_mmu_reset_context(struct kvm_vcpu *vcpu) @@ -5664,7 +5747,8 @@ int noinline kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, u64 err if (r == RET_PF_INVALID) { r = kvm_mmu_do_page_fault(vcpu, cr2_or_gpa, - lower_32_bits(error_code), false); + lower_32_bits(error_code), false, + &emulation_type); if (KVM_BUG_ON(r == RET_PF_INVALID, vcpu->kvm)) return -EIO; } @@ -5706,48 +5790,77 @@ emulate: } EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); -void kvm_mmu_invalidate_gva(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gva_t gva, hpa_t root_hpa) +static void __kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, + u64 addr, hpa_t root_hpa) +{ + struct kvm_shadow_walk_iterator iterator; + + vcpu_clear_mmio_info(vcpu, addr); + + if (!VALID_PAGE(root_hpa)) + return; + + write_lock(&vcpu->kvm->mmu_lock); + for_each_shadow_entry_using_root(vcpu, root_hpa, addr, iterator) { + struct kvm_mmu_page *sp = sptep_to_sp(iterator.sptep); + + if (sp->unsync) { + int ret = kvm_sync_spte(vcpu, sp, iterator.index); + + if (ret < 0) + mmu_page_zap_pte(vcpu->kvm, sp, iterator.sptep, NULL); + if (ret) + kvm_flush_remote_tlbs_sptep(vcpu->kvm, iterator.sptep); + } + + if (!sp->unsync_children) + break; + } + write_unlock(&vcpu->kvm->mmu_lock); +} + +void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, + u64 addr, unsigned long roots) { int i; + WARN_ON_ONCE(roots & ~KVM_MMU_ROOTS_ALL); + /* It's actually a GPA for vcpu->arch.guest_mmu. */ if (mmu != &vcpu->arch.guest_mmu) { /* INVLPG on a non-canonical address is a NOP according to the SDM. */ - if (is_noncanonical_address(gva, vcpu)) + if (is_noncanonical_address(addr, vcpu)) return; - static_call(kvm_x86_flush_tlb_gva)(vcpu, gva); + static_call(kvm_x86_flush_tlb_gva)(vcpu, addr); } - if (!mmu->invlpg) + if (!mmu->sync_spte) return; - if (root_hpa == INVALID_PAGE) { - mmu->invlpg(vcpu, gva, mmu->root.hpa); + if (roots & KVM_MMU_ROOT_CURRENT) + __kvm_mmu_invalidate_addr(vcpu, mmu, addr, mmu->root.hpa); - /* - * INVLPG is required to invalidate any global mappings for the VA, - * irrespective of PCID. Since it would take us roughly similar amount - * of work to determine whether any of the prev_root mappings of the VA - * is marked global, or to just sync it blindly, so we might as well - * just always sync it. - * - * Mappings not reachable via the current cr3 or the prev_roots will be - * synced when switching to that cr3, so nothing needs to be done here - * for them. - */ - for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) - if (VALID_PAGE(mmu->prev_roots[i].hpa)) - mmu->invlpg(vcpu, gva, mmu->prev_roots[i].hpa); - } else { - mmu->invlpg(vcpu, gva, root_hpa); + for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) { + if (roots & KVM_MMU_ROOT_PREVIOUS(i)) + __kvm_mmu_invalidate_addr(vcpu, mmu, addr, mmu->prev_roots[i].hpa); } } +EXPORT_SYMBOL_GPL(kvm_mmu_invalidate_addr); void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) { - kvm_mmu_invalidate_gva(vcpu, vcpu->arch.walk_mmu, gva, INVALID_PAGE); + /* + * INVLPG is required to invalidate any global mappings for the VA, + * irrespective of PCID. Blindly sync all roots as it would take + * roughly the same amount of work/time to determine whether any of the + * previous roots have a global mapping. + * + * Mappings not reachable via the current or previous cached roots will + * be synced when switching to that new cr3, so nothing needs to be + * done here for them. + */ + kvm_mmu_invalidate_addr(vcpu, vcpu->arch.walk_mmu, gva, KVM_MMU_ROOTS_ALL); ++vcpu->stat.invlpg; } EXPORT_SYMBOL_GPL(kvm_mmu_invlpg); @@ -5756,27 +5869,20 @@ EXPORT_SYMBOL_GPL(kvm_mmu_invlpg); void kvm_mmu_invpcid_gva(struct kvm_vcpu *vcpu, gva_t gva, unsigned long pcid) { struct kvm_mmu *mmu = vcpu->arch.mmu; - bool tlb_flush = false; + unsigned long roots = 0; uint i; - if (pcid == kvm_get_active_pcid(vcpu)) { - if (mmu->invlpg) - mmu->invlpg(vcpu, gva, mmu->root.hpa); - tlb_flush = true; - } + if (pcid == kvm_get_active_pcid(vcpu)) + roots |= KVM_MMU_ROOT_CURRENT; for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) { if (VALID_PAGE(mmu->prev_roots[i].hpa) && - pcid == kvm_get_pcid(vcpu, mmu->prev_roots[i].pgd)) { - if (mmu->invlpg) - mmu->invlpg(vcpu, gva, mmu->prev_roots[i].hpa); - tlb_flush = true; - } + pcid == kvm_get_pcid(vcpu, mmu->prev_roots[i].pgd)) + roots |= KVM_MMU_ROOT_PREVIOUS(i); } - if (tlb_flush) - static_call(kvm_x86_flush_tlb_gva)(vcpu, gva); - + if (roots) + kvm_mmu_invalidate_addr(vcpu, mmu, gva, roots); ++vcpu->stat.invlpg; /* @@ -5813,29 +5919,30 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, EXPORT_SYMBOL_GPL(kvm_configure_mmu); /* The return value indicates if tlb flush on all vcpus is needed. */ -typedef bool (*slot_level_handler) (struct kvm *kvm, +typedef bool (*slot_rmaps_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head, const struct kvm_memory_slot *slot); -/* The caller should hold mmu-lock before calling this function. */ -static __always_inline bool -slot_handle_level_range(struct kvm *kvm, const struct kvm_memory_slot *memslot, - slot_level_handler fn, int start_level, int end_level, - gfn_t start_gfn, gfn_t end_gfn, bool flush_on_yield, - bool flush) +static __always_inline bool __walk_slot_rmaps(struct kvm *kvm, + const struct kvm_memory_slot *slot, + slot_rmaps_handler fn, + int start_level, int end_level, + gfn_t start_gfn, gfn_t end_gfn, + bool flush_on_yield, bool flush) { struct slot_rmap_walk_iterator iterator; - for_each_slot_rmap_range(memslot, start_level, end_level, start_gfn, + lockdep_assert_held_write(&kvm->mmu_lock); + + for_each_slot_rmap_range(slot, start_level, end_level, start_gfn, end_gfn, &iterator) { if (iterator.rmap) - flush |= fn(kvm, iterator.rmap, memslot); + flush |= fn(kvm, iterator.rmap, slot); if (need_resched() || rwlock_needbreak(&kvm->mmu_lock)) { if (flush && flush_on_yield) { - kvm_flush_remote_tlbs_with_address(kvm, - start_gfn, - iterator.gfn - start_gfn + 1); + kvm_flush_remote_tlbs_range(kvm, start_gfn, + iterator.gfn - start_gfn + 1); flush = false; } cond_resched_rwlock_write(&kvm->mmu_lock); @@ -5845,23 +5952,23 @@ slot_handle_level_range(struct kvm *kvm, const struct kvm_memory_slot *memslot, return flush; } -static __always_inline bool -slot_handle_level(struct kvm *kvm, const struct kvm_memory_slot *memslot, - slot_level_handler fn, int start_level, int end_level, - bool flush_on_yield) +static __always_inline bool walk_slot_rmaps(struct kvm *kvm, + const struct kvm_memory_slot *slot, + slot_rmaps_handler fn, + int start_level, int end_level, + bool flush_on_yield) { - return slot_handle_level_range(kvm, memslot, fn, start_level, - end_level, memslot->base_gfn, - memslot->base_gfn + memslot->npages - 1, - flush_on_yield, false); + return __walk_slot_rmaps(kvm, slot, fn, start_level, end_level, + slot->base_gfn, slot->base_gfn + slot->npages - 1, + flush_on_yield, false); } -static __always_inline bool -slot_handle_level_4k(struct kvm *kvm, const struct kvm_memory_slot *memslot, - slot_level_handler fn, bool flush_on_yield) +static __always_inline bool walk_slot_rmaps_4k(struct kvm *kvm, + const struct kvm_memory_slot *slot, + slot_rmaps_handler fn, + bool flush_on_yield) { - return slot_handle_level(kvm, memslot, fn, PG_LEVEL_4K, - PG_LEVEL_4K, flush_on_yield); + return walk_slot_rmaps(kvm, slot, fn, PG_LEVEL_4K, PG_LEVEL_4K, flush_on_yield); } static void free_mmu_pages(struct kvm_mmu *mmu) @@ -6156,9 +6263,9 @@ static bool kvm_rmap_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_e if (WARN_ON_ONCE(start >= end)) continue; - flush = slot_handle_level_range(kvm, memslot, __kvm_zap_rmap, - PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL, - start, end - 1, true, flush); + flush = __walk_slot_rmaps(kvm, memslot, __kvm_zap_rmap, + PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL, + start, end - 1, true, flush); } } @@ -6190,8 +6297,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) } if (flush) - kvm_flush_remote_tlbs_with_address(kvm, gfn_start, - gfn_end - gfn_start); + kvm_flush_remote_tlbs_range(kvm, gfn_start, gfn_end - gfn_start); kvm_mmu_invalidate_end(kvm, 0, -1ul); @@ -6211,8 +6317,8 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, { if (kvm_memslots_have_rmaps(kvm)) { write_lock(&kvm->mmu_lock); - slot_handle_level(kvm, memslot, slot_rmap_write_protect, - start_level, KVM_MAX_HUGEPAGE_LEVEL, false); + walk_slot_rmaps(kvm, memslot, slot_rmap_write_protect, + start_level, KVM_MAX_HUGEPAGE_LEVEL, false); write_unlock(&kvm->mmu_lock); } @@ -6447,10 +6553,9 @@ static void kvm_shadow_mmu_try_split_huge_pages(struct kvm *kvm, * all the way to the target level. There's no need to split pages * already at the target level. */ - for (level = KVM_MAX_HUGEPAGE_LEVEL; level > target_level; level--) { - slot_handle_level_range(kvm, slot, shadow_mmu_try_split_huge_pages, - level, level, start, end - 1, true, false); - } + for (level = KVM_MAX_HUGEPAGE_LEVEL; level > target_level; level--) + __walk_slot_rmaps(kvm, slot, shadow_mmu_try_split_huge_pages, + level, level, start, end - 1, true, false); } /* Must be called with the mmu_lock held in write-mode. */ @@ -6529,7 +6634,7 @@ restart: PG_LEVEL_NUM)) { kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); - if (kvm_available_flush_tlb_with_range()) + if (kvm_available_flush_remote_tlbs_range()) kvm_flush_remote_tlbs_sptep(kvm, sptep); else need_tlb_flush = 1; @@ -6548,8 +6653,8 @@ static void kvm_rmap_zap_collapsible_sptes(struct kvm *kvm, * Note, use KVM_MAX_HUGEPAGE_LEVEL - 1 since there's no need to zap * pages that are already mapped at the maximum hugepage level. */ - if (slot_handle_level(kvm, slot, kvm_mmu_zap_collapsible_spte, - PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL - 1, true)) + if (walk_slot_rmaps(kvm, slot, kvm_mmu_zap_collapsible_spte, + PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL - 1, true)) kvm_arch_flush_remote_tlbs_memslot(kvm, slot); } @@ -6580,8 +6685,7 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, * is observed by any other operation on the same memslot. */ lockdep_assert_held(&kvm->slots_lock); - kvm_flush_remote_tlbs_with_address(kvm, memslot->base_gfn, - memslot->npages); + kvm_flush_remote_tlbs_range(kvm, memslot->base_gfn, memslot->npages); } void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, @@ -6593,7 +6697,7 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, * Clear dirty bits only on 4k SPTEs since the legacy MMU only * support dirty logging at a 4k granularity. */ - slot_handle_level_4k(kvm, memslot, __rmap_clear_dirty, false); + walk_slot_rmaps_4k(kvm, memslot, __rmap_clear_dirty, false); write_unlock(&kvm->mmu_lock); } @@ -6663,8 +6767,8 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) } } -static unsigned long -mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) +static unsigned long mmu_shrink_scan(struct shrinker *shrink, + struct shrink_control *sc) { struct kvm *kvm; int nr_to_scan = sc->nr_to_scan; @@ -6722,8 +6826,8 @@ unlock: return freed; } -static unsigned long -mmu_shrink_count(struct shrinker *shrink, struct shrink_control *sc) +static unsigned long mmu_shrink_count(struct shrinker *shrink, + struct shrink_control *sc) { return percpu_counter_read_positive(&kvm_total_used_mmu_pages); } @@ -6987,7 +7091,10 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm) */ slot = NULL; if (atomic_read(&kvm->nr_memslots_dirty_logging)) { - slot = gfn_to_memslot(kvm, sp->gfn); + struct kvm_memslots *slots; + + slots = kvm_memslots_for_spte_role(kvm, sp->role); + slot = __gfn_to_memslot(slots, sp->gfn); WARN_ON_ONCE(!slot); } diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index cc58631e2336..d39af5639ce9 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -170,14 +170,14 @@ bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, struct kvm_memory_slot *slot, u64 gfn, int min_level); -void kvm_flush_remote_tlbs_with_address(struct kvm *kvm, - u64 start_gfn, u64 pages); +void kvm_flush_remote_tlbs_range(struct kvm *kvm, gfn_t start_gfn, + gfn_t nr_pages); /* Flush the given page (huge or not) of guest memory. */ static inline void kvm_flush_remote_tlbs_gfn(struct kvm *kvm, gfn_t gfn, int level) { - kvm_flush_remote_tlbs_with_address(kvm, gfn_round_for_level(gfn, level), - KVM_PAGES_PER_HPAGE(level)); + kvm_flush_remote_tlbs_range(kvm, gfn_round_for_level(gfn, level), + KVM_PAGES_PER_HPAGE(level)); } unsigned int pte_list_count(struct kvm_rmap_head *rmap_head); @@ -240,6 +240,13 @@ struct kvm_page_fault { kvm_pfn_t pfn; hva_t hva; bool map_writable; + + /* + * Indicates the guest is trying to write a gfn that contains one or + * more of the PTEs used to translate the write itself, i.e. the access + * is changing its own translation in the guest page tables. + */ + bool write_fault_to_shadow_pgtable; }; int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); @@ -273,7 +280,7 @@ enum { }; static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, - u32 err, bool prefetch) + u32 err, bool prefetch, int *emulation_type) { struct kvm_page_fault fault = { .addr = cr2_or_gpa, @@ -312,6 +319,9 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, else r = vcpu->arch.mmu->page_fault(vcpu, &fault); + if (fault.write_fault_to_shadow_pgtable && emulation_type) + *emulation_type |= EMULTYPE_WRITE_PF_TO_SP; + /* * Similar to above, prefetch faults aren't truly spurious, and the * async #PF path doesn't do emulation. Do count faults that are fixed diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 57f0b75c80f9..0662e0278e70 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -324,7 +324,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, trace_kvm_mmu_pagetable_walk(addr, access); retry_walk: walker->level = mmu->cpu_role.base.level; - pte = mmu->get_guest_pgd(vcpu); + pte = kvm_mmu_get_guest_pgd(vcpu, mmu); have_ad = PT_HAVE_ACCESSED_DIRTY(mmu); #if PTTYPE == 64 @@ -519,7 +519,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, static bool FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, - u64 *spte, pt_element_t gpte, bool no_dirty_log) + u64 *spte, pt_element_t gpte) { struct kvm_memory_slot *slot; unsigned pte_access; @@ -535,8 +535,7 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, pte_access = sp->role.access & FNAME(gpte_access)(gpte); FNAME(protect_clean_gpte)(vcpu->arch.mmu, &pte_access, gpte); - slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, - no_dirty_log && (pte_access & ACC_WRITE_MASK)); + slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, pte_access & ACC_WRITE_MASK); if (!slot) return false; @@ -605,7 +604,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, if (is_shadow_present_pte(*spte)) continue; - if (!FNAME(prefetch_gpte)(vcpu, sp, spte, gptep[i], true)) + if (!FNAME(prefetch_gpte)(vcpu, sp, spte, gptep[i])) break; } } @@ -685,8 +684,17 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, if (sp != ERR_PTR(-EEXIST)) link_shadow_page(vcpu, it.sptep, sp); + + if (fault->write && table_gfn == fault->gfn) + fault->write_fault_to_shadow_pgtable = true; } + /* + * Adjust the hugepage size _after_ resolving indirect shadow pages. + * KVM doesn't support mapping hugepages into the guest for gfns that + * are being shadowed by KVM, i.e. allocating a new shadow page may + * affect the allowed hugepage size. + */ kvm_mmu_hugepage_adjust(vcpu, fault); trace_kvm_mmu_spte_requested(fault); @@ -731,46 +739,6 @@ out_gpte_changed: return RET_PF_RETRY; } - /* - * To see whether the mapped gfn can write its page table in the current - * mapping. - * - * It is the helper function of FNAME(page_fault). When guest uses large page - * size to map the writable gfn which is used as current page table, we should - * force kvm to use small page size to map it because new shadow page will be - * created when kvm establishes shadow page table that stop kvm using large - * page size. Do it early can avoid unnecessary #PF and emulation. - * - * @write_fault_to_shadow_pgtable will return true if the fault gfn is - * currently used as its page table. - * - * Note: the PDPT page table is not checked for PAE-32 bit guest. It is ok - * since the PDPT is always shadowed, that means, we can not use large page - * size to map the gfn which is used as PDPT. - */ -static bool -FNAME(is_self_change_mapping)(struct kvm_vcpu *vcpu, - struct guest_walker *walker, bool user_fault, - bool *write_fault_to_shadow_pgtable) -{ - int level; - gfn_t mask = ~(KVM_PAGES_PER_HPAGE(walker->level) - 1); - bool self_changed = false; - - if (!(walker->pte_access & ACC_WRITE_MASK || - (!is_cr0_wp(vcpu->arch.mmu) && !user_fault))) - return false; - - for (level = walker->level; level <= walker->max_level; level++) { - gfn_t gfn = walker->gfn ^ walker->table_gfn[level - 1]; - - self_changed |= !(gfn & mask); - *write_fault_to_shadow_pgtable |= !gfn; - } - - return self_changed; -} - /* * Page fault handler. There are several causes for a page fault: * - there is no shadow pte for the guest pte @@ -789,7 +757,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault { struct guest_walker walker; int r; - bool is_self_change_mapping; pgprintk("%s: addr %lx err %x\n", __func__, fault->addr, fault->error_code); WARN_ON_ONCE(fault->is_tdp); @@ -814,6 +781,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault } fault->gfn = walker.gfn; + fault->max_level = walker.level; fault->slot = kvm_vcpu_gfn_to_memslot(vcpu, fault->gfn); if (page_fault_handle_page_track(vcpu, fault)) { @@ -825,16 +793,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (r) return r; - vcpu->arch.write_fault_to_shadow_pgtable = false; - - is_self_change_mapping = FNAME(is_self_change_mapping)(vcpu, - &walker, fault->user, &vcpu->arch.write_fault_to_shadow_pgtable); - - if (is_self_change_mapping) - fault->max_level = PG_LEVEL_4K; - else - fault->max_level = walker.level; - r = kvm_faultin_pfn(vcpu, fault, walker.pte_access); if (r != RET_PF_CONTINUE) return r; @@ -887,64 +845,6 @@ static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp) return gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t); } -static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva, hpa_t root_hpa) -{ - struct kvm_shadow_walk_iterator iterator; - struct kvm_mmu_page *sp; - u64 old_spte; - int level; - u64 *sptep; - - vcpu_clear_mmio_info(vcpu, gva); - - /* - * No need to check return value here, rmap_can_add() can - * help us to skip pte prefetch later. - */ - mmu_topup_memory_caches(vcpu, true); - - if (!VALID_PAGE(root_hpa)) { - WARN_ON(1); - return; - } - - write_lock(&vcpu->kvm->mmu_lock); - for_each_shadow_entry_using_root(vcpu, root_hpa, gva, iterator) { - level = iterator.level; - sptep = iterator.sptep; - - sp = sptep_to_sp(sptep); - old_spte = *sptep; - if (is_last_spte(old_spte, level)) { - pt_element_t gpte; - gpa_t pte_gpa; - - if (!sp->unsync) - break; - - pte_gpa = FNAME(get_level1_sp_gpa)(sp); - pte_gpa += spte_index(sptep) * sizeof(pt_element_t); - - mmu_page_zap_pte(vcpu->kvm, sp, sptep, NULL); - if (is_shadow_present_pte(old_spte)) - kvm_flush_remote_tlbs_sptep(vcpu->kvm, sptep); - - if (!rmap_can_add(vcpu)) - break; - - if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte, - sizeof(pt_element_t))) - break; - - FNAME(prefetch_gpte)(vcpu, sp, sptep, gpte, false); - } - - if (!sp->unsync_children) - break; - } - write_unlock(&vcpu->kvm->mmu_lock); -} - /* Note, @addr is a GPA when gva_to_gpa() translates an L2 GPA to an L1 GPA. */ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t addr, u64 access, @@ -977,114 +877,75 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, * can't change unless all sptes pointing to it are nuked first. * * Returns - * < 0: the sp should be zapped - * 0: the sp is synced and no tlb flushing is required - * > 0: the sp is synced and tlb flushing is required + * < 0: failed to sync spte + * 0: the spte is synced and no tlb flushing is required + * > 0: the spte is synced and tlb flushing is required */ -static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) +static int FNAME(sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int i) { - union kvm_mmu_page_role root_role = vcpu->arch.mmu->root_role; - int i; bool host_writable; gpa_t first_pte_gpa; - bool flush = false; + u64 *sptep, spte; + struct kvm_memory_slot *slot; + unsigned pte_access; + pt_element_t gpte; + gpa_t pte_gpa; + gfn_t gfn; - /* - * Ignore various flags when verifying that it's safe to sync a shadow - * page using the current MMU context. - * - * - level: not part of the overall MMU role and will never match as the MMU's - * level tracks the root level - * - access: updated based on the new guest PTE - * - quadrant: not part of the overall MMU role (similar to level) - */ - const union kvm_mmu_page_role sync_role_ign = { - .level = 0xf, - .access = 0x7, - .quadrant = 0x3, - .passthrough = 0x1, - }; - - /* - * Direct pages can never be unsync, and KVM should never attempt to - * sync a shadow page for a different MMU context, e.g. if the role - * differs then the memslot lookup (SMM vs. non-SMM) will be bogus, the - * reserved bits checks will be wrong, etc... - */ - if (WARN_ON_ONCE(sp->role.direct || - (sp->role.word ^ root_role.word) & ~sync_role_ign.word)) - return -1; + if (WARN_ON_ONCE(!sp->spt[i])) + return 0; first_pte_gpa = FNAME(get_level1_sp_gpa)(sp); + pte_gpa = first_pte_gpa + i * sizeof(pt_element_t); - for (i = 0; i < SPTE_ENT_PER_PAGE; i++) { - u64 *sptep, spte; - struct kvm_memory_slot *slot; - unsigned pte_access; - pt_element_t gpte; - gpa_t pte_gpa; - gfn_t gfn; + if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte, + sizeof(pt_element_t))) + return -1; - if (!sp->spt[i]) - continue; + if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) + return 1; - pte_gpa = first_pte_gpa + i * sizeof(pt_element_t); + gfn = gpte_to_gfn(gpte); + pte_access = sp->role.access; + pte_access &= FNAME(gpte_access)(gpte); + FNAME(protect_clean_gpte)(vcpu->arch.mmu, &pte_access, gpte); - if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte, - sizeof(pt_element_t))) - return -1; - - if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) { - flush = true; - continue; - } - - gfn = gpte_to_gfn(gpte); - pte_access = sp->role.access; - pte_access &= FNAME(gpte_access)(gpte); - FNAME(protect_clean_gpte)(vcpu->arch.mmu, &pte_access, gpte); - - if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access)) - continue; - - /* - * Drop the SPTE if the new protections would result in a RWX=0 - * SPTE or if the gfn is changing. The RWX=0 case only affects - * EPT with execute-only support, i.e. EPT without an effective - * "present" bit, as all other paging modes will create a - * read-only SPTE if pte_access is zero. - */ - if ((!pte_access && !shadow_present_mask) || - gfn != kvm_mmu_page_get_gfn(sp, i)) { - drop_spte(vcpu->kvm, &sp->spt[i]); - flush = true; - continue; - } - - /* Update the shadowed access bits in case they changed. */ - kvm_mmu_page_set_access(sp, i, pte_access); - - sptep = &sp->spt[i]; - spte = *sptep; - host_writable = spte & shadow_host_writable_mask; - slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); - make_spte(vcpu, sp, slot, pte_access, gfn, - spte_to_pfn(spte), spte, true, false, - host_writable, &spte); - - flush |= mmu_spte_update(sptep, spte); - } + if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access)) + return 0; /* - * Note, any flush is purely for KVM's correctness, e.g. when dropping - * an existing SPTE or clearing W/A/D bits to ensure an mmu_notifier - * unmap or dirty logging event doesn't fail to flush. The guest is - * responsible for flushing the TLB to ensure any changes in protection - * bits are recognized, i.e. until the guest flushes or page faults on - * a relevant address, KVM is architecturally allowed to let vCPUs use - * cached translations with the old protection bits. + * Drop the SPTE if the new protections would result in a RWX=0 + * SPTE or if the gfn is changing. The RWX=0 case only affects + * EPT with execute-only support, i.e. EPT without an effective + * "present" bit, as all other paging modes will create a + * read-only SPTE if pte_access is zero. */ - return flush; + if ((!pte_access && !shadow_present_mask) || + gfn != kvm_mmu_page_get_gfn(sp, i)) { + drop_spte(vcpu->kvm, &sp->spt[i]); + return 1; + } + /* + * Do nothing if the permissions are unchanged. The existing SPTE is + * still, and prefetch_invalid_gpte() has verified that the A/D bits + * are set in the "new" gPTE, i.e. there is no danger of missing an A/D + * update due to A/D bits being set in the SPTE but not the gPTE. + */ + if (kvm_mmu_page_get_access(sp, i) == pte_access) + return 0; + + /* Update the shadowed access bits in case they changed. */ + kvm_mmu_page_set_access(sp, i, pte_access); + + sptep = &sp->spt[i]; + spte = *sptep; + host_writable = spte & shadow_host_writable_mask; + slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn); + make_spte(vcpu, sp, slot, pte_access, gfn, + spte_to_pfn(spte), spte, true, false, + host_writable, &spte); + + return mmu_spte_update(sptep, spte); } #undef pt_element_t diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index c15bfca3ed15..cf2c6426a6fc 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -164,7 +164,7 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, /* * For simplicity, enforce the NX huge page mitigation even if not * strictly necessary. KVM could ignore the mitigation if paging is - * disabled in the guest, as the guest doesn't have an page tables to + * disabled in the guest, as the guest doesn't have any page tables to * abuse. But to safely ignore the mitigation, KVM would have to * ensure a new MMU is loaded (or all shadow pages zapped) when CR0.PG * is toggled on, and that's a net negative for performance when TDP is diff --git a/arch/x86/kvm/mmu/tdp_iter.h b/arch/x86/kvm/mmu/tdp_iter.h index f0af385c56e0..fae559559a80 100644 --- a/arch/x86/kvm/mmu/tdp_iter.h +++ b/arch/x86/kvm/mmu/tdp_iter.h @@ -29,29 +29,49 @@ static inline void __kvm_tdp_mmu_write_spte(tdp_ptep_t sptep, u64 new_spte) WRITE_ONCE(*rcu_dereference(sptep), new_spte); } +/* + * SPTEs must be modified atomically if they are shadow-present, leaf + * SPTEs, and have volatile bits, i.e. has bits that can be set outside + * of mmu_lock. The Writable bit can be set by KVM's fast page fault + * handler, and Accessed and Dirty bits can be set by the CPU. + * + * Note, non-leaf SPTEs do have Accessed bits and those bits are + * technically volatile, but KVM doesn't consume the Accessed bit of + * non-leaf SPTEs, i.e. KVM doesn't care if it clobbers the bit. This + * logic needs to be reassessed if KVM were to use non-leaf Accessed + * bits, e.g. to skip stepping down into child SPTEs when aging SPTEs. + */ +static inline bool kvm_tdp_mmu_spte_need_atomic_write(u64 old_spte, int level) +{ + return is_shadow_present_pte(old_spte) && + is_last_spte(old_spte, level) && + spte_has_volatile_bits(old_spte); +} + static inline u64 kvm_tdp_mmu_write_spte(tdp_ptep_t sptep, u64 old_spte, u64 new_spte, int level) { - /* - * Atomically write the SPTE if it is a shadow-present, leaf SPTE with - * volatile bits, i.e. has bits that can be set outside of mmu_lock. - * The Writable bit can be set by KVM's fast page fault handler, and - * Accessed and Dirty bits can be set by the CPU. - * - * Note, non-leaf SPTEs do have Accessed bits and those bits are - * technically volatile, but KVM doesn't consume the Accessed bit of - * non-leaf SPTEs, i.e. KVM doesn't care if it clobbers the bit. This - * logic needs to be reassessed if KVM were to use non-leaf Accessed - * bits, e.g. to skip stepping down into child SPTEs when aging SPTEs. - */ - if (is_shadow_present_pte(old_spte) && is_last_spte(old_spte, level) && - spte_has_volatile_bits(old_spte)) + if (kvm_tdp_mmu_spte_need_atomic_write(old_spte, level)) return kvm_tdp_mmu_write_spte_atomic(sptep, new_spte); __kvm_tdp_mmu_write_spte(sptep, new_spte); return old_spte; } +static inline u64 tdp_mmu_clear_spte_bits(tdp_ptep_t sptep, u64 old_spte, + u64 mask, int level) +{ + atomic64_t *sptep_atomic; + + if (kvm_tdp_mmu_spte_need_atomic_write(old_spte, level)) { + sptep_atomic = (atomic64_t *)rcu_dereference(sptep); + return (u64)atomic64_fetch_and(~mask, sptep_atomic); + } + + __kvm_tdp_mmu_write_spte(sptep, old_spte & ~mask); + return old_spte; +} + /* * A TDP iterator performs a pre-order walk over a TDP paging structure. */ diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7c25dbf32ecc..08340219c35a 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -40,7 +40,17 @@ static __always_inline bool kvm_lockdep_assert_mmu_lock_held(struct kvm *kvm, void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm) { - /* Also waits for any queued work items. */ + /* + * Invalidate all roots, which besides the obvious, schedules all roots + * for zapping and thus puts the TDP MMU's reference to each root, i.e. + * ultimately frees all roots. + */ + kvm_tdp_mmu_invalidate_all_roots(kvm); + + /* + * Destroying a workqueue also first flushes the workqueue, i.e. no + * need to invoke kvm_tdp_mmu_zap_invalidated_roots(). + */ destroy_workqueue(kvm->arch.tdp_mmu_zap_wq); WARN_ON(atomic64_read(&kvm->arch.tdp_mmu_pages)); @@ -116,16 +126,6 @@ static void tdp_mmu_schedule_zap_root(struct kvm *kvm, struct kvm_mmu_page *root queue_work(kvm->arch.tdp_mmu_zap_wq, &root->tdp_mmu_async_work); } -static inline bool kvm_tdp_root_mark_invalid(struct kvm_mmu_page *page) -{ - union kvm_mmu_page_role role = page->role; - role.invalid = true; - - /* No need to use cmpxchg, only the invalid bit can change. */ - role.word = xchg(&page->role.word, role.word); - return role.invalid; -} - void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root, bool shared) { @@ -134,45 +134,12 @@ void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root, if (!refcount_dec_and_test(&root->tdp_mmu_root_count)) return; - WARN_ON(!is_tdp_mmu_page(root)); - /* - * The root now has refcount=0. It is valid, but readers already - * cannot acquire a reference to it because kvm_tdp_mmu_get_root() - * rejects it. This remains true for the rest of the execution - * of this function, because readers visit valid roots only - * (except for tdp_mmu_zap_root_work(), which however - * does not acquire any reference itself). - * - * Even though there are flows that need to visit all roots for - * correctness, they all take mmu_lock for write, so they cannot yet - * run concurrently. The same is true after kvm_tdp_root_mark_invalid, - * since the root still has refcount=0. - * - * However, tdp_mmu_zap_root can yield, and writers do not expect to - * see refcount=0 (see for example kvm_tdp_mmu_invalidate_all_roots()). - * So the root temporarily gets an extra reference, going to refcount=1 - * while staying invalid. Readers still cannot acquire any reference; - * but writers are now allowed to run if tdp_mmu_zap_root yields and - * they might take an extra reference if they themselves yield. - * Therefore, when the reference is given back by the worker, - * there is no guarantee that the refcount is still 1. If not, whoever - * puts the last reference will free the page, but they will not have to - * zap the root because a root cannot go from invalid to valid. + * The TDP MMU itself holds a reference to each root until the root is + * explicitly invalidated, i.e. the final reference should be never be + * put for a valid root. */ - if (!kvm_tdp_root_mark_invalid(root)) { - refcount_set(&root->tdp_mmu_root_count, 1); - - /* - * Zapping the root in a worker is not just "nice to have"; - * it is required because kvm_tdp_mmu_invalidate_all_roots() - * skips already-invalid roots. If kvm_tdp_mmu_put_root() did - * not add the root to the workqueue, kvm_tdp_mmu_zap_all_fast() - * might return with some roots not zapped yet. - */ - tdp_mmu_schedule_zap_root(kvm, root); - return; - } + KVM_BUG_ON(!is_tdp_mmu_page(root) || !root->role.invalid, kvm); spin_lock(&kvm->arch.tdp_mmu_pages_lock); list_del_rcu(&root->link); @@ -320,7 +287,14 @@ hpa_t kvm_tdp_mmu_get_vcpu_root_hpa(struct kvm_vcpu *vcpu) root = tdp_mmu_alloc_sp(vcpu); tdp_mmu_init_sp(root, NULL, 0, role); - refcount_set(&root->tdp_mmu_root_count, 1); + /* + * TDP MMU roots are kept until they are explicitly invalidated, either + * by a memslot update or by the destruction of the VM. Initialize the + * refcount to two; one reference for the vCPU, and one reference for + * the TDP MMU itself, which is held until the root is invalidated and + * is ultimately put by tdp_mmu_zap_root_work(). + */ + refcount_set(&root->tdp_mmu_root_count, 2); spin_lock(&kvm->arch.tdp_mmu_pages_lock); list_add_rcu(&root->link, &kvm->arch.tdp_mmu_roots); @@ -334,35 +308,6 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, u64 old_spte, u64 new_spte, int level, bool shared); -static void handle_changed_spte_acc_track(u64 old_spte, u64 new_spte, int level) -{ - if (!is_shadow_present_pte(old_spte) || !is_last_spte(old_spte, level)) - return; - - if (is_accessed_spte(old_spte) && - (!is_shadow_present_pte(new_spte) || !is_accessed_spte(new_spte) || - spte_to_pfn(old_spte) != spte_to_pfn(new_spte))) - kvm_set_pfn_accessed(spte_to_pfn(old_spte)); -} - -static void handle_changed_spte_dirty_log(struct kvm *kvm, int as_id, gfn_t gfn, - u64 old_spte, u64 new_spte, int level) -{ - bool pfn_changed; - struct kvm_memory_slot *slot; - - if (level > PG_LEVEL_4K) - return; - - pfn_changed = spte_to_pfn(old_spte) != spte_to_pfn(new_spte); - - if ((!is_writable_pte(old_spte) || pfn_changed) && - is_writable_pte(new_spte)) { - slot = __gfn_to_memslot(__kvm_memslots(kvm, as_id), gfn); - mark_page_dirty_in_slot(kvm, slot, gfn); - } -} - static void tdp_account_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp) { kvm_account_pgtable_pages((void *)sp->spt, +1); @@ -505,7 +450,7 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) } /** - * __handle_changed_spte - handle bookkeeping associated with an SPTE change + * handle_changed_spte - handle bookkeeping associated with an SPTE change * @kvm: kvm instance * @as_id: the address space of the paging structure the SPTE was a part of * @gfn: the base GFN that was mapped by the SPTE @@ -516,12 +461,13 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) * the MMU lock and the operation must synchronize with other * threads that might be modifying SPTEs. * - * Handle bookkeeping that might result from the modification of a SPTE. - * This function must be called for all TDP SPTE modifications. + * Handle bookkeeping that might result from the modification of a SPTE. Note, + * dirty logging updates are handled in common code, not here (see make_spte() + * and fast_pf_fix_direct_spte()). */ -static void __handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, - u64 old_spte, u64 new_spte, int level, - bool shared) +static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, + u64 old_spte, u64 new_spte, int level, + bool shared) { bool was_present = is_shadow_present_pte(old_spte); bool is_present = is_shadow_present_pte(new_spte); @@ -605,17 +551,10 @@ static void __handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, if (was_present && !was_leaf && (is_leaf || !is_present || WARN_ON_ONCE(pfn_changed))) handle_removed_pt(kvm, spte_to_child_pt(old_spte, level), shared); -} -static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, - u64 old_spte, u64 new_spte, int level, - bool shared) -{ - __handle_changed_spte(kvm, as_id, gfn, old_spte, new_spte, level, - shared); - handle_changed_spte_acc_track(old_spte, new_spte, level); - handle_changed_spte_dirty_log(kvm, as_id, gfn, old_spte, - new_spte, level); + if (was_leaf && is_accessed_spte(old_spte) && + (!is_present || !is_accessed_spte(new_spte) || pfn_changed)) + kvm_set_pfn_accessed(spte_to_pfn(old_spte)); } /* @@ -658,9 +597,8 @@ static inline int tdp_mmu_set_spte_atomic(struct kvm *kvm, if (!try_cmpxchg64(sptep, &iter->old_spte, new_spte)) return -EBUSY; - __handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte, - new_spte, iter->level, true); - handle_changed_spte_acc_track(iter->old_spte, new_spte, iter->level); + handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte, + new_spte, iter->level, true); return 0; } @@ -696,7 +634,7 @@ static inline int tdp_mmu_zap_spte_atomic(struct kvm *kvm, /* - * __tdp_mmu_set_spte - Set a TDP MMU SPTE and handle the associated bookkeeping + * tdp_mmu_set_spte - Set a TDP MMU SPTE and handle the associated bookkeeping * @kvm: KVM instance * @as_id: Address space ID, i.e. regular vs. SMM * @sptep: Pointer to the SPTE @@ -704,23 +642,12 @@ static inline int tdp_mmu_zap_spte_atomic(struct kvm *kvm, * @new_spte: The new value that will be set for the SPTE * @gfn: The base GFN that was (or will be) mapped by the SPTE * @level: The level _containing_ the SPTE (its parent PT's level) - * @record_acc_track: Notify the MM subsystem of changes to the accessed state - * of the page. Should be set unless handling an MMU - * notifier for access tracking. Leaving record_acc_track - * unset in that case prevents page accesses from being - * double counted. - * @record_dirty_log: Record the page as dirty in the dirty bitmap if - * appropriate for the change being made. Should be set - * unless performing certain dirty logging operations. - * Leaving record_dirty_log unset in that case prevents page - * writes from being double counted. * * Returns the old SPTE value, which _may_ be different than @old_spte if the * SPTE had voldatile bits. */ -static u64 __tdp_mmu_set_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep, - u64 old_spte, u64 new_spte, gfn_t gfn, int level, - bool record_acc_track, bool record_dirty_log) +static u64 tdp_mmu_set_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep, + u64 old_spte, u64 new_spte, gfn_t gfn, int level) { lockdep_assert_held_write(&kvm->mmu_lock); @@ -735,46 +662,17 @@ static u64 __tdp_mmu_set_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep, old_spte = kvm_tdp_mmu_write_spte(sptep, old_spte, new_spte, level); - __handle_changed_spte(kvm, as_id, gfn, old_spte, new_spte, level, false); - - if (record_acc_track) - handle_changed_spte_acc_track(old_spte, new_spte, level); - if (record_dirty_log) - handle_changed_spte_dirty_log(kvm, as_id, gfn, old_spte, - new_spte, level); + handle_changed_spte(kvm, as_id, gfn, old_spte, new_spte, level, false); return old_spte; } -static inline void _tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter, - u64 new_spte, bool record_acc_track, - bool record_dirty_log) +static inline void tdp_mmu_iter_set_spte(struct kvm *kvm, struct tdp_iter *iter, + u64 new_spte) { WARN_ON_ONCE(iter->yielded); - - iter->old_spte = __tdp_mmu_set_spte(kvm, iter->as_id, iter->sptep, - iter->old_spte, new_spte, - iter->gfn, iter->level, - record_acc_track, record_dirty_log); -} - -static inline void tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter, - u64 new_spte) -{ - _tdp_mmu_set_spte(kvm, iter, new_spte, true, true); -} - -static inline void tdp_mmu_set_spte_no_acc_track(struct kvm *kvm, - struct tdp_iter *iter, - u64 new_spte) -{ - _tdp_mmu_set_spte(kvm, iter, new_spte, false, true); -} - -static inline void tdp_mmu_set_spte_no_dirty_log(struct kvm *kvm, - struct tdp_iter *iter, - u64 new_spte) -{ - _tdp_mmu_set_spte(kvm, iter, new_spte, true, false); + iter->old_spte = tdp_mmu_set_spte(kvm, iter->as_id, iter->sptep, + iter->old_spte, new_spte, + iter->gfn, iter->level); } #define tdp_root_for_each_pte(_iter, _root, _start, _end) \ @@ -866,7 +764,7 @@ retry: continue; if (!shared) - tdp_mmu_set_spte(kvm, &iter, 0); + tdp_mmu_iter_set_spte(kvm, &iter, 0); else if (tdp_mmu_set_spte_atomic(kvm, &iter, 0)) goto retry; } @@ -923,8 +821,8 @@ bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp) if (WARN_ON_ONCE(!is_shadow_present_pte(old_spte))) return false; - __tdp_mmu_set_spte(kvm, kvm_mmu_page_as_id(sp), sp->ptep, old_spte, 0, - sp->gfn, sp->role.level + 1, true, true); + tdp_mmu_set_spte(kvm, kvm_mmu_page_as_id(sp), sp->ptep, old_spte, 0, + sp->gfn, sp->role.level + 1); return true; } @@ -958,7 +856,7 @@ static bool tdp_mmu_zap_leafs(struct kvm *kvm, struct kvm_mmu_page *root, !is_last_spte(iter.old_spte, iter.level)) continue; - tdp_mmu_set_spte(kvm, &iter, 0); + tdp_mmu_iter_set_spte(kvm, &iter, 0); flush = true; } @@ -1022,32 +920,49 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm) /* * Mark each TDP MMU root as invalid to prevent vCPUs from reusing a root that * is about to be zapped, e.g. in response to a memslots update. The actual - * zapping is performed asynchronously, so a reference is taken on all roots. - * Using a separate workqueue makes it easy to ensure that the destruction is - * performed before the "fast zap" completes, without keeping a separate list - * of invalidated roots; the list is effectively the list of work items in - * the workqueue. + * zapping is performed asynchronously. Using a separate workqueue makes it + * easy to ensure that the destruction is performed before the "fast zap" + * completes, without keeping a separate list of invalidated roots; the list is + * effectively the list of work items in the workqueue. * - * Get a reference even if the root is already invalid, the asynchronous worker - * assumes it was gifted a reference to the root it processes. Because mmu_lock - * is held for write, it should be impossible to observe a root with zero refcount, - * i.e. the list of roots cannot be stale. - * - * This has essentially the same effect for the TDP MMU - * as updating mmu_valid_gen does for the shadow MMU. + * Note, the asynchronous worker is gifted the TDP MMU's reference. + * See kvm_tdp_mmu_get_vcpu_root_hpa(). */ void kvm_tdp_mmu_invalidate_all_roots(struct kvm *kvm) { struct kvm_mmu_page *root; - lockdep_assert_held_write(&kvm->mmu_lock); - list_for_each_entry(root, &kvm->arch.tdp_mmu_roots, link) { - if (!root->role.invalid && - !WARN_ON_ONCE(!kvm_tdp_mmu_get_root(root))) { + /* + * mmu_lock must be held for write to ensure that a root doesn't become + * invalid while there are active readers (invalidating a root while + * there are active readers may or may not be problematic in practice, + * but it's uncharted territory and not supported). + * + * Waive the assertion if there are no users of @kvm, i.e. the VM is + * being destroyed after all references have been put, or if no vCPUs + * have been created (which means there are no roots), i.e. the VM is + * being destroyed in an error path of KVM_CREATE_VM. + */ + if (IS_ENABLED(CONFIG_PROVE_LOCKING) && + refcount_read(&kvm->users_count) && kvm->created_vcpus) + lockdep_assert_held_write(&kvm->mmu_lock); + + /* + * As above, mmu_lock isn't held when destroying the VM! There can't + * be other references to @kvm, i.e. nothing else can invalidate roots + * or be consuming roots, but walking the list of roots does need to be + * guarded against roots being deleted by the asynchronous zap worker. + */ + rcu_read_lock(); + + list_for_each_entry_rcu(root, &kvm->arch.tdp_mmu_roots, link) { + if (!root->role.invalid) { root->role.invalid = true; tdp_mmu_schedule_zap_root(kvm, root); } } + + rcu_read_unlock(); } /* @@ -1128,7 +1043,7 @@ static int tdp_mmu_link_sp(struct kvm *kvm, struct tdp_iter *iter, if (ret) return ret; } else { - tdp_mmu_set_spte(kvm, iter, spte); + tdp_mmu_iter_set_spte(kvm, iter, spte); } tdp_account_mmu_page(kvm, sp); @@ -1262,33 +1177,42 @@ static __always_inline bool kvm_tdp_mmu_handle_gfn(struct kvm *kvm, /* * Mark the SPTEs range of GFNs [start, end) unaccessed and return non-zero * if any of the GFNs in the range have been accessed. + * + * No need to mark the corresponding PFN as accessed as this call is coming + * from the clear_young() or clear_flush_young() notifier, which uses the + * return value to determine if the page has been accessed. */ static bool age_gfn_range(struct kvm *kvm, struct tdp_iter *iter, struct kvm_gfn_range *range) { - u64 new_spte = 0; + u64 new_spte; /* If we have a non-accessed entry we don't need to change the pte. */ if (!is_accessed_spte(iter->old_spte)) return false; - new_spte = iter->old_spte; - - if (spte_ad_enabled(new_spte)) { - new_spte &= ~shadow_accessed_mask; + if (spte_ad_enabled(iter->old_spte)) { + iter->old_spte = tdp_mmu_clear_spte_bits(iter->sptep, + iter->old_spte, + shadow_accessed_mask, + iter->level); + new_spte = iter->old_spte & ~shadow_accessed_mask; } else { /* * Capture the dirty status of the page, so that it doesn't get * lost when the SPTE is marked for access tracking. */ - if (is_writable_pte(new_spte)) - kvm_set_pfn_dirty(spte_to_pfn(new_spte)); + if (is_writable_pte(iter->old_spte)) + kvm_set_pfn_dirty(spte_to_pfn(iter->old_spte)); - new_spte = mark_spte_for_access_track(new_spte); + new_spte = mark_spte_for_access_track(iter->old_spte); + iter->old_spte = kvm_tdp_mmu_write_spte(iter->sptep, + iter->old_spte, new_spte, + iter->level); } - tdp_mmu_set_spte_no_acc_track(kvm, iter, new_spte); - + trace_kvm_tdp_mmu_spte_changed(iter->as_id, iter->gfn, iter->level, + iter->old_spte, new_spte); return true; } @@ -1324,15 +1248,15 @@ static bool set_spte_gfn(struct kvm *kvm, struct tdp_iter *iter, * Note, when changing a read-only SPTE, it's not strictly necessary to * zero the SPTE before setting the new PFN, but doing so preserves the * invariant that the PFN of a present * leaf SPTE can never change. - * See __handle_changed_spte(). + * See handle_changed_spte(). */ - tdp_mmu_set_spte(kvm, iter, 0); + tdp_mmu_iter_set_spte(kvm, iter, 0); if (!pte_write(range->pte)) { new_spte = kvm_mmu_changed_pte_notifier_make_spte(iter->old_spte, pte_pfn(range->pte)); - tdp_mmu_set_spte(kvm, iter, new_spte); + tdp_mmu_iter_set_spte(kvm, iter, new_spte); } return true; @@ -1349,7 +1273,7 @@ bool kvm_tdp_mmu_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) /* * No need to handle the remote TLB flush under RCU protection, the * target SPTE _must_ be a leaf SPTE, i.e. cannot result in freeing a - * shadow page. See the WARN on pfn_changed in __handle_changed_spte(). + * shadow page. See the WARN on pfn_changed in handle_changed_spte(). */ return kvm_tdp_mmu_handle_gfn(kvm, range, set_spte_gfn); } @@ -1607,8 +1531,8 @@ void kvm_tdp_mmu_try_split_huge_pages(struct kvm *kvm, static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, gfn_t start, gfn_t end) { + u64 dbit = kvm_ad_enabled() ? shadow_dirty_mask : PT_WRITABLE_MASK; struct tdp_iter iter; - u64 new_spte; bool spte_set = false; rcu_read_lock(); @@ -1621,19 +1545,13 @@ retry: if (!is_shadow_present_pte(iter.old_spte)) continue; - if (spte_ad_need_write_protect(iter.old_spte)) { - if (is_writable_pte(iter.old_spte)) - new_spte = iter.old_spte & ~PT_WRITABLE_MASK; - else - continue; - } else { - if (iter.old_spte & shadow_dirty_mask) - new_spte = iter.old_spte & ~shadow_dirty_mask; - else - continue; - } + MMU_WARN_ON(kvm_ad_enabled() && + spte_ad_need_write_protect(iter.old_spte)); - if (tdp_mmu_set_spte_atomic(kvm, &iter, new_spte)) + if (!(iter.old_spte & dbit)) + continue; + + if (tdp_mmu_set_spte_atomic(kvm, &iter, iter.old_spte & ~dbit)) goto retry; spte_set = true; @@ -1675,8 +1593,9 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, gfn_t gfn, unsigned long mask, bool wrprot) { + u64 dbit = (wrprot || !kvm_ad_enabled()) ? PT_WRITABLE_MASK : + shadow_dirty_mask; struct tdp_iter iter; - u64 new_spte; rcu_read_lock(); @@ -1685,25 +1604,26 @@ static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, if (!mask) break; + MMU_WARN_ON(kvm_ad_enabled() && + spte_ad_need_write_protect(iter.old_spte)); + if (iter.level > PG_LEVEL_4K || !(mask & (1UL << (iter.gfn - gfn)))) continue; mask &= ~(1UL << (iter.gfn - gfn)); - if (wrprot || spte_ad_need_write_protect(iter.old_spte)) { - if (is_writable_pte(iter.old_spte)) - new_spte = iter.old_spte & ~PT_WRITABLE_MASK; - else - continue; - } else { - if (iter.old_spte & shadow_dirty_mask) - new_spte = iter.old_spte & ~shadow_dirty_mask; - else - continue; - } + if (!(iter.old_spte & dbit)) + continue; - tdp_mmu_set_spte_no_dirty_log(kvm, &iter, new_spte); + iter.old_spte = tdp_mmu_clear_spte_bits(iter.sptep, + iter.old_spte, dbit, + iter.level); + + trace_kvm_tdp_mmu_spte_changed(iter.as_id, iter.gfn, iter.level, + iter.old_spte, + iter.old_spte & ~dbit); + kvm_set_pfn_dirty(spte_to_pfn(iter.old_spte)); } rcu_read_unlock(); @@ -1821,7 +1741,7 @@ static bool write_protect_gfn(struct kvm *kvm, struct kvm_mmu_page *root, if (new_spte == iter.old_spte) break; - tdp_mmu_set_spte(kvm, &iter, new_spte); + tdp_mmu_iter_set_spte(kvm, &iter, new_spte); spte_set = true; } diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 612e6c70ce2e..1690d41c1830 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -93,7 +93,7 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops) #undef __KVM_X86_PMU_OP } -static inline bool pmc_is_enabled(struct kvm_pmc *pmc) +static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc) { return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc); } @@ -400,6 +400,12 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) return is_fixed_event_allowed(filter, pmc->idx); } +static bool pmc_event_is_allowed(struct kvm_pmc *pmc) +{ + return pmc_is_globally_enabled(pmc) && pmc_speculative_in_use(pmc) && + check_pmu_event_filter(pmc); +} + static void reprogram_counter(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); @@ -409,10 +415,7 @@ static void reprogram_counter(struct kvm_pmc *pmc) pmc_pause_counter(pmc); - if (!pmc_speculative_in_use(pmc) || !pmc_is_enabled(pmc)) - goto reprogram_complete; - - if (!check_pmu_event_filter(pmc)) + if (!pmc_event_is_allowed(pmc)) goto reprogram_complete; if (pmc->counter < pmc->prev_counter) @@ -540,9 +543,9 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data) if (!pmc) return 1; - if (!(kvm_read_cr4(vcpu) & X86_CR4_PCE) && + if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_PCE) && (static_call(kvm_x86_get_cpl)(vcpu) != 0) && - (kvm_read_cr0(vcpu) & X86_CR0_PE)) + kvm_is_cr0_bit_set(vcpu, X86_CR0_PE)) return 1; *data = pmc_read_counter(pmc) & mask; @@ -589,6 +592,10 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) */ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) { + if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm)) + return; + + bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX); static_call(kvm_x86_pmu_refresh)(vcpu); } @@ -646,7 +653,7 @@ static void kvm_pmu_incr_counter(struct kvm_pmc *pmc) { pmc->prev_counter = pmc->counter; pmc->counter = (pmc->counter + 1) & pmc_bitmask(pmc); - kvm_pmu_request_counter_reprogam(pmc); + kvm_pmu_request_counter_reprogram(pmc); } static inline bool eventsel_match_perf_hw_id(struct kvm_pmc *pmc, @@ -684,7 +691,7 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id) for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); - if (!pmc || !pmc_is_enabled(pmc) || !pmc_speculative_in_use(pmc)) + if (!pmc || !pmc_event_is_allowed(pmc)) continue; /* Ignore checks for edge detect, pin control, invert and CMASK bits */ diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index be62c16f2265..5c7bbf03b599 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -195,7 +195,7 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops) KVM_PMC_MAX_FIXED); } -static inline void kvm_pmu_request_counter_reprogam(struct kvm_pmc *pmc) +static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc) { set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi); kvm_make_request(KVM_REQ_PMU, pmc->vcpu); diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 05d38944a6c0..96936ddf1b3c 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -139,13 +139,18 @@ void recalc_intercepts(struct vcpu_svm *svm) if (g->int_ctl & V_INTR_MASKING_MASK) { /* - * Once running L2 with HF_VINTR_MASK, EFLAGS.IF and CR8 - * does not affect any interrupt we may want to inject; - * therefore, writes to CR8 are irrelevant to L0, as are - * interrupt window vmexits. + * If L2 is active and V_INTR_MASKING is enabled in vmcb12, + * disable intercept of CR8 writes as L2's CR8 does not affect + * any interrupt KVM may want to inject. + * + * Similarly, disable intercept of virtual interrupts (used to + * detect interrupt windows) if the saved RFLAGS.IF is '0', as + * the effective RFLAGS.IF for L1 interrupts will never be set + * while L2 is running (L2's RFLAGS.IF doesn't affect L1 IRQs). */ vmcb_clr_intercept(c, INTERCEPT_CR8_WRITE); - vmcb_clr_intercept(c, INTERCEPT_VINTR); + if (!(svm->vmcb01.ptr->save.rflags & X86_EFLAGS_IF)) + vmcb_clr_intercept(c, INTERCEPT_VINTR); } /* @@ -276,6 +281,11 @@ static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu, if (CC(!nested_svm_check_tlb_ctl(vcpu, control->tlb_ctl))) return false; + if (CC((control->int_ctl & V_NMI_ENABLE_MASK) && + !vmcb12_is_intercept(control, INTERCEPT_NMI))) { + return false; + } + return true; } @@ -416,22 +426,24 @@ void nested_sync_control_from_vmcb02(struct vcpu_svm *svm) /* Only a few fields of int_ctl are written by the processor. */ mask = V_IRQ_MASK | V_TPR_MASK; - if (!(svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK) && - svm_is_intercept(svm, INTERCEPT_VINTR)) { - /* - * In order to request an interrupt window, L0 is usurping - * svm->vmcb->control.int_ctl and possibly setting V_IRQ - * even if it was clear in L1's VMCB. Restoring it would be - * wrong. However, in this case V_IRQ will remain true until - * interrupt_window_interception calls svm_clear_vintr and - * restores int_ctl. We can just leave it aside. - */ + /* + * Don't sync vmcb02 V_IRQ back to vmcb12 if KVM (L0) is intercepting + * virtual interrupts in order to request an interrupt window, as KVM + * has usurped vmcb02's int_ctl. If an interrupt window opens before + * the next VM-Exit, svm_clear_vintr() will restore vmcb12's int_ctl. + * If no window opens, V_IRQ will be correctly preserved in vmcb12's + * int_ctl (because it was never recognized while L2 was running). + */ + if (svm_is_intercept(svm, INTERCEPT_VINTR) && + !test_bit(INTERCEPT_VINTR, (unsigned long *)svm->nested.ctl.intercepts)) mask &= ~V_IRQ_MASK; - } if (nested_vgif_enabled(svm)) mask |= V_GIF_MASK; + if (nested_vnmi_enabled(svm)) + mask |= V_NMI_BLOCKING_MASK | V_NMI_PENDING_MASK; + svm->nested.ctl.int_ctl &= ~mask; svm->nested.ctl.int_ctl |= svm->vmcb->control.int_ctl & mask; } @@ -651,6 +663,17 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, else int_ctl_vmcb01_bits |= (V_GIF_MASK | V_GIF_ENABLE_MASK); + if (vnmi) { + if (vmcb01->control.int_ctl & V_NMI_PENDING_MASK) { + svm->vcpu.arch.nmi_pending++; + kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); + } + if (nested_vnmi_enabled(svm)) + int_ctl_vmcb12_bits |= (V_NMI_PENDING_MASK | + V_NMI_ENABLE_MASK | + V_NMI_BLOCKING_MASK); + } + /* Copied from vmcb01. msrpm_base can be overwritten later. */ vmcb02->control.nested_ctl = vmcb01->control.nested_ctl; vmcb02->control.iopm_base_pa = vmcb01->control.iopm_base_pa; @@ -1021,6 +1044,28 @@ int nested_svm_vmexit(struct vcpu_svm *svm) svm_switch_vmcb(svm, &svm->vmcb01); + /* + * Rules for synchronizing int_ctl bits from vmcb02 to vmcb01: + * + * V_IRQ, V_IRQ_VECTOR, V_INTR_PRIO_MASK, V_IGN_TPR: If L1 doesn't + * intercept interrupts, then KVM will use vmcb02's V_IRQ (and related + * flags) to detect interrupt windows for L1 IRQs (even if L1 uses + * virtual interrupt masking). Raise KVM_REQ_EVENT to ensure that + * KVM re-requests an interrupt window if necessary, which implicitly + * copies this bits from vmcb02 to vmcb01. + * + * V_TPR: If L1 doesn't use virtual interrupt masking, then L1's vTPR + * is stored in vmcb02, but its value doesn't need to be copied from/to + * vmcb01 because it is copied from/to the virtual APIC's TPR register + * on each VM entry/exit. + * + * V_GIF: If nested vGIF is not used, KVM uses vmcb02's V_GIF for L1's + * V_GIF. However, GIF is architecturally clear on each VM exit, thus + * there is no need to copy V_GIF from vmcb02 to vmcb01. + */ + if (!nested_exit_on_intr(svm)) + kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); + if (unlikely(svm->lbrv_enabled && (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK))) { svm_copy_lbrs(vmcb12, vmcb02); svm_update_lbrv(vcpu); @@ -1029,6 +1074,20 @@ int nested_svm_vmexit(struct vcpu_svm *svm) svm_update_lbrv(vcpu); } + if (vnmi) { + if (vmcb02->control.int_ctl & V_NMI_BLOCKING_MASK) + vmcb01->control.int_ctl |= V_NMI_BLOCKING_MASK; + else + vmcb01->control.int_ctl &= ~V_NMI_BLOCKING_MASK; + + if (vcpu->arch.nmi_pending) { + vcpu->arch.nmi_pending--; + vmcb01->control.int_ctl |= V_NMI_PENDING_MASK; + } else { + vmcb01->control.int_ctl &= ~V_NMI_PENDING_MASK; + } + } + /* * On vmexit the GIF is set to false and * no event can be injected in L1. diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index cc77a0681800..5fa939e411d8 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -161,7 +161,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) data &= ~pmu->reserved_bits; if (data != pmc->eventsel) { pmc->eventsel = data; - kvm_pmu_request_counter_reprogam(pmc); + kvm_pmu_request_counter_reprogram(pmc); } return 0; } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index f25bc3cbb250..54089f990c8f 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,9 @@ #include #include + +#include + #include "trace.h" #include "svm.h" @@ -95,6 +99,7 @@ static const struct svm_direct_access_msrs { #endif { .index = MSR_IA32_SPEC_CTRL, .always = false }, { .index = MSR_IA32_PRED_CMD, .always = false }, + { .index = MSR_IA32_FLUSH_CMD, .always = false }, { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false }, { .index = MSR_IA32_LASTBRANCHTOIP, .always = false }, { .index = MSR_IA32_LASTINTFROMIP, .always = false }, @@ -230,6 +235,8 @@ module_param(dump_invalid_vmcb, bool, 0644); bool intercept_smi = true; module_param(intercept_smi, bool, 0444); +bool vnmi = true; +module_param(vnmi, bool, 0444); static bool svm_gp_erratum_intercept = true; @@ -1311,6 +1318,9 @@ static void init_vmcb(struct kvm_vcpu *vcpu) if (kvm_vcpu_apicv_active(vcpu)) avic_init_vmcb(svm, vmcb); + if (vnmi) + svm->vmcb->control.int_ctl |= V_NMI_ENABLE_MASK; + if (vgif) { svm_clr_intercept(svm, INTERCEPT_STGI); svm_clr_intercept(svm, INTERCEPT_CLGI); @@ -1583,6 +1593,16 @@ static void svm_set_vintr(struct vcpu_svm *svm) svm_set_intercept(svm, INTERCEPT_VINTR); + /* + * Recalculating intercepts may have cleared the VINTR intercept. If + * V_INTR_MASKING is enabled in vmcb12, then the effective RFLAGS.IF + * for L1 physical interrupts is L1's RFLAGS.IF at the time of VMRUN. + * Requesting an interrupt window if save.RFLAGS.IF=0 is pointless as + * interrupts will never be unblocked while L2 is running. + */ + if (!svm_is_intercept(svm, INTERCEPT_VINTR)) + return; + /* * This is just a dummy VINTR to actually cause a vmexit to happen. * Actual injection of virtual interrupts happens through EVENTINJ. @@ -2480,16 +2500,29 @@ static int task_switch_interception(struct kvm_vcpu *vcpu) has_error_code, error_code); } +static void svm_clr_iret_intercept(struct vcpu_svm *svm) +{ + if (!sev_es_guest(svm->vcpu.kvm)) + svm_clr_intercept(svm, INTERCEPT_IRET); +} + +static void svm_set_iret_intercept(struct vcpu_svm *svm) +{ + if (!sev_es_guest(svm->vcpu.kvm)) + svm_set_intercept(svm, INTERCEPT_IRET); +} + static int iret_interception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); ++vcpu->stat.nmi_window_exits; svm->awaiting_iret_completion = true; - if (!sev_es_guest(vcpu->kvm)) { - svm_clr_intercept(svm, INTERCEPT_IRET); + + svm_clr_iret_intercept(svm); + if (!sev_es_guest(vcpu->kvm)) svm->nmi_iret_rip = kvm_rip_read(vcpu); - } + kvm_make_request(KVM_REQ_EVENT, vcpu); return 1; } @@ -2872,7 +2905,7 @@ static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data) static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) { struct vcpu_svm *svm = to_svm(vcpu); - int r; + int ret = 0; u32 ecx = msr->index; u64 data = msr->data; @@ -2942,21 +2975,6 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) */ set_msr_interception(vcpu, svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1); break; - case MSR_IA32_PRED_CMD: - if (!msr->host_initiated && - !guest_has_pred_cmd_msr(vcpu)) - return 1; - - if (data & ~PRED_CMD_IBPB) - return 1; - if (!boot_cpu_has(X86_FEATURE_IBPB)) - return 1; - if (!data) - break; - - wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); - set_msr_interception(vcpu, svm->msrpm, MSR_IA32_PRED_CMD, 0, 1); - break; case MSR_AMD64_VIRT_SPEC_CTRL: if (!msr->host_initiated && !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD)) @@ -3009,10 +3027,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) * guest via direct_access_msrs, and switch it via user return. */ preempt_disable(); - r = kvm_set_user_return_msr(tsc_aux_uret_slot, data, -1ull); + ret = kvm_set_user_return_msr(tsc_aux_uret_slot, data, -1ull); preempt_enable(); - if (r) - return 1; + if (ret) + break; svm->tsc_aux = data; break; @@ -3070,7 +3088,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) default: return kvm_set_msr_common(vcpu, msr); } - return 0; + return ret; } static int msr_interception(struct kvm_vcpu *vcpu) @@ -3481,11 +3499,43 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu) return; svm->nmi_masked = true; - if (!sev_es_guest(vcpu->kvm)) - svm_set_intercept(svm, INTERCEPT_IRET); + svm_set_iret_intercept(svm); ++vcpu->stat.nmi_injections; } +static bool svm_is_vnmi_pending(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (!is_vnmi_enabled(svm)) + return false; + + return !!(svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK); +} + +static bool svm_set_vnmi_pending(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (!is_vnmi_enabled(svm)) + return false; + + if (svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK) + return false; + + svm->vmcb->control.int_ctl |= V_NMI_PENDING_MASK; + vmcb_mark_dirty(svm->vmcb, VMCB_INTR); + + /* + * Because the pending NMI is serviced by hardware, KVM can't know when + * the NMI is "injected", but for all intents and purposes, passing the + * NMI off to hardware counts as injection. + */ + ++vcpu->stat.nmi_injections; + + return true; +} + static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3581,6 +3631,35 @@ static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) svm_set_intercept(svm, INTERCEPT_CR8_WRITE); } +static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (is_vnmi_enabled(svm)) + return svm->vmcb->control.int_ctl & V_NMI_BLOCKING_MASK; + else + return svm->nmi_masked; +} + +static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (is_vnmi_enabled(svm)) { + if (masked) + svm->vmcb->control.int_ctl |= V_NMI_BLOCKING_MASK; + else + svm->vmcb->control.int_ctl &= ~V_NMI_BLOCKING_MASK; + + } else { + svm->nmi_masked = masked; + if (masked) + svm_set_iret_intercept(svm); + else + svm_clr_iret_intercept(svm); + } +} + bool svm_nmi_blocked(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3592,8 +3671,10 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu) if (is_guest_mode(vcpu) && nested_exit_on_nmi(svm)) return false; - return (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || - svm->nmi_masked; + if (svm_get_nmi_mask(vcpu)) + return true; + + return vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK; } static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) @@ -3611,26 +3692,6 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection) return 1; } -static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) -{ - return to_svm(vcpu)->nmi_masked; -} - -static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - if (masked) { - svm->nmi_masked = true; - if (!sev_es_guest(vcpu->kvm)) - svm_set_intercept(svm, INTERCEPT_IRET); - } else { - svm->nmi_masked = false; - if (!sev_es_guest(vcpu->kvm)) - svm_clr_intercept(svm, INTERCEPT_IRET); - } -} - bool svm_interrupt_blocked(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3711,7 +3772,16 @@ static void svm_enable_nmi_window(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - if (svm->nmi_masked && !svm->awaiting_iret_completion) + /* + * KVM should never request an NMI window when vNMI is enabled, as KVM + * allows at most one to-be-injected NMI and one pending NMI, i.e. if + * two NMIs arrive simultaneously, KVM will inject one and set + * V_NMI_PENDING for the other. WARN, but continue with the standard + * single-step approach to try and salvage the pending NMI. + */ + WARN_ON_ONCE(is_vnmi_enabled(svm)); + + if (svm_get_nmi_mask(vcpu) && !svm->awaiting_iret_completion) return; /* IRET will cause a vm exit */ if (!gif_set(svm)) { @@ -3773,13 +3843,13 @@ static void svm_flush_tlb_all(struct kvm_vcpu *vcpu) { /* * When running on Hyper-V with EnlightenedNptTlb enabled, remote TLB - * flushes should be routed to hv_remote_flush_tlb() without requesting + * flushes should be routed to hv_flush_remote_tlbs() without requesting * a "regular" remote flush. Reaching this point means either there's - * a KVM bug or a prior hv_remote_flush_tlb() call failed, both of + * a KVM bug or a prior hv_flush_remote_tlbs() call failed, both of * which might be fatal to the guest. Yell, but try to recover. */ if (WARN_ON_ONCE(svm_hv_is_enlightened_tlb_enabled(vcpu))) - hv_remote_flush_tlb(vcpu->kvm); + hv_flush_remote_tlbs(vcpu->kvm); svm_flush_tlb_asid(vcpu); } @@ -4138,7 +4208,7 @@ static bool svm_has_emulated_msr(struct kvm *kvm, u32 index) { switch (index) { case MSR_IA32_MCG_EXT_CTL: - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: return false; case MSR_IA32_SMBASE: if (!IS_ENABLED(CONFIG_KVM_SMM)) @@ -4180,8 +4250,18 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) svm->vgif_enabled = vgif && guest_cpuid_has(vcpu, X86_FEATURE_VGIF); + svm->vnmi_enabled = vnmi && guest_cpuid_has(vcpu, X86_FEATURE_VNMI); + svm_recalc_instruction_intercepts(vcpu, svm); + if (boot_cpu_has(X86_FEATURE_IBPB)) + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_PRED_CMD, 0, + !!guest_has_pred_cmd_msr(vcpu)); + + if (boot_cpu_has(X86_FEATURE_FLUSH_L1D)) + set_msr_interception(vcpu, svm->msrpm, MSR_IA32_FLUSH_CMD, 0, + !!guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D)); + /* For sev guests, the memory encryption bit is not reserved in CR3. */ if (sev_guest(vcpu->kvm)) { best = kvm_find_cpuid_entry(vcpu, 0x8000001F); @@ -4559,7 +4639,6 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, void *insn, int insn_len) { bool smep, smap, is_user; - unsigned long cr4; u64 error_code; /* Emulation is always possible when KVM has access to all guest state. */ @@ -4651,9 +4730,8 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, if (error_code & (PFERR_GUEST_PAGE_MASK | PFERR_FETCH_MASK)) goto resume_guest; - cr4 = kvm_read_cr4(vcpu); - smep = cr4 & X86_CR4_SMEP; - smap = cr4 & X86_CR4_SMAP; + smep = kvm_is_cr4_bit_set(vcpu, X86_CR4_SMEP); + smap = kvm_is_cr4_bit_set(vcpu, X86_CR4_SMAP); is_user = svm_get_cpl(vcpu) == 3; if (smap && (!smep || is_user)) { pr_err_ratelimited("SEV Guest triggered AMD Erratum 1096\n"); @@ -4791,6 +4869,8 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .patch_hypercall = svm_patch_hypercall, .inject_irq = svm_inject_irq, .inject_nmi = svm_inject_nmi, + .is_vnmi_pending = svm_is_vnmi_pending, + .set_vnmi_pending = svm_set_vnmi_pending, .inject_exception = svm_inject_exception, .cancel_injection = svm_cancel_injection, .interrupt_allowed = svm_interrupt_allowed, @@ -4933,6 +5013,9 @@ static __init void svm_set_cpu_caps(void) if (vgif) kvm_cpu_cap_set(X86_FEATURE_VGIF); + if (vnmi) + kvm_cpu_cap_set(X86_FEATURE_VNMI); + /* Nested VM can receive #VMEXIT instead of triggering #GP */ kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK); } @@ -5084,6 +5167,16 @@ static __init int svm_hardware_setup(void) pr_info("Virtual GIF supported\n"); } + vnmi = vgif && vnmi && boot_cpu_has(X86_FEATURE_VNMI); + if (vnmi) + pr_info("Virtual NMI enabled\n"); + + if (!vnmi) { + svm_x86_ops.is_vnmi_pending = NULL; + svm_x86_ops.set_vnmi_pending = NULL; + } + + if (lbrv) { if (!boot_cpu_has(X86_FEATURE_LBRV)) lbrv = false; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 839809972da1..f44751dd8d5d 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -36,6 +36,7 @@ extern bool npt_enabled; extern int vgif; extern bool intercept_smi; extern bool x2avic_enabled; +extern bool vnmi; /* * Clean bits in VMCB. @@ -265,6 +266,7 @@ struct vcpu_svm { bool pause_filter_enabled : 1; bool pause_threshold_enabled : 1; bool vgif_enabled : 1; + bool vnmi_enabled : 1; u32 ldr_reg; u32 dfr_reg; @@ -539,6 +541,12 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm) return svm->nested.ctl.nested_ctl & SVM_NESTED_CTL_NP_ENABLE; } +static inline bool nested_vnmi_enabled(struct vcpu_svm *svm) +{ + return svm->vnmi_enabled && + (svm->nested.ctl.int_ctl & V_NMI_ENABLE_MASK); +} + static inline bool is_x2apic_msrpm_offset(u32 offset) { /* 4 msrs per u8, and 4 u8 in u32 */ @@ -548,6 +556,27 @@ static inline bool is_x2apic_msrpm_offset(u32 offset) (msr < (APIC_BASE_MSR + 0x100)); } +static inline struct vmcb *get_vnmi_vmcb_l1(struct vcpu_svm *svm) +{ + if (!vnmi) + return NULL; + + if (is_guest_mode(&svm->vcpu)) + return NULL; + else + return svm->vmcb01.ptr; +} + +static inline bool is_vnmi_enabled(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = get_vnmi_vmcb_l1(svm); + + if (vmcb) + return !!(vmcb->control.int_ctl & V_NMI_ENABLE_MASK); + else + return false; +} + /* svm.c */ #define MSR_INVALID 0xffffffffU diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h index 786d46d73a8e..f85bc617ffe4 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.h +++ b/arch/x86/kvm/svm/svm_onhyperv.h @@ -45,9 +45,8 @@ static inline __init void svm_hv_hardware_setup(void) if (npt_enabled && ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) { pr_info(KBUILD_MODNAME ": Hyper-V enlightened NPT TLB flush enabled\n"); - svm_x86_ops.tlb_remote_flush = hv_remote_flush_tlb; - svm_x86_ops.tlb_remote_flush_with_range = - hv_remote_flush_tlb_with_range; + svm_x86_ops.flush_remote_tlbs = hv_flush_remote_tlbs; + svm_x86_ops.flush_remote_tlbs_range = hv_flush_remote_tlbs_range; } if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) { diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index 22daca752797..79450e1ed7cf 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -13,7 +13,110 @@ #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK -DEFINE_STATIC_KEY_FALSE(enable_evmcs); +/* + * Enlightened VMCSv1 doesn't support these: + * + * POSTED_INTR_NV = 0x00000002, + * GUEST_INTR_STATUS = 0x00000810, + * APIC_ACCESS_ADDR = 0x00002014, + * POSTED_INTR_DESC_ADDR = 0x00002016, + * EOI_EXIT_BITMAP0 = 0x0000201c, + * EOI_EXIT_BITMAP1 = 0x0000201e, + * EOI_EXIT_BITMAP2 = 0x00002020, + * EOI_EXIT_BITMAP3 = 0x00002022, + * GUEST_PML_INDEX = 0x00000812, + * PML_ADDRESS = 0x0000200e, + * VM_FUNCTION_CONTROL = 0x00002018, + * EPTP_LIST_ADDRESS = 0x00002024, + * VMREAD_BITMAP = 0x00002026, + * VMWRITE_BITMAP = 0x00002028, + * + * TSC_MULTIPLIER = 0x00002032, + * PLE_GAP = 0x00004020, + * PLE_WINDOW = 0x00004022, + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, + * + * Currently unsupported in KVM: + * GUEST_IA32_RTIT_CTL = 0x00002814, + */ +#define EVMCS1_SUPPORTED_PINCTRL \ + (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ + PIN_BASED_EXT_INTR_MASK | \ + PIN_BASED_NMI_EXITING | \ + PIN_BASED_VIRTUAL_NMIS) + +#define EVMCS1_SUPPORTED_EXEC_CTRL \ + (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ + CPU_BASED_HLT_EXITING | \ + CPU_BASED_CR3_LOAD_EXITING | \ + CPU_BASED_CR3_STORE_EXITING | \ + CPU_BASED_UNCOND_IO_EXITING | \ + CPU_BASED_MOV_DR_EXITING | \ + CPU_BASED_USE_TSC_OFFSETTING | \ + CPU_BASED_MWAIT_EXITING | \ + CPU_BASED_MONITOR_EXITING | \ + CPU_BASED_INVLPG_EXITING | \ + CPU_BASED_RDPMC_EXITING | \ + CPU_BASED_INTR_WINDOW_EXITING | \ + CPU_BASED_CR8_LOAD_EXITING | \ + CPU_BASED_CR8_STORE_EXITING | \ + CPU_BASED_RDTSC_EXITING | \ + CPU_BASED_TPR_SHADOW | \ + CPU_BASED_USE_IO_BITMAPS | \ + CPU_BASED_MONITOR_TRAP_FLAG | \ + CPU_BASED_USE_MSR_BITMAPS | \ + CPU_BASED_NMI_WINDOW_EXITING | \ + CPU_BASED_PAUSE_EXITING | \ + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) + +#define EVMCS1_SUPPORTED_2NDEXEC \ + (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ + SECONDARY_EXEC_WBINVD_EXITING | \ + SECONDARY_EXEC_ENABLE_VPID | \ + SECONDARY_EXEC_ENABLE_EPT | \ + SECONDARY_EXEC_UNRESTRICTED_GUEST | \ + SECONDARY_EXEC_DESC | \ + SECONDARY_EXEC_ENABLE_RDTSCP | \ + SECONDARY_EXEC_ENABLE_INVPCID | \ + SECONDARY_EXEC_XSAVES | \ + SECONDARY_EXEC_RDSEED_EXITING | \ + SECONDARY_EXEC_RDRAND_EXITING | \ + SECONDARY_EXEC_TSC_SCALING | \ + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ + SECONDARY_EXEC_PT_USE_GPA | \ + SECONDARY_EXEC_PT_CONCEAL_VMX | \ + SECONDARY_EXEC_BUS_LOCK_DETECTION | \ + SECONDARY_EXEC_NOTIFY_VM_EXITING | \ + SECONDARY_EXEC_ENCLS_EXITING) + +#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) + +#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ + (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ + VM_EXIT_SAVE_DEBUG_CONTROLS | \ + VM_EXIT_ACK_INTR_ON_EXIT | \ + VM_EXIT_HOST_ADDR_SPACE_SIZE | \ + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_EXIT_SAVE_IA32_PAT | \ + VM_EXIT_LOAD_IA32_PAT | \ + VM_EXIT_SAVE_IA32_EFER | \ + VM_EXIT_LOAD_IA32_EFER | \ + VM_EXIT_CLEAR_BNDCFGS | \ + VM_EXIT_PT_CONCEAL_PIP | \ + VM_EXIT_CLEAR_IA32_RTIT_CTL) + +#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ + VM_ENTRY_LOAD_DEBUG_CONTROLS | \ + VM_ENTRY_IA32E_MODE | \ + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_ENTRY_LOAD_IA32_PAT | \ + VM_ENTRY_LOAD_IA32_EFER | \ + VM_ENTRY_LOAD_BNDCFGS | \ + VM_ENTRY_PT_CONCEAL_PIP | \ + VM_ENTRY_LOAD_IA32_RTIT_CTL) + +#define EVMCS1_SUPPORTED_VMFUNC (0) #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x) #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \ @@ -506,6 +609,8 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) } #if IS_ENABLED(CONFIG_HYPERV) +DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); + /* * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption * is: in case a feature has corresponding fields in eVMCS described and it was diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h index 78d17667e7ec..9623fe1651c4 100644 --- a/arch/x86/kvm/vmx/hyperv.h +++ b/arch/x86/kvm/vmx/hyperv.h @@ -16,117 +16,10 @@ struct vmcs_config; -DECLARE_STATIC_KEY_FALSE(enable_evmcs); - #define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) #define KVM_EVMCS_VERSION 1 -/* - * Enlightened VMCSv1 doesn't support these: - * - * POSTED_INTR_NV = 0x00000002, - * GUEST_INTR_STATUS = 0x00000810, - * APIC_ACCESS_ADDR = 0x00002014, - * POSTED_INTR_DESC_ADDR = 0x00002016, - * EOI_EXIT_BITMAP0 = 0x0000201c, - * EOI_EXIT_BITMAP1 = 0x0000201e, - * EOI_EXIT_BITMAP2 = 0x00002020, - * EOI_EXIT_BITMAP3 = 0x00002022, - * GUEST_PML_INDEX = 0x00000812, - * PML_ADDRESS = 0x0000200e, - * VM_FUNCTION_CONTROL = 0x00002018, - * EPTP_LIST_ADDRESS = 0x00002024, - * VMREAD_BITMAP = 0x00002026, - * VMWRITE_BITMAP = 0x00002028, - * - * TSC_MULTIPLIER = 0x00002032, - * PLE_GAP = 0x00004020, - * PLE_WINDOW = 0x00004022, - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, - * - * Currently unsupported in KVM: - * GUEST_IA32_RTIT_CTL = 0x00002814, - */ -#define EVMCS1_SUPPORTED_PINCTRL \ - (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ - PIN_BASED_EXT_INTR_MASK | \ - PIN_BASED_NMI_EXITING | \ - PIN_BASED_VIRTUAL_NMIS) - -#define EVMCS1_SUPPORTED_EXEC_CTRL \ - (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ - CPU_BASED_HLT_EXITING | \ - CPU_BASED_CR3_LOAD_EXITING | \ - CPU_BASED_CR3_STORE_EXITING | \ - CPU_BASED_UNCOND_IO_EXITING | \ - CPU_BASED_MOV_DR_EXITING | \ - CPU_BASED_USE_TSC_OFFSETTING | \ - CPU_BASED_MWAIT_EXITING | \ - CPU_BASED_MONITOR_EXITING | \ - CPU_BASED_INVLPG_EXITING | \ - CPU_BASED_RDPMC_EXITING | \ - CPU_BASED_INTR_WINDOW_EXITING | \ - CPU_BASED_CR8_LOAD_EXITING | \ - CPU_BASED_CR8_STORE_EXITING | \ - CPU_BASED_RDTSC_EXITING | \ - CPU_BASED_TPR_SHADOW | \ - CPU_BASED_USE_IO_BITMAPS | \ - CPU_BASED_MONITOR_TRAP_FLAG | \ - CPU_BASED_USE_MSR_BITMAPS | \ - CPU_BASED_NMI_WINDOW_EXITING | \ - CPU_BASED_PAUSE_EXITING | \ - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) - -#define EVMCS1_SUPPORTED_2NDEXEC \ - (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ - SECONDARY_EXEC_WBINVD_EXITING | \ - SECONDARY_EXEC_ENABLE_VPID | \ - SECONDARY_EXEC_ENABLE_EPT | \ - SECONDARY_EXEC_UNRESTRICTED_GUEST | \ - SECONDARY_EXEC_DESC | \ - SECONDARY_EXEC_ENABLE_RDTSCP | \ - SECONDARY_EXEC_ENABLE_INVPCID | \ - SECONDARY_EXEC_XSAVES | \ - SECONDARY_EXEC_RDSEED_EXITING | \ - SECONDARY_EXEC_RDRAND_EXITING | \ - SECONDARY_EXEC_TSC_SCALING | \ - SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ - SECONDARY_EXEC_PT_USE_GPA | \ - SECONDARY_EXEC_PT_CONCEAL_VMX | \ - SECONDARY_EXEC_BUS_LOCK_DETECTION | \ - SECONDARY_EXEC_NOTIFY_VM_EXITING | \ - SECONDARY_EXEC_ENCLS_EXITING) - -#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) - -#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ - (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ - VM_EXIT_SAVE_DEBUG_CONTROLS | \ - VM_EXIT_ACK_INTR_ON_EXIT | \ - VM_EXIT_HOST_ADDR_SPACE_SIZE | \ - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ - VM_EXIT_SAVE_IA32_PAT | \ - VM_EXIT_LOAD_IA32_PAT | \ - VM_EXIT_SAVE_IA32_EFER | \ - VM_EXIT_LOAD_IA32_EFER | \ - VM_EXIT_CLEAR_BNDCFGS | \ - VM_EXIT_PT_CONCEAL_PIP | \ - VM_EXIT_CLEAR_IA32_RTIT_CTL) - -#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ - VM_ENTRY_LOAD_DEBUG_CONTROLS | \ - VM_ENTRY_IA32E_MODE | \ - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ - VM_ENTRY_LOAD_IA32_PAT | \ - VM_ENTRY_LOAD_IA32_EFER | \ - VM_ENTRY_LOAD_BNDCFGS | \ - VM_ENTRY_PT_CONCEAL_PIP | \ - VM_ENTRY_LOAD_IA32_RTIT_CTL) - -#define EVMCS1_SUPPORTED_VMFUNC (0) - struct evmcs_field { u16 offset; u16 clean_field; @@ -174,6 +67,13 @@ static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs, #if IS_ENABLED(CONFIG_HYPERV) +DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); + +static __always_inline bool kvm_is_using_evmcs(void) +{ + return static_branch_unlikely(&__kvm_is_using_evmcs); +} + static __always_inline int get_evmcs_offset(unsigned long field, u16 *clean_field) { @@ -263,6 +163,7 @@ static inline void evmcs_load(u64 phys_addr) void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); #else /* !IS_ENABLED(CONFIG_HYPERV) */ +static __always_inline bool kvm_is_using_evmcs(void) { return false; } static __always_inline void evmcs_write64(unsigned long field, u64 value) {} static __always_inline void evmcs_write32(unsigned long field, u32 value) {} static __always_inline void evmcs_write16(unsigned long field, u16 value) {} diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 768487611db7..e35cf0bd0df9 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -358,6 +358,7 @@ static bool nested_ept_root_matches(hpa_t root_hpa, u64 root_eptp, u64 eptp) static void nested_ept_invalidate_addr(struct kvm_vcpu *vcpu, gpa_t eptp, gpa_t addr) { + unsigned long roots = 0; uint i; struct kvm_mmu_root_info *cached_root; @@ -368,8 +369,10 @@ static void nested_ept_invalidate_addr(struct kvm_vcpu *vcpu, gpa_t eptp, if (nested_ept_root_matches(cached_root->hpa, cached_root->pgd, eptp)) - vcpu->arch.mmu->invlpg(vcpu, addr, cached_root->hpa); + roots |= KVM_MMU_ROOT_PREVIOUS(i); } + if (roots) + kvm_mmu_invalidate_addr(vcpu, vcpu->arch.mmu, addr, roots); } static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu, @@ -654,6 +657,9 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, MSR_IA32_PRED_CMD, MSR_TYPE_W); + nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0, + MSR_IA32_FLUSH_CMD, MSR_TYPE_W); + kvm_vcpu_unmap(vcpu, &vmx->nested.msr_bitmap_map, false); vmx->nested.force_msr_bitmap_recalc = false; @@ -4483,7 +4489,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, * CR0_GUEST_HOST_MASK is already set in the original vmcs01 * (KVM doesn't change it); */ - vcpu->arch.cr0_guest_owned_bits = KVM_POSSIBLE_CR0_GUEST_BITS; + vcpu->arch.cr0_guest_owned_bits = vmx_l1_guest_owned_cr0_bits(); vmx_set_cr0(vcpu, vmcs12->host_cr0); /* Same as above - no reason to call set_cr4_guest_host_mask(). */ @@ -4634,7 +4640,7 @@ static void nested_vmx_restore_host_state(struct kvm_vcpu *vcpu) */ vmx_set_efer(vcpu, nested_vmx_get_vmcs01_guest_efer(vmx)); - vcpu->arch.cr0_guest_owned_bits = KVM_POSSIBLE_CR0_GUEST_BITS; + vcpu->arch.cr0_guest_owned_bits = vmx_l1_guest_owned_cr0_bits(); vmx_set_cr0(vcpu, vmcs_readl(CR0_READ_SHADOW)); vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK); @@ -5156,7 +5162,7 @@ static int handle_vmxon(struct kvm_vcpu *vcpu) * does force CR0.PE=1, but only to also force VM86 in order to emulate * Real Mode, and so there's no need to check CR0.PE manually. */ - if (!kvm_read_cr4_bits(vcpu, X86_CR4_VMXE)) { + if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_VMXE)) { kvm_queue_exception(vcpu, UD_VECTOR); return 1; } @@ -6755,36 +6761,9 @@ static u64 nested_vmx_calc_vmcs_enum_msr(void) return (u64)max_idx << VMCS_FIELD_INDEX_SHIFT; } -/* - * nested_vmx_setup_ctls_msrs() sets up variables containing the values to be - * returned for the various VMX controls MSRs when nested VMX is enabled. - * The same values should also be used to verify that vmcs12 control fields are - * valid during nested entry from L1 to L2. - * Each of these control msrs has a low and high 32-bit half: A low bit is on - * if the corresponding bit in the (32-bit) control field *must* be on, and a - * bit in the high half is on if the corresponding bit in the control field - * may be on. See also vmx_control_verify(). - */ -void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) +static void nested_vmx_setup_pinbased_ctls(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) { - struct nested_vmx_msrs *msrs = &vmcs_conf->nested; - - /* - * Note that as a general rule, the high half of the MSRs (bits in - * the control fields which may be 1) should be initialized by the - * intersection of the underlying hardware's MSR (i.e., features which - * can be supported) and the list of features we want to expose - - * because they are known to be properly supported in our code. - * Also, usually, the low half of the MSRs (bits which must be 1) can - * be set to 0, meaning that L1 may turn off any of these bits. The - * reason is that if one of these bits is necessary, it will appear - * in vmcs01 and prepare_vmcs02, when it bitwise-or's the control - * fields of vmcs01 and vmcs02, will turn these bits off - and - * nested_vmx_l1_wants_exit() will not pass related exits to L1. - * These rules have exceptions below. - */ - - /* pin-based controls */ msrs->pinbased_ctls_low = PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR; @@ -6797,8 +6776,11 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) msrs->pinbased_ctls_high |= PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | PIN_BASED_VMX_PREEMPTION_TIMER; +} - /* exit controls */ +static void nested_vmx_setup_exit_ctls(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ msrs->exit_ctls_low = VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR; @@ -6817,8 +6799,11 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) /* We support free control of debug control saving. */ msrs->exit_ctls_low &= ~VM_EXIT_SAVE_DEBUG_CONTROLS; +} - /* entry controls */ +static void nested_vmx_setup_entry_ctls(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ msrs->entry_ctls_low = VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR; @@ -6834,8 +6819,11 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) /* We support free control of debug control loading. */ msrs->entry_ctls_low &= ~VM_ENTRY_LOAD_DEBUG_CONTROLS; +} - /* cpu-based controls */ +static void nested_vmx_setup_cpubased_ctls(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ msrs->procbased_ctls_low = CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR; @@ -6867,12 +6855,12 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) /* We support free control of CR3 access interception. */ msrs->procbased_ctls_low &= ~(CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING); +} - /* - * secondary cpu-based controls. Do not include those that - * depend on CPUID bits, they are added later by - * vmx_vcpu_after_set_cpuid. - */ +static void nested_vmx_setup_secondary_ctls(u32 ept_caps, + struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ msrs->secondary_ctls_low = 0; msrs->secondary_ctls_high = vmcs_conf->cpu_based_2nd_exec_ctrl; @@ -6950,8 +6938,11 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) if (enable_sgx) msrs->secondary_ctls_high |= SECONDARY_EXEC_ENCLS_EXITING; +} - /* miscellaneous data */ +static void nested_vmx_setup_misc_data(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ msrs->misc_low = (u32)vmcs_conf->misc & VMX_MISC_SAVE_EFER_LMA; msrs->misc_low |= MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS | @@ -6959,7 +6950,10 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) VMX_MISC_ACTIVITY_HLT | VMX_MISC_ACTIVITY_WAIT_SIPI; msrs->misc_high = 0; +} +static void nested_vmx_setup_basic(struct nested_vmx_msrs *msrs) +{ /* * This MSR reports some information about VMX support. We * should return information about the VMX we emulate for the @@ -6974,7 +6968,10 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) if (cpu_has_vmx_basic_inout()) msrs->basic |= VMX_BASIC_INOUT; +} +static void nested_vmx_setup_cr_fixed(struct nested_vmx_msrs *msrs) +{ /* * These MSRs specify bits which the guest must keep fixed on * while L1 is in VMXON mode (in L1's root mode, or running an L2). @@ -6991,6 +6988,51 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) if (vmx_umip_emulated()) msrs->cr4_fixed1 |= X86_CR4_UMIP; +} + +/* + * nested_vmx_setup_ctls_msrs() sets up variables containing the values to be + * returned for the various VMX controls MSRs when nested VMX is enabled. + * The same values should also be used to verify that vmcs12 control fields are + * valid during nested entry from L1 to L2. + * Each of these control msrs has a low and high 32-bit half: A low bit is on + * if the corresponding bit in the (32-bit) control field *must* be on, and a + * bit in the high half is on if the corresponding bit in the control field + * may be on. See also vmx_control_verify(). + */ +void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps) +{ + struct nested_vmx_msrs *msrs = &vmcs_conf->nested; + + /* + * Note that as a general rule, the high half of the MSRs (bits in + * the control fields which may be 1) should be initialized by the + * intersection of the underlying hardware's MSR (i.e., features which + * can be supported) and the list of features we want to expose - + * because they are known to be properly supported in our code. + * Also, usually, the low half of the MSRs (bits which must be 1) can + * be set to 0, meaning that L1 may turn off any of these bits. The + * reason is that if one of these bits is necessary, it will appear + * in vmcs01 and prepare_vmcs02, when it bitwise-or's the control + * fields of vmcs01 and vmcs02, will turn these bits off - and + * nested_vmx_l1_wants_exit() will not pass related exits to L1. + * These rules have exceptions below. + */ + nested_vmx_setup_pinbased_ctls(vmcs_conf, msrs); + + nested_vmx_setup_exit_ctls(vmcs_conf, msrs); + + nested_vmx_setup_entry_ctls(vmcs_conf, msrs); + + nested_vmx_setup_cpubased_ctls(vmcs_conf, msrs); + + nested_vmx_setup_secondary_ctls(ept_caps, vmcs_conf, msrs); + + nested_vmx_setup_misc_data(vmcs_conf, msrs); + + nested_vmx_setup_basic(msrs); + + nested_vmx_setup_cr_fixed(msrs); msrs->vmcs_enum = nested_vmx_calc_vmcs_enum_msr(); } diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index e8a3be0b9df9..741efe2c497b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -57,7 +57,7 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); __set_bit(INTEL_PMC_IDX_FIXED + i, pmu->pmc_in_use); - kvm_pmu_request_counter_reprogam(pmc); + kvm_pmu_request_counter_reprogram(pmc); } } @@ -76,13 +76,13 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) static void reprogram_counters(struct kvm_pmu *pmu, u64 diff) { int bit; - struct kvm_pmc *pmc; - for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) { - pmc = intel_pmc_idx_to_pmc(pmu, bit); - if (pmc) - kvm_pmu_request_counter_reprogam(pmc); - } + if (!diff) + return; + + for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) + set_bit(bit, pmu->reprogram_pmi); + kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu)); } static bool intel_hw_event_available(struct kvm_pmc *pmc) @@ -351,45 +351,47 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) switch (msr) { case MSR_CORE_PERF_FIXED_CTR_CTRL: msr_info->data = pmu->fixed_ctr_ctrl; - return 0; + break; case MSR_CORE_PERF_GLOBAL_STATUS: msr_info->data = pmu->global_status; - return 0; + break; case MSR_CORE_PERF_GLOBAL_CTRL: msr_info->data = pmu->global_ctrl; - return 0; + break; case MSR_CORE_PERF_GLOBAL_OVF_CTRL: msr_info->data = 0; - return 0; + break; case MSR_IA32_PEBS_ENABLE: msr_info->data = pmu->pebs_enable; - return 0; + break; case MSR_IA32_DS_AREA: msr_info->data = pmu->ds_area; - return 0; + break; case MSR_PEBS_DATA_CFG: msr_info->data = pmu->pebs_data_cfg; - return 0; + break; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { u64 val = pmc_read_counter(pmc); msr_info->data = val & pmu->counter_bitmask[KVM_PMC_GP]; - return 0; + break; } else if ((pmc = get_fixed_pmc(pmu, msr))) { u64 val = pmc_read_counter(pmc); msr_info->data = val & pmu->counter_bitmask[KVM_PMC_FIXED]; - return 0; + break; } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) { msr_info->data = pmc->eventsel; - return 0; - } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, true)) - return 0; + break; + } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, true)) { + break; + } + return 1; } - return 1; + return 0; } static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) @@ -402,44 +404,43 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) switch (msr) { case MSR_CORE_PERF_FIXED_CTR_CTRL: - if (pmu->fixed_ctr_ctrl == data) - return 0; - if (!(data & pmu->fixed_ctr_ctrl_mask)) { + if (data & pmu->fixed_ctr_ctrl_mask) + return 1; + + if (pmu->fixed_ctr_ctrl != data) reprogram_fixed_counters(pmu, data); - return 0; - } break; case MSR_CORE_PERF_GLOBAL_STATUS: - if (msr_info->host_initiated) { - pmu->global_status = data; - return 0; - } - break; /* RO MSR */ + if (!msr_info->host_initiated) + return 1; /* RO MSR */ + + pmu->global_status = data; + break; case MSR_CORE_PERF_GLOBAL_CTRL: - if (pmu->global_ctrl == data) - return 0; - if (kvm_valid_perf_global_ctrl(pmu, data)) { + if (!kvm_valid_perf_global_ctrl(pmu, data)) + return 1; + + if (pmu->global_ctrl != data) { diff = pmu->global_ctrl ^ data; pmu->global_ctrl = data; reprogram_counters(pmu, diff); - return 0; } break; case MSR_CORE_PERF_GLOBAL_OVF_CTRL: - if (!(data & pmu->global_ovf_ctrl_mask)) { - if (!msr_info->host_initiated) - pmu->global_status &= ~data; - return 0; - } + if (data & pmu->global_ovf_ctrl_mask) + return 1; + + if (!msr_info->host_initiated) + pmu->global_status &= ~data; break; case MSR_IA32_PEBS_ENABLE: - if (pmu->pebs_enable == data) - return 0; - if (!(data & pmu->pebs_enable_mask)) { + if (data & pmu->pebs_enable_mask) + return 1; + + if (pmu->pebs_enable != data) { diff = pmu->pebs_enable ^ data; pmu->pebs_enable = data; reprogram_counters(pmu, diff); - return 0; } break; case MSR_IA32_DS_AREA: @@ -447,15 +448,14 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; if (is_noncanonical_address(data, vcpu)) return 1; + pmu->ds_area = data; - return 0; + break; case MSR_PEBS_DATA_CFG: - if (pmu->pebs_data_cfg == data) - return 0; - if (!(data & pmu->pebs_data_cfg_mask)) { - pmu->pebs_data_cfg = data; - return 0; - } + if (data & pmu->pebs_data_cfg_mask) + return 1; + + pmu->pebs_data_cfg = data; break; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || @@ -463,33 +463,38 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if ((msr & MSR_PMC_FULL_WIDTH_BIT) && (data & ~pmu->counter_bitmask[KVM_PMC_GP])) return 1; + if (!msr_info->host_initiated && !(msr & MSR_PMC_FULL_WIDTH_BIT)) data = (s64)(s32)data; pmc->counter += data - pmc_read_counter(pmc); pmc_update_sample_period(pmc); - return 0; + break; } else if ((pmc = get_fixed_pmc(pmu, msr))) { pmc->counter += data - pmc_read_counter(pmc); pmc_update_sample_period(pmc); - return 0; + break; } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) { - if (data == pmc->eventsel) - return 0; reserved_bits = pmu->reserved_bits; if ((pmc->idx == 2) && (pmu->raw_event_mask & HSW_IN_TX_CHECKPOINTED)) reserved_bits ^= HSW_IN_TX_CHECKPOINTED; - if (!(data & reserved_bits)) { + if (data & reserved_bits) + return 1; + + if (data != pmc->eventsel) { pmc->eventsel = data; - kvm_pmu_request_counter_reprogam(pmc); - return 0; + kvm_pmu_request_counter_reprogram(pmc); } - } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) - return 0; + break; + } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) { + break; + } + /* Not a known PMU MSR. */ + return 1; } - return 1; + return 0; } static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu) @@ -531,6 +536,16 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_enable_mask = ~0ull; pmu->pebs_data_cfg_mask = ~0ull; + memset(&lbr_desc->records, 0, sizeof(lbr_desc->records)); + + /* + * Setting passthrough of LBR MSRs is done only in the VM-Entry loop, + * and PMU refresh is disallowed after the vCPU has run, i.e. this code + * should never be reached while KVM is passing through MSRs. + */ + if (KVM_BUG_ON(lbr_desc->msr_passthrough, vcpu->kvm)) + return; + entry = kvm_find_cpuid_entry(vcpu, 0xa); if (!entry || !vcpu->kvm->arch.enable_pmu) return; diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index aa53c98034bf..2261b684a7d4 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -29,14 +29,14 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset, /* Skip vmcs.GUEST_DS retrieval for 64-bit mode to avoid VMREADs. */ *gva = offset; - if (!is_long_mode(vcpu)) { + if (!is_64_bit_mode(vcpu)) { vmx_get_segment(vcpu, &s, VCPU_SREG_DS); *gva += s.base; } if (!IS_ALIGNED(*gva, alignment)) { fault = true; - } else if (likely(is_long_mode(vcpu))) { + } else if (likely(is_64_bit_mode(vcpu))) { fault = is_noncanonical_address(*gva, vcpu); } else { *gva &= 0xffffffff; @@ -170,12 +170,19 @@ static int __handle_encls_ecreate(struct kvm_vcpu *vcpu, return 1; } - /* Enforce CPUID restrictions on MISCSELECT, ATTRIBUTES and XFRM. */ + /* + * Enforce CPUID restrictions on MISCSELECT, ATTRIBUTES and XFRM. Note + * that the allowed XFRM (XFeature Request Mask) isn't strictly bound + * by the supported XCR0. FP+SSE *must* be set in XFRM, even if XSAVE + * is unsupported, i.e. even if XCR0 itself is completely unsupported. + */ if ((u32)miscselect & ~sgx_12_0->ebx || (u32)attributes & ~sgx_12_1->eax || (u32)(attributes >> 32) & ~sgx_12_1->ebx || (u32)xfrm & ~sgx_12_1->ecx || - (u32)(xfrm >> 32) & ~sgx_12_1->edx) { + (u32)(xfrm >> 32) & ~sgx_12_1->edx || + xfrm & ~(vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE) || + (xfrm & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) { kvm_inject_gp(vcpu, 0); return 1; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index d2d6e1b6c788..44fb619803b8 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -164,6 +164,7 @@ module_param(allow_smaller_maxphyaddr, bool, S_IRUGO); static u32 vmx_possible_passthrough_msrs[MAX_POSSIBLE_PASSTHROUGH_MSRS] = { MSR_IA32_SPEC_CTRL, MSR_IA32_PRED_CMD, + MSR_IA32_FLUSH_CMD, MSR_IA32_TSC, #ifdef CONFIG_X86_64 MSR_FS_BASE, @@ -579,7 +580,7 @@ static __init void hv_init_evmcs(void) if (enlightened_vmcs) { pr_info("Using Hyper-V Enlightened VMCS\n"); - static_branch_enable(&enable_evmcs); + static_branch_enable(&__kvm_is_using_evmcs); } if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) @@ -595,7 +596,7 @@ static void hv_reset_evmcs(void) { struct hv_vp_assist_page *vp_ap; - if (!static_branch_unlikely(&enable_evmcs)) + if (!kvm_is_using_evmcs()) return; /* @@ -1945,7 +1946,7 @@ static inline bool is_vmx_feature_control_msr_valid(struct vcpu_vmx *vmx, static int vmx_get_msr_feature(struct kvm_msr_entry *msr) { switch (msr->index) { - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: if (!nested) return 1; return vmx_get_vmx_msr(&vmcs_config.nested, msr->index, &msr->data); @@ -2030,7 +2031,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = to_vmx(vcpu)->msr_ia32_sgxlepubkeyhash [msr_info->index - MSR_IA32_SGXLEPUBKEYHASH0]; break; - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: if (!nested_vmx_allowed(vcpu)) return 1; if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index, @@ -2285,33 +2286,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (data & ~(TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR)) return 1; goto find_uret_msr; - case MSR_IA32_PRED_CMD: - if (!msr_info->host_initiated && - !guest_has_pred_cmd_msr(vcpu)) - return 1; - - if (data & ~PRED_CMD_IBPB) - return 1; - if (!boot_cpu_has(X86_FEATURE_IBPB)) - return 1; - if (!data) - break; - - wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); - - /* - * For non-nested: - * When it's written (to non-zero) for the first time, pass - * it through. - * - * For nested: - * The handling of the MSR bitmap for L2 guests is done in - * nested_vmx_prepare_msr_bitmap. We should not touch the - * vmcs02.msr_bitmap here since it gets completely overwritten - * in the merging. - */ - vmx_disable_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W); - break; case MSR_IA32_CR_PAT: if (!kvm_pat_valid(data)) return 1; @@ -2366,7 +2340,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vmx->msr_ia32_sgxlepubkeyhash [msr_index - MSR_IA32_SGXLEPUBKEYHASH0] = data; break; - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: if (!msr_info->host_initiated) return 1; /* they are read-only */ if (!nested_vmx_allowed(vcpu)) @@ -2816,8 +2790,7 @@ static int vmx_hardware_enable(void) * This can happen if we hot-added a CPU but failed to allocate * VP assist page for it. */ - if (static_branch_unlikely(&enable_evmcs) && - !hv_get_vp_assist_page(cpu)) + if (kvm_is_using_evmcs() && !hv_get_vp_assist_page(cpu)) return -EFAULT; intel_pt_handle_vmx(1); @@ -2869,7 +2842,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags) memset(vmcs, 0, vmcs_config.size); /* KVM supports Enlightened VMCS v1 only */ - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) vmcs->hdr.revision_id = KVM_EVMCS_VERSION; else vmcs->hdr.revision_id = vmcs_config.revision_id; @@ -2964,7 +2937,7 @@ static __init int alloc_kvm_area(void) * still be marked with revision_id reported by * physical CPU. */ - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) vmcs->hdr.revision_id = vmcs_config.revision_id; per_cpu(vmxarea, cpu) = vmcs; @@ -3931,7 +3904,7 @@ static void vmx_msr_bitmap_l01_changed(struct vcpu_vmx *vmx) * 'Enlightened MSR Bitmap' feature L0 needs to know that MSR * bitmap has changed. */ - if (IS_ENABLED(CONFIG_HYPERV) && static_branch_unlikely(&enable_evmcs)) { + if (kvm_is_using_evmcs()) { struct hv_enlightened_vmcs *evmcs = (void *)vmx->vmcs01.vmcs; if (evmcs->hv_enlightenments_control.msr_bitmap) @@ -4773,7 +4746,7 @@ static void init_vmcs(struct vcpu_vmx *vmx) /* 22.2.1, 20.8.1 */ vm_entry_controls_set(vmx, vmx_vmentry_ctrl()); - vmx->vcpu.arch.cr0_guest_owned_bits = KVM_POSSIBLE_CR0_GUEST_BITS; + vmx->vcpu.arch.cr0_guest_owned_bits = vmx_l1_guest_owned_cr0_bits(); vmcs_writel(CR0_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr0_guest_owned_bits); set_cr4_guest_host_mask(vmx); @@ -5163,7 +5136,7 @@ bool vmx_guest_inject_ac(struct kvm_vcpu *vcpu) if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) return true; - return vmx_get_cpl(vcpu) == 3 && kvm_read_cr0_bits(vcpu, X86_CR0_AM) && + return vmx_get_cpl(vcpu) == 3 && kvm_is_cr0_bit_set(vcpu, X86_CR0_AM) && (kvm_get_rflags(vcpu) & X86_EFLAGS_AC); } @@ -5500,7 +5473,7 @@ static int handle_cr(struct kvm_vcpu *vcpu) break; case 3: /* lmsw */ val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f; - trace_kvm_cr_write(0, (kvm_read_cr0(vcpu) & ~0xful) | val); + trace_kvm_cr_write(0, (kvm_read_cr0_bits(vcpu, ~0xful) | val)); kvm_lmsw(vcpu, val); return kvm_skip_emulated_instruction(vcpu); @@ -6957,7 +6930,7 @@ static bool vmx_has_emulated_msr(struct kvm *kvm, u32 index) * real mode. */ return enable_unrestricted_guest || emulate_invalid_guest_state; - case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: return nested; case MSR_AMD64_VIRT_SPEC_CTRL: case MSR_AMD64_TSC_RATIO: @@ -7310,7 +7283,7 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx_vcpu_enter_exit(vcpu, __vmx_vcpu_run_flags(vmx)); /* All fields are clean at this point */ - if (static_branch_unlikely(&enable_evmcs)) { + if (kvm_is_using_evmcs()) { current_evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL; @@ -7440,7 +7413,7 @@ static int vmx_vcpu_create(struct kvm_vcpu *vcpu) * feature only for vmcs01, KVM currently isn't equipped to realize any * performance benefits from enabling it for vmcs02. */ - if (IS_ENABLED(CONFIG_HYPERV) && static_branch_unlikely(&enable_evmcs) && + if (kvm_is_using_evmcs() && (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)) { struct hv_enlightened_vmcs *evmcs = (void *)vmx->vmcs01.vmcs; @@ -7558,7 +7531,7 @@ static u8 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) if (!kvm_arch_has_noncoherent_dma(vcpu->kvm)) return (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT) | VMX_EPT_IPAT_BIT; - if (kvm_read_cr0(vcpu) & X86_CR0_CD) { + if (kvm_read_cr0_bits(vcpu, X86_CR0_CD)) { if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED)) cache = MTRR_TYPE_WRBACK; else @@ -7744,6 +7717,13 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vmx_set_intercept_for_msr(vcpu, MSR_IA32_XFD_ERR, MSR_TYPE_R, !guest_cpuid_has(vcpu, X86_FEATURE_XFD)); + if (boot_cpu_has(X86_FEATURE_IBPB)) + vmx_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W, + !guest_has_pred_cmd_msr(vcpu)); + + if (boot_cpu_has(X86_FEATURE_FLUSH_L1D)) + vmx_set_intercept_for_msr(vcpu, MSR_IA32_FLUSH_CMD, MSR_TYPE_W, + !guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D)); set_cr4_guest_host_mask(vmx); @@ -7776,9 +7756,11 @@ static u64 vmx_get_perf_capabilities(void) if (boot_cpu_has(X86_FEATURE_PDCM)) rdmsrl(MSR_IA32_PERF_CAPABILITIES, host_perf_cap); - x86_perf_get_lbr(&lbr); - if (lbr.nr) - perf_cap |= host_perf_cap & PMU_CAP_LBR_FMT; + if (!cpu_feature_enabled(X86_FEATURE_ARCH_LBR)) { + x86_perf_get_lbr(&lbr); + if (lbr.nr) + perf_cap |= host_perf_cap & PMU_CAP_LBR_FMT; + } if (vmx_pebs_supported()) { perf_cap |= host_perf_cap & PERF_CAP_PEBS_MASK; @@ -7918,6 +7900,21 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu, /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED. */ break; + case x86_intercept_pause: + /* + * PAUSE is a single-byte NOP with a REPE prefix, i.e. collides + * with vanilla NOPs in the emulator. Apply the interception + * check only to actual PAUSE instructions. Don't check + * PAUSE-loop-exiting, software can't expect a given PAUSE to + * exit, i.e. KVM is within its rights to allow L2 to execute + * the PAUSE. + */ + if ((info->rep_prefix != REPE_PREFIX) || + !nested_cpu_has2(vmcs12, CPU_BASED_PAUSE_EXITING)) + return X86EMUL_CONTINUE; + + break; + /* TODO: check more intercepts... */ default: break; @@ -8415,9 +8412,8 @@ static __init int hardware_setup(void) #if IS_ENABLED(CONFIG_HYPERV) if (ms_hyperv.nested_features & HV_X64_NESTED_GUEST_MAPPING_FLUSH && enable_ept) { - vmx_x86_ops.tlb_remote_flush = hv_remote_flush_tlb; - vmx_x86_ops.tlb_remote_flush_with_range = - hv_remote_flush_tlb_with_range; + vmx_x86_ops.flush_remote_tlbs = hv_flush_remote_tlbs; + vmx_x86_ops.flush_remote_tlbs_range = hv_flush_remote_tlbs_range; } #endif diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 2acdc54bc34b..9e66531861cf 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -369,7 +369,7 @@ struct vcpu_vmx { struct lbr_desc lbr_desc; /* Save desired MSR intercept (read: pass-through) state */ -#define MAX_POSSIBLE_PASSTHROUGH_MSRS 15 +#define MAX_POSSIBLE_PASSTHROUGH_MSRS 16 struct { DECLARE_BITMAP(read, MAX_POSSIBLE_PASSTHROUGH_MSRS); DECLARE_BITMAP(write, MAX_POSSIBLE_PASSTHROUGH_MSRS); @@ -640,6 +640,24 @@ BUILD_CONTROLS_SHADOW(tertiary_exec, TERTIARY_VM_EXEC_CONTROL, 64) (1 << VCPU_EXREG_EXIT_INFO_1) | \ (1 << VCPU_EXREG_EXIT_INFO_2)) +static inline unsigned long vmx_l1_guest_owned_cr0_bits(void) +{ + unsigned long bits = KVM_POSSIBLE_CR0_GUEST_BITS; + + /* + * CR0.WP needs to be intercepted when KVM is shadowing legacy paging + * in order to construct shadow PTEs with the correct protections. + * Note! CR0.WP technically can be passed through to the guest if + * paging is disabled, but checking CR0.PG would generate a cyclical + * dependency of sorts due to forcing the caller to ensure CR0 holds + * the correct value prior to determining which CR0 bits can be owned + * by L1. Keep it simple and limit the optimization to EPT. + */ + if (!enable_ept) + bits &= ~X86_CR0_WP; + return bits; +} + static __always_inline struct kvm_vmx *to_kvm_vmx(struct kvm *kvm) { return container_of(kvm, struct kvm_vmx, kvm); diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h index db95bde52998..ce47dc265f89 100644 --- a/arch/x86/kvm/vmx/vmx_ops.h +++ b/arch/x86/kvm/vmx/vmx_ops.h @@ -147,7 +147,7 @@ do_exception: static __always_inline u16 vmcs_read16(unsigned long field) { vmcs_check16(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_read16(field); return __vmcs_readl(field); } @@ -155,7 +155,7 @@ static __always_inline u16 vmcs_read16(unsigned long field) static __always_inline u32 vmcs_read32(unsigned long field) { vmcs_check32(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_read32(field); return __vmcs_readl(field); } @@ -163,7 +163,7 @@ static __always_inline u32 vmcs_read32(unsigned long field) static __always_inline u64 vmcs_read64(unsigned long field) { vmcs_check64(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_read64(field); #ifdef CONFIG_X86_64 return __vmcs_readl(field); @@ -175,7 +175,7 @@ static __always_inline u64 vmcs_read64(unsigned long field) static __always_inline unsigned long vmcs_readl(unsigned long field) { vmcs_checkl(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_read64(field); return __vmcs_readl(field); } @@ -222,7 +222,7 @@ static __always_inline void __vmcs_writel(unsigned long field, unsigned long val static __always_inline void vmcs_write16(unsigned long field, u16 value) { vmcs_check16(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write16(field, value); __vmcs_writel(field, value); @@ -231,7 +231,7 @@ static __always_inline void vmcs_write16(unsigned long field, u16 value) static __always_inline void vmcs_write32(unsigned long field, u32 value) { vmcs_check32(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write32(field, value); __vmcs_writel(field, value); @@ -240,7 +240,7 @@ static __always_inline void vmcs_write32(unsigned long field, u32 value) static __always_inline void vmcs_write64(unsigned long field, u64 value) { vmcs_check64(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write64(field, value); __vmcs_writel(field, value); @@ -252,7 +252,7 @@ static __always_inline void vmcs_write64(unsigned long field, u64 value) static __always_inline void vmcs_writel(unsigned long field, unsigned long value) { vmcs_checkl(field); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write64(field, value); __vmcs_writel(field, value); @@ -262,7 +262,7 @@ static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask) { BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000, "vmcs_clear_bits does not support 64-bit fields"); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write32(field, evmcs_read32(field) & ~mask); __vmcs_writel(field, __vmcs_readl(field) & ~mask); @@ -272,7 +272,7 @@ static __always_inline void vmcs_set_bits(unsigned long field, u32 mask) { BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000, "vmcs_set_bits does not support 64-bit fields"); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_write32(field, evmcs_read32(field) | mask); __vmcs_writel(field, __vmcs_readl(field) | mask); @@ -289,7 +289,7 @@ static inline void vmcs_load(struct vmcs *vmcs) { u64 phys_addr = __pa(vmcs); - if (static_branch_unlikely(&enable_evmcs)) + if (kvm_is_using_evmcs()) return evmcs_load(phys_addr); vmx_asm1(vmptrld, "m"(phys_addr), vmcs, phys_addr); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3d852ce84920..04b57a336b34 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -60,7 +60,9 @@ #include #include #include +#include +#include #include #include @@ -194,7 +196,7 @@ bool __read_mostly eager_page_split = true; module_param(eager_page_split, bool, 0644); /* Enable/disable SMT_RSB bug mitigation */ -bool __read_mostly mitigate_smt_rsb; +static bool __read_mostly mitigate_smt_rsb; module_param(mitigate_smt_rsb, bool, 0444); /* @@ -802,8 +804,8 @@ void kvm_inject_emulated_page_fault(struct kvm_vcpu *vcpu, */ if ((fault->error_code & PFERR_PRESENT_MASK) && !(fault->error_code & PFERR_RSVD_MASK)) - kvm_mmu_invalidate_gva(vcpu, fault_mmu, fault->address, - fault_mmu->root.hpa); + kvm_mmu_invalidate_addr(vcpu, fault_mmu, fault->address, + KVM_MMU_ROOT_CURRENT); fault_mmu->inject_page_fault(vcpu, fault); } @@ -841,7 +843,7 @@ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl) bool kvm_require_dr(struct kvm_vcpu *vcpu, int dr) { - if ((dr != 4 && dr != 5) || !kvm_read_cr4_bits(vcpu, X86_CR4_DE)) + if ((dr != 4 && dr != 5) || !kvm_is_cr4_bit_set(vcpu, X86_CR4_DE)) return true; kvm_queue_exception(vcpu, UD_VECTOR); @@ -906,6 +908,24 @@ EXPORT_SYMBOL_GPL(load_pdptrs); void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0) { + /* + * CR0.WP is incorporated into the MMU role, but only for non-nested, + * indirect shadow MMUs. If paging is disabled, no updates are needed + * as there are no permission bits to emulate. If TDP is enabled, the + * MMU's metadata needs to be updated, e.g. so that emulating guest + * translations does the right thing, but there's no need to unload the + * root as CR0.WP doesn't affect SPTEs. + */ + if ((cr0 ^ old_cr0) == X86_CR0_WP) { + if (!(cr0 & X86_CR0_PG)) + return; + + if (tdp_enabled) { + kvm_init_mmu(vcpu); + return; + } + } + if ((cr0 ^ old_cr0) & X86_CR0_PG) { kvm_clear_async_pf_completion_queue(vcpu); kvm_async_pf_hash_reset(vcpu); @@ -965,7 +985,7 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) return 1; if (!(cr0 & X86_CR0_PG) && - (is_64_bit_mode(vcpu) || kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE))) + (is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE))) return 1; static_call(kvm_x86_set_cr0)(vcpu, cr0); @@ -987,7 +1007,7 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) if (vcpu->arch.guest_state_protected) return; - if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE)) { + if (kvm_is_cr4_bit_set(vcpu, X86_CR4_OSXSAVE)) { if (vcpu->arch.xcr0 != host_xcr0) xsetbv(XCR_XFEATURE_ENABLED_MASK, vcpu->arch.xcr0); @@ -1001,7 +1021,7 @@ void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu) if (static_cpu_has(X86_FEATURE_PKU) && vcpu->arch.pkru != vcpu->arch.host_pkru && ((vcpu->arch.xcr0 & XFEATURE_MASK_PKRU) || - kvm_read_cr4_bits(vcpu, X86_CR4_PKE))) + kvm_is_cr4_bit_set(vcpu, X86_CR4_PKE))) write_pkru(vcpu->arch.pkru); #endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ } @@ -1015,14 +1035,14 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu) #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS if (static_cpu_has(X86_FEATURE_PKU) && ((vcpu->arch.xcr0 & XFEATURE_MASK_PKRU) || - kvm_read_cr4_bits(vcpu, X86_CR4_PKE))) { + kvm_is_cr4_bit_set(vcpu, X86_CR4_PKE))) { vcpu->arch.pkru = rdpkru(); if (vcpu->arch.pkru != vcpu->arch.host_pkru) write_pkru(vcpu->arch.host_pkru); } #endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ - if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE)) { + if (kvm_is_cr4_bit_set(vcpu, X86_CR4_OSXSAVE)) { if (vcpu->arch.xcr0 != host_xcr0) xsetbv(XCR_XFEATURE_ENABLED_MASK, host_xcr0); @@ -1178,9 +1198,6 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) return 1; if ((cr4 & X86_CR4_PCIDE) && !(old_cr4 & X86_CR4_PCIDE)) { - if (!guest_cpuid_has(vcpu, X86_FEATURE_PCID)) - return 1; - /* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */ if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_MASK) || !is_long_mode(vcpu)) return 1; @@ -1227,7 +1244,7 @@ static void kvm_invalidate_pcid(struct kvm_vcpu *vcpu, unsigned long pcid) * PCIDs for them are also 0, because MOV to CR3 always flushes the TLB * with PCIDE=0. */ - if (!kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE)) + if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)) return; for (i = 0; i < KVM_MMU_NUM_PREV_ROOTS; i++) @@ -1242,9 +1259,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) bool skip_tlb_flush = false; unsigned long pcid = 0; #ifdef CONFIG_X86_64 - bool pcid_enabled = kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE); - - if (pcid_enabled) { + if (kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)) { skip_tlb_flush = cr3 & X86_CR3_PCID_NOFLUSH; cr3 &= ~X86_CR3_PCID_NOFLUSH; pcid = cr3 & X86_CR3_PCID_MASK; @@ -1431,7 +1446,7 @@ static const u32 msrs_to_save_base[] = { #endif MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA, MSR_IA32_FEAT_CTL, MSR_IA32_BNDCFGS, MSR_TSC_AUX, - MSR_IA32_SPEC_CTRL, + MSR_IA32_SPEC_CTRL, MSR_IA32_TSX_CTRL, MSR_IA32_RTIT_CTL, MSR_IA32_RTIT_STATUS, MSR_IA32_RTIT_CR3_MATCH, MSR_IA32_RTIT_OUTPUT_BASE, MSR_IA32_RTIT_OUTPUT_MASK, MSR_IA32_RTIT_ADDR0_A, MSR_IA32_RTIT_ADDR0_B, @@ -1543,38 +1558,40 @@ static u32 emulated_msrs[ARRAY_SIZE(emulated_msrs_all)]; static unsigned num_emulated_msrs; /* - * List of msr numbers which are used to expose MSR-based features that - * can be used by a hypervisor to validate requested CPU features. + * List of MSRs that control the existence of MSR-based features, i.e. MSRs + * that are effectively CPUID leafs. VMX MSRs are also included in the set of + * feature MSRs, but are handled separately to allow expedited lookups. */ -static const u32 msr_based_features_all[] = { - MSR_IA32_VMX_BASIC, - MSR_IA32_VMX_TRUE_PINBASED_CTLS, - MSR_IA32_VMX_PINBASED_CTLS, - MSR_IA32_VMX_TRUE_PROCBASED_CTLS, - MSR_IA32_VMX_PROCBASED_CTLS, - MSR_IA32_VMX_TRUE_EXIT_CTLS, - MSR_IA32_VMX_EXIT_CTLS, - MSR_IA32_VMX_TRUE_ENTRY_CTLS, - MSR_IA32_VMX_ENTRY_CTLS, - MSR_IA32_VMX_MISC, - MSR_IA32_VMX_CR0_FIXED0, - MSR_IA32_VMX_CR0_FIXED1, - MSR_IA32_VMX_CR4_FIXED0, - MSR_IA32_VMX_CR4_FIXED1, - MSR_IA32_VMX_VMCS_ENUM, - MSR_IA32_VMX_PROCBASED_CTLS2, - MSR_IA32_VMX_EPT_VPID_CAP, - MSR_IA32_VMX_VMFUNC, - +static const u32 msr_based_features_all_except_vmx[] = { MSR_AMD64_DE_CFG, MSR_IA32_UCODE_REV, MSR_IA32_ARCH_CAPABILITIES, MSR_IA32_PERF_CAPABILITIES, }; -static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all)]; +static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + + (KVM_LAST_EMULATED_VMX_MSR - KVM_FIRST_EMULATED_VMX_MSR + 1)]; static unsigned int num_msr_based_features; +/* + * All feature MSRs except uCode revID, which tracks the currently loaded uCode + * patch, are immutable once the vCPU model is defined. + */ +static bool kvm_is_immutable_feature_msr(u32 msr) +{ + int i; + + if (msr >= KVM_FIRST_EMULATED_VMX_MSR && msr <= KVM_LAST_EMULATED_VMX_MSR) + return true; + + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) { + if (msr == msr_based_features_all_except_vmx[i]) + return msr != MSR_IA32_UCODE_REV; + } + + return false; +} + /* * Some IA32_ARCH_CAPABILITIES bits have dependencies on MSRs that KVM * does not yet virtualize. These include: @@ -2192,6 +2209,22 @@ static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) { + u64 val; + + /* + * Disallow writes to immutable feature MSRs after KVM_RUN. KVM does + * not support modifying the guest vCPU model on the fly, e.g. changing + * the nVMX capabilities while L2 is running is nonsensical. Ignore + * writes of the same value, e.g. to allow userspace to blindly stuff + * all MSRs when emulating RESET. + */ + if (kvm_vcpu_has_run(vcpu) && kvm_is_immutable_feature_msr(index)) { + if (do_get_msr(vcpu, index, &val) || *data != val) + return -EINVAL; + + return 0; + } + return kvm_set_msr_ignored_check(vcpu, index, *data, true); } @@ -3614,9 +3647,40 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (data & ~kvm_caps.supported_perf_cap) return 1; + /* + * Note, this is not just a performance optimization! KVM + * disallows changing feature MSRs after the vCPU has run; PMU + * refresh will bug the VM if called after the vCPU has run. + */ + if (vcpu->arch.perf_capabilities == data) + break; + vcpu->arch.perf_capabilities = data; kvm_pmu_refresh(vcpu); - return 0; + break; + case MSR_IA32_PRED_CMD: + if (!msr_info->host_initiated && !guest_has_pred_cmd_msr(vcpu)) + return 1; + + if (!boot_cpu_has(X86_FEATURE_IBPB) || (data & ~PRED_CMD_IBPB)) + return 1; + if (!data) + break; + + wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); + break; + case MSR_IA32_FLUSH_CMD: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D)) + return 1; + + if (!boot_cpu_has(X86_FEATURE_FLUSH_L1D) || (data & ~L1D_FLUSH)) + return 1; + if (!data) + break; + + wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH); + break; case MSR_EFER: return set_efer(vcpu, msr_info); case MSR_K7_HWCR: @@ -4532,9 +4596,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = 0; break; case KVM_CAP_XSAVE2: { - u64 guest_perm = xstate_get_guest_group_perm(); - - r = xstate_required_size(kvm_caps.supported_xcr0 & guest_perm, false); + r = xstate_required_size(kvm_get_filtered_xcr0(), false); if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; @@ -5034,7 +5096,7 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, return 0; if (mce->status & MCI_STATUS_UC) { if ((vcpu->arch.mcg_status & MCG_STATUS_MCIP) || - !kvm_read_cr4_bits(vcpu, X86_CR4_MCE)) { + !kvm_is_cr4_bit_set(vcpu, X86_CR4_MCE)) { kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); return 0; } @@ -5126,7 +5188,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->interrupt.shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu); events->nmi.injected = vcpu->arch.nmi_injected; - events->nmi.pending = vcpu->arch.nmi_pending != 0; + events->nmi.pending = kvm_get_nr_pending_nmis(vcpu); events->nmi.masked = static_call(kvm_x86_get_nmi_mask)(vcpu); /* events->sipi_vector is never valid when reporting to user space */ @@ -5213,8 +5275,11 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, events->interrupt.shadow); vcpu->arch.nmi_injected = events->nmi.injected; - if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) - vcpu->arch.nmi_pending = events->nmi.pending; + if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING) { + vcpu->arch.nmi_pending = 0; + atomic_set(&vcpu->arch.nmi_queued, events->nmi.pending); + kvm_make_request(KVM_REQ_NMI, vcpu); + } static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked); if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR && @@ -6022,11 +6087,6 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm, return 0; } -static unsigned long kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm) -{ - return kvm->arch.n_max_mmu_pages; -} - static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) { struct kvm_pic *pic = kvm->arch.vpic; @@ -6673,8 +6733,7 @@ static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp) return 0; } -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; void __user *argp = (void __user *)arg; @@ -6712,9 +6771,6 @@ set_identity_unlock: case KVM_SET_NR_MMU_PAGES: r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg); break; - case KVM_GET_NR_MMU_PAGES: - r = kvm_vm_ioctl_get_nr_mmu_pages(kvm); - break; case KVM_CREATE_IRQCHIP: { mutex_lock(&kvm->lock); @@ -7019,6 +7075,18 @@ out: return r; } +static void kvm_probe_feature_msr(u32 msr_index) +{ + struct kvm_msr_entry msr = { + .index = msr_index, + }; + + if (kvm_get_msr_feature(&msr)) + return; + + msr_based_features[num_msr_based_features++] = msr_index; +} + static void kvm_probe_msr_to_save(u32 msr_index) { u32 dummy[2]; @@ -7087,6 +7155,10 @@ static void kvm_probe_msr_to_save(u32 msr_index) if (!kvm_cpu_cap_has(X86_FEATURE_XFD)) return; break; + case MSR_IA32_TSX_CTRL: + if (!(kvm_get_arch_capabilities() & ARCH_CAP_TSX_CTRL_MSR)) + return; + break; default: break; } @@ -7094,7 +7166,7 @@ static void kvm_probe_msr_to_save(u32 msr_index) msrs_to_save[num_msrs_to_save++] = msr_index; } -static void kvm_init_msr_list(void) +static void kvm_init_msr_lists(void) { unsigned i; @@ -7120,15 +7192,11 @@ static void kvm_init_msr_list(void) emulated_msrs[num_emulated_msrs++] = emulated_msrs_all[i]; } - for (i = 0; i < ARRAY_SIZE(msr_based_features_all); i++) { - struct kvm_msr_entry msr; + for (i = KVM_FIRST_EMULATED_VMX_MSR; i <= KVM_LAST_EMULATED_VMX_MSR; i++) + kvm_probe_feature_msr(i); - msr.index = msr_based_features_all[i]; - if (kvm_get_msr_feature(&msr)) - continue; - - msr_based_features[num_msr_based_features++] = msr_based_features_all[i]; - } + for (i = 0; i < ARRAY_SIZE(msr_based_features_all_except_vmx); i++) + kvm_probe_feature_msr(msr_based_features_all_except_vmx[i]); } static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len, @@ -8464,7 +8532,6 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu, int emulation_type) } static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, - bool write_fault_to_shadow_pgtable, int emulation_type) { gpa_t gpa = cr2_or_gpa; @@ -8535,7 +8602,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, * be fixed by unprotecting shadow page and it should * be reported to userspace. */ - return !write_fault_to_shadow_pgtable; + return !(emulation_type & EMULTYPE_WRITE_PF_TO_SP); } static bool retry_instruction(struct x86_emulate_ctxt *ctxt, @@ -8783,20 +8850,12 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int r; struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt; bool writeback = true; - bool write_fault_to_spt; if (unlikely(!kvm_can_emulate_insn(vcpu, emulation_type, insn, insn_len))) return 1; vcpu->arch.l1tf_flush_l1d = true; - /* - * Clear write_fault_to_shadow_pgtable here to ensure it is - * never reused. - */ - write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable; - vcpu->arch.write_fault_to_shadow_pgtable = false; - if (!(emulation_type & EMULTYPE_NO_DECODE)) { kvm_clear_exception_queue(vcpu); @@ -8817,7 +8876,6 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, return 1; } if (reexecute_instruction(vcpu, cr2_or_gpa, - write_fault_to_spt, emulation_type)) return 1; @@ -8896,8 +8954,7 @@ restart: return 1; if (r == EMULATION_FAILED) { - if (reexecute_instruction(vcpu, cr2_or_gpa, write_fault_to_spt, - emulation_type)) + if (reexecute_instruction(vcpu, cr2_or_gpa, emulation_type)) return 1; return handle_emulation_failure(vcpu, emulation_type); @@ -9475,7 +9532,7 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) kvm_caps.max_guest_tsc_khz = max; } kvm_caps.default_tsc_scaling_ratio = 1ULL << kvm_caps.tsc_scaling_ratio_frac_bits; - kvm_init_msr_list(); + kvm_init_msr_lists(); return 0; out_unwind_ops: @@ -9806,7 +9863,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) vcpu->run->hypercall.args[0] = gpa; vcpu->run->hypercall.args[1] = npages; vcpu->run->hypercall.args[2] = attrs; - vcpu->run->hypercall.longmode = op_64_bit; + vcpu->run->hypercall.flags = 0; + if (op_64_bit) + vcpu->run->hypercall.flags |= KVM_EXIT_HYPERCALL_LONG_MODE; + + WARN_ON_ONCE(vcpu->run->hypercall.flags & KVM_EXIT_HYPERCALL_MBZ); vcpu->arch.complete_userspace_io = complete_hypercall_exit; return 0; } @@ -10168,19 +10229,46 @@ out: static void process_nmi(struct kvm_vcpu *vcpu) { - unsigned limit = 2; + unsigned int limit; /* - * x86 is limited to one NMI running, and one NMI pending after it. - * If an NMI is already in progress, limit further NMIs to just one. - * Otherwise, allow two (and we'll inject the first one immediately). + * x86 is limited to one NMI pending, but because KVM can't react to + * incoming NMIs as quickly as bare metal, e.g. if the vCPU is + * scheduled out, KVM needs to play nice with two queued NMIs showing + * up at the same time. To handle this scenario, allow two NMIs to be + * (temporarily) pending so long as NMIs are not blocked and KVM is not + * waiting for a previous NMI injection to complete (which effectively + * blocks NMIs). KVM will immediately inject one of the two NMIs, and + * will request an NMI window to handle the second NMI. */ if (static_call(kvm_x86_get_nmi_mask)(vcpu) || vcpu->arch.nmi_injected) limit = 1; + else + limit = 2; + + /* + * Adjust the limit to account for pending virtual NMIs, which aren't + * tracked in vcpu->arch.nmi_pending. + */ + if (static_call(kvm_x86_is_vnmi_pending)(vcpu)) + limit--; vcpu->arch.nmi_pending += atomic_xchg(&vcpu->arch.nmi_queued, 0); vcpu->arch.nmi_pending = min(vcpu->arch.nmi_pending, limit); - kvm_make_request(KVM_REQ_EVENT, vcpu); + + if (vcpu->arch.nmi_pending && + (static_call(kvm_x86_set_vnmi_pending)(vcpu))) + vcpu->arch.nmi_pending--; + + if (vcpu->arch.nmi_pending) + kvm_make_request(KVM_REQ_EVENT, vcpu); +} + +/* Return total number of NMIs pending injection to the VM */ +int kvm_get_nr_pending_nmis(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.nmi_pending + + static_call(kvm_x86_is_vnmi_pending)(vcpu); } void kvm_make_scan_ioapic_request_mask(struct kvm *kvm, @@ -10670,6 +10758,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED; break; } + + /* Note, VM-Exits that go down the "slow" path are accounted below. */ + ++vcpu->stat.exits; } /* @@ -13266,7 +13357,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva) return 1; } - pcid_enabled = kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE); + pcid_enabled = kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE); switch (type) { case INVPCID_TYPE_INDIV_ADDR: diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index a8167b47b8c8..c544602d07a3 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -3,6 +3,7 @@ #define ARCH_X86_KVM_X86_H #include +#include #include #include #include "kvm_cache_regs.h" @@ -40,6 +41,14 @@ void kvm_spurious_fault(void); failed; \ }) +/* + * The first...last VMX feature MSRs that are emulated by KVM. This may or may + * not cover all known VMX MSRs, as KVM doesn't emulate an MSR until there's an + * associated feature that KVM supports for nested virtualization. + */ +#define KVM_FIRST_EMULATED_VMX_MSR MSR_IA32_VMX_BASIC +#define KVM_LAST_EMULATED_VMX_MSR MSR_IA32_VMX_VMFUNC + #define KVM_DEFAULT_PLE_GAP 128 #define KVM_VMX_DEFAULT_PLE_WINDOW 4096 #define KVM_DEFAULT_PLE_WINDOW_GROW 2 @@ -83,6 +92,11 @@ static inline unsigned int __shrink_ple_window(unsigned int val, void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu); int kvm_check_nested_events(struct kvm_vcpu *vcpu); +static inline bool kvm_vcpu_has_run(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.last_vmentry_cpu != -1; +} + static inline bool kvm_is_exception_pending(struct kvm_vcpu *vcpu) { return vcpu->arch.exception.pending || @@ -123,15 +137,15 @@ static inline bool kvm_exception_is_soft(unsigned int nr) static inline bool is_protmode(struct kvm_vcpu *vcpu) { - return kvm_read_cr0_bits(vcpu, X86_CR0_PE); + return kvm_is_cr0_bit_set(vcpu, X86_CR0_PE); } -static inline int is_long_mode(struct kvm_vcpu *vcpu) +static inline bool is_long_mode(struct kvm_vcpu *vcpu) { #ifdef CONFIG_X86_64 - return vcpu->arch.efer & EFER_LMA; + return !!(vcpu->arch.efer & EFER_LMA); #else - return 0; + return false; #endif } @@ -171,19 +185,19 @@ static inline bool mmu_is_nested(struct kvm_vcpu *vcpu) return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu; } -static inline int is_pae(struct kvm_vcpu *vcpu) +static inline bool is_pae(struct kvm_vcpu *vcpu) { - return kvm_read_cr4_bits(vcpu, X86_CR4_PAE); + return kvm_is_cr4_bit_set(vcpu, X86_CR4_PAE); } -static inline int is_pse(struct kvm_vcpu *vcpu) +static inline bool is_pse(struct kvm_vcpu *vcpu) { - return kvm_read_cr4_bits(vcpu, X86_CR4_PSE); + return kvm_is_cr4_bit_set(vcpu, X86_CR4_PSE); } -static inline int is_paging(struct kvm_vcpu *vcpu) +static inline bool is_paging(struct kvm_vcpu *vcpu) { - return likely(kvm_read_cr0_bits(vcpu, X86_CR0_PG)); + return likely(kvm_is_cr0_bit_set(vcpu, X86_CR0_PG)); } static inline bool is_pae_paging(struct kvm_vcpu *vcpu) @@ -193,7 +207,7 @@ static inline bool is_pae_paging(struct kvm_vcpu *vcpu) static inline u8 vcpu_virt_addr_bits(struct kvm_vcpu *vcpu) { - return kvm_read_cr4_bits(vcpu, X86_CR4_LA57) ? 57 : 48; + return kvm_is_cr4_bit_set(vcpu, X86_CR4_LA57) ? 57 : 48; } static inline bool is_noncanonical_address(u64 la, struct kvm_vcpu *vcpu) @@ -315,6 +329,34 @@ extern struct kvm_caps kvm_caps; extern bool enable_pmu; +/* + * Get a filtered version of KVM's supported XCR0 that strips out dynamic + * features for which the current process doesn't (yet) have permission to use. + * This is intended to be used only when enumerating support to userspace, + * e.g. in KVM_GET_SUPPORTED_CPUID and KVM_CAP_XSAVE2, it does NOT need to be + * used to check/restrict guest behavior as KVM rejects KVM_SET_CPUID{2} if + * userspace attempts to enable unpermitted features. + */ +static inline u64 kvm_get_filtered_xcr0(void) +{ + u64 permitted_xcr0 = kvm_caps.supported_xcr0; + + BUILD_BUG_ON(XFEATURE_MASK_USER_DYNAMIC != XFEATURE_MASK_XTILE_DATA); + + if (permitted_xcr0 & XFEATURE_MASK_USER_DYNAMIC) { + permitted_xcr0 &= xstate_get_guest_group_perm(); + + /* + * Treat XTILE_CFG as unsupported if the current process isn't + * allowed to use XTILE_DATA, as attempting to set XTILE_CFG in + * XCR0 without setting XTILE_DATA is architecturally illegal. + */ + if (!(permitted_xcr0 & XFEATURE_MASK_XTILE_DATA)) + permitted_xcr0 &= ~XFEATURE_MASK_XTILE_CFG; + } + return permitted_xcr0; +} + static inline bool kvm_mpx_supported(void) { return (kvm_caps.supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 4fc5c2de2de4..01c5de4c279b 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include @@ -29,7 +31,7 @@ */ SYM_FUNC_START(rep_movs_alternative) cmpq $64,%rcx - jae .Lunrolled + jae .Llarge cmp $8,%ecx jae .Lword @@ -65,6 +67,12 @@ SYM_FUNC_START(rep_movs_alternative) _ASM_EXTABLE_UA( 2b, .Lcopy_user_tail) _ASM_EXTABLE_UA( 3b, .Lcopy_user_tail) +.Llarge: +0: ALTERNATIVE "jmp .Lunrolled", "rep movsb", X86_FEATURE_ERMS +1: RET + + _ASM_EXTABLE_UA( 0b, 1b) + .p2align 4 .Lunrolled: 10: movq (%rsi),%r8 diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index b70d98d79a9d..b64a2bd1a1ef 100644 --- a/arch/x86/lib/getuser.S +++ b/arch/x86/lib/getuser.S @@ -37,22 +37,22 @@ #define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC -#ifdef CONFIG_X86_5LEVEL -#define LOAD_TASK_SIZE_MINUS_N(n) \ - ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rdx), \ - __stringify(mov $((1 << 56) - 4096 - (n)),%rdx), X86_FEATURE_LA57 -#else -#define LOAD_TASK_SIZE_MINUS_N(n) \ - mov $(TASK_SIZE_MAX - (n)),%_ASM_DX -#endif +.macro check_range size:req +.if IS_ENABLED(CONFIG_X86_64) + mov %rax, %rdx + sar $63, %rdx + or %rdx, %rax +.else + cmp $TASK_SIZE_MAX-\size+1, %eax + jae .Lbad_get_user + sbb %edx, %edx /* array_index_mask_nospec() */ + and %edx, %eax +.endif +.endm .text SYM_FUNC_START(__get_user_1) - LOAD_TASK_SIZE_MINUS_N(0) - cmp %_ASM_DX,%_ASM_AX - jae bad_get_user - sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ - and %_ASM_DX, %_ASM_AX + check_range size=1 ASM_STAC 1: movzbl (%_ASM_AX),%edx xor %eax,%eax @@ -62,11 +62,7 @@ SYM_FUNC_END(__get_user_1) EXPORT_SYMBOL(__get_user_1) SYM_FUNC_START(__get_user_2) - LOAD_TASK_SIZE_MINUS_N(1) - cmp %_ASM_DX,%_ASM_AX - jae bad_get_user - sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ - and %_ASM_DX, %_ASM_AX + check_range size=2 ASM_STAC 2: movzwl (%_ASM_AX),%edx xor %eax,%eax @@ -76,11 +72,7 @@ SYM_FUNC_END(__get_user_2) EXPORT_SYMBOL(__get_user_2) SYM_FUNC_START(__get_user_4) - LOAD_TASK_SIZE_MINUS_N(3) - cmp %_ASM_DX,%_ASM_AX - jae bad_get_user - sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ - and %_ASM_DX, %_ASM_AX + check_range size=4 ASM_STAC 3: movl (%_ASM_AX),%edx xor %eax,%eax @@ -90,30 +82,17 @@ SYM_FUNC_END(__get_user_4) EXPORT_SYMBOL(__get_user_4) SYM_FUNC_START(__get_user_8) + check_range size=8 + ASM_STAC #ifdef CONFIG_X86_64 - LOAD_TASK_SIZE_MINUS_N(7) - cmp %_ASM_DX,%_ASM_AX - jae bad_get_user - sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ - and %_ASM_DX, %_ASM_AX - ASM_STAC 4: movq (%_ASM_AX),%rdx - xor %eax,%eax - ASM_CLAC - RET #else - LOAD_TASK_SIZE_MINUS_N(7) - cmp %_ASM_DX,%_ASM_AX - jae bad_get_user_8 - sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ - and %_ASM_DX, %_ASM_AX - ASM_STAC 4: movl (%_ASM_AX),%edx 5: movl 4(%_ASM_AX),%ecx +#endif xor %eax,%eax ASM_CLAC RET -#endif SYM_FUNC_END(__get_user_8) EXPORT_SYMBOL(__get_user_8) @@ -166,7 +145,7 @@ EXPORT_SYMBOL(__get_user_nocheck_8) SYM_CODE_START_LOCAL(.Lbad_get_user_clac) ASM_CLAC -bad_get_user: +.Lbad_get_user: xor %edx,%edx mov $(-EFAULT),%_ASM_AX RET @@ -184,23 +163,23 @@ SYM_CODE_END(.Lbad_get_user_8_clac) #endif /* get_user */ - _ASM_EXTABLE_UA(1b, .Lbad_get_user_clac) - _ASM_EXTABLE_UA(2b, .Lbad_get_user_clac) - _ASM_EXTABLE_UA(3b, .Lbad_get_user_clac) + _ASM_EXTABLE(1b, .Lbad_get_user_clac) + _ASM_EXTABLE(2b, .Lbad_get_user_clac) + _ASM_EXTABLE(3b, .Lbad_get_user_clac) #ifdef CONFIG_X86_64 - _ASM_EXTABLE_UA(4b, .Lbad_get_user_clac) + _ASM_EXTABLE(4b, .Lbad_get_user_clac) #else - _ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac) - _ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac) + _ASM_EXTABLE(4b, .Lbad_get_user_8_clac) + _ASM_EXTABLE(5b, .Lbad_get_user_8_clac) #endif /* __get_user */ - _ASM_EXTABLE_UA(6b, .Lbad_get_user_clac) - _ASM_EXTABLE_UA(7b, .Lbad_get_user_clac) - _ASM_EXTABLE_UA(8b, .Lbad_get_user_clac) + _ASM_EXTABLE(6b, .Lbad_get_user_clac) + _ASM_EXTABLE(7b, .Lbad_get_user_clac) + _ASM_EXTABLE(8b, .Lbad_get_user_clac) #ifdef CONFIG_X86_64 - _ASM_EXTABLE_UA(9b, .Lbad_get_user_clac) + _ASM_EXTABLE(9b, .Lbad_get_user_clac) #else - _ASM_EXTABLE_UA(9b, .Lbad_get_user_8_clac) - _ASM_EXTABLE_UA(10b, .Lbad_get_user_8_clac) + _ASM_EXTABLE(9b, .Lbad_get_user_8_clac) + _ASM_EXTABLE(10b, .Lbad_get_user_8_clac) #endif diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S index 32125224fcca..3062d09a776d 100644 --- a/arch/x86/lib/putuser.S +++ b/arch/x86/lib/putuser.S @@ -33,20 +33,20 @@ * as they get called from within inline assembly. */ -#ifdef CONFIG_X86_5LEVEL -#define LOAD_TASK_SIZE_MINUS_N(n) \ - ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rbx), \ - __stringify(mov $((1 << 56) - 4096 - (n)),%rbx), X86_FEATURE_LA57 -#else -#define LOAD_TASK_SIZE_MINUS_N(n) \ - mov $(TASK_SIZE_MAX - (n)),%_ASM_BX -#endif +.macro check_range size:req +.if IS_ENABLED(CONFIG_X86_64) + mov %rcx, %rbx + sar $63, %rbx + or %rbx, %rcx +.else + cmp $TASK_SIZE_MAX-\size+1, %ecx + jae .Lbad_put_user +.endif +.endm .text SYM_FUNC_START(__put_user_1) - LOAD_TASK_SIZE_MINUS_N(0) - cmp %_ASM_BX,%_ASM_CX - jae .Lbad_put_user + check_range size=1 ASM_STAC 1: movb %al,(%_ASM_CX) xor %ecx,%ecx @@ -66,9 +66,7 @@ SYM_FUNC_END(__put_user_nocheck_1) EXPORT_SYMBOL(__put_user_nocheck_1) SYM_FUNC_START(__put_user_2) - LOAD_TASK_SIZE_MINUS_N(1) - cmp %_ASM_BX,%_ASM_CX - jae .Lbad_put_user + check_range size=2 ASM_STAC 3: movw %ax,(%_ASM_CX) xor %ecx,%ecx @@ -88,9 +86,7 @@ SYM_FUNC_END(__put_user_nocheck_2) EXPORT_SYMBOL(__put_user_nocheck_2) SYM_FUNC_START(__put_user_4) - LOAD_TASK_SIZE_MINUS_N(3) - cmp %_ASM_BX,%_ASM_CX - jae .Lbad_put_user + check_range size=4 ASM_STAC 5: movl %eax,(%_ASM_CX) xor %ecx,%ecx @@ -110,9 +106,7 @@ SYM_FUNC_END(__put_user_nocheck_4) EXPORT_SYMBOL(__put_user_nocheck_4) SYM_FUNC_START(__put_user_8) - LOAD_TASK_SIZE_MINUS_N(7) - cmp %_ASM_BX,%_ASM_CX - jae .Lbad_put_user + check_range size=8 ASM_STAC 7: mov %_ASM_AX,(%_ASM_CX) #ifdef CONFIG_X86_32 @@ -144,15 +138,15 @@ SYM_CODE_START_LOCAL(.Lbad_put_user_clac) RET SYM_CODE_END(.Lbad_put_user_clac) - _ASM_EXTABLE_UA(1b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(2b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(3b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(4b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(5b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(6b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(7b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(9b, .Lbad_put_user_clac) + _ASM_EXTABLE(1b, .Lbad_put_user_clac) + _ASM_EXTABLE(2b, .Lbad_put_user_clac) + _ASM_EXTABLE(3b, .Lbad_put_user_clac) + _ASM_EXTABLE(4b, .Lbad_put_user_clac) + _ASM_EXTABLE(5b, .Lbad_put_user_clac) + _ASM_EXTABLE(6b, .Lbad_put_user_clac) + _ASM_EXTABLE(7b, .Lbad_put_user_clac) + _ASM_EXTABLE(9b, .Lbad_put_user_clac) #ifdef CONFIG_X86_32 - _ASM_EXTABLE_UA(8b, .Lbad_put_user_clac) - _ASM_EXTABLE_UA(10b, .Lbad_put_user_clac) + _ASM_EXTABLE(8b, .Lbad_put_user_clac) + _ASM_EXTABLE(10b, .Lbad_put_user_clac) #endif diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index 5f61c65322be..b3b1e376dce8 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -33,7 +33,7 @@ .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR ALTERNATIVE_2 __stringify(RETPOLINE \reg), \ @@ -75,7 +75,7 @@ SYM_CODE_END(__x86_indirect_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_call_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR CALL_DEPTH_ACCOUNT @@ -103,7 +103,7 @@ SYM_CODE_END(__x86_indirect_call_thunk_array) .align RETPOLINE_THUNK_SIZE SYM_INNER_LABEL(__x86_indirect_jump_thunk_\reg, SYM_L_GLOBAL) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR POLINE \reg ANNOTATE_UNRET_SAFE @@ -144,8 +144,8 @@ SYM_CODE_END(__x86_indirect_jump_thunk_array) */ .align 64 .skip 63, 0xcc -SYM_FUNC_START_NOALIGN(zen_untrain_ret); - +SYM_START(zen_untrain_ret, SYM_L_GLOBAL, SYM_A_NONE) + ANNOTATE_NOENDBR /* * As executed from zen_untrain_ret, this is: * diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index c3a5bbc0b41e..003d90138e20 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -140,13 +140,4 @@ void __memcpy_flushcache(void *_dst, const void *_src, size_t size) } } EXPORT_SYMBOL_GPL(__memcpy_flushcache); - -void memcpy_page_flushcache(char *to, struct page *page, size_t offset, - size_t len) -{ - char *from = kmap_atomic(page); - - memcpy_flushcache(to, from + offset, len); - kunmap_atomic(from); -} #endif diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c index 092ea436c7e6..b43301cb2a80 100644 --- a/arch/x86/mm/debug_pagetables.c +++ b/arch/x86/mm/debug_pagetables.c @@ -71,6 +71,5 @@ static void __exit pt_dump_debug_exit(void) module_init(pt_dump_debug_init); module_exit(pt_dump_debug_exit); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arjan van de Ven "); MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 60814e110a54..271dcb2deabc 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -130,10 +130,36 @@ static bool ex_handler_fprestore(const struct exception_table_entry *fixup, return true; } -static bool ex_handler_uaccess(const struct exception_table_entry *fixup, - struct pt_regs *regs, int trapnr) +/* + * On x86-64, we end up being imprecise with 'access_ok()', and allow + * non-canonical user addresses to make the range comparisons simpler, + * and to not have to worry about LAM being enabled. + * + * In fact, we allow up to one page of "slop" at the sign boundary, + * which means that we can do access_ok() by just checking the sign + * of the pointer for the common case of having a small access size. + */ +static bool gp_fault_address_ok(unsigned long fault_address) { - WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?"); +#ifdef CONFIG_X86_64 + /* Is it in the "user space" part of the non-canonical space? */ + if (valid_user_address(fault_address)) + return true; + + /* .. or just above it? */ + fault_address -= PAGE_SIZE; + if (valid_user_address(fault_address)) + return true; +#endif + return false; +} + +static bool ex_handler_uaccess(const struct exception_table_entry *fixup, + struct pt_regs *regs, int trapnr, + unsigned long fault_address) +{ + WARN_ONCE(trapnr == X86_TRAP_GP && !gp_fault_address_ok(fault_address), + "General protection fault in user access. Non-canonical address?"); return ex_handler_default(fixup, regs); } @@ -189,10 +215,12 @@ static bool ex_handler_imm_reg(const struct exception_table_entry *fixup, } static bool ex_handler_ucopy_len(const struct exception_table_entry *fixup, - struct pt_regs *regs, int trapnr, int reg, int imm) + struct pt_regs *regs, int trapnr, + unsigned long fault_address, + int reg, int imm) { regs->cx = imm * regs->cx + *pt_regs_nr(regs, reg); - return ex_handler_uaccess(fixup, regs, trapnr); + return ex_handler_uaccess(fixup, regs, trapnr, fault_address); } int ex_get_fixup_type(unsigned long ip) @@ -238,7 +266,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, case EX_TYPE_FAULT_MCE_SAFE: return ex_handler_fault(e, regs, trapnr); case EX_TYPE_UACCESS: - return ex_handler_uaccess(e, regs, trapnr); + return ex_handler_uaccess(e, regs, trapnr, fault_addr); case EX_TYPE_COPY: return ex_handler_copy(e, regs, trapnr); case EX_TYPE_CLEAR_FS: @@ -269,7 +297,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code, case EX_TYPE_FAULT_SGX: return ex_handler_sgx(e, regs, trapnr); case EX_TYPE_UCOPY_LEN: - return ex_handler_ucopy_len(e, regs, trapnr, reg, imm); + return ex_handler_ucopy_len(e, regs, trapnr, fault_addr, reg, imm); case EX_TYPE_ZEROPAD: return ex_handler_zeropad(e, regs, fault_addr); } diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index a498ae1fbe66..e4399983c50c 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -19,6 +19,7 @@ #include /* faulthandler_disabled() */ #include /* efi_crash_gracefully_on_page_fault()*/ #include +#include /* find_and_lock_vma() */ #include /* boot_cpu_has, ... */ #include /* dotraplinkage, ... */ @@ -1333,6 +1334,38 @@ void do_user_addr_fault(struct pt_regs *regs, } #endif +#ifdef CONFIG_PER_VMA_LOCK + if (!(flags & FAULT_FLAG_USER)) + goto lock_mmap; + + vma = lock_vma_under_rcu(mm, address); + if (!vma) + goto lock_mmap; + + if (unlikely(access_error(error_code, vma))) { + vma_end_read(vma); + goto lock_mmap; + } + fault = handle_mm_fault(vma, address, flags | FAULT_FLAG_VMA_LOCK, regs); + vma_end_read(vma); + + if (!(fault & VM_FAULT_RETRY)) { + count_vm_vma_lock_event(VMA_LOCK_SUCCESS); + goto done; + } + count_vm_vma_lock_event(VMA_LOCK_RETRY); + + /* Quick path to respond to signals */ + if (fault_signal_pending(fault, regs)) { + if (!user_mode(regs)) + kernelmode_fixup_or_oops(regs, error_code, address, + SIGBUS, BUS_ADRERR, + ARCH_DEFAULT_PKEY); + return; + } +lock_mmap: +#endif /* CONFIG_PER_VMA_LOCK */ + /* * Kernel-mode access to the user address space should only occur * on well-defined single instructions listed in the exception @@ -1433,6 +1466,9 @@ good_area: } mmap_read_unlock(mm); +#ifdef CONFIG_PER_VMA_LOCK +done: +#endif if (likely(!(fault & VM_FAULT_ERROR))) return; diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index cbc53da4c1b4..8192452d1d2d 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -261,6 +262,24 @@ static void __init probe_page_size_mask(void) } } +#define INTEL_MATCH(_model) { .vendor = X86_VENDOR_INTEL, \ + .family = 6, \ + .model = _model, \ + } +/* + * INVLPG may not properly flush Global entries + * on these CPUs when PCIDs are enabled. + */ +static const struct x86_cpu_id invlpg_miss_ids[] = { + INTEL_MATCH(INTEL_FAM6_ALDERLAKE ), + INTEL_MATCH(INTEL_FAM6_ALDERLAKE_L ), + INTEL_MATCH(INTEL_FAM6_ALDERLAKE_N ), + INTEL_MATCH(INTEL_FAM6_RAPTORLAKE ), + INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_P), + INTEL_MATCH(INTEL_FAM6_RAPTORLAKE_S), + {} +}; + static void setup_pcid(void) { if (!IS_ENABLED(CONFIG_X86_64)) @@ -269,6 +288,12 @@ static void setup_pcid(void) if (!boot_cpu_has(X86_FEATURE_PCID)) return; + if (x86_match_cpu(invlpg_miss_ids)) { + pr_info("Incomplete global flushes, disabling PCID"); + setup_clear_cpu_cap(X86_FEATURE_PCID); + return; + } + if (boot_cpu_has(X86_FEATURE_PGE)) { /* * This can't be cr4_set_bits_and_update_boot() -- the @@ -1048,6 +1073,11 @@ __visible DEFINE_PER_CPU_ALIGNED(struct tlb_state, cpu_tlbstate) = { .cr4 = ~0UL, /* fail hard if we screw up cr4 shadow initialization */ }; +#ifdef CONFIG_ADDRESS_MASKING +DEFINE_PER_CPU(u64, tlbstate_untag_mask); +EXPORT_PER_CPU_SYMBOL(tlbstate_untag_mask); +#endif + void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache) { /* entry 0 MUST be WB (hardwired to speed up translations) */ diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c index 46a00aa858b6..de10800cd4dd 100644 --- a/arch/x86/mm/pat/memtype.c +++ b/arch/x86/mm/pat/memtype.c @@ -1073,11 +1073,15 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, } /* - * untrack_pfn_moved is called, while mremapping a pfnmap for a new region, - * with the old vma after its pfnmap page table has been removed. The new - * vma has a new pfnmap to the same pfn & cache type with VM_PAT set. + * untrack_pfn_clear is called if the following situation fits: + * + * 1) while mremapping a pfnmap for a new region, with the old vma after + * its pfnmap page table has been removed. The new vma has a new pfnmap + * to the same pfn & cache type with VM_PAT set. + * 2) while duplicating vm area, the new vma fails to copy the pgtable from + * old vma. */ -void untrack_pfn_moved(struct vm_area_struct *vma) +void untrack_pfn_clear(struct vm_area_struct *vma) { vm_flags_clear(vma, VM_PAT); } diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 16c5292d227d..267acf27480a 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -154,26 +154,30 @@ static inline u16 user_pcid(u16 asid) return ret; } -static inline unsigned long build_cr3(pgd_t *pgd, u16 asid) +static inline unsigned long build_cr3(pgd_t *pgd, u16 asid, unsigned long lam) { + unsigned long cr3 = __sme_pa(pgd) | lam; + if (static_cpu_has(X86_FEATURE_PCID)) { - return __sme_pa(pgd) | kern_pcid(asid); + VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE); + cr3 |= kern_pcid(asid); } else { VM_WARN_ON_ONCE(asid != 0); - return __sme_pa(pgd); } + + return cr3; } -static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid) +static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid, + unsigned long lam) { - VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE); /* * Use boot_cpu_has() instead of this_cpu_has() as this function * might be called during early boot. This should work even after * boot because all CPU's the have same capabilities: */ VM_WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_PCID)); - return __sme_pa(pgd) | kern_pcid(asid) | CR3_NOFLUSH; + return build_cr3(pgd, asid, lam) | CR3_NOFLUSH; } /* @@ -274,15 +278,16 @@ static inline void invalidate_user_asid(u16 asid) (unsigned long *)this_cpu_ptr(&cpu_tlbstate.user_pcid_flush_mask)); } -static void load_new_mm_cr3(pgd_t *pgdir, u16 new_asid, bool need_flush) +static void load_new_mm_cr3(pgd_t *pgdir, u16 new_asid, unsigned long lam, + bool need_flush) { unsigned long new_mm_cr3; if (need_flush) { invalidate_user_asid(new_asid); - new_mm_cr3 = build_cr3(pgdir, new_asid); + new_mm_cr3 = build_cr3(pgdir, new_asid, lam); } else { - new_mm_cr3 = build_cr3_noflush(pgdir, new_asid); + new_mm_cr3 = build_cr3_noflush(pgdir, new_asid, lam); } /* @@ -491,6 +496,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, { struct mm_struct *real_prev = this_cpu_read(cpu_tlbstate.loaded_mm); u16 prev_asid = this_cpu_read(cpu_tlbstate.loaded_mm_asid); + unsigned long new_lam = mm_lam_cr3_mask(next); bool was_lazy = this_cpu_read(cpu_tlbstate_shared.is_lazy); unsigned cpu = smp_processor_id(); u64 next_tlb_gen; @@ -520,7 +526,8 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * isn't free. */ #ifdef CONFIG_DEBUG_VM - if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev->pgd, prev_asid))) { + if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev->pgd, prev_asid, + tlbstate_lam_cr3_mask()))) { /* * If we were to BUG here, we'd be very likely to kill * the system so hard that we don't see the call trace. @@ -552,9 +559,15 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, * instruction. */ if (real_prev == next) { + /* Not actually switching mm's */ VM_WARN_ON(this_cpu_read(cpu_tlbstate.ctxs[prev_asid].ctx_id) != next->context.ctx_id); + /* + * If this races with another thread that enables lam, 'new_lam' + * might not match tlbstate_lam_cr3_mask(). + */ + /* * Even in lazy TLB mode, the CPU should stay set in the * mm_cpumask. The TLB shootdown code can figure out from @@ -622,15 +635,16 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, barrier(); } + set_tlbstate_lam_mode(next); if (need_flush) { this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id); this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen); - load_new_mm_cr3(next->pgd, new_asid, true); + load_new_mm_cr3(next->pgd, new_asid, new_lam, true); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); } else { /* The new ASID is already up to date. */ - load_new_mm_cr3(next->pgd, new_asid, false); + load_new_mm_cr3(next->pgd, new_asid, new_lam, false); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, 0); } @@ -691,6 +705,10 @@ void initialize_tlbstate_and_flush(void) /* Assert that CR3 already references the right mm. */ WARN_ON((cr3 & CR3_ADDR_MASK) != __pa(mm->pgd)); + /* LAM expected to be disabled */ + WARN_ON(cr3 & (X86_CR3_LAM_U48 | X86_CR3_LAM_U57)); + WARN_ON(mm_lam_cr3_mask(mm)); + /* * Assert that CR4.PCIDE is set if needed. (CR4.PCIDE initialization * doesn't work like other CR4 bits because it can only be set from @@ -699,8 +717,8 @@ void initialize_tlbstate_and_flush(void) WARN_ON(boot_cpu_has(X86_FEATURE_PCID) && !(cr4_read_shadow() & X86_CR4_PCIDE)); - /* Force ASID 0 and force a TLB flush. */ - write_cr3(build_cr3(mm->pgd, 0)); + /* Disable LAM, force ASID 0 and force a TLB flush. */ + write_cr3(build_cr3(mm->pgd, 0, 0)); /* Reinitialize tlbstate. */ this_cpu_write(cpu_tlbstate.last_user_mm_spec, LAST_USER_MM_INIT); @@ -708,6 +726,7 @@ void initialize_tlbstate_and_flush(void) this_cpu_write(cpu_tlbstate.next_asid, 1); this_cpu_write(cpu_tlbstate.ctxs[0].ctx_id, mm->context.ctx_id); this_cpu_write(cpu_tlbstate.ctxs[0].tlb_gen, tlb_gen); + set_tlbstate_lam_mode(mm); for (i = 1; i < TLB_NR_DYN_ASIDS; i++) this_cpu_write(cpu_tlbstate.ctxs[i].ctx_id, 0); @@ -1071,8 +1090,10 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) */ unsigned long __get_current_cr3_fast(void) { - unsigned long cr3 = build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd, - this_cpu_read(cpu_tlbstate.loaded_mm_asid)); + unsigned long cr3 = + build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd, + this_cpu_read(cpu_tlbstate.loaded_mm_asid), + tlbstate_lam_cr3_mask()); /* For now, be very restrictive about when this can be called. */ VM_WARN_ON(in_nmi() || preemptible()); diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 8babce71915f..014c508e914d 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -198,7 +198,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) i++; } kfree(v); - return 0; + return msi_device_populate_sysfs(&dev->dev); error: if (ret == -ENOSYS) @@ -254,7 +254,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) dev_dbg(&dev->dev, "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq); } - return 0; + return msi_device_populate_sysfs(&dev->dev); error: dev_err(&dev->dev, "Failed to create MSI%s! ret=%d!\n", @@ -346,7 +346,7 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (ret < 0) goto out; } - ret = 0; + ret = msi_device_populate_sysfs(&dev->dev); out: return ret; } @@ -394,6 +394,8 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev) xen_destroy_irq(msidesc->irq + i); msidesc->irq = 0; } + + msi_device_destroy_sysfs(&dev->dev); } static void xen_pv_teardown_msi_irqs(struct pci_dev *dev) diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index 7fe564eaf228..c4365a05ab83 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -50,7 +50,7 @@ #define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8) SYM_CODE_START_LOCAL(pvh_start_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK cld lgdt (_pa(gdt)) diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 236447ee9beb..7a4d5e911415 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -288,7 +288,7 @@ EXPORT_SYMBOL(restore_processor_state); #endif #if defined(CONFIG_HIBERNATION) && defined(CONFIG_HOTPLUG_CPU) -static void resume_play_dead(void) +static void __noreturn resume_play_dead(void) { play_dead_common(); tboot_shutdown(TB_SHUTDOWN_WFS); diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 2925074b9a58..d30949e25ebd 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -406,7 +406,7 @@ static void read_ehdr(FILE *fp) if (ehdr.e_version != EV_CURRENT) die("Unknown ELF version\n"); if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) - die("Bad Elf header size\n"); + die("Bad ELF header size\n"); if (ehdr.e_phentsize != sizeof(Elf_Phdr)) die("Bad program header entry\n"); if (ehdr.e_shentsize != sizeof(Elf_Shdr)) diff --git a/arch/x86/um/shared/sysdep/stub_32.h b/arch/x86/um/shared/sysdep/stub_32.h index 4c6c2be0c899..38fa894b65d0 100644 --- a/arch/x86/um/shared/sysdep/stub_32.h +++ b/arch/x86/um/shared/sysdep/stub_32.h @@ -89,19 +89,19 @@ static inline void remap_stack_and_trap(void) "addl %4,%%ebx ; movl %%eax, (%%ebx) ;" "int $3" : : - "g" (~(UM_KERN_PAGE_SIZE - 1)), + "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)), "g" (STUB_MMAP_NR), "g" (UML_STUB_FIELD_FD), "g" (UML_STUB_FIELD_OFFSET), "g" (UML_STUB_FIELD_CHILD_ERR), - "c" (UM_KERN_PAGE_SIZE), + "c" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE), "d" (PROT_READ | PROT_WRITE), "S" (MAP_FIXED | MAP_SHARED) : "memory"); } -static __always_inline void *get_stub_page(void) +static __always_inline void *get_stub_data(void) { unsigned long ret; @@ -109,7 +109,7 @@ static __always_inline void *get_stub_page(void) "movl %%esp,%0 ;" "andl %1,%0" : "=a" (ret) - : "g" (~(UM_KERN_PAGE_SIZE - 1))); + : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1))); return (void *)ret; } diff --git a/arch/x86/um/shared/sysdep/stub_64.h b/arch/x86/um/shared/sysdep/stub_64.h index 92ea1670cf1c..2de1c8f88173 100644 --- a/arch/x86/um/shared/sysdep/stub_64.h +++ b/arch/x86/um/shared/sysdep/stub_64.h @@ -98,18 +98,18 @@ static inline void remap_stack_and_trap(void) "int3" : : "g" (STUB_MMAP_NR), - "g" (~(UM_KERN_PAGE_SIZE - 1)), + "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)), "g" (MAP_FIXED | MAP_SHARED), "g" (UML_STUB_FIELD_FD), "g" (UML_STUB_FIELD_OFFSET), "g" (UML_STUB_FIELD_CHILD_ERR), - "S" (UM_KERN_PAGE_SIZE), + "S" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE), "d" (PROT_READ | PROT_WRITE) : __syscall_clobber, "r10", "r8", "r9"); } -static __always_inline void *get_stub_page(void) +static __always_inline void *get_stub_data(void) { unsigned long ret; @@ -117,7 +117,7 @@ static __always_inline void *get_stub_page(void) "movq %%rsp,%0 ;" "andq %1,%0" : "=a" (ret) - : "g" (~(UM_KERN_PAGE_SIZE - 1))); + : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1))); return (void *)ret; } diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c index f7eefba034f9..040668b989b5 100644 --- a/arch/x86/um/stub_segv.c +++ b/arch/x86/um/stub_segv.c @@ -11,7 +11,7 @@ void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig, siginfo_t *info, void *p) { - struct faultinfo *f = get_stub_page(); + struct faultinfo *f = get_stub_data(); ucontext_t *uc = p; GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext); diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S index 4a184f6e4e4d..08f1ceb9eb81 100644 --- a/arch/x86/xen/xen-asm.S +++ b/arch/x86/xen/xen-asm.S @@ -165,7 +165,7 @@ xen_pv_trap asm_exc_xen_hypervisor_callback SYM_CODE_START(xen_early_idt_handler_array) i = 0 .rept NUM_EXCEPTION_VECTORS - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ENDBR pop %rcx pop %r11 @@ -193,7 +193,7 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 * rsp->rax } */ SYM_CODE_START(xen_iret) - UNWIND_HINT_EMPTY + UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR pushq $0 jmp hypercall_iret diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index 91f7a53519a7..643d02900fbb 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -45,7 +45,7 @@ SYM_CODE_END(hypercall_page) #ifdef CONFIG_XEN_PV __INIT SYM_CODE_START(startup_xen) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ANNOTATE_NOENDBR cld @@ -71,7 +71,7 @@ SYM_CODE_END(startup_xen) #ifdef CONFIG_XEN_PV_SMP .pushsection .text SYM_CODE_START(asm_cpu_bringup_and_idle) - UNWIND_HINT_EMPTY + UNWIND_HINT_END_OF_STACK ENDBR call cpu_bringup_and_idle diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index bcb0c5d2abc2..3c6e5471f025 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -772,18 +772,17 @@ config HIGHMEM If unsure, say Y. config ARCH_FORCE_MAX_ORDER - int "Maximum zone order" - default "11" + int "Order of maximal physically contiguous allocations" + default "10" help - The kernel memory allocator divides physically contiguous memory - blocks into "zones", where each zone is a power of two number of - pages. This option selects the largest power of two that the kernel - keeps in the memory allocator. If you need to allocate very large - blocks of physically contiguous memory, then you may need to - increase this value. + The kernel page allocator limits the size of maximal physically + contiguous allocations. The limit is called MAX_ORDER and it + defines the maximal power of two of number of pages that can be + allocated as a single contiguous block. This option allows + overriding the default setting when ability to allocate very + large blocks of physically contiguous memory is required. - This config option is actually maximum order plus one. For example, - a value of 11 means that the largest free memory block is 2^10 pages. + Don't change if unsure. endmenu diff --git a/arch/xtensa/include/asm/cmpxchg.h b/arch/xtensa/include/asm/cmpxchg.h index eb87810357ad..675a11ea8de7 100644 --- a/arch/xtensa/include/asm/cmpxchg.h +++ b/arch/xtensa/include/asm/cmpxchg.h @@ -170,7 +170,7 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val) } #define arch_xchg(ptr,x) \ - ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + ((__typeof__(*(ptr)))__arch_xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) static inline u32 xchg_small(volatile void *ptr, u32 x, int size) { @@ -203,7 +203,7 @@ static inline u32 xchg_small(volatile void *ptr, u32 x, int size) extern void __xchg_called_with_bad_pointer(void); static __inline__ unsigned long -__xchg(unsigned long x, volatile void * ptr, int size) +__arch_xchg(unsigned long x, volatile void * ptr, int size) { switch (size) { case 1: diff --git a/arch/xtensa/include/asm/smp.h b/arch/xtensa/include/asm/smp.h index 4e43f5643891..5dc5bf8cdd77 100644 --- a/arch/xtensa/include/asm/smp.h +++ b/arch/xtensa/include/asm/smp.h @@ -33,7 +33,7 @@ void show_ipi_list(struct seq_file *p, int prec); void __cpu_die(unsigned int cpu); int __cpu_disable(void); -void cpu_die(void); +void __noreturn cpu_die(void); void cpu_restart(void); #endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 876d5df157ed..5c01d7e70d90 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -343,7 +343,19 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, struct rt_sigframe *frame; int err = 0, sig = ksig->sig; unsigned long sp, ra, tp, ps; + unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; + unsigned long handler_fdpic_GOT = 0; unsigned int base; + bool fdpic = IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) && + (current->personality & FDPIC_FUNCPTRS); + + if (fdpic) { + unsigned long __user *fdpic_func_desc = + (unsigned long __user *)handler; + if (__get_user(handler, &fdpic_func_desc[0]) || + __get_user(handler_fdpic_GOT, &fdpic_func_desc[1])) + return -EFAULT; + } sp = regs->areg[1]; @@ -373,20 +385,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (ksig->ka.sa.sa_flags & SA_RESTORER) { - ra = (unsigned long)ksig->ka.sa.sa_restorer; + if (fdpic) { + unsigned long __user *fdpic_func_desc = + (unsigned long __user *)ksig->ka.sa.sa_restorer; + + err |= __get_user(ra, fdpic_func_desc); + } else { + ra = (unsigned long)ksig->ka.sa.sa_restorer; + } } else { /* Create sys_rt_sigreturn syscall in stack frame */ err |= gen_return_code(frame->retcode); - - if (err) { - return -EFAULT; - } ra = (unsigned long) frame->retcode; } - /* + if (err) + return -EFAULT; + + /* * Create signal handler execution context. * Return context not modified until this point. */ @@ -394,8 +412,7 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, /* Set up registers for signal handler; preserve the threadptr */ tp = regs->threadptr; ps = regs->ps; - start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler, - (unsigned long) frame); + start_thread(regs, handler, (unsigned long)frame); /* Set up a stack frame for a call4 if userspace uses windowed ABI */ if (ps & PS_WOE_MASK) { @@ -413,6 +430,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, regs->areg[base + 4] = (unsigned long) &frame->uc; regs->threadptr = tp; regs->ps = ps; + if (fdpic) + regs->areg[base + 11] = handler_fdpic_GOT; pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n", current->comm, current->pid, sig, frame, regs->pc); diff --git a/arch/xtensa/kernel/smp.c b/arch/xtensa/kernel/smp.c index 4dc109dd6214..07dd6baf18cf 100644 --- a/arch/xtensa/kernel/smp.c +++ b/arch/xtensa/kernel/smp.c @@ -322,7 +322,7 @@ void __cpu_die(unsigned int cpu) pr_err("CPU%u: unable to kill\n", cpu); } -void arch_cpu_idle_dead(void) +void __noreturn arch_cpu_idle_dead(void) { cpu_die(); } @@ -341,6 +341,8 @@ void __ref cpu_die(void) __asm__ __volatile__( " movi a2, cpu_restart\n" " jx a2\n"); + + BUG(); } #endif /* CONFIG_HOTPLUG_CPU */ @@ -389,7 +391,7 @@ void arch_send_call_function_single_ipi(int cpu) send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC); } -void smp_send_reschedule(int cpu) +void arch_smp_send_reschedule(int cpu) { send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); } diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 2a31b1ab0c9f..17a7ef86fd0d 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -56,6 +56,8 @@ EXPORT_SYMBOL(empty_zero_page); */ extern long long __ashrdi3(long long, int); extern long long __ashldi3(long long, int); +extern long long __bswapdi2(long long); +extern int __bswapsi2(int); extern long long __lshrdi3(long long, int); extern int __divsi3(int, int); extern int __modsi3(int, int); @@ -66,6 +68,8 @@ extern unsigned long long __umulsidi3(unsigned int, unsigned int); EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__bswapdi2); +EXPORT_SYMBOL(__bswapsi2); EXPORT_SYMBOL(__lshrdi3); EXPORT_SYMBOL(__divsi3); EXPORT_SYMBOL(__modsi3); diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile index 7ecef0519a27..c9c2614188f7 100644 --- a/arch/xtensa/lib/Makefile +++ b/arch/xtensa/lib/Makefile @@ -4,7 +4,7 @@ # lib-y += memcopy.o memset.o checksum.o \ - ashldi3.o ashrdi3.o lshrdi3.o \ + ashldi3.o ashrdi3.o bswapdi2.o bswapsi2.o lshrdi3.o \ divsi3.o udivsi3.o modsi3.o umodsi3.o mulsi3.o umulsidi3.o \ usercopy.o strncpy_user.o strnlen_user.o lib-$(CONFIG_PCI) += pci-auto.o diff --git a/arch/xtensa/lib/bswapdi2.S b/arch/xtensa/lib/bswapdi2.S new file mode 100644 index 000000000000..d8e52e05eba6 --- /dev/null +++ b/arch/xtensa/lib/bswapdi2.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ +#include +#include +#include + +ENTRY(__bswapdi2) + + abi_entry_default + ssai 8 + srli a4, a2, 16 + src a4, a4, a2 + src a4, a4, a4 + src a4, a2, a4 + srli a2, a3, 16 + src a2, a2, a3 + src a2, a2, a2 + src a2, a3, a2 + mov a3, a4 + abi_ret_default + +ENDPROC(__bswapdi2) diff --git a/arch/xtensa/lib/bswapsi2.S b/arch/xtensa/lib/bswapsi2.S new file mode 100644 index 000000000000..9c1de1344f79 --- /dev/null +++ b/arch/xtensa/lib/bswapsi2.S @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ +#include +#include +#include + +ENTRY(__bswapsi2) + + abi_entry_default + ssai 8 + srli a3, a2, 16 + src a3, a3, a2 + src a3, a3, a3 + src a2, a2, a3 + abi_ret_default + +ENDPROC(__bswapsi2) diff --git a/block/bdev.c b/block/bdev.c index 850852fe4b78..21c63bfef323 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -418,8 +418,11 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) bdev->bd_partno = partno; bdev->bd_inode = inode; bdev->bd_queue = disk->queue; + if (partno) + bdev->bd_has_submit_bio = disk->part0->bd_has_submit_bio; + else + bdev->bd_has_submit_bio = false; bdev->bd_stats = alloc_percpu(struct disk_stats); - bdev->bd_has_submit_bio = false; if (!bdev->bd_stats) { iput(inode); return NULL; @@ -428,6 +431,14 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno) return bdev; } +void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) +{ + spin_lock(&bdev->bd_size_lock); + i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); + bdev->bd_nr_sectors = sectors; + spin_unlock(&bdev->bd_size_lock); +} + void bdev_add(struct block_device *bdev, dev_t dev) { bdev->bd_dev = dev; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index ff45649361e7..0ce64dd73cfe 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -567,6 +567,9 @@ restart: list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) { struct blkcg *blkcg = blkg->blkcg; + if (hlist_unhashed(&blkg->blkcg_node)) + continue; + spin_lock(&blkcg->lock); blkg_destroy(blkg); spin_unlock(&blkcg->lock); diff --git a/block/blk-core.c b/block/blk-core.c index 00c74330fa92..1da77e7d6289 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -520,7 +520,7 @@ static inline int bio_check_eod(struct bio *bio) sector_t maxsector = bdev_nr_sectors(bio->bi_bdev); unsigned int nr_sectors = bio_sectors(bio); - if (nr_sectors && maxsector && + if (nr_sectors && (nr_sectors > maxsector || bio->bi_iter.bi_sector > maxsector - nr_sectors)) { pr_info_ratelimited("%s: attempt to access beyond end of device\n" diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 8f01d786f5cb..d4e9b4556d14 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -212,61 +212,44 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, return true; } -struct integrity_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_integrity *, char *); - ssize_t (*store)(struct blk_integrity *, const char *, size_t); -}; - -static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr, - char *page) +static inline struct blk_integrity *dev_to_bi(struct device *dev) { - struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); - struct blk_integrity *bi = &disk->queue->integrity; - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - - return entry->show(bi, page); + return &dev_to_disk(dev)->queue->integrity; } -static ssize_t integrity_attr_store(struct kobject *kobj, - struct attribute *attr, const char *page, - size_t count) +static ssize_t format_show(struct device *dev, struct device_attribute *attr, + char *page) { - struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); - struct blk_integrity *bi = &disk->queue->integrity; - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - ssize_t ret = 0; + struct blk_integrity *bi = dev_to_bi(dev); - if (entry->store) - ret = entry->store(bi, page, count); - - return ret; -} - -static ssize_t integrity_format_show(struct blk_integrity *bi, char *page) -{ if (bi->profile && bi->profile->name) - return sprintf(page, "%s\n", bi->profile->name); - else - return sprintf(page, "none\n"); + return sysfs_emit(page, "%s\n", bi->profile->name); + return sysfs_emit(page, "none\n"); } -static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page) +static ssize_t tag_size_show(struct device *dev, struct device_attribute *attr, + char *page) { - return sprintf(page, "%u\n", bi->tag_size); + struct blk_integrity *bi = dev_to_bi(dev); + + return sysfs_emit(page, "%u\n", bi->tag_size); } -static ssize_t integrity_interval_show(struct blk_integrity *bi, char *page) +static ssize_t protection_interval_bytes_show(struct device *dev, + struct device_attribute *attr, + char *page) { - return sprintf(page, "%u\n", - bi->interval_exp ? 1 << bi->interval_exp : 0); + struct blk_integrity *bi = dev_to_bi(dev); + + return sysfs_emit(page, "%u\n", + bi->interval_exp ? 1 << bi->interval_exp : 0); } -static ssize_t integrity_verify_store(struct blk_integrity *bi, - const char *page, size_t count) +static ssize_t read_verify_store(struct device *dev, + struct device_attribute *attr, + const char *page, size_t count) { + struct blk_integrity *bi = dev_to_bi(dev); char *p = (char *) page; unsigned long val = simple_strtoul(p, &p, 10); @@ -278,14 +261,20 @@ static ssize_t integrity_verify_store(struct blk_integrity *bi, return count; } -static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page) +static ssize_t read_verify_show(struct device *dev, + struct device_attribute *attr, char *page) { - return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_VERIFY) != 0); + struct blk_integrity *bi = dev_to_bi(dev); + + return sysfs_emit(page, "%d\n", !!(bi->flags & BLK_INTEGRITY_VERIFY)); } -static ssize_t integrity_generate_store(struct blk_integrity *bi, - const char *page, size_t count) +static ssize_t write_generate_store(struct device *dev, + struct device_attribute *attr, + const char *page, size_t count) { + struct blk_integrity *bi = dev_to_bi(dev); + char *p = (char *) page; unsigned long val = simple_strtoul(p, &p, 10); @@ -297,68 +286,44 @@ static ssize_t integrity_generate_store(struct blk_integrity *bi, return count; } -static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page) +static ssize_t write_generate_show(struct device *dev, + struct device_attribute *attr, char *page) { - return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_GENERATE) != 0); + struct blk_integrity *bi = dev_to_bi(dev); + + return sysfs_emit(page, "%d\n", !!(bi->flags & BLK_INTEGRITY_GENERATE)); } -static ssize_t integrity_device_show(struct blk_integrity *bi, char *page) +static ssize_t device_is_integrity_capable_show(struct device *dev, + struct device_attribute *attr, + char *page) { - return sprintf(page, "%u\n", - (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0); + struct blk_integrity *bi = dev_to_bi(dev); + + return sysfs_emit(page, "%u\n", + !!(bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE)); } -static struct integrity_sysfs_entry integrity_format_entry = { - .attr = { .name = "format", .mode = 0444 }, - .show = integrity_format_show, -}; - -static struct integrity_sysfs_entry integrity_tag_size_entry = { - .attr = { .name = "tag_size", .mode = 0444 }, - .show = integrity_tag_size_show, -}; - -static struct integrity_sysfs_entry integrity_interval_entry = { - .attr = { .name = "protection_interval_bytes", .mode = 0444 }, - .show = integrity_interval_show, -}; - -static struct integrity_sysfs_entry integrity_verify_entry = { - .attr = { .name = "read_verify", .mode = 0644 }, - .show = integrity_verify_show, - .store = integrity_verify_store, -}; - -static struct integrity_sysfs_entry integrity_generate_entry = { - .attr = { .name = "write_generate", .mode = 0644 }, - .show = integrity_generate_show, - .store = integrity_generate_store, -}; - -static struct integrity_sysfs_entry integrity_device_entry = { - .attr = { .name = "device_is_integrity_capable", .mode = 0444 }, - .show = integrity_device_show, -}; +static DEVICE_ATTR_RO(format); +static DEVICE_ATTR_RO(tag_size); +static DEVICE_ATTR_RO(protection_interval_bytes); +static DEVICE_ATTR_RW(read_verify); +static DEVICE_ATTR_RW(write_generate); +static DEVICE_ATTR_RO(device_is_integrity_capable); static struct attribute *integrity_attrs[] = { - &integrity_format_entry.attr, - &integrity_tag_size_entry.attr, - &integrity_interval_entry.attr, - &integrity_verify_entry.attr, - &integrity_generate_entry.attr, - &integrity_device_entry.attr, - NULL, -}; -ATTRIBUTE_GROUPS(integrity); - -static const struct sysfs_ops integrity_ops = { - .show = &integrity_attr_show, - .store = &integrity_attr_store, + &dev_attr_format.attr, + &dev_attr_tag_size.attr, + &dev_attr_protection_interval_bytes.attr, + &dev_attr_read_verify.attr, + &dev_attr_write_generate.attr, + &dev_attr_device_is_integrity_capable.attr, + NULL }; -static const struct kobj_type integrity_ktype = { - .default_groups = integrity_groups, - .sysfs_ops = &integrity_ops, +const struct attribute_group blk_integrity_attr_group = { + .name = "integrity", + .attrs = integrity_attrs, }; static blk_status_t blk_integrity_nop_fn(struct blk_integrity_iter *iter) @@ -437,21 +402,3 @@ void blk_integrity_unregister(struct gendisk *disk) memset(bi, 0, sizeof(*bi)); } EXPORT_SYMBOL(blk_integrity_unregister); - -int blk_integrity_add(struct gendisk *disk) -{ - int ret; - - ret = kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, - &disk_to_dev(disk)->kobj, "%s", "integrity"); - if (!ret) - kobject_uevent(&disk->integrity_kobj, KOBJ_ADD); - return ret; -} - -void blk_integrity_del(struct gendisk *disk) -{ - kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE); - kobject_del(&disk->integrity_kobj); - kobject_put(&disk->integrity_kobj); -} diff --git a/block/blk-map.c b/block/blk-map.c index 04c55f1c492e..46eed2e627c3 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -248,7 +248,7 @@ static struct bio *blk_rq_map_bio_alloc(struct request *rq, { struct bio *bio; - if (rq->cmd_flags & REQ_ALLOC_CACHE) { + if (rq->cmd_flags & REQ_ALLOC_CACHE && (nr_vecs <= BIO_INLINE_VECS)) { bio = bio_alloc_bioset(NULL, nr_vecs, rq->cmd_flags, gfp_mask, &fs_bio_set); if (!bio) diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index d6af9d431dc6..dfd81cab5788 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -39,16 +39,20 @@ void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) { unsigned int users; + /* + * calling test_bit() prior to test_and_set_bit() is intentional, + * it avoids dirtying the cacheline if the queue is already active. + */ if (blk_mq_is_shared_tags(hctx->flags)) { struct request_queue *q = hctx->queue; - if (test_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags)) + if (test_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags) || + test_and_set_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags)) return; - set_bit(QUEUE_FLAG_HCTX_ACTIVE, &q->queue_flags); } else { - if (test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) + if (test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state) || + test_and_set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) return; - set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state); } users = atomic_inc_return(&hctx->tags->active_queues); diff --git a/block/blk-settings.c b/block/blk-settings.c index 896b4654ab00..4dd59059b788 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -915,6 +915,7 @@ static bool disk_has_partitions(struct gendisk *disk) void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model) { struct request_queue *q = disk->queue; + unsigned int old_model = q->limits.zoned; switch (model) { case BLK_ZONED_HM: @@ -952,7 +953,7 @@ void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model) */ blk_queue_zone_write_granularity(q, queue_logical_block_size(q)); - } else { + } else if (old_model != BLK_ZONED_NONE) { disk_clear_zone_settings(disk); } } diff --git a/block/blk-wbt.c b/block/blk-wbt.c index e49a48684532..9ec2a2f1eda3 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -730,14 +730,16 @@ void wbt_enable_default(struct gendisk *disk) { struct request_queue *q = disk->queue; struct rq_qos *rqos; - bool disable_flag = q->elevator && - test_bit(ELEVATOR_FLAG_DISABLE_WBT, &q->elevator->flags); + bool enable = IS_ENABLED(CONFIG_BLK_WBT_MQ); + + if (q->elevator && + test_bit(ELEVATOR_FLAG_DISABLE_WBT, &q->elevator->flags)) + enable = false; /* Throttling already enabled? */ rqos = wbt_rq_qos(q); if (rqos) { - if (!disable_flag && - RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT) + if (enable && RQWB(rqos)->enable_state == WBT_STATE_OFF_DEFAULT) RQWB(rqos)->enable_state = WBT_STATE_ON_DEFAULT; return; } @@ -746,7 +748,7 @@ void wbt_enable_default(struct gendisk *disk) if (!blk_queue_registered(q)) return; - if (queue_is_mq(q) && !disable_flag) + if (queue_is_mq(q) && enable) wbt_init(disk); } EXPORT_SYMBOL_GPL(wbt_enable_default); diff --git a/block/blk.h b/block/blk.h index 2da831103471..45547bcf1119 100644 --- a/block/blk.h +++ b/block/blk.h @@ -214,8 +214,7 @@ static inline bool integrity_req_gap_front_merge(struct request *req, bip_next->bip_vec[0].bv_offset); } -int blk_integrity_add(struct gendisk *disk); -void blk_integrity_del(struct gendisk *); +extern const struct attribute_group blk_integrity_attr_group; #else /* CONFIG_BLK_DEV_INTEGRITY */ static inline bool blk_integrity_merge_rq(struct request_queue *rq, struct request *r1, struct request *r2) @@ -248,13 +247,6 @@ static inline bool bio_integrity_endio(struct bio *bio) static inline void bio_integrity_free(struct bio *bio) { } -static inline int blk_integrity_add(struct gendisk *disk) -{ - return 0; -} -static inline void blk_integrity_del(struct gendisk *disk) -{ -} #endif /* CONFIG_BLK_DEV_INTEGRITY */ unsigned long blk_rq_timeout(unsigned long timeout); @@ -419,6 +411,8 @@ int bdev_resize_partition(struct gendisk *disk, int partno, sector_t start, sector_t length); void blk_drop_partitions(struct gendisk *disk); +void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors); + struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, struct lock_class_key *lkclass); diff --git a/block/bsg.c b/block/bsg.c index 30fcc865ef4f..7eca43f33d7f 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -245,7 +245,7 @@ static int __init bsg_init(void) dev_t devid; int ret; - bsg_class = class_create(THIS_MODULE, "bsg"); + bsg_class = class_create("bsg"); if (IS_ERR(bsg_class)) return PTR_ERR(bsg_class); bsg_class->devnode = bsg_devnode; diff --git a/block/fops.c b/block/fops.c index d2e6be4e3d1c..58d0aebc7313 100644 --- a/block/fops.c +++ b/block/fops.c @@ -678,6 +678,16 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start, return error; } +static int blkdev_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *bd_inode = bdev_file_inode(file); + + if (bdev_read_only(I_BDEV(bd_inode))) + return generic_file_readonly_mmap(file, vma); + + return generic_file_mmap(file, vma); +} + const struct file_operations def_blk_fops = { .open = blkdev_open, .release = blkdev_close, @@ -685,7 +695,7 @@ const struct file_operations def_blk_fops = { .read_iter = blkdev_read_iter, .write_iter = blkdev_write_iter, .iopoll = iocb_bio_iopoll, - .mmap = generic_file_mmap, + .mmap = blkdev_mmap, .fsync = blkdev_fsync, .unlocked_ioctl = blkdev_ioctl, #ifdef CONFIG_COMPAT diff --git a/block/genhd.c b/block/genhd.c index 2d58ac54043a..1cb489b927d5 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -57,12 +57,7 @@ static DEFINE_IDA(ext_devt_ida); void set_capacity(struct gendisk *disk, sector_t sectors) { - struct block_device *bdev = disk->part0; - - spin_lock(&bdev->bd_size_lock); - i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); - bdev->bd_nr_sectors = sectors; - spin_unlock(&bdev->bd_size_lock); + bdev_set_nr_sectors(disk->part0, sectors); } EXPORT_SYMBOL(set_capacity); @@ -475,12 +470,10 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, if (ret) goto out_device_del; - if (!sysfs_deprecated) { - ret = sysfs_create_link(block_depr, &ddev->kobj, - kobject_name(&ddev->kobj)); - if (ret) - goto out_device_del; - } + ret = sysfs_create_link(block_depr, &ddev->kobj, + kobject_name(&ddev->kobj)); + if (ret) + goto out_device_del; /* * avoid probable deadlock caused by allocating memory with @@ -489,15 +482,11 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, */ pm_runtime_set_memalloc_noio(ddev, true); - ret = blk_integrity_add(disk); - if (ret) - goto out_del_block_link; - disk->part0->bd_holder_dir = kobject_create_and_add("holders", &ddev->kobj); if (!disk->part0->bd_holder_dir) { ret = -ENOMEM; - goto out_del_integrity; + goto out_del_block_link; } disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); if (!disk->slave_dir) { @@ -560,11 +549,8 @@ out_put_slave_dir: disk->slave_dir = NULL; out_put_holder_dir: kobject_put(disk->part0->bd_holder_dir); -out_del_integrity: - blk_integrity_del(disk); out_del_block_link: - if (!sysfs_deprecated) - sysfs_remove_link(block_depr, dev_name(ddev)); + sysfs_remove_link(block_depr, dev_name(ddev)); out_device_del: device_del(ddev); out_free_ext_minor: @@ -624,7 +610,6 @@ void del_gendisk(struct gendisk *disk) if (WARN_ON_ONCE(!disk_live(disk) && !(disk->flags & GENHD_FL_HIDDEN))) return; - blk_integrity_del(disk); disk_del_events(disk); mutex_lock(&disk->open_mutex); @@ -666,8 +651,7 @@ void del_gendisk(struct gendisk *disk) part_stat_set_all(disk->part0, 0); disk->part0->bd_stamp = 0; - if (!sysfs_deprecated) - sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); + sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); device_del(disk_to_dev(disk)); @@ -912,7 +896,6 @@ static int __init genhd_device_init(void) { int error; - block_class.dev_kobj = sysfs_dev_block_kobj; error = class_register(&block_class); if (unlikely(error)) return error; @@ -921,8 +904,7 @@ static int __init genhd_device_init(void) register_blkdev(BLOCK_EXT_MAJOR, "blkext"); /* create top-level block dir */ - if (!sysfs_deprecated) - block_depr = kobject_create_and_add("block", NULL); + block_depr = kobject_create_and_add("block", NULL); return 0; } @@ -1161,6 +1143,9 @@ static const struct attribute_group *disk_attr_groups[] = { &disk_attr_group, #ifdef CONFIG_BLK_DEV_IO_TRACE &blk_trace_attr_group, +#endif +#ifdef CONFIG_BLK_DEV_INTEGRITY + &blk_integrity_attr_group, #endif NULL }; diff --git a/block/partitions/core.c b/block/partitions/core.c index 7b8ef6296abd..49e0496ff23c 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -85,14 +85,6 @@ static int (*check_part[])(struct parsed_partitions *) = { NULL }; -static void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors) -{ - spin_lock(&bdev->bd_size_lock); - i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT); - bdev->bd_nr_sectors = sectors; - spin_unlock(&bdev->bd_size_lock); -} - static struct parsed_partitions *allocate_partitions(struct gendisk *hd) { struct parsed_partitions *state; diff --git a/crypto/Kconfig b/crypto/Kconfig index 9c86f7045157..a0e080d5f6ae 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1395,6 +1395,9 @@ endif if ARM64 source "arch/arm64/crypto/Kconfig" endif +if LOONGARCH +source "arch/loongarch/crypto/Kconfig" +endif if MIPS source "arch/mips/crypto/Kconfig" endif diff --git a/crypto/acompress.c b/crypto/acompress.c index 82a290df2822..1c682810a484 100644 --- a/crypto/acompress.c +++ b/crypto/acompress.c @@ -125,7 +125,7 @@ static const struct crypto_type crypto_acomp_type = { #ifdef CONFIG_PROC_FS .show = crypto_acomp_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_acomp_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/aead.c b/crypto/aead.c index ffc48a7dfb34..d5ba204ebdbf 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -242,7 +242,7 @@ static const struct crypto_type crypto_aead_type = { #ifdef CONFIG_PROC_FS .show = crypto_aead_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_aead_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/ahash.c b/crypto/ahash.c index b8a607928e72..324651040446 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -509,7 +509,7 @@ static const struct crypto_type crypto_ahash_type = { #ifdef CONFIG_PROC_FS .show = crypto_ahash_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_ahash_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 186e762b509a..7960ceb528c3 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -98,7 +98,7 @@ static const struct crypto_type crypto_akcipher_type = { #ifdef CONFIG_PROC_FS .show = crypto_akcipher_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_akcipher_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/algapi.c b/crypto/algapi.c index d7eb8f9e9883..5e7cd603d489 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -961,6 +961,9 @@ EXPORT_SYMBOL_GPL(crypto_enqueue_request); void crypto_enqueue_request_head(struct crypto_queue *queue, struct crypto_async_request *request) { + if (unlikely(queue->qlen >= queue->max_qlen)) + queue->backlog = queue->backlog->prev; + queue->qlen++; list_add(&request->list, &queue->list); } diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 41a2f0eb4ce4..a5da8ccd353e 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -17,7 +17,6 @@ #include #include "asymmetric_keys.h" -MODULE_LICENSE("GPL"); const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { [VERIFYING_MODULE_SIGNATURE] = "mod sig", diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index eca5671ad3f2..50c933f86b21 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -380,9 +380,10 @@ int public_key_verify_signature(const struct public_key *pkey, struct crypto_wait cwait; struct crypto_akcipher *tfm; struct akcipher_request *req; - struct scatterlist src_sg[2]; + struct scatterlist src_sg; char alg_name[CRYPTO_MAX_ALG_NAME]; - char *key, *ptr; + char *buf, *ptr; + size_t buf_len; int ret; pr_devel("==>%s()\n", __func__); @@ -420,34 +421,37 @@ int public_key_verify_signature(const struct public_key *pkey, if (!req) goto error_free_tfm; - key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, - GFP_KERNEL); - if (!key) + buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, + sig->s_size + sig->digest_size); + + buf = kmalloc(buf_len, GFP_KERNEL); + if (!buf) goto error_free_req; - memcpy(key, pkey->key, pkey->keylen); - ptr = key + pkey->keylen; + memcpy(buf, pkey->key, pkey->keylen); + ptr = buf + pkey->keylen; ptr = pkey_pack_u32(ptr, pkey->algo); ptr = pkey_pack_u32(ptr, pkey->paramlen); memcpy(ptr, pkey->params, pkey->paramlen); if (pkey->key_is_private) - ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); + ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen); else - ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); + ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen); if (ret) - goto error_free_key; + goto error_free_buf; if (strcmp(pkey->pkey_algo, "sm2") == 0 && sig->data_size) { ret = cert_sig_digest_update(sig, tfm); if (ret) - goto error_free_key; + goto error_free_buf; } - sg_init_table(src_sg, 2); - sg_set_buf(&src_sg[0], sig->s, sig->s_size); - sg_set_buf(&src_sg[1], sig->digest, sig->digest_size); - akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size, + memcpy(buf, sig->s, sig->s_size); + memcpy(buf + sig->s_size, sig->digest, sig->digest_size); + + sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size); + akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size, sig->digest_size); crypto_init_wait(&cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | @@ -455,8 +459,8 @@ int public_key_verify_signature(const struct public_key *pkey, crypto_req_done, &cwait); ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); -error_free_key: - kfree(key); +error_free_buf: + kfree(buf); error_free_req: akcipher_request_free(req); error_free_tfm: diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c index 21f791615114..74fcc0897041 100644 --- a/crypto/crypto_engine.c +++ b/crypto/crypto_engine.c @@ -129,9 +129,6 @@ start_request: if (!engine->retry_support) engine->cur_req = async_req; - if (backlog) - crypto_request_complete(backlog, -EINPROGRESS); - if (engine->busy) was_busy = true; else @@ -217,6 +214,9 @@ req_err_2: crypto_request_complete(async_req, ret); retry: + if (backlog) + crypto_request_complete(backlog, -EINPROGRESS); + /* If retry mechanism is supported, send new requests to engine */ if (engine->retry_support) { spin_lock_irqsave(&engine->queue_lock, flags); diff --git a/crypto/kpp.c b/crypto/kpp.c index 74f2e8e918fa..33d44e59387f 100644 --- a/crypto/kpp.c +++ b/crypto/kpp.c @@ -96,7 +96,7 @@ static const struct crypto_type crypto_kpp_type = { #ifdef CONFIG_PROC_FS .show = crypto_kpp_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_kpp_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/rng.c b/crypto/rng.c index ffde0f64fb25..279dffdebf59 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -118,7 +118,7 @@ static const struct crypto_type crypto_rng_type = { #ifdef CONFIG_PROC_FS .show = crypto_rng_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_rng_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/scompress.c b/crypto/scompress.c index 24138b42a648..442a82c9de7d 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -240,7 +240,7 @@ static const struct crypto_type crypto_scomp_type = { #ifdef CONFIG_PROC_FS .show = crypto_scomp_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_scomp_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/shash.c b/crypto/shash.c index 5845b7d59b2f..717b42df3495 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -548,7 +548,7 @@ static const struct crypto_type crypto_shash_type = { #ifdef CONFIG_PROC_FS .show = crypto_shash_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_shash_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 6caca02d7e55..7b275716cf4e 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -776,7 +776,7 @@ static const struct crypto_type crypto_skcipher_type = { #ifdef CONFIG_PROC_FS .show = crypto_skcipher_show, #endif -#ifdef CONFIG_CRYPTO_USER +#if IS_ENABLED(CONFIG_CRYPTO_USER) .report = crypto_skcipher_report, #endif #ifdef CONFIG_CRYPTO_STATS diff --git a/drivers/Kconfig b/drivers/Kconfig index 968bd0a6fd78..514ae6b24cb2 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -241,4 +241,6 @@ source "drivers/peci/Kconfig" source "drivers/hte/Kconfig" +source "drivers/cdx/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 20b118dca999..7241d80a7b29 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -194,3 +194,4 @@ obj-$(CONFIG_MOST) += most/ obj-$(CONFIG_PECI) += peci/ obj-$(CONFIG_HTE) += hte/ obj-$(CONFIG_DRM_ACCEL) += accel/ +obj-$(CONFIG_CDX_BUS) += cdx/ diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index 1b69824286fd..4a9baf02439e 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -34,7 +34,7 @@ static char *accel_devnode(const struct device *dev, umode_t *mode) static int accel_sysfs_init(void) { - accel_class = class_create(THIS_MODULE, "accel"); + accel_class = class_create("accel"); if (IS_ERR(accel_class)) return PTR_ERR(accel_class); diff --git a/drivers/accel/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c index a4b3f50f1cba..d9df64e75f33 100644 --- a/drivers/accel/habanalabs/common/habanalabs_drv.c +++ b/drivers/accel/habanalabs/common/habanalabs_drv.c @@ -696,7 +696,7 @@ static int __init hl_init(void) hl_major = MAJOR(dev); - hl_class = class_create(THIS_MODULE, HL_NAME); + hl_class = class_create(HL_NAME); if (IS_ERR(hl_class)) { pr_err("failed to allocate class\n"); rc = PTR_ERR(hl_class); diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index 9f216eb6f76e..5c57f7b4494e 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -997,14 +997,34 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u struct xfer_queue_elem elem; struct wire_msg *out_buf; struct wrapper_msg *w; + long ret = -EAGAIN; + int xfer_count = 0; int retry_count; - long ret; if (qdev->in_reset) { mutex_unlock(&qdev->cntl_mutex); return ERR_PTR(-ENODEV); } + /* Attempt to avoid a partial commit of a message */ + list_for_each_entry(w, &wrappers->list, list) + xfer_count++; + + for (retry_count = 0; retry_count < QAIC_MHI_RETRY_MAX; retry_count++) { + if (xfer_count <= mhi_get_free_desc_count(qdev->cntl_ch, DMA_TO_DEVICE)) { + ret = 0; + break; + } + msleep_interruptible(QAIC_MHI_RETRY_WAIT_MS); + if (signal_pending(current)) + break; + } + + if (ret) { + mutex_unlock(&qdev->cntl_mutex); + return ERR_PTR(ret); + } + elem.seq_num = seq_num; elem.buf = NULL; init_completion(&elem.xfer_done); @@ -1038,16 +1058,9 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u list_for_each_entry(w, &wrappers->list, list) { kref_get(&w->ref_count); retry_count = 0; -retry: ret = mhi_queue_buf(qdev->cntl_ch, DMA_TO_DEVICE, &w->msg, w->len, list_is_last(&w->list, &wrappers->list) ? MHI_EOT : MHI_CHAIN); if (ret) { - if (ret == -EAGAIN && retry_count++ < QAIC_MHI_RETRY_MAX) { - msleep_interruptible(QAIC_MHI_RETRY_WAIT_MS); - if (!signal_pending(current)) - goto retry; - } - qdev->cntl_lost_buf = true; kref_put(&w->ref_count, free_wrapper); mutex_unlock(&qdev->cntl_mutex); @@ -1249,7 +1262,7 @@ dma_cont_failed: int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct qaic_manage_msg *user_msg; + struct qaic_manage_msg *user_msg = data; struct qaic_device *qdev; struct manage_msg *msg; struct qaic_user *usr; @@ -1258,6 +1271,9 @@ int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ int usr_rcu_id; int ret; + if (user_msg->len > QAIC_MANAGE_MAX_MSG_LENGTH) + return -EINVAL; + usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); @@ -1275,13 +1291,6 @@ int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ return -ENODEV; } - user_msg = data; - - if (user_msg->len > QAIC_MANAGE_MAX_MSG_LENGTH) { - ret = -EINVAL; - goto out; - } - msg = kzalloc(QAIC_MANAGE_MAX_MSG_LENGTH + sizeof(*msg), GFP_KERNEL); if (!msg) { ret = -ENOMEM; diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index c0a574cd1b35..e42c1f9ffff8 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -591,7 +591,7 @@ static int qaic_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc struct qaic_bo *bo = to_qaic_bo(obj); unsigned long offset = 0; struct scatterlist *sg; - int ret; + int ret = 0; if (obj->import_attach) return -EINVAL; @@ -663,6 +663,10 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (args->pad) return -EINVAL; + size = PAGE_ALIGN(args->size); + if (size == 0) + return -EINVAL; + usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); if (!usr->qddev) { @@ -677,12 +681,6 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi goto unlock_dev_srcu; } - size = PAGE_ALIGN(args->size); - if (size == 0) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - bo = qaic_alloc_init_bo(); if (IS_ERR(bo)) { ret = PTR_ERR(bo); @@ -926,8 +924,8 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi { struct qaic_attach_slice_entry *slice_ent; struct qaic_attach_slice *args = data; + int rcu_id, usr_rcu_id, qdev_rcu_id; struct dma_bridge_chan *dbc; - int usr_rcu_id, qdev_rcu_id; struct drm_gem_object *obj; struct qaic_device *qdev; unsigned long arg_size; @@ -936,6 +934,22 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi struct qaic_bo *bo; int ret; + if (args->hdr.count == 0) + return -EINVAL; + + arg_size = args->hdr.count * sizeof(*slice_ent); + if (arg_size / args->hdr.count != sizeof(*slice_ent)) + return -EINVAL; + + if (args->hdr.size == 0) + return -EINVAL; + + if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE)) + return -EINVAL; + + if (args->data == 0) + return -EINVAL; + usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); if (!usr->qddev) { @@ -950,43 +964,11 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi goto unlock_dev_srcu; } - if (args->hdr.count == 0) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - - arg_size = args->hdr.count * sizeof(*slice_ent); - if (arg_size / args->hdr.count != sizeof(*slice_ent)) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - if (args->hdr.dbc_id >= qdev->num_dbc) { ret = -EINVAL; goto unlock_dev_srcu; } - if (args->hdr.size == 0) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - - if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE)) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - - dbc = &qdev->dbc[args->hdr.dbc_id]; - if (dbc->usr != usr) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - - if (args->data == 0) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - user_data = u64_to_user_ptr(args->data); slice_ent = kzalloc(arg_size, GFP_KERNEL); @@ -1013,9 +995,21 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi bo = to_qaic_bo(obj); + if (bo->sliced) { + ret = -EINVAL; + goto put_bo; + } + + dbc = &qdev->dbc[args->hdr.dbc_id]; + rcu_id = srcu_read_lock(&dbc->ch_lock); + if (dbc->usr != usr) { + ret = -EINVAL; + goto unlock_ch_srcu; + } + ret = qaic_prepare_bo(qdev, bo, &args->hdr); if (ret) - goto put_bo; + goto unlock_ch_srcu; ret = qaic_attach_slicing_bo(qdev, bo, &args->hdr, slice_ent); if (ret) @@ -1025,6 +1019,7 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, args->hdr.dir); bo->dbc = dbc; + srcu_read_unlock(&dbc->ch_lock, rcu_id); drm_gem_object_put(obj); srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); srcu_read_unlock(&usr->qddev_lock, usr_rcu_id); @@ -1033,6 +1028,8 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi unprepare_bo: qaic_unprepare_bo(qdev, bo); +unlock_ch_srcu: + srcu_read_unlock(&dbc->ch_lock, rcu_id); put_bo: drm_gem_object_put(obj); free_slice_ent: @@ -1316,7 +1313,6 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr received_ts = ktime_get_ns(); size = is_partial ? sizeof(*pexec) : sizeof(*exec); - n = (unsigned long)size * args->hdr.count; if (args->hdr.count == 0 || n / args->hdr.count != size) return -EINVAL; @@ -1665,6 +1661,9 @@ int qaic_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file int rcu_id; int ret; + if (args->pad != 0) + return -EINVAL; + usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); if (!usr->qddev) { @@ -1679,11 +1678,6 @@ int qaic_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file goto unlock_dev_srcu; } - if (args->pad != 0) { - ret = -EINVAL; - goto unlock_dev_srcu; - } - if (args->dbc_id >= qdev->num_dbc) { ret = -EINVAL; goto unlock_dev_srcu; @@ -1855,6 +1849,11 @@ void wakeup_dbc(struct qaic_device *qdev, u32 dbc_id) dbc->usr = NULL; empty_xfer_list(qdev, dbc); synchronize_srcu(&dbc->ch_lock); + /* + * Threads holding channel lock, may add more elements in the xfer_list. + * Flush out these elements from xfer_list. + */ + empty_xfer_list(qdev, dbc); } void release_dbc(struct qaic_device *qdev, u32 dbc_id) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index ff80eb571729..2d0828db28d8 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -262,8 +262,8 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id) static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) { + u16 major = -1, minor = -1; struct qaic_device *qdev; - u16 major, minor; int ret; /* diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index c4d54a5326b1..06b43b678d6e 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -24,7 +24,6 @@ MODULE_AUTHOR("samuel.thibault@ens-lyon.org"); MODULE_DESCRIPTION("braille device"); -MODULE_LICENSE("GPL"); /* * Braille device support part. diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c index 3843d2576d3f..c5598b6d5db8 100644 --- a/drivers/acpi/acpi_lpit.c +++ b/drivers/acpi/acpi_lpit.c @@ -98,6 +98,12 @@ EXPORT_SYMBOL_GPL(lpit_read_residency_count_address); static void lpit_update_residency(struct lpit_residency_info *info, struct acpi_lpit_native *lpit_native) { + struct device *dev_root = bus_get_dev_root(&cpu_subsys); + + /* Silently fail, if cpuidle attribute group is not present */ + if (!dev_root) + return; + info->frequency = lpit_native->counter_frequency ? lpit_native->counter_frequency : tsc_khz * 1000; if (!info->frequency) @@ -108,18 +114,18 @@ static void lpit_update_residency(struct lpit_residency_info *info, info->iomem_addr = ioremap(info->gaddr.address, info->gaddr.bit_width / 8); if (!info->iomem_addr) - return; + goto exit; - /* Silently fail, if cpuidle attribute group is not present */ - sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj, + sysfs_add_file_to_group(&dev_root->kobj, &dev_attr_low_power_idle_system_residency_us.attr, "cpuidle"); } else if (info->gaddr.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { - /* Silently fail, if cpuidle attribute group is not present */ - sysfs_add_file_to_group(&cpu_subsys.dev_root->kobj, + sysfs_add_file_to_group(&dev_root->kobj, &dev_attr_low_power_idle_cpu_residency_us.attr, "cpuidle"); } +exit: + put_device(dev_root); } static void lpit_process(u64 begin, u64 end) diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 1d6ef9654725..67c2c3b959e1 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -7,7 +7,6 @@ #ifndef APEI_INTERNAL_H #define APEI_INTERNAL_H -#include #include struct apei_exec_context; @@ -130,10 +129,5 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) return sizeof(*estatus) + estatus->data_length; } -void cper_estatus_print(const char *pfx, - const struct acpi_hest_generic_status *estatus); -int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus); -int cper_estatus_check(const struct acpi_hest_generic_status *estatus); - int apei_osc_setup(void); #endif diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c index c23eb75866d0..7514e38d5640 100644 --- a/drivers/acpi/apei/bert.c +++ b/drivers/acpi/apei/bert.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "apei-internal.h" diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c32a06bcac0c..d161ff707de4 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -810,9 +810,10 @@ static bool acpi_of_modalias(struct acpi_device *adev, * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias buffer * - * This is a counterpart of of_modalias_node() for struct acpi_device objects. - * If there is a compatible string for @adev, it will be copied to @modalias - * with the vendor prefix stripped; otherwise, @default_id will be used. + * This is a counterpart of of_alias_from_compatible() for struct acpi_device + * objects. If there is a compatible string for @adev, it will be copied to + * @modalias with the vendor prefix stripped; otherwise, @default_id will be + * used. */ void acpi_set_modalias(struct acpi_device *adev, const char *default_id, char *modalias, size_t len) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 23507d29f000..c2c70139c4f1 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -23,6 +23,7 @@ #define pr_fmt(fmt) "ACPI: PM: " fmt +#include #include #include #include @@ -1022,6 +1023,21 @@ void acpi_resume_power_resources(void) } #endif +static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = { + { + /* + * The Toshiba Click Mini has a CPR3 power-resource which must + * be on for the touchscreen to work, but which is not in any + * _PR? lists. The other 2 affected power-resources are no-ops. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"), + }, + }, + {} +}; + /** * acpi_turn_off_unused_power_resources - Turn off power resources not in use. */ @@ -1029,6 +1045,9 @@ void acpi_turn_off_unused_power_resources(void) { struct acpi_power_resource *resource; + if (dmi_check_system(dmi_leave_unused_power_resources_on)) + return; + mutex_lock(&power_resource_list_lock); list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index e8492b3a393a..0800a9d77558 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -516,6 +516,17 @@ static const struct dmi_system_id maingear_laptop[] = { { } }; +static const struct dmi_system_id lg_laptop[] = { + { + .ident = "LG Electronics 17U70P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + DMI_MATCH(DMI_BOARD_NAME, "17U70P"), + }, + }, + { } +}; + struct irq_override_cmp { const struct dmi_system_id *system; unsigned char irq; @@ -532,6 +543,7 @@ static const struct irq_override_cmp override_table[] = { { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, + { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, }; static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index ec002ecfe4cf..4720a3649a61 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -786,6 +786,32 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .critical = acpi_thermal_zone_device_critical, }; +static int acpi_thermal_zone_sysfs_add(struct acpi_thermal *tz) +{ + struct device *tzdev = thermal_zone_device(tz->thermal_zone); + int ret; + + ret = sysfs_create_link(&tz->device->dev.kobj, + &tzdev->kobj, "thermal_zone"); + if (ret) + return ret; + + ret = sysfs_create_link(&tzdev->kobj, + &tz->device->dev.kobj, "device"); + if (ret) + sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); + + return ret; +} + +static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz) +{ + struct device *tzdev = thermal_zone_device(tz->thermal_zone); + + sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); + sysfs_remove_link(&tzdev->kobj, "device"); +} + static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { int trips = 0; @@ -819,21 +845,15 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (IS_ERR(tz->thermal_zone)) return -ENODEV; - result = sysfs_create_link(&tz->device->dev.kobj, - &tz->thermal_zone->device.kobj, "thermal_zone"); + result = acpi_thermal_zone_sysfs_add(tz); if (result) goto unregister_tzd; - result = sysfs_create_link(&tz->thermal_zone->device.kobj, - &tz->device->dev.kobj, "device"); - if (result) - goto remove_tz_link; - status = acpi_bus_attach_private_data(tz->device->handle, tz->thermal_zone); if (ACPI_FAILURE(status)) { result = -ENODEV; - goto remove_dev_link; + goto remove_links; } result = thermal_zone_device_enable(tz->thermal_zone); @@ -847,10 +867,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) acpi_bus_detach: acpi_bus_detach_private_data(tz->device->handle); -remove_dev_link: - sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); -remove_tz_link: - sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); +remove_links: + acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: thermal_zone_device_unregister(tz->thermal_zone); @@ -859,8 +877,7 @@ unregister_tzd: static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) { - sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); - sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); + acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); tz->thermal_zone = NULL; acpi_bus_detach_private_data(tz->device->handle); diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 69ef2d9710c2..bcc25d457581 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -293,20 +293,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, }, - /* - * Older models with nvidia GPU which need acpi_video backlight - * control and where the old nvidia binary driver series does not - * call acpi_video_register_backlight(). - */ - { - .callback = video_detect_force_video, - /* ThinkPad W530 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"), - }, - }, - /* * These models have a working acpi_video backlight control, and using * native backlight causes a regression where backlight does not work diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c index 8812ecd03d55..45d0f16f374f 100644 --- a/drivers/acpi/x86/apple.c +++ b/drivers/acpi/x86/apple.c @@ -71,13 +71,16 @@ void acpi_extract_apple_properties(struct acpi_device *adev) if ( key->type != ACPI_TYPE_STRING || (val->type != ACPI_TYPE_INTEGER && - val->type != ACPI_TYPE_BUFFER)) + val->type != ACPI_TYPE_BUFFER && + val->type != ACPI_TYPE_STRING)) continue; /* skip invalid properties */ __set_bit(i, valid); newsize += key->string.length + 1; if ( val->type == ACPI_TYPE_BUFFER) newsize += val->buffer.length; + else if (val->type == ACPI_TYPE_STRING) + newsize += val->string.length + 1; } numvalid = bitmap_weight(valid, numprops); @@ -119,6 +122,12 @@ void acpi_extract_apple_properties(struct acpi_device *adev) newprops[v].type = val->type; if (val->type == ACPI_TYPE_INTEGER) { newprops[v].integer.value = val->integer.value; + } else if (val->type == ACPI_TYPE_STRING) { + newprops[v].string.length = val->string.length; + newprops[v].string.pointer = free_space; + memcpy(free_space, val->string.pointer, + val->string.length); + free_space += val->string.length + 1; } else { newprops[v].buffer.length = val->buffer.length; newprops[v].buffer.pointer = free_space; diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index ba420a28a4aa..9c2d6f35f88a 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -143,6 +143,16 @@ static const struct override_status_id override_status_ids[] = { DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), }), + + /* + * The LSM303D on the Lenovo Yoga Tablet 2 series is present + * as both ACCL0001 and MAGN0001. As we can only ever register an + * i2c client for one of them, ignore MAGN0001. + */ + NOT_PRESENT_ENTRY_HID("MAGN0001", "1", ATOM_SILVERMONT, { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"), + }), }; bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index fb56bfc45096..8fb7672021ee 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1934,24 +1934,23 @@ static void binder_deferred_fd_close(int fd) static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_thread *thread, struct binder_buffer *buffer, - binder_size_t failed_at, + binder_size_t off_end_offset, bool is_failure) { int debug_id = buffer->debug_id; - binder_size_t off_start_offset, buffer_offset, off_end_offset; + binder_size_t off_start_offset, buffer_offset; binder_debug(BINDER_DEBUG_TRANSACTION, "%d buffer release %d, size %zd-%zd, failed at %llx\n", proc->pid, buffer->debug_id, buffer->data_size, buffer->offsets_size, - (unsigned long long)failed_at); + (unsigned long long)off_end_offset); if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); off_start_offset = ALIGN(buffer->data_size, sizeof(void *)); - off_end_offset = is_failure && failed_at ? failed_at : - off_start_offset + buffer->offsets_size; + for (buffer_offset = off_start_offset; buffer_offset < off_end_offset; buffer_offset += sizeof(binder_size_t)) { struct binder_object_header *hdr; @@ -2111,6 +2110,21 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, } } +/* Clean up all the objects in the buffer */ +static inline void binder_release_entire_buffer(struct binder_proc *proc, + struct binder_thread *thread, + struct binder_buffer *buffer, + bool is_failure) +{ + binder_size_t off_end_offset; + + off_end_offset = ALIGN(buffer->data_size, sizeof(void *)); + off_end_offset += buffer->offsets_size; + + binder_transaction_buffer_release(proc, thread, buffer, + off_end_offset, is_failure); +} + static int binder_translate_binder(struct flat_binder_object *fp, struct binder_transaction *t, struct binder_thread *thread) @@ -2806,7 +2820,7 @@ static int binder_proc_transaction(struct binder_transaction *t, t_outdated->buffer = NULL; buffer->transaction = NULL; trace_binder_transaction_update_buffer_release(buffer); - binder_transaction_buffer_release(proc, NULL, buffer, 0, 0); + binder_release_entire_buffer(proc, NULL, buffer, false); binder_alloc_free_buf(&proc->alloc, buffer); kfree(t_outdated); binder_stats_deleted(BINDER_STAT_TRANSACTION); @@ -3775,7 +3789,7 @@ binder_free_buf(struct binder_proc *proc, binder_node_inner_unlock(buf_node); } trace_binder_transaction_buffer_release(buffer); - binder_transaction_buffer_release(proc, thread, buffer, 0, is_failure); + binder_release_entire_buffer(proc, thread, buffer, is_failure); binder_alloc_free_buf(&proc->alloc, buffer); } diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 55a3c3c2409f..662a2a2e2e84 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -212,8 +212,8 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, mm = alloc->mm; if (mm) { - mmap_read_lock(mm); - vma = vma_lookup(mm, alloc->vma_addr); + mmap_write_lock(mm); + vma = alloc->vma; } if (!vma && need_mm) { @@ -270,7 +270,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, trace_binder_alloc_page_end(alloc, index); } if (mm) { - mmap_read_unlock(mm); + mmap_write_unlock(mm); mmput(mm); } return 0; @@ -303,21 +303,24 @@ err_page_ptr_cleared: } err_no_vma: if (mm) { - mmap_read_unlock(mm); + mmap_write_unlock(mm); mmput(mm); } return vma ? -ENOMEM : -ESRCH; } +static inline void binder_alloc_set_vma(struct binder_alloc *alloc, + struct vm_area_struct *vma) +{ + /* pairs with smp_load_acquire in binder_alloc_get_vma() */ + smp_store_release(&alloc->vma, vma); +} + static inline struct vm_area_struct *binder_alloc_get_vma( struct binder_alloc *alloc) { - struct vm_area_struct *vma = NULL; - - if (alloc->vma_addr) - vma = vma_lookup(alloc->mm, alloc->vma_addr); - - return vma; + /* pairs with smp_store_release in binder_alloc_set_vma() */ + return smp_load_acquire(&alloc->vma); } static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) @@ -380,15 +383,13 @@ static struct binder_buffer *binder_alloc_new_buf_locked( size_t size, data_offsets_size; int ret; - mmap_read_lock(alloc->mm); + /* Check binder_alloc is fully initialized */ if (!binder_alloc_get_vma(alloc)) { - mmap_read_unlock(alloc->mm); binder_alloc_debug(BINDER_DEBUG_USER_ERROR, "%d: binder_alloc_buf, no vma\n", alloc->pid); return ERR_PTR(-ESRCH); } - mmap_read_unlock(alloc->mm); data_offsets_size = ALIGN(data_size, sizeof(void *)) + ALIGN(offsets_size, sizeof(void *)); @@ -778,7 +779,9 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, buffer->free = 1; binder_insert_free_buffer(alloc, buffer); alloc->free_async_space = alloc->buffer_size / 2; - alloc->vma_addr = vma->vm_start; + + /* Signal binder_alloc is fully initialized */ + binder_alloc_set_vma(alloc, vma); return 0; @@ -808,8 +811,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) buffers = 0; mutex_lock(&alloc->mutex); - BUG_ON(alloc->vma_addr && - vma_lookup(alloc->mm, alloc->vma_addr)); + BUG_ON(alloc->vma); while ((n = rb_first(&alloc->allocated_buffers))) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -916,25 +918,17 @@ void binder_alloc_print_pages(struct seq_file *m, * Make sure the binder_alloc is fully initialized, otherwise we might * read inconsistent state. */ - - mmap_read_lock(alloc->mm); - if (binder_alloc_get_vma(alloc) == NULL) { - mmap_read_unlock(alloc->mm); - goto uninitialized; + if (binder_alloc_get_vma(alloc) != NULL) { + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + page = &alloc->pages[i]; + if (!page->page_ptr) + free++; + else if (list_empty(&page->lru)) + active++; + else + lru++; + } } - - mmap_read_unlock(alloc->mm); - for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { - page = &alloc->pages[i]; - if (!page->page_ptr) - free++; - else if (list_empty(&page->lru)) - active++; - else - lru++; - } - -uninitialized: mutex_unlock(&alloc->mutex); seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high); @@ -969,7 +963,7 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) */ void binder_alloc_vma_close(struct binder_alloc *alloc) { - alloc->vma_addr = 0; + binder_alloc_set_vma(alloc, NULL); } /** diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 0f811ac4bcff..138d1d5af9ce 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -75,7 +75,7 @@ struct binder_lru_page { /** * struct binder_alloc - per-binder proc state for binder allocator * @mutex: protects binder_alloc fields - * @vma_addr: vm_area_struct->vm_start passed to mmap_handler + * @vma: vm_area_struct passed to mmap_handler * (invariant after mmap) * @mm: copy of task->mm (invariant after open) * @buffer: base of per-proc address space mapped via mmap @@ -99,7 +99,7 @@ struct binder_lru_page { */ struct binder_alloc { struct mutex mutex; - unsigned long vma_addr; + struct vm_area_struct *vma; struct mm_struct *mm; void __user *buffer; struct list_head buffers; diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c index 43a881073a42..c2b323bc3b3a 100644 --- a/drivers/android/binder_alloc_selftest.c +++ b/drivers/android/binder_alloc_selftest.c @@ -287,7 +287,7 @@ void binder_selftest_alloc(struct binder_alloc *alloc) if (!binder_selftest_run) return; mutex_lock(&binder_selftest_lock); - if (!binder_selftest_run || !alloc->vma_addr) + if (!binder_selftest_run || !alloc->vma) goto done; pr_info("STARTED\n"); binder_selftest_alloc_offset(alloc, end_offset, 0); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7bb12deab70c..8ce90284eb34 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2694,18 +2694,36 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) return 0; } -static struct ata_device *ata_find_dev(struct ata_port *ap, int devno) +static struct ata_device *ata_find_dev(struct ata_port *ap, unsigned int devno) { - if (!sata_pmp_attached(ap)) { - if (likely(devno >= 0 && - devno < ata_link_max_devices(&ap->link))) + /* + * For the non-PMP case, ata_link_max_devices() returns 1 (SATA case), + * or 2 (IDE master + slave case). However, the former case includes + * libsas hosted devices which are numbered per scsi host, leading + * to devno potentially being larger than 0 but with each struct + * ata_device having its own struct ata_port and struct ata_link. + * To accommodate these, ignore devno and always use device number 0. + */ + if (likely(!sata_pmp_attached(ap))) { + int link_max_devices = ata_link_max_devices(&ap->link); + + if (link_max_devices == 1) + return &ap->link.device[0]; + + if (devno < link_max_devices) return &ap->link.device[devno]; - } else { - if (likely(devno >= 0 && - devno < ap->nr_pmp_links)) - return &ap->pmp_link[devno].device[0]; + + return NULL; } + /* + * For PMP-attached devices, the device number corresponds to C + * (channel) of SCSI [H:C:I:L], indicating the port pmp link + * for the device. + */ + if (devno < ap->nr_pmp_links) + return &ap->pmp_link[devno].device[0]; + return NULL; } diff --git a/drivers/ata/pata_parport/pata_parport.c b/drivers/ata/pata_parport/pata_parport.c index ef2c29a75269..1af64d435d3c 100644 --- a/drivers/ata/pata_parport/pata_parport.c +++ b/drivers/ata/pata_parport/pata_parport.c @@ -557,8 +557,7 @@ void pata_parport_unregister_driver(struct pi_protocol *pr) } EXPORT_SYMBOL_GPL(pata_parport_unregister_driver); -static ssize_t new_device_store(struct bus_type *bus, const char *buf, - size_t count) +static ssize_t new_device_store(const struct bus_type *bus, const char *buf, size_t count) { char port[12] = "auto"; char protocol[8] = "auto"; @@ -632,8 +631,7 @@ static void pi_remove_one(struct device *dev) /* pata_parport_dev_release will do ida_free(dev->id) and kfree(pi) */ } -static ssize_t delete_device_store(struct bus_type *bus, const char *buf, - size_t count) +static ssize_t delete_device_store(const struct bus_type *bus, const char *buf, size_t count) { struct device *dev; diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 6f04b831a5c0..2b8fd6bb7da0 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -230,4 +230,16 @@ config GENERIC_ARCH_NUMA Enable support for generic NUMA implementation. Currently, RISC-V and ARM64 use it. +config FW_DEVLINK_SYNC_STATE_TIMEOUT + bool "sync_state() behavior defaults to timeout instead of strict" + help + This is build time equivalent of adding kernel command line parameter + "fw_devlink.sync_state=timeout". Give up waiting on consumers and + call sync_state() on any devices that haven't yet received their + sync_state() calls after deferred_probe_timeout has expired or by + late_initcall() if !CONFIG_MODULES. You should almost always want to + select N here unless you have already successfully tested with the + command line option on every system/board your kernel is expected to + work on. + endmenu diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index b1c1dd38ab01..b741b5ba82bd 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -835,18 +835,19 @@ void __init init_cpu_topology(void) if (ret) { /* * Discard anything that was parsed if we hit an error so we - * don't use partial information. + * don't use partial information. But do not return yet to give + * arch-specific early cache level detection a chance to run. */ reset_cpu_topology(); - return; } for_each_possible_cpu(cpu) { ret = fetch_cache_info(cpu); - if (ret) { + if (!ret) + continue; + else if (ret != -ENOENT) pr_err("Early cacheinfo failed, ret = %d\n", ret); - break; - } + return; } } diff --git a/drivers/base/base.h b/drivers/base/base.h index 726a12a244c0..eb4c0ace9242 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -27,11 +27,13 @@ * on this bus. * @bus - pointer back to the struct bus_type that this structure is associated * with. + * @dev_root: Default device to use as the parent. * * @glue_dirs - "glue" directory to put in-between the parent device to * avoid namespace conflicts * @class - pointer back to the struct class that this structure is associated * with. + * @lock_key: Lock class key for use by the lock validator * * This structure is the one that is the actual kobject allowing struct * bus_type/class to be statically allocated safely. Nothing outside of the @@ -48,10 +50,11 @@ struct subsys_private { struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; - struct bus_type *bus; + const struct bus_type *bus; + struct device *dev_root; struct kset glue_dirs; - struct class *class; + const struct class *class; struct lock_class_key lock_key; }; @@ -70,6 +73,8 @@ static inline void subsys_put(struct subsys_private *sp) kset_put(&sp->subsys); } +struct subsys_private *class_to_subsys(const struct class *class); + struct driver_private { struct kobject kobj; struct klist klist_devices; @@ -122,69 +127,73 @@ struct device_private { container_of(obj, struct device_private, knode_class) /* initialisation functions */ -extern int devices_init(void); -extern int buses_init(void); -extern int classes_init(void); -extern int firmware_init(void); +int devices_init(void); +int buses_init(void); +int classes_init(void); +int firmware_init(void); #ifdef CONFIG_SYS_HYPERVISOR -extern int hypervisor_init(void); +int hypervisor_init(void); #else static inline int hypervisor_init(void) { return 0; } #endif -extern int platform_bus_init(void); -extern void cpu_dev_init(void); -extern void container_dev_init(void); +int platform_bus_init(void); +void cpu_dev_init(void); +void container_dev_init(void); #ifdef CONFIG_AUXILIARY_BUS -extern void auxiliary_bus_init(void); +void auxiliary_bus_init(void); #else static inline void auxiliary_bus_init(void) { } #endif struct kobject *virtual_device_parent(struct device *dev); -extern int bus_add_device(struct device *dev); -extern void bus_probe_device(struct device *dev); -extern void bus_remove_device(struct device *dev); +int bus_add_device(struct device *dev); +void bus_probe_device(struct device *dev); +void bus_remove_device(struct device *dev); void bus_notify(struct device *dev, enum bus_notifier_event value); bool bus_is_registered(const struct bus_type *bus); -extern int bus_add_driver(struct device_driver *drv); -extern void bus_remove_driver(struct device_driver *drv); -extern void device_release_driver_internal(struct device *dev, - struct device_driver *drv, - struct device *parent); +int bus_add_driver(struct device_driver *drv); +void bus_remove_driver(struct device_driver *drv); +void device_release_driver_internal(struct device *dev, struct device_driver *drv, + struct device *parent); -extern void driver_detach(struct device_driver *drv); -extern void driver_deferred_probe_del(struct device *dev); -extern void device_set_deferred_probe_reason(const struct device *dev, - struct va_format *vaf); +void driver_detach(struct device_driver *drv); +void driver_deferred_probe_del(struct device *dev); +void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf); static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1; } -extern int driver_add_groups(struct device_driver *drv, - const struct attribute_group **groups); -extern void driver_remove_groups(struct device_driver *drv, - const struct attribute_group **groups); +static inline void dev_sync_state(struct device *dev) +{ + if (dev->bus->sync_state) + dev->bus->sync_state(dev); + else if (dev->driver && dev->driver->sync_state) + dev->driver->sync_state(dev); +} + +int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups); +void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); void device_driver_detach(struct device *dev); -extern int devres_release_all(struct device *dev); -extern void device_block_probing(void); -extern void device_unblock_probing(void); -extern void deferred_probe_extend_timeout(void); -extern void driver_deferred_probe_trigger(void); +int devres_release_all(struct device *dev); +void device_block_probing(void); +void device_unblock_probing(void); +void deferred_probe_extend_timeout(void); +void driver_deferred_probe_trigger(void); const char *device_get_devnode(const struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid, const char **tmp); /* /sys/devices directory */ extern struct kset *devices_kset; -extern void devices_kset_move_last(struct device *dev); +void devices_kset_move_last(struct device *dev); #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) -extern void module_add_driver(struct module *mod, struct device_driver *drv); -extern void module_remove_driver(struct device_driver *drv); +void module_add_driver(struct module *mod, struct device_driver *drv); +void module_remove_driver(struct device_driver *drv); #else static inline void module_add_driver(struct module *mod, struct device_driver *drv) { } @@ -192,23 +201,34 @@ static inline void module_remove_driver(struct device_driver *drv) { } #endif #ifdef CONFIG_DEVTMPFS -extern int devtmpfs_init(void); +int devtmpfs_init(void); #else static inline int devtmpfs_init(void) { return 0; } #endif +#ifdef CONFIG_BLOCK +extern struct class block_class; +static inline bool is_blockdev(struct device *dev) +{ + return dev->class == &block_class; +} +#else +static inline bool is_blockdev(struct device *dev) { return false; } +#endif + /* Device links support */ -extern int device_links_read_lock(void); -extern void device_links_read_unlock(int idx); -extern int device_links_read_lock_held(void); -extern int device_links_check_suppliers(struct device *dev); -extern void device_links_force_bind(struct device *dev); -extern void device_links_driver_bound(struct device *dev); -extern void device_links_driver_cleanup(struct device *dev); -extern void device_links_no_driver(struct device *dev); -extern bool device_links_busy(struct device *dev); -extern void device_links_unbind_consumers(struct device *dev); -extern void fw_devlink_drivers_done(void); +int device_links_read_lock(void); +void device_links_read_unlock(int idx); +int device_links_read_lock_held(void); +int device_links_check_suppliers(struct device *dev); +void device_links_force_bind(struct device *dev); +void device_links_driver_bound(struct device *dev); +void device_links_driver_cleanup(struct device *dev); +void device_links_no_driver(struct device *dev); +bool device_links_busy(struct device *dev); +void device_links_unbind_consumers(struct device *dev); +void fw_devlink_drivers_done(void); +void fw_devlink_probing_done(void); /* device pm support */ void device_pm_move_to_tail(struct device *dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index dd4b82d7510f..84a21084d67d 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -84,7 +84,7 @@ done: return sp; } -static struct bus_type *bus_get(struct bus_type *bus) +static const struct bus_type *bus_get(const struct bus_type *bus) { struct subsys_private *sp = bus_to_subsys(bus); @@ -233,7 +233,7 @@ static const struct kset_uevent_ops bus_uevent_ops = { static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = bus_get(drv->bus); + const struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -256,7 +256,7 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = bus_get(drv->bus); + const struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -274,7 +274,7 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); -static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) +static ssize_t drivers_autoprobe_show(const struct bus_type *bus, char *buf) { struct subsys_private *sp = bus_to_subsys(bus); int ret; @@ -287,7 +287,7 @@ static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) return ret; } -static ssize_t drivers_autoprobe_store(struct bus_type *bus, +static ssize_t drivers_autoprobe_store(const struct bus_type *bus, const char *buf, size_t count) { struct subsys_private *sp = bus_to_subsys(bus); @@ -304,7 +304,7 @@ static ssize_t drivers_autoprobe_store(struct bus_type *bus, return count; } -static ssize_t drivers_probe_store(struct bus_type *bus, +static ssize_t drivers_probe_store(const struct bus_type *bus, const char *buf, size_t count) { struct device *dev; @@ -769,7 +769,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, * attached and rescan it against existing drivers to see if it matches * any by calling device_attach() for the unbound devices. */ -int bus_rescan_devices(struct bus_type *bus) +int bus_rescan_devices(const struct bus_type *bus) { return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); } @@ -808,7 +808,7 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } -static ssize_t bus_uevent_store(struct bus_type *bus, +static ssize_t bus_uevent_store(const struct bus_type *bus, const char *buf, size_t count) { struct subsys_private *sp = bus_to_subsys(bus); @@ -841,7 +841,7 @@ static struct bus_attribute bus_attr_uevent = __ATTR(uevent, 0200, NULL, * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the subsystem. */ -int bus_register(struct bus_type *bus) +int bus_register(const struct bus_type *bus) { int retval; struct subsys_private *priv; @@ -935,8 +935,8 @@ void bus_unregister(const struct bus_type *bus) return; pr_debug("bus: '%s': unregistering\n", bus->name); - if (bus->dev_root) - device_unregister(bus->dev_root); + if (sp->dev_root) + device_unregister(sp->dev_root); bus_kobj = &sp->subsys.kobj; sysfs_remove_groups(bus_kobj, bus->bus_groups); @@ -1198,6 +1198,7 @@ static int subsys_register(struct bus_type *subsys, const struct attribute_group **groups, struct kobject *parent_of_root) { + struct subsys_private *sp; struct device *dev; int err; @@ -1205,6 +1206,12 @@ static int subsys_register(struct bus_type *subsys, if (err < 0) return err; + sp = bus_to_subsys(subsys); + if (!sp) { + err = -EINVAL; + goto err_sp; + } + dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (!dev) { err = -ENOMEM; @@ -1223,7 +1230,8 @@ static int subsys_register(struct bus_type *subsys, if (err < 0) goto err_dev_reg; - subsys->dev_root = dev; + sp->dev_root = dev; + subsys_put(sp); return 0; err_dev_reg: @@ -1232,6 +1240,8 @@ err_dev_reg: err_name: kfree(dev); err_dev: + subsys_put(sp); +err_sp: bus_unregister(subsys); return err; } @@ -1297,7 +1307,7 @@ EXPORT_SYMBOL_GPL(subsys_virtual_register); * from being unregistered or unloaded while the caller is using it. * The caller is responsible for preventing this. */ -struct device_driver *driver_find(const char *name, struct bus_type *bus) +struct device_driver *driver_find(const char *name, const struct bus_type *bus) { struct subsys_private *sp = bus_to_subsys(bus); struct kobject *k; @@ -1349,9 +1359,15 @@ bool bus_is_registered(const struct bus_type *bus) */ struct device *bus_get_dev_root(const struct bus_type *bus) { - if (bus) - return get_device(bus->dev_root); - return NULL; + struct subsys_private *sp = bus_to_subsys(bus); + struct device *dev_root; + + if (!sp) + return NULL; + + dev_root = get_device(sp->dev_root); + subsys_put(sp); + return dev_root; } EXPORT_SYMBOL_GPL(bus_get_dev_root); diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 41f0eadf1931..cbae8be1fe52 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -28,6 +28,9 @@ static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); #define per_cpu_cacheinfo_idx(cpu, idx) \ (per_cpu_cacheinfo(cpu) + (idx)) +/* Set if no cache information is found in DT/ACPI. */ +static bool use_arch_info; + struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) { return ci_cacheinfo(cpu); @@ -38,11 +41,11 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, { /* * For non DT/ACPI systems, assume unique level 1 caches, - * system-wide shared caches for all other levels. This will be used - * only if arch specific code has not populated shared_cpu_map + * system-wide shared caches for all other levels. */ - if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI))) - return !(this_leaf->level == 1); + if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI)) || + use_arch_info) + return (this_leaf->level != 1) && (sib_leaf->level != 1); if ((sib_leaf->attributes & CACHE_ID) && (this_leaf->attributes & CACHE_ID)) @@ -79,6 +82,9 @@ bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y) } #ifdef CONFIG_OF + +static bool of_check_cache_nodes(struct device_node *np); + /* OF properties to query for a given cache type */ struct cache_type_info { const char *size_prop; @@ -206,6 +212,11 @@ static int cache_setup_of_node(unsigned int cpu) return -ENOENT; } + if (!of_check_cache_nodes(np)) { + of_node_put(np); + return -ENOENT; + } + prev = np; while (index < cache_leaves(cpu)) { @@ -230,6 +241,25 @@ static int cache_setup_of_node(unsigned int cpu) return 0; } +static bool of_check_cache_nodes(struct device_node *np) +{ + struct device_node *next; + + if (of_property_present(np, "cache-size") || + of_property_present(np, "i-cache-size") || + of_property_present(np, "d-cache-size") || + of_property_present(np, "cache-unified")) + return true; + + next = of_find_next_cache_node(np); + if (next) { + of_node_put(next); + return true; + } + + return false; +} + static int of_count_cache_leaves(struct device_node *np) { unsigned int leaves = 0; @@ -261,6 +291,11 @@ int init_of_cache_level(unsigned int cpu) struct device_node *prev = NULL; unsigned int levels = 0, leaves, level; + if (!of_check_cache_nodes(np)) { + of_node_put(np); + return -ENOENT; + } + leaves = of_count_cache_leaves(np); if (leaves > 0) levels = 1; @@ -312,6 +347,10 @@ static int cache_setup_properties(unsigned int cpu) else if (!acpi_disabled) ret = cache_setup_acpi(cpu); + // Assume there is no cache information available in DT/ACPI from now. + if (ret && use_arch_cache_info()) + use_arch_info = true; + return ret; } @@ -330,7 +369,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) * to update the shared cpu_map if the cache attributes were * populated early before all the cpus are brought online */ - if (!last_level_cache_is_valid(cpu)) { + if (!last_level_cache_is_valid(cpu) && !use_arch_info) { ret = cache_setup_properties(cpu); if (ret) return ret; @@ -349,6 +388,16 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) continue;/* skip if itself or no cacheinfo */ for (sib_index = 0; sib_index < cache_leaves(i); sib_index++) { sib_leaf = per_cpu_cacheinfo_idx(i, sib_index); + + /* + * Comparing cache IDs only makes sense if the leaves + * belong to the same cache level of same type. Skip + * the check if level and type do not match. + */ + if (sib_leaf->level != this_leaf->level || + sib_leaf->type != this_leaf->type) + continue; + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); cpumask_set_cpu(i, &this_leaf->shared_cpu_map); @@ -361,11 +410,14 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) coherency_max_size = this_leaf->coherency_line_size; } + /* shared_cpu_map is now populated for the cpu */ + this_cpu_ci->cpu_map_populated = true; return 0; } static void cache_shared_cpu_map_remove(unsigned int cpu) { + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); struct cacheinfo *this_leaf, *sib_leaf; unsigned int sibling, index, sib_index; @@ -380,6 +432,16 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) for (sib_index = 0; sib_index < cache_leaves(sibling); sib_index++) { sib_leaf = per_cpu_cacheinfo_idx(sibling, sib_index); + + /* + * Comparing cache IDs only makes sense if the leaves + * belong to the same cache level of same type. Skip + * the check if level and type do not match. + */ + if (sib_leaf->level != this_leaf->level || + sib_leaf->type != this_leaf->type) + continue; + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); @@ -388,6 +450,9 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) } } } + + /* cpu is no longer populated in the shared map */ + this_cpu_ci->cpu_map_populated = false; } static void free_cache_attributes(unsigned int cpu) @@ -398,6 +463,11 @@ static void free_cache_attributes(unsigned int cpu) cache_shared_cpu_map_remove(cpu); } +int __weak early_cache_level(unsigned int cpu) +{ + return -ENOENT; +} + int __weak init_cache_level(unsigned int cpu) { return -ENOENT; @@ -423,32 +493,71 @@ int allocate_cache_info(int cpu) int fetch_cache_info(unsigned int cpu) { - struct cpu_cacheinfo *this_cpu_ci; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); unsigned int levels = 0, split_levels = 0; int ret; if (acpi_disabled) { ret = init_of_cache_level(cpu); - if (ret < 0) - return ret; } else { ret = acpi_get_cache_info(cpu, &levels, &split_levels); - if (ret < 0) + if (!ret) { + this_cpu_ci->num_levels = levels; + /* + * This assumes that: + * - there cannot be any split caches (data/instruction) + * above a unified cache + * - data/instruction caches come by pair + */ + this_cpu_ci->num_leaves = levels + split_levels; + } + } + + if (ret || !cache_leaves(cpu)) { + ret = early_cache_level(cpu); + if (ret) return ret; - this_cpu_ci = get_cpu_cacheinfo(cpu); - this_cpu_ci->num_levels = levels; - /* - * This assumes that: - * - there cannot be any split caches (data/instruction) - * above a unified cache - * - data/instruction caches come by pair - */ - this_cpu_ci->num_leaves = levels + split_levels; + if (!cache_leaves(cpu)) + return -ENOENT; + + this_cpu_ci->early_ci_levels = true; } - if (!cache_leaves(cpu)) + + return allocate_cache_info(cpu); +} + +static inline int init_level_allocate_ci(unsigned int cpu) +{ + unsigned int early_leaves = cache_leaves(cpu); + + /* Since early initialization/allocation of the cacheinfo is allowed + * via fetch_cache_info() and this also gets called as CPU hotplug + * callbacks via cacheinfo_cpu_online, the init/alloc can be skipped + * as it will happen only once (the cacheinfo memory is never freed). + * Just populate the cacheinfo. However, if the cacheinfo has been + * allocated early through the arch-specific early_cache_level() call, + * there is a chance the info is wrong (this can happen on arm64). In + * that case, call init_cache_level() anyway to give the arch-specific + * code a chance to make things right. + */ + if (per_cpu_cacheinfo(cpu) && !ci_cacheinfo(cpu)->early_ci_levels) + return 0; + + if (init_cache_level(cpu) || !cache_leaves(cpu)) return -ENOENT; + /* + * Now that we have properly initialized the cache level info, make + * sure we don't try to do that again the next time we are called + * (e.g. as CPU hotplug callbacks). + */ + ci_cacheinfo(cpu)->early_ci_levels = false; + + if (cache_leaves(cpu) <= early_leaves) + return 0; + + kfree(per_cpu_cacheinfo(cpu)); return allocate_cache_info(cpu); } @@ -456,23 +565,10 @@ int detect_cache_attributes(unsigned int cpu) { int ret; - /* Since early initialization/allocation of the cacheinfo is allowed - * via fetch_cache_info() and this also gets called as CPU hotplug - * callbacks via cacheinfo_cpu_online, the init/alloc can be skipped - * as it will happen only once (the cacheinfo memory is never freed). - * Just populate the cacheinfo. - */ - if (per_cpu_cacheinfo(cpu)) - goto populate_leaves; - - if (init_cache_level(cpu) || !cache_leaves(cpu)) - return -ENOENT; - - ret = allocate_cache_info(cpu); + ret = init_level_allocate_ci(cpu); if (ret) return ret; -populate_leaves: /* * If LLC is valid the cache leaves were already populated so just go to * update the cpu map. diff --git a/drivers/base/class.c b/drivers/base/class.c index 2373b3e210d8..05d9df90f621 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -20,8 +20,52 @@ #include #include "base.h" +/* /sys/class */ +static struct kset *class_kset; + #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) +/** + * class_to_subsys - Turn a struct class into a struct subsys_private + * + * @class: pointer to the struct bus_type to look up + * + * The driver core internals need to work on the subsys_private structure, not + * the external struct class pointer. This function walks the list of + * registered classes in the system and finds the matching one and returns the + * internal struct subsys_private that relates to that class. + * + * Note, the reference count of the return value is INCREMENTED if it is not + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +struct subsys_private *class_to_subsys(const struct class *class) +{ + struct subsys_private *sp = NULL; + struct kobject *kobj; + + if (!class || !class_kset) + return NULL; + + spin_lock(&class_kset->list_lock); + + if (list_empty(&class_kset->list)) + goto done; + + list_for_each_entry(kobj, &class_kset->list, entry) { + struct kset *kset = container_of(kobj, struct kset, kobj); + + sp = container_of_const(kset, struct subsys_private, subsys); + if (sp->class == class) + goto done; + } + sp = NULL; +done: + sp = subsys_get(sp); + spin_unlock(&class_kset->list_lock); + return sp; +} + static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -49,25 +93,24 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, static void class_release(struct kobject *kobj) { struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; + const struct class *class = cp->class; pr_debug("class '%s': release.\n", class->name); - class->p = NULL; - if (class->class_release) class->class_release(class); else pr_debug("class '%s' does not have a release() function, " "be careful\n", class->name); + lockdep_unregister_key(&cp->lock_key); kfree(cp); } static const struct kobj_ns_type_operations *class_child_ns_type(const struct kobject *kobj) { const struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; + const struct class *class = cp->class; return class->ns_type; } @@ -83,45 +126,35 @@ static const struct kobj_type class_ktype = { .child_ns_type = class_child_ns_type, }; -/* Hotplug events for classes go to the class subsys */ -static struct kset *class_kset; - - -int class_create_file_ns(struct class *cls, const struct class_attribute *attr, +int class_create_file_ns(const struct class *cls, const struct class_attribute *attr, const void *ns) { + struct subsys_private *sp = class_to_subsys(cls); int error; - if (cls) - error = sysfs_create_file_ns(&cls->p->subsys.kobj, - &attr->attr, ns); - else - error = -EINVAL; + if (!sp) + return -EINVAL; + + error = sysfs_create_file_ns(&sp->subsys.kobj, &attr->attr, ns); + subsys_put(sp); + return error; } EXPORT_SYMBOL_GPL(class_create_file_ns); -void class_remove_file_ns(struct class *cls, const struct class_attribute *attr, +void class_remove_file_ns(const struct class *cls, const struct class_attribute *attr, const void *ns) { - if (cls) - sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); + struct subsys_private *sp = class_to_subsys(cls); + + if (!sp) + return; + + sysfs_remove_file_ns(&sp->subsys.kobj, &attr->attr, ns); + subsys_put(sp); } EXPORT_SYMBOL_GPL(class_remove_file_ns); -static struct class *class_get(struct class *cls) -{ - if (cls) - kset_get(&cls->p->subsys); - return cls; -} - -static void class_put(struct class *cls) -{ - if (cls) - kset_put(&cls->p->subsys); -} - static struct device *klist_class_to_dev(struct klist_node *n) { struct device_private *p = to_device_private_class(n); @@ -142,21 +175,10 @@ static void klist_class_dev_put(struct klist_node *n) put_device(dev); } -static int class_add_groups(struct class *cls, - const struct attribute_group **groups) -{ - return sysfs_create_groups(&cls->p->subsys.kobj, groups); -} - -static void class_remove_groups(struct class *cls, - const struct attribute_group **groups) -{ - return sysfs_remove_groups(&cls->p->subsys.kobj, groups); -} - -int __class_register(struct class *cls, struct lock_class_key *key) +int class_register(const struct class *cls) { struct subsys_private *cp; + struct lock_class_key *key; int error; pr_debug("device class '%s': registering\n", cls->name); @@ -167,6 +189,8 @@ int __class_register(struct class *cls, struct lock_class_key *key) klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); INIT_LIST_HEAD(&cp->interfaces); kset_init(&cp->glue_dirs); + key = &cp->lock_key; + lockdep_register_key(key); __mutex_init(&cp->mutex, "subsys mutex", key); error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); if (error) { @@ -174,27 +198,15 @@ int __class_register(struct class *cls, struct lock_class_key *key) return error; } - /* set the default /sys/dev directory for devices of this class */ - if (!cls->dev_kobj) - cls->dev_kobj = sysfs_dev_char_kobj; - -#if defined(CONFIG_BLOCK) - /* let the block class directory show up in the root of sysfs */ - if (!sysfs_deprecated || cls != &block_class) - cp->subsys.kobj.kset = class_kset; -#else cp->subsys.kobj.kset = class_kset; -#endif cp->subsys.kobj.ktype = &class_ktype; cp->class = cls; - cls->p = cp; error = kset_register(&cp->subsys); if (error) goto err_out; - error = class_add_groups(class_get(cls), cls->class_groups); - class_put(cls); + error = sysfs_create_groups(&cp->subsys.kobj, cls->class_groups); if (error) { kobject_del(&cp->subsys.kobj); kfree_const(cp->subsys.kobj.name); @@ -204,30 +216,34 @@ int __class_register(struct class *cls, struct lock_class_key *key) err_out: kfree(cp); - cls->p = NULL; return error; } -EXPORT_SYMBOL_GPL(__class_register); +EXPORT_SYMBOL_GPL(class_register); -void class_unregister(struct class *cls) +void class_unregister(const struct class *cls) { + struct subsys_private *sp = class_to_subsys(cls); + + if (!sp) + return; + pr_debug("device class '%s': unregistering\n", cls->name); - class_remove_groups(cls, cls->class_groups); - kset_unregister(&cls->p->subsys); + + sysfs_remove_groups(&sp->subsys.kobj, cls->class_groups); + kset_unregister(&sp->subsys); + subsys_put(sp); } EXPORT_SYMBOL_GPL(class_unregister); -static void class_create_release(struct class *cls) +static void class_create_release(const struct class *cls) { pr_debug("%s called for %s\n", __func__, cls->name); kfree(cls); } /** - * __class_create - create a struct class structure - * @owner: pointer to the module that is to "own" this struct class + * class_create - create a struct class structure * @name: pointer to a string for the name of this class. - * @key: the lock_class_key for this class; used by mutex lock debugging * * This is used to create a struct class pointer that can then be used * in calls to device_create(). @@ -237,8 +253,7 @@ static void class_create_release(struct class *cls) * Note, the pointer created here is to be destroyed when finished by * making a call to class_destroy(). */ -struct class *__class_create(struct module *owner, const char *name, - struct lock_class_key *key) +struct class *class_create(const char *name) { struct class *cls; int retval; @@ -250,10 +265,9 @@ struct class *__class_create(struct module *owner, const char *name, } cls->name = name; - cls->owner = owner; cls->class_release = class_create_release; - retval = __class_register(cls, key); + retval = class_register(cls); if (retval) goto error; @@ -263,7 +277,7 @@ error: kfree(cls); return ERR_PTR(retval); } -EXPORT_SYMBOL_GPL(__class_create); +EXPORT_SYMBOL_GPL(class_create); /** * class_destroy - destroys a struct class structure @@ -272,7 +286,7 @@ EXPORT_SYMBOL_GPL(__class_create); * Note, the pointer to be destroyed must have been created with a call * to class_create(). */ -void class_destroy(struct class *cls) +void class_destroy(const struct class *cls) { if (IS_ERR_OR_NULL(cls)) return; @@ -293,15 +307,20 @@ EXPORT_SYMBOL_GPL(class_destroy); * otherwise if it is NULL, the iteration starts at the beginning of * the list. */ -void class_dev_iter_init(struct class_dev_iter *iter, struct class *class, - struct device *start, const struct device_type *type) +void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, + const struct device *start, const struct device_type *type) { + struct subsys_private *sp = class_to_subsys(class); struct klist_node *start_knode = NULL; + if (!sp) + return; + if (start) start_knode = &start->p->knode_class; - klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); + klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode); iter->type = type; + iter->sp = sp; } EXPORT_SYMBOL_GPL(class_dev_iter_init); @@ -343,6 +362,7 @@ EXPORT_SYMBOL_GPL(class_dev_iter_next); void class_dev_iter_exit(struct class_dev_iter *iter) { klist_iter_exit(&iter->ki); + subsys_put(iter->sp); } EXPORT_SYMBOL_GPL(class_dev_iter_exit); @@ -364,16 +384,17 @@ EXPORT_SYMBOL_GPL(class_dev_iter_exit); * @fn is allowed to do anything including calling back into class * code. There's no locking restriction. */ -int class_for_each_device(struct class *class, struct device *start, +int class_for_each_device(const struct class *class, const struct device *start, void *data, int (*fn)(struct device *, void *)) { + struct subsys_private *sp = class_to_subsys(class); struct class_dev_iter iter; struct device *dev; int error = 0; if (!class) return -EINVAL; - if (!class->p) { + if (!sp) { WARN(1, "%s called for class '%s' before it was initialized", __func__, class->name); return -EINVAL; @@ -386,6 +407,7 @@ int class_for_each_device(struct class *class, struct device *start, break; } class_dev_iter_exit(&iter); + subsys_put(sp); return error; } @@ -411,16 +433,17 @@ EXPORT_SYMBOL_GPL(class_for_each_device); * @match is allowed to do anything including calling back into class * code. There's no locking restriction. */ -struct device *class_find_device(struct class *class, struct device *start, +struct device *class_find_device(const struct class *class, const struct device *start, const void *data, int (*match)(struct device *, const void *)) { + struct subsys_private *sp = class_to_subsys(class); struct class_dev_iter iter; struct device *dev; if (!class) return NULL; - if (!class->p) { + if (!sp) { WARN(1, "%s called for class '%s' before it was initialized", __func__, class->name); return NULL; @@ -434,6 +457,7 @@ struct device *class_find_device(struct class *class, struct device *start, } } class_dev_iter_exit(&iter); + subsys_put(sp); return dev; } @@ -441,26 +465,33 @@ EXPORT_SYMBOL_GPL(class_find_device); int class_interface_register(struct class_interface *class_intf) { - struct class *parent; + struct subsys_private *sp; + const struct class *parent; struct class_dev_iter iter; struct device *dev; if (!class_intf || !class_intf->class) return -ENODEV; - parent = class_get(class_intf->class); - if (!parent) + parent = class_intf->class; + sp = class_to_subsys(parent); + if (!sp) return -EINVAL; - mutex_lock(&parent->p->mutex); - list_add_tail(&class_intf->node, &parent->p->interfaces); + /* + * Reference in sp is now incremented and will be dropped when + * the interface is removed in the call to class_interface_unregister() + */ + + mutex_lock(&sp->mutex); + list_add_tail(&class_intf->node, &sp->interfaces); if (class_intf->add_dev) { class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) - class_intf->add_dev(dev, class_intf); + class_intf->add_dev(dev); class_dev_iter_exit(&iter); } - mutex_unlock(&parent->p->mutex); + mutex_unlock(&sp->mutex); return 0; } @@ -468,29 +499,40 @@ EXPORT_SYMBOL_GPL(class_interface_register); void class_interface_unregister(struct class_interface *class_intf) { - struct class *parent = class_intf->class; + struct subsys_private *sp; + const struct class *parent = class_intf->class; struct class_dev_iter iter; struct device *dev; if (!parent) return; - mutex_lock(&parent->p->mutex); + sp = class_to_subsys(parent); + if (!sp) + return; + + mutex_lock(&sp->mutex); list_del_init(&class_intf->node); if (class_intf->remove_dev) { class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) - class_intf->remove_dev(dev, class_intf); + class_intf->remove_dev(dev); class_dev_iter_exit(&iter); } - mutex_unlock(&parent->p->mutex); + mutex_unlock(&sp->mutex); - class_put(parent); + /* + * Decrement the reference count twice, once for the class_to_subsys() + * call in the start of this function, and the second one from the + * reference increment in class_interface_register() + */ + subsys_put(sp); + subsys_put(sp); } EXPORT_SYMBOL_GPL(class_interface_unregister); -ssize_t show_class_attr_string(struct class *class, - struct class_attribute *attr, char *buf) +ssize_t show_class_attr_string(const struct class *class, + const struct class_attribute *attr, char *buf) { struct class_attribute_string *cs; @@ -587,6 +629,31 @@ void class_compat_remove_link(struct class_compat *cls, struct device *dev, } EXPORT_SYMBOL_GPL(class_compat_remove_link); +/** + * class_is_registered - determine if at this moment in time, a class is + * registered in the driver core or not. + * @class: the class to check + * + * Returns a boolean to state if the class is registered in the driver core + * or not. Note that the value could switch right after this call is made, + * so only use this in places where you "know" it is safe to do so (usually + * to determine if the specific class has been registered yet or not). + * + * Be careful in using this. + */ +bool class_is_registered(const struct class *class) +{ + struct subsys_private *sp = class_to_subsys(class); + bool is_initialized = false; + + if (sp) { + is_initialized = true; + subsys_put(sp); + } + return is_initialized; +} +EXPORT_SYMBOL_GPL(class_is_registered); + int __init classes_init(void) { class_kset = kset_create_and_add("class", NULL, NULL); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6878dfcbf0d6..3dff5037943e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -36,19 +36,6 @@ #include "physical_location.h" #include "power/power.h" -#ifdef CONFIG_SYSFS_DEPRECATED -#ifdef CONFIG_SYSFS_DEPRECATED_V2 -long sysfs_deprecated = 1; -#else -long sysfs_deprecated = 0; -#endif -static int __init sysfs_deprecated_setup(char *arg) -{ - return kstrtol(arg, 10, &sysfs_deprecated); -} -early_param("sysfs.deprecated", sysfs_deprecated_setup); -#endif - /* Device links support. */ static LIST_HEAD(deferred_sync); static unsigned int defer_sync_state_count = 1; @@ -550,13 +537,11 @@ static void devlink_dev_release(struct device *dev) static struct class devlink_class = { .name = "devlink", - .owner = THIS_MODULE, .dev_groups = devlink_groups, .dev_release = devlink_dev_release, }; -static int devlink_add_symlinks(struct device *dev, - struct class_interface *class_intf) +static int devlink_add_symlinks(struct device *dev) { int ret; size_t len; @@ -605,8 +590,7 @@ out: return ret; } -static void devlink_remove_symlinks(struct device *dev, - struct class_interface *class_intf) +static void devlink_remove_symlinks(struct device *dev) { struct device_link *link = to_devlink(dev); size_t len; @@ -1173,10 +1157,7 @@ static void device_links_flush_sync_list(struct list_head *list, if (dev != dont_lock_dev) device_lock(dev); - if (dev->bus->sync_state) - dev->bus->sync_state(dev); - else if (dev->driver && dev->driver->sync_state) - dev->driver->sync_state(dev); + dev_sync_state(dev); if (dev != dont_lock_dev) device_unlock(dev); @@ -1685,6 +1666,31 @@ static int __init fw_devlink_strict_setup(char *arg) } early_param("fw_devlink.strict", fw_devlink_strict_setup); +#define FW_DEVLINK_SYNC_STATE_STRICT 0 +#define FW_DEVLINK_SYNC_STATE_TIMEOUT 1 + +#ifndef CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT +static int fw_devlink_sync_state; +#else +static int fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_TIMEOUT; +#endif + +static int __init fw_devlink_sync_state_setup(char *arg) +{ + if (!arg) + return -EINVAL; + + if (strcmp(arg, "strict") == 0) { + fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_STRICT; + return 0; + } else if (strcmp(arg, "timeout") == 0) { + fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_TIMEOUT; + return 0; + } + return -EINVAL; +} +early_param("fw_devlink.sync_state", fw_devlink_sync_state_setup); + static inline u32 fw_devlink_get_flags(u8 fwlink_flags) { if (fwlink_flags & FWLINK_FLAG_CYCLE) @@ -1755,6 +1761,44 @@ void fw_devlink_drivers_done(void) device_links_write_unlock(); } +static int fw_devlink_dev_sync_state(struct device *dev, void *data) +{ + struct device_link *link = to_devlink(dev); + struct device *sup = link->supplier; + + if (!(link->flags & DL_FLAG_MANAGED) || + link->status == DL_STATE_ACTIVE || sup->state_synced || + !dev_has_sync_state(sup)) + return 0; + + if (fw_devlink_sync_state == FW_DEVLINK_SYNC_STATE_STRICT) { + dev_warn(sup, "sync_state() pending due to %s\n", + dev_name(link->consumer)); + return 0; + } + + if (!list_empty(&sup->links.defer_sync)) + return 0; + + dev_warn(sup, "Timed out. Forcing sync_state()\n"); + sup->state_synced = true; + get_device(sup); + list_add_tail(&sup->links.defer_sync, data); + + return 0; +} + +void fw_devlink_probing_done(void) +{ + LIST_HEAD(sync_list); + + device_links_write_lock(); + class_for_each_device(&devlink_class, NULL, &sync_list, + fw_devlink_dev_sync_state); + device_links_write_unlock(); + device_links_flush_sync_list(&sync_list, NULL); +} + /** * wait_for_init_devices_probe - Try to probe any device needed for init * @@ -2209,8 +2253,12 @@ static void fw_devlink_link_device(struct device *dev) int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; -struct kobject *sysfs_dev_char_kobj; -struct kobject *sysfs_dev_block_kobj; + +/* /sys/dev/char */ +static struct kobject *sysfs_dev_char_kobj; + +/* /sys/dev/block */ +static struct kobject *sysfs_dev_block_kobj; static DEFINE_MUTEX(device_hotplug_lock); @@ -2779,7 +2827,7 @@ EXPORT_SYMBOL_GPL(devm_device_add_groups); static int device_add_attrs(struct device *dev) { - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; int error; @@ -2846,7 +2894,7 @@ static int device_add_attrs(struct device *dev) static void device_remove_attrs(struct device *dev) { - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; if (dev->physical_location) { @@ -3079,7 +3127,7 @@ struct kobject *virtual_device_parent(struct device *dev) struct class_dir { struct kobject kobj; - struct class *class; + const struct class *class; }; #define to_class_dir(obj) container_of(obj, struct class_dir, kobj) @@ -3103,8 +3151,8 @@ static const struct kobj_type class_dir_ktype = { .child_ns_type = class_dir_child_ns_type }; -static struct kobject * -class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) +static struct kobject *class_dir_create_and_add(struct subsys_private *sp, + struct kobject *parent_kobj) { struct class_dir *dir; int retval; @@ -3113,12 +3161,12 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) if (!dir) return ERR_PTR(-ENOMEM); - dir->class = class; + dir->class = sp->class; kobject_init(&dir->kobj, &class_dir_ktype); - dir->kobj.kset = &class->p->glue_dirs; + dir->kobj.kset = &sp->glue_dirs; - retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); + retval = kobject_add(&dir->kobj, parent_kobj, "%s", sp->class->name); if (retval < 0) { kobject_put(&dir->kobj); return ERR_PTR(retval); @@ -3131,21 +3179,13 @@ static DEFINE_MUTEX(gdp_mutex); static struct kobject *get_device_parent(struct device *dev, struct device *parent) { + struct subsys_private *sp = class_to_subsys(dev->class); struct kobject *kobj = NULL; - if (dev->class) { + if (sp) { struct kobject *parent_kobj; struct kobject *k; -#ifdef CONFIG_BLOCK - /* block disks show up in /sys/block */ - if (sysfs_deprecated && dev->class == &block_class) { - if (parent && parent->class == &block_class) - return &parent->kobj; - return &block_class.p->subsys.kobj; - } -#endif - /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live @@ -3153,30 +3193,34 @@ static struct kobject *get_device_parent(struct device *dev, */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); - else if (parent->class && !dev->class->ns_type) + else if (parent->class && !dev->class->ns_type) { + subsys_put(sp); return &parent->kobj; - else + } else { parent_kobj = &parent->kobj; + } mutex_lock(&gdp_mutex); /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->p->glue_dirs.list_lock); - list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) + spin_lock(&sp->glue_dirs.list_lock); + list_for_each_entry(k, &sp->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } - spin_unlock(&dev->class->p->glue_dirs.list_lock); + spin_unlock(&sp->glue_dirs.list_lock); if (kobj) { mutex_unlock(&gdp_mutex); + subsys_put(sp); return kobj; } /* or create a new class-directory at the parent device */ - k = class_dir_create_and_add(dev->class, parent_kobj); + k = class_dir_create_and_add(sp, parent_kobj); /* do not emit an uevent for this simple "glue" directory */ mutex_unlock(&gdp_mutex); + subsys_put(sp); return k; } @@ -3199,10 +3243,23 @@ static struct kobject *get_device_parent(struct device *dev, static inline bool live_in_glue_dir(struct kobject *kobj, struct device *dev) { - if (!kobj || !dev->class || - kobj->kset != &dev->class->p->glue_dirs) + struct subsys_private *sp; + bool retval; + + if (!kobj || !dev->class) return false; - return true; + + sp = class_to_subsys(dev->class); + if (!sp) + return false; + + if (kobj->kset == &sp->glue_dirs) + retval = true; + else + retval = false; + + subsys_put(sp); + return retval; } static inline struct kobject *get_glue_dir(struct device *dev) @@ -3299,6 +3356,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) static int device_add_class_symlinks(struct device *dev) { struct device_node *of_node = dev_of_node(dev); + struct subsys_private *sp; int error; if (of_node) { @@ -3308,12 +3366,11 @@ static int device_add_class_symlinks(struct device *dev) /* An error here doesn't warrant bringing down the device */ } - if (!dev->class) + sp = class_to_subsys(dev->class); + if (!sp) return 0; - error = sysfs_create_link(&dev->kobj, - &dev->class->p->subsys.kobj, - "subsystem"); + error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem"); if (error) goto out_devnode; @@ -3324,46 +3381,38 @@ static int device_add_class_symlinks(struct device *dev) goto out_subsys; } -#ifdef CONFIG_BLOCK - /* /sys/block has directories and does not need symlinks */ - if (sysfs_deprecated && dev->class == &block_class) - return 0; -#endif - /* link in the class directory pointing to the device */ - error = sysfs_create_link(&dev->class->p->subsys.kobj, - &dev->kobj, dev_name(dev)); + error = sysfs_create_link(&sp->subsys.kobj, &dev->kobj, dev_name(dev)); if (error) goto out_device; - - return 0; + goto exit; out_device: sysfs_remove_link(&dev->kobj, "device"); - out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); out_devnode: sysfs_remove_link(&dev->kobj, "of_node"); +exit: + subsys_put(sp); return error; } static void device_remove_class_symlinks(struct device *dev) { + struct subsys_private *sp = class_to_subsys(dev->class); + if (dev_of_node(dev)) sysfs_remove_link(&dev->kobj, "of_node"); - if (!dev->class) + if (!sp) return; if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&dev->kobj, "subsystem"); -#ifdef CONFIG_BLOCK - if (sysfs_deprecated && dev->class == &block_class) - return; -#endif - sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); + sysfs_delete_link(&sp->subsys.kobj, &dev->kobj, dev_name(dev)); + subsys_put(sp); } /** @@ -3383,27 +3432,13 @@ int dev_set_name(struct device *dev, const char *fmt, ...) } EXPORT_SYMBOL_GPL(dev_set_name); -/** - * device_to_dev_kobj - select a /sys/dev/ directory for the device - * @dev: device - * - * By default we select char/ for new entries. Setting class->dev_obj - * to NULL prevents an entry from being created. class->dev_kobj must - * be set (or cleared) before any devices are registered to the class - * otherwise device_create_sys_dev_entry() and - * device_remove_sys_dev_entry() will disagree about the presence of - * the link. - */ +/* select a /sys/dev/ directory for the device */ static struct kobject *device_to_dev_kobj(struct device *dev) { - struct kobject *kobj; - - if (dev->class) - kobj = dev->class->dev_kobj; + if (is_blockdev(dev)) + return sysfs_dev_block_kobj; else - kobj = sysfs_dev_char_kobj; - - return kobj; + return sysfs_dev_char_kobj; } static int device_create_sys_dev_entry(struct device *dev) @@ -3472,6 +3507,7 @@ static int device_private_init(struct device *dev) */ int device_add(struct device *dev) { + struct subsys_private *sp; struct device *parent; struct kobject *kobj; struct class_interface *class_intf; @@ -3600,18 +3636,18 @@ int device_add(struct device *dev) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); - if (dev->class) { - mutex_lock(&dev->class->p->mutex); + sp = class_to_subsys(dev->class); + if (sp) { + mutex_lock(&sp->mutex); /* tie the class to the device */ - klist_add_tail(&dev->p->knode_class, - &dev->class->p->klist_devices); + klist_add_tail(&dev->p->knode_class, &sp->klist_devices); /* notify any interfaces that the device is here */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) + list_for_each_entry(class_intf, &sp->interfaces, node) if (class_intf->add_dev) - class_intf->add_dev(dev, class_intf); - mutex_unlock(&dev->class->p->mutex); + class_intf->add_dev(dev); + mutex_unlock(&sp->mutex); + subsys_put(sp); } done: put_device(dev); @@ -3731,6 +3767,7 @@ EXPORT_SYMBOL_GPL(kill_device); */ void device_del(struct device *dev) { + struct subsys_private *sp; struct device *parent = dev->parent; struct kobject *glue_dir = NULL; struct class_interface *class_intf; @@ -3757,18 +3794,20 @@ void device_del(struct device *dev) device_remove_sys_dev_entry(dev); device_remove_file(dev, &dev_attr_dev); } - if (dev->class) { + + sp = class_to_subsys(dev->class); + if (sp) { device_remove_class_symlinks(dev); - mutex_lock(&dev->class->p->mutex); + mutex_lock(&sp->mutex); /* notify any interfaces that the device is now gone */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) + list_for_each_entry(class_intf, &sp->interfaces, node) if (class_intf->remove_dev) - class_intf->remove_dev(dev, class_intf); + class_intf->remove_dev(dev); /* remove the device from the class list */ klist_del(&dev->p->knode_class); - mutex_unlock(&dev->class->p->mutex); + mutex_unlock(&sp->mutex); + subsys_put(sp); } device_remove_file(dev, &dev_attr_uevent); device_remove_attrs(dev); @@ -4231,7 +4270,7 @@ static void device_create_release(struct device *dev) } static __printf(6, 0) struct device * -device_create_groups_vargs(struct class *class, struct device *parent, +device_create_groups_vargs(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args) @@ -4291,11 +4330,8 @@ error: * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). */ -struct device *device_create(struct class *class, struct device *parent, +struct device *device_create(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) { va_list vargs; @@ -4332,11 +4368,8 @@ EXPORT_SYMBOL_GPL(device_create); * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). */ -struct device *device_create_with_groups(struct class *class, +struct device *device_create_with_groups(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, @@ -4361,7 +4394,7 @@ EXPORT_SYMBOL_GPL(device_create_with_groups); * This call unregisters and cleans up a device that was created with a * call to device_create(). */ -void device_destroy(struct class *class, dev_t devt) +void device_destroy(const struct class *class, dev_t devt) { struct device *dev; @@ -4383,9 +4416,12 @@ EXPORT_SYMBOL_GPL(device_destroy); * on the same device to ensure that new_name is valid and * won't conflict with other devices. * - * Note: Don't call this function. Currently, the networking layer calls this - * function, but that will change. The following text from Kay Sievers offers - * some insight: + * Note: given that some subsystems (networking and infiniband) use this + * function, with no immediate plans for this to change, we cannot assume or + * require that this function not be called at all. + * + * However, if you're writing new code, do not call this function. The following + * text from Kay Sievers offers some insight: * * Renaming devices is racy at many levels, symlinks and other stuff are not * replaced atomically, and you get a "move" uevent, but it's not easy to @@ -4399,13 +4435,6 @@ EXPORT_SYMBOL_GPL(device_destroy); * kernel device renaming. Besides that, it's not even implemented now for * other things than (driver-core wise very simple) network devices. * - * We are currently about to change network renaming in udev to completely - * disallow renaming of devices in the same namespace as the kernel uses, - * because we can't solve the problems properly, that arise with swapping names - * of multiple interfaces without races. Means, renaming of eth[0-9]* will only - * be allowed to some other name than eth[0-9]*, for the aforementioned - * reasons. - * * Make up a "real" name in the driver before you register anything, or add * some other attributes for userspace to find the device, or use udev to add * symlinks -- but never rename kernel devices later, it's a complete mess. We @@ -4431,9 +4460,16 @@ int device_rename(struct device *dev, const char *new_name) } if (dev->class) { - error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, - kobj, old_device_name, + struct subsys_private *sp = class_to_subsys(dev->class); + + if (!sp) { + error = -EINVAL; + goto out; + } + + error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name, new_name, kobject_namespace(kobj)); + subsys_put(sp); if (error) goto out; } @@ -4558,7 +4594,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) { struct kobject *kobj = &dev->kobj; - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; int error; @@ -4616,6 +4652,7 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) { int error; struct kobject *kobj = &dev->kobj; + struct subsys_private *sp; dev = get_device(dev); if (!dev) @@ -4652,21 +4689,19 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) if (error) goto out; -#ifdef CONFIG_BLOCK - if (sysfs_deprecated && dev->class == &block_class) - goto out; -#endif - /* * Change the owner of the symlink located in the class directory of * the device class associated with @dev which points to the actual * directory entry for @dev to @kuid/@kgid. This ensures that the * symlink shows the same permissions as its target. */ - error = sysfs_link_change_owner(&dev->class->p->subsys.kobj, &dev->kobj, - dev_name(dev), kuid, kgid); - if (error) + sp = class_to_subsys(dev->class); + if (!sp) { + error = -EINVAL; goto out; + } + error = sysfs_link_change_owner(&sp->subsys.kobj, &dev->kobj, dev_name(dev), kuid, kgid); + subsys_put(sp); out: put_device(dev); @@ -4965,9 +5000,13 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) } else { if (fwnode_is_primary(fn)) { dev->fwnode = fn->secondary; + + /* Skip nullifying fn->secondary if the primary is shared */ + if (parent && fn == parent->fwnode) + return; + /* Set fn->secondary = NULL, so fn remains the primary fwnode */ - if (!(parent && fn == parent->fwnode)) - fn->secondary = NULL; + fn->secondary = NULL; } else { dev->fwnode = NULL; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 8def2ba08a82..9c09ca5c4ab6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -315,6 +315,8 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe) dev_info(p->device, "deferred probe pending\n"); mutex_unlock(&deferred_probe_mutex); + + fw_devlink_probing_done(); } static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); @@ -364,6 +366,10 @@ static int deferred_probe_initcall(void) schedule_delayed_work(&deferred_probe_timeout_work, driver_deferred_probe_timeout * HZ); } + + if (!IS_ENABLED(CONFIG_MODULES)) + fw_devlink_probing_done(); + return 0; } late_initcall(deferred_probe_initcall); @@ -504,6 +510,27 @@ EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); +static ssize_t state_synced_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0; + + if (strcmp("1", buf)) + return -EINVAL; + + device_lock(dev); + if (!dev->state_synced) { + dev->state_synced = true; + dev_sync_state(dev); + } else { + ret = -EINVAL; + } + device_unlock(dev); + + return ret ? ret : count; +} + static ssize_t state_synced_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -515,7 +542,7 @@ static ssize_t state_synced_show(struct device *dev, return sysfs_emit(buf, "%u\n", val); } -static DEVICE_ATTR_RO(state_synced); +static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { @@ -708,7 +735,12 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv) calltime = ktime_get(); ret = really_probe(dev, drv); rettime = ktime_get(); - pr_debug("probe of %s returned %d after %lld usecs\n", + /* + * Don't change this to pr_debug() because that requires + * CONFIG_DYNAMIC_DEBUG and we want a simple 'initcall_debug' on the + * kernel commandline to print this all the time at the debug level. + */ + printk(KERN_DEBUG "probe of %s returned %d after %lld usecs\n", dev_name(dev), ret, ktime_us_delta(rettime, calltime)); return ret; } diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 1c06781f7114..91536ee05f14 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -167,7 +167,7 @@ static int devcd_free(struct device *dev, void *data) return 0; } -static ssize_t disabled_show(struct class *class, struct class_attribute *attr, +static ssize_t disabled_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", devcd_disabled); @@ -197,7 +197,7 @@ static ssize_t disabled_show(struct class *class, struct class_attribute *attr, * so, above situation would not occur. */ -static ssize_t disabled_store(struct class *class, struct class_attribute *attr, +static ssize_t disabled_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { long tmp = simple_strtol(buf, NULL, 10); @@ -226,7 +226,6 @@ ATTRIBUTE_GROUPS(devcd_class); static struct class devcd_class = { .name = "devcoredump", - .owner = THIS_MODULE, .dev_release = devcd_dev_release, .dev_groups = devcd_dev_groups, .class_groups = devcd_class_groups, diff --git a/drivers/base/devres.c b/drivers/base/devres.c index c0e100074aa3..5c998cfac335 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -722,20 +722,21 @@ static void devm_action_release(struct device *dev, void *res) } /** - * devm_add_action() - add a custom action to list of managed resources + * __devm_add_action() - add a custom action to list of managed resources * @dev: Device that owns the action * @action: Function that should be called * @data: Pointer to data passed to @action implementation + * @name: Name of the resource (for debugging purposes) * * This adds a custom action to the list of managed resources so that * it gets executed as part of standard resource unwinding. */ -int devm_add_action(struct device *dev, void (*action)(void *), void *data) +int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name) { struct action_devres *devres; - devres = devres_alloc(devm_action_release, - sizeof(struct action_devres), GFP_KERNEL); + devres = __devres_alloc_node(devm_action_release, sizeof(struct action_devres), + GFP_KERNEL, NUMA_NO_NODE, name); if (!devres) return -ENOMEM; @@ -745,7 +746,7 @@ int devm_add_action(struct device *dev, void (*action)(void *), void *data) devres_add(dev, devres); return 0; } -EXPORT_SYMBOL_GPL(devm_add_action); +EXPORT_SYMBOL_GPL(__devm_add_action); /** * devm_remove_action() - removes previously added custom action diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index ae72d4ba8547..b848764ef018 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -94,15 +94,6 @@ static struct file_system_type dev_fs_type = { .mount = public_dev_mount, }; -#ifdef CONFIG_BLOCK -static inline int is_blockdev(struct device *dev) -{ - return dev->class == &block_class; -} -#else -static inline int is_blockdev(struct device *dev) { return 0; } -#endif - static int devtmpfs_submit_req(struct req *req, const char *tmp) { init_completion(&req->done); diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index 5166b323a0f8..5ca00e02fe82 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -3,6 +3,8 @@ menu "Firmware loader" config FW_LOADER tristate "Firmware loading facility" if EXPERT + select CRYPTO_HASH if FW_LOADER_DEBUG + select CRYPTO_SHA256 if FW_LOADER_DEBUG default y help This enables the firmware loading facility in the kernel. The kernel @@ -24,6 +26,17 @@ config FW_LOADER You also want to be sure to enable this built-in if you are going to enable built-in firmware (CONFIG_EXTRA_FIRMWARE). +config FW_LOADER_DEBUG + bool "Log filenames and checksums for loaded firmware" + depends on CRYPTO = FW_LOADER || CRYPTO=y + depends on DYNAMIC_DEBUG + depends on FW_LOADER + default FW_LOADER + help + Select this option to use dynamic debug to log firmware filenames and + SHA256 checksums to the kernel log for each firmware file that is + loaded. + if FW_LOADER config FW_LOADER_PAGED_BUF diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 017c4cdb219e..b58c42f1b1ce 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -493,9 +493,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, const void *in_buffer)) { size_t size; - int i, len; + int i, len, maxlen = 0; int rc = -ENOENT; - char *path; + char *path, *nt = NULL; size_t msize = INT_MAX; void *buffer = NULL; @@ -518,8 +518,17 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, if (!fw_path[i][0]) continue; - len = snprintf(path, PATH_MAX, "%s/%s%s", - fw_path[i], fw_priv->fw_name, suffix); + /* strip off \n from customized path */ + maxlen = strlen(fw_path[i]); + if (i == 0) { + nt = strchr(fw_path[i], '\n'); + if (nt) + maxlen = nt - fw_path[i]; + } + + len = snprintf(path, PATH_MAX, "%.*s/%s%s", + maxlen, fw_path[i], + fw_priv->fw_name, suffix); if (len >= PATH_MAX) { rc = -ENAMETOOLONG; break; @@ -791,6 +800,50 @@ static void fw_abort_batch_reqs(struct firmware *fw) mutex_unlock(&fw_lock); } +#if defined(CONFIG_FW_LOADER_DEBUG) +#include +#include + +static void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device) +{ + struct shash_desc *shash; + struct crypto_shash *alg; + u8 *sha256buf; + char *outbuf; + + alg = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(alg)) + return; + + sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); + outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL); + shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL); + if (!sha256buf || !outbuf || !shash) + goto out_free; + + shash->tfm = alg; + + if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0) + goto out_shash; + + for (int i = 0; i < SHA256_DIGEST_SIZE; i++) + sprintf(&outbuf[i * 2], "%02x", sha256buf[i]); + outbuf[SHA256_BLOCK_SIZE] = 0; + dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf); + +out_shash: + crypto_free_shash(alg); +out_free: + kfree(shash); + kfree(outbuf); + kfree(sha256buf); +} +#else +static void fw_log_firmware_info(const struct firmware *fw, const char *name, + struct device *device) +{} +#endif + /* called from request_firmware() and request_firmware_work_func() */ static int _request_firmware(const struct firmware **firmware_p, const char *name, @@ -861,11 +914,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name, revert_creds(old_cred); put_cred(kern_cred); - out: +out: if (ret < 0) { fw_abort_batch_reqs(fw); release_firmware(fw); fw = NULL; + } else { + fw_log_firmware_info(fw, name, device); } *firmware_p = fw; diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index 56911d75b90a..c9c93b47d9a5 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -25,7 +25,7 @@ void __fw_load_abort(struct fw_priv *fw_priv) } #ifdef CONFIG_FW_LOADER_USER_HELPER -static ssize_t timeout_show(struct class *class, struct class_attribute *attr, +static ssize_t timeout_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", __firmware_loading_timeout()); @@ -44,7 +44,7 @@ static ssize_t timeout_show(struct class *class, struct class_attribute *attr, * * Note: zero means 'wait forever'. **/ -static ssize_t timeout_store(struct class *class, struct class_attribute *attr, +static ssize_t timeout_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { int tmp_loading_timeout = simple_strtol(buf, NULL, 10); diff --git a/drivers/base/physical_location.h b/drivers/base/physical_location.h index 82cde9f1b161..3f3f61307998 100644 --- a/drivers/base/physical_location.h +++ b/drivers/base/physical_location.h @@ -8,7 +8,7 @@ #include #ifdef CONFIG_ACPI -extern bool dev_add_physical_location(struct device *dev); +bool dev_add_physical_location(struct device *dev); extern const struct attribute_group dev_attr_physical_location_group; #else static inline bool dev_add_physical_location(struct device *dev) { return false; }; diff --git a/drivers/base/power/wakeup_stats.c b/drivers/base/power/wakeup_stats.c index 924fac493c4f..6732ed2869f9 100644 --- a/drivers/base/power/wakeup_stats.c +++ b/drivers/base/power/wakeup_stats.c @@ -210,7 +210,7 @@ void wakeup_source_sysfs_remove(struct wakeup_source *ws) static int __init wakeup_sources_sysfs_init(void) { - wakeup_class = class_create(THIS_MODULE, "wakeup"); + wakeup_class = class_create("wakeup"); return PTR_ERR_OR_ZERO(wakeup_class); } diff --git a/drivers/base/property.c b/drivers/base/property.c index 083a95791d3b..f6117ec9805c 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -37,8 +37,10 @@ EXPORT_SYMBOL_GPL(__dev_fwnode_const); * @propname: Name of the property * * Check if property @propname is present in the device firmware description. + * + * Return: true if property @propname is present. Otherwise, returns false. */ -bool device_property_present(struct device *dev, const char *propname) +bool device_property_present(const struct device *dev, const char *propname) { return fwnode_property_present(dev_fwnode(dev), propname); } @@ -48,6 +50,8 @@ EXPORT_SYMBOL_GPL(device_property_present); * fwnode_property_present - check if a property of a firmware node is present * @fwnode: Firmware node whose property to check * @propname: Name of the property + * + * Return: true if property @propname is present. Otherwise, returns false. */ bool fwnode_property_present(const struct fwnode_handle *fwnode, const char *propname) @@ -86,7 +90,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u8_array(struct device *dev, const char *propname, +int device_property_read_u8_array(const struct device *dev, const char *propname, u8 *val, size_t nval) { return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval); @@ -114,7 +118,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u16_array(struct device *dev, const char *propname, +int device_property_read_u16_array(const struct device *dev, const char *propname, u16 *val, size_t nval) { return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval); @@ -142,7 +146,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u32_array(struct device *dev, const char *propname, +int device_property_read_u32_array(const struct device *dev, const char *propname, u32 *val, size_t nval) { return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval); @@ -170,7 +174,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u64_array(struct device *dev, const char *propname, +int device_property_read_u64_array(const struct device *dev, const char *propname, u64 *val, size_t nval) { return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval); @@ -198,7 +202,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_string_array(struct device *dev, const char *propname, +int device_property_read_string_array(const struct device *dev, const char *propname, const char **val, size_t nval) { return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval); @@ -220,7 +224,7 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array); * %-EPROTO or %-EILSEQ if the property type is not a string. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_string(struct device *dev, const char *propname, +int device_property_read_string(const struct device *dev, const char *propname, const char **val) { return fwnode_property_read_string(dev_fwnode(dev), propname, val); @@ -242,7 +246,7 @@ EXPORT_SYMBOL_GPL(device_property_read_string); * %-EPROTO if the property is not an array of strings, * %-ENXIO if no suitable firmware interface is present. */ -int device_property_match_string(struct device *dev, const char *propname, +int device_property_match_string(const struct device *dev, const char *propname, const char *string) { return fwnode_property_match_string(dev_fwnode(dev), propname, string); @@ -508,10 +512,10 @@ EXPORT_SYMBOL_GPL(fwnode_property_match_string); * Obtain a reference based on a named property in an fwnode, with * integer arguments. * - * Caller is responsible to call fwnode_handle_put() on the returned - * args->fwnode pointer. + * The caller is responsible for calling fwnode_handle_put() on the returned + * @args->fwnode pointer. * - * Returns: %0 on success + * Return: %0 on success * %-ENOENT when the index is out of bounds, the index has an empty * reference or the property was not found * %-EINVAL on parse error @@ -547,8 +551,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); * * @index can be used when the named reference holds a table of references. * - * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to - * call fwnode_handle_put() on the returned fwnode pointer. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: a pointer to the reference fwnode, when found. Otherwise, + * returns an error pointer. */ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, const char *name, @@ -567,7 +574,7 @@ EXPORT_SYMBOL_GPL(fwnode_find_reference); * fwnode_get_name - Return the name of a node * @fwnode: The firmware node * - * Returns a pointer to the node name. + * Return: a pointer to the node name, or %NULL. */ const char *fwnode_get_name(const struct fwnode_handle *fwnode) { @@ -579,7 +586,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_name); * fwnode_get_name_prefix - Return the prefix of node for printing purposes * @fwnode: The firmware node * - * Returns the prefix of a node, intended to be printed right before the node. + * Return: the prefix of a node, intended to be printed right before the node. * The prefix works also as a separator between the nodes. */ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) @@ -591,7 +598,10 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) * fwnode_get_parent - Return parent firwmare node * @fwnode: Firmware whose parent is retrieved * - * Return parent firmware node of the given node if possible or %NULL if no + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: parent firmware node of the given node if possible or %NULL if no * parent was available. */ struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) @@ -608,8 +618,12 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent); * on the passed node, making it suitable for iterating through a * node's parents. * - * Returns a node pointer with refcount incremented, use - * fwnode_handle_put() on it when done. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @fwnode + * unconditionally. + * + * Return: parent firmware node of the given node if possible or %NULL if no + * parent was available. */ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) { @@ -629,10 +643,12 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent); * firmware node that has a corresponding struct device and returns that struct * device. * - * The caller of this function is expected to call put_device() on the returned - * device when they are done. + * The caller is responsible for calling put_device() on the returned device + * pointer. + * + * Return: a pointer to the device of the @fwnode's closest ancestor. */ -struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) +struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode) { struct fwnode_handle *parent; struct device *dev; @@ -651,7 +667,7 @@ struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) * fwnode_count_parents - Return the number of parents a node has * @fwnode: The node the parents of which are to be counted * - * Returns the number of parents a node has. + * Return: the number of parents a node has. */ unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode) { @@ -670,12 +686,12 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents); * @fwnode: The node the parent of which is requested * @depth: Distance of the parent from the node * - * Returns the nth parent of a node. If there is no parent at the requested + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the nth parent of a node. If there is no parent at the requested * @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to * fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on. - * - * The caller is responsible for calling fwnode_handle_put() for the returned - * node. */ struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode, unsigned int depth) @@ -700,9 +716,9 @@ EXPORT_SYMBOL_GPL(fwnode_get_nth_parent); * * A node is considered an ancestor of itself too. * - * Returns true if @ancestor is an ancestor of @child. Otherwise, returns false. + * Return: true if @ancestor is an ancestor of @child. Otherwise, returns false. */ -bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle *child) +bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor, const struct fwnode_handle *child) { struct fwnode_handle *parent; @@ -725,6 +741,10 @@ bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle * fwnode_get_next_child_node - Return the next child node handle for a node * @fwnode: Firmware node to find the next child node for. * @child: Handle to one of the node's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle * fwnode_get_next_child_node(const struct fwnode_handle *fwnode, @@ -735,10 +755,13 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode, EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); /** - * fwnode_get_next_available_child_node - Return the next - * available child node handle for a node + * fwnode_get_next_available_child_node - Return the next available child node handle for a node * @fwnode: Firmware node to find the next child node for. * @child: Handle to one of the node's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle * fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode, @@ -762,7 +785,11 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node); /** * device_get_next_child_node - Return the next child node handle for a device * @dev: Device to find the next child node for. - * @child: Handle to one of the device's child nodes or a null handle. + * @child: Handle to one of the device's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle *device_get_next_child_node(const struct device *dev, struct fwnode_handle *child) @@ -787,6 +814,9 @@ EXPORT_SYMBOL_GPL(device_get_next_child_node); * fwnode_get_named_child_node - Return first matching named child node handle * @fwnode: Firmware node to find the named child node for. * @childname: String to match child node name against. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_get_named_child_node(const struct fwnode_handle *fwnode, @@ -800,6 +830,9 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); * device_get_named_child_node - Return first matching named child node handle * @dev: Device to find the named child node for. * @childname: String to match child node name against. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle *device_get_named_child_node(const struct device *dev, const char *childname) @@ -812,7 +845,10 @@ EXPORT_SYMBOL_GPL(device_get_named_child_node); * fwnode_handle_get - Obtain a reference to a device node * @fwnode: Pointer to the device node to obtain the reference to. * - * Returns the fwnode handle. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the fwnode handle. */ struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode) { @@ -841,6 +877,8 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put); * fwnode_device_is_available - check if a device is available for use * @fwnode: Pointer to the fwnode of the device. * + * Return: true if device is available for use. Otherwise, returns false. + * * For fwnode node types that don't implement the .device_is_available() * operation, this function returns true. */ @@ -859,6 +897,8 @@ EXPORT_SYMBOL_GPL(fwnode_device_is_available); /** * device_get_child_node_count - return the number of child nodes for device * @dev: Device to cound the child nodes for + * + * Return: the number of child nodes for a given device. */ unsigned int device_get_child_node_count(const struct device *dev) { @@ -895,7 +935,7 @@ EXPORT_SYMBOL_GPL(device_get_dma_attr); * 'phy-connection-type', and return its index in phy_modes table, or errno in * error case. */ -int fwnode_get_phy_mode(struct fwnode_handle *fwnode) +int fwnode_get_phy_mode(const struct fwnode_handle *fwnode) { const char *pm; int err, i; @@ -934,7 +974,7 @@ EXPORT_SYMBOL_GPL(device_get_phy_mode); * @fwnode: Pointer to the firmware node * @index: Index of the IO range * - * Returns a pointer to the mapped memory. + * Return: a pointer to the mapped memory. */ void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index) { @@ -947,8 +987,8 @@ EXPORT_SYMBOL(fwnode_iomap); * @fwnode: Pointer to the firmware node * @index: Zero-based index of the IRQ * - * Returns Linux IRQ number on success. Other values are determined - * accordingly to acpi_/of_ irq_get() operation. + * Return: Linux IRQ number on success. Other values are determined + * according to acpi_irq_get() or of_irq_get() operation. */ int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index) { @@ -967,8 +1007,7 @@ EXPORT_SYMBOL(fwnode_irq_get); * number of the IRQ resource corresponding to the index of the matched * string. * - * Return: - * Linux IRQ number on success, or negative errno otherwise. + * Return: Linux IRQ number on success, or negative errno otherwise. */ int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name) { @@ -990,7 +1029,11 @@ EXPORT_SYMBOL(fwnode_irq_get_byname); * @fwnode: Pointer to the parent firmware node * @prev: Previous endpoint node or %NULL to get the first * - * Returns an endpoint firmware node pointer or %NULL if no more endpoints + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @prev + * unconditionally. + * + * Return: an endpoint firmware node pointer or %NULL if no more endpoints * are available. */ struct fwnode_handle * @@ -1030,6 +1073,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); * fwnode_graph_get_port_parent - Return the device fwnode of a port endpoint * @endpoint: Endpoint firmware node of the port * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * * Return: the firmware node of the device the @endpoint belongs to. */ struct fwnode_handle * @@ -1051,6 +1097,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote device the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_port_parent(const struct fwnode_handle *fwnode) @@ -1071,6 +1120,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote port the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_port(const struct fwnode_handle *fwnode) @@ -1084,6 +1136,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote endpoint the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode) @@ -1111,8 +1166,11 @@ static bool fwnode_graph_remote_available(struct fwnode_handle *ep) * @endpoint: identifier of the endpoint node under the port node * @flags: fwnode lookup flags * - * Return the fwnode handle of the local endpoint corresponding the port and - * endpoint IDs or NULL if not found. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the fwnode handle of the local endpoint corresponding the port and + * endpoint IDs or %NULL if not found. * * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint * has not been found, look for the closest endpoint ID greater than the @@ -1120,9 +1178,6 @@ static bool fwnode_graph_remote_available(struct fwnode_handle *ep) * * Does not return endpoints that belong to disabled devices or endpoints that * are unconnected, unless FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags. - * - * The returned endpoint needs to be released by calling fwnode_handle_put() on - * it when it is not needed any more. */ struct fwnode_handle * fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, @@ -1180,7 +1235,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id); * If FWNODE_GRAPH_DEVICE_DISABLED flag is specified, also unconnected endpoints * and endpoints connected to disabled devices are counted. */ -unsigned int fwnode_graph_get_endpoint_count(struct fwnode_handle *fwnode, +unsigned int fwnode_graph_get_endpoint_count(const struct fwnode_handle *fwnode, unsigned long flags) { struct fwnode_handle *ep; @@ -1328,7 +1383,8 @@ EXPORT_SYMBOL_GPL(fwnode_connection_find_match); * @fwnode and other device nodes. @match will be used to convert the * connection description to data the caller is expecting to be returned * through the @matches array. - * If @matches is NULL @matches_len is ignored and the total number of resolved + * + * If @matches is %NULL @matches_len is ignored and the total number of resolved * matches is returned. * * Return: Number of matches resolved, or negative errno. diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 33a8366e22a5..0db2021f7477 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,16 +4,23 @@ # subsystems should select the appropriate symbols. config REGMAP + bool "Register Map support" if KUNIT_ALL_TESTS default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI) select IRQ_DOMAIN if REGMAP_IRQ select MDIO_BUS if REGMAP_MDIO - bool + help + Enable support for the Register Map (regmap) access API. + + Usually, this option is automatically selected when needed. + However, you may want to enable it manually for running the regmap + KUnit tests. + + If unsure, say N. config REGMAP_KUNIT tristate "KUnit tests for regmap" - depends on KUNIT + depends on KUNIT && REGMAP default KUNIT_ALL_TESTS - select REGMAP select REGMAP_RAM config REGMAP_AC97 diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c index 9b1b559107ef..c2e3a0f6c218 100644 --- a/drivers/base/regmap/regcache-maple.c +++ b/drivers/base/regmap/regcache-maple.c @@ -203,15 +203,18 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min, mas_for_each(&mas, entry, max) { for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) { + mas_pause(&mas); + rcu_read_unlock(); ret = regcache_sync_val(map, r, entry[r - mas.index]); if (ret != 0) goto out; + rcu_read_lock(); } } -out: rcu_read_unlock(); +out: map->cache_bypass = false; return ret; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 817eda2075aa..c491fabe3617 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -226,8 +226,8 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, if (*ppos < 0 || !count) return -EINVAL; - if (count > (PAGE_SIZE << (MAX_ORDER - 1))) - count = PAGE_SIZE << (MAX_ORDER - 1); + if (count > (PAGE_SIZE << MAX_ORDER)) + count = PAGE_SIZE << MAX_ORDER; buf = kmalloc(count, GFP_KERNEL); if (!buf) @@ -373,8 +373,8 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file, if (*ppos < 0 || !count) return -EINVAL; - if (count > (PAGE_SIZE << (MAX_ORDER - 1))) - count = PAGE_SIZE << (MAX_ORDER - 1); + if (count > (PAGE_SIZE << MAX_ORDER)) + count = PAGE_SIZE << MAX_ORDER; buf = kmalloc(count, GFP_KERNEL); if (!buf) diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c index 09899ae99fc1..159c0b740b00 100644 --- a/drivers/base/regmap/regmap-sdw.c +++ b/drivers/base/regmap/regmap-sdw.c @@ -59,6 +59,10 @@ static int regmap_sdw_config_check(const struct regmap_config *config) if (config->pad_bits != 0) return -ENOTSUPP; + /* Only bulk writes are supported not multi-register writes */ + if (config->can_multi_write) + return -ENOTSUPP; + return 0; } diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index db7851f0e3b8..fa2d3fba6ac9 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2082,6 +2082,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, size_t val_count = val_len / val_bytes; size_t chunk_count, chunk_bytes; size_t chunk_regs = val_count; + size_t max_data = map->max_raw_write - map->format.reg_bytes - + map->format.pad_bytes; int ret, i; if (!val_count) @@ -2089,8 +2091,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, if (map->use_single_write) chunk_regs = 1; - else if (map->max_raw_write && val_len > map->max_raw_write) - chunk_regs = map->max_raw_write / val_bytes; + else if (map->max_raw_write && val_len > max_data) + chunk_regs = max_data / val_bytes; chunk_count = val_count / chunk_regs; chunk_bytes = chunk_regs * val_bytes; diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 0fb1d4ab9d8a..8dec5228fde3 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -110,6 +111,18 @@ static void soc_release(struct device *dev) kfree(soc_dev); } +static void soc_device_get_machine(struct soc_device_attribute *soc_dev_attr) +{ + struct device_node *np; + + if (soc_dev_attr->machine) + return; + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &soc_dev_attr->machine); + of_node_put(np); +} + static struct soc_device_attribute *early_soc_dev_attr; struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) @@ -118,6 +131,8 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr const struct attribute_group **soc_attr_groups; int ret; + soc_device_get_machine(soc_dev_attr); + if (!soc_bus_registered) { if (early_soc_dev_attr) return ERR_PTR(-EBUSY); diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 7a368c90467d..4c666f72203f 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -290,7 +290,7 @@ aoechr_init(void) } init_completion(&emsgs_comp); spin_lock_init(&emsgs_lock); - aoe_class = class_create(THIS_MODULE, "aoe"); + aoe_class = class_create("aoe"); if (IS_ERR(aoe_class)) { unregister_chrdev(AOE_MAJOR, "aoechr"); return PTR_ERR(aoe_class); diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 34177f1bd97d..bcad9b926b0c 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -404,7 +404,6 @@ static int brd_alloc(int i) /* Tell the block layer that this is not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, disk->queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); blk_queue_flag_set(QUEUE_FLAG_NOWAIT, disk->queue); err = add_disk(disk); if (err) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 719a7260c22b..8c2bc47de473 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1283,7 +1283,7 @@ static void one_flush_endio(struct bio *bio) static void submit_one_flush(struct drbd_device *device, struct issue_flush_context *ctx) { struct bio *bio = bio_alloc(device->ldev->backing_bdev, 0, - REQ_OP_FLUSH | REQ_PREFLUSH, GFP_NOIO); + REQ_OP_WRITE | REQ_PREFLUSH, GFP_NOIO); struct one_flush_context *octx = kmalloc(sizeof(*octx), GFP_NOIO); if (!octx) { diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 487840e3564d..cec2c20f5e59 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3108,7 +3108,7 @@ loop: ptr->resultcode = 0; if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) { - if (ptr->length <= 0 || ptr->length >= MAX_LEN) + if (ptr->length <= 0 || ptr->length > MAX_LEN) return -EINVAL; ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length); fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index d445fd0934bd..65ecde3e2a5b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -609,7 +609,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) request.len = htonl(size); } handle = nbd_cmd_handle(cmd); - memcpy(request.handle, &handle, sizeof(handle)); + request.cookie = cpu_to_be64(handle); trace_nbd_send_request(&request, nbd->index, blk_mq_rq_from_pdu(cmd)); @@ -621,7 +621,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) trace_nbd_header_sent(req, handle); if (result < 0) { if (was_interrupted(result)) { - /* If we havne't sent anything we can just return BUSY, + /* If we haven't sent anything we can just return BUSY, * however if we have sent something we need to make * sure we only allow this req to be sent until we are * completely done. @@ -735,7 +735,7 @@ static struct nbd_cmd *nbd_handle_reply(struct nbd_device *nbd, int index, u32 tag; int ret = 0; - memcpy(&handle, reply->handle, sizeof(handle)); + handle = be64_to_cpu(reply->cookie); tag = nbd_handle_to_tag(handle); hwq = blk_mq_unique_tag_to_hwq(tag); if (hwq < nbd->tag_set.nr_hw_queues) @@ -1666,7 +1666,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd) return -EIO; dir = debugfs_create_dir(nbd_name(nbd), nbd_dbg_dir); - if (!dir) { + if (IS_ERR(dir)) { dev_err(nbd_to_dev(nbd), "Failed to create debugfs dir for '%s'\n", nbd_name(nbd)); return -EIO; @@ -1692,7 +1692,7 @@ static int nbd_dbg_init(void) struct dentry *dbg_dir; dbg_dir = debugfs_create_dir("nbd", NULL); - if (!dbg_dir) + if (IS_ERR(dbg_dir)) return -EIO; nbd_dbg_dir = dbg_dir; @@ -1805,7 +1805,6 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) * Tell the block layer that we are not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); disk->queue->limits.discard_granularity = 0; blk_queue_max_discard_sectors(disk->queue, 0); blk_queue_max_segment_size(disk->queue, UINT_MAX); diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index b195b8b9fe32..b3fedafe301e 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -2144,7 +2144,6 @@ static int null_add_dev(struct nullb_device *dev) nullb->q->queuedata = nullb; blk_queue_flag_set(QUEUE_FLAG_NONROT, nullb->q); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, nullb->q); mutex_lock(&lock); rv = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 5ae2a80db2c3..d5d7884cedd4 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -100,7 +100,8 @@ static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t psd_pool; static struct bio_set pkt_bio_set; -static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */ +/* /sys/class/pktcdvd */ +static struct class class_pktcdvd; static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */ /* forward declaration */ @@ -315,8 +316,8 @@ static const struct attribute_group *pkt_groups[] = { static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) { - if (class_pktcdvd) { - pd->dev = device_create_with_groups(class_pktcdvd, NULL, + if (class_is_registered(&class_pktcdvd)) { + pd->dev = device_create_with_groups(&class_pktcdvd, NULL, MKDEV(0, 0), pd, pkt_groups, "%s", pd->name); if (IS_ERR(pd->dev)) @@ -326,7 +327,7 @@ static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) { - if (class_pktcdvd) + if (class_is_registered(&class_pktcdvd)) device_unregister(pd->dev); } @@ -338,12 +339,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) device_map show mappings *******************************************************************/ -static void class_pktcdvd_release(struct class *cls) -{ - kfree(cls); -} - -static ssize_t device_map_show(struct class *c, struct class_attribute *attr, +static ssize_t device_map_show(const struct class *c, const struct class_attribute *attr, char *data) { int n = 0; @@ -364,7 +360,7 @@ static ssize_t device_map_show(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RO(device_map); -static ssize_t add_store(struct class *c, struct class_attribute *attr, +static ssize_t add_store(const struct class *c, const struct class_attribute *attr, const char *buf, size_t count) { unsigned int major, minor; @@ -385,7 +381,7 @@ static ssize_t add_store(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_WO(add); -static ssize_t remove_store(struct class *c, struct class_attribute *attr, +static ssize_t remove_store(const struct class *c, const struct class_attribute *attr, const char *buf, size_t count) { unsigned int major, minor; @@ -405,36 +401,23 @@ static struct attribute *class_pktcdvd_attrs[] = { }; ATTRIBUTE_GROUPS(class_pktcdvd); +static struct class class_pktcdvd = { + .name = DRIVER_NAME, + .class_groups = class_pktcdvd_groups, +}; + static int pkt_sysfs_init(void) { - int ret = 0; - /* * create control files in sysfs * /sys/class/pktcdvd/... */ - class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL); - if (!class_pktcdvd) - return -ENOMEM; - class_pktcdvd->name = DRIVER_NAME; - class_pktcdvd->owner = THIS_MODULE; - class_pktcdvd->class_release = class_pktcdvd_release; - class_pktcdvd->class_groups = class_pktcdvd_groups; - ret = class_register(class_pktcdvd); - if (ret) { - kfree(class_pktcdvd); - class_pktcdvd = NULL; - pr_err("failed to create class pktcdvd\n"); - return ret; - } - return 0; + return class_register(&class_pktcdvd); } static void pkt_sysfs_cleanup(void) { - if (class_pktcdvd) - class_destroy(class_pktcdvd); - class_pktcdvd = NULL; + class_unregister(&class_pktcdvd); } /******************************************************************** diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 5cb008b9700a..84ad3b17956f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -491,12 +491,12 @@ static bool single_major = true; module_param(single_major, bool, 0444); MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: true)"); -static ssize_t add_store(struct bus_type *bus, const char *buf, size_t count); -static ssize_t remove_store(struct bus_type *bus, const char *buf, +static ssize_t add_store(const struct bus_type *bus, const char *buf, size_t count); +static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count); -static ssize_t add_single_major_store(struct bus_type *bus, const char *buf, +static ssize_t add_single_major_store(const struct bus_type *bus, const char *buf, size_t count); -static ssize_t remove_single_major_store(struct bus_type *bus, const char *buf, +static ssize_t remove_single_major_store(const struct bus_type *bus, const char *buf, size_t count); static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth); @@ -538,7 +538,7 @@ static bool rbd_is_lock_owner(struct rbd_device *rbd_dev) return is_lock_owner; } -static ssize_t supported_features_show(struct bus_type *bus, char *buf) +static ssize_t supported_features_show(const struct bus_type *bus, char *buf) { return sprintf(buf, "0x%llx\n", RBD_FEATURES_SUPPORTED); } @@ -6967,9 +6967,7 @@ err_out_format: return ret; } -static ssize_t do_rbd_add(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_add(const char *buf, size_t count) { struct rbd_device *rbd_dev = NULL; struct ceph_options *ceph_opts = NULL; @@ -7081,18 +7079,18 @@ err_out_args: goto out; } -static ssize_t add_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t add_store(const struct bus_type *bus, const char *buf, size_t count) { if (single_major) return -EINVAL; - return do_rbd_add(bus, buf, count); + return do_rbd_add(buf, count); } -static ssize_t add_single_major_store(struct bus_type *bus, const char *buf, +static ssize_t add_single_major_store(const struct bus_type *bus, const char *buf, size_t count) { - return do_rbd_add(bus, buf, count); + return do_rbd_add(buf, count); } static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) @@ -7122,9 +7120,7 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev) } } -static ssize_t do_rbd_remove(struct bus_type *bus, - const char *buf, - size_t count) +static ssize_t do_rbd_remove(const char *buf, size_t count) { struct rbd_device *rbd_dev = NULL; struct list_head *tmp; @@ -7196,18 +7192,18 @@ static ssize_t do_rbd_remove(struct bus_type *bus, return count; } -static ssize_t remove_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count) { if (single_major) return -EINVAL; - return do_rbd_remove(bus, buf, count); + return do_rbd_remove(buf, count); } -static ssize_t remove_single_major_store(struct bus_type *bus, const char *buf, +static ssize_t remove_single_major_store(const struct bus_type *bus, const char *buf, size_t count) { - return do_rbd_remove(bus, buf, count); + return do_rbd_remove(buf, count); } /* diff --git a/drivers/block/rnbd/rnbd-clt-sysfs.c b/drivers/block/rnbd/rnbd-clt-sysfs.c index e7c7d9a68168..8c6087949794 100644 --- a/drivers/block/rnbd/rnbd-clt-sysfs.c +++ b/drivers/block/rnbd/rnbd-clt-sysfs.c @@ -646,7 +646,7 @@ int rnbd_clt_create_sysfs_files(void) { int err; - rnbd_dev_class = class_create(THIS_MODULE, "rnbd-client"); + rnbd_dev_class = class_create("rnbd-client"); if (IS_ERR(rnbd_dev_class)) return PTR_ERR(rnbd_dev_class); diff --git a/drivers/block/rnbd/rnbd-proto.h b/drivers/block/rnbd/rnbd-proto.h index ea7ac8bca63c..da1d0542d7e2 100644 --- a/drivers/block/rnbd/rnbd-proto.h +++ b/drivers/block/rnbd/rnbd-proto.h @@ -241,7 +241,7 @@ static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf) bio_opf = REQ_OP_WRITE; break; case RNBD_OP_FLUSH: - bio_opf = REQ_OP_FLUSH | REQ_PREFLUSH; + bio_opf = REQ_OP_WRITE | REQ_PREFLUSH; break; case RNBD_OP_DISCARD: bio_opf = REQ_OP_DISCARD; diff --git a/drivers/block/rnbd/rnbd-srv-sysfs.c b/drivers/block/rnbd/rnbd-srv-sysfs.c index 297a6924ff4e..d5d9267e1fa5 100644 --- a/drivers/block/rnbd/rnbd-srv-sysfs.c +++ b/drivers/block/rnbd/rnbd-srv-sysfs.c @@ -215,7 +215,7 @@ int rnbd_srv_create_sysfs_files(void) { int err; - rnbd_dev_class = class_create(THIS_MODULE, "rnbd-server"); + rnbd_dev_class = class_create("rnbd-server"); if (IS_ERR(rnbd_dev_class)) return PTR_ERR(rnbd_dev_class); diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index afbef182820b..33d3298a0da1 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -129,6 +129,7 @@ struct ublk_queue { unsigned long io_addr; /* mapped vm address */ unsigned int max_io_sz; bool force_abort; + bool timeout; unsigned short nr_io_ready; /* how many ios setup */ struct ublk_device *dev; struct ublk_io ios[]; @@ -898,6 +899,22 @@ static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq) } } +static enum blk_eh_timer_return ublk_timeout(struct request *rq) +{ + struct ublk_queue *ubq = rq->mq_hctx->driver_data; + + if (ubq->flags & UBLK_F_UNPRIVILEGED_DEV) { + if (!ubq->timeout) { + send_sig(SIGKILL, ubq->ubq_daemon, 0); + ubq->timeout = true; + } + + return BLK_EH_DONE; + } + + return BLK_EH_RESET_TIMER; +} + static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { @@ -957,6 +974,7 @@ static const struct blk_mq_ops ublk_mq_ops = { .queue_rq = ublk_queue_rq, .init_hctx = ublk_init_hctx, .init_request = ublk_init_rq, + .timeout = ublk_timeout, }; static int ublk_ch_open(struct inode *inode, struct file *filp) @@ -1017,7 +1035,7 @@ static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma) } static void ublk_commit_completion(struct ublk_device *ub, - struct ublksrv_io_cmd *ub_cmd) + const struct ublksrv_io_cmd *ub_cmd) { u32 qid = ub_cmd->q_id, tag = ub_cmd->tag; struct ublk_queue *ubq = ublk_get_queue(ub, qid); @@ -1102,6 +1120,11 @@ static inline bool ublk_queue_ready(struct ublk_queue *ubq) return ubq->nr_io_ready == ubq->q_depth; } +static void ublk_cmd_cancel_cb(struct io_uring_cmd *cmd, unsigned issue_flags) +{ + io_uring_cmd_done(cmd, UBLK_IO_RES_ABORT, 0, issue_flags); +} + static void ublk_cancel_queue(struct ublk_queue *ubq) { int i; @@ -1113,8 +1136,8 @@ static void ublk_cancel_queue(struct ublk_queue *ubq) struct ublk_io *io = &ubq->ios[i]; if (io->flags & UBLK_IO_FLAG_ACTIVE) - io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0, - IO_URING_F_UNLOCKED); + io_uring_cmd_complete_in_task(io->cmd, + ublk_cmd_cancel_cb); } /* all io commands are canceled */ @@ -1263,7 +1286,7 @@ static inline int ublk_check_cmd_op(u32 cmd_op) { u32 ioc_type = _IOC_TYPE(cmd_op); - if (IS_ENABLED(CONFIG_BLKDEV_UBLK_LEGACY_OPCODES) && ioc_type != 'u') + if (!IS_ENABLED(CONFIG_BLKDEV_UBLK_LEGACY_OPCODES) && ioc_type != 'u') return -EOPNOTSUPP; if (ioc_type != 'u' && ioc_type != 0) @@ -1274,7 +1297,7 @@ static inline int ublk_check_cmd_op(u32 cmd_op) static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags, - struct ublksrv_io_cmd *ub_cmd) + const struct ublksrv_io_cmd *ub_cmd) { struct ublk_device *ub = cmd->file->private_data; struct ublk_queue *ubq; @@ -1381,17 +1404,17 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { - struct ublksrv_io_cmd *ub_src = (struct ublksrv_io_cmd *) cmd->cmd; - struct ublksrv_io_cmd ub_cmd; - /* * Not necessary for async retry, but let's keep it simple and always * copy the values to avoid any potential reuse. */ - ub_cmd.q_id = READ_ONCE(ub_src->q_id); - ub_cmd.tag = READ_ONCE(ub_src->tag); - ub_cmd.result = READ_ONCE(ub_src->result); - ub_cmd.addr = READ_ONCE(ub_src->addr); + const struct ublksrv_io_cmd *ub_src = io_uring_sqe_cmd(cmd->sqe); + const struct ublksrv_io_cmd ub_cmd = { + .q_id = READ_ONCE(ub_src->q_id), + .tag = READ_ONCE(ub_src->tag), + .result = READ_ONCE(ub_src->result), + .addr = READ_ONCE(ub_src->addr) + }; return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd); } @@ -1601,7 +1624,7 @@ static struct ublk_device *ublk_get_device_from_id(int idx) static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); int ublksrv_pid = (int)header->data[0]; struct gendisk *disk; int ret = -EINVAL; @@ -1664,7 +1687,7 @@ out_unlock: static int ublk_ctrl_get_queue_affinity(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); void __user *argp = (void __user *)(unsigned long)header->addr; cpumask_var_t cpumask; unsigned long queue; @@ -1715,7 +1738,7 @@ static inline void ublk_dump_dev_info(struct ublksrv_ctrl_dev_info *info) static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); void __user *argp = (void __user *)(unsigned long)header->addr; struct ublksrv_ctrl_dev_info info; struct ublk_device *ub; @@ -1737,6 +1760,18 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) else if (!(info.flags & UBLK_F_UNPRIVILEGED_DEV)) return -EPERM; + /* + * unprivileged device can't be trusted, but RECOVERY and + * RECOVERY_REISSUE still may hang error handling, so can't + * support recovery features for unprivileged ublk now + * + * TODO: provide forward progress for RECOVERY handler, so that + * unprivileged device can benefit from it + */ + if (info.flags & UBLK_F_UNPRIVILEGED_DEV) + info.flags &= ~(UBLK_F_USER_RECOVERY_REISSUE | + UBLK_F_USER_RECOVERY); + /* the created device is always owned by current user */ ublk_store_owner_uid_gid(&info.owner_uid, &info.owner_gid); @@ -1880,7 +1915,7 @@ static int ublk_ctrl_del_dev(struct ublk_device **p_ub) static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); pr_devel("%s: cmd_op %x, dev id %d qid %d data %llx buf %llx len %u\n", __func__, cmd->cmd_op, header->dev_id, header->queue_id, @@ -1899,7 +1934,7 @@ static int ublk_ctrl_stop_dev(struct ublk_device *ub) static int ublk_ctrl_get_dev_info(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); void __user *argp = (void __user *)(unsigned long)header->addr; if (header->len < sizeof(struct ublksrv_ctrl_dev_info) || !header->addr) @@ -1930,7 +1965,7 @@ static void ublk_ctrl_fill_params_devt(struct ublk_device *ub) static int ublk_ctrl_get_params(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); void __user *argp = (void __user *)(unsigned long)header->addr; struct ublk_params_header ph; int ret; @@ -1961,7 +1996,7 @@ static int ublk_ctrl_get_params(struct ublk_device *ub, static int ublk_ctrl_set_params(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); void __user *argp = (void __user *)(unsigned long)header->addr; struct ublk_params_header ph; int ret = -EFAULT; @@ -2007,6 +2042,7 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) put_task_struct(ubq->ubq_daemon); /* We have to reset it to NULL, otherwise ub won't accept new FETCH_REQ */ ubq->ubq_daemon = NULL; + ubq->timeout = false; for (i = 0; i < ubq->q_depth; i++) { struct ublk_io *io = &ubq->ios[i]; @@ -2021,7 +2057,7 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq) static int ublk_ctrl_start_recovery(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); int ret = -EINVAL; int i; @@ -2063,7 +2099,7 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, static int ublk_ctrl_end_recovery(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); int ublksrv_pid = (int)header->data[0]; int ret = -EINVAL; @@ -2130,7 +2166,7 @@ exit: static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, struct io_uring_cmd *cmd) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)io_uring_sqe_cmd(cmd->sqe); bool unprivileged = ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV; void __user *argp = (void __user *)(unsigned long)header->addr; char *dev_path = NULL; @@ -2209,7 +2245,7 @@ exit: static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { - struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); struct ublk_device *ub = NULL; u32 cmd_op = cmd->cmd_op; int ret = -EINVAL; @@ -2311,7 +2347,7 @@ static int __init ublk_init(void) if (ret) goto unregister_mis; - ublk_chr_class = class_create(THIS_MODULE, "ublk-char"); + ublk_chr_class = class_create("ublk-char"); if (IS_ERR(ublk_chr_class)) { ret = PTR_ERR(ublk_chr_class); goto free_chrdev_region; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index a5cf7f1e871c..c362f4ad80ab 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -239,9 +239,9 @@ static void put_persistent_gnt(struct xen_blkif_ring *ring, atomic_dec(&ring->persistent_gnt_in_use); } -static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *root, - unsigned int num) +static void free_persistent_gnts(struct xen_blkif_ring *ring) { + struct rb_root *root = &ring->persistent_gnts; struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct persistent_gnt *persistent_gnt; @@ -249,6 +249,9 @@ static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *ro int segs_to_unmap = 0; struct gntab_unmap_queue_data unmap_data; + if (RB_EMPTY_ROOT(root)) + return; + unmap_data.pages = pages; unmap_data.unmap_ops = unmap; unmap_data.kunmap_ops = NULL; @@ -277,9 +280,11 @@ static void free_persistent_gnts(struct xen_blkif_ring *ring, struct rb_root *ro rb_erase(&persistent_gnt->node, root); kfree(persistent_gnt); - num--; + ring->persistent_gnt_c--; } - BUG_ON(num != 0); + + BUG_ON(!RB_EMPTY_ROOT(&ring->persistent_gnts)); + BUG_ON(ring->persistent_gnt_c != 0); } void xen_blkbk_unmap_purged_grants(struct work_struct *work) @@ -631,12 +636,7 @@ purge_gnt_list: void xen_blkbk_free_caches(struct xen_blkif_ring *ring) { /* Free all persistent grant pages */ - if (!RB_EMPTY_ROOT(&ring->persistent_gnts)) - free_persistent_gnts(ring, &ring->persistent_gnts, - ring->persistent_gnt_c); - - BUG_ON(!RB_EMPTY_ROOT(&ring->persistent_gnts)); - ring->persistent_gnt_c = 0; + free_persistent_gnts(ring); /* Since we are shutting down remove all pages from the buffer */ gnttab_page_cache_shrink(&ring->free_pages, 0 /* All */); @@ -891,7 +891,7 @@ next: out: for (i = last_map; i < num; i++) { /* Don't zap current batch's valid persistent grants. */ - if(i >= map_until) + if (i >= map_until) pages[i]->persistent_gnt = NULL; pages[i]->handle = BLKBACK_INVALID_HANDLE; } @@ -1072,7 +1072,111 @@ static void end_block_io_op(struct bio *bio) bio_put(bio); } +static void blkif_get_x86_32_req(struct blkif_request *dst, + const struct blkif_x86_32_request *src) +{ + unsigned int i, n; + dst->operation = READ_ONCE(src->operation); + + switch (dst->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = READ_ONCE(src->u.rw.nr_segments); + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; + dst->u.rw.sector_number = src->u.rw.sector_number; + n = min_t(unsigned int, BLKIF_MAX_SEGMENTS_PER_REQUEST, + dst->u.rw.nr_segments); + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + + case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + + case BLKIF_OP_INDIRECT: + dst->u.indirect.indirect_op = src->u.indirect.indirect_op; + dst->u.indirect.nr_segments = + READ_ONCE(src->u.indirect.nr_segments); + dst->u.indirect.handle = src->u.indirect.handle; + dst->u.indirect.id = src->u.indirect.id; + dst->u.indirect.sector_number = src->u.indirect.sector_number; + n = min(MAX_INDIRECT_PAGES, + INDIRECT_PAGES(dst->u.indirect.nr_segments)); + for (i = 0; i < n; i++) + dst->u.indirect.indirect_grefs[i] = + src->u.indirect.indirect_grefs[i]; + break; + + default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; + break; + } +} + +static void blkif_get_x86_64_req(struct blkif_request *dst, + const struct blkif_x86_64_request *src) +{ + unsigned int i, n; + + dst->operation = READ_ONCE(src->operation); + + switch (dst->operation) { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = READ_ONCE(src->u.rw.nr_segments); + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; + dst->u.rw.sector_number = src->u.rw.sector_number; + n = min_t(unsigned int, BLKIF_MAX_SEGMENTS_PER_REQUEST, + dst->u.rw.nr_segments); + for (i = 0; i < n; i++) + dst->u.rw.seg[i] = src->u.rw.seg[i]; + break; + + case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; + dst->u.discard.id = src->u.discard.id; + dst->u.discard.sector_number = src->u.discard.sector_number; + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + + case BLKIF_OP_INDIRECT: + dst->u.indirect.indirect_op = src->u.indirect.indirect_op; + dst->u.indirect.nr_segments = + READ_ONCE(src->u.indirect.nr_segments); + dst->u.indirect.handle = src->u.indirect.handle; + dst->u.indirect.id = src->u.indirect.id; + dst->u.indirect.sector_number = src->u.indirect.sector_number; + n = min(MAX_INDIRECT_PAGES, + INDIRECT_PAGES(dst->u.indirect.nr_segments)); + for (i = 0; i < n; i++) + dst->u.indirect.indirect_grefs[i] = + src->u.indirect.indirect_grefs[i]; + break; + + default: + /* + * Don't know how to translate this op. Only get the + * ID so failure can be reported to the frontend. + */ + dst->u.other.id = src->u.other.id; + break; + } +} /* * Function to copy the from the ring buffer the 'struct blkif_request' diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index a28473470e66..40f67bfc052d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -296,7 +296,7 @@ struct xen_blkif_ring { struct work_struct free_work; /* Thread shutdown wait queue. */ wait_queue_head_t shutdown_wq; - struct xen_blkif *blkif; + struct xen_blkif *blkif; }; struct xen_blkif { @@ -315,7 +315,7 @@ struct xen_blkif { atomic_t drain; struct work_struct free_work; - unsigned int nr_ring_pages; + unsigned int nr_ring_pages; bool multi_ref; /* All rings for this device. */ struct xen_blkif_ring *rings; @@ -329,7 +329,7 @@ struct seg_buf { }; struct grant_page { - struct page *page; + struct page *page; struct persistent_gnt *persistent_gnt; grant_handle_t handle; grant_ref_t gref; @@ -384,7 +384,6 @@ void xen_blkif_xenbus_fini(void); irqreturn_t xen_blkif_be_int(int irq, void *dev_id); int xen_blkif_schedule(void *arg); -int xen_blkif_purge_persistent(void *arg); void xen_blkbk_free_caches(struct xen_blkif_ring *ring); int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, @@ -395,100 +394,4 @@ int xen_blkbk_barrier(struct xenbus_transaction xbt, struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be); void xen_blkbk_unmap_purged_grants(struct work_struct *work); -static inline void blkif_get_x86_32_req(struct blkif_request *dst, - struct blkif_x86_32_request *src) -{ - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j; - dst->operation = READ_ONCE(src->operation); - switch (dst->operation) { - case BLKIF_OP_READ: - case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: - case BLKIF_OP_FLUSH_DISKCACHE: - dst->u.rw.nr_segments = src->u.rw.nr_segments; - dst->u.rw.handle = src->u.rw.handle; - dst->u.rw.id = src->u.rw.id; - dst->u.rw.sector_number = src->u.rw.sector_number; - barrier(); - if (n > dst->u.rw.nr_segments) - n = dst->u.rw.nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->u.rw.seg[i]; - break; - case BLKIF_OP_DISCARD: - dst->u.discard.flag = src->u.discard.flag; - dst->u.discard.id = src->u.discard.id; - dst->u.discard.sector_number = src->u.discard.sector_number; - dst->u.discard.nr_sectors = src->u.discard.nr_sectors; - break; - case BLKIF_OP_INDIRECT: - dst->u.indirect.indirect_op = src->u.indirect.indirect_op; - dst->u.indirect.nr_segments = src->u.indirect.nr_segments; - dst->u.indirect.handle = src->u.indirect.handle; - dst->u.indirect.id = src->u.indirect.id; - dst->u.indirect.sector_number = src->u.indirect.sector_number; - barrier(); - j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments)); - for (i = 0; i < j; i++) - dst->u.indirect.indirect_grefs[i] = - src->u.indirect.indirect_grefs[i]; - break; - default: - /* - * Don't know how to translate this op. Only get the - * ID so failure can be reported to the frontend. - */ - dst->u.other.id = src->u.other.id; - break; - } -} - -static inline void blkif_get_x86_64_req(struct blkif_request *dst, - struct blkif_x86_64_request *src) -{ - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j; - dst->operation = READ_ONCE(src->operation); - switch (dst->operation) { - case BLKIF_OP_READ: - case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: - case BLKIF_OP_FLUSH_DISKCACHE: - dst->u.rw.nr_segments = src->u.rw.nr_segments; - dst->u.rw.handle = src->u.rw.handle; - dst->u.rw.id = src->u.rw.id; - dst->u.rw.sector_number = src->u.rw.sector_number; - barrier(); - if (n > dst->u.rw.nr_segments) - n = dst->u.rw.nr_segments; - for (i = 0; i < n; i++) - dst->u.rw.seg[i] = src->u.rw.seg[i]; - break; - case BLKIF_OP_DISCARD: - dst->u.discard.flag = src->u.discard.flag; - dst->u.discard.id = src->u.discard.id; - dst->u.discard.sector_number = src->u.discard.sector_number; - dst->u.discard.nr_sectors = src->u.discard.nr_sectors; - break; - case BLKIF_OP_INDIRECT: - dst->u.indirect.indirect_op = src->u.indirect.indirect_op; - dst->u.indirect.nr_segments = src->u.indirect.nr_segments; - dst->u.indirect.handle = src->u.indirect.handle; - dst->u.indirect.id = src->u.indirect.id; - dst->u.indirect.sector_number = src->u.indirect.sector_number; - barrier(); - j = min(MAX_INDIRECT_PAGES, INDIRECT_PAGES(dst->u.indirect.nr_segments)); - for (i = 0; i < j; i++) - dst->u.indirect.indirect_grefs[i] = - src->u.indirect.indirect_grefs[i]; - break; - default: - /* - * Don't know how to translate this op. Only get the - * ID so failure can be reported to the frontend. - */ - dst->u.other.id = src->u.other.id; - break; - } -} - #endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 23ed258b57f0..c1890c8a9f6e 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -780,7 +780,8 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri ring_req->u.rw.handle = info->handle; ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; - if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) { + if (req_op(req) == REQ_OP_FLUSH || + (req_op(req) == REQ_OP_WRITE && (req->cmd_flags & REQ_FUA))) { /* * Ideally we can do an unordered flush-to-disk. * In case the backend onlysupports barriers, use that. diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index aa490da3cef2..f6d90f1ba5cf 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -54,9 +54,8 @@ static size_t huge_class_size; static const struct block_device_operations zram_devops; static void zram_free_page(struct zram *zram, size_t index); -static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, - u32 index, int offset, struct bio *bio); - +static int zram_read_page(struct zram *zram, struct page *page, u32 index, + struct bio *parent); static int zram_slot_trylock(struct zram *zram, u32 index) { @@ -148,6 +147,7 @@ static inline bool is_partial_io(struct bio_vec *bvec) { return bvec->bv_len != PAGE_SIZE; } +#define ZRAM_PARTIAL_IO 1 #else static inline bool is_partial_io(struct bio_vec *bvec) { @@ -174,36 +174,6 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index) return prio & ZRAM_COMP_PRIORITY_MASK; } -/* - * Check if request is within bounds and aligned on zram logical blocks. - */ -static inline bool valid_io_request(struct zram *zram, - sector_t start, unsigned int size) -{ - u64 end, bound; - - /* unaligned request */ - if (unlikely(start & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) - return false; - if (unlikely(size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) - return false; - - end = start + (size >> SECTOR_SHIFT); - bound = zram->disksize >> SECTOR_SHIFT; - /* out of range */ - if (unlikely(start >= bound || end > bound || start > end)) - return false; - - /* I/O request is valid */ - return true; -} - -static void update_position(u32 *index, int *offset, struct bio_vec *bvec) -{ - *index += (*offset + bvec->bv_len) / PAGE_SIZE; - *offset = (*offset + bvec->bv_len) % PAGE_SIZE; -} - static inline void update_used_max(struct zram *zram, const unsigned long pages) { @@ -606,41 +576,16 @@ static void free_block_bdev(struct zram *zram, unsigned long blk_idx) atomic64_dec(&zram->stats.bd_count); } -static void zram_page_end_io(struct bio *bio) -{ - struct page *page = bio_first_page_all(bio); - - page_endio(page, op_is_write(bio_op(bio)), - blk_status_to_errno(bio->bi_status)); - bio_put(bio); -} - -/* - * Returns 1 if the submission is successful. - */ -static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, +static void read_from_bdev_async(struct zram *zram, struct page *page, unsigned long entry, struct bio *parent) { struct bio *bio; - bio = bio_alloc(zram->bdev, 1, parent ? parent->bi_opf : REQ_OP_READ, - GFP_NOIO); - if (!bio) - return -ENOMEM; - + bio = bio_alloc(zram->bdev, 1, parent->bi_opf, GFP_NOIO); bio->bi_iter.bi_sector = entry * (PAGE_SIZE >> 9); - if (!bio_add_page(bio, bvec->bv_page, bvec->bv_len, bvec->bv_offset)) { - bio_put(bio); - return -EIO; - } - - if (!parent) - bio->bi_end_io = zram_page_end_io; - else - bio_chain(bio, parent); - + __bio_add_page(bio, page, PAGE_SIZE, 0); + bio_chain(bio, parent); submit_bio(bio); - return 1; } #define PAGE_WB_SIG "page_index=" @@ -701,10 +646,6 @@ static ssize_t writeback_store(struct device *dev, } for (; nr_pages != 0; index++, nr_pages--) { - struct bio_vec bvec; - - bvec_set_page(&bvec, page, PAGE_SIZE, 0); - spin_lock(&zram->wb_limit_lock); if (zram->wb_limit_enable && !zram->bd_wb_limit) { spin_unlock(&zram->wb_limit_lock); @@ -748,7 +689,7 @@ static ssize_t writeback_store(struct device *dev, /* Need for hugepage writeback racing */ zram_set_flag(zram, index, ZRAM_IDLE); zram_slot_unlock(zram, index); - if (zram_bvec_read(zram, &bvec, index, 0, NULL)) { + if (zram_read_page(zram, page, index, NULL)) { zram_slot_lock(zram, index); zram_clear_flag(zram, index, ZRAM_UNDER_WB); zram_clear_flag(zram, index, ZRAM_IDLE); @@ -759,9 +700,8 @@ static ssize_t writeback_store(struct device *dev, bio_init(&bio, zram->bdev, &bio_vec, 1, REQ_OP_WRITE | REQ_SYNC); bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9); + bio_add_page(&bio, page, PAGE_SIZE, 0); - bio_add_page(&bio, bvec.bv_page, bvec.bv_len, - bvec.bv_offset); /* * XXX: A single page IO would be inefficient for write * but it would be not bad as starter. @@ -829,19 +769,20 @@ struct zram_work { struct work_struct work; struct zram *zram; unsigned long entry; - struct bio *bio; - struct bio_vec bvec; + struct page *page; + int error; }; -#if PAGE_SIZE != 4096 static void zram_sync_read(struct work_struct *work) { struct zram_work *zw = container_of(work, struct zram_work, work); - struct zram *zram = zw->zram; - unsigned long entry = zw->entry; - struct bio *bio = zw->bio; + struct bio_vec bv; + struct bio bio; - read_from_bdev_async(zram, &zw->bvec, entry, bio); + bio_init(&bio, zw->zram->bdev, &bv, 1, REQ_OP_READ); + bio.bi_iter.bi_sector = zw->entry * (PAGE_SIZE >> 9); + __bio_add_page(&bio, zw->page, PAGE_SIZE, 0); + zw->error = submit_bio_wait(&bio); } /* @@ -849,45 +790,39 @@ static void zram_sync_read(struct work_struct *work) * chained IO with parent IO in same context, it's a deadlock. To avoid that, * use a worker thread context. */ -static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec, - unsigned long entry, struct bio *bio) +static int read_from_bdev_sync(struct zram *zram, struct page *page, + unsigned long entry) { struct zram_work work; - work.bvec = *bvec; + work.page = page; work.zram = zram; work.entry = entry; - work.bio = bio; INIT_WORK_ONSTACK(&work.work, zram_sync_read); queue_work(system_unbound_wq, &work.work); flush_work(&work.work); destroy_work_on_stack(&work.work); - return 1; + return work.error; } -#else -static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec, - unsigned long entry, struct bio *bio) -{ - WARN_ON(1); - return -EIO; -} -#endif -static int read_from_bdev(struct zram *zram, struct bio_vec *bvec, - unsigned long entry, struct bio *parent, bool sync) +static int read_from_bdev(struct zram *zram, struct page *page, + unsigned long entry, struct bio *parent) { atomic64_inc(&zram->stats.bd_reads); - if (sync) - return read_from_bdev_sync(zram, bvec, entry, parent); - else - return read_from_bdev_async(zram, bvec, entry, parent); + if (!parent) { + if (WARN_ON_ONCE(!IS_ENABLED(ZRAM_PARTIAL_IO))) + return -EIO; + return read_from_bdev_sync(zram, page, entry); + } + read_from_bdev_async(zram, page, entry, parent); + return 0; } #else static inline void reset_bdev(struct zram *zram) {}; -static int read_from_bdev(struct zram *zram, struct bio_vec *bvec, - unsigned long entry, struct bio *parent, bool sync) +static int read_from_bdev(struct zram *zram, struct page *page, + unsigned long entry, struct bio *parent) { return -EIO; } @@ -1190,10 +1125,9 @@ static ssize_t io_stat_show(struct device *dev, down_read(&zram->init_lock); ret = scnprintf(buf, PAGE_SIZE, - "%8llu %8llu %8llu %8llu\n", + "%8llu %8llu 0 %8llu\n", (u64)atomic64_read(&zram->stats.failed_reads), (u64)atomic64_read(&zram->stats.failed_writes), - (u64)atomic64_read(&zram->stats.invalid_io), (u64)atomic64_read(&zram->stats.notify_free)); up_read(&zram->init_lock); @@ -1371,20 +1305,6 @@ out: ~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB)); } -/* - * Reads a page from the writeback devices. Corresponding ZRAM slot - * should be unlocked. - */ -static int zram_bvec_read_from_bdev(struct zram *zram, struct page *page, - u32 index, struct bio *bio, bool partial_io) -{ - struct bio_vec bvec; - - bvec_set_page(&bvec, page, PAGE_SIZE, 0); - return read_from_bdev(zram, &bvec, zram_get_element(zram, index), bio, - partial_io); -} - /* * Reads (decompresses if needed) a page from zspool (zsmalloc). * Corresponding ZRAM slot should be locked. @@ -1434,8 +1354,8 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page, return ret; } -static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, - struct bio *bio, bool partial_io) +static int zram_read_page(struct zram *zram, struct page *page, u32 index, + struct bio *parent) { int ret; @@ -1445,11 +1365,14 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, ret = zram_read_from_zspool(zram, page, index); zram_slot_unlock(zram, index); } else { - /* Slot should be unlocked before the function call */ + /* + * The slot should be unlocked before reading from the backing + * device. + */ zram_slot_unlock(zram, index); - ret = zram_bvec_read_from_bdev(zram, page, index, bio, - partial_io); + ret = read_from_bdev(zram, page, zram_get_element(zram, index), + parent); } /* Should NEVER happen. Return bio error if it does. */ @@ -1459,39 +1382,34 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, return ret; } -static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, - u32 index, int offset, struct bio *bio) +/* + * Use a temporary buffer to decompress the page, as the decompressor + * always expects a full page for the output. + */ +static int zram_bvec_read_partial(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset) { + struct page *page = alloc_page(GFP_NOIO); int ret; - struct page *page; - - page = bvec->bv_page; - if (is_partial_io(bvec)) { - /* Use a temporary buffer to decompress the page */ - page = alloc_page(GFP_NOIO|__GFP_HIGHMEM); - if (!page) - return -ENOMEM; - } - - ret = __zram_bvec_read(zram, page, index, bio, is_partial_io(bvec)); - if (unlikely(ret)) - goto out; - - if (is_partial_io(bvec)) { - void *src = kmap_atomic(page); - - memcpy_to_bvec(bvec, src + offset); - kunmap_atomic(src); - } -out: - if (is_partial_io(bvec)) - __free_page(page); + if (!page) + return -ENOMEM; + ret = zram_read_page(zram, page, index, NULL); + if (likely(!ret)) + memcpy_to_bvec(bvec, page_address(page) + offset); + __free_page(page); return ret; } -static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, - u32 index, struct bio *bio) +static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio) +{ + if (is_partial_io(bvec)) + return zram_bvec_read_partial(zram, bvec, index, offset); + return zram_read_page(zram, bvec->bv_page, index, bio); +} + +static int zram_write_page(struct zram *zram, struct page *page, u32 index) { int ret = 0; unsigned long alloced_pages; @@ -1499,7 +1417,6 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, unsigned int comp_len = 0; void *src, *dst, *mem; struct zcomp_strm *zstrm; - struct page *page = bvec->bv_page; unsigned long element = 0; enum zram_pageflags flags = 0; @@ -1617,42 +1534,35 @@ out: return ret; } -static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, - u32 index, int offset, struct bio *bio) +/* + * This is a partial IO. Read the full page before writing the changes. + */ +static int zram_bvec_write_partial(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio) { + struct page *page = alloc_page(GFP_NOIO); int ret; - struct page *page = NULL; - struct bio_vec vec; - vec = *bvec; - if (is_partial_io(bvec)) { - void *dst; - /* - * This is a partial IO. We need to read the full page - * before to write the changes. - */ - page = alloc_page(GFP_NOIO|__GFP_HIGHMEM); - if (!page) - return -ENOMEM; + if (!page) + return -ENOMEM; - ret = __zram_bvec_read(zram, page, index, bio, true); - if (ret) - goto out; - - dst = kmap_atomic(page); - memcpy_from_bvec(dst + offset, bvec); - kunmap_atomic(dst); - - bvec_set_page(&vec, page, PAGE_SIZE, 0); + ret = zram_read_page(zram, page, index, bio); + if (!ret) { + memcpy_from_bvec(page_address(page) + offset, bvec); + ret = zram_write_page(zram, page, index); } - - ret = __zram_bvec_write(zram, &vec, index, bio); -out: - if (is_partial_io(bvec)) - __free_page(page); + __free_page(page); return ret; } +static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio) +{ + if (is_partial_io(bvec)) + return zram_bvec_write_partial(zram, bvec, index, offset, bio); + return zram_write_page(zram, bvec->bv_page, index); +} + #ifdef CONFIG_ZRAM_MULTI_COMP /* * This function will decompress (unless it's ZRAM_HUGE) the page and then @@ -1761,7 +1671,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page, /* * No direct reclaim (slow path) for handle allocation and no - * re-compression attempt (unlike in __zram_bvec_write()) since + * re-compression attempt (unlike in zram_write_bvec()) since * we already have stored that object in zsmalloc. If we cannot * alloc memory for recompressed object then we bail out and * simply keep the old (existing) object in zsmalloc. @@ -1921,15 +1831,12 @@ release_init_lock: } #endif -/* - * zram_bio_discard - handler on discard request - * @index: physical block index in PAGE_SIZE units - * @offset: byte offset within physical block - */ -static void zram_bio_discard(struct zram *zram, u32 index, - int offset, struct bio *bio) +static void zram_bio_discard(struct zram *zram, struct bio *bio) { size_t n = bio->bi_iter.bi_size; + u32 index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + u32 offset = (bio->bi_iter.bi_sector & (SECTORS_PER_PAGE - 1)) << + SECTOR_SHIFT; /* * zram manages data in physical block size units. Because logical block @@ -1957,80 +1864,58 @@ static void zram_bio_discard(struct zram *zram, u32 index, index++; n -= PAGE_SIZE; } + + bio_endio(bio); } -/* - * Returns errno if it has some problem. Otherwise return 0 or 1. - * Returns 0 if IO request was done synchronously - * Returns 1 if IO request was successfully submitted. - */ -static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index, - int offset, enum req_op op, struct bio *bio) +static void zram_bio_read(struct zram *zram, struct bio *bio) { - int ret; - - if (!op_is_write(op)) { - ret = zram_bvec_read(zram, bvec, index, offset, bio); - flush_dcache_page(bvec->bv_page); - } else { - ret = zram_bvec_write(zram, bvec, index, offset, bio); - } - - zram_slot_lock(zram, index); - zram_accessed(zram, index); - zram_slot_unlock(zram, index); - - if (unlikely(ret < 0)) { - if (!op_is_write(op)) - atomic64_inc(&zram->stats.failed_reads); - else - atomic64_inc(&zram->stats.failed_writes); - } - - return ret; -} - -static void __zram_make_request(struct zram *zram, struct bio *bio) -{ - int offset; - u32 index; - struct bio_vec bvec; struct bvec_iter iter; + struct bio_vec bv; unsigned long start_time; - index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; - offset = (bio->bi_iter.bi_sector & - (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + start_time = bio_start_io_acct(bio); + bio_for_each_segment(bv, bio, iter) { + u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) << + SECTOR_SHIFT; - switch (bio_op(bio)) { - case REQ_OP_DISCARD: - case REQ_OP_WRITE_ZEROES: - zram_bio_discard(zram, index, offset, bio); - bio_endio(bio); - return; - default: - break; + if (zram_bvec_read(zram, &bv, index, offset, bio) < 0) { + atomic64_inc(&zram->stats.failed_reads); + bio->bi_status = BLK_STS_IOERR; + break; + } + flush_dcache_page(bv.bv_page); + + zram_slot_lock(zram, index); + zram_accessed(zram, index); + zram_slot_unlock(zram, index); } + bio_end_io_acct(bio, start_time); + bio_endio(bio); +} + +static void zram_bio_write(struct zram *zram, struct bio *bio) +{ + struct bvec_iter iter; + struct bio_vec bv; + unsigned long start_time; start_time = bio_start_io_acct(bio); - bio_for_each_segment(bvec, bio, iter) { - struct bio_vec bv = bvec; - unsigned int unwritten = bvec.bv_len; + bio_for_each_segment(bv, bio, iter) { + u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) << + SECTOR_SHIFT; - do { - bv.bv_len = min_t(unsigned int, PAGE_SIZE - offset, - unwritten); - if (zram_bvec_rw(zram, &bv, index, offset, - bio_op(bio), bio) < 0) { - bio->bi_status = BLK_STS_IOERR; - break; - } + if (zram_bvec_write(zram, &bv, index, offset, bio) < 0) { + atomic64_inc(&zram->stats.failed_writes); + bio->bi_status = BLK_STS_IOERR; + break; + } - bv.bv_offset += bv.bv_len; - unwritten -= bv.bv_len; - - update_position(&index, &offset, &bv); - } while (unwritten); + zram_slot_lock(zram, index); + zram_accessed(zram, index); + zram_slot_unlock(zram, index); } bio_end_io_acct(bio, start_time); bio_endio(bio); @@ -2043,14 +1928,21 @@ static void zram_submit_bio(struct bio *bio) { struct zram *zram = bio->bi_bdev->bd_disk->private_data; - if (!valid_io_request(zram, bio->bi_iter.bi_sector, - bio->bi_iter.bi_size)) { - atomic64_inc(&zram->stats.invalid_io); - bio_io_error(bio); - return; + switch (bio_op(bio)) { + case REQ_OP_READ: + zram_bio_read(zram, bio); + break; + case REQ_OP_WRITE: + zram_bio_write(zram, bio); + break; + case REQ_OP_DISCARD: + case REQ_OP_WRITE_ZEROES: + zram_bio_discard(zram, bio); + break; + default: + WARN_ON_ONCE(1); + bio_endio(bio); } - - __zram_make_request(zram, bio); } static void zram_slot_free_notify(struct block_device *bdev, @@ -2323,7 +2215,6 @@ static int zram_add(void) /* zram devices sort of resembles non-rotational disks */ blk_queue_flag_set(QUEUE_FLAG_NONROT, zram->disk->queue); blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, zram->disk->queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, zram->disk->queue); /* * To ensure that we always get PAGE_SIZE aligned @@ -2424,8 +2315,8 @@ static int zram_remove(struct zram *zram) * creates a new un-initialized zram device and returns back this device's * device_id (or an error code if it fails to create a new device). */ -static ssize_t hot_add_show(struct class *class, - struct class_attribute *attr, +static ssize_t hot_add_show(const struct class *class, + const struct class_attribute *attr, char *buf) { int ret; @@ -2438,11 +2329,12 @@ static ssize_t hot_add_show(struct class *class, return ret; return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } +/* This attribute must be set to 0400, so CLASS_ATTR_RO() can not be used */ static struct class_attribute class_attr_hot_add = __ATTR(hot_add, 0400, hot_add_show, NULL); -static ssize_t hot_remove_store(struct class *class, - struct class_attribute *attr, +static ssize_t hot_remove_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t count) { @@ -2481,7 +2373,6 @@ ATTRIBUTE_GROUPS(zram_control_class); static struct class zram_control_class = { .name = "zram-control", - .owner = THIS_MODULE, .class_groups = zram_control_class_groups, }; diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index c5254626f051..ca7a15bd4845 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -78,7 +78,6 @@ struct zram_stats { atomic64_t compr_data_size; /* compressed size of pages stored */ atomic64_t failed_reads; /* can happen when memory is too low */ atomic64_t failed_writes; /* can happen when memory is too low */ - atomic64_t invalid_io; /* non-page-aligned I/O requests */ atomic64_t notify_free; /* no. of swap slot free notifications */ atomic64_t same_pages; /* no. of same element filled pages */ atomic64_t huge_pages; /* no. of huge pages */ diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 3a34d7c1475b..52ef44688d38 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1319,17 +1319,17 @@ static void nxp_serdev_remove(struct serdev_device *serdev) hci_free_dev(hdev); } -static struct btnxpuart_data w8987_data = { +static struct btnxpuart_data w8987_data __maybe_unused = { .helper_fw_name = NULL, .fw_name = FIRMWARE_W8987, }; -static struct btnxpuart_data w8997_data = { +static struct btnxpuart_data w8997_data __maybe_unused = { .helper_fw_name = FIRMWARE_HELPER, .fw_name = FIRMWARE_W8997, }; -static const struct of_device_id nxpuart_of_match_table[] = { +static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = { { .compatible = "nxp,88w8987-bt", .data = &w8987_data }, { .compatible = "nxp,88w8997-bt", .data = &w8997_data }, { } diff --git a/drivers/bus/arm-integrator-lm.c b/drivers/bus/arm-integrator-lm.c index 2344d560b144..b715c8ab36e8 100644 --- a/drivers/bus/arm-integrator-lm.c +++ b/drivers/bus/arm-integrator-lm.c @@ -126,4 +126,3 @@ static struct platform_driver integrator_ap_lm_driver = { module_platform_driver(integrator_ap_lm_driver); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Integrator AP Logical Module driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/bt1-apb.c b/drivers/bus/bt1-apb.c index 63b1b4a76671..e97c1d1c7578 100644 --- a/drivers/bus/bt1-apb.c +++ b/drivers/bus/bt1-apb.c @@ -416,4 +416,3 @@ module_platform_driver(bt1_apb_driver); MODULE_AUTHOR("Serge Semin "); MODULE_DESCRIPTION("Baikal-T1 APB-bus driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/bt1-axi.c b/drivers/bus/bt1-axi.c index 70e49a6e5374..4007e7322cf2 100644 --- a/drivers/bus/bt1-axi.c +++ b/drivers/bus/bt1-axi.c @@ -309,4 +309,3 @@ module_platform_driver(bt1_axi_driver); MODULE_AUTHOR("Serge Semin "); MODULE_DESCRIPTION("Baikal-T1 AXI-bus driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 36cb091a33b4..653e2d4c116f 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -231,7 +231,7 @@ exit: return 0; } -static ssize_t rescan_store(struct bus_type *bus, +static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { unsigned long val; @@ -284,7 +284,7 @@ exit: return 0; } -static ssize_t autorescan_store(struct bus_type *bus, +static ssize_t autorescan_store(const struct bus_type *bus, const char *buf, size_t count) { bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_set_autorescan); @@ -292,7 +292,7 @@ static ssize_t autorescan_store(struct bus_type *bus, return count; } -static ssize_t autorescan_show(struct bus_type *bus, char *buf) +static ssize_t autorescan_show(const struct bus_type *bus, char *buf) { bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_get_autorescan); return strlen(buf); diff --git a/drivers/bus/intel-ixp4xx-eb.c b/drivers/bus/intel-ixp4xx-eb.c index 91db001eb69a..f5ba6bee6fd8 100644 --- a/drivers/bus/intel-ixp4xx-eb.c +++ b/drivers/bus/intel-ixp4xx-eb.c @@ -423,4 +423,3 @@ static struct platform_driver ixp4xx_exp_driver = { module_platform_driver(ixp4xx_exp_driver); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Intel IXP4xx external bus driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index a6a48e515478..600881808982 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -126,7 +126,7 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele /* Check if the channel is supported by the controller */ if ((ch_id >= mhi_cntrl->max_chan) || !mhi_cntrl->mhi_chan[ch_id].name) { - dev_err(dev, "Channel (%u) not supported!\n", ch_id); + dev_dbg(dev, "Channel (%u) not supported!\n", ch_id); return -ENODEV; } @@ -702,7 +702,7 @@ static void mhi_ep_cmd_ring_worker(struct work_struct *work) el = &ring->ring_cache[ring->rd_offset]; ret = mhi_ep_process_cmd_ring(ring, el); - if (ret) + if (ret && ret != -ENODEV) dev_err(dev, "Error processing cmd ring element: %zu\n", ring->rd_offset); mhi_ep_ring_inc_index(ring); diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 1c69feee1703..d2a19b07ccb8 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -391,6 +391,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) { const struct firmware *firmware = NULL; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_pm_state new_state; const char *fw_name; void *buf; dma_addr_t dma_addr; @@ -508,14 +509,18 @@ error_ready_state: } error_fw_load: - mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; - wake_up_all(&mhi_cntrl->state_event); + write_lock_irq(&mhi_cntrl->pm_lock); + new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_FW_DL_ERR); + write_unlock_irq(&mhi_cntrl->pm_lock); + if (new_state == MHI_PM_FW_DL_ERR) + wake_up_all(&mhi_cntrl->state_event); } int mhi_download_amss_image(struct mhi_controller *mhi_cntrl) { struct image_info *image_info = mhi_cntrl->fbc_image; struct device *dev = &mhi_cntrl->mhi_dev->dev; + enum mhi_pm_state new_state; int ret; if (!image_info) @@ -526,8 +531,11 @@ int mhi_download_amss_image(struct mhi_controller *mhi_cntrl) &image_info->mhi_buf[image_info->entries - 1]); if (ret) { dev_err(dev, "MHI did not load AMSS, ret:%d\n", ret); - mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; - wake_up_all(&mhi_cntrl->state_event); + write_lock_irq(&mhi_cntrl->pm_lock); + new_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_FW_DL_ERR); + write_unlock_irq(&mhi_cntrl->pm_lock); + if (new_state == MHI_PM_FW_DL_ERR) + wake_up_all(&mhi_cntrl->state_event); } return ret; diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 3d779ee6396d..f72fcb66f408 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -516,6 +516,12 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl) return -EIO; } + if (val >= mhi_cntrl->reg_len - (8 * MHI_DEV_WAKE_DB)) { + dev_err(dev, "CHDB offset: 0x%x is out of range: 0x%zx\n", + val, mhi_cntrl->reg_len - (8 * MHI_DEV_WAKE_DB)); + return -ERANGE; + } + /* Setup wake db */ mhi_cntrl->wake_db = base + val + (8 * MHI_DEV_WAKE_DB); mhi_cntrl->wake_set = false; @@ -532,6 +538,12 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl) return -EIO; } + if (val >= mhi_cntrl->reg_len - (8 * mhi_cntrl->total_ev_rings)) { + dev_err(dev, "ERDB offset: 0x%x is out of range: 0x%zx\n", + val, mhi_cntrl->reg_len - (8 * mhi_cntrl->total_ev_rings)); + return -ERANGE; + } + /* Setup event db address for each ev_ring */ mhi_event = mhi_cntrl->mhi_event; for (i = 0; i < mhi_cntrl->total_ev_rings; i++, val += 8, mhi_event++) { @@ -1100,7 +1112,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) if (bhi_off >= mhi_cntrl->reg_len) { dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n", bhi_off, mhi_cntrl->reg_len); - ret = -EINVAL; + ret = -ERANGE; goto error_reg_offset; } mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off; @@ -1117,7 +1129,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) dev_err(dev, "BHIe offset: 0x%x is out of range: 0x%zx\n", bhie_off, mhi_cntrl->reg_len); - ret = -EINVAL; + ret = -ERANGE; goto error_reg_offset; } mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off; diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index df0fbfee7b78..74a75439c713 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -503,7 +503,7 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv) } write_unlock_irq(&mhi_cntrl->pm_lock); - if (pm_state != MHI_PM_SYS_ERR_DETECT || ee == mhi_cntrl->ee) + if (pm_state != MHI_PM_SYS_ERR_DETECT) goto exit_intvec; switch (ee) { @@ -961,7 +961,9 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, } read_lock_bh(&mhi_cntrl->pm_lock); - if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) + + /* Ring EV DB only if there is any pending element to process */ + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)) && count) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); @@ -1031,7 +1033,9 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl, count++; } read_lock_bh(&mhi_cntrl->pm_lock); - if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) + + /* Ring EV DB only if there is any pending element to process */ + if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)) && count) mhi_ring_er_db(mhi_event); read_unlock_bh(&mhi_cntrl->pm_lock); @@ -1679,18 +1683,3 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) } } EXPORT_SYMBOL_GPL(mhi_unprepare_from_transfer); - -int mhi_poll(struct mhi_device *mhi_dev, u32 budget) -{ - struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; - struct mhi_chan *mhi_chan = mhi_dev->dl_chan; - struct mhi_event *mhi_event = &mhi_cntrl->mhi_event[mhi_chan->er_index]; - int ret; - - spin_lock_bh(&mhi_event->lock); - ret = mhi_event->process_event(mhi_cntrl, mhi_event, budget); - spin_unlock_bh(&mhi_event->lock); - - return ret; -} -EXPORT_SYMBOL_GPL(mhi_poll); diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index f39657f71483..db0a0b062d8e 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -8,7 +8,6 @@ * Copyright (C) 2020 Linaro Ltd */ -#include #include #include #include @@ -344,8 +343,6 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = { MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), - MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1), - MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), }; @@ -366,6 +363,15 @@ static const struct mhi_controller_config modem_foxconn_sdx55_config = { .event_cfg = mhi_foxconn_sdx55_events, }; +static const struct mhi_pci_dev_info mhi_foxconn_sdx24_info = { + .name = "foxconn-sdx24", + .config = &modem_foxconn_sdx55_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .name = "foxconn-sdx55", .fw = "qcom/sdx55m/sbl1.mbn", @@ -590,6 +596,15 @@ static const struct pci_device_id mhi_pci_id_table[] = { /* T99W373 (sdx62) */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0d9), .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx65_info }, + /* T99W510 (sdx24), variant 1 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f0), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + /* T99W510 (sdx24), variant 2 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f1), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, + /* T99W510 (sdx24), variant 3 */ + { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f2), + .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx24_info }, /* MV31-W (Cinterion) */ { PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3), .driver_data = (kernel_ulong_t) &mhi_mv31_info }, @@ -903,11 +918,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mhi_pdev->pci_state = pci_store_saved_state(pdev); pci_load_saved_state(pdev, NULL); - pci_enable_pcie_error_reporting(pdev); - err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config); if (err) - goto err_disable_reporting; + return err; /* MHI bus does not power up the controller by default */ err = mhi_prepare_for_power_up(mhi_cntrl); @@ -941,8 +954,6 @@ err_unprepare: mhi_unprepare_after_power_down(mhi_cntrl); err_unregister: mhi_unregister_controller(mhi_cntrl); -err_disable_reporting: - pci_disable_pcie_error_reporting(pdev); return err; } @@ -965,7 +976,6 @@ static void mhi_pci_remove(struct pci_dev *pdev) pm_runtime_get_noresume(&pdev->dev); mhi_unregister_controller(mhi_cntrl); - pci_disable_pcie_error_reporting(pdev); } static void mhi_pci_shutdown(struct pci_dev *pdev) diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c index 663c82749222..c1fef1b4bd89 100644 --- a/drivers/bus/qcom-ebi2.c +++ b/drivers/bus/qcom-ebi2.c @@ -403,4 +403,3 @@ static struct platform_driver qcom_ebi2_driver = { module_platform_driver(qcom_ebi2_driver); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Qualcomm EBI2 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c index eedeb29a5ff3..3fef18a43c01 100644 --- a/drivers/bus/qcom-ssc-block-bus.c +++ b/drivers/bus/qcom-ssc-block-bus.c @@ -386,4 +386,3 @@ module_platform_driver(qcom_ssc_block_bus_driver); MODULE_DESCRIPTION("A driver for handling the init sequence needed for accessing the SSC block on (some) qcom SoCs over AHB"); MODULE_AUTHOR("Michael Srba "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index 7afe1947e1c0..4da77ca7b75a 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Simple Power-Managed Bus Driver * @@ -138,4 +139,3 @@ module_platform_driver(simple_pm_bus_driver); MODULE_DESCRIPTION("Simple Power-Managed Bus Driver"); MODULE_AUTHOR("Geert Uytterhoeven "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/cdx/Kconfig b/drivers/cdx/Kconfig new file mode 100644 index 000000000000..a08958485e31 --- /dev/null +++ b/drivers/cdx/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# CDX bus configuration +# +# Copyright (C) 2022-2023, Advanced Micro Devices, Inc. +# + +config CDX_BUS + bool "CDX Bus driver" + depends on OF && ARM64 + help + Driver to enable Composable DMA Transfer(CDX) Bus. CDX bus + exposes Fabric devices which uses composable DMA IP to the + APU. CDX bus provides a mechanism for scanning and probing + of CDX devices. CDX devices are memory mapped on system bus + for embedded CPUs. CDX bus uses CDX controller and firmware + to scan these CDX devices. + +source "drivers/cdx/controller/Kconfig" diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile new file mode 100644 index 000000000000..0324e4914f6e --- /dev/null +++ b/drivers/cdx/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for CDX +# +# Copyright (C) 2022-2023, Advanced Micro Devices, Inc. +# + +obj-$(CONFIG_CDX_BUS) += cdx.o controller/ diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c new file mode 100644 index 000000000000..38511fd36325 --- /dev/null +++ b/drivers/cdx/cdx.c @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CDX bus driver. + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +/* + * Architecture Overview + * ===================== + * CDX is a Hardware Architecture designed for AMD FPGA devices. It + * consists of sophisticated mechanism for interaction between FPGA, + * Firmware and the APUs (Application CPUs). + * + * Firmware resides on RPU (Realtime CPUs) which interacts with + * the FPGA program manager and the APUs. The RPU provides memory-mapped + * interface (RPU if) which is used to communicate with APUs. + * + * The diagram below shows an overview of the CDX architecture: + * + * +--------------------------------------+ + * | Application CPUs (APU) | + * | | + * | CDX device drivers| + * | Linux OS | | + * | CDX bus | + * | | | + * | CDX controller | + * | | | + * +-----------------------------|--------+ + * | (discover, config, + * | reset, rescan) + * | + * +------------------------| RPU if |----+ + * | | | + * | V | + * | Realtime CPUs (RPU) | + * | | + * +--------------------------------------+ + * | + * +---------------------|----------------+ + * | FPGA | | + * | +-----------------------+ | + * | | | | | + * | +-------+ +-------+ +-------+ | + * | | dev 1 | | dev 2 | | dev 3 | | + * | +-------+ +-------+ +-------+ | + * +--------------------------------------+ + * + * The RPU firmware extracts the device information from the loaded FPGA + * image and implements a mechanism that allows the APU drivers to + * enumerate such devices (device personality and resource details) via + * a dedicated communication channel. RPU mediates operations such as + * discover, reset and rescan of the FPGA devices for the APU. This is + * done using memory mapped interface provided by the RPU to APU. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cdx.h" + +/* Default DMA mask for devices on a CDX bus */ +#define CDX_DEFAULT_DMA_MASK (~0ULL) +#define MAX_CDX_CONTROLLERS 16 + +/* CDX controllers registered with the CDX bus */ +static DEFINE_XARRAY_ALLOC(cdx_controllers); + +/** + * cdx_dev_reset - Reset a CDX device + * @dev: CDX device + * + * Return: -errno on failure, 0 on success. + */ +int cdx_dev_reset(struct device *dev) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; + struct cdx_device_config dev_config = {0}; + struct cdx_driver *cdx_drv; + int ret; + + cdx_drv = to_cdx_driver(dev->driver); + /* Notify driver that device is being reset */ + if (cdx_drv && cdx_drv->reset_prepare) + cdx_drv->reset_prepare(cdx_dev); + + dev_config.type = CDX_DEV_RESET_CONF; + ret = cdx->ops->dev_configure(cdx, cdx_dev->bus_num, + cdx_dev->dev_num, &dev_config); + if (ret) + dev_err(dev, "cdx device reset failed\n"); + + /* Notify driver that device reset is complete */ + if (cdx_drv && cdx_drv->reset_done) + cdx_drv->reset_done(cdx_dev); + + return ret; +} +EXPORT_SYMBOL_GPL(cdx_dev_reset); + +/** + * cdx_unregister_device - Unregister a CDX device + * @dev: CDX device + * @data: This is always passed as NULL, and is not used in this API, + * but is required here as the bus_for_each_dev() API expects + * the passed function (cdx_unregister_device) to have this + * as an argument. + * + * Return: 0 on success. + */ +static int cdx_unregister_device(struct device *dev, + void *data) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + kfree(cdx_dev->driver_override); + cdx_dev->driver_override = NULL; + /* + * Do not free cdx_dev here as it would be freed in + * cdx_device_release() called from within put_device(). + */ + device_del(&cdx_dev->dev); + put_device(&cdx_dev->dev); + + return 0; +} + +static void cdx_unregister_devices(struct bus_type *bus) +{ + /* Reset all the devices attached to cdx bus */ + bus_for_each_dev(bus, NULL, NULL, cdx_unregister_device); +} + +/** + * cdx_match_one_device - Tell if a CDX device structure has a matching + * CDX device id structure + * @id: single CDX device id structure to match + * @dev: the CDX device structure to match against + * + * Return: matching cdx_device_id structure or NULL if there is no match. + */ +static inline const struct cdx_device_id * +cdx_match_one_device(const struct cdx_device_id *id, + const struct cdx_device *dev) +{ + /* Use vendor ID and device ID for matching */ + if ((id->vendor == CDX_ANY_ID || id->vendor == dev->vendor) && + (id->device == CDX_ANY_ID || id->device == dev->device)) + return id; + return NULL; +} + +/** + * cdx_match_id - See if a CDX device matches a given cdx_id table + * @ids: array of CDX device ID structures to search in + * @dev: the CDX device structure to match against. + * + * Used by a driver to check whether a CDX device is in its list of + * supported devices. Returns the matching cdx_device_id structure or + * NULL if there is no match. + * + * Return: matching cdx_device_id structure or NULL if there is no match. + */ +static inline const struct cdx_device_id * +cdx_match_id(const struct cdx_device_id *ids, struct cdx_device *dev) +{ + if (ids) { + while (ids->vendor || ids->device) { + if (cdx_match_one_device(ids, dev)) + return ids; + ids++; + } + } + return NULL; +} + +/** + * cdx_bus_match - device to driver matching callback + * @dev: the cdx device to match against + * @drv: the device driver to search for matching cdx device + * structures + * + * Return: true on success, false otherwise. + */ +static int cdx_bus_match(struct device *dev, struct device_driver *drv) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_driver *cdx_drv = to_cdx_driver(drv); + const struct cdx_device_id *found_id = NULL; + const struct cdx_device_id *ids; + + ids = cdx_drv->match_id_table; + + /* When driver_override is set, only bind to the matching driver */ + if (cdx_dev->driver_override && strcmp(cdx_dev->driver_override, drv->name)) + return false; + + found_id = cdx_match_id(ids, cdx_dev); + if (!found_id) + return false; + + do { + /* + * In case override_only was set, enforce driver_override + * matching. + */ + if (!found_id->override_only) + return true; + if (cdx_dev->driver_override) + return true; + + ids = found_id + 1; + found_id = cdx_match_id(ids, cdx_dev); + } while (found_id); + + return false; +} + +static int cdx_probe(struct device *dev) +{ + struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); + struct cdx_device *cdx_dev = to_cdx_device(dev); + int error; + + error = cdx_drv->probe(cdx_dev); + if (error) { + dev_err_probe(dev, error, "%s failed\n", __func__); + return error; + } + + return 0; +} + +static void cdx_remove(struct device *dev) +{ + struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); + struct cdx_device *cdx_dev = to_cdx_device(dev); + + if (cdx_drv && cdx_drv->remove) + cdx_drv->remove(cdx_dev); +} + +static void cdx_shutdown(struct device *dev) +{ + struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); + struct cdx_device *cdx_dev = to_cdx_device(dev); + + if (cdx_drv && cdx_drv->shutdown) + cdx_drv->shutdown(cdx_dev); +} + +static int cdx_dma_configure(struct device *dev) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + u32 input_id = cdx_dev->req_id; + int ret; + + ret = of_dma_configure_id(dev, dev->parent->of_node, 0, &input_id); + if (ret && ret != -EPROBE_DEFER) { + dev_err(dev, "of_dma_configure_id() failed\n"); + return ret; + } + + return 0; +} + +/* show configuration fields */ +#define cdx_config_attr(field, format_string) \ +static ssize_t \ +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct cdx_device *cdx_dev = to_cdx_device(dev); \ + return sysfs_emit(buf, format_string, cdx_dev->field); \ +} \ +static DEVICE_ATTR_RO(field) + +cdx_config_attr(vendor, "0x%04x\n"); +cdx_config_attr(device, "0x%04x\n"); + +static ssize_t remove_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + bool val; + + if (kstrtobool(buf, &val) < 0) + return -EINVAL; + + if (!val) + return -EINVAL; + + if (device_remove_file_self(dev, attr)) { + int ret; + + ret = cdx_unregister_device(dev, NULL); + if (ret) + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(remove); + +static ssize_t reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + bool val; + int ret; + + if (kstrtobool(buf, &val) < 0) + return -EINVAL; + + if (!val) + return -EINVAL; + + ret = cdx_dev_reset(dev); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_WO(reset); + +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + int ret; + + if (WARN_ON(dev->bus != &cdx_bus_type)) + return -EINVAL; + + ret = driver_set_override(dev, &cdx_dev->driver_override, buf, count); + if (ret) + return ret; + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + return sysfs_emit(buf, "%s\n", cdx_dev->driver_override); +} +static DEVICE_ATTR_RW(driver_override); + +static struct attribute *cdx_dev_attrs[] = { + &dev_attr_remove.attr, + &dev_attr_reset.attr, + &dev_attr_vendor.attr, + &dev_attr_device.attr, + &dev_attr_driver_override.attr, + NULL, +}; +ATTRIBUTE_GROUPS(cdx_dev); + +static ssize_t rescan_store(const struct bus_type *bus, + const char *buf, size_t count) +{ + struct cdx_controller *cdx; + unsigned long index; + bool val; + + if (kstrtobool(buf, &val) < 0) + return -EINVAL; + + if (!val) + return -EINVAL; + + /* Unregister all the devices on the bus */ + cdx_unregister_devices(&cdx_bus_type); + + /* Rescan all the devices */ + xa_for_each(&cdx_controllers, index, cdx) { + int ret; + + ret = cdx->ops->scan(cdx); + if (ret) + dev_err(cdx->dev, "cdx bus scanning failed\n"); + } + + return count; +} +static BUS_ATTR_WO(rescan); + +static struct attribute *cdx_bus_attrs[] = { + &bus_attr_rescan.attr, + NULL, +}; +ATTRIBUTE_GROUPS(cdx_bus); + +struct bus_type cdx_bus_type = { + .name = "cdx", + .match = cdx_bus_match, + .probe = cdx_probe, + .remove = cdx_remove, + .shutdown = cdx_shutdown, + .dma_configure = cdx_dma_configure, + .bus_groups = cdx_bus_groups, + .dev_groups = cdx_dev_groups, +}; +EXPORT_SYMBOL_GPL(cdx_bus_type); + +int __cdx_driver_register(struct cdx_driver *cdx_driver, + struct module *owner) +{ + int error; + + cdx_driver->driver.owner = owner; + cdx_driver->driver.bus = &cdx_bus_type; + + error = driver_register(&cdx_driver->driver); + if (error) { + pr_err("driver_register() failed for %s: %d\n", + cdx_driver->driver.name, error); + return error; + } + + return 0; +} +EXPORT_SYMBOL_GPL(__cdx_driver_register); + +void cdx_driver_unregister(struct cdx_driver *cdx_driver) +{ + driver_unregister(&cdx_driver->driver); +} +EXPORT_SYMBOL_GPL(cdx_driver_unregister); + +static void cdx_device_release(struct device *dev) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + kfree(cdx_dev); +} + +int cdx_device_add(struct cdx_dev_params *dev_params) +{ + struct cdx_controller *cdx = dev_params->cdx; + struct device *parent = cdx->dev; + struct cdx_device *cdx_dev; + int ret; + + cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL); + if (!cdx_dev) + return -ENOMEM; + + /* Populate resource */ + memcpy(cdx_dev->res, dev_params->res, sizeof(struct resource) * + dev_params->res_count); + cdx_dev->res_count = dev_params->res_count; + + /* Populate CDX dev params */ + cdx_dev->req_id = dev_params->req_id; + cdx_dev->vendor = dev_params->vendor; + cdx_dev->device = dev_params->device; + cdx_dev->bus_num = dev_params->bus_num; + cdx_dev->dev_num = dev_params->dev_num; + cdx_dev->cdx = dev_params->cdx; + cdx_dev->dma_mask = CDX_DEFAULT_DMA_MASK; + + /* Initialize generic device */ + device_initialize(&cdx_dev->dev); + cdx_dev->dev.parent = parent; + cdx_dev->dev.bus = &cdx_bus_type; + cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; + cdx_dev->dev.release = cdx_device_release; + + /* Set Name */ + dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", + ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), + cdx_dev->dev_num); + + ret = device_add(&cdx_dev->dev); + if (ret) { + dev_err(&cdx_dev->dev, + "cdx device add failed: %d", ret); + goto fail; + } + + return 0; +fail: + /* + * Do not free cdx_dev here as it would be freed in + * cdx_device_release() called from put_device(). + */ + put_device(&cdx_dev->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(cdx_device_add); + +int cdx_register_controller(struct cdx_controller *cdx) +{ + int ret; + + ret = xa_alloc(&cdx_controllers, &cdx->id, cdx, + XA_LIMIT(0, MAX_CDX_CONTROLLERS - 1), GFP_KERNEL); + if (ret) { + dev_err(cdx->dev, + "No free index available. Maximum controllers already registered\n"); + cdx->id = (u8)MAX_CDX_CONTROLLERS; + return ret; + } + + /* Scan all the devices */ + cdx->ops->scan(cdx); + + return 0; +} +EXPORT_SYMBOL_GPL(cdx_register_controller); + +void cdx_unregister_controller(struct cdx_controller *cdx) +{ + if (cdx->id >= MAX_CDX_CONTROLLERS) + return; + + device_for_each_child(cdx->dev, NULL, cdx_unregister_device); + xa_erase(&cdx_controllers, cdx->id); +} +EXPORT_SYMBOL_GPL(cdx_unregister_controller); + +static int __init cdx_bus_init(void) +{ + return bus_register(&cdx_bus_type); +} +postcore_initcall(cdx_bus_init); diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h new file mode 100644 index 000000000000..c436ac7ac86f --- /dev/null +++ b/drivers/cdx/cdx.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Header file for the CDX Bus + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef _CDX_H_ +#define _CDX_H_ + +#include + +/** + * struct cdx_dev_params - CDX device parameters + * @cdx: CDX controller associated with the device + * @parent: Associated CDX controller + * @vendor: Vendor ID for CDX device + * @device: Device ID for CDX device + * @bus_num: Bus number for this CDX device + * @dev_num: Device number for this device + * @res: array of MMIO region entries + * @res_count: number of valid MMIO regions + * @req_id: Requestor ID associated with CDX device + */ +struct cdx_dev_params { + struct cdx_controller *cdx; + u16 vendor; + u16 device; + u8 bus_num; + u8 dev_num; + struct resource res[MAX_CDX_DEV_RESOURCES]; + u8 res_count; + u32 req_id; +}; + +/** + * cdx_register_controller - Register a CDX controller and its ports + * on the CDX bus. + * @cdx: The CDX controller to register + * + * Return: -errno on failure, 0 on success. + */ +int cdx_register_controller(struct cdx_controller *cdx); + +/** + * cdx_unregister_controller - Unregister a CDX controller + * @cdx: The CDX controller to unregister + */ +void cdx_unregister_controller(struct cdx_controller *cdx); + +/** + * cdx_device_add - Add a CDX device. This function adds a CDX device + * on the CDX bus as per the device parameters provided + * by caller. It also creates and registers an associated + * Linux generic device. + * @dev_params: device parameters associated with the device to be created. + * + * Return: -errno on failure, 0 on success. + */ +int cdx_device_add(struct cdx_dev_params *dev_params); + +#endif /* _CDX_H_ */ diff --git a/drivers/cdx/controller/Kconfig b/drivers/cdx/controller/Kconfig new file mode 100644 index 000000000000..c3e3b9ff8dfe --- /dev/null +++ b/drivers/cdx/controller/Kconfig @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# CDX controller configuration +# +# Copyright (C) 2022-2023, Advanced Micro Devices, Inc. +# + +if CDX_BUS + +config CDX_CONTROLLER + tristate "CDX bus controller" + select REMOTEPROC + select RPMSG + help + CDX controller drives the CDX bus. It interacts with + firmware to get the hardware devices and registers with + the CDX bus. Say Y to enable the CDX hardware driver. + + If unsure, say N. + +config MCDI_LOGGING + bool "MCDI Logging for the CDX controller" + depends on CDX_CONTROLLER + help + Enable MCDI Logging for + the CDX Controller for debug + purpose. + + If unsure, say N. + +endif diff --git a/drivers/cdx/controller/Makefile b/drivers/cdx/controller/Makefile new file mode 100644 index 000000000000..f071be411d96 --- /dev/null +++ b/drivers/cdx/controller/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for CDX controller drivers +# +# Copyright (C) 2022-2023, Advanced Micro Devices, Inc. +# + +obj-$(CONFIG_CDX_CONTROLLER) += cdx-controller.o +cdx-controller-objs := cdx_controller.o cdx_rpmsg.o mcdi.o mcdi_functions.o diff --git a/drivers/cdx/controller/bitfield.h b/drivers/cdx/controller/bitfield.h new file mode 100644 index 000000000000..567f8ec47582 --- /dev/null +++ b/drivers/cdx/controller/bitfield.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2013 Solarflare Communications Inc. + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef CDX_BITFIELD_H +#define CDX_BITFIELD_H + +#include + +/* Lowest bit numbers and widths */ +#define CDX_DWORD_LBN 0 +#define CDX_DWORD_WIDTH 32 + +/* Specified attribute (e.g. LBN) of the specified field */ +#define CDX_VAL(field, attribute) field ## _ ## attribute +/* Low bit number of the specified field */ +#define CDX_LOW_BIT(field) CDX_VAL(field, LBN) +/* Bit width of the specified field */ +#define CDX_WIDTH(field) CDX_VAL(field, WIDTH) +/* High bit number of the specified field */ +#define CDX_HIGH_BIT(field) (CDX_LOW_BIT(field) + CDX_WIDTH(field) - 1) + +/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */ +struct cdx_dword { + __le32 cdx_u32; +}; + +/* Value expanders for printk */ +#define CDX_DWORD_VAL(dword) \ + ((unsigned int)le32_to_cpu((dword).cdx_u32)) + +/* + * Extract bit field portion [low,high) from the 32-bit little-endian + * element which contains bits [min,max) + */ +#define CDX_DWORD_FIELD(dword, field) \ + (FIELD_GET(GENMASK(CDX_HIGH_BIT(field), CDX_LOW_BIT(field)), \ + le32_to_cpu((dword).cdx_u32))) + +/* + * Creates the portion of the named bit field that lies within the + * range [min,max). + */ +#define CDX_INSERT_FIELD(field, value) \ + (FIELD_PREP(GENMASK(CDX_HIGH_BIT(field), \ + CDX_LOW_BIT(field)), value)) + +/* + * Creates the portion of the named bit fields that lie within the + * range [min,max). + */ +#define CDX_INSERT_FIELDS(field1, value1, \ + field2, value2, \ + field3, value3, \ + field4, value4, \ + field5, value5, \ + field6, value6, \ + field7, value7) \ + (CDX_INSERT_FIELD(field1, (value1)) | \ + CDX_INSERT_FIELD(field2, (value2)) | \ + CDX_INSERT_FIELD(field3, (value3)) | \ + CDX_INSERT_FIELD(field4, (value4)) | \ + CDX_INSERT_FIELD(field5, (value5)) | \ + CDX_INSERT_FIELD(field6, (value6)) | \ + CDX_INSERT_FIELD(field7, (value7))) + +#define CDX_POPULATE_DWORD(dword, ...) \ + (dword).cdx_u32 = cpu_to_le32(CDX_INSERT_FIELDS(__VA_ARGS__)) + +/* Populate a dword field with various numbers of arguments */ +#define CDX_POPULATE_DWORD_7 CDX_POPULATE_DWORD +#define CDX_POPULATE_DWORD_6(dword, ...) \ + CDX_POPULATE_DWORD_7(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_POPULATE_DWORD_5(dword, ...) \ + CDX_POPULATE_DWORD_6(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_POPULATE_DWORD_4(dword, ...) \ + CDX_POPULATE_DWORD_5(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_POPULATE_DWORD_3(dword, ...) \ + CDX_POPULATE_DWORD_4(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_POPULATE_DWORD_2(dword, ...) \ + CDX_POPULATE_DWORD_3(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_POPULATE_DWORD_1(dword, ...) \ + CDX_POPULATE_DWORD_2(dword, CDX_DWORD, 0, __VA_ARGS__) +#define CDX_SET_DWORD(dword) \ + CDX_POPULATE_DWORD_1(dword, CDX_DWORD, 0xffffffff) + +#endif /* CDX_BITFIELD_H */ diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c new file mode 100644 index 000000000000..dc52f95f8978 --- /dev/null +++ b/drivers/cdx/controller/cdx_controller.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CDX host controller driver for AMD versal-net platform. + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "cdx_controller.h" +#include "../cdx.h" +#include "mcdi_functions.h" +#include "mcdi.h" + +static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd) +{ + return MCDI_RPC_TIMEOUT; +} + +static void cdx_mcdi_request(struct cdx_mcdi *cdx, + const struct cdx_dword *hdr, size_t hdr_len, + const struct cdx_dword *sdu, size_t sdu_len) +{ + if (cdx_rpmsg_send(cdx, hdr, hdr_len, sdu, sdu_len)) + dev_err(&cdx->rpdev->dev, "Failed to send rpmsg data\n"); +} + +static const struct cdx_mcdi_ops mcdi_ops = { + .mcdi_rpc_timeout = cdx_mcdi_rpc_timeout, + .mcdi_request = cdx_mcdi_request, +}; + +void cdx_rpmsg_post_probe(struct cdx_controller *cdx) +{ + /* Register CDX controller with CDX bus driver */ + if (cdx_register_controller(cdx)) + dev_err(cdx->dev, "Failed to register CDX controller\n"); +} + +void cdx_rpmsg_pre_remove(struct cdx_controller *cdx) +{ + cdx_unregister_controller(cdx); + cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT); +} + +static int cdx_configure_device(struct cdx_controller *cdx, + u8 bus_num, u8 dev_num, + struct cdx_device_config *dev_config) +{ + int ret = 0; + + switch (dev_config->type) { + case CDX_DEV_RESET_CONF: + ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cdx_scan_devices(struct cdx_controller *cdx) +{ + struct cdx_mcdi *cdx_mcdi = cdx->priv; + u8 bus_num, dev_num, num_cdx_bus; + int ret; + + /* MCDI FW Read: Fetch the number of CDX buses on this controller */ + ret = cdx_mcdi_get_num_buses(cdx_mcdi); + if (ret < 0) { + dev_err(cdx->dev, + "Get number of CDX buses failed: %d\n", ret); + return ret; + } + num_cdx_bus = (u8)ret; + + for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) { + u8 num_cdx_dev; + + /* MCDI FW Read: Fetch the number of devices present */ + ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num); + if (ret < 0) { + dev_err(cdx->dev, + "Get devices on CDX bus %d failed: %d\n", bus_num, ret); + continue; + } + num_cdx_dev = (u8)ret; + + for (dev_num = 0; dev_num < num_cdx_dev; dev_num++) { + struct cdx_dev_params dev_params; + + /* MCDI FW: Get the device config */ + ret = cdx_mcdi_get_dev_config(cdx_mcdi, bus_num, + dev_num, &dev_params); + if (ret) { + dev_err(cdx->dev, + "CDX device config get failed for %d(bus):%d(dev), %d\n", + bus_num, dev_num, ret); + continue; + } + dev_params.cdx = cdx; + + /* Add the device to the cdx bus */ + ret = cdx_device_add(&dev_params); + if (ret) { + dev_err(cdx->dev, "registering cdx dev: %d failed: %d\n", + dev_num, ret); + continue; + } + + dev_dbg(cdx->dev, "CDX dev: %d on cdx bus: %d created\n", + dev_num, bus_num); + } + } + + return 0; +} + +static struct cdx_ops cdx_ops = { + .scan = cdx_scan_devices, + .dev_configure = cdx_configure_device, +}; + +static int xlnx_cdx_probe(struct platform_device *pdev) +{ + struct cdx_controller *cdx; + struct cdx_mcdi *cdx_mcdi; + int ret; + + cdx_mcdi = kzalloc(sizeof(*cdx_mcdi), GFP_KERNEL); + if (!cdx_mcdi) + return -ENOMEM; + + /* Store the MCDI ops */ + cdx_mcdi->mcdi_ops = &mcdi_ops; + /* MCDI FW: Initialize the FW path */ + ret = cdx_mcdi_init(cdx_mcdi); + if (ret) { + dev_err_probe(&pdev->dev, ret, "MCDI Initialization failed\n"); + goto mcdi_init_fail; + } + + cdx = kzalloc(sizeof(*cdx), GFP_KERNEL); + if (!cdx) { + ret = -ENOMEM; + goto cdx_alloc_fail; + } + platform_set_drvdata(pdev, cdx); + + cdx->dev = &pdev->dev; + cdx->priv = cdx_mcdi; + cdx->ops = &cdx_ops; + + ret = cdx_setup_rpmsg(pdev); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to register CDX RPMsg transport\n"); + goto cdx_rpmsg_fail; + } + + dev_info(&pdev->dev, "Successfully registered CDX controller with RPMsg as transport\n"); + return 0; + +cdx_rpmsg_fail: + kfree(cdx); +cdx_alloc_fail: + cdx_mcdi_finish(cdx_mcdi); +mcdi_init_fail: + kfree(cdx_mcdi); + + return ret; +} + +static int xlnx_cdx_remove(struct platform_device *pdev) +{ + struct cdx_controller *cdx = platform_get_drvdata(pdev); + struct cdx_mcdi *cdx_mcdi = cdx->priv; + + cdx_destroy_rpmsg(pdev); + + kfree(cdx); + + cdx_mcdi_finish(cdx_mcdi); + kfree(cdx_mcdi); + + return 0; +} + +static const struct of_device_id cdx_match_table[] = { + {.compatible = "xlnx,versal-net-cdx",}, + { }, +}; + +MODULE_DEVICE_TABLE(of, cdx_match_table); + +static struct platform_driver cdx_pdriver = { + .driver = { + .name = "cdx-controller", + .pm = NULL, + .of_match_table = cdx_match_table, + }, + .probe = xlnx_cdx_probe, + .remove = xlnx_cdx_remove, +}; + +static int __init cdx_controller_init(void) +{ + int ret; + + ret = platform_driver_register(&cdx_pdriver); + if (ret) + pr_err("platform_driver_register() failed: %d\n", ret); + + return ret; +} + +static void __exit cdx_controller_exit(void) +{ + platform_driver_unregister(&cdx_pdriver); +} + +module_init(cdx_controller_init); +module_exit(cdx_controller_exit); + +MODULE_AUTHOR("AMD Inc."); +MODULE_DESCRIPTION("CDX controller for AMD devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cdx/controller/cdx_controller.h b/drivers/cdx/controller/cdx_controller.h new file mode 100644 index 000000000000..43b7c742df87 --- /dev/null +++ b/drivers/cdx/controller/cdx_controller.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Header file for the CDX Controller + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef _CDX_CONTROLLER_H_ +#define _CDX_CONTROLLER_H_ + +#include +#include "mcdi_functions.h" + +void cdx_rpmsg_post_probe(struct cdx_controller *cdx); + +void cdx_rpmsg_pre_remove(struct cdx_controller *cdx); + +int cdx_rpmsg_send(struct cdx_mcdi *cdx_mcdi, + const struct cdx_dword *hdr, size_t hdr_len, + const struct cdx_dword *sdu, size_t sdu_len); + +void cdx_rpmsg_read_resp(struct cdx_mcdi *cdx_mcdi, + struct cdx_dword *outbuf, size_t offset, + size_t outlen); + +int cdx_setup_rpmsg(struct platform_device *pdev); + +void cdx_destroy_rpmsg(struct platform_device *pdev); + +#endif /* _CDX_CONT_PRIV_H_ */ diff --git a/drivers/cdx/controller/cdx_rpmsg.c b/drivers/cdx/controller/cdx_rpmsg.c new file mode 100644 index 000000000000..f37e639d6ce3 --- /dev/null +++ b/drivers/cdx/controller/cdx_rpmsg.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Platform driver for CDX bus. + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include + +#include "../cdx.h" +#include "cdx_controller.h" +#include "mcdi_functions.h" +#include "mcdi.h" + +static struct rpmsg_device_id cdx_rpmsg_id_table[] = { + { .name = "mcdi_ipc" }, + { }, +}; +MODULE_DEVICE_TABLE(rpmsg, cdx_rpmsg_id_table); + +int cdx_rpmsg_send(struct cdx_mcdi *cdx_mcdi, + const struct cdx_dword *hdr, size_t hdr_len, + const struct cdx_dword *sdu, size_t sdu_len) +{ + unsigned char *send_buf; + int ret; + + send_buf = kzalloc(hdr_len + sdu_len, GFP_KERNEL); + if (!send_buf) + return -ENOMEM; + + memcpy(send_buf, hdr, hdr_len); + memcpy(send_buf + hdr_len, sdu, sdu_len); + + ret = rpmsg_send(cdx_mcdi->ept, send_buf, hdr_len + sdu_len); + kfree(send_buf); + + return ret; +} + +static int cdx_attach_to_rproc(struct platform_device *pdev) +{ + struct device_node *r5_core_node; + struct cdx_controller *cdx_c; + struct cdx_mcdi *cdx_mcdi; + struct device *dev; + struct rproc *rp; + int ret; + + dev = &pdev->dev; + cdx_c = platform_get_drvdata(pdev); + cdx_mcdi = cdx_c->priv; + + r5_core_node = of_parse_phandle(dev->of_node, "xlnx,rproc", 0); + if (!r5_core_node) { + dev_err(&pdev->dev, "xlnx,rproc: invalid phandle\n"); + return -EINVAL; + } + + rp = rproc_get_by_phandle(r5_core_node->phandle); + if (!rp) { + ret = -EPROBE_DEFER; + goto pdev_err; + } + + /* Attach to remote processor */ + ret = rproc_boot(rp); + if (ret) { + dev_err(&pdev->dev, "Failed to attach to remote processor\n"); + rproc_put(rp); + goto pdev_err; + } + + cdx_mcdi->r5_rproc = rp; +pdev_err: + of_node_put(r5_core_node); + return ret; +} + +static void cdx_detach_to_r5(struct platform_device *pdev) +{ + struct cdx_controller *cdx_c; + struct cdx_mcdi *cdx_mcdi; + + cdx_c = platform_get_drvdata(pdev); + cdx_mcdi = cdx_c->priv; + + rproc_detach(cdx_mcdi->r5_rproc); + rproc_put(cdx_mcdi->r5_rproc); +} + +static int cdx_rpmsg_cb(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 src) +{ + struct cdx_controller *cdx_c = dev_get_drvdata(&rpdev->dev); + struct cdx_mcdi *cdx_mcdi = cdx_c->priv; + + if (len > MCDI_BUF_LEN) + return -EINVAL; + + cdx_mcdi_process_cmd(cdx_mcdi, (struct cdx_dword *)data, len); + + return 0; +} + +static void cdx_rpmsg_post_probe_work(struct work_struct *work) +{ + struct cdx_controller *cdx_c; + struct cdx_mcdi *cdx_mcdi; + + cdx_mcdi = container_of(work, struct cdx_mcdi, work); + cdx_c = dev_get_drvdata(&cdx_mcdi->rpdev->dev); + cdx_rpmsg_post_probe(cdx_c); +} + +static int cdx_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct rpmsg_channel_info chinfo = {0}; + struct cdx_controller *cdx_c; + struct cdx_mcdi *cdx_mcdi; + + cdx_c = (struct cdx_controller *)cdx_rpmsg_id_table[0].driver_data; + cdx_mcdi = cdx_c->priv; + + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = rpdev->dst; + strscpy(chinfo.name, cdx_rpmsg_id_table[0].name, + strlen(cdx_rpmsg_id_table[0].name)); + + cdx_mcdi->ept = rpmsg_create_ept(rpdev, cdx_rpmsg_cb, NULL, chinfo); + if (!cdx_mcdi->ept) { + dev_err_probe(&rpdev->dev, -ENXIO, + "Failed to create ept for channel %s\n", + chinfo.name); + return -EINVAL; + } + + cdx_mcdi->rpdev = rpdev; + dev_set_drvdata(&rpdev->dev, cdx_c); + + schedule_work(&cdx_mcdi->work); + return 0; +} + +static void cdx_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct cdx_controller *cdx_c = dev_get_drvdata(&rpdev->dev); + struct cdx_mcdi *cdx_mcdi = cdx_c->priv; + + flush_work(&cdx_mcdi->work); + cdx_rpmsg_pre_remove(cdx_c); + + rpmsg_destroy_ept(cdx_mcdi->ept); + dev_set_drvdata(&rpdev->dev, NULL); +} + +static struct rpmsg_driver cdx_rpmsg_driver = { + .drv.name = KBUILD_MODNAME, + .id_table = cdx_rpmsg_id_table, + .probe = cdx_rpmsg_probe, + .remove = cdx_rpmsg_remove, + .callback = cdx_rpmsg_cb, +}; + +int cdx_setup_rpmsg(struct platform_device *pdev) +{ + struct cdx_controller *cdx_c; + struct cdx_mcdi *cdx_mcdi; + int ret; + + /* Attach to remote processor */ + ret = cdx_attach_to_rproc(pdev); + if (ret) + return ret; + + cdx_c = platform_get_drvdata(pdev); + cdx_mcdi = cdx_c->priv; + + /* Register RPMsg driver */ + cdx_rpmsg_id_table[0].driver_data = (kernel_ulong_t)cdx_c; + + INIT_WORK(&cdx_mcdi->work, cdx_rpmsg_post_probe_work); + ret = register_rpmsg_driver(&cdx_rpmsg_driver); + if (ret) { + dev_err(&pdev->dev, + "Failed to register cdx RPMsg driver: %d\n", ret); + cdx_detach_to_r5(pdev); + } + + return ret; +} + +void cdx_destroy_rpmsg(struct platform_device *pdev) +{ + unregister_rpmsg_driver(&cdx_rpmsg_driver); + + cdx_detach_to_r5(pdev); +} diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h new file mode 100644 index 000000000000..4ccb7b52951b --- /dev/null +++ b/drivers/cdx/controller/mc_cdx_pcol.h @@ -0,0 +1,590 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Driver for AMD network controllers and boards + * + * Copyright (C) 2021, Xilinx, Inc. + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef MC_CDX_PCOL_H +#define MC_CDX_PCOL_H + +/* The current version of the MCDI protocol. */ +#define MCDI_PCOL_VERSION 2 + +/* + * Each MCDI request starts with an MCDI_HEADER, which is a 32bit + * structure, filled in by the client. + * + * 0 7 8 16 20 22 23 24 31 + * | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS | + * | | | + * | | \--- Response + * | \------- Error + * \------------------------------ Resync (always set) + * + * The client writes its request into MC shared memory, and rings the + * doorbell. Each request is completed either by the MC writing + * back into shared memory, or by writing out an event. + * + * All MCDI commands support completion by shared memory response. Each + * request may also contain additional data (accounted for by HEADER.LEN), + * and some responses may also contain additional data (again, accounted + * for by HEADER.LEN). + * + * Some MCDI commands support completion by event, in which any associated + * response data is included in the event. + * + * The protocol requires one response to be delivered for every request; a + * request should not be sent unless the response for the previous request + * has been received (either by polling shared memory, or by receiving + * an event). + */ + +/** Request/Response structure */ +#define MCDI_HEADER_OFST 0 +#define MCDI_HEADER_CODE_LBN 0 +#define MCDI_HEADER_CODE_WIDTH 7 +#define MCDI_HEADER_RESYNC_LBN 7 +#define MCDI_HEADER_RESYNC_WIDTH 1 +#define MCDI_HEADER_DATALEN_LBN 8 +#define MCDI_HEADER_DATALEN_WIDTH 8 +#define MCDI_HEADER_SEQ_LBN 16 +#define MCDI_HEADER_SEQ_WIDTH 4 +#define MCDI_HEADER_RSVD_LBN 20 +#define MCDI_HEADER_RSVD_WIDTH 1 +#define MCDI_HEADER_NOT_EPOCH_LBN 21 +#define MCDI_HEADER_NOT_EPOCH_WIDTH 1 +#define MCDI_HEADER_ERROR_LBN 22 +#define MCDI_HEADER_ERROR_WIDTH 1 +#define MCDI_HEADER_RESPONSE_LBN 23 +#define MCDI_HEADER_RESPONSE_WIDTH 1 +#define MCDI_HEADER_XFLAGS_LBN 24 +#define MCDI_HEADER_XFLAGS_WIDTH 8 +/* Request response using event */ +#define MCDI_HEADER_XFLAGS_EVREQ 0x01 +/* Request (and signal) early doorbell return */ +#define MCDI_HEADER_XFLAGS_DBRET 0x02 + +/* Maximum number of payload bytes */ +#define MCDI_CTL_SDU_LEN_MAX_V2 0x400 + +#define MCDI_CTL_SDU_LEN_MAX MCDI_CTL_SDU_LEN_MAX_V2 + +/* + * The MC can generate events for two reasons: + * - To advance a shared memory request if XFLAGS_EVREQ was set + * - As a notification (link state, i2c event), controlled + * via MC_CMD_LOG_CTRL + * + * Both events share a common structure: + * + * 0 32 33 36 44 52 60 + * | Data | Cont | Level | Src | Code | Rsvd | + * | + * \ There is another event pending in this notification + * + * If Code==CMDDONE, then the fields are further interpreted as: + * + * - LEVEL==INFO Command succeeded + * - LEVEL==ERR Command failed + * + * 0 8 16 24 32 + * | Seq | Datalen | Errno | Rsvd | + * + * These fields are taken directly out of the standard MCDI header, i.e., + * LEVEL==ERR, Datalen == 0 => Reboot + * + * Events can be squirted out of the UART (using LOG_CTRL) without a + * MCDI header. An event can be distinguished from a MCDI response by + * examining the first byte which is 0xc0. This corresponds to the + * non-existent MCDI command MC_CMD_DEBUG_LOG. + * + * 0 7 8 + * | command | Resync | = 0xc0 + * + * Since the event is written in big-endian byte order, this works + * providing bits 56-63 of the event are 0xc0. + * + * 56 60 63 + * | Rsvd | Code | = 0xc0 + * + * Which means for convenience the event code is 0xc for all MC + * generated events. + */ + +/* + * the errno value may be followed by the (0-based) number of the + * first argument that could not be processed. + */ +#define MC_CMD_ERR_ARG_OFST 4 + +/* MC_CMD_ERR MCDI error codes. */ +/* Operation not permitted. */ +#define MC_CMD_ERR_EPERM 0x1 +/* Non-existent command target */ +#define MC_CMD_ERR_ENOENT 0x2 +/* assert() has killed the MC */ +#define MC_CMD_ERR_EINTR 0x4 +/* I/O failure */ +#define MC_CMD_ERR_EIO 0x5 +/* Already exists */ +#define MC_CMD_ERR_EEXIST 0x6 +/* Try again */ +#define MC_CMD_ERR_EAGAIN 0xb +/* Out of memory */ +#define MC_CMD_ERR_ENOMEM 0xc +/* Caller does not hold required locks */ +#define MC_CMD_ERR_EACCES 0xd +/* Resource is currently unavailable (e.g. lock contention) */ +#define MC_CMD_ERR_EBUSY 0x10 +/* No such device */ +#define MC_CMD_ERR_ENODEV 0x13 +/* Invalid argument to target */ +#define MC_CMD_ERR_EINVAL 0x16 +/* No space */ +#define MC_CMD_ERR_ENOSPC 0x1c +/* Read-only */ +#define MC_CMD_ERR_EROFS 0x1e +/* Broken pipe */ +#define MC_CMD_ERR_EPIPE 0x20 +/* Out of range */ +#define MC_CMD_ERR_ERANGE 0x22 +/* Non-recursive resource is already acquired */ +#define MC_CMD_ERR_EDEADLK 0x23 +/* Operation not implemented */ +#define MC_CMD_ERR_ENOSYS 0x26 +/* Operation timed out */ +#define MC_CMD_ERR_ETIME 0x3e +/* Link has been severed */ +#define MC_CMD_ERR_ENOLINK 0x43 +/* Protocol error */ +#define MC_CMD_ERR_EPROTO 0x47 +/* Bad message */ +#define MC_CMD_ERR_EBADMSG 0x4a +/* Operation not supported */ +#define MC_CMD_ERR_ENOTSUP 0x5f +/* Address not available */ +#define MC_CMD_ERR_EADDRNOTAVAIL 0x63 +/* Not connected */ +#define MC_CMD_ERR_ENOTCONN 0x6b +/* Operation already in progress */ +#define MC_CMD_ERR_EALREADY 0x72 +/* Stale handle. The handle references resource that no longer exists */ +#define MC_CMD_ERR_ESTALE 0x74 +/* Resource allocation failed. */ +#define MC_CMD_ERR_ALLOC_FAIL 0x1000 +/* V-adaptor not found. */ +#define MC_CMD_ERR_NO_VADAPTOR 0x1001 +/* EVB port not found. */ +#define MC_CMD_ERR_NO_EVB_PORT 0x1002 +/* V-switch not found. */ +#define MC_CMD_ERR_NO_VSWITCH 0x1003 +/* Too many VLAN tags. */ +#define MC_CMD_ERR_VLAN_LIMIT 0x1004 +/* Bad PCI function number. */ +#define MC_CMD_ERR_BAD_PCI_FUNC 0x1005 +/* Invalid VLAN mode. */ +#define MC_CMD_ERR_BAD_VLAN_MODE 0x1006 +/* Invalid v-switch type. */ +#define MC_CMD_ERR_BAD_VSWITCH_TYPE 0x1007 +/* Invalid v-port type. */ +#define MC_CMD_ERR_BAD_VPORT_TYPE 0x1008 +/* MAC address exists. */ +#define MC_CMD_ERR_MAC_EXIST 0x1009 +/* Slave core not present */ +#define MC_CMD_ERR_SLAVE_NOT_PRESENT 0x100a +/* The datapath is disabled. */ +#define MC_CMD_ERR_DATAPATH_DISABLED 0x100b +/* The requesting client is not a function */ +#define MC_CMD_ERR_CLIENT_NOT_FN 0x100c +/* + * The requested operation might require the command to be passed between + * MCs, and the transport doesn't support that. Should only ever been seen over + * the UART. + */ +#define MC_CMD_ERR_NO_PRIVILEGE 0x1013 +/* + * Workaround 26807 could not be turned on/off because some functions + * have already installed filters. See the comment at + * MC_CMD_WORKAROUND_BUG26807. May also returned for other operations such as + * sub-variant switching. + */ +#define MC_CMD_ERR_FILTERS_PRESENT 0x1014 +/* The clock whose frequency you've attempted to set doesn't exist */ +#define MC_CMD_ERR_NO_CLOCK 0x1015 +/* + * Returned by MC_CMD_TESTASSERT if the action that should have caused an + * assertion failed to do so. + */ +#define MC_CMD_ERR_UNREACHABLE 0x1016 +/* + * This command needs to be processed in the background but there were no + * resources to do so. Send it again after a command has completed. + */ +#define MC_CMD_ERR_QUEUE_FULL 0x1017 +/* + * The operation could not be completed because the PCIe link has gone + * away. This error code is never expected to be returned over the TLP + * transport. + */ +#define MC_CMD_ERR_NO_PCIE 0x1018 +/* + * The operation could not be completed because the datapath has gone + * away. This is distinct from MC_CMD_ERR_DATAPATH_DISABLED in that the + * datapath absence may be temporary + */ +#define MC_CMD_ERR_NO_DATAPATH 0x1019 +/* The operation could not complete because some VIs are allocated */ +#define MC_CMD_ERR_VIS_PRESENT 0x101a +/* + * The operation could not complete because some PIO buffers are + * allocated + */ +#define MC_CMD_ERR_PIOBUFS_PRESENT 0x101b + +/***********************************/ +/* + * MC_CMD_CDX_BUS_ENUM_BUSES + * CDX bus hosts devices (functions) that are implemented using the Composable + * DMA subsystem and directly mapped into the memory space of the FGPA PSX + * Application Processors (APUs). As such, they only apply to the PSX APU side, + * not the host (PCIe). Unlike PCIe, these devices have no native configuration + * space or enumeration mechanism, so this message set provides a minimal + * interface for discovery and management (bus reset, FLR, BME) of such + * devices. This command returns the number of CDX buses present in the system. + */ +#define MC_CMD_CDX_BUS_ENUM_BUSES 0x1 +#define MC_CMD_CDX_BUS_ENUM_BUSES_MSGSET 0x1 +#undef MC_CMD_0x1_PRIVILEGE_CTG + +#define MC_CMD_0x1_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_BUS_ENUM_BUSES_IN msgrequest */ +#define MC_CMD_CDX_BUS_ENUM_BUSES_IN_LEN 0 + +/* MC_CMD_CDX_BUS_ENUM_BUSES_OUT msgresponse */ +#define MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN 4 +/* + * Number of CDX buses present in the system. Buses are numbered 0 to + * BUS_COUNT-1 + */ +#define MC_CMD_CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT_OFST 0 +#define MC_CMD_CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT_LEN 4 + +/***********************************/ +/* + * MC_CMD_CDX_BUS_ENUM_DEVICES + * Enumerate CDX bus devices on a given bus + */ +#define MC_CMD_CDX_BUS_ENUM_DEVICES 0x2 +#define MC_CMD_CDX_BUS_ENUM_DEVICES_MSGSET 0x2 +#undef MC_CMD_0x2_PRIVILEGE_CTG + +#define MC_CMD_0x2_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_BUS_ENUM_DEVICES_IN msgrequest */ +#define MC_CMD_CDX_BUS_ENUM_DEVICES_IN_LEN 4 +/* + * Bus number to enumerate, in range 0 to BUS_COUNT-1, as returned by + * MC_CMD_CDX_BUS_ENUM_BUSES_OUT + */ +#define MC_CMD_CDX_BUS_ENUM_DEVICES_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_ENUM_DEVICES_IN_BUS_LEN 4 + +/* MC_CMD_CDX_BUS_ENUM_DEVICES_OUT msgresponse */ +#define MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN 4 +/* + * Number of devices present on the bus. Devices on the bus are numbered 0 to + * DEVICE_COUNT-1. Returns EAGAIN if number of devices unknown or if the target + * devices are not ready (e.g. undergoing a bus reset) + */ +#define MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT_OFST 0 +#define MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT_LEN 4 + +/***********************************/ +/* + * MC_CMD_CDX_BUS_GET_DEVICE_CONFIG + * Returns device identification and MMIO/MSI resource data for a CDX device. + * The expected usage is for the caller to first retrieve the number of devices + * on the bus using MC_CMD_BUS_ENUM_DEVICES, then loop through the range (0, + * DEVICE_COUNT - 1), retrieving device resource data. May return EAGAIN if the + * number of exposed devices or device resources change during enumeration (due + * to e.g. a PL reload / bus reset), in which case the caller is expected to + * restart the enumeration loop. MMIO addresses are specified in terms of bus + * addresses (prior to any potential IOMMU translation). For versal-net, these + * are equivalent to APU physical addresses. Implementation note - for this to + * work, the implementation needs to keep state (generation count) per client. + */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG 0x3 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_MSGSET 0x3 +#undef MC_CMD_0x3_PRIVILEGE_CTG + +#define MC_CMD_0x3_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN msgrequest */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN 8 +/* Device bus number, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_BUS_LEN 4 +/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE_OFST 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE_LEN 4 + +/* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT msgresponse */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN 88 +/* 16-bit Vendor identifier, compliant with PCI-SIG VendorID assignment. */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID_OFST 0 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID_LEN 2 +/* 16-bit Device ID assigned by the vendor */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID_OFST 2 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID_LEN 2 +/* + * 16-bit Subsystem Vendor ID, , compliant with PCI-SIG VendorID assignment. + * For further device differentiation, as required. 0 if unused. + */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID_OFST 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID_LEN 2 +/* + * 16-bit Subsystem Device ID assigned by the vendor. For further device + * differentiation, as required. 0 if unused. + */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID_OFST 6 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID_LEN 2 +/* 24-bit Device Class code, compliant with PCI-SIG Device Class codes */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS_OFST 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS_LEN 3 +/* 8-bit vendor-assigned revision */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION_OFST 11 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION_LEN 1 +/* Reserved (alignment) */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_RESERVED_OFST 12 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_RESERVED_LEN 4 +/* MMIO region 0 base address (bus address), 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_OFST 16 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_LO_OFST 16 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_LO_LBN 128 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_HI_OFST 20 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_HI_LBN 160 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE_HI_WIDTH 32 +/* MMIO region 0 size, 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_OFST 24 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_LO_OFST 24 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_LO_LBN 192 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_HI_OFST 28 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_HI_LBN 224 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE_HI_WIDTH 32 +/* MMIO region 1 base address (bus address), 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_OFST 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_LO_OFST 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_LO_LBN 256 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_HI_OFST 36 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_HI_LBN 288 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE_HI_WIDTH 32 +/* MMIO region 1 size, 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_OFST 40 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_LO_OFST 40 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_LO_LBN 320 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_HI_OFST 44 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_HI_LBN 352 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE_HI_WIDTH 32 +/* MMIO region 2 base address (bus address), 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_OFST 48 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_LO_OFST 48 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_LO_LBN 384 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_HI_OFST 52 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_HI_LBN 416 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE_HI_WIDTH 32 +/* MMIO region 2 size, 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_OFST 56 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_LO_OFST 56 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_LO_LBN 448 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_HI_OFST 60 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_HI_LBN 480 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE_HI_WIDTH 32 +/* MMIO region 3 base address (bus address), 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_OFST 64 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_LO_OFST 64 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_LO_LBN 512 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_HI_OFST 68 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_HI_LBN 544 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE_HI_WIDTH 32 +/* MMIO region 3 size, 0 if unused */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_OFST 72 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_LEN 8 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_LO_OFST 72 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_LO_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_LO_LBN 576 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_LO_WIDTH 32 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_HI_OFST 76 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_HI_LEN 4 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_HI_LBN 608 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE_HI_WIDTH 32 +/* MSI vector count */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT_OFST 80 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT_LEN 4 +/* Requester ID used by device (SMMU StreamID, GIC ITS DeviceID) */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 + +/***********************************/ +/* + * MC_CMD_CDX_DEVICE_RESET + * After this call completes, device DMA and interrupts are quiesced, devices + * logic is reset in a hardware-specific way and DMA bus mastering is disabled. + */ +#define MC_CMD_CDX_DEVICE_RESET 0x6 +#define MC_CMD_CDX_DEVICE_RESET_MSGSET 0x6 +#undef MC_CMD_0x6_PRIVILEGE_CTG + +#define MC_CMD_0x6_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_DEVICE_RESET_IN msgrequest */ +#define MC_CMD_CDX_DEVICE_RESET_IN_LEN 8 +/* Device bus number, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_DEVICE_RESET_IN_BUS_OFST 0 +#define MC_CMD_CDX_DEVICE_RESET_IN_BUS_LEN 4 +/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ +#define MC_CMD_CDX_DEVICE_RESET_IN_DEVICE_OFST 4 +#define MC_CMD_CDX_DEVICE_RESET_IN_DEVICE_LEN 4 + +/* + * MC_CMD_CDX_DEVICE_RESET_OUT msgresponse: The device is quiesced and all + * pending device initiated DMA has completed. + */ +#define MC_CMD_CDX_DEVICE_RESET_OUT_LEN 0 + +/***********************************/ +/* + * MC_CMD_CDX_DEVICE_CONTROL_SET + * If BUS_MASTER is set to disabled, device DMA and interrupts are quiesced. + * Pending DMA requests and MSI interrupts are flushed and no further DMA or + * interrupts are issued after this command returns. If BUS_MASTER is set to + * enabled, device is allowed to initiate DMA. Whether interrupts are enabled + * also depends on the value of MSI_ENABLE bit. Note that, in this case, the + * device may start DMA before the host receives and processes the MCDI + * response. MSI_ENABLE masks or unmasks device interrupts only. Note that for + * interrupts to be delivered to the host, both BUS_MASTER and MSI_ENABLE needs + * to be set. MMIO_REGIONS_ENABLE enables or disables host accesses to device + * MMIO regions. Note that an implementation is allowed to permanently set this + * bit to 1, in which case MC_CMD_CDX_DEVICE_CONTROL_GET will always return 1 + * for this bit, regardless of the value set here. + */ +#define MC_CMD_CDX_DEVICE_CONTROL_SET 0x7 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_MSGSET 0x7 +#undef MC_CMD_0x7_PRIVILEGE_CTG + +#define MC_CMD_0x7_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_DEVICE_CONTROL_SET_IN msgrequest */ +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_LEN 12 +/* Device bus number, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_LEN 4 +/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_DEVICE_OFST 4 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_DEVICE_LEN 4 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_FLAGS_OFST 8 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_FLAGS_LEN 4 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_OFST 8 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN 0 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_WIDTH 1 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_OFST 8 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN 1 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_WIDTH 1 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MMIO_REGIONS_ENABLE_OFST 8 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MMIO_REGIONS_ENABLE_LBN 2 +#define MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MMIO_REGIONS_ENABLE_WIDTH 1 + +/* MC_CMD_CDX_DEVICE_CONTROL_SET_OUT msgresponse */ +#define MC_CMD_CDX_DEVICE_CONTROL_SET_OUT_LEN 0 + +/***********************************/ +/* + * MC_CMD_CDX_DEVICE_CONTROL_GET + * Returns device DMA, interrupt and MMIO region access control bits. See + * MC_CMD_CDX_DEVICE_CONTROL_SET for definition of the available control bits. + */ +#define MC_CMD_CDX_DEVICE_CONTROL_GET 0x8 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_MSGSET 0x8 +#undef MC_CMD_0x8_PRIVILEGE_CTG + +#define MC_CMD_0x8_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_DEVICE_CONTROL_GET_IN msgrequest */ +#define MC_CMD_CDX_DEVICE_CONTROL_GET_IN_LEN 8 +/* Device bus number, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_DEVICE_CONTROL_GET_IN_BUS_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_IN_BUS_LEN 4 +/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ +#define MC_CMD_CDX_DEVICE_CONTROL_GET_IN_DEVICE_OFST 4 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_IN_DEVICE_LEN 4 + +/* MC_CMD_CDX_DEVICE_CONTROL_GET_OUT msgresponse */ +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN 4 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_FLAGS_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_FLAGS_LEN 4 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_BUS_MASTER_ENABLE_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_BUS_MASTER_ENABLE_LBN 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_BUS_MASTER_ENABLE_WIDTH 1 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MSI_ENABLE_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MSI_ENABLE_LBN 1 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MSI_ENABLE_WIDTH 1 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_OFST 0 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN 2 +#define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1 + +/***********************************/ +/* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ +#define MC_CMD_V2_EXTN 0x7f + +/* MC_CMD_V2_EXTN_IN msgrequest */ +#define MC_CMD_V2_EXTN_IN_LEN 4 +/* the extended command number */ +#define MC_CMD_V2_EXTN_IN_EXTENDED_CMD_LBN 0 +#define MC_CMD_V2_EXTN_IN_EXTENDED_CMD_WIDTH 15 +#define MC_CMD_V2_EXTN_IN_UNUSED_LBN 15 +#define MC_CMD_V2_EXTN_IN_UNUSED_WIDTH 1 +/* the actual length of the encapsulated command */ +#define MC_CMD_V2_EXTN_IN_ACTUAL_LEN_LBN 16 +#define MC_CMD_V2_EXTN_IN_ACTUAL_LEN_WIDTH 10 +#define MC_CMD_V2_EXTN_IN_UNUSED2_LBN 26 +#define MC_CMD_V2_EXTN_IN_UNUSED2_WIDTH 2 +/* Type of command/response */ +#define MC_CMD_V2_EXTN_IN_MESSAGE_TYPE_LBN 28 +#define MC_CMD_V2_EXTN_IN_MESSAGE_TYPE_WIDTH 4 +/* + * enum: MCDI command directed to versal-net. MCDI responses of this type + * are not defined. + */ +#define MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM 0x2 + +#endif /* MC_CDX_PCOL_H */ diff --git a/drivers/cdx/controller/mcdi.c b/drivers/cdx/controller/mcdi.c new file mode 100644 index 000000000000..a211a2ca762e --- /dev/null +++ b/drivers/cdx/controller/mcdi.c @@ -0,0 +1,903 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Management-Controller-to-Driver Interface + * + * Copyright 2008-2013 Solarflare Communications Inc. + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bitfield.h" +#include "mcdi.h" + +struct cdx_mcdi_copy_buffer { + struct cdx_dword buffer[DIV_ROUND_UP(MCDI_CTL_SDU_LEN_MAX, 4)]; +}; + +#ifdef CONFIG_MCDI_LOGGING +#define LOG_LINE_MAX (1024 - 32) +#endif + +static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd); +static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx); +static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx, + struct cdx_mcdi_cmd *cmd, + unsigned int *handle); +static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi, + bool allow_retry); +static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd); +static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct cdx_dword *outbuf, + int len, + struct list_head *cleanup_list); +static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct list_head *cleanup_list); +static void cdx_mcdi_cmd_work(struct work_struct *context); +static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list); +static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd, + size_t inlen, int raw, int arg, int err_no); + +static bool cdx_cmd_cancelled(struct cdx_mcdi_cmd *cmd) +{ + return cmd->state == MCDI_STATE_RUNNING_CANCELLED; +} + +static void cdx_mcdi_cmd_release(struct kref *ref) +{ + kfree(container_of(ref, struct cdx_mcdi_cmd, ref)); +} + +static unsigned int cdx_mcdi_cmd_handle(struct cdx_mcdi_cmd *cmd) +{ + return cmd->handle; +} + +static void _cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct list_head *cleanup_list) +{ + /* if cancelled, the completers have already been called */ + if (cdx_cmd_cancelled(cmd)) + return; + + if (cmd->completer) { + list_add_tail(&cmd->cleanup_list, cleanup_list); + ++mcdi->outstanding_cleanups; + kref_get(&cmd->ref); + } +} + +static void cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct list_head *cleanup_list) +{ + list_del(&cmd->list); + _cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); + cmd->state = MCDI_STATE_FINISHED; + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + if (list_empty(&mcdi->cmd_list)) + wake_up(&mcdi->cmd_complete_wq); +} + +static unsigned long cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd) +{ + if (!cdx->mcdi_ops->mcdi_rpc_timeout) + return MCDI_RPC_TIMEOUT; + else + return cdx->mcdi_ops->mcdi_rpc_timeout(cdx, cmd); +} + +int cdx_mcdi_init(struct cdx_mcdi *cdx) +{ + struct cdx_mcdi_iface *mcdi; + int rc = -ENOMEM; + + cdx->mcdi = kzalloc(sizeof(*cdx->mcdi), GFP_KERNEL); + if (!cdx->mcdi) + goto fail; + + mcdi = cdx_mcdi_if(cdx); + mcdi->cdx = cdx; + +#ifdef CONFIG_MCDI_LOGGING + mcdi->logging_buffer = kmalloc(LOG_LINE_MAX, GFP_KERNEL); + if (!mcdi->logging_buffer) + goto fail2; +#endif + mcdi->workqueue = alloc_ordered_workqueue("mcdi_wq", 0); + if (!mcdi->workqueue) + goto fail3; + mutex_init(&mcdi->iface_lock); + mcdi->mode = MCDI_MODE_EVENTS; + INIT_LIST_HEAD(&mcdi->cmd_list); + init_waitqueue_head(&mcdi->cmd_complete_wq); + + mcdi->new_epoch = true; + + return 0; +fail3: +#ifdef CONFIG_MCDI_LOGGING + kfree(mcdi->logging_buffer); +fail2: +#endif + kfree(cdx->mcdi); + cdx->mcdi = NULL; +fail: + return rc; +} + +void cdx_mcdi_finish(struct cdx_mcdi *cdx) +{ + struct cdx_mcdi_iface *mcdi; + + mcdi = cdx_mcdi_if(cdx); + if (!mcdi) + return; + + cdx_mcdi_wait_for_cleanup(cdx); + +#ifdef CONFIG_MCDI_LOGGING + kfree(mcdi->logging_buffer); +#endif + + destroy_workqueue(mcdi->workqueue); + kfree(cdx->mcdi); + cdx->mcdi = NULL; +} + +static bool cdx_mcdi_flushed(struct cdx_mcdi_iface *mcdi, bool ignore_cleanups) +{ + bool flushed; + + mutex_lock(&mcdi->iface_lock); + flushed = list_empty(&mcdi->cmd_list) && + (ignore_cleanups || !mcdi->outstanding_cleanups); + mutex_unlock(&mcdi->iface_lock); + return flushed; +} + +/* Wait for outstanding MCDI commands to complete. */ +static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + + if (!mcdi) + return; + + wait_event(mcdi->cmd_complete_wq, + cdx_mcdi_flushed(mcdi, false)); +} + +int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, + unsigned int timeout_jiffies) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + DEFINE_WAIT_FUNC(wait, woken_wake_function); + int rc = 0; + + if (!mcdi) + return -EINVAL; + + flush_workqueue(mcdi->workqueue); + + add_wait_queue(&mcdi->cmd_complete_wq, &wait); + + while (!cdx_mcdi_flushed(mcdi, true)) { + rc = wait_woken(&wait, TASK_IDLE, timeout_jiffies); + if (rc) + continue; + break; + } + + remove_wait_queue(&mcdi->cmd_complete_wq, &wait); + + if (rc > 0) + rc = 0; + else if (rc == 0) + rc = -ETIMEDOUT; + + return rc; +} + +static u8 cdx_mcdi_payload_csum(const struct cdx_dword *hdr, size_t hdr_len, + const struct cdx_dword *sdu, size_t sdu_len) +{ + u8 *p = (u8 *)hdr; + u8 csum = 0; + int i; + + for (i = 0; i < hdr_len; i++) + csum += p[i]; + + p = (u8 *)sdu; + for (i = 0; i < sdu_len; i++) + csum += p[i]; + + return ~csum & 0xff; +} + +static void cdx_mcdi_send_request(struct cdx_mcdi *cdx, + struct cdx_mcdi_cmd *cmd) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + const struct cdx_dword *inbuf = cmd->inbuf; + size_t inlen = cmd->inlen; + struct cdx_dword hdr[2]; + size_t hdr_len; + bool not_epoch; + u32 xflags; +#ifdef CONFIG_MCDI_LOGGING + char *buf; +#endif + + if (!mcdi) + return; +#ifdef CONFIG_MCDI_LOGGING + buf = mcdi->logging_buffer; /* page-sized */ +#endif + + mcdi->prev_seq = cmd->seq; + mcdi->seq_held_by[cmd->seq] = cmd; + mcdi->db_held_by = cmd; + cmd->started = jiffies; + + not_epoch = !mcdi->new_epoch; + xflags = 0; + + /* MCDI v2 */ + WARN_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2); + CDX_POPULATE_DWORD_7(hdr[0], + MCDI_HEADER_RESPONSE, 0, + MCDI_HEADER_RESYNC, 1, + MCDI_HEADER_CODE, MC_CMD_V2_EXTN, + MCDI_HEADER_DATALEN, 0, + MCDI_HEADER_SEQ, cmd->seq, + MCDI_HEADER_XFLAGS, xflags, + MCDI_HEADER_NOT_EPOCH, not_epoch); + CDX_POPULATE_DWORD_3(hdr[1], + MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd->cmd, + MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen, + MC_CMD_V2_EXTN_IN_MESSAGE_TYPE, + MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM); + hdr_len = 8; + +#ifdef CONFIG_MCDI_LOGGING + if (!WARN_ON_ONCE(!buf)) { + const struct cdx_dword *frags[] = { hdr, inbuf }; + const size_t frag_len[] = { hdr_len, round_up(inlen, 4) }; + int bytes = 0; + int i, j; + + for (j = 0; j < ARRAY_SIZE(frags); j++) { + const struct cdx_dword *frag; + + frag = frags[j]; + for (i = 0; + i < frag_len[j] / 4; + i++) { + /* + * Do not exceed the internal printk limit. + * The string before that is just over 70 bytes. + */ + if ((bytes + 75) > LOG_LINE_MAX) { + pr_info("MCDI RPC REQ:%s \\\n", buf); + bytes = 0; + } + bytes += snprintf(buf + bytes, + LOG_LINE_MAX - bytes, " %08x", + le32_to_cpu(frag[i].cdx_u32)); + } + } + + pr_info("MCDI RPC REQ:%s\n", buf); + } +#endif + hdr[0].cdx_u32 |= (__force __le32)(cdx_mcdi_payload_csum(hdr, hdr_len, inbuf, inlen) << + MCDI_HEADER_XFLAGS_LBN); + cdx->mcdi_ops->mcdi_request(cdx, hdr, hdr_len, inbuf, inlen); + + mcdi->new_epoch = false; +} + +static int cdx_mcdi_errno(struct cdx_mcdi *cdx, unsigned int mcdi_err) +{ + switch (mcdi_err) { + case 0: + case MC_CMD_ERR_QUEUE_FULL: + return mcdi_err; + case MC_CMD_ERR_EPERM: + return -EPERM; + case MC_CMD_ERR_ENOENT: + return -ENOENT; + case MC_CMD_ERR_EINTR: + return -EINTR; + case MC_CMD_ERR_EAGAIN: + return -EAGAIN; + case MC_CMD_ERR_EACCES: + return -EACCES; + case MC_CMD_ERR_EBUSY: + return -EBUSY; + case MC_CMD_ERR_EINVAL: + return -EINVAL; + case MC_CMD_ERR_ERANGE: + return -ERANGE; + case MC_CMD_ERR_EDEADLK: + return -EDEADLK; + case MC_CMD_ERR_ENOSYS: + return -EOPNOTSUPP; + case MC_CMD_ERR_ETIME: + return -ETIME; + case MC_CMD_ERR_EALREADY: + return -EALREADY; + case MC_CMD_ERR_ENOSPC: + return -ENOSPC; + case MC_CMD_ERR_ENOMEM: + return -ENOMEM; + case MC_CMD_ERR_ENOTSUP: + return -EOPNOTSUPP; + case MC_CMD_ERR_ALLOC_FAIL: + return -ENOBUFS; + case MC_CMD_ERR_MAC_EXIST: + return -EADDRINUSE; + case MC_CMD_ERR_NO_EVB_PORT: + return -EAGAIN; + default: + return -EPROTO; + } +} + +static void cdx_mcdi_process_cleanup_list(struct cdx_mcdi *cdx, + struct list_head *cleanup_list) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + unsigned int cleanups = 0; + + if (!mcdi) + return; + + while (!list_empty(cleanup_list)) { + struct cdx_mcdi_cmd *cmd = + list_first_entry(cleanup_list, + struct cdx_mcdi_cmd, cleanup_list); + cmd->completer(cdx, cmd->cookie, cmd->rc, + cmd->outbuf, cmd->outlen); + list_del(&cmd->cleanup_list); + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + ++cleanups; + } + + if (cleanups) { + bool all_done; + + mutex_lock(&mcdi->iface_lock); + CDX_WARN_ON_PARANOID(cleanups > mcdi->outstanding_cleanups); + all_done = (mcdi->outstanding_cleanups -= cleanups) == 0; + mutex_unlock(&mcdi->iface_lock); + if (all_done) + wake_up(&mcdi->cmd_complete_wq); + } +} + +static void _cdx_mcdi_cancel_cmd(struct cdx_mcdi_iface *mcdi, + unsigned int handle, + struct list_head *cleanup_list) +{ + struct cdx_mcdi_cmd *cmd; + + list_for_each_entry(cmd, &mcdi->cmd_list, list) + if (cdx_mcdi_cmd_handle(cmd) == handle) { + switch (cmd->state) { + case MCDI_STATE_QUEUED: + case MCDI_STATE_RETRY: + pr_debug("command %#x inlen %zu cancelled in queue\n", + cmd->cmd, cmd->inlen); + /* if not yet running, properly cancel it */ + cmd->rc = -EPIPE; + cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); + break; + case MCDI_STATE_RUNNING: + case MCDI_STATE_RUNNING_CANCELLED: + case MCDI_STATE_FINISHED: + default: + /* invalid state? */ + WARN_ON(1); + } + break; + } +} + +static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + LIST_HEAD(cleanup_list); + + if (!mcdi) + return; + + mutex_lock(&mcdi->iface_lock); + cdx_mcdi_timeout_cmd(mcdi, cmd, &cleanup_list); + mutex_unlock(&mcdi->iface_lock); + cdx_mcdi_process_cleanup_list(cdx, &cleanup_list); +} + +struct cdx_mcdi_blocking_data { + struct kref ref; + bool done; + wait_queue_head_t wq; + int rc; + struct cdx_dword *outbuf; + size_t outlen; + size_t outlen_actual; +}; + +static void cdx_mcdi_blocking_data_release(struct kref *ref) +{ + kfree(container_of(ref, struct cdx_mcdi_blocking_data, ref)); +} + +static void cdx_mcdi_rpc_completer(struct cdx_mcdi *cdx, unsigned long cookie, + int rc, struct cdx_dword *outbuf, + size_t outlen_actual) +{ + struct cdx_mcdi_blocking_data *wait_data = + (struct cdx_mcdi_blocking_data *)cookie; + + wait_data->rc = rc; + memcpy(wait_data->outbuf, outbuf, + min(outlen_actual, wait_data->outlen)); + wait_data->outlen_actual = outlen_actual; + /* memory barrier */ + smp_wmb(); + wait_data->done = true; + wake_up(&wait_data->wq); + kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); +} + +static int cdx_mcdi_rpc_sync(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + struct cdx_dword *outbuf, size_t outlen, + size_t *outlen_actual, bool quiet) +{ + struct cdx_mcdi_blocking_data *wait_data; + struct cdx_mcdi_cmd *cmd_item; + unsigned int handle; + int rc; + + if (outlen_actual) + *outlen_actual = 0; + + wait_data = kmalloc(sizeof(*wait_data), GFP_KERNEL); + if (!wait_data) + return -ENOMEM; + + cmd_item = kmalloc(sizeof(*cmd_item), GFP_KERNEL); + if (!cmd_item) { + kfree(wait_data); + return -ENOMEM; + } + + kref_init(&wait_data->ref); + wait_data->done = false; + init_waitqueue_head(&wait_data->wq); + wait_data->outbuf = outbuf; + wait_data->outlen = outlen; + + kref_init(&cmd_item->ref); + cmd_item->quiet = quiet; + cmd_item->cookie = (unsigned long)wait_data; + cmd_item->completer = &cdx_mcdi_rpc_completer; + cmd_item->cmd = cmd; + cmd_item->inlen = inlen; + cmd_item->inbuf = inbuf; + + /* Claim an extra reference for the completer to put. */ + kref_get(&wait_data->ref); + rc = cdx_mcdi_rpc_async_internal(cdx, cmd_item, &handle); + if (rc) { + kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); + goto out; + } + + if (!wait_event_timeout(wait_data->wq, wait_data->done, + cdx_mcdi_rpc_timeout(cdx, cmd)) && + !wait_data->done) { + pr_err("MC command 0x%x inlen %zu timed out (sync)\n", + cmd, inlen); + + cdx_mcdi_cancel_cmd(cdx, cmd_item); + + wait_data->rc = -ETIMEDOUT; + wait_data->outlen_actual = 0; + } + + if (outlen_actual) + *outlen_actual = wait_data->outlen_actual; + rc = wait_data->rc; + +out: + kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); + + return rc; +} + +static bool cdx_mcdi_get_seq(struct cdx_mcdi_iface *mcdi, unsigned char *seq) +{ + *seq = mcdi->prev_seq; + do { + *seq = (*seq + 1) % ARRAY_SIZE(mcdi->seq_held_by); + } while (mcdi->seq_held_by[*seq] && *seq != mcdi->prev_seq); + return !mcdi->seq_held_by[*seq]; +} + +static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx, + struct cdx_mcdi_cmd *cmd, + unsigned int *handle) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + LIST_HEAD(cleanup_list); + + if (!mcdi) { + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + return -ENETDOWN; + } + + if (mcdi->mode == MCDI_MODE_FAIL) { + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + return -ENETDOWN; + } + + cmd->mcdi = mcdi; + INIT_WORK(&cmd->work, cdx_mcdi_cmd_work); + INIT_LIST_HEAD(&cmd->list); + INIT_LIST_HEAD(&cmd->cleanup_list); + cmd->rc = 0; + cmd->outbuf = NULL; + cmd->outlen = 0; + + queue_work(mcdi->workqueue, &cmd->work); + return 0; +} + +static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd) +{ + struct cdx_mcdi *cdx = mcdi->cdx; + u8 seq; + + if (!mcdi->db_held_by && + cdx_mcdi_get_seq(mcdi, &seq)) { + cmd->seq = seq; + cmd->reboot_seen = false; + cdx_mcdi_send_request(cdx, cmd); + cmd->state = MCDI_STATE_RUNNING; + } else { + cmd->state = MCDI_STATE_QUEUED; + } +} + +/* try to advance other commands */ +static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi, + bool allow_retry) +{ + struct cdx_mcdi_cmd *cmd, *tmp; + + list_for_each_entry_safe(cmd, tmp, &mcdi->cmd_list, list) + if (cmd->state == MCDI_STATE_QUEUED || + (cmd->state == MCDI_STATE_RETRY && allow_retry)) + cdx_mcdi_cmd_start_or_queue(mcdi, cmd); +} + +void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len) +{ + struct cdx_mcdi_iface *mcdi; + struct cdx_mcdi_cmd *cmd; + LIST_HEAD(cleanup_list); + unsigned int respseq; + + if (!len || !outbuf) { + pr_err("Got empty MC response\n"); + return; + } + + mcdi = cdx_mcdi_if(cdx); + if (!mcdi) + return; + + respseq = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_SEQ); + + mutex_lock(&mcdi->iface_lock); + cmd = mcdi->seq_held_by[respseq]; + + if (cmd) { + if (cmd->state == MCDI_STATE_FINISHED) { + mutex_unlock(&mcdi->iface_lock); + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + return; + } + + cdx_mcdi_complete_cmd(mcdi, cmd, outbuf, len, &cleanup_list); + } else { + pr_err("MC response unexpected for seq : %0X\n", respseq); + } + + mutex_unlock(&mcdi->iface_lock); + + cdx_mcdi_process_cleanup_list(mcdi->cdx, &cleanup_list); +} + +static void cdx_mcdi_cmd_work(struct work_struct *context) +{ + struct cdx_mcdi_cmd *cmd = + container_of(context, struct cdx_mcdi_cmd, work); + struct cdx_mcdi_iface *mcdi = cmd->mcdi; + + mutex_lock(&mcdi->iface_lock); + + cmd->handle = mcdi->prev_handle++; + list_add_tail(&cmd->list, &mcdi->cmd_list); + cdx_mcdi_cmd_start_or_queue(mcdi, cmd); + + mutex_unlock(&mcdi->iface_lock); +} + +/* + * Returns true if the MCDI module is finished with the command. + * (examples of false would be if the command was proxied, or it was + * rejected by the MC due to lack of resources and requeued). + */ +static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct cdx_dword *outbuf, + int len, + struct list_head *cleanup_list) +{ + size_t resp_hdr_len, resp_data_len; + struct cdx_mcdi *cdx = mcdi->cdx; + unsigned int respcmd, error; + bool completed = false; + int rc; + + /* ensure the command can't go away before this function returns */ + kref_get(&cmd->ref); + + respcmd = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_CODE); + error = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_ERROR); + + if (respcmd != MC_CMD_V2_EXTN) { + resp_hdr_len = 4; + resp_data_len = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_DATALEN); + } else { + resp_data_len = 0; + resp_hdr_len = 8; + if (len >= 8) + resp_data_len = + CDX_DWORD_FIELD(outbuf[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); + } + + if ((resp_hdr_len + resp_data_len) > len) { + pr_warn("Incomplete MCDI response received %d. Expected %zu\n", + len, (resp_hdr_len + resp_data_len)); + resp_data_len = 0; + } + +#ifdef CONFIG_MCDI_LOGGING + if (!WARN_ON_ONCE(!mcdi->logging_buffer)) { + char *log = mcdi->logging_buffer; + int i, bytes = 0; + size_t rlen; + + WARN_ON_ONCE(resp_hdr_len % 4); + + rlen = resp_hdr_len / 4 + DIV_ROUND_UP(resp_data_len, 4); + + for (i = 0; i < rlen; i++) { + if ((bytes + 75) > LOG_LINE_MAX) { + pr_info("MCDI RPC RESP:%s \\\n", log); + bytes = 0; + } + bytes += snprintf(log + bytes, LOG_LINE_MAX - bytes, + " %08x", le32_to_cpu(outbuf[i].cdx_u32)); + } + + pr_info("MCDI RPC RESP:%s\n", log); + } +#endif + + if (error && resp_data_len == 0) { + /* MC rebooted during command */ + rc = -EIO; + } else { + if (WARN_ON_ONCE(error && resp_data_len < 4)) + resp_data_len = 4; + if (error) { + rc = CDX_DWORD_FIELD(outbuf[resp_hdr_len / 4], CDX_DWORD); + if (!cmd->quiet) { + int err_arg = 0; + + if (resp_data_len >= MC_CMD_ERR_ARG_OFST + 4) { + int offset = (resp_hdr_len + MC_CMD_ERR_ARG_OFST) / 4; + + err_arg = CDX_DWORD_VAL(outbuf[offset]); + } + + _cdx_mcdi_display_error(cdx, cmd->cmd, + cmd->inlen, rc, err_arg, + cdx_mcdi_errno(cdx, rc)); + } + rc = cdx_mcdi_errno(cdx, rc); + } else { + rc = 0; + } + } + + /* free doorbell */ + if (mcdi->db_held_by == cmd) + mcdi->db_held_by = NULL; + + if (cdx_cmd_cancelled(cmd)) { + list_del(&cmd->list); + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + completed = true; + } else if (rc == MC_CMD_ERR_QUEUE_FULL) { + cmd->state = MCDI_STATE_RETRY; + } else { + cmd->rc = rc; + cmd->outbuf = outbuf + DIV_ROUND_UP(resp_hdr_len, 4); + cmd->outlen = resp_data_len; + cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); + completed = true; + } + + /* free sequence number and buffer */ + mcdi->seq_held_by[cmd->seq] = NULL; + + cdx_mcdi_start_or_queue(mcdi, rc != MC_CMD_ERR_QUEUE_FULL); + + /* wake up anyone waiting for flush */ + wake_up(&mcdi->cmd_complete_wq); + + kref_put(&cmd->ref, cdx_mcdi_cmd_release); + + return completed; +} + +static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi, + struct cdx_mcdi_cmd *cmd, + struct list_head *cleanup_list) +{ + struct cdx_mcdi *cdx = mcdi->cdx; + + pr_err("MC command 0x%x inlen %zu state %d timed out after %u ms\n", + cmd->cmd, cmd->inlen, cmd->state, + jiffies_to_msecs(jiffies - cmd->started)); + + cmd->rc = -ETIMEDOUT; + cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); + + cdx_mcdi_mode_fail(cdx, cleanup_list); +} + +/** + * cdx_mcdi_rpc - Issue an MCDI command and wait for completion + * @cdx: NIC through which to issue the command + * @cmd: Command type number + * @inbuf: Command parameters + * @inlen: Length of command parameters, in bytes. Must be a multiple + * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1. + * @outbuf: Response buffer. May be %NULL if @outlen is 0. + * @outlen: Length of response buffer, in bytes. If the actual + * response is longer than @outlen & ~3, it will be truncated + * to that length. + * @outlen_actual: Pointer through which to return the actual response + * length. May be %NULL if this is not needed. + * + * This function may sleep and therefore must be called in process + * context. + * + * Return: A negative error code, or zero if successful. The error + * code may come from the MCDI response or may indicate a failure + * to communicate with the MC. In the former case, the response + * will still be copied to @outbuf and *@outlen_actual will be + * set accordingly. In the latter case, *@outlen_actual will be + * set to zero. + */ +int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + struct cdx_dword *outbuf, size_t outlen, + size_t *outlen_actual) +{ + return cdx_mcdi_rpc_sync(cdx, cmd, inbuf, inlen, outbuf, outlen, + outlen_actual, false); +} + +/** + * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously + * @cdx: NIC through which to issue the command + * @cmd: Command type number + * @inbuf: Command parameters + * @inlen: Length of command parameters, in bytes + * @complete: Function to be called on completion or cancellation. + * @cookie: Arbitrary value to be passed to @complete. + * + * This function does not sleep and therefore may be called in atomic + * context. It will fail if event queues are disabled or if MCDI + * event completions have been disabled due to an error. + * + * If it succeeds, the @complete function will be called exactly once + * in process context, when one of the following occurs: + * (a) the completion event is received (in process context) + * (b) event queues are disabled (in the process that disables them) + */ +int +cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + cdx_mcdi_async_completer *complete, unsigned long cookie) +{ + struct cdx_mcdi_cmd *cmd_item = + kmalloc(sizeof(struct cdx_mcdi_cmd) + inlen, GFP_ATOMIC); + + if (!cmd_item) + return -ENOMEM; + + kref_init(&cmd_item->ref); + cmd_item->quiet = true; + cmd_item->cookie = cookie; + cmd_item->completer = complete; + cmd_item->cmd = cmd; + cmd_item->inlen = inlen; + /* inbuf is probably not valid after return, so take a copy */ + cmd_item->inbuf = (struct cdx_dword *)(cmd_item + 1); + memcpy(cmd_item + 1, inbuf, inlen); + + return cdx_mcdi_rpc_async_internal(cdx, cmd_item, NULL); +} + +static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd, + size_t inlen, int raw, int arg, int err_no) +{ + pr_err("MC command 0x%x inlen %d failed err_no=%d (raw=%d) arg=%d\n", + cmd, (int)inlen, err_no, raw, arg); +} + +/* + * Set MCDI mode to fail to prevent any new commands, then cancel any + * outstanding commands. + * Caller must hold the mcdi iface_lock. + */ +static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list) +{ + struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); + + if (!mcdi) + return; + + mcdi->mode = MCDI_MODE_FAIL; + + while (!list_empty(&mcdi->cmd_list)) { + struct cdx_mcdi_cmd *cmd; + + cmd = list_first_entry(&mcdi->cmd_list, struct cdx_mcdi_cmd, + list); + _cdx_mcdi_cancel_cmd(mcdi, cdx_mcdi_cmd_handle(cmd), cleanup_list); + } +} diff --git a/drivers/cdx/controller/mcdi.h b/drivers/cdx/controller/mcdi.h new file mode 100644 index 000000000000..0bfbeab04e43 --- /dev/null +++ b/drivers/cdx/controller/mcdi.h @@ -0,0 +1,248 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright 2008-2013 Solarflare Communications Inc. + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef CDX_MCDI_H +#define CDX_MCDI_H + +#include +#include +#include + +#include "bitfield.h" +#include "mc_cdx_pcol.h" + +#ifdef DEBUG +#define CDX_WARN_ON_ONCE_PARANOID(x) WARN_ON_ONCE(x) +#define CDX_WARN_ON_PARANOID(x) WARN_ON(x) +#else +#define CDX_WARN_ON_ONCE_PARANOID(x) do {} while (0) +#define CDX_WARN_ON_PARANOID(x) do {} while (0) +#endif + +/** + * enum cdx_mcdi_mode - MCDI transaction mode + * @MCDI_MODE_EVENTS: wait for an mcdi response callback. + * @MCDI_MODE_FAIL: we think MCDI is dead, so fail-fast all calls + */ +enum cdx_mcdi_mode { + MCDI_MODE_EVENTS, + MCDI_MODE_FAIL, +}; + +#define MCDI_RPC_TIMEOUT (10 * HZ) +#define MCDI_RPC_LONG_TIMEOU (60 * HZ) +#define MCDI_RPC_POST_RST_TIME (10 * HZ) + +#define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) + +/** + * enum cdx_mcdi_cmd_state - State for an individual MCDI command + * @MCDI_STATE_QUEUED: Command not started and is waiting to run. + * @MCDI_STATE_RETRY: Command was submitted and MC rejected with no resources, + * as MC have too many outstanding commands. Command will be retried once + * another command returns. + * @MCDI_STATE_RUNNING: Command was accepted and is running. + * @MCDI_STATE_RUNNING_CANCELLED: Command is running but the issuer cancelled + * the command. + * @MCDI_STATE_FINISHED: Processing of this command has completed. + */ + +enum cdx_mcdi_cmd_state { + MCDI_STATE_QUEUED, + MCDI_STATE_RETRY, + MCDI_STATE_RUNNING, + MCDI_STATE_RUNNING_CANCELLED, + MCDI_STATE_FINISHED, +}; + +/** + * struct cdx_mcdi - CDX MCDI Firmware interface, to interact + * with CDX controller. + * @mcdi: MCDI interface + * @mcdi_ops: MCDI operations + * @r5_rproc : R5 Remoteproc device handle + * @rpdev: RPMsg device + * @ept: RPMsg endpoint + * @work: Post probe work + */ +struct cdx_mcdi { + /* MCDI interface */ + struct cdx_mcdi_data *mcdi; + const struct cdx_mcdi_ops *mcdi_ops; + + struct rproc *r5_rproc; + struct rpmsg_device *rpdev; + struct rpmsg_endpoint *ept; + struct work_struct work; +}; + +struct cdx_mcdi_ops { + void (*mcdi_request)(struct cdx_mcdi *cdx, + const struct cdx_dword *hdr, size_t hdr_len, + const struct cdx_dword *sdu, size_t sdu_len); + unsigned int (*mcdi_rpc_timeout)(struct cdx_mcdi *cdx, unsigned int cmd); +}; + +typedef void cdx_mcdi_async_completer(struct cdx_mcdi *cdx, + unsigned long cookie, int rc, + struct cdx_dword *outbuf, + size_t outlen_actual); + +/** + * struct cdx_mcdi_cmd - An outstanding MCDI command + * @ref: Reference count. There will be one reference if the command is + * in the mcdi_iface cmd_list, another if it's on a cleanup list, + * and a third if it's queued in the work queue. + * @list: The data for this entry in mcdi->cmd_list + * @cleanup_list: The data for this entry in a cleanup list + * @work: The work item for this command, queued in mcdi->workqueue + * @mcdi: The mcdi_iface for this command + * @state: The state of this command + * @inlen: inbuf length + * @inbuf: Input buffer + * @quiet: Whether to silence errors + * @reboot_seen: Whether a reboot has been seen during this command, + * to prevent duplicates + * @seq: Sequence number + * @started: Jiffies this command was started at + * @cookie: Context for completion function + * @completer: Completion function + * @handle: Command handle + * @cmd: Command number + * @rc: Return code + * @outlen: Length of output buffer + * @outbuf: Output buffer + */ +struct cdx_mcdi_cmd { + struct kref ref; + struct list_head list; + struct list_head cleanup_list; + struct work_struct work; + struct cdx_mcdi_iface *mcdi; + enum cdx_mcdi_cmd_state state; + size_t inlen; + const struct cdx_dword *inbuf; + bool quiet; + bool reboot_seen; + u8 seq; + unsigned long started; + unsigned long cookie; + cdx_mcdi_async_completer *completer; + unsigned int handle; + unsigned int cmd; + int rc; + size_t outlen; + struct cdx_dword *outbuf; + /* followed by inbuf data if necessary */ +}; + +/** + * struct cdx_mcdi_iface - MCDI protocol context + * @cdx: The associated NIC + * @iface_lock: Serialise access to this structure + * @outstanding_cleanups: Count of cleanups + * @cmd_list: List of outstanding and running commands + * @workqueue: Workqueue used for delayed processing + * @cmd_complete_wq: Waitqueue for command completion + * @db_held_by: Command the MC doorbell is in use by + * @seq_held_by: Command each sequence number is in use by + * @prev_handle: The last used command handle + * @mode: Poll for mcdi completion, or wait for an mcdi_event + * @prev_seq: The last used sequence number + * @new_epoch: Indicates start of day or start of MC reboot recovery + * @logging_buffer: Buffer that may be used to build MCDI tracing messages + * @logging_enabled: Whether to trace MCDI + */ +struct cdx_mcdi_iface { + struct cdx_mcdi *cdx; + /* Serialise access */ + struct mutex iface_lock; + unsigned int outstanding_cleanups; + struct list_head cmd_list; + struct workqueue_struct *workqueue; + wait_queue_head_t cmd_complete_wq; + struct cdx_mcdi_cmd *db_held_by; + struct cdx_mcdi_cmd *seq_held_by[16]; + unsigned int prev_handle; + enum cdx_mcdi_mode mode; + u8 prev_seq; + bool new_epoch; +#ifdef CONFIG_MCDI_LOGGING + bool logging_enabled; + char *logging_buffer; +#endif +}; + +/** + * struct cdx_mcdi_data - extra state for NICs that implement MCDI + * @iface: Interface/protocol state + * @fn_flags: Flags for this function, as returned by %MC_CMD_DRV_ATTACH. + */ +struct cdx_mcdi_data { + struct cdx_mcdi_iface iface; + u32 fn_flags; +}; + +static inline struct cdx_mcdi_iface *cdx_mcdi_if(struct cdx_mcdi *cdx) +{ + return cdx->mcdi ? &cdx->mcdi->iface : NULL; +} + +int cdx_mcdi_init(struct cdx_mcdi *cdx); +void cdx_mcdi_finish(struct cdx_mcdi *cdx); + +void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len); +int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + struct cdx_dword *outbuf, size_t outlen, size_t *outlen_actual); +int cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + cdx_mcdi_async_completer *complete, + unsigned long cookie); +int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, + unsigned int timeout_jiffies); + +/* + * We expect that 16- and 32-bit fields in MCDI requests and responses + * are appropriately aligned, but 64-bit fields are only + * 32-bit-aligned. + */ +#define MCDI_DECLARE_BUF(_name, _len) struct cdx_dword _name[DIV_ROUND_UP(_len, 4)] = {{0}} +#define _MCDI_PTR(_buf, _offset) \ + ((u8 *)(_buf) + (_offset)) +#define MCDI_PTR(_buf, _field) \ + _MCDI_PTR(_buf, MC_CMD_ ## _field ## _OFST) +#define _MCDI_CHECK_ALIGN(_ofst, _align) \ + ((void)BUILD_BUG_ON_ZERO((_ofst) & ((_align) - 1)), \ + (_ofst)) +#define _MCDI_DWORD(_buf, _field) \ + ((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2)) + +#define MCDI_BYTE(_buf, _field) \ + ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ + *MCDI_PTR(_buf, _field)) +#define MCDI_WORD(_buf, _field) \ + ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2), \ + le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) +#define MCDI_SET_DWORD(_buf, _field, _value) \ + CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), CDX_DWORD, _value) +#define MCDI_DWORD(_buf, _field) \ + CDX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), CDX_DWORD) +#define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \ + CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \ + MC_CMD_ ## _name1, _value1) +#define MCDI_SET_QWORD(_buf, _field, _value) \ + do { \ + CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[0], \ + CDX_DWORD, (u32)(_value)); \ + CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[1], \ + CDX_DWORD, (u64)(_value) >> 32); \ + } while (0) +#define MCDI_QWORD(_buf, _field) \ + (CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[0], CDX_DWORD) | \ + (u64)CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[1], CDX_DWORD) << 32) + +#endif /* CDX_MCDI_H */ diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c new file mode 100644 index 000000000000..0158f26533dd --- /dev/null +++ b/drivers/cdx/controller/mcdi_functions.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#include + +#include "mcdi.h" +#include "mcdi_functions.h" + +int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx) +{ + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN); + size_t outlen; + int ret; + + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_BUSES, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (ret) + return ret; + + if (outlen != MC_CMD_CDX_BUS_ENUM_BUSES_OUT_LEN) + return -EIO; + + return MCDI_DWORD(outbuf, CDX_BUS_ENUM_BUSES_OUT_BUS_COUNT); +} + +int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num) +{ + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN); + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_ENUM_DEVICES_IN_LEN); + size_t outlen; + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_ENUM_DEVICES_IN_BUS, bus_num); + + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_ENUM_DEVICES, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (ret) + return ret; + + if (outlen != MC_CMD_CDX_BUS_ENUM_DEVICES_OUT_LEN) + return -EIO; + + return MCDI_DWORD(outbuf, CDX_BUS_ENUM_DEVICES_OUT_DEVICE_COUNT); +} + +int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, + u8 bus_num, u8 dev_num, + struct cdx_dev_params *dev_params) +{ + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); + struct resource *res = &dev_params->res[0]; + size_t outlen; + u32 req_id; + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_BUS, bus_num); + MCDI_SET_DWORD(inbuf, CDX_BUS_GET_DEVICE_CONFIG_IN_DEVICE, dev_num); + + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (ret) + return ret; + + if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) + return -EIO; + + dev_params->bus_num = bus_num; + dev_params->dev_num = dev_num; + + req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); + dev_params->req_id = req_id; + + dev_params->res_count = 0; + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { + res[dev_params->res_count].start = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE); + res[dev_params->res_count].end = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_BASE) + + MCDI_QWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) - 1; + res[dev_params->res_count].flags = IORESOURCE_MEM; + dev_params->res_count++; + } + + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) != 0) { + res[dev_params->res_count].start = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE); + res[dev_params->res_count].end = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_BASE) + + MCDI_QWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION1_SIZE) - 1; + res[dev_params->res_count].flags = IORESOURCE_MEM; + dev_params->res_count++; + } + + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) != 0) { + res[dev_params->res_count].start = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE); + res[dev_params->res_count].end = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_BASE) + + MCDI_QWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION2_SIZE) - 1; + res[dev_params->res_count].flags = IORESOURCE_MEM; + dev_params->res_count++; + } + + if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) != 0) { + res[dev_params->res_count].start = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE); + res[dev_params->res_count].end = + MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_BASE) + + MCDI_QWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION3_SIZE) - 1; + res[dev_params->res_count].flags = IORESOURCE_MEM; + dev_params->res_count++; + } + + dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); + dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); + + return 0; +} + +int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_BUS, bus_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_DEVICE, dev_num); + + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_RESET, inbuf, sizeof(inbuf), + NULL, 0, NULL); + + return ret; +} diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h new file mode 100644 index 000000000000..7440ace5539a --- /dev/null +++ b/drivers/cdx/controller/mcdi_functions.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Header file for MCDI FW interaction for CDX bus. + * + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. + */ + +#ifndef CDX_MCDI_FUNCTIONS_H +#define CDX_MCDI_FUNCTIONS_H + +#include "mcdi.h" +#include "../cdx.h" + +/** + * cdx_mcdi_get_num_buses - Get the total number of buses on + * the controller. + * @cdx: pointer to MCDI interface. + * + * Return: total number of buses available on the controller, + * <0 on failure + */ +int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx); + +/** + * cdx_mcdi_get_num_devs - Get the total number of devices on + * a particular bus of the controller. + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * + * Return: total number of devices available on the bus, <0 on failure + */ +int cdx_mcdi_get_num_devs(struct cdx_mcdi *cdx, int bus_num); + +/** + * cdx_mcdi_get_dev_config - Get configuration for a particular + * bus_num:dev_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * @dev_num: Device number. + * @dev_params: Pointer to cdx_dev_params, this is populated by this + * device with the configuration corresponding to the provided + * bus_num:dev_num. + * + * Return: 0 total number of devices available on the bus, <0 on failure + */ +int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, + u8 bus_num, u8 dev_num, + struct cdx_dev_params *dev_params); + +/** + * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * @dev_num: Device number. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, + u8 bus_num, u8 dev_num); + +#endif /* CDX_MCDI_FUNCTIONS_H */ diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 30fe9848dac1..801d6c83f896 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -247,8 +247,6 @@ config SONYPI To compile this driver as a module, choose M here: the module will be called sonypi. -source "drivers/char/pcmcia/Kconfig" - config MWAVE tristate "ACP Modem (Mwave) support" depends on X86 && TTY diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 1b35d1724565..c5f532e412f1 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ obj-y += agp/ -obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index d68d05d5d383..514f9f287a78 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -90,6 +90,9 @@ parisc_agp_tlbflush(struct agp_memory *mem) { struct _parisc_agp_info *info = &parisc_agp_info; + /* force fdc ops to be visible to IOMMU */ + asm_io_sync(); + writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM); readq(info->ioc_regs+IOC_PCOM); /* flush */ } @@ -158,6 +161,7 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) info->gatt[j] = parisc_agp_mask_memory(agp_bridge, paddr, type); + asm_io_fdc(&info->gatt[j]); } } @@ -191,7 +195,16 @@ static unsigned long parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, int type) { - return SBA_PDIR_VALID_BIT | addr; + unsigned ci; /* coherent index */ + dma_addr_t pa; + + pa = addr & IOVP_MASK; + asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pa))); + + pa |= (ci >> PAGE_SHIFT) & 0xff;/* move CI (8 bits) into lowest byte */ + pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ + + return cpu_to_le64(pa); } static void diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index d5f943938427..ff429ba02fa4 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -293,7 +293,7 @@ static int __init bsr_init(void) if (!np) goto out_err; - bsr_class = class_create(THIS_MODULE, "bsr"); + bsr_class = class_create("bsr"); if (IS_ERR(bsr_class)) { printk(KERN_ERR "class_create() failed for bsr_class\n"); ret = PTR_ERR(bsr_class); diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 06749e295ada..b3eaf3e5ef2e 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -504,7 +504,7 @@ static int __init dsp56k_init_driver(void) printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - dsp56k_class = class_create(THIS_MODULE, "dsp56k"); + dsp56k_class = class_create("dsp56k"); if (IS_ERR(dsp56k_class)) { err = PTR_ERR(dsp56k_class); goto out_chrdev; diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index d160fa4c73fe..73e5a9e28f85 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -860,7 +860,7 @@ static int __init init_ipmi_devintf(void) pr_info("ipmi device interface\n"); - ipmi_class = class_create(THIS_MODULE, "ipmi"); + ipmi_class = class_create("ipmi"); if (IS_ERR(ipmi_class)) { pr_err("ipmi: can't register device class\n"); return PTR_ERR(ipmi_class); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 38aad99ebb61..70cfc5140c2c 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -1049,7 +1049,7 @@ static int __init lp_init(void) return -EIO; } - lp_class = class_create(THIS_MODULE, "printer"); + lp_class = class_create("printer"); if (IS_ERR(lp_class)) { err = PTR_ERR(lp_class); goto out_reg; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index ffb101d349f0..f494d31f2b98 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -762,7 +762,7 @@ static int __init chr_dev_init(void) if (register_chrdev(MEM_MAJOR, "mem", &memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); - mem_class = class_create(THIS_MODULE, "mem"); + mem_class = class_create("mem"); if (IS_ERR(mem_class)) return PTR_ERR(mem_class); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 7a1388b0572b..1c44c29a666e 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -286,7 +286,7 @@ static int __init misc_init(void) struct proc_dir_entry *ret; ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops); - misc_class = class_create(THIS_MODULE, "misc"); + misc_class = class_create("misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig deleted file mode 100644 index f5d589b2be44..000000000000 --- a/drivers/char/pcmcia/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# PCMCIA character device configuration -# - -menu "PCMCIA character devices" - depends on PCMCIA!=n - -config SYNCLINK_CS - tristate "SyncLink PC Card support" - depends on PCMCIA && TTY - help - Enable support for the SyncLink PC Card serial adapter, running - asynchronous and HDLC communications up to 512Kbps. The port is - selectable for RS-232, V.35, RS-449, RS-530, and X.21 - - This driver may be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclink_cs. If you want to do that, say M - here. - -config CARDMAN_4000 - tristate "Omnikey Cardman 4000 support" - depends on PCMCIA - select BITREVERSE - help - Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard - reader. - - This kernel driver requires additional userspace support, either - by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/), - or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc). - -config CARDMAN_4040 - tristate "Omnikey CardMan 4040 support" - depends on PCMCIA - help - Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard - reader. - - This card is basically a USB CCID device connected to a FIFO - in I/O space. To use the kernel driver, you will need either the - PC/SC ifdhandler provided from the Omnikey homepage - (http://www.omnikey.com/), or a current development version of OpenCT - (http://www.opensc-project.org/opensc). - -config SCR24X - tristate "SCR24x Chip Card Interface support" - depends on PCMCIA - help - Enable support for the SCR24x PCMCIA Chip Card Interface. - - To compile this driver as a module, choose M here. - The module will be called scr24x_cs.. - - If unsure say N. - -config IPWIRELESS - tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA && NETDEVICES && TTY - select PPP - help - This is a driver for 3G UMTS PCMCIA card from IPWireless company. In - some countries (for example Czech Republic, T-Mobile ISP) this card - is shipped for service called UMTS 4G. - -endmenu - diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile deleted file mode 100644 index 024eed1c4ca5..000000000000 --- a/drivers/char/pcmcia/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# drivers/char/pcmcia/Makefile -# -# Makefile for the Linux PCMCIA char device drivers. -# - -obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o -obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o -obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o -obj-$(CONFIG_SCR24X) += scr24x_cs.o diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c deleted file mode 100644 index e656f42a28ac..000000000000 --- a/drivers/char/pcmcia/cm4000_cs.c +++ /dev/null @@ -1,1912 +0,0 @@ - /* - * A driver for the PCMCIA Smartcard Reader "Omnikey CardMan Mobile 4000" - * - * cm4000_cs.c support.linux@omnikey.com - * - * Tue Oct 23 11:32:43 GMT 2001 herp - cleaned up header files - * Sun Jan 20 10:11:15 MET 2002 herp - added modversion header files - * Thu Nov 14 16:34:11 GMT 2002 mh - added PPS functionality - * Tue Nov 19 16:36:27 GMT 2002 mh - added SUSPEND/RESUME functionailty - * Wed Jul 28 12:55:01 CEST 2004 mh - kernel 2.6 adjustments - * - * current version: 2.4.0gm4 - * - * (C) 2000,2001,2002,2003,2004 Omnikey AG - * - * (C) 2005-2006 Harald Welte - * - Adhere to Kernel process/coding-style.rst - * - Port to 2.6.13 "new" style PCMCIA - * - Check for copy_{from,to}_user return values - * - Use nonseekable_open() - * - add class interface for udev device creation - * - * All rights reserved. Licensed under dual BSD/GPL license. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* #define ATR_CSUM */ - -#define reader_to_dev(x) (&x->p_dev->dev) - -/* n (debug level) is ignored */ -/* additional debug output may be enabled by re-compiling with - * CM4000_DEBUG set */ -/* #define CM4000_DEBUG */ -#define DEBUGP(n, rdr, x, args...) do { \ - dev_dbg(reader_to_dev(rdr), "%s:" x, \ - __func__ , ## args); \ - } while (0) - -static DEFINE_MUTEX(cmm_mutex); - -#define T_1SEC (HZ) -#define T_10MSEC msecs_to_jiffies(10) -#define T_20MSEC msecs_to_jiffies(20) -#define T_40MSEC msecs_to_jiffies(40) -#define T_50MSEC msecs_to_jiffies(50) -#define T_100MSEC msecs_to_jiffies(100) -#define T_500MSEC msecs_to_jiffies(500) - -static void cm4000_release(struct pcmcia_device *link); - -static int major; /* major number we get from the kernel */ - -/* note: the first state has to have number 0 always */ - -#define M_FETCH_ATR 0 -#define M_TIMEOUT_WAIT 1 -#define M_READ_ATR_LEN 2 -#define M_READ_ATR 3 -#define M_ATR_PRESENT 4 -#define M_BAD_CARD 5 -#define M_CARDOFF 6 - -#define LOCK_IO 0 -#define LOCK_MONITOR 1 - -#define IS_AUTOPPS_ACT 6 -#define IS_PROCBYTE_PRESENT 7 -#define IS_INVREV 8 -#define IS_ANY_T0 9 -#define IS_ANY_T1 10 -#define IS_ATR_PRESENT 11 -#define IS_ATR_VALID 12 -#define IS_CMM_ABSENT 13 -#define IS_BAD_LENGTH 14 -#define IS_BAD_CSUM 15 -#define IS_BAD_CARD 16 - -#define REG_FLAGS0(x) (x + 0) -#define REG_FLAGS1(x) (x + 1) -#define REG_NUM_BYTES(x) (x + 2) -#define REG_BUF_ADDR(x) (x + 3) -#define REG_BUF_DATA(x) (x + 4) -#define REG_NUM_SEND(x) (x + 5) -#define REG_BAUDRATE(x) (x + 6) -#define REG_STOPBITS(x) (x + 7) - -struct cm4000_dev { - struct pcmcia_device *p_dev; - - unsigned char atr[MAX_ATR]; - unsigned char rbuf[512]; - unsigned char sbuf[512]; - - wait_queue_head_t devq; /* when removing cardman must not be - zeroed! */ - - wait_queue_head_t ioq; /* if IO is locked, wait on this Q */ - wait_queue_head_t atrq; /* wait for ATR valid */ - wait_queue_head_t readq; /* used by write to wake blk.read */ - - /* warning: do not move this struct group. - * initialising to zero depends on it - see ZERO_DEV below. */ - struct_group(init, - unsigned char atr_csum; - unsigned char atr_len_retry; - unsigned short atr_len; - unsigned short rlen; /* bytes avail. after write */ - unsigned short rpos; /* latest read pos. write zeroes */ - unsigned char procbyte; /* T=0 procedure byte */ - unsigned char mstate; /* state of card monitor */ - unsigned char cwarn; /* slow down warning */ - unsigned char flags0; /* cardman IO-flags 0 */ - unsigned char flags1; /* cardman IO-flags 1 */ - unsigned int mdelay; /* variable monitor speeds, in jiffies */ - - unsigned int baudv; /* baud value for speed */ - unsigned char ta1; - unsigned char proto; /* T=0, T=1, ... */ - unsigned long flags; /* lock+flags (MONITOR,IO,ATR) * for concurrent - access */ - - unsigned char pts[4]; - - struct timer_list timer; /* used to keep monitor running */ - int monitor_running; - ); -}; - -#define ZERO_DEV(dev) memset(&((dev)->init), 0, sizeof((dev)->init)) - -static struct pcmcia_device *dev_table[CM4000_MAX_DEV]; -static struct class *cmm_class; - -/* This table doesn't use spaces after the comma between fields and thus - * violates process/coding-style.rst. However, I don't really think wrapping it around will - * make it any clearer to read -HW */ -static unsigned char fi_di_table[10][14] = { -/*FI 00 01 02 03 04 05 06 07 08 09 10 11 12 13 */ -/*DI */ -/* 0 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, -/* 1 */ {0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x91,0x11,0x11,0x11,0x11}, -/* 2 */ {0x02,0x12,0x22,0x32,0x11,0x11,0x11,0x11,0x11,0x92,0xA2,0xB2,0x11,0x11}, -/* 3 */ {0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x11,0x11,0x93,0xA3,0xB3,0xC3,0xD3}, -/* 4 */ {0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x11,0x11,0x94,0xA4,0xB4,0xC4,0xD4}, -/* 5 */ {0x00,0x15,0x25,0x35,0x45,0x55,0x65,0x11,0x11,0x95,0xA5,0xB5,0xC5,0xD5}, -/* 6 */ {0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x11,0x11,0x96,0xA6,0xB6,0xC6,0xD6}, -/* 7 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, -/* 8 */ {0x08,0x11,0x28,0x38,0x48,0x58,0x68,0x11,0x11,0x98,0xA8,0xB8,0xC8,0xD8}, -/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9} -}; - -#ifndef CM4000_DEBUG -#define xoutb outb -#define xinb inb -#else -static inline void xoutb(unsigned char val, unsigned short port) -{ - pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); - outb(val, port); -} -static inline unsigned char xinb(unsigned short port) -{ - unsigned char val; - - val = inb(port); - pr_debug("%.2x=inb(%.4x)\n", val, port); - - return val; -} -#endif - -static inline unsigned char invert_revert(unsigned char ch) -{ - return bitrev8(~ch); -} - -static void str_invert_revert(unsigned char *b, int len) -{ - int i; - - for (i = 0; i < len; i++) - b[i] = invert_revert(b[i]); -} - -#define ATRLENCK(dev,pos) \ - if (pos>=dev->atr_len || pos>=MAX_ATR) \ - goto return_0; - -static unsigned int calc_baudv(unsigned char fidi) -{ - unsigned int wcrcf, wbrcf, fi_rfu, di_rfu; - - fi_rfu = 372; - di_rfu = 1; - - /* FI */ - switch ((fidi >> 4) & 0x0F) { - case 0x00: - wcrcf = 372; - break; - case 0x01: - wcrcf = 372; - break; - case 0x02: - wcrcf = 558; - break; - case 0x03: - wcrcf = 744; - break; - case 0x04: - wcrcf = 1116; - break; - case 0x05: - wcrcf = 1488; - break; - case 0x06: - wcrcf = 1860; - break; - case 0x07: - wcrcf = fi_rfu; - break; - case 0x08: - wcrcf = fi_rfu; - break; - case 0x09: - wcrcf = 512; - break; - case 0x0A: - wcrcf = 768; - break; - case 0x0B: - wcrcf = 1024; - break; - case 0x0C: - wcrcf = 1536; - break; - case 0x0D: - wcrcf = 2048; - break; - default: - wcrcf = fi_rfu; - break; - } - - /* DI */ - switch (fidi & 0x0F) { - case 0x00: - wbrcf = di_rfu; - break; - case 0x01: - wbrcf = 1; - break; - case 0x02: - wbrcf = 2; - break; - case 0x03: - wbrcf = 4; - break; - case 0x04: - wbrcf = 8; - break; - case 0x05: - wbrcf = 16; - break; - case 0x06: - wbrcf = 32; - break; - case 0x07: - wbrcf = di_rfu; - break; - case 0x08: - wbrcf = 12; - break; - case 0x09: - wbrcf = 20; - break; - default: - wbrcf = di_rfu; - break; - } - - return (wcrcf / wbrcf); -} - -static unsigned short io_read_num_rec_bytes(unsigned int iobase, - unsigned short *s) -{ - unsigned short tmp; - - tmp = *s = 0; - do { - *s = tmp; - tmp = inb(REG_NUM_BYTES(iobase)) | - (inb(REG_FLAGS0(iobase)) & 4 ? 0x100 : 0); - } while (tmp != *s); - - return *s; -} - -static int parse_atr(struct cm4000_dev *dev) -{ - unsigned char any_t1, any_t0; - unsigned char ch, ifno; - int ix, done; - - DEBUGP(3, dev, "-> parse_atr: dev->atr_len = %i\n", dev->atr_len); - - if (dev->atr_len < 3) { - DEBUGP(5, dev, "parse_atr: atr_len < 3\n"); - return 0; - } - - if (dev->atr[0] == 0x3f) - set_bit(IS_INVREV, &dev->flags); - else - clear_bit(IS_INVREV, &dev->flags); - ix = 1; - ifno = 1; - ch = dev->atr[1]; - dev->proto = 0; /* XXX PROTO */ - any_t1 = any_t0 = done = 0; - dev->ta1 = 0x11; /* defaults to 9600 baud */ - do { - if (ifno == 1 && (ch & 0x10)) { - /* read first interface byte and TA1 is present */ - dev->ta1 = dev->atr[2]; - DEBUGP(5, dev, "Card says FiDi is 0x%.2x\n", dev->ta1); - ifno++; - } else if ((ifno == 2) && (ch & 0x10)) { /* TA(2) */ - dev->ta1 = 0x11; - ifno++; - } - - DEBUGP(5, dev, "Yi=%.2x\n", ch & 0xf0); - ix += ((ch & 0x10) >> 4) /* no of int.face chars */ - +((ch & 0x20) >> 5) - + ((ch & 0x40) >> 6) - + ((ch & 0x80) >> 7); - /* ATRLENCK(dev,ix); */ - if (ch & 0x80) { /* TDi */ - ch = dev->atr[ix]; - if ((ch & 0x0f)) { - any_t1 = 1; - DEBUGP(5, dev, "card is capable of T=1\n"); - } else { - any_t0 = 1; - DEBUGP(5, dev, "card is capable of T=0\n"); - } - } else - done = 1; - } while (!done); - - DEBUGP(5, dev, "ix=%d noHist=%d any_t1=%d\n", - ix, dev->atr[1] & 15, any_t1); - if (ix + 1 + (dev->atr[1] & 0x0f) + any_t1 != dev->atr_len) { - DEBUGP(5, dev, "length error\n"); - return 0; - } - if (any_t0) - set_bit(IS_ANY_T0, &dev->flags); - - if (any_t1) { /* compute csum */ - dev->atr_csum = 0; -#ifdef ATR_CSUM - for (i = 1; i < dev->atr_len; i++) - dev->atr_csum ^= dev->atr[i]; - if (dev->atr_csum) { - set_bit(IS_BAD_CSUM, &dev->flags); - DEBUGP(5, dev, "bad checksum\n"); - goto return_0; - } -#endif - if (any_t0 == 0) - dev->proto = 1; /* XXX PROTO */ - set_bit(IS_ANY_T1, &dev->flags); - } - - return 1; -} - -struct card_fixup { - char atr[12]; - u_int8_t atr_len; - u_int8_t stopbits; -}; - -static struct card_fixup card_fixups[] = { - { /* ACOS */ - .atr = { 0x3b, 0xb3, 0x11, 0x00, 0x00, 0x41, 0x01 }, - .atr_len = 7, - .stopbits = 0x03, - }, - { /* Motorola */ - .atr = {0x3b, 0x76, 0x13, 0x00, 0x00, 0x80, 0x62, 0x07, - 0x41, 0x81, 0x81 }, - .atr_len = 11, - .stopbits = 0x04, - }, -}; - -static void set_cardparameter(struct cm4000_dev *dev) -{ - int i; - unsigned int iobase = dev->p_dev->resource[0]->start; - u_int8_t stopbits = 0x02; /* ISO default */ - - DEBUGP(3, dev, "-> set_cardparameter\n"); - - dev->flags1 = dev->flags1 | (((dev->baudv - 1) & 0x0100) >> 8); - xoutb(dev->flags1, REG_FLAGS1(iobase)); - DEBUGP(5, dev, "flags1 = 0x%02x\n", dev->flags1); - - /* set baudrate */ - xoutb((unsigned char)((dev->baudv - 1) & 0xFF), REG_BAUDRATE(iobase)); - - DEBUGP(5, dev, "baudv = %i -> write 0x%02x\n", dev->baudv, - ((dev->baudv - 1) & 0xFF)); - - /* set stopbits */ - for (i = 0; i < ARRAY_SIZE(card_fixups); i++) { - if (!memcmp(dev->atr, card_fixups[i].atr, - card_fixups[i].atr_len)) - stopbits = card_fixups[i].stopbits; - } - xoutb(stopbits, REG_STOPBITS(iobase)); - - DEBUGP(3, dev, "<- set_cardparameter\n"); -} - -static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) -{ - - unsigned long tmp, i; - unsigned short num_bytes_read; - unsigned char pts_reply[4]; - ssize_t rc; - unsigned int iobase = dev->p_dev->resource[0]->start; - - rc = 0; - - DEBUGP(3, dev, "-> set_protocol\n"); - DEBUGP(5, dev, "ptsreq->Protocol = 0x%.8x, ptsreq->Flags=0x%.8x, " - "ptsreq->pts1=0x%.2x, ptsreq->pts2=0x%.2x, " - "ptsreq->pts3=0x%.2x\n", (unsigned int)ptsreq->protocol, - (unsigned int)ptsreq->flags, ptsreq->pts1, ptsreq->pts2, - ptsreq->pts3); - - /* Fill PTS structure */ - dev->pts[0] = 0xff; - dev->pts[1] = 0x00; - tmp = ptsreq->protocol; - while ((tmp = (tmp >> 1)) > 0) - dev->pts[1]++; - dev->proto = dev->pts[1]; /* Set new protocol */ - dev->pts[1] = (0x01 << 4) | (dev->pts[1]); - - /* Correct Fi/Di according to CM4000 Fi/Di table */ - DEBUGP(5, dev, "Ta(1) from ATR is 0x%.2x\n", dev->ta1); - /* set Fi/Di according to ATR TA(1) */ - dev->pts[2] = fi_di_table[dev->ta1 & 0x0F][(dev->ta1 >> 4) & 0x0F]; - - /* Calculate PCK character */ - dev->pts[3] = dev->pts[0] ^ dev->pts[1] ^ dev->pts[2]; - - DEBUGP(5, dev, "pts0=%.2x, pts1=%.2x, pts2=%.2x, pts3=%.2x\n", - dev->pts[0], dev->pts[1], dev->pts[2], dev->pts[3]); - - /* check card convention */ - if (test_bit(IS_INVREV, &dev->flags)) - str_invert_revert(dev->pts, 4); - - /* reset SM */ - xoutb(0x80, REG_FLAGS0(iobase)); - - /* Enable access to the message buffer */ - DEBUGP(5, dev, "Enable access to the messages buffer\n"); - dev->flags1 = 0x20 /* T_Active */ - | (test_bit(IS_INVREV, &dev->flags) ? 0x02 : 0x00) /* inv parity */ - | ((dev->baudv >> 8) & 0x01); /* MSB-baud */ - xoutb(dev->flags1, REG_FLAGS1(iobase)); - - DEBUGP(5, dev, "Enable message buffer -> flags1 = 0x%.2x\n", - dev->flags1); - - /* write challenge to the buffer */ - DEBUGP(5, dev, "Write challenge to buffer: "); - for (i = 0; i < 4; i++) { - xoutb(i, REG_BUF_ADDR(iobase)); - xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */ -#ifdef CM4000_DEBUG - pr_debug("0x%.2x ", dev->pts[i]); - } - pr_debug("\n"); -#else - } -#endif - - /* set number of bytes to write */ - DEBUGP(5, dev, "Set number of bytes to write\n"); - xoutb(0x04, REG_NUM_SEND(iobase)); - - /* Trigger CARDMAN CONTROLLER */ - xoutb(0x50, REG_FLAGS0(iobase)); - - /* Monitor progress */ - /* wait for xmit done */ - DEBUGP(5, dev, "Waiting for NumRecBytes getting valid\n"); - - for (i = 0; i < 100; i++) { - if (inb(REG_FLAGS0(iobase)) & 0x08) { - DEBUGP(5, dev, "NumRecBytes is valid\n"); - break; - } - /* can not sleep as this is in atomic context */ - mdelay(10); - } - if (i == 100) { - DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting " - "valid\n"); - rc = -EIO; - goto exit_setprotocol; - } - - DEBUGP(5, dev, "Reading NumRecBytes\n"); - for (i = 0; i < 100; i++) { - io_read_num_rec_bytes(iobase, &num_bytes_read); - if (num_bytes_read >= 4) { - DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read); - if (num_bytes_read > 4) { - rc = -EIO; - goto exit_setprotocol; - } - break; - } - /* can not sleep as this is in atomic context */ - mdelay(10); - } - - /* check whether it is a short PTS reply? */ - if (num_bytes_read == 3) - i = 0; - - if (i == 100) { - DEBUGP(5, dev, "Timeout reading num_bytes_read\n"); - rc = -EIO; - goto exit_setprotocol; - } - - DEBUGP(5, dev, "Reset the CARDMAN CONTROLLER\n"); - xoutb(0x80, REG_FLAGS0(iobase)); - - /* Read PPS reply */ - DEBUGP(5, dev, "Read PPS reply\n"); - for (i = 0; i < num_bytes_read; i++) { - xoutb(i, REG_BUF_ADDR(iobase)); - pts_reply[i] = inb(REG_BUF_DATA(iobase)); - } - -#ifdef CM4000_DEBUG - DEBUGP(2, dev, "PTSreply: "); - for (i = 0; i < num_bytes_read; i++) { - pr_debug("0x%.2x ", pts_reply[i]); - } - pr_debug("\n"); -#endif /* CM4000_DEBUG */ - - DEBUGP(5, dev, "Clear Tactive in Flags1\n"); - xoutb(0x20, REG_FLAGS1(iobase)); - - /* Compare ptsreq and ptsreply */ - if ((dev->pts[0] == pts_reply[0]) && - (dev->pts[1] == pts_reply[1]) && - (dev->pts[2] == pts_reply[2]) && (dev->pts[3] == pts_reply[3])) { - /* setcardparameter according to PPS */ - dev->baudv = calc_baudv(dev->pts[2]); - set_cardparameter(dev); - } else if ((dev->pts[0] == pts_reply[0]) && - ((dev->pts[1] & 0xef) == pts_reply[1]) && - ((pts_reply[0] ^ pts_reply[1]) == pts_reply[2])) { - /* short PTS reply, set card parameter to default values */ - dev->baudv = calc_baudv(0x11); - set_cardparameter(dev); - } else - rc = -EIO; - -exit_setprotocol: - DEBUGP(3, dev, "<- set_protocol\n"); - return rc; -} - -static int io_detect_cm4000(unsigned int iobase, struct cm4000_dev *dev) -{ - - /* note: statemachine is assumed to be reset */ - if (inb(REG_FLAGS0(iobase)) & 8) { - clear_bit(IS_ATR_VALID, &dev->flags); - set_bit(IS_CMM_ABSENT, &dev->flags); - return 0; /* detect CMM = 1 -> failure */ - } - /* xoutb(0x40, REG_FLAGS1(iobase)); detectCMM */ - xoutb(dev->flags1 | 0x40, REG_FLAGS1(iobase)); - if ((inb(REG_FLAGS0(iobase)) & 8) == 0) { - clear_bit(IS_ATR_VALID, &dev->flags); - set_bit(IS_CMM_ABSENT, &dev->flags); - return 0; /* detect CMM=0 -> failure */ - } - /* clear detectCMM again by restoring original flags1 */ - xoutb(dev->flags1, REG_FLAGS1(iobase)); - return 1; -} - -static void terminate_monitor(struct cm4000_dev *dev) -{ - - /* tell the monitor to stop and wait until - * it terminates. - */ - DEBUGP(3, dev, "-> terminate_monitor\n"); - wait_event_interruptible(dev->devq, - test_and_set_bit(LOCK_MONITOR, - (void *)&dev->flags)); - - /* now, LOCK_MONITOR has been set. - * allow a last cycle in the monitor. - * the monitor will indicate that it has - * finished by clearing this bit. - */ - DEBUGP(5, dev, "Now allow last cycle of monitor!\n"); - while (test_bit(LOCK_MONITOR, (void *)&dev->flags)) - msleep(25); - - DEBUGP(5, dev, "Delete timer\n"); - del_timer_sync(&dev->timer); -#ifdef CM4000_DEBUG - dev->monitor_running = 0; -#endif - - DEBUGP(3, dev, "<- terminate_monitor\n"); -} - -/* - * monitor the card every 50msec. as a side-effect, retrieve the - * atr once a card is inserted. another side-effect of retrieving the - * atr is that the card will be powered on, so there is no need to - * power on the card explicitly from the application: the driver - * is already doing that for you. - */ - -static void monitor_card(struct timer_list *t) -{ - struct cm4000_dev *dev = from_timer(dev, t, timer); - unsigned int iobase = dev->p_dev->resource[0]->start; - unsigned short s; - struct ptsreq ptsreq; - int i, atrc; - - DEBUGP(7, dev, "-> monitor_card\n"); - - /* if someone has set the lock for us: we're done! */ - if (test_and_set_bit(LOCK_MONITOR, &dev->flags)) { - DEBUGP(4, dev, "About to stop monitor\n"); - /* no */ - dev->rlen = - dev->rpos = - dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0; - dev->mstate = M_FETCH_ATR; - clear_bit(LOCK_MONITOR, &dev->flags); - /* close et al. are sleeping on devq, so wake it */ - wake_up_interruptible(&dev->devq); - DEBUGP(2, dev, "<- monitor_card (we are done now)\n"); - return; - } - - /* try to lock io: if it is already locked, just add another timer */ - if (test_and_set_bit(LOCK_IO, (void *)&dev->flags)) { - DEBUGP(4, dev, "Couldn't get IO lock\n"); - goto return_with_timer; - } - - /* is a card/a reader inserted at all ? */ - dev->flags0 = xinb(REG_FLAGS0(iobase)); - DEBUGP(7, dev, "dev->flags0 = 0x%2x\n", dev->flags0); - DEBUGP(7, dev, "smartcard present: %s\n", - dev->flags0 & 1 ? "yes" : "no"); - DEBUGP(7, dev, "cardman present: %s\n", - dev->flags0 == 0xff ? "no" : "yes"); - - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ - || dev->flags0 == 0xff) { /* no cardman inserted */ - /* no */ - dev->rlen = - dev->rpos = - dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0; - dev->mstate = M_FETCH_ATR; - - dev->flags &= 0x000000ff; /* only keep IO and MONITOR locks */ - - if (dev->flags0 == 0xff) { - DEBUGP(4, dev, "set IS_CMM_ABSENT bit\n"); - set_bit(IS_CMM_ABSENT, &dev->flags); - } else if (test_bit(IS_CMM_ABSENT, &dev->flags)) { - DEBUGP(4, dev, "clear IS_CMM_ABSENT bit " - "(card is removed)\n"); - clear_bit(IS_CMM_ABSENT, &dev->flags); - } - - goto release_io; - } else if ((dev->flags0 & 1) && test_bit(IS_CMM_ABSENT, &dev->flags)) { - /* cardman and card present but cardman was absent before - * (after suspend with inserted card) */ - DEBUGP(4, dev, "clear IS_CMM_ABSENT bit (card is inserted)\n"); - clear_bit(IS_CMM_ABSENT, &dev->flags); - } - - if (test_bit(IS_ATR_VALID, &dev->flags) == 1) { - DEBUGP(7, dev, "believe ATR is already valid (do nothing)\n"); - goto release_io; - } - - switch (dev->mstate) { - case M_CARDOFF: { - unsigned char flags0; - - DEBUGP(4, dev, "M_CARDOFF\n"); - flags0 = inb(REG_FLAGS0(iobase)); - if (flags0 & 0x02) { - /* wait until Flags0 indicate power is off */ - dev->mdelay = T_10MSEC; - } else { - /* Flags0 indicate power off and no card inserted now; - * Reset CARDMAN CONTROLLER */ - xoutb(0x80, REG_FLAGS0(iobase)); - - /* prepare for fetching ATR again: after card off ATR - * is read again automatically */ - dev->rlen = - dev->rpos = - dev->atr_csum = - dev->atr_len_retry = dev->cwarn = 0; - dev->mstate = M_FETCH_ATR; - - /* minimal gap between CARDOFF and read ATR is 50msec */ - dev->mdelay = T_50MSEC; - } - break; - } - case M_FETCH_ATR: - DEBUGP(4, dev, "M_FETCH_ATR\n"); - xoutb(0x80, REG_FLAGS0(iobase)); - DEBUGP(4, dev, "Reset BAUDV to 9600\n"); - dev->baudv = 0x173; /* 9600 */ - xoutb(0x02, REG_STOPBITS(iobase)); /* stopbits=2 */ - xoutb(0x73, REG_BAUDRATE(iobase)); /* baud value */ - xoutb(0x21, REG_FLAGS1(iobase)); /* T_Active=1, baud - value */ - /* warm start vs. power on: */ - xoutb(dev->flags0 & 2 ? 0x46 : 0x44, REG_FLAGS0(iobase)); - dev->mdelay = T_40MSEC; - dev->mstate = M_TIMEOUT_WAIT; - break; - case M_TIMEOUT_WAIT: - DEBUGP(4, dev, "M_TIMEOUT_WAIT\n"); - /* numRecBytes */ - io_read_num_rec_bytes(iobase, &dev->atr_len); - dev->mdelay = T_10MSEC; - dev->mstate = M_READ_ATR_LEN; - break; - case M_READ_ATR_LEN: - DEBUGP(4, dev, "M_READ_ATR_LEN\n"); - /* infinite loop possible, since there is no timeout */ - -#define MAX_ATR_LEN_RETRY 100 - - if (dev->atr_len == io_read_num_rec_bytes(iobase, &s)) { - if (dev->atr_len_retry++ >= MAX_ATR_LEN_RETRY) { /* + XX msec */ - dev->mdelay = T_10MSEC; - dev->mstate = M_READ_ATR; - } - } else { - dev->atr_len = s; - dev->atr_len_retry = 0; /* set new timeout */ - } - - DEBUGP(4, dev, "Current ATR_LEN = %i\n", dev->atr_len); - break; - case M_READ_ATR: - DEBUGP(4, dev, "M_READ_ATR\n"); - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ - for (i = 0; i < dev->atr_len; i++) { - xoutb(i, REG_BUF_ADDR(iobase)); - dev->atr[i] = inb(REG_BUF_DATA(iobase)); - } - /* Deactivate T_Active flags */ - DEBUGP(4, dev, "Deactivate T_Active flags\n"); - dev->flags1 = 0x01; - xoutb(dev->flags1, REG_FLAGS1(iobase)); - - /* atr is present (which doesn't mean it's valid) */ - set_bit(IS_ATR_PRESENT, &dev->flags); - if (dev->atr[0] == 0x03) - str_invert_revert(dev->atr, dev->atr_len); - atrc = parse_atr(dev); - if (atrc == 0) { /* atr invalid */ - dev->mdelay = 0; - dev->mstate = M_BAD_CARD; - } else { - dev->mdelay = T_50MSEC; - dev->mstate = M_ATR_PRESENT; - set_bit(IS_ATR_VALID, &dev->flags); - } - - if (test_bit(IS_ATR_VALID, &dev->flags) == 1) { - DEBUGP(4, dev, "monitor_card: ATR valid\n"); - /* if ta1 == 0x11, no PPS necessary (default values) */ - /* do not do PPS with multi protocol cards */ - if ((test_bit(IS_AUTOPPS_ACT, &dev->flags) == 0) && - (dev->ta1 != 0x11) && - !(test_bit(IS_ANY_T0, &dev->flags) && - test_bit(IS_ANY_T1, &dev->flags))) { - DEBUGP(4, dev, "Perform AUTOPPS\n"); - set_bit(IS_AUTOPPS_ACT, &dev->flags); - ptsreq.protocol = (0x01 << dev->proto); - ptsreq.flags = 0x01; - ptsreq.pts1 = 0x00; - ptsreq.pts2 = 0x00; - ptsreq.pts3 = 0x00; - if (set_protocol(dev, &ptsreq) == 0) { - DEBUGP(4, dev, "AUTOPPS ret SUCC\n"); - clear_bit(IS_AUTOPPS_ACT, &dev->flags); - wake_up_interruptible(&dev->atrq); - } else { - DEBUGP(4, dev, "AUTOPPS failed: " - "repower using defaults\n"); - /* prepare for repowering */ - clear_bit(IS_ATR_PRESENT, &dev->flags); - clear_bit(IS_ATR_VALID, &dev->flags); - dev->rlen = - dev->rpos = - dev->atr_csum = - dev->atr_len_retry = dev->cwarn = 0; - dev->mstate = M_FETCH_ATR; - - dev->mdelay = T_50MSEC; - } - } else { - /* for cards which use slightly different - * params (extra guard time) */ - set_cardparameter(dev); - if (test_bit(IS_AUTOPPS_ACT, &dev->flags) == 1) - DEBUGP(4, dev, "AUTOPPS already active " - "2nd try:use default values\n"); - if (dev->ta1 == 0x11) - DEBUGP(4, dev, "No AUTOPPS necessary " - "TA(1)==0x11\n"); - if (test_bit(IS_ANY_T0, &dev->flags) - && test_bit(IS_ANY_T1, &dev->flags)) - DEBUGP(4, dev, "Do NOT perform AUTOPPS " - "with multiprotocol cards\n"); - clear_bit(IS_AUTOPPS_ACT, &dev->flags); - wake_up_interruptible(&dev->atrq); - } - } else { - DEBUGP(4, dev, "ATR invalid\n"); - wake_up_interruptible(&dev->atrq); - } - break; - case M_BAD_CARD: - DEBUGP(4, dev, "M_BAD_CARD\n"); - /* slow down warning, but prompt immediately after insertion */ - if (dev->cwarn == 0 || dev->cwarn == 10) { - set_bit(IS_BAD_CARD, &dev->flags); - dev_warn(&dev->p_dev->dev, MODULE_NAME ": "); - if (test_bit(IS_BAD_CSUM, &dev->flags)) { - DEBUGP(4, dev, "ATR checksum (0x%.2x, should " - "be zero) failed\n", dev->atr_csum); - } -#ifdef CM4000_DEBUG - else if (test_bit(IS_BAD_LENGTH, &dev->flags)) { - DEBUGP(4, dev, "ATR length error\n"); - } else { - DEBUGP(4, dev, "card damaged or wrong way " - "inserted\n"); - } -#endif - dev->cwarn = 0; - wake_up_interruptible(&dev->atrq); /* wake open */ - } - dev->cwarn++; - dev->mdelay = T_100MSEC; - dev->mstate = M_FETCH_ATR; - break; - default: - DEBUGP(7, dev, "Unknown action\n"); - break; /* nothing */ - } - -release_io: - DEBUGP(7, dev, "release_io\n"); - clear_bit(LOCK_IO, &dev->flags); - wake_up_interruptible(&dev->ioq); /* whoever needs IO */ - -return_with_timer: - DEBUGP(7, dev, "<- monitor_card (returns with timer)\n"); - mod_timer(&dev->timer, jiffies + dev->mdelay); - clear_bit(LOCK_MONITOR, &dev->flags); -} - -/* Interface to userland (file_operations) */ - -static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count, - loff_t *ppos) -{ - struct cm4000_dev *dev = filp->private_data; - unsigned int iobase = dev->p_dev->resource[0]->start; - ssize_t rc; - int i, j, k; - - DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid); - - if (count == 0) /* according to manpage */ - return 0; - - if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ - test_bit(IS_CMM_ABSENT, &dev->flags)) - return -ENODEV; - - if (test_bit(IS_BAD_CSUM, &dev->flags)) - return -EIO; - - /* also see the note about this in cmm_write */ - if (wait_event_interruptible - (dev->atrq, - ((filp->f_flags & O_NONBLOCK) - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - return -ERESTARTSYS; - } - - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) - return -EIO; - - /* this one implements blocking IO */ - if (wait_event_interruptible - (dev->readq, - ((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - return -ERESTARTSYS; - } - - /* lock io */ - if (wait_event_interruptible - (dev->ioq, - ((filp->f_flags & O_NONBLOCK) - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - return -ERESTARTSYS; - } - - rc = 0; - dev->flags0 = inb(REG_FLAGS0(iobase)); - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ - || dev->flags0 == 0xff) { /* no cardman inserted */ - clear_bit(IS_ATR_VALID, &dev->flags); - if (dev->flags0 & 1) { - set_bit(IS_CMM_ABSENT, &dev->flags); - rc = -ENODEV; - } else { - rc = -EIO; - } - goto release_io; - } - - DEBUGP(4, dev, "begin read answer\n"); - j = min(count, (size_t)(dev->rlen - dev->rpos)); - k = dev->rpos; - if (k + j > 255) - j = 256 - k; - DEBUGP(4, dev, "read1 j=%d\n", j); - for (i = 0; i < j; i++) { - xoutb(k++, REG_BUF_ADDR(iobase)); - dev->rbuf[i] = xinb(REG_BUF_DATA(iobase)); - } - j = min(count, (size_t)(dev->rlen - dev->rpos)); - if (k + j > 255) { - DEBUGP(4, dev, "read2 j=%d\n", j); - dev->flags1 |= 0x10; /* MSB buf addr set */ - xoutb(dev->flags1, REG_FLAGS1(iobase)); - for (; i < j; i++) { - xoutb(k++, REG_BUF_ADDR(iobase)); - dev->rbuf[i] = xinb(REG_BUF_DATA(iobase)); - } - } - - if (dev->proto == 0 && count > dev->rlen - dev->rpos && i) { - DEBUGP(4, dev, "T=0 and count > buffer\n"); - dev->rbuf[i] = dev->rbuf[i - 1]; - dev->rbuf[i - 1] = dev->procbyte; - j++; - } - count = j; - - dev->rpos = dev->rlen + 1; - - /* Clear T1Active */ - DEBUGP(4, dev, "Clear T1Active\n"); - dev->flags1 &= 0xdf; - xoutb(dev->flags1, REG_FLAGS1(iobase)); - - xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */ - /* last check before exit */ - if (!io_detect_cm4000(iobase, dev)) { - rc = -ENODEV; - goto release_io; - } - - if (test_bit(IS_INVREV, &dev->flags) && count > 0) - str_invert_revert(dev->rbuf, count); - - if (copy_to_user(buf, dev->rbuf, count)) - rc = -EFAULT; - -release_io: - clear_bit(LOCK_IO, &dev->flags); - wake_up_interruptible(&dev->ioq); - - DEBUGP(2, dev, "<- cmm_read returns: rc = %zi\n", - (rc < 0 ? rc : count)); - return rc < 0 ? rc : count; -} - -static ssize_t cmm_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct cm4000_dev *dev = filp->private_data; - unsigned int iobase = dev->p_dev->resource[0]->start; - unsigned short s; - unsigned char infolen; - unsigned char sendT0; - unsigned short nsend; - unsigned short nr; - ssize_t rc; - int i; - - DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid); - - if (count == 0) /* according to manpage */ - return 0; - - if (dev->proto == 0 && count < 4) { - /* T0 must have at least 4 bytes */ - DEBUGP(4, dev, "T0 short write\n"); - return -EIO; - } - - nr = count & 0x1ff; /* max bytes to write */ - - sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0; - - if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ - test_bit(IS_CMM_ABSENT, &dev->flags)) - return -ENODEV; - - if (test_bit(IS_BAD_CSUM, &dev->flags)) { - DEBUGP(4, dev, "bad csum\n"); - return -EIO; - } - - /* - * wait for atr to become valid. - * note: it is important to lock this code. if we dont, the monitor - * could be run between test_bit and the call to sleep on the - * atr-queue. if *then* the monitor detects atr valid, it will wake up - * any process on the atr-queue, *but* since we have been interrupted, - * we do not yet sleep on this queue. this would result in a missed - * wake_up and the calling process would sleep forever (until - * interrupted). also, do *not* restore_flags before sleep_on, because - * this could result in the same situation! - */ - if (wait_event_interruptible - (dev->atrq, - ((filp->f_flags & O_NONBLOCK) - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - return -ERESTARTSYS; - } - - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { /* invalid atr */ - DEBUGP(4, dev, "invalid ATR\n"); - return -EIO; - } - - /* lock io */ - if (wait_event_interruptible - (dev->ioq, - ((filp->f_flags & O_NONBLOCK) - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - return -ERESTARTSYS; - } - - if (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count))) - return -EFAULT; - - rc = 0; - dev->flags0 = inb(REG_FLAGS0(iobase)); - if ((dev->flags0 & 1) == 0 /* no smartcard inserted */ - || dev->flags0 == 0xff) { /* no cardman inserted */ - clear_bit(IS_ATR_VALID, &dev->flags); - if (dev->flags0 & 1) { - set_bit(IS_CMM_ABSENT, &dev->flags); - rc = -ENODEV; - } else { - DEBUGP(4, dev, "IO error\n"); - rc = -EIO; - } - goto release_io; - } - - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ - - if (!io_detect_cm4000(iobase, dev)) { - rc = -ENODEV; - goto release_io; - } - - /* reflect T=0 send/read mode in flags1 */ - dev->flags1 |= (sendT0); - - set_cardparameter(dev); - - /* dummy read, reset flag procedure received */ - inb(REG_FLAGS1(iobase)); - - dev->flags1 = 0x20 /* T_Active */ - | (sendT0) - | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity */ - | (((dev->baudv - 1) & 0x0100) >> 8); /* MSB-Baud */ - DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1); - xoutb(dev->flags1, REG_FLAGS1(iobase)); - - /* xmit data */ - DEBUGP(4, dev, "Xmit data\n"); - for (i = 0; i < nr; i++) { - if (i >= 256) { - dev->flags1 = 0x20 /* T_Active */ - | (sendT0) /* SendT0 */ - /* inverse parity: */ - | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0) - | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */ - | 0x10; /* set address high */ - DEBUGP(4, dev, "dev->flags = 0x%.2x - set address " - "high\n", dev->flags1); - xoutb(dev->flags1, REG_FLAGS1(iobase)); - } - if (test_bit(IS_INVREV, &dev->flags)) { - DEBUGP(4, dev, "Apply inverse convention for 0x%.2x " - "-> 0x%.2x\n", (unsigned char)dev->sbuf[i], - invert_revert(dev->sbuf[i])); - xoutb(i, REG_BUF_ADDR(iobase)); - xoutb(invert_revert(dev->sbuf[i]), - REG_BUF_DATA(iobase)); - } else { - xoutb(i, REG_BUF_ADDR(iobase)); - xoutb(dev->sbuf[i], REG_BUF_DATA(iobase)); - } - } - DEBUGP(4, dev, "Xmit done\n"); - - if (dev->proto == 0) { - /* T=0 proto: 0 byte reply */ - if (nr == 4) { - DEBUGP(4, dev, "T=0 assumes 0 byte reply\n"); - xoutb(i, REG_BUF_ADDR(iobase)); - if (test_bit(IS_INVREV, &dev->flags)) - xoutb(0xff, REG_BUF_DATA(iobase)); - else - xoutb(0x00, REG_BUF_DATA(iobase)); - } - - /* numSendBytes */ - if (sendT0) - nsend = nr; - else { - if (nr == 4) - nsend = 5; - else { - nsend = 5 + (unsigned char)dev->sbuf[4]; - if (dev->sbuf[4] == 0) - nsend += 0x100; - } - } - } else - nsend = nr; - - /* T0: output procedure byte */ - if (test_bit(IS_INVREV, &dev->flags)) { - DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) " - "0x%.2x\n", invert_revert(dev->sbuf[1])); - xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase)); - } else { - DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]); - xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase)); - } - - DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n", - (unsigned char)(nsend & 0xff)); - xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase)); - - DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n", - 0x40 /* SM_Active */ - | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ - |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ - |(nsend & 0x100) >> 8 /* MSB numSendBytes */ ); - xoutb(0x40 /* SM_Active */ - | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */ - |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */ - |(nsend & 0x100) >> 8, /* MSB numSendBytes */ - REG_FLAGS0(iobase)); - - /* wait for xmit done */ - if (dev->proto == 1) { - DEBUGP(4, dev, "Wait for xmit done\n"); - for (i = 0; i < 1000; i++) { - if (inb(REG_FLAGS0(iobase)) & 0x08) - break; - msleep_interruptible(10); - } - if (i == 1000) { - DEBUGP(4, dev, "timeout waiting for xmit done\n"); - rc = -EIO; - goto release_io; - } - } - - /* T=1: wait for infoLen */ - - infolen = 0; - if (dev->proto) { - /* wait until infoLen is valid */ - for (i = 0; i < 6000; i++) { /* max waiting time of 1 min */ - io_read_num_rec_bytes(iobase, &s); - if (s >= 3) { - infolen = inb(REG_FLAGS1(iobase)); - DEBUGP(4, dev, "infolen=%d\n", infolen); - break; - } - msleep_interruptible(10); - } - if (i == 6000) { - DEBUGP(4, dev, "timeout waiting for infoLen\n"); - rc = -EIO; - goto release_io; - } - } else - clear_bit(IS_PROCBYTE_PRESENT, &dev->flags); - - /* numRecBytes | bit9 of numRecytes */ - io_read_num_rec_bytes(iobase, &dev->rlen); - for (i = 0; i < 600; i++) { /* max waiting time of 2 sec */ - if (dev->proto) { - if (dev->rlen >= infolen + 4) - break; - } - msleep_interruptible(10); - /* numRecBytes | bit9 of numRecytes */ - io_read_num_rec_bytes(iobase, &s); - if (s > dev->rlen) { - DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n"); - i = 0; /* reset timeout */ - dev->rlen = s; - } - /* T=0: we are done when numRecBytes doesn't - * increment any more and NoProcedureByte - * is set and numRecBytes == bytes sent + 6 - * (header bytes + data + 1 for sw2) - * except when the card replies an error - * which means, no data will be sent back. - */ - else if (dev->proto == 0) { - if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) { - /* no procedure byte received since last read */ - DEBUGP(1, dev, "NoProcedure byte set\n"); - /* i=0; */ - } else { - /* procedure byte received since last read */ - DEBUGP(1, dev, "NoProcedure byte unset " - "(reset timeout)\n"); - dev->procbyte = inb(REG_FLAGS1(iobase)); - DEBUGP(1, dev, "Read procedure byte 0x%.2x\n", - dev->procbyte); - i = 0; /* resettimeout */ - } - if (inb(REG_FLAGS0(iobase)) & 0x08) { - DEBUGP(1, dev, "T0Done flag (read reply)\n"); - break; - } - } - if (dev->proto) - infolen = inb(REG_FLAGS1(iobase)); - } - if (i == 600) { - DEBUGP(1, dev, "timeout waiting for numRecBytes\n"); - rc = -EIO; - goto release_io; - } else { - if (dev->proto == 0) { - DEBUGP(1, dev, "Wait for T0Done bit to be set\n"); - for (i = 0; i < 1000; i++) { - if (inb(REG_FLAGS0(iobase)) & 0x08) - break; - msleep_interruptible(10); - } - if (i == 1000) { - DEBUGP(1, dev, "timeout waiting for T0Done\n"); - rc = -EIO; - goto release_io; - } - - dev->procbyte = inb(REG_FLAGS1(iobase)); - DEBUGP(4, dev, "Read procedure byte 0x%.2x\n", - dev->procbyte); - - io_read_num_rec_bytes(iobase, &dev->rlen); - DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen); - - } - } - /* T=1: read offset=zero, T=0: read offset=after challenge */ - dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr; - DEBUGP(4, dev, "dev->rlen = %i, dev->rpos = %i, nr = %i\n", - dev->rlen, dev->rpos, nr); - -release_io: - DEBUGP(4, dev, "Reset SM\n"); - xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */ - - if (rc < 0) { - DEBUGP(4, dev, "Write failed but clear T_Active\n"); - dev->flags1 &= 0xdf; - xoutb(dev->flags1, REG_FLAGS1(iobase)); - } - - clear_bit(LOCK_IO, &dev->flags); - wake_up_interruptible(&dev->ioq); - wake_up_interruptible(&dev->readq); /* tell read we have data */ - - /* ITSEC E2: clear write buffer */ - memset((char *)dev->sbuf, 0, 512); - - /* return error or actually written bytes */ - DEBUGP(2, dev, "<- cmm_write\n"); - return rc < 0 ? rc : nr; -} - -static void start_monitor(struct cm4000_dev *dev) -{ - DEBUGP(3, dev, "-> start_monitor\n"); - if (!dev->monitor_running) { - DEBUGP(5, dev, "create, init and add timer\n"); - timer_setup(&dev->timer, monitor_card, 0); - dev->monitor_running = 1; - mod_timer(&dev->timer, jiffies); - } else - DEBUGP(5, dev, "monitor already running\n"); - DEBUGP(3, dev, "<- start_monitor\n"); -} - -static void stop_monitor(struct cm4000_dev *dev) -{ - DEBUGP(3, dev, "-> stop_monitor\n"); - if (dev->monitor_running) { - DEBUGP(5, dev, "stopping monitor\n"); - terminate_monitor(dev); - /* reset monitor SM */ - clear_bit(IS_ATR_VALID, &dev->flags); - clear_bit(IS_ATR_PRESENT, &dev->flags); - } else - DEBUGP(5, dev, "monitor already stopped\n"); - DEBUGP(3, dev, "<- stop_monitor\n"); -} - -static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct cm4000_dev *dev = filp->private_data; - unsigned int iobase = dev->p_dev->resource[0]->start; - struct inode *inode = file_inode(filp); - struct pcmcia_device *link; - int rc; - void __user *argp = (void __user *)arg; -#ifdef CM4000_DEBUG - char *ioctl_names[CM_IOC_MAXNR + 1] = { - [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS", - [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR", - [_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF", - [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS", - [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", - }; - DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), - iminor(inode), ioctl_names[_IOC_NR(cmd)]); -#endif - - mutex_lock(&cmm_mutex); - rc = -ENODEV; - link = dev_table[iminor(inode)]; - if (!pcmcia_dev_present(link)) { - DEBUGP(4, dev, "DEV_OK false\n"); - goto out; - } - - if (test_bit(IS_CMM_ABSENT, &dev->flags)) { - DEBUGP(4, dev, "CMM_ABSENT flag set\n"); - goto out; - } - rc = -EINVAL; - - if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { - DEBUGP(4, dev, "ioctype mismatch\n"); - goto out; - } - if (_IOC_NR(cmd) > CM_IOC_MAXNR) { - DEBUGP(4, dev, "iocnr mismatch\n"); - goto out; - } - rc = 0; - - switch (cmd) { - case CM_IOCGSTATUS: - DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n"); - { - int status; - - /* clear other bits, but leave inserted & powered as - * they are */ - status = dev->flags0 & 3; - if (test_bit(IS_ATR_PRESENT, &dev->flags)) - status |= CM_ATR_PRESENT; - if (test_bit(IS_ATR_VALID, &dev->flags)) - status |= CM_ATR_VALID; - if (test_bit(IS_CMM_ABSENT, &dev->flags)) - status |= CM_NO_READER; - if (test_bit(IS_BAD_CARD, &dev->flags)) - status |= CM_BAD_CARD; - if (copy_to_user(argp, &status, sizeof(int))) - rc = -EFAULT; - } - break; - case CM_IOCGATR: - DEBUGP(4, dev, "... in CM_IOCGATR\n"); - { - struct atreq __user *atreq = argp; - int tmp; - /* allow nonblocking io and being interrupted */ - if (wait_event_interruptible - (dev->atrq, - ((filp->f_flags & O_NONBLOCK) - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) - != 0)))) { - if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; - } - - rc = -EFAULT; - if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { - tmp = -1; - if (copy_to_user(&(atreq->atr_len), &tmp, - sizeof(int))) - break; - } else { - if (copy_to_user(atreq->atr, dev->atr, - dev->atr_len)) - break; - - tmp = dev->atr_len; - if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) - break; - } - rc = 0; - break; - } - case CM_IOCARDOFF: - -#ifdef CM4000_DEBUG - DEBUGP(4, dev, "... in CM_IOCARDOFF\n"); - if (dev->flags0 & 0x01) { - DEBUGP(4, dev, " Card inserted\n"); - } else { - DEBUGP(2, dev, " No card inserted\n"); - } - if (dev->flags0 & 0x02) { - DEBUGP(4, dev, " Card powered\n"); - } else { - DEBUGP(2, dev, " Card not powered\n"); - } -#endif - - /* is a card inserted and powered? */ - if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) { - - /* get IO lock */ - if (wait_event_interruptible - (dev->ioq, - ((filp->f_flags & O_NONBLOCK) - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) - == 0)))) { - if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; - } - /* Set Flags0 = 0x42 */ - DEBUGP(4, dev, "Set Flags0=0x42 \n"); - xoutb(0x42, REG_FLAGS0(iobase)); - clear_bit(IS_ATR_PRESENT, &dev->flags); - clear_bit(IS_ATR_VALID, &dev->flags); - dev->mstate = M_CARDOFF; - clear_bit(LOCK_IO, &dev->flags); - if (wait_event_interruptible - (dev->atrq, - ((filp->f_flags & O_NONBLOCK) - || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != - 0)))) { - if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; - } - } - /* release lock */ - clear_bit(LOCK_IO, &dev->flags); - wake_up_interruptible(&dev->ioq); - - rc = 0; - break; - case CM_IOCSPTS: - { - struct ptsreq krnptsreq; - - if (copy_from_user(&krnptsreq, argp, - sizeof(struct ptsreq))) { - rc = -EFAULT; - break; - } - - rc = 0; - DEBUGP(4, dev, "... in CM_IOCSPTS\n"); - /* wait for ATR to get valid */ - if (wait_event_interruptible - (dev->atrq, - ((filp->f_flags & O_NONBLOCK) - || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) - != 0)))) { - if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; - } - /* get IO lock */ - if (wait_event_interruptible - (dev->ioq, - ((filp->f_flags & O_NONBLOCK) - || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) - == 0)))) { - if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; - } - - if ((rc = set_protocol(dev, &krnptsreq)) != 0) { - /* auto power_on again */ - dev->mstate = M_FETCH_ATR; - clear_bit(IS_ATR_VALID, &dev->flags); - } - /* release lock */ - clear_bit(LOCK_IO, &dev->flags); - wake_up_interruptible(&dev->ioq); - - } - break; -#ifdef CM4000_DEBUG - case CM_IOSDBGLVL: - rc = -ENOTTY; - break; -#endif - default: - DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); - rc = -ENOTTY; - } -out: - mutex_unlock(&cmm_mutex); - return rc; -} - -static int cmm_open(struct inode *inode, struct file *filp) -{ - struct cm4000_dev *dev; - struct pcmcia_device *link; - int minor = iminor(inode); - int ret; - - if (minor >= CM4000_MAX_DEV) - return -ENODEV; - - mutex_lock(&cmm_mutex); - link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } - - if (link->open) { - ret = -EBUSY; - goto out; - } - - dev = link->priv; - filp->private_data = dev; - - DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n", - imajor(inode), minor, current->comm, current->pid); - - /* init device variables, they may be "polluted" after close - * or, the device may never have been closed (i.e. open failed) - */ - - ZERO_DEV(dev); - - /* opening will always block since the - * monitor will be started by open, which - * means we have to wait for ATR becoming - * valid = block until valid (or card - * inserted) - */ - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto out; - } - - dev->mdelay = T_50MSEC; - - /* start monitoring the cardstatus */ - start_monitor(dev); - - link->open = 1; /* only one open per device */ - - DEBUGP(2, dev, "<- cmm_open\n"); - ret = stream_open(inode, filp); -out: - mutex_unlock(&cmm_mutex); - return ret; -} - -static int cmm_close(struct inode *inode, struct file *filp) -{ - struct cm4000_dev *dev; - struct pcmcia_device *link; - int minor = iminor(inode); - - if (minor >= CM4000_MAX_DEV) - return -ENODEV; - - link = dev_table[minor]; - if (link == NULL) - return -ENODEV; - - dev = link->priv; - - DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n", - imajor(inode), minor); - - stop_monitor(dev); - - ZERO_DEV(dev); - - link->open = 0; /* only one open per device */ - wake_up(&dev->devq); /* socket removed? */ - - DEBUGP(2, dev, "cmm_close\n"); - return 0; -} - -static void cmm_cm4000_release(struct pcmcia_device * link) -{ - struct cm4000_dev *dev = link->priv; - - /* dont terminate the monitor, rather rely on - * close doing that for us. - */ - DEBUGP(3, dev, "-> cmm_cm4000_release\n"); - while (link->open) { - printk(KERN_INFO MODULE_NAME ": delaying release until " - "process has terminated\n"); - /* note: don't interrupt us: - * close the applications which own - * the devices _first_ ! - */ - wait_event(dev->devq, (link->open == 0)); - } - /* dev->devq=NULL; this cannot be zeroed earlier */ - DEBUGP(3, dev, "<- cmm_cm4000_release\n"); - return; -} - -/*==== Interface to PCMCIA Layer =======================================*/ - -static int cm4000_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - return pcmcia_request_io(p_dev); -} - -static int cm4000_config(struct pcmcia_device * link, int devno) -{ - link->config_flags |= CONF_AUTO_SET_IO; - - /* read the config-tuples */ - if (pcmcia_loop_config(link, cm4000_config_check, NULL)) - goto cs_release; - - if (pcmcia_enable_device(link)) - goto cs_release; - - return 0; - -cs_release: - cm4000_release(link); - return -ENODEV; -} - -static int cm4000_suspend(struct pcmcia_device *link) -{ - struct cm4000_dev *dev; - - dev = link->priv; - stop_monitor(dev); - - return 0; -} - -static int cm4000_resume(struct pcmcia_device *link) -{ - struct cm4000_dev *dev; - - dev = link->priv; - if (link->open) - start_monitor(dev); - - return 0; -} - -static void cm4000_release(struct pcmcia_device *link) -{ - cmm_cm4000_release(link); /* delay release until device closed */ - pcmcia_disable_device(link); -} - -static int cm4000_probe(struct pcmcia_device *link) -{ - struct cm4000_dev *dev; - int i, ret; - - for (i = 0; i < CM4000_MAX_DEV; i++) - if (dev_table[i] == NULL) - break; - - if (i == CM4000_MAX_DEV) { - printk(KERN_NOTICE MODULE_NAME ": all devices in use\n"); - return -ENODEV; - } - - /* create a new cm4000_cs device */ - dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - - dev->p_dev = link; - link->priv = dev; - dev_table[i] = link; - - init_waitqueue_head(&dev->devq); - init_waitqueue_head(&dev->ioq); - init_waitqueue_head(&dev->atrq); - init_waitqueue_head(&dev->readq); - - ret = cm4000_config(link, i); - if (ret) { - dev_table[i] = NULL; - kfree(dev); - return ret; - } - - device_create(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i); - - return 0; -} - -static void cm4000_detach(struct pcmcia_device *link) -{ - struct cm4000_dev *dev = link->priv; - int devno; - - /* find device */ - for (devno = 0; devno < CM4000_MAX_DEV; devno++) - if (dev_table[devno] == link) - break; - if (devno == CM4000_MAX_DEV) - return; - - stop_monitor(dev); - - cm4000_release(link); - - dev_table[devno] = NULL; - kfree(dev); - - device_destroy(cmm_class, MKDEV(major, devno)); - - return; -} - -static const struct file_operations cm4000_fops = { - .owner = THIS_MODULE, - .read = cmm_read, - .write = cmm_write, - .unlocked_ioctl = cmm_ioctl, - .open = cmm_open, - .release= cmm_close, - .llseek = no_llseek, -}; - -static const struct pcmcia_device_id cm4000_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002), - PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, cm4000_ids); - -static struct pcmcia_driver cm4000_driver = { - .owner = THIS_MODULE, - .name = "cm4000_cs", - .probe = cm4000_probe, - .remove = cm4000_detach, - .suspend = cm4000_suspend, - .resume = cm4000_resume, - .id_table = cm4000_ids, -}; - -static int __init cmm_init(void) -{ - int rc; - - cmm_class = class_create(THIS_MODULE, "cardman_4000"); - if (IS_ERR(cmm_class)) - return PTR_ERR(cmm_class); - - major = register_chrdev(0, DEVICE_NAME, &cm4000_fops); - if (major < 0) { - printk(KERN_WARNING MODULE_NAME - ": could not get major number\n"); - class_destroy(cmm_class); - return major; - } - - rc = pcmcia_register_driver(&cm4000_driver); - if (rc < 0) { - unregister_chrdev(major, DEVICE_NAME); - class_destroy(cmm_class); - return rc; - } - - return 0; -} - -static void __exit cmm_exit(void) -{ - pcmcia_unregister_driver(&cm4000_driver); - unregister_chrdev(major, DEVICE_NAME); - class_destroy(cmm_class); -}; - -module_init(cmm_init); -module_exit(cmm_exit); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c deleted file mode 100644 index 827711911da4..000000000000 --- a/drivers/char/pcmcia/cm4040_cs.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040 - * - * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/) - * - * (C) 2005-2006 Harald Welte - * - add support for poll() - * - driver cleanup - * - add waitqueues - * - adhere to linux kernel coding style and policies - * - support 2.6.13 "new style" pcmcia interface - * - add class interface for udev device creation - * - * The device basically is a USB CCID compliant device that has been - * attached to an I/O-Mapped FIFO. - * - * All rights reserved, Dual BSD/GPL Licensed. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cm4040_cs.h" - - -#define reader_to_dev(x) (&x->p_dev->dev) - -/* n (debug level) is ignored */ -/* additional debug output may be enabled by re-compiling with - * CM4040_DEBUG set */ -/* #define CM4040_DEBUG */ -#define DEBUGP(n, rdr, x, args...) do { \ - dev_dbg(reader_to_dev(rdr), "%s:" x, \ - __func__ , ## args); \ - } while (0) - -static DEFINE_MUTEX(cm4040_mutex); - -#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ) -#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ) -#define CCID_DRIVER_MINIMUM_TIMEOUT (3*HZ) -#define READ_WRITE_BUFFER_SIZE 512 -#define POLL_LOOP_COUNT 1000 - -/* how often to poll for fifo status change */ -#define POLL_PERIOD msecs_to_jiffies(10) - -static void reader_release(struct pcmcia_device *link); - -static int major; -static struct class *cmx_class; - -#define BS_READABLE 0x01 -#define BS_WRITABLE 0x02 - -struct reader_dev { - struct pcmcia_device *p_dev; - wait_queue_head_t devq; - wait_queue_head_t poll_wait; - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - unsigned long buffer_status; - unsigned long timeout; - unsigned char s_buf[READ_WRITE_BUFFER_SIZE]; - unsigned char r_buf[READ_WRITE_BUFFER_SIZE]; - struct timer_list poll_timer; -}; - -static struct pcmcia_device *dev_table[CM_MAX_DEV]; - -#ifndef CM4040_DEBUG -#define xoutb outb -#define xinb inb -#else -static inline void xoutb(unsigned char val, unsigned short port) -{ - pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); - outb(val, port); -} - -static inline unsigned char xinb(unsigned short port) -{ - unsigned char val; - - val = inb(port); - pr_debug("%.2x=inb(%.4x)\n", val, port); - return val; -} -#endif - -/* poll the device fifo status register. not to be confused with - * the poll syscall. */ -static void cm4040_do_poll(struct timer_list *t) -{ - struct reader_dev *dev = from_timer(dev, t, poll_timer); - unsigned int obs = xinb(dev->p_dev->resource[0]->start - + REG_OFFSET_BUFFER_STATUS); - - if ((obs & BSR_BULK_IN_FULL)) { - set_bit(BS_READABLE, &dev->buffer_status); - DEBUGP(4, dev, "waking up read_wait\n"); - wake_up_interruptible(&dev->read_wait); - } else - clear_bit(BS_READABLE, &dev->buffer_status); - - if (!(obs & BSR_BULK_OUT_FULL)) { - set_bit(BS_WRITABLE, &dev->buffer_status); - DEBUGP(4, dev, "waking up write_wait\n"); - wake_up_interruptible(&dev->write_wait); - } else - clear_bit(BS_WRITABLE, &dev->buffer_status); - - if (dev->buffer_status) - wake_up_interruptible(&dev->poll_wait); - - mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); -} - -static void cm4040_stop_poll(struct reader_dev *dev) -{ - del_timer_sync(&dev->poll_timer); -} - -static int wait_for_bulk_out_ready(struct reader_dev *dev) -{ - int i, rc; - int iobase = dev->p_dev->resource[0]->start; - - for (i = 0; i < POLL_LOOP_COUNT; i++) { - if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) - & BSR_BULK_OUT_FULL) == 0) { - DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i); - return 1; - } - } - - DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n", - dev->timeout); - rc = wait_event_interruptible_timeout(dev->write_wait, - test_and_clear_bit(BS_WRITABLE, - &dev->buffer_status), - dev->timeout); - - if (rc > 0) - DEBUGP(4, dev, "woke up: BulkOut empty\n"); - else if (rc == 0) - DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n"); - else if (rc < 0) - DEBUGP(4, dev, "woke up: signal arrived\n"); - - return rc; -} - -/* Write to Sync Control Register */ -static int write_sync_reg(unsigned char val, struct reader_dev *dev) -{ - int iobase = dev->p_dev->resource[0]->start; - int rc; - - rc = wait_for_bulk_out_ready(dev); - if (rc <= 0) - return rc; - - xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL); - rc = wait_for_bulk_out_ready(dev); - if (rc <= 0) - return rc; - - return 1; -} - -static int wait_for_bulk_in_ready(struct reader_dev *dev) -{ - int i, rc; - int iobase = dev->p_dev->resource[0]->start; - - for (i = 0; i < POLL_LOOP_COUNT; i++) { - if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) - & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) { - DEBUGP(3, dev, "BulkIn full (i=%d)\n", i); - return 1; - } - } - - DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n", - dev->timeout); - rc = wait_event_interruptible_timeout(dev->read_wait, - test_and_clear_bit(BS_READABLE, - &dev->buffer_status), - dev->timeout); - if (rc > 0) - DEBUGP(4, dev, "woke up: BulkIn full\n"); - else if (rc == 0) - DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n"); - else if (rc < 0) - DEBUGP(4, dev, "woke up: signal arrived\n"); - - return rc; -} - -static ssize_t cm4040_read(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) -{ - struct reader_dev *dev = filp->private_data; - int iobase = dev->p_dev->resource[0]->start; - size_t bytes_to_read; - unsigned long i; - size_t min_bytes_to_read; - int rc; - - DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid); - - if (count == 0) - return 0; - - if (count < 10) - return -EFAULT; - - if (filp->f_flags & O_NONBLOCK) { - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - DEBUGP(2, dev, "<- cm4040_read (failure)\n"); - return -EAGAIN; - } - - if (!pcmcia_dev_present(dev->p_dev)) - return -ENODEV; - - for (i = 0; i < 5; i++) { - rc = wait_for_bulk_in_ready(dev); - if (rc <= 0) { - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - return -EIO; - } - dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN); -#ifdef CM4040_DEBUG - pr_debug("%lu:%2x ", i, dev->r_buf[i]); - } - pr_debug("\n"); -#else - } -#endif - - bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]); - - DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read); - - min_bytes_to_read = min(count, bytes_to_read + 5); - min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE); - - DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read); - - for (i = 0; i < (min_bytes_to_read-5); i++) { - rc = wait_for_bulk_in_ready(dev); - if (rc <= 0) { - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - return -EIO; - } - dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN); -#ifdef CM4040_DEBUG - pr_debug("%lu:%2x ", i, dev->r_buf[i]); - } - pr_debug("\n"); -#else - } -#endif - - *ppos = min_bytes_to_read; - if (copy_to_user(buf, dev->r_buf, min_bytes_to_read)) - return -EFAULT; - - rc = wait_for_bulk_in_ready(dev); - if (rc <= 0) { - DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc); - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - return -EIO; - } - - rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev); - if (rc <= 0) { - DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc); - DEBUGP(2, dev, "<- cm4040_read (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - else - return -EIO; - } - - xinb(iobase + REG_OFFSET_BULK_IN); - - DEBUGP(2, dev, "<- cm4040_read (successfully)\n"); - return min_bytes_to_read; -} - -static ssize_t cm4040_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct reader_dev *dev = filp->private_data; - int iobase = dev->p_dev->resource[0]->start; - ssize_t rc; - int i; - unsigned int bytes_to_write; - - DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid); - - if (count == 0) { - DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n"); - return 0; - } - - if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) { - DEBUGP(2, dev, "<- cm4040_write buffersize=%zd < 5\n", count); - return -EIO; - } - - if (filp->f_flags & O_NONBLOCK) { - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - DEBUGP(4, dev, "<- cm4040_write (failure)\n"); - return -EAGAIN; - } - - if (!pcmcia_dev_present(dev->p_dev)) - return -ENODEV; - - bytes_to_write = count; - if (copy_from_user(dev->s_buf, buf, bytes_to_write)) - return -EFAULT; - - switch (dev->s_buf[0]) { - case CMD_PC_TO_RDR_XFRBLOCK: - case CMD_PC_TO_RDR_SECURE: - case CMD_PC_TO_RDR_TEST_SECURE: - case CMD_PC_TO_RDR_OK_SECURE: - dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT; - break; - - case CMD_PC_TO_RDR_ICCPOWERON: - dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT; - break; - - case CMD_PC_TO_RDR_GETSLOTSTATUS: - case CMD_PC_TO_RDR_ICCPOWEROFF: - case CMD_PC_TO_RDR_GETPARAMETERS: - case CMD_PC_TO_RDR_RESETPARAMETERS: - case CMD_PC_TO_RDR_SETPARAMETERS: - case CMD_PC_TO_RDR_ESCAPE: - case CMD_PC_TO_RDR_ICCCLOCK: - default: - dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; - break; - } - - rc = write_sync_reg(SCR_HOST_TO_READER_START, dev); - if (rc <= 0) { - DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - else - return -EIO; - } - - DEBUGP(4, dev, "start \n"); - - for (i = 0; i < bytes_to_write; i++) { - rc = wait_for_bulk_out_ready(dev); - if (rc <= 0) { - DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n", - rc); - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - else - return -EIO; - } - - xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT); - } - DEBUGP(4, dev, "end\n"); - - rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev); - - if (rc <= 0) { - DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc); - DEBUGP(2, dev, "<- cm4040_write (failed)\n"); - if (rc == -ERESTARTSYS) - return rc; - else - return -EIO; - } - - DEBUGP(2, dev, "<- cm4040_write (successfully)\n"); - return count; -} - -static __poll_t cm4040_poll(struct file *filp, poll_table *wait) -{ - struct reader_dev *dev = filp->private_data; - __poll_t mask = 0; - - poll_wait(filp, &dev->poll_wait, wait); - - if (test_and_clear_bit(BS_READABLE, &dev->buffer_status)) - mask |= EPOLLIN | EPOLLRDNORM; - if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status)) - mask |= EPOLLOUT | EPOLLWRNORM; - - DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask); - - return mask; -} - -static int cm4040_open(struct inode *inode, struct file *filp) -{ - struct reader_dev *dev; - struct pcmcia_device *link; - int minor = iminor(inode); - int ret; - - if (minor >= CM_MAX_DEV) - return -ENODEV; - - mutex_lock(&cm4040_mutex); - link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } - - if (link->open) { - ret = -EBUSY; - goto out; - } - - dev = link->priv; - filp->private_data = dev; - - if (filp->f_flags & O_NONBLOCK) { - DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - ret = -EAGAIN; - goto out; - } - - link->open = 1; - - mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); - - DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); - ret = nonseekable_open(inode, filp); -out: - mutex_unlock(&cm4040_mutex); - return ret; -} - -static int cm4040_close(struct inode *inode, struct file *filp) -{ - struct reader_dev *dev = filp->private_data; - struct pcmcia_device *link; - int minor = iminor(inode); - - DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode), - iminor(inode)); - - if (minor >= CM_MAX_DEV) - return -ENODEV; - - link = dev_table[minor]; - if (link == NULL) - return -ENODEV; - - cm4040_stop_poll(dev); - - link->open = 0; - wake_up(&dev->devq); - - DEBUGP(2, dev, "<- cm4040_close\n"); - return 0; -} - -static void cm4040_reader_release(struct pcmcia_device *link) -{ - struct reader_dev *dev = link->priv; - - DEBUGP(3, dev, "-> cm4040_reader_release\n"); - while (link->open) { - DEBUGP(3, dev, MODULE_NAME ": delaying release " - "until process has terminated\n"); - wait_event(dev->devq, (link->open == 0)); - } - DEBUGP(3, dev, "<- cm4040_reader_release\n"); - return; -} - -static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - return pcmcia_request_io(p_dev); -} - - -static int reader_config(struct pcmcia_device *link, int devno) -{ - struct reader_dev *dev; - int fail_rc; - - link->config_flags |= CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(link, cm4040_config_check, NULL)) - goto cs_release; - - fail_rc = pcmcia_enable_device(link); - if (fail_rc != 0) { - dev_info(&link->dev, "pcmcia_enable_device failed 0x%x\n", - fail_rc); - goto cs_release; - } - - dev = link->priv; - - DEBUGP(2, dev, "device " DEVICE_NAME "%d at %pR\n", devno, - link->resource[0]); - DEBUGP(2, dev, "<- reader_config (succ)\n"); - - return 0; - -cs_release: - reader_release(link); - return -ENODEV; -} - -static void reader_release(struct pcmcia_device *link) -{ - cm4040_reader_release(link); - pcmcia_disable_device(link); -} - -static int reader_probe(struct pcmcia_device *link) -{ - struct reader_dev *dev; - int i, ret; - - for (i = 0; i < CM_MAX_DEV; i++) { - if (dev_table[i] == NULL) - break; - } - - if (i == CM_MAX_DEV) - return -ENODEV; - - dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - - dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; - dev->buffer_status = 0; - - link->priv = dev; - dev->p_dev = link; - - dev_table[i] = link; - - init_waitqueue_head(&dev->devq); - init_waitqueue_head(&dev->poll_wait); - init_waitqueue_head(&dev->read_wait); - init_waitqueue_head(&dev->write_wait); - timer_setup(&dev->poll_timer, cm4040_do_poll, 0); - - ret = reader_config(link, i); - if (ret) { - dev_table[i] = NULL; - kfree(dev); - return ret; - } - - device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i); - - return 0; -} - -static void reader_detach(struct pcmcia_device *link) -{ - struct reader_dev *dev = link->priv; - int devno; - - /* find device */ - for (devno = 0; devno < CM_MAX_DEV; devno++) { - if (dev_table[devno] == link) - break; - } - if (devno == CM_MAX_DEV) - return; - - reader_release(link); - - dev_table[devno] = NULL; - kfree(dev); - - device_destroy(cmx_class, MKDEV(major, devno)); - - return; -} - -static const struct file_operations reader_fops = { - .owner = THIS_MODULE, - .read = cm4040_read, - .write = cm4040_write, - .open = cm4040_open, - .release = cm4040_close, - .poll = cm4040_poll, - .llseek = no_llseek, -}; - -static const struct pcmcia_device_id cm4040_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200), - PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040", - 0xE32CDD8C, 0x8F23318B), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, cm4040_ids); - -static struct pcmcia_driver reader_driver = { - .owner = THIS_MODULE, - .name = "cm4040_cs", - .probe = reader_probe, - .remove = reader_detach, - .id_table = cm4040_ids, -}; - -static int __init cm4040_init(void) -{ - int rc; - - cmx_class = class_create(THIS_MODULE, "cardman_4040"); - if (IS_ERR(cmx_class)) - return PTR_ERR(cmx_class); - - major = register_chrdev(0, DEVICE_NAME, &reader_fops); - if (major < 0) { - printk(KERN_WARNING MODULE_NAME - ": could not get major number\n"); - class_destroy(cmx_class); - return major; - } - - rc = pcmcia_register_driver(&reader_driver); - if (rc < 0) { - unregister_chrdev(major, DEVICE_NAME); - class_destroy(cmx_class); - return rc; - } - - return 0; -} - -static void __exit cm4040_exit(void) -{ - pcmcia_unregister_driver(&reader_driver); - unregister_chrdev(major, DEVICE_NAME); - class_destroy(cmx_class); -} - -module_init(cm4040_init); -module_exit(cm4040_exit); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/char/pcmcia/cm4040_cs.h b/drivers/char/pcmcia/cm4040_cs.h deleted file mode 100644 index e2ffff995d51..000000000000 --- a/drivers/char/pcmcia/cm4040_cs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _CM4040_H_ -#define _CM4040_H_ - -#define CM_MAX_DEV 4 - -#define DEVICE_NAME "cmx" -#define MODULE_NAME "cm4040_cs" - -#define REG_OFFSET_BULK_OUT 0 -#define REG_OFFSET_BULK_IN 0 -#define REG_OFFSET_BUFFER_STATUS 1 -#define REG_OFFSET_SYNC_CONTROL 2 - -#define BSR_BULK_IN_FULL 0x02 -#define BSR_BULK_OUT_FULL 0x01 - -#define SCR_HOST_TO_READER_START 0x80 -#define SCR_ABORT 0x40 -#define SCR_EN_NOTIFY 0x20 -#define SCR_ACK_NOTIFY 0x10 -#define SCR_READER_TO_HOST_DONE 0x08 -#define SCR_HOST_TO_READER_DONE 0x04 -#define SCR_PULSE_INTERRUPT 0x02 -#define SCR_POWER_DOWN 0x01 - - -#define CMD_PC_TO_RDR_ICCPOWERON 0x62 -#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65 -#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63 -#define CMD_PC_TO_RDR_SECURE 0x69 -#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C -#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D -#define CMD_PC_TO_RDR_SETPARAMETERS 0x61 -#define CMD_PC_TO_RDR_XFRBLOCK 0x6F -#define CMD_PC_TO_RDR_ESCAPE 0x6B -#define CMD_PC_TO_RDR_ICCCLOCK 0x6E -#define CMD_PC_TO_RDR_TEST_SECURE 0x74 -#define CMD_PC_TO_RDR_OK_SECURE 0x89 - - -#define CMD_RDR_TO_PC_SLOTSTATUS 0x81 -#define CMD_RDR_TO_PC_DATABLOCK 0x80 -#define CMD_RDR_TO_PC_PARAMETERS 0x82 -#define CMD_RDR_TO_PC_ESCAPE 0x83 -#define CMD_RDR_TO_PC_OK_SECURE 0x89 - -#endif /* _CM4040_H_ */ diff --git a/drivers/char/pcmcia/scr24x_cs.c b/drivers/char/pcmcia/scr24x_cs.c deleted file mode 100644 index 1bdce08fae3d..000000000000 --- a/drivers/char/pcmcia/scr24x_cs.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * SCR24x PCMCIA Smart Card Reader Driver - * - * Copyright (C) 2005-2006 TL Sudheendran - * Copyright (C) 2016 Lubomir Rintel - * - * Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define CCID_HEADER_SIZE 10 -#define CCID_LENGTH_OFFSET 1 -#define CCID_MAX_LEN 271 - -#define SCR24X_DATA(n) (1 + n) -#define SCR24X_CMD_STATUS 7 -#define CMD_START 0x40 -#define CMD_WRITE_BYTE 0x41 -#define CMD_READ_BYTE 0x42 -#define STATUS_BUSY 0x80 - -struct scr24x_dev { - struct device *dev; - struct cdev c_dev; - unsigned char buf[CCID_MAX_LEN]; - int devno; - struct mutex lock; - struct kref refcnt; - u8 __iomem *regs; -}; - -#define SCR24X_DEVS 8 -static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS); - -static struct class *scr24x_class; -static dev_t scr24x_devt; - -static void scr24x_delete(struct kref *kref) -{ - struct scr24x_dev *dev = container_of(kref, struct scr24x_dev, - refcnt); - - kfree(dev); -} - -static int scr24x_wait_ready(struct scr24x_dev *dev) -{ - u_char status; - int timeout = 100; - - do { - status = ioread8(dev->regs + SCR24X_CMD_STATUS); - if (!(status & STATUS_BUSY)) - return 0; - - msleep(20); - } while (--timeout); - - return -EIO; -} - -static int scr24x_open(struct inode *inode, struct file *filp) -{ - struct scr24x_dev *dev = container_of(inode->i_cdev, - struct scr24x_dev, c_dev); - - kref_get(&dev->refcnt); - filp->private_data = dev; - - return stream_open(inode, filp); -} - -static int scr24x_release(struct inode *inode, struct file *filp) -{ - struct scr24x_dev *dev = filp->private_data; - - /* We must not take the dev->lock here as scr24x_delete() - * might be called to remove the dev structure altogether. - * We don't need the lock anyway, since after the reference - * acquired in probe() is released in remove() the chrdev - * is already unregistered and noone can possibly acquire - * a reference via open() anymore. */ - kref_put(&dev->refcnt, scr24x_delete); - return 0; -} - -static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit) -{ - size_t i, y; - int ret; - - for (i = offset; i < limit; i += 5) { - iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS); - ret = scr24x_wait_ready(dev); - if (ret < 0) - return ret; - - for (y = 0; y < 5 && i + y < limit; y++) - dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y)); - } - - return 0; -} - -static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count, - loff_t *ppos) -{ - struct scr24x_dev *dev = filp->private_data; - int ret; - int len; - - if (count < CCID_HEADER_SIZE) - return -EINVAL; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - - if (!dev->dev) { - ret = -ENODEV; - goto out; - } - - ret = scr24x_wait_ready(dev); - if (ret < 0) - goto out; - len = CCID_HEADER_SIZE; - ret = read_chunk(dev, 0, len); - if (ret < 0) - goto out; - - len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET])); - if (len > sizeof(dev->buf)) { - ret = -EIO; - goto out; - } - ret = read_chunk(dev, CCID_HEADER_SIZE, len); - if (ret < 0) - goto out; - - if (len < count) - count = len; - - if (copy_to_user(buf, dev->buf, count)) { - ret = -EFAULT; - goto out; - } - - ret = count; -out: - mutex_unlock(&dev->lock); - return ret; -} - -static ssize_t scr24x_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct scr24x_dev *dev = filp->private_data; - size_t i, y; - int ret; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - - if (!dev->dev) { - ret = -ENODEV; - goto out; - } - - if (count > sizeof(dev->buf)) { - ret = -EINVAL; - goto out; - } - - if (copy_from_user(dev->buf, buf, count)) { - ret = -EFAULT; - goto out; - } - - ret = scr24x_wait_ready(dev); - if (ret < 0) - goto out; - - iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS); - ret = scr24x_wait_ready(dev); - if (ret < 0) - goto out; - - for (i = 0; i < count; i += 5) { - for (y = 0; y < 5 && i + y < count; y++) - iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y)); - - iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS); - ret = scr24x_wait_ready(dev); - if (ret < 0) - goto out; - } - - ret = count; -out: - mutex_unlock(&dev->lock); - return ret; -} - -static const struct file_operations scr24x_fops = { - .owner = THIS_MODULE, - .read = scr24x_read, - .write = scr24x_write, - .open = scr24x_open, - .release = scr24x_release, - .llseek = no_llseek, -}; - -static int scr24x_config_check(struct pcmcia_device *link, void *priv_data) -{ - if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11) - return -ENODEV; - return pcmcia_request_io(link); -} - -static int scr24x_probe(struct pcmcia_device *link) -{ - struct scr24x_dev *dev; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS); - if (dev->devno >= SCR24X_DEVS) { - ret = -EBUSY; - goto err; - } - - mutex_init(&dev->lock); - kref_init(&dev->refcnt); - - link->priv = dev; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, scr24x_config_check, NULL); - if (ret < 0) - goto err; - - dev->dev = &link->dev; - dev->regs = devm_ioport_map(&link->dev, - link->resource[PCMCIA_IOPORT_0]->start, - resource_size(link->resource[PCMCIA_IOPORT_0])); - if (!dev->regs) { - ret = -EIO; - goto err; - } - - cdev_init(&dev->c_dev, &scr24x_fops); - dev->c_dev.owner = THIS_MODULE; - ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1); - if (ret < 0) - goto err; - - ret = pcmcia_enable_device(link); - if (ret < 0) { - pcmcia_disable_device(link); - goto err; - } - - device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno), - NULL, "scr24x%d", dev->devno); - - dev_info(&link->dev, "SCR24x Chip Card Interface\n"); - return 0; - -err: - if (dev->devno < SCR24X_DEVS) - clear_bit(dev->devno, scr24x_minors); - kfree (dev); - return ret; -} - -static void scr24x_remove(struct pcmcia_device *link) -{ - struct scr24x_dev *dev = (struct scr24x_dev *)link->priv; - - device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno)); - mutex_lock(&dev->lock); - pcmcia_disable_device(link); - cdev_del(&dev->c_dev); - clear_bit(dev->devno, scr24x_minors); - dev->dev = NULL; - mutex_unlock(&dev->lock); - - kref_put(&dev->refcnt, scr24x_delete); -} - -static const struct pcmcia_device_id scr24x_ids[] = { - PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader", - 0x53cb94f9, 0xbfdf89a5), - PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3), - PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de), - PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, scr24x_ids); - -static struct pcmcia_driver scr24x_driver = { - .owner = THIS_MODULE, - .name = "scr24x_cs", - .probe = scr24x_probe, - .remove = scr24x_remove, - .id_table = scr24x_ids, -}; - -static int __init scr24x_init(void) -{ - int ret; - - scr24x_class = class_create(THIS_MODULE, "scr24x"); - if (IS_ERR(scr24x_class)) - return PTR_ERR(scr24x_class); - - ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x"); - if (ret < 0) { - class_destroy(scr24x_class); - return ret; - } - - ret = pcmcia_register_driver(&scr24x_driver); - if (ret < 0) { - unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); - class_destroy(scr24x_class); - } - - return ret; -} - -static void __exit scr24x_exit(void) -{ - pcmcia_unregister_driver(&scr24x_driver); - unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); - class_destroy(scr24x_class); -} - -module_init(scr24x_init); -module_exit(scr24x_exit); - -MODULE_AUTHOR("Lubomir Rintel"); -MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c deleted file mode 100644 index 6ddfeb2fe98f..000000000000 --- a/drivers/char/pcmcia/synclink_cs.c +++ /dev/null @@ -1,4290 +0,0 @@ -/* - * linux/drivers/char/pcmcia/synclink_cs.c - * - * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ - * - * Device driver for Microgate SyncLink PC Card - * multiprotocol serial adapter. - * - * written by Paul Fulghum for Microgate Corporation - * paulkf@microgate.com - * - * Microgate and SyncLink are trademarks of Microgate Corporation - * - * This code is released under the GNU General Public License (GPL) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) -#if defined(__i386__) -# define BREAKPOINT() asm(" int $3"); -#else -# define BREAKPOINT() { } -#endif - -#define MAX_DEVICE_COUNT 4 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) -#define SYNCLINK_GENERIC_HDLC 1 -#else -#define SYNCLINK_GENERIC_HDLC 0 -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - -#include - -static MGSL_PARAMS default_params = { - MGSL_MODE_HDLC, /* unsigned long mode */ - 0, /* unsigned char loopback; */ - HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ - HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ - 0, /* unsigned long clock_speed; */ - 0xff, /* unsigned char addr_filter; */ - HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ - HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ - HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ - 9600, /* unsigned long data_rate; */ - 8, /* unsigned char data_bits; */ - 1, /* unsigned char stop_bits; */ - ASYNC_PARITY_NONE /* unsigned char parity; */ -}; - -typedef struct { - int count; - unsigned char status; - char data[1]; -} RXBUF; - -/* The queue of BH actions to be performed */ - -#define BH_RECEIVE 1 -#define BH_TRANSMIT 2 -#define BH_STATUS 4 - -#define IO_PIN_SHUTDOWN_LIMIT 100 - -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -struct _input_signal_events { - int ri_up; - int ri_down; - int dsr_up; - int dsr_down; - int dcd_up; - int dcd_down; - int cts_up; - int cts_down; -}; - - -/* - * Device instance data structure - */ - -typedef struct _mgslpc_info { - struct tty_port port; - void *if_ptr; /* General purpose pointer (used by SPPP) */ - int magic; - int line; - - struct mgsl_icount icount; - - int timeout; - int x_char; /* xon/xoff character */ - unsigned char read_status_mask; - unsigned char ignore_status_mask; - - unsigned char *tx_buf; - int tx_put; - int tx_get; - int tx_count; - - /* circular list of fixed length rx buffers */ - - unsigned char *rx_buf; /* memory allocated for all rx buffers */ - int rx_buf_total_size; /* size of memory allocated for rx buffers */ - int rx_put; /* index of next empty rx buffer */ - int rx_get; /* index of next full rx buffer */ - int rx_buf_size; /* size in bytes of single rx buffer */ - int rx_buf_count; /* total number of rx buffers */ - int rx_frame_count; /* number of full rx buffers */ - - wait_queue_head_t status_event_wait_q; - wait_queue_head_t event_wait_q; - struct timer_list tx_timer; /* HDLC transmit timeout timer */ - struct _mgslpc_info *next_device; /* device list link */ - - unsigned short imra_value; - unsigned short imrb_value; - unsigned char pim_value; - - spinlock_t lock; - struct work_struct task; /* task structure for scheduling bh */ - - u32 max_frame_size; - - u32 pending_bh; - - bool bh_running; - bool bh_requested; - - int dcd_chkcount; /* check counts to prevent */ - int cts_chkcount; /* too many IRQs if a signal */ - int dsr_chkcount; /* is floating */ - int ri_chkcount; - - bool rx_enabled; - bool rx_overflow; - - bool tx_enabled; - bool tx_active; - bool tx_aborting; - u32 idle_mode; - - int if_mode; /* serial interface selection (RS-232, v.35 etc) */ - - char device_name[25]; /* device instance name */ - - unsigned int io_base; /* base I/O address of adapter */ - unsigned int irq_level; - - MGSL_PARAMS params; /* communications parameters */ - - unsigned char serial_signals; /* current serial signal states */ - - bool irq_occurred; /* for diagnostics use */ - char testing_irq; - unsigned int init_error; /* startup error (DIAGS) */ - - char *flag_buf; - bool drop_rts_on_tx_done; - - struct _input_signal_events input_signal_events; - - /* PCMCIA support */ - struct pcmcia_device *p_dev; - int stop; - - /* SPPP/Cisco HDLC device parts */ - int netcount; - spinlock_t netlock; - -#if SYNCLINK_GENERIC_HDLC - struct net_device *netdev; -#endif - -} MGSLPC_INFO; - -#define MGSLPC_MAGIC 0x5402 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define TXBUFSIZE 4096 - - -#define CHA 0x00 /* channel A offset */ -#define CHB 0x40 /* channel B offset */ - -/* - * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. - */ -#undef PVR - -#define RXFIFO 0 -#define TXFIFO 0 -#define STAR 0x20 -#define CMDR 0x20 -#define RSTA 0x21 -#define PRE 0x21 -#define MODE 0x22 -#define TIMR 0x23 -#define XAD1 0x24 -#define XAD2 0x25 -#define RAH1 0x26 -#define RAH2 0x27 -#define DAFO 0x27 -#define RAL1 0x28 -#define RFC 0x28 -#define RHCR 0x29 -#define RAL2 0x29 -#define RBCL 0x2a -#define XBCL 0x2a -#define RBCH 0x2b -#define XBCH 0x2b -#define CCR0 0x2c -#define CCR1 0x2d -#define CCR2 0x2e -#define CCR3 0x2f -#define VSTR 0x34 -#define BGR 0x34 -#define RLCR 0x35 -#define AML 0x36 -#define AMH 0x37 -#define GIS 0x38 -#define IVA 0x38 -#define IPC 0x39 -#define ISR 0x3a -#define IMR 0x3a -#define PVR 0x3c -#define PIS 0x3d -#define PIM 0x3d -#define PCR 0x3e -#define CCR4 0x3f - -// IMR/ISR - -#define IRQ_BREAK_ON BIT15 // rx break detected -#define IRQ_DATAOVERRUN BIT14 // receive data overflow -#define IRQ_ALLSENT BIT13 // all sent -#define IRQ_UNDERRUN BIT12 // transmit data underrun -#define IRQ_TIMER BIT11 // timer interrupt -#define IRQ_CTS BIT10 // CTS status change -#define IRQ_TXREPEAT BIT9 // tx message repeat -#define IRQ_TXFIFO BIT8 // transmit pool ready -#define IRQ_RXEOM BIT7 // receive message end -#define IRQ_EXITHUNT BIT6 // receive frame start -#define IRQ_RXTIME BIT6 // rx char timeout -#define IRQ_DCD BIT2 // carrier detect status change -#define IRQ_OVERRUN BIT1 // receive frame overflow -#define IRQ_RXFIFO BIT0 // receive pool full - -// STAR - -#define XFW BIT6 // transmit FIFO write enable -#define CEC BIT2 // command executing -#define CTS BIT1 // CTS state - -#define PVR_DTR BIT0 -#define PVR_DSR BIT1 -#define PVR_RI BIT2 -#define PVR_AUTOCTS BIT3 -#define PVR_RS232 0x20 /* 0010b */ -#define PVR_V35 0xe0 /* 1110b */ -#define PVR_RS422 0x40 /* 0100b */ - -/* Register access functions */ - -#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg)) -#define read_reg(info, reg) inb((info)->io_base + (reg)) - -#define read_reg16(info, reg) inw((info)->io_base + (reg)) -#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg)) - -#define set_reg_bits(info, reg, mask) \ - write_reg(info, (reg), \ - (unsigned char) (read_reg(info, (reg)) | (mask))) -#define clear_reg_bits(info, reg, mask) \ - write_reg(info, (reg), \ - (unsigned char) (read_reg(info, (reg)) & ~(mask))) -/* - * interrupt enable/disable routines - */ -static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) -{ - if (channel == CHA) { - info->imra_value |= mask; - write_reg16(info, CHA + IMR, info->imra_value); - } else { - info->imrb_value |= mask; - write_reg16(info, CHB + IMR, info->imrb_value); - } -} -static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask) -{ - if (channel == CHA) { - info->imra_value &= ~mask; - write_reg16(info, CHA + IMR, info->imra_value); - } else { - info->imrb_value &= ~mask; - write_reg16(info, CHB + IMR, info->imrb_value); - } -} - -#define port_irq_disable(info, mask) \ - { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); } - -#define port_irq_enable(info, mask) \ - { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); } - -static void rx_start(MGSLPC_INFO *info); -static void rx_stop(MGSLPC_INFO *info); - -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty); -static void tx_stop(MGSLPC_INFO *info); -static void tx_set_idle(MGSLPC_INFO *info); - -static void get_signals(MGSLPC_INFO *info); -static void set_signals(MGSLPC_INFO *info); - -static void reset_device(MGSLPC_INFO *info); - -static void hdlc_mode(MGSLPC_INFO *info); -static void async_mode(MGSLPC_INFO *info); - -static void tx_timeout(struct timer_list *t); - -static bool carrier_raised(struct tty_port *port); -static void dtr_rts(struct tty_port *port, bool active); - -#if SYNCLINK_GENERIC_HDLC -#define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(MGSLPC_INFO *info); -static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); -static int hdlcdev_init(MGSLPC_INFO *info); -static void hdlcdev_exit(MGSLPC_INFO *info); -#endif - -static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); - -static bool register_test(MGSLPC_INFO *info); -static bool irq_test(MGSLPC_INFO *info); -static int adapter_test(MGSLPC_INFO *info); - -static int claim_resources(MGSLPC_INFO *info); -static void release_resources(MGSLPC_INFO *info); -static int mgslpc_add_device(MGSLPC_INFO *info); -static void mgslpc_remove_device(MGSLPC_INFO *info); - -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); -static void rx_reset_buffers(MGSLPC_INFO *info); -static int rx_alloc_buffers(MGSLPC_INFO *info); -static void rx_free_buffers(MGSLPC_INFO *info); - -static irqreturn_t mgslpc_isr(int irq, void *dev_id); - -/* - * Bottom half interrupt handlers - */ -static void bh_handler(struct work_struct *work); -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty); -static void bh_status(MGSLPC_INFO *info); - -/* - * ioctl handlers - */ -static int tiocmget(struct tty_struct *tty); -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); -static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); -static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params, struct tty_struct *tty); -static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); -static int set_txidle(MGSLPC_INFO *info, int idle_mode); -static int set_txenable(MGSLPC_INFO *info, int enable, struct tty_struct *tty); -static int tx_abort(MGSLPC_INFO *info); -static int set_rxenable(MGSLPC_INFO *info, int enable); -static int wait_events(MGSLPC_INFO *info, int __user *mask); - -static MGSLPC_INFO *mgslpc_device_list = NULL; -static int mgslpc_device_count = 0; - -/* - * Set this param to non-zero to load eax with the - * .text section address and breakpoint on module load. - * This is useful for use with gdb and add-symbol-file command. - */ -static bool break_on_load; - -/* - * Driver major number, defaults to zero to get auto - * assigned major number. May be forced as module parameter. - */ -static int ttymajor=0; - -static int debug_level = 0; -static int maxframe[MAX_DEVICE_COUNT] = {0,}; - -module_param(break_on_load, bool, 0); -module_param(ttymajor, int, 0); -module_param(debug_level, int, 0); -module_param_array(maxframe, int, NULL, 0); - -MODULE_LICENSE("GPL"); - -static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.34 $"; - -static struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty); -static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); - -/* PCMCIA prototypes */ - -static int mgslpc_config(struct pcmcia_device *link); -static void mgslpc_release(u_long arg); -static void mgslpc_detach(struct pcmcia_device *p_dev); - -/* - * 1st function defined in .text section. Calling this function in - * init_module() followed by a breakpoint allows a remote debugger - * (gdb) to get the .text address for the add-symbol-file command. - * This allows remote debugging of dynamically loadable modules. - */ -static void* mgslpc_get_text_ptr(void) -{ - return mgslpc_get_text_ptr; -} - -/* - * line discipline callback wrappers - * - * The wrappers maintain line discipline references - * while calling into the line discipline. - * - * ldisc_receive_buf - pass receive data to line discipline - */ - -static void ldisc_receive_buf(struct tty_struct *tty, - const __u8 *data, char *flags, int count) -{ - struct tty_ldisc *ld; - if (!tty) - return; - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->receive_buf) - ld->ops->receive_buf(tty, data, flags, count); - tty_ldisc_deref(ld); - } -} - -static const struct tty_port_operations mgslpc_port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts -}; - -static int mgslpc_probe(struct pcmcia_device *link) -{ - MGSLPC_INFO *info; - int ret; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_attach\n"); - - info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); - if (!info) { - printk("Error can't allocate device instance data\n"); - return -ENOMEM; - } - - info->magic = MGSLPC_MAGIC; - tty_port_init(&info->port); - info->port.ops = &mgslpc_port_ops; - INIT_WORK(&info->task, bh_handler); - info->max_frame_size = 4096; - init_waitqueue_head(&info->status_event_wait_q); - init_waitqueue_head(&info->event_wait_q); - spin_lock_init(&info->lock); - spin_lock_init(&info->netlock); - memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); - info->idle_mode = HDLC_TXIDLE_FLAGS; - info->imra_value = 0xffff; - info->imrb_value = 0xffff; - info->pim_value = 0xff; - - info->p_dev = link; - link->priv = info; - - /* Initialize the struct pcmcia_device structure */ - - ret = mgslpc_config(link); - if (ret != 0) - goto failed; - - ret = mgslpc_add_device(info); - if (ret != 0) - goto failed_release; - - return 0; - -failed_release: - mgslpc_release((u_long)link); -failed: - tty_port_destroy(&info->port); - kfree(info); - return ret; -} - -/* Card has been inserted. - */ - -static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - return pcmcia_request_io(p_dev); -} - -static int mgslpc_config(struct pcmcia_device *link) -{ - MGSLPC_INFO *info = link->priv; - int ret; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_config(0x%p)\n", link); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); - if (ret != 0) - goto failed; - - link->config_index = 8; - link->config_regs = PRESENT_OPTION; - - ret = pcmcia_request_irq(link, mgslpc_isr); - if (ret) - goto failed; - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - info->io_base = link->resource[0]->start; - info->irq_level = link->irq; - return 0; - -failed: - mgslpc_release((u_long)link); - return -ENODEV; -} - -/* Card has been removed. - * Unregister device and release PCMCIA configuration. - * If device is open, postpone until it is closed. - */ -static void mgslpc_release(u_long arg) -{ - struct pcmcia_device *link = (struct pcmcia_device *)arg; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_release(0x%p)\n", link); - - pcmcia_disable_device(link); -} - -static void mgslpc_detach(struct pcmcia_device *link) -{ - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_detach(0x%p)\n", link); - - ((MGSLPC_INFO *)link->priv)->stop = 1; - mgslpc_release((u_long)link); - - mgslpc_remove_device((MGSLPC_INFO *)link->priv); -} - -static int mgslpc_suspend(struct pcmcia_device *link) -{ - MGSLPC_INFO *info = link->priv; - - info->stop = 1; - - return 0; -} - -static int mgslpc_resume(struct pcmcia_device *link) -{ - MGSLPC_INFO *info = link->priv; - - info->stop = 0; - - return 0; -} - - -static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info, - char *name, const char *routine) -{ -#ifdef MGSLPC_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for mgsl struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null mgslpc_info for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return true; - } - if (info->magic != MGSLPC_MAGIC) { - printk(badmagic, name, routine); - return true; - } -#else - if (!info) - return true; -#endif - return false; -} - - -#define CMD_RXFIFO BIT7 // release current rx FIFO -#define CMD_RXRESET BIT6 // receiver reset -#define CMD_RXFIFO_READ BIT5 -#define CMD_START_TIMER BIT4 -#define CMD_TXFIFO BIT3 // release current tx FIFO -#define CMD_TXEOM BIT1 // transmit end message -#define CMD_TXRESET BIT0 // transmit reset - -static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel) -{ - int i = 0; - /* wait for command completion */ - while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { - udelay(1); - if (i++ == 1000) - return false; - } - return true; -} - -static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) -{ - wait_command_complete(info, channel); - write_reg(info, (unsigned char) (channel + CMDR), cmd); -} - -static void tx_pause(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (mgslpc_paranoia_check(info, tty->name, "tx_pause")) - return; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("tx_pause(%s)\n", info->device_name); - - spin_lock_irqsave(&info->lock, flags); - if (info->tx_enabled) - tx_stop(info); - spin_unlock_irqrestore(&info->lock, flags); -} - -static void tx_release(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (mgslpc_paranoia_check(info, tty->name, "tx_release")) - return; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("tx_release(%s)\n", info->device_name); - - spin_lock_irqsave(&info->lock, flags); - if (!info->tx_enabled) - tx_start(info, tty); - spin_unlock_irqrestore(&info->lock, flags); -} - -/* Return next bottom half action to perform. - * or 0 if nothing to do. - */ -static int bh_action(MGSLPC_INFO *info) -{ - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&info->lock, flags); - - if (info->pending_bh & BH_RECEIVE) { - info->pending_bh &= ~BH_RECEIVE; - rc = BH_RECEIVE; - } else if (info->pending_bh & BH_TRANSMIT) { - info->pending_bh &= ~BH_TRANSMIT; - rc = BH_TRANSMIT; - } else if (info->pending_bh & BH_STATUS) { - info->pending_bh &= ~BH_STATUS; - rc = BH_STATUS; - } - - if (!rc) { - /* Mark BH routine as complete */ - info->bh_running = false; - info->bh_requested = false; - } - - spin_unlock_irqrestore(&info->lock, flags); - - return rc; -} - -static void bh_handler(struct work_struct *work) -{ - MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); - struct tty_struct *tty; - int action; - - if (debug_level >= DEBUG_LEVEL_BH) - printk("%s(%d):bh_handler(%s) entry\n", - __FILE__,__LINE__,info->device_name); - - info->bh_running = true; - tty = tty_port_tty_get(&info->port); - - while((action = bh_action(info)) != 0) { - - /* Process work item */ - if (debug_level >= DEBUG_LEVEL_BH) - printk("%s(%d):bh_handler() work item action=%d\n", - __FILE__,__LINE__,action); - - switch (action) { - - case BH_RECEIVE: - while(rx_get_frame(info, tty)); - break; - case BH_TRANSMIT: - bh_transmit(info, tty); - break; - case BH_STATUS: - bh_status(info); - break; - default: - /* unknown work item ID */ - printk("Unknown work item ID=%08X!\n", action); - break; - } - } - - tty_kref_put(tty); - if (debug_level >= DEBUG_LEVEL_BH) - printk("%s(%d):bh_handler(%s) exit\n", - __FILE__,__LINE__,info->device_name); -} - -static void bh_transmit(MGSLPC_INFO *info, struct tty_struct *tty) -{ - if (debug_level >= DEBUG_LEVEL_BH) - printk("bh_transmit() entry on %s\n", info->device_name); - - if (tty) - tty_wakeup(tty); -} - -static void bh_status(MGSLPC_INFO *info) -{ - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - info->dcd_chkcount = 0; - info->cts_chkcount = 0; -} - -/* eom: non-zero = end of frame */ -static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) -{ - unsigned char data[2]; - unsigned char fifo_count, read_count, i; - RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):rx_ready_hdlc(eom=%d)\n", __FILE__, __LINE__, eom); - - if (!info->rx_enabled) - return; - - if (info->rx_frame_count >= info->rx_buf_count) { - /* no more free buffers */ - issue_command(info, CHA, CMD_RXRESET); - info->pending_bh |= BH_RECEIVE; - info->rx_overflow = true; - info->icount.buf_overrun++; - return; - } - - if (eom) { - /* end of frame, get FIFO count from RBCL register */ - fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); - if (fifo_count == 0) - fifo_count = 32; - } else - fifo_count = 32; - - do { - if (fifo_count == 1) { - read_count = 1; - data[0] = read_reg(info, CHA + RXFIFO); - } else { - read_count = 2; - *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); - } - fifo_count -= read_count; - if (!fifo_count && eom) - buf->status = data[--read_count]; - - for (i = 0; i < read_count; i++) { - if (buf->count >= info->max_frame_size) { - /* frame too large, reset receiver and reset current buffer */ - issue_command(info, CHA, CMD_RXRESET); - buf->count = 0; - return; - } - *(buf->data + buf->count) = data[i]; - buf->count++; - } - } while (fifo_count); - - if (eom) { - info->pending_bh |= BH_RECEIVE; - info->rx_frame_count++; - info->rx_put++; - if (info->rx_put >= info->rx_buf_count) - info->rx_put = 0; - } - issue_command(info, CHA, CMD_RXFIFO); -} - -static void rx_ready_async(MGSLPC_INFO *info, int tcd) -{ - struct tty_port *port = &info->port; - unsigned char data, status, flag; - int fifo_count; - int work = 0; - struct mgsl_icount *icount = &info->icount; - - if (tcd) { - /* early termination, get FIFO count from RBCL register */ - fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); - - /* Zero fifo count could mean 0 or 32 bytes available. - * If BIT5 of STAR is set then at least 1 byte is available. - */ - if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) - fifo_count = 32; - } else - fifo_count = 32; - - tty_buffer_request_room(port, fifo_count); - /* Flush received async data to receive data buffer. */ - while (fifo_count) { - data = read_reg(info, CHA + RXFIFO); - status = read_reg(info, CHA + RXFIFO); - fifo_count -= 2; - - icount->rx++; - flag = TTY_NORMAL; - - // if no frameing/crc error then save data - // BIT7:parity error - // BIT6:framing error - - if (status & (BIT7 | BIT6)) { - if (status & BIT7) - icount->parity++; - else - icount->frame++; - - /* discard char if tty control flags say so */ - if (status & info->ignore_status_mask) - continue; - - status &= info->read_status_mask; - - if (status & BIT7) - flag = TTY_PARITY; - else if (status & BIT6) - flag = TTY_FRAME; - } - work += tty_insert_flip_char(port, data, flag); - } - issue_command(info, CHA, CMD_RXFIFO); - - if (debug_level >= DEBUG_LEVEL_ISR) { - printk("%s(%d):rx_ready_async", - __FILE__,__LINE__); - printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", - __FILE__,__LINE__,icount->rx,icount->brk, - icount->parity,icount->frame,icount->overrun); - } - - if (work) - tty_flip_buffer_push(port); -} - - -static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) -{ - if (!info->tx_active) - return; - - info->tx_active = false; - info->tx_aborting = false; - - if (info->params.mode == MGSL_MODE_ASYNC) - return; - - info->tx_count = info->tx_put = info->tx_get = 0; - del_timer(&info->tx_timer); - - if (info->drop_rts_on_tx_done) { - get_signals(info); - if (info->serial_signals & SerialSignal_RTS) { - info->serial_signals &= ~SerialSignal_RTS; - set_signals(info); - } - info->drop_rts_on_tx_done = false; - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - { - if (tty && (tty->flow.stopped || tty->hw_stopped)) { - tx_stop(info); - return; - } - info->pending_bh |= BH_TRANSMIT; - } -} - -static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) -{ - unsigned char fifo_count = 32; - int c; - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):tx_ready(%s)\n", __FILE__, __LINE__, info->device_name); - - if (info->params.mode == MGSL_MODE_HDLC) { - if (!info->tx_active) - return; - } else { - if (tty && (tty->flow.stopped || tty->hw_stopped)) { - tx_stop(info); - return; - } - if (!info->tx_count) - info->tx_active = false; - } - - if (!info->tx_count) - return; - - while (info->tx_count && fifo_count) { - c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); - - if (c == 1) { - write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); - } else { - write_reg16(info, CHA + TXFIFO, - *((unsigned short*)(info->tx_buf + info->tx_get))); - } - info->tx_count -= c; - info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1); - fifo_count -= c; - } - - if (info->params.mode == MGSL_MODE_ASYNC) { - if (info->tx_count < WAKEUP_CHARS) - info->pending_bh |= BH_TRANSMIT; - issue_command(info, CHA, CMD_TXFIFO); - } else { - if (info->tx_count) - issue_command(info, CHA, CMD_TXFIFO); - else - issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM); - } -} - -static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) -{ - get_signals(info); - if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - irq_disable(info, CHB, IRQ_CTS); - info->icount.cts++; - if (info->serial_signals & SerialSignal_CTS) - info->input_signal_events.cts_up++; - else - info->input_signal_events.cts_down++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - if (tty && tty_port_cts_enabled(&info->port)) { - if (tty->hw_stopped) { - if (info->serial_signals & SerialSignal_CTS) { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("CTS tx start..."); - tty->hw_stopped = 0; - tx_start(info, tty); - info->pending_bh |= BH_TRANSMIT; - return; - } - } else { - if (!(info->serial_signals & SerialSignal_CTS)) { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("CTS tx stop..."); - tty->hw_stopped = 1; - tx_stop(info); - } - } - } - info->pending_bh |= BH_STATUS; -} - -static void dcd_change(MGSLPC_INFO *info, struct tty_struct *tty) -{ - get_signals(info); - if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - irq_disable(info, CHB, IRQ_DCD); - info->icount.dcd++; - if (info->serial_signals & SerialSignal_DCD) { - info->input_signal_events.dcd_up++; - } - else - info->input_signal_events.dcd_down++; -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) { - if (info->serial_signals & SerialSignal_DCD) - netif_carrier_on(info->netdev); - else - netif_carrier_off(info->netdev); - } -#endif - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - if (tty_port_check_carrier(&info->port)) { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s CD now %s...", info->device_name, - (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); - if (info->serial_signals & SerialSignal_DCD) - wake_up_interruptible(&info->port.open_wait); - else { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("doing serial hangup..."); - if (tty) - tty_hangup(tty); - } - } - info->pending_bh |= BH_STATUS; -} - -static void dsr_change(MGSLPC_INFO *info) -{ - get_signals(info); - if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - port_irq_disable(info, PVR_DSR); - info->icount.dsr++; - if (info->serial_signals & SerialSignal_DSR) - info->input_signal_events.dsr_up++; - else - info->input_signal_events.dsr_down++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; -} - -static void ri_change(MGSLPC_INFO *info) -{ - get_signals(info); - if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - port_irq_disable(info, PVR_RI); - info->icount.rng++; - if (info->serial_signals & SerialSignal_RI) - info->input_signal_events.ri_up++; - else - info->input_signal_events.ri_down++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; -} - -/* Interrupt service routine entry point. - * - * Arguments: - * - * irq interrupt number that caused interrupt - * dev_id device ID supplied during interrupt registration - */ -static irqreturn_t mgslpc_isr(int dummy, void *dev_id) -{ - MGSLPC_INFO *info = dev_id; - struct tty_struct *tty; - unsigned short isr; - unsigned char gis, pis; - int count=0; - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("mgslpc_isr(%d) entry.\n", info->irq_level); - - if (!(info->p_dev->_locked)) - return IRQ_HANDLED; - - tty = tty_port_tty_get(&info->port); - - spin_lock(&info->lock); - - while ((gis = read_reg(info, CHA + GIS))) { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis); - - if ((gis & 0x70) || count > 1000) { - printk("synclink_cs:hardware failed or ejected\n"); - break; - } - count++; - - if (gis & (BIT1 | BIT0)) { - isr = read_reg16(info, CHB + ISR); - if (isr & IRQ_DCD) - dcd_change(info, tty); - if (isr & IRQ_CTS) - cts_change(info, tty); - } - if (gis & (BIT3 | BIT2)) - { - isr = read_reg16(info, CHA + ISR); - if (isr & IRQ_TIMER) { - info->irq_occurred = true; - irq_disable(info, CHA, IRQ_TIMER); - } - - /* receive IRQs */ - if (isr & IRQ_EXITHUNT) { - info->icount.exithunt++; - wake_up_interruptible(&info->event_wait_q); - } - if (isr & IRQ_BREAK_ON) { - info->icount.brk++; - if (info->port.flags & ASYNC_SAK) - do_SAK(tty); - } - if (isr & IRQ_RXTIME) { - issue_command(info, CHA, CMD_RXFIFO_READ); - } - if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) { - if (info->params.mode == MGSL_MODE_HDLC) - rx_ready_hdlc(info, isr & IRQ_RXEOM); - else - rx_ready_async(info, isr & IRQ_RXEOM); - } - - /* transmit IRQs */ - if (isr & IRQ_UNDERRUN) { - if (info->tx_aborting) - info->icount.txabort++; - else - info->icount.txunder++; - tx_done(info, tty); - } - else if (isr & IRQ_ALLSENT) { - info->icount.txok++; - tx_done(info, tty); - } - else if (isr & IRQ_TXFIFO) - tx_ready(info, tty); - } - if (gis & BIT7) { - pis = read_reg(info, CHA + PIS); - if (pis & BIT1) - dsr_change(info); - if (pis & BIT2) - ri_change(info); - } - } - - /* Request bottom half processing if there's something - * for it to do and the bh is not already running - */ - - if (info->pending_bh && !info->bh_running && !info->bh_requested) { - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):%s queueing bh task.\n", - __FILE__,__LINE__,info->device_name); - schedule_work(&info->task); - info->bh_requested = true; - } - - spin_unlock(&info->lock); - tty_kref_put(tty); - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):mgslpc_isr(%d)exit.\n", - __FILE__, __LINE__, info->irq_level); - - return IRQ_HANDLED; -} - -/* Initialize and start device. - */ -static int startup(MGSLPC_INFO * info, struct tty_struct *tty) -{ - int retval = 0; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name); - - if (tty_port_initialized(&info->port)) - return 0; - - if (!info->tx_buf) { - /* allocate a page of memory for a transmit buffer */ - info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - if (!info->tx_buf) { - printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", - __FILE__, __LINE__, info->device_name); - return -ENOMEM; - } - } - - info->pending_bh = 0; - - memset(&info->icount, 0, sizeof(info->icount)); - - timer_setup(&info->tx_timer, tx_timeout, 0); - - /* Allocate and claim adapter resources */ - retval = claim_resources(info); - - /* perform existence check and diagnostics */ - if (!retval) - retval = adapter_test(info); - - if (retval) { - if (capable(CAP_SYS_ADMIN) && tty) - set_bit(TTY_IO_ERROR, &tty->flags); - release_resources(info); - return retval; - } - - /* program hardware for current parameters */ - mgslpc_change_params(info, tty); - - if (tty) - clear_bit(TTY_IO_ERROR, &tty->flags); - - tty_port_set_initialized(&info->port, true); - - return 0; -} - -/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware - */ -static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) -{ - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_shutdown(%s)\n", - __FILE__, __LINE__, info->device_name); - - /* clear status wait queue because status changes */ - /* can't happen after shutting down the hardware */ - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - del_timer_sync(&info->tx_timer); - - if (info->tx_buf) { - free_page((unsigned long) info->tx_buf); - info->tx_buf = NULL; - } - - spin_lock_irqsave(&info->lock, flags); - - rx_stop(info); - tx_stop(info); - - /* TODO:disable interrupts instead of reset to preserve signal states */ - reset_device(info); - - if (!tty || C_HUPCL(tty)) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); - } - - spin_unlock_irqrestore(&info->lock, flags); - - release_resources(info); - - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - - tty_port_set_initialized(&info->port, false); -} - -static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - - rx_stop(info); - tx_stop(info); - info->tx_count = info->tx_put = info->tx_get = 0; - - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) - hdlc_mode(info); - else - async_mode(info); - - set_signals(info); - - info->dcd_chkcount = 0; - info->cts_chkcount = 0; - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - - irq_enable(info, CHB, IRQ_DCD | IRQ_CTS); - port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); - get_signals(info); - - if (info->netcount || (tty && C_CREAD(tty))) - rx_start(info); - - spin_unlock_irqrestore(&info->lock, flags); -} - -/* Reconfigure adapter based on new parameters - */ -static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) -{ - unsigned cflag; - int bits_per_char; - - if (!tty) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_change_params(%s)\n", - __FILE__, __LINE__, info->device_name); - - cflag = tty->termios.c_cflag; - - /* if B0 rate (hangup) specified then negate RTS and DTR */ - /* otherwise assert RTS and DTR */ - if (cflag & CBAUD) - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - - /* byte size and parity */ - if ((cflag & CSIZE) != CS8) { - cflag &= ~CSIZE; - cflag |= CS7; - tty->termios.c_cflag = cflag; - } - info->params.data_bits = tty_get_char_size(cflag); - - if (cflag & CSTOPB) - info->params.stop_bits = 2; - else - info->params.stop_bits = 1; - - info->params.parity = ASYNC_PARITY_NONE; - if (cflag & PARENB) { - if (cflag & PARODD) - info->params.parity = ASYNC_PARITY_ODD; - else - info->params.parity = ASYNC_PARITY_EVEN; - if (cflag & CMSPAR) - info->params.parity = ASYNC_PARITY_SPACE; - } - - /* calculate number of jiffies to transmit a full - * FIFO (32 bytes) at specified data rate - */ - bits_per_char = info->params.data_bits + - info->params.stop_bits + 1; - - /* if port data rate is set to 460800 or less then - * allow tty settings to override, otherwise keep the - * current data rate. - */ - if (info->params.data_rate <= 460800) { - info->params.data_rate = tty_get_baud_rate(tty); - } - - if (info->params.data_rate) { - info->timeout = (32*HZ*bits_per_char) / - info->params.data_rate; - } - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - /* process tty input control flags */ - - info->read_status_mask = 0; - if (I_INPCK(tty)) - info->read_status_mask |= BIT7 | BIT6; - if (I_IGNPAR(tty)) - info->ignore_status_mask |= BIT7 | BIT6; - - mgslpc_program_hw(info, tty); -} - -/* Add a character to the transmit buffer - */ -static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) { - printk("%s(%d):mgslpc_put_char(%d) on %s\n", - __FILE__, __LINE__, ch, info->device_name); - } - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) - return 0; - - if (!info->tx_buf) - return 0; - - spin_lock_irqsave(&info->lock, flags); - - if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) { - if (info->tx_count < TXBUFSIZE - 1) { - info->tx_buf[info->tx_put++] = ch; - info->tx_put &= TXBUFSIZE-1; - info->tx_count++; - } - } - - spin_unlock_irqrestore(&info->lock, flags); - return 1; -} - -/* Enable transmitter so remaining characters in the - * transmit buffer are sent. - */ -static void mgslpc_flush_chars(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n", - __FILE__, __LINE__, info->device_name, info->tx_count); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars")) - return; - - if (info->tx_count <= 0 || tty->flow.stopped || - tty->hw_stopped || !info->tx_buf) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n", - __FILE__, __LINE__, info->device_name); - - spin_lock_irqsave(&info->lock, flags); - if (!info->tx_active) - tx_start(info, tty); - spin_unlock_irqrestore(&info->lock, flags); -} - -/* Send a block of data - * - * Arguments: - * - * tty pointer to tty information structure - * buf pointer to buffer containing send data - * count size of send data in bytes - * - * Returns: number of characters written - */ -static int mgslpc_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_write(%s) count=%d\n", - __FILE__, __LINE__, info->device_name, count); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") || - !info->tx_buf) - goto cleanup; - - if (info->params.mode == MGSL_MODE_HDLC) { - if (count > TXBUFSIZE) { - ret = -EIO; - goto cleanup; - } - if (info->tx_active) - goto cleanup; - else if (info->tx_count) - goto start; - } - - for (;;) { - c = min(count, - min(TXBUFSIZE - info->tx_count - 1, - TXBUFSIZE - info->tx_put)); - if (c <= 0) - break; - - memcpy(info->tx_buf + info->tx_put, buf, c); - - spin_lock_irqsave(&info->lock, flags); - info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1); - info->tx_count += c; - spin_unlock_irqrestore(&info->lock, flags); - - buf += c; - count -= c; - ret += c; - } -start: - if (info->tx_count && !tty->flow.stopped && !tty->hw_stopped) { - spin_lock_irqsave(&info->lock, flags); - if (!info->tx_active) - tx_start(info, tty); - spin_unlock_irqrestore(&info->lock, flags); - } -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_write(%s) returning=%d\n", - __FILE__, __LINE__, info->device_name, ret); - return ret; -} - -/* Return the count of free bytes in transmit buffer - */ -static unsigned int mgslpc_write_room(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - int ret; - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room")) - return 0; - - if (info->params.mode == MGSL_MODE_HDLC) { - /* HDLC (frame oriented) mode */ - if (info->tx_active) - return 0; - else - return HDLC_MAX_FRAME_SIZE; - } else { - ret = TXBUFSIZE - info->tx_count - 1; - if (ret < 0) - ret = 0; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_write_room(%s)=%d\n", - __FILE__, __LINE__, info->device_name, ret); - return ret; -} - -/* Return the count of bytes in transmit buffer - */ -static unsigned int mgslpc_chars_in_buffer(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned int rc; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_chars_in_buffer(%s)\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer")) - return 0; - - if (info->params.mode == MGSL_MODE_HDLC) - rc = info->tx_active ? info->max_frame_size : 0; - else - rc = info->tx_count; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_chars_in_buffer(%s)=%u\n", - __FILE__, __LINE__, info->device_name, rc); - - return rc; -} - -/* Discard all data in the send buffer - */ -static void mgslpc_flush_buffer(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_flush_buffer(%s) entry\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer")) - return; - - spin_lock_irqsave(&info->lock, flags); - info->tx_count = info->tx_put = info->tx_get = 0; - del_timer(&info->tx_timer); - spin_unlock_irqrestore(&info->lock, flags); - - wake_up_interruptible(&tty->write_wait); - tty_wakeup(tty); -} - -/* Send a high-priority XON/XOFF character - */ -static void mgslpc_send_xchar(struct tty_struct *tty, char ch) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_send_xchar(%s,%d)\n", - __FILE__, __LINE__, info->device_name, ch); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar")) - return; - - info->x_char = ch; - if (ch) { - spin_lock_irqsave(&info->lock, flags); - if (!info->tx_enabled) - tx_start(info, tty); - spin_unlock_irqrestore(&info->lock, flags); - } -} - -/* Signal remote device to throttle send data (our receive data) - */ -static void mgslpc_throttle(struct tty_struct * tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_throttle(%s) entry\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle")) - return; - - if (I_IXOFF(tty)) - mgslpc_send_xchar(tty, STOP_CHAR(tty)); - - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->lock, flags); - info->serial_signals &= ~SerialSignal_RTS; - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - } -} - -/* Signal remote device to stop throttling send data (our receive data) - */ -static void mgslpc_unthrottle(struct tty_struct * tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_unthrottle(%s) entry\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - mgslpc_send_xchar(tty, START_CHAR(tty)); - } - - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->lock, flags); - info->serial_signals |= SerialSignal_RTS; - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - } -} - -/* get the current serial statistics - */ -static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("get_params(%s)\n", info->device_name); - if (!user_icount) { - memset(&info->icount, 0, sizeof(info->icount)); - } else { - COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) - return -EFAULT; - } - return 0; -} - -/* get the current serial parameters - */ -static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("get_params(%s)\n", info->device_name); - COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); - if (err) - return -EFAULT; - return 0; -} - -/* set the serial parameters - * - * Arguments: - * - * info pointer to device instance data - * new_params user buffer containing new serial params - * - * Returns: 0 if success, otherwise error code - */ -static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty) -{ - unsigned long flags; - MGSL_PARAMS tmp_params; - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):set_params %s\n", __FILE__,__LINE__, - info->device_name); - COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); - if (err) { - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):set_params(%s) user buffer copy failed\n", - __FILE__, __LINE__, info->device_name); - return -EFAULT; - } - - spin_lock_irqsave(&info->lock, flags); - memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); - spin_unlock_irqrestore(&info->lock, flags); - - mgslpc_change_params(info, tty); - - return 0; -} - -static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("get_txidle(%s)=%d\n", info->device_name, info->idle_mode); - COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); - if (err) - return -EFAULT; - return 0; -} - -static int set_txidle(MGSLPC_INFO * info, int idle_mode) -{ - unsigned long flags; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("set_txidle(%s,%d)\n", info->device_name, idle_mode); - spin_lock_irqsave(&info->lock, flags); - info->idle_mode = idle_mode; - tx_set_idle(info); - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int get_interface(MGSLPC_INFO * info, int __user *if_mode) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("get_interface(%s)=%d\n", info->device_name, info->if_mode); - COPY_TO_USER(err,if_mode, &info->if_mode, sizeof(int)); - if (err) - return -EFAULT; - return 0; -} - -static int set_interface(MGSLPC_INFO * info, int if_mode) -{ - unsigned long flags; - unsigned char val; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("set_interface(%s,%d)\n", info->device_name, if_mode); - spin_lock_irqsave(&info->lock, flags); - info->if_mode = if_mode; - - val = read_reg(info, PVR) & 0x0f; - switch (info->if_mode) - { - case MGSL_INTERFACE_RS232: val |= PVR_RS232; break; - case MGSL_INTERFACE_V35: val |= PVR_V35; break; - case MGSL_INTERFACE_RS422: val |= PVR_RS422; break; - } - write_reg(info, PVR, val); - - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("set_txenable(%s,%d)\n", info->device_name, enable); - - spin_lock_irqsave(&info->lock, flags); - if (enable) { - if (!info->tx_enabled) - tx_start(info, tty); - } else { - if (info->tx_enabled) - tx_stop(info); - } - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int tx_abort(MGSLPC_INFO * info) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("tx_abort(%s)\n", info->device_name); - - spin_lock_irqsave(&info->lock, flags); - if (info->tx_active && info->tx_count && - info->params.mode == MGSL_MODE_HDLC) { - /* clear data count so FIFO is not filled on next IRQ. - * This results in underrun and abort transmission. - */ - info->tx_count = info->tx_put = info->tx_get = 0; - info->tx_aborting = true; - } - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int set_rxenable(MGSLPC_INFO * info, int enable) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("set_rxenable(%s,%d)\n", info->device_name, enable); - - spin_lock_irqsave(&info->lock, flags); - if (enable) { - if (!info->rx_enabled) - rx_start(info); - } else { - if (info->rx_enabled) - rx_stop(info); - } - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -/* wait for specified event to occur - * - * Arguments: info pointer to device instance data - * mask pointer to bitmask of events to wait for - * Return Value: 0 if successful and bit mask updated with - * of events triggerred, - * otherwise error code - */ -static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) -{ - unsigned long flags; - int s; - int rc=0; - struct mgsl_icount cprev, cnow; - int events; - int mask; - struct _input_signal_events oldsigs, newsigs; - DECLARE_WAITQUEUE(wait, current); - - COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); - if (rc) - return -EFAULT; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("wait_events(%s,%d)\n", info->device_name, mask); - - spin_lock_irqsave(&info->lock, flags); - - /* return immediately if state matches requested events */ - get_signals(info); - s = info->serial_signals; - events = mask & - ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + - ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + - ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + - ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); - if (events) { - spin_unlock_irqrestore(&info->lock, flags); - goto exit; - } - - /* save current irq counts */ - cprev = info->icount; - oldsigs = info->input_signal_events; - - if ((info->params.mode == MGSL_MODE_HDLC) && - (mask & MgslEvent_ExitHuntMode)) - irq_enable(info, CHA, IRQ_EXITHUNT); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&info->event_wait_q, &wait); - - spin_unlock_irqrestore(&info->lock, flags); - - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get current irq counts */ - spin_lock_irqsave(&info->lock, flags); - cnow = info->icount; - newsigs = info->input_signal_events; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock, flags); - - /* if no change, wait aborted for some reason */ - if (newsigs.dsr_up == oldsigs.dsr_up && - newsigs.dsr_down == oldsigs.dsr_down && - newsigs.dcd_up == oldsigs.dcd_up && - newsigs.dcd_down == oldsigs.dcd_down && - newsigs.cts_up == oldsigs.cts_up && - newsigs.cts_down == oldsigs.cts_down && - newsigs.ri_up == oldsigs.ri_up && - newsigs.ri_down == oldsigs.ri_down && - cnow.exithunt == cprev.exithunt && - cnow.rxidle == cprev.rxidle) { - rc = -EIO; - break; - } - - events = mask & - ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + - (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + - (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + - (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + - (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + - (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + - (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + - (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + - (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + - (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); - if (events) - break; - - cprev = cnow; - oldsigs = newsigs; - } - - remove_wait_queue(&info->event_wait_q, &wait); - set_current_state(TASK_RUNNING); - - if (mask & MgslEvent_ExitHuntMode) { - spin_lock_irqsave(&info->lock, flags); - if (!waitqueue_active(&info->event_wait_q)) - irq_disable(info, CHA, IRQ_EXITHUNT); - spin_unlock_irqrestore(&info->lock, flags); - } -exit: - if (rc == 0) - PUT_USER(rc, events, mask_ptr); - return rc; -} - -static int modem_input_wait(MGSLPC_INFO *info,int arg) -{ - unsigned long flags; - int rc; - struct mgsl_icount cprev, cnow; - DECLARE_WAITQUEUE(wait, current); - - /* save current irq counts */ - spin_lock_irqsave(&info->lock, flags); - cprev = info->icount; - add_wait_queue(&info->status_event_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock, flags); - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get new irq counts */ - spin_lock_irqsave(&info->lock, flags); - cnow = info->icount; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock, flags); - - /* if no change, wait aborted for some reason */ - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - rc = -EIO; - break; - } - - /* check for change in caller specified modem input */ - if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || - (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || - (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || - (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { - rc = 0; - break; - } - - cprev = cnow; - } - remove_wait_queue(&info->status_event_wait_q, &wait); - set_current_state(TASK_RUNNING); - return rc; -} - -/* return the state of the serial control and status signals - */ -static int tiocmget(struct tty_struct *tty) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned int result; - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - - result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + - ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + - ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + - ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + - ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + - ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmget() value=%08X\n", - __FILE__, __LINE__, info->device_name, result); - return result; -} - -/* set modem control signals (DTR/RTS) - */ -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmset(%x,%x)\n", - __FILE__, __LINE__, info->device_name, set, clear); - - if (set & TIOCM_RTS) - info->serial_signals |= SerialSignal_RTS; - if (set & TIOCM_DTR) - info->serial_signals |= SerialSignal_DTR; - if (clear & TIOCM_RTS) - info->serial_signals &= ~SerialSignal_RTS; - if (clear & TIOCM_DTR) - info->serial_signals &= ~SerialSignal_DTR; - - spin_lock_irqsave(&info->lock, flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - - return 0; -} - -/* Set or clear transmit break condition - * - * Arguments: tty pointer to tty instance data - * break_state -1=set break condition, 0=clear - */ -static int mgslpc_break(struct tty_struct *tty, int break_state) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_break(%s,%d)\n", - __FILE__, __LINE__, info->device_name, break_state); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break")) - return -EINVAL; - - spin_lock_irqsave(&info->lock, flags); - if (break_state == -1) - set_reg_bits(info, CHA+DAFO, BIT6); - else - clear_reg_bits(info, CHA+DAFO, BIT6); - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int mgslpc_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - struct mgsl_icount cnow; /* kernel counter temps */ - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->lock, flags); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - -/* Service an IOCTL request - * - * Arguments: - * - * tty pointer to tty instance data - * cmd IOCTL command code - * arg command argument/context - * - * Return Value: 0 if success, otherwise error code - */ -static int mgslpc_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - void __user *argp = (void __user *)arg; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__, __LINE__, - info->device_name, cmd); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty_io_error(tty)) - return -EIO; - } - - switch (cmd) { - case MGSL_IOCGPARAMS: - return get_params(info, argp); - case MGSL_IOCSPARAMS: - return set_params(info, argp, tty); - case MGSL_IOCGTXIDLE: - return get_txidle(info, argp); - case MGSL_IOCSTXIDLE: - return set_txidle(info, (int)arg); - case MGSL_IOCGIF: - return get_interface(info, argp); - case MGSL_IOCSIF: - return set_interface(info,(int)arg); - case MGSL_IOCTXENABLE: - return set_txenable(info,(int)arg, tty); - case MGSL_IOCRXENABLE: - return set_rxenable(info,(int)arg); - case MGSL_IOCTXABORT: - return tx_abort(info); - case MGSL_IOCGSTATS: - return get_stats(info, argp); - case MGSL_IOCWAITEVENT: - return wait_events(info, argp); - case TIOCMIWAIT: - return modem_input_wait(info,(int)arg); - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* Set new termios settings - * - * Arguments: - * - * tty pointer to tty structure - * termios pointer to buffer to hold returned old termios - */ -static void mgslpc_set_termios(struct tty_struct *tty, - const struct ktermios *old_termios) -{ - MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_set_termios %s\n", __FILE__, __LINE__, - tty->driver->name); - - /* just return if nothing has changed */ - if ((tty->termios.c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios.c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - mgslpc_change_params(info, tty); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - spin_lock_irqsave(&info->lock, flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) - info->serial_signals |= SerialSignal_RTS; - spin_lock_irqsave(&info->lock, flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - } - - /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - tx_release(tty); - } -} - -static void mgslpc_close(struct tty_struct *tty, struct file * filp) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - struct tty_port *port = &info->port; - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", - __FILE__, __LINE__, info->device_name, port->count); - - if (tty_port_close_start(port, tty, filp) == 0) - goto cleanup; - - if (tty_port_initialized(port)) - mgslpc_wait_until_sent(tty, info->timeout); - - mgslpc_flush_buffer(tty); - - tty_ldisc_flush(tty); - shutdown(info, tty); - - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__, - tty->driver->name, port->count); -} - -/* Wait until the transmitter is empty. - */ -static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - unsigned long orig_jiffies, char_time; - - if (!info) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent")) - return; - - if (!tty_port_initialized(&info->port)) - goto exit; - - orig_jiffies = jiffies; - - /* Set check interval to 1/5 of estimated time to - * send a character, and make it at least 1. The check - * interval should also be less than the timeout. - * Note: use tight timings here to satisfy the NIST-PCTS. - */ - - if (info->params.data_rate) { - char_time = info->timeout/(32 * 5); - if (!char_time) - char_time++; - } else - char_time = 1; - - if (timeout) - char_time = min_t(unsigned long, char_time, timeout); - - if (info->params.mode == MGSL_MODE_HDLC) { - while (info->tx_active) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } else { - while ((info->tx_count || info->tx_active) && - info->tx_enabled) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } - -exit: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n", - __FILE__, __LINE__, info->device_name); -} - -/* Called by tty_hangup() when a hangup is signaled. - * This is the same as closing all open files for the port. - */ -static void mgslpc_hangup(struct tty_struct *tty) -{ - MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_hangup(%s)\n", - __FILE__, __LINE__, info->device_name); - - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup")) - return; - - mgslpc_flush_buffer(tty); - shutdown(info, tty); - tty_port_hangup(&info->port); -} - -static bool carrier_raised(struct tty_port *port) -{ - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - - return info->serial_signals & SerialSignal_DCD; -} - -static void dtr_rts(struct tty_port *port, bool active) -{ - MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - if (active) - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); - spin_unlock_irqrestore(&info->lock, flags); -} - - -static int mgslpc_open(struct tty_struct *tty, struct file * filp) -{ - MGSLPC_INFO *info; - struct tty_port *port; - int retval, line; - unsigned long flags; - - /* verify range of specified line number */ - line = tty->index; - if (line >= mgslpc_device_count) { - printk("%s(%d):mgslpc_open with invalid line #%d.\n", - __FILE__, __LINE__, line); - return -ENODEV; - } - - /* find the info structure for the specified line */ - info = mgslpc_device_list; - while(info && info->line != line) - info = info->next_device; - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) - return -ENODEV; - - port = &info->port; - tty->driver_data = info; - tty_port_tty_set(port, tty); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", - __FILE__, __LINE__, tty->driver->name, port->count); - - spin_lock_irqsave(&info->netlock, flags); - if (info->netcount) { - retval = -EBUSY; - spin_unlock_irqrestore(&info->netlock, flags); - goto cleanup; - } - spin_lock(&port->lock); - port->count++; - spin_unlock(&port->lock); - spin_unlock_irqrestore(&info->netlock, flags); - - if (port->count == 1) { - /* 1st open on this device, init hardware */ - retval = startup(info, tty); - if (retval < 0) - goto cleanup; - } - - retval = tty_port_block_til_ready(&info->port, tty, filp); - if (retval) { - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready(%s) returned %d\n", - __FILE__, __LINE__, info->device_name, retval); - goto cleanup; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_open(%s) success\n", - __FILE__, __LINE__, info->device_name); - retval = 0; - -cleanup: - return retval; -} - -/* - * /proc fs routines.... - */ - -static inline void line_info(struct seq_file *m, MGSLPC_INFO *info) -{ - char stat_buf[30]; - unsigned long flags; - - seq_printf(m, "%s:io:%04X irq:%d", - info->device_name, info->io_base, info->irq_level); - - /* output current serial signal states */ - spin_lock_irqsave(&info->lock, flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (info->serial_signals & SerialSignal_RTS) - strcat(stat_buf, "|RTS"); - if (info->serial_signals & SerialSignal_CTS) - strcat(stat_buf, "|CTS"); - if (info->serial_signals & SerialSignal_DTR) - strcat(stat_buf, "|DTR"); - if (info->serial_signals & SerialSignal_DSR) - strcat(stat_buf, "|DSR"); - if (info->serial_signals & SerialSignal_DCD) - strcat(stat_buf, "|CD"); - if (info->serial_signals & SerialSignal_RI) - strcat(stat_buf, "|RI"); - - if (info->params.mode == MGSL_MODE_HDLC) { - seq_printf(m, " HDLC txok:%d rxok:%d", - info->icount.txok, info->icount.rxok); - if (info->icount.txunder) - seq_printf(m, " txunder:%d", info->icount.txunder); - if (info->icount.txabort) - seq_printf(m, " txabort:%d", info->icount.txabort); - if (info->icount.rxshort) - seq_printf(m, " rxshort:%d", info->icount.rxshort); - if (info->icount.rxlong) - seq_printf(m, " rxlong:%d", info->icount.rxlong); - if (info->icount.rxover) - seq_printf(m, " rxover:%d", info->icount.rxover); - if (info->icount.rxcrc) - seq_printf(m, " rxcrc:%d", info->icount.rxcrc); - } else { - seq_printf(m, " ASYNC tx:%d rx:%d", - info->icount.tx, info->icount.rx); - if (info->icount.frame) - seq_printf(m, " fe:%d", info->icount.frame); - if (info->icount.parity) - seq_printf(m, " pe:%d", info->icount.parity); - if (info->icount.brk) - seq_printf(m, " brk:%d", info->icount.brk); - if (info->icount.overrun) - seq_printf(m, " oe:%d", info->icount.overrun); - } - - /* Append serial signal status to end */ - seq_printf(m, " %s\n", stat_buf+1); - - seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", - info->tx_active,info->bh_requested,info->bh_running, - info->pending_bh); -} - -/* Called to print information about devices - */ -static int mgslpc_proc_show(struct seq_file *m, void *v) -{ - MGSLPC_INFO *info; - - seq_printf(m, "synclink driver:%s\n", driver_version); - - info = mgslpc_device_list; - while (info) { - line_info(m, info); - info = info->next_device; - } - return 0; -} - -static int rx_alloc_buffers(MGSLPC_INFO *info) -{ - /* each buffer has header and data */ - info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size; - - /* calculate total allocation size for 8 buffers */ - info->rx_buf_total_size = info->rx_buf_size * 8; - - /* limit total allocated memory */ - if (info->rx_buf_total_size > 0x10000) - info->rx_buf_total_size = 0x10000; - - /* calculate number of buffers */ - info->rx_buf_count = info->rx_buf_total_size / info->rx_buf_size; - - info->rx_buf = kmalloc(info->rx_buf_total_size, GFP_KERNEL); - if (info->rx_buf == NULL) - return -ENOMEM; - - /* unused flag buffer to satisfy receive_buf calling interface */ - info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL); - if (!info->flag_buf) { - kfree(info->rx_buf); - info->rx_buf = NULL; - return -ENOMEM; - } - - rx_reset_buffers(info); - return 0; -} - -static void rx_free_buffers(MGSLPC_INFO *info) -{ - kfree(info->rx_buf); - info->rx_buf = NULL; - kfree(info->flag_buf); - info->flag_buf = NULL; -} - -static int claim_resources(MGSLPC_INFO *info) -{ - if (rx_alloc_buffers(info) < 0) { - printk("Can't allocate rx buffer %s\n", info->device_name); - release_resources(info); - return -ENODEV; - } - return 0; -} - -static void release_resources(MGSLPC_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_INFO) - printk("release_resources(%s)\n", info->device_name); - rx_free_buffers(info); -} - -/* Add the specified device instance data structure to the - * global linked list of devices and increment the device count. - * - * Arguments: info pointer to device instance data - */ -static int mgslpc_add_device(MGSLPC_INFO *info) -{ - MGSLPC_INFO *current_dev = NULL; - struct device *tty_dev; - int ret; - - info->next_device = NULL; - info->line = mgslpc_device_count; - sprintf(info->device_name,"ttySLP%d",info->line); - - if (info->line < MAX_DEVICE_COUNT) { - if (maxframe[info->line]) - info->max_frame_size = maxframe[info->line]; - } - - mgslpc_device_count++; - - if (!mgslpc_device_list) - mgslpc_device_list = info; - else { - current_dev = mgslpc_device_list; - while (current_dev->next_device) - current_dev = current_dev->next_device; - current_dev->next_device = info; - } - - if (info->max_frame_size < 4096) - info->max_frame_size = 4096; - else if (info->max_frame_size > 65535) - info->max_frame_size = 65535; - - printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n", - info->device_name, info->io_base, info->irq_level); - -#if SYNCLINK_GENERIC_HDLC - ret = hdlcdev_init(info); - if (ret != 0) - goto failed; -#endif - - tty_dev = tty_port_register_device(&info->port, serial_driver, info->line, - &info->p_dev->dev); - if (IS_ERR(tty_dev)) { - ret = PTR_ERR(tty_dev); -#if SYNCLINK_GENERIC_HDLC - hdlcdev_exit(info); -#endif - goto failed; - } - - return 0; - -failed: - if (current_dev) - current_dev->next_device = NULL; - else - mgslpc_device_list = NULL; - mgslpc_device_count--; - return ret; -} - -static void mgslpc_remove_device(MGSLPC_INFO *remove_info) -{ - MGSLPC_INFO *info = mgslpc_device_list; - MGSLPC_INFO *last = NULL; - - while(info) { - if (info == remove_info) { - if (last) - last->next_device = info->next_device; - else - mgslpc_device_list = info->next_device; - tty_unregister_device(serial_driver, info->line); -#if SYNCLINK_GENERIC_HDLC - hdlcdev_exit(info); -#endif - release_resources(info); - tty_port_destroy(&info->port); - kfree(info); - mgslpc_device_count--; - return; - } - last = info; - info = info->next_device; - } -} - -static const struct pcmcia_device_id mgslpc_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); - -static struct pcmcia_driver mgslpc_driver = { - .owner = THIS_MODULE, - .name = "synclink_cs", - .probe = mgslpc_probe, - .remove = mgslpc_detach, - .id_table = mgslpc_ids, - .suspend = mgslpc_suspend, - .resume = mgslpc_resume, -}; - -static const struct tty_operations mgslpc_ops = { - .open = mgslpc_open, - .close = mgslpc_close, - .write = mgslpc_write, - .put_char = mgslpc_put_char, - .flush_chars = mgslpc_flush_chars, - .write_room = mgslpc_write_room, - .chars_in_buffer = mgslpc_chars_in_buffer, - .flush_buffer = mgslpc_flush_buffer, - .ioctl = mgslpc_ioctl, - .throttle = mgslpc_throttle, - .unthrottle = mgslpc_unthrottle, - .send_xchar = mgslpc_send_xchar, - .break_ctl = mgslpc_break, - .wait_until_sent = mgslpc_wait_until_sent, - .set_termios = mgslpc_set_termios, - .stop = tx_pause, - .start = tx_release, - .hangup = mgslpc_hangup, - .tiocmget = tiocmget, - .tiocmset = tiocmset, - .get_icount = mgslpc_get_icount, - .proc_show = mgslpc_proc_show, -}; - -static int __init synclink_cs_init(void) -{ - int rc; - - if (break_on_load) { - mgslpc_get_text_ptr(); - BREAKPOINT(); - } - - serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(serial_driver)) { - rc = PTR_ERR(serial_driver); - goto err; - } - - /* Initialize the tty_driver structure */ - serial_driver->driver_name = "synclink_cs"; - serial_driver->name = "ttySLP"; - serial_driver->major = ttymajor; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(serial_driver, &mgslpc_ops); - - rc = tty_register_driver(serial_driver); - if (rc < 0) { - printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", - __FILE__, __LINE__); - goto err_put_tty; - } - - rc = pcmcia_register_driver(&mgslpc_driver); - if (rc < 0) - goto err_unreg_tty; - - printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, - serial_driver->major); - - return 0; -err_unreg_tty: - tty_unregister_driver(serial_driver); -err_put_tty: - tty_driver_kref_put(serial_driver); -err: - return rc; -} - -static void __exit synclink_cs_exit(void) -{ - pcmcia_unregister_driver(&mgslpc_driver); - tty_unregister_driver(serial_driver); - tty_driver_kref_put(serial_driver); -} - -module_init(synclink_cs_init); -module_exit(synclink_cs_exit); - -static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) -{ - unsigned int M, N; - unsigned char val; - - /* note:standard BRG mode is broken in V3.2 chip - * so enhanced mode is always used - */ - - if (rate) { - N = 3686400 / rate; - if (!N) - N = 1; - N >>= 1; - for (M = 1; N > 64 && M < 16; M++) - N >>= 1; - N--; - - /* BGR[5..0] = N - * BGR[9..6] = M - * BGR[7..0] contained in BGR register - * BGR[9..8] contained in CCR2[7..6] - * divisor = (N+1)*2^M - * - * Note: M *must* not be zero (causes asymetric duty cycle) - */ - write_reg(info, (unsigned char) (channel + BGR), - (unsigned char) ((M << 6) + N)); - val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f; - val |= ((M << 4) & 0xc0); - write_reg(info, (unsigned char) (channel + CCR2), val); - } -} - -/* Enabled the AUX clock output at the specified frequency. - */ -static void enable_auxclk(MGSLPC_INFO *info) -{ - unsigned char val; - - /* MODE - * - * 07..06 MDS[1..0] 10 = transparent HDLC mode - * 05 ADM Address Mode, 0 = no addr recognition - * 04 TMD Timer Mode, 0 = external - * 03 RAC Receiver Active, 0 = inactive - * 02 RTS 0=RTS active during xmit, 1=RTS always active - * 01 TRS Timer Resolution, 1=512 - * 00 TLP Test Loop, 0 = no loop - * - * 1000 0010 - */ - val = 0x82; - - /* channel B RTS is used to enable AUXCLK driver on SP505 */ - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) - val |= BIT2; - write_reg(info, CHB + MODE, val); - - /* CCR0 - * - * 07 PU Power Up, 1=active, 0=power down - * 06 MCE Master Clock Enable, 1=enabled - * 05 Reserved, 0 - * 04..02 SC[2..0] Encoding - * 01..00 SM[1..0] Serial Mode, 00=HDLC - * - * 11000000 - */ - write_reg(info, CHB + CCR0, 0xc0); - - /* CCR1 - * - * 07 SFLG Shared Flag, 0 = disable shared flags - * 06 GALP Go Active On Loop, 0 = not used - * 05 GLP Go On Loop, 0 = not used - * 04 ODS Output Driver Select, 1=TxD is push-pull output - * 03 ITF Interframe Time Fill, 0=mark, 1=flag - * 02..00 CM[2..0] Clock Mode - * - * 0001 0111 - */ - write_reg(info, CHB + CCR1, 0x17); - - /* CCR2 (Channel B) - * - * 07..06 BGR[9..8] Baud rate bits 9..8 - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value - * 04 SSEL Clock source select, 1=submode b - * 03 TOE 0=TxCLK is input, 1=TxCLK is output - * 02 RWX Read/Write Exchange 0=disabled - * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 - * 00 DIV, data inversion 0=disabled, 1=enabled - * - * 0011 1000 - */ - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) - write_reg(info, CHB + CCR2, 0x38); - else - write_reg(info, CHB + CCR2, 0x30); - - /* CCR4 - * - * 07 MCK4 Master Clock Divide by 4, 1=enabled - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled - * 05 TST1 Test Pin, 0=normal operation - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) - * 03..02 Reserved, must be 0 - * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes - * - * 0101 0000 - */ - write_reg(info, CHB + CCR4, 0x50); - - /* if auxclk not enabled, set internal BRG so - * CTS transitions can be detected (requires TxC) - */ - if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed) - mgslpc_set_rate(info, CHB, info->params.clock_speed); - else - mgslpc_set_rate(info, CHB, 921600); -} - -static void loopback_enable(MGSLPC_INFO *info) -{ - unsigned char val; - - /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */ - val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0); - write_reg(info, CHA + CCR1, val); - - /* CCR2:04 SSEL Clock source select, 1=submode b */ - val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5); - write_reg(info, CHA + CCR2, val); - - /* set LinkSpeed if available, otherwise default to 2Mbps */ - if (info->params.clock_speed) - mgslpc_set_rate(info, CHA, info->params.clock_speed); - else - mgslpc_set_rate(info, CHA, 1843200); - - /* MODE:00 TLP Test Loop, 1=loopback enabled */ - val = read_reg(info, CHA + MODE) | BIT0; - write_reg(info, CHA + MODE, val); -} - -static void hdlc_mode(MGSLPC_INFO *info) -{ - unsigned char val; - unsigned char clkmode, clksubmode; - - /* disable all interrupts */ - irq_disable(info, CHA, 0xffff); - irq_disable(info, CHB, 0xffff); - port_irq_disable(info, 0xff); - - /* assume clock mode 0a, rcv=RxC xmt=TxC */ - clkmode = clksubmode = 0; - if (info->params.flags & HDLC_FLAG_RXC_DPLL - && info->params.flags & HDLC_FLAG_TXC_DPLL) { - /* clock mode 7a, rcv = DPLL, xmt = DPLL */ - clkmode = 7; - } else if (info->params.flags & HDLC_FLAG_RXC_BRG - && info->params.flags & HDLC_FLAG_TXC_BRG) { - /* clock mode 7b, rcv = BRG, xmt = BRG */ - clkmode = 7; - clksubmode = 1; - } else if (info->params.flags & HDLC_FLAG_RXC_DPLL) { - if (info->params.flags & HDLC_FLAG_TXC_BRG) { - /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */ - clkmode = 6; - clksubmode = 1; - } else { - /* clock mode 6a, rcv = DPLL, xmt = TxC */ - clkmode = 6; - } - } else if (info->params.flags & HDLC_FLAG_TXC_BRG) { - /* clock mode 0b, rcv = RxC, xmt = BRG */ - clksubmode = 1; - } - - /* MODE - * - * 07..06 MDS[1..0] 10 = transparent HDLC mode - * 05 ADM Address Mode, 0 = no addr recognition - * 04 TMD Timer Mode, 0 = external - * 03 RAC Receiver Active, 0 = inactive - * 02 RTS 0=RTS active during xmit, 1=RTS always active - * 01 TRS Timer Resolution, 1=512 - * 00 TLP Test Loop, 0 = no loop - * - * 1000 0010 - */ - val = 0x82; - if (info->params.loopback) - val |= BIT0; - - /* preserve RTS state */ - if (info->serial_signals & SerialSignal_RTS) - val |= BIT2; - write_reg(info, CHA + MODE, val); - - /* CCR0 - * - * 07 PU Power Up, 1=active, 0=power down - * 06 MCE Master Clock Enable, 1=enabled - * 05 Reserved, 0 - * 04..02 SC[2..0] Encoding - * 01..00 SM[1..0] Serial Mode, 00=HDLC - * - * 11000000 - */ - val = 0xc0; - switch (info->params.encoding) - { - case HDLC_ENCODING_NRZI: - val |= BIT3; - break; - case HDLC_ENCODING_BIPHASE_SPACE: - val |= BIT4; - break; // FM0 - case HDLC_ENCODING_BIPHASE_MARK: - val |= BIT4 | BIT2; - break; // FM1 - case HDLC_ENCODING_BIPHASE_LEVEL: - val |= BIT4 | BIT3; - break; // Manchester - } - write_reg(info, CHA + CCR0, val); - - /* CCR1 - * - * 07 SFLG Shared Flag, 0 = disable shared flags - * 06 GALP Go Active On Loop, 0 = not used - * 05 GLP Go On Loop, 0 = not used - * 04 ODS Output Driver Select, 1=TxD is push-pull output - * 03 ITF Interframe Time Fill, 0=mark, 1=flag - * 02..00 CM[2..0] Clock Mode - * - * 0001 0000 - */ - val = 0x10 + clkmode; - write_reg(info, CHA + CCR1, val); - - /* CCR2 - * - * 07..06 BGR[9..8] Baud rate bits 9..8 - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value - * 04 SSEL Clock source select, 1=submode b - * 03 TOE 0=TxCLK is input, 0=TxCLK is input - * 02 RWX Read/Write Exchange 0=disabled - * 01 C32, CRC select, 0=CRC-16, 1=CRC-32 - * 00 DIV, data inversion 0=disabled, 1=enabled - * - * 0000 0000 - */ - val = 0x00; - if (clkmode == 2 || clkmode == 3 || clkmode == 6 - || clkmode == 7 || (clkmode == 0 && clksubmode == 1)) - val |= BIT5; - if (clksubmode) - val |= BIT4; - if (info->params.crc_type == HDLC_CRC_32_CCITT) - val |= BIT1; - if (info->params.encoding == HDLC_ENCODING_NRZB) - val |= BIT0; - write_reg(info, CHA + CCR2, val); - - /* CCR3 - * - * 07..06 PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8 - * 05 EPT Enable preamble transmission, 1=enabled - * 04 RADD Receive address pushed to FIFO, 0=disabled - * 03 CRL CRC Reset Level, 0=FFFF - * 02 RCRC Rx CRC 0=On 1=Off - * 01 TCRC Tx CRC 0=On 1=Off - * 00 PSD DPLL Phase Shift Disable - * - * 0000 0000 - */ - val = 0x00; - if (info->params.crc_type == HDLC_CRC_NONE) - val |= BIT2 | BIT1; - if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) - val |= BIT5; - switch (info->params.preamble_length) - { - case HDLC_PREAMBLE_LENGTH_16BITS: - val |= BIT6; - break; - case HDLC_PREAMBLE_LENGTH_32BITS: - val |= BIT6; - break; - case HDLC_PREAMBLE_LENGTH_64BITS: - val |= BIT7 | BIT6; - break; - } - write_reg(info, CHA + CCR3, val); - - /* PRE - Preamble pattern */ - val = 0; - switch (info->params.preamble) - { - case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; - case HDLC_PREAMBLE_PATTERN_10: val = 0xaa; break; - case HDLC_PREAMBLE_PATTERN_01: val = 0x55; break; - case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; - } - write_reg(info, CHA + PRE, val); - - /* CCR4 - * - * 07 MCK4 Master Clock Divide by 4, 1=enabled - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled - * 05 TST1 Test Pin, 0=normal operation - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) - * 03..02 Reserved, must be 0 - * 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes - * - * 0101 0000 - */ - val = 0x50; - write_reg(info, CHA + CCR4, val); - if (info->params.flags & HDLC_FLAG_RXC_DPLL) - mgslpc_set_rate(info, CHA, info->params.clock_speed * 16); - else - mgslpc_set_rate(info, CHA, info->params.clock_speed); - - /* RLCR Receive length check register - * - * 7 1=enable receive length check - * 6..0 Max frame length = (RL + 1) * 32 - */ - write_reg(info, CHA + RLCR, 0); - - /* XBCH Transmit Byte Count High - * - * 07 DMA mode, 0 = interrupt driven - * 06 NRM, 0=ABM (ignored) - * 05 CAS Carrier Auto Start - * 04 XC Transmit Continuously (ignored) - * 03..00 XBC[10..8] Transmit byte count bits 10..8 - * - * 0000 0000 - */ - val = 0x00; - if (info->params.flags & HDLC_FLAG_AUTO_DCD) - val |= BIT5; - write_reg(info, CHA + XBCH, val); - enable_auxclk(info); - if (info->params.loopback || info->testing_irq) - loopback_enable(info); - if (info->params.flags & HDLC_FLAG_AUTO_CTS) - { - irq_enable(info, CHB, IRQ_CTS); - /* PVR[3] 1=AUTO CTS active */ - set_reg_bits(info, CHA + PVR, BIT3); - } else - clear_reg_bits(info, CHA + PVR, BIT3); - - irq_enable(info, CHA, - IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT | - IRQ_UNDERRUN | IRQ_TXFIFO); - issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); - wait_command_complete(info, CHA); - read_reg16(info, CHA + ISR); /* clear pending IRQs */ - - /* Master clock mode enabled above to allow reset commands - * to complete even if no data clocks are present. - * - * Disable master clock mode for normal communications because - * V3.2 of the ESCC2 has a bug that prevents the transmit all sent - * IRQ when in master clock mode. - * - * Leave master clock mode enabled for IRQ test because the - * timer IRQ used by the test can only happen in master clock mode. - */ - if (!info->testing_irq) - clear_reg_bits(info, CHA + CCR0, BIT6); - - tx_set_idle(info); - - tx_stop(info); - rx_stop(info); -} - -static void rx_stop(MGSLPC_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):rx_stop(%s)\n", - __FILE__, __LINE__, info->device_name); - - /* MODE:03 RAC Receiver Active, 0=inactive */ - clear_reg_bits(info, CHA + MODE, BIT3); - - info->rx_enabled = false; - info->rx_overflow = false; -} - -static void rx_start(MGSLPC_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):rx_start(%s)\n", - __FILE__, __LINE__, info->device_name); - - rx_reset_buffers(info); - info->rx_enabled = false; - info->rx_overflow = false; - - /* MODE:03 RAC Receiver Active, 1=active */ - set_reg_bits(info, CHA + MODE, BIT3); - - info->rx_enabled = true; -} - -static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):tx_start(%s)\n", - __FILE__, __LINE__, info->device_name); - - if (info->tx_count) { - /* If auto RTS enabled and RTS is inactive, then assert */ - /* RTS and set a flag indicating that the driver should */ - /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = false; - - if (info->params.flags & HDLC_FLAG_AUTO_RTS) { - get_signals(info); - if (!(info->serial_signals & SerialSignal_RTS)) { - info->serial_signals |= SerialSignal_RTS; - set_signals(info); - info->drop_rts_on_tx_done = true; - } - } - - if (info->params.mode == MGSL_MODE_ASYNC) { - if (!info->tx_active) { - info->tx_active = true; - tx_ready(info, tty); - } - } else { - info->tx_active = true; - tx_ready(info, tty); - mod_timer(&info->tx_timer, jiffies + - msecs_to_jiffies(5000)); - } - } - - if (!info->tx_enabled) - info->tx_enabled = true; -} - -static void tx_stop(MGSLPC_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):tx_stop(%s)\n", - __FILE__, __LINE__, info->device_name); - - del_timer(&info->tx_timer); - - info->tx_enabled = false; - info->tx_active = false; -} - -/* Reset the adapter to a known state and prepare it for further use. - */ -static void reset_device(MGSLPC_INFO *info) -{ - /* power up both channels (set BIT7) */ - write_reg(info, CHA + CCR0, 0x80); - write_reg(info, CHB + CCR0, 0x80); - write_reg(info, CHA + MODE, 0); - write_reg(info, CHB + MODE, 0); - - /* disable all interrupts */ - irq_disable(info, CHA, 0xffff); - irq_disable(info, CHB, 0xffff); - port_irq_disable(info, 0xff); - - /* PCR Port Configuration Register - * - * 07..04 DEC[3..0] Serial I/F select outputs - * 03 output, 1=AUTO CTS control enabled - * 02 RI Ring Indicator input 0=active - * 01 DSR input 0=active - * 00 DTR output 0=active - * - * 0000 0110 - */ - write_reg(info, PCR, 0x06); - - /* PVR Port Value Register - * - * 07..04 DEC[3..0] Serial I/F select (0000=disabled) - * 03 AUTO CTS output 1=enabled - * 02 RI Ring Indicator input - * 01 DSR input - * 00 DTR output (1=inactive) - * - * 0000 0001 - */ -// write_reg(info, PVR, PVR_DTR); - - /* IPC Interrupt Port Configuration - * - * 07 VIS 1=Masked interrupts visible - * 06..05 Reserved, 0 - * 04..03 SLA Slave address, 00 ignored - * 02 CASM Cascading Mode, 1=daisy chain - * 01..00 IC[1..0] Interrupt Config, 01=push-pull output, active low - * - * 0000 0101 - */ - write_reg(info, IPC, 0x05); -} - -static void async_mode(MGSLPC_INFO *info) -{ - unsigned char val; - - /* disable all interrupts */ - irq_disable(info, CHA, 0xffff); - irq_disable(info, CHB, 0xffff); - port_irq_disable(info, 0xff); - - /* MODE - * - * 07 Reserved, 0 - * 06 FRTS RTS State, 0=active - * 05 FCTS Flow Control on CTS - * 04 FLON Flow Control Enable - * 03 RAC Receiver Active, 0 = inactive - * 02 RTS 0=Auto RTS, 1=manual RTS - * 01 TRS Timer Resolution, 1=512 - * 00 TLP Test Loop, 0 = no loop - * - * 0000 0110 - */ - val = 0x06; - if (info->params.loopback) - val |= BIT0; - - /* preserve RTS state */ - if (!(info->serial_signals & SerialSignal_RTS)) - val |= BIT6; - write_reg(info, CHA + MODE, val); - - /* CCR0 - * - * 07 PU Power Up, 1=active, 0=power down - * 06 MCE Master Clock Enable, 1=enabled - * 05 Reserved, 0 - * 04..02 SC[2..0] Encoding, 000=NRZ - * 01..00 SM[1..0] Serial Mode, 11=Async - * - * 1000 0011 - */ - write_reg(info, CHA + CCR0, 0x83); - - /* CCR1 - * - * 07..05 Reserved, 0 - * 04 ODS Output Driver Select, 1=TxD is push-pull output - * 03 BCR Bit Clock Rate, 1=16x - * 02..00 CM[2..0] Clock Mode, 111=BRG - * - * 0001 1111 - */ - write_reg(info, CHA + CCR1, 0x1f); - - /* CCR2 (channel A) - * - * 07..06 BGR[9..8] Baud rate bits 9..8 - * 05 BDF Baud rate divisor factor, 0=1, 1=BGR value - * 04 SSEL Clock source select, 1=submode b - * 03 TOE 0=TxCLK is input, 0=TxCLK is input - * 02 RWX Read/Write Exchange 0=disabled - * 01 Reserved, 0 - * 00 DIV, data inversion 0=disabled, 1=enabled - * - * 0001 0000 - */ - write_reg(info, CHA + CCR2, 0x10); - - /* CCR3 - * - * 07..01 Reserved, 0 - * 00 PSD DPLL Phase Shift Disable - * - * 0000 0000 - */ - write_reg(info, CHA + CCR3, 0); - - /* CCR4 - * - * 07 MCK4 Master Clock Divide by 4, 1=enabled - * 06 EBRG Enhanced Baud Rate Generator Mode, 1=enabled - * 05 TST1 Test Pin, 0=normal operation - * 04 ICD Ivert Carrier Detect, 1=enabled (active low) - * 03..00 Reserved, must be 0 - * - * 0101 0000 - */ - write_reg(info, CHA + CCR4, 0x50); - mgslpc_set_rate(info, CHA, info->params.data_rate * 16); - - /* DAFO Data Format - * - * 07 Reserved, 0 - * 06 XBRK transmit break, 0=normal operation - * 05 Stop bits (0=1, 1=2) - * 04..03 PAR[1..0] Parity (01=odd, 10=even) - * 02 PAREN Parity Enable - * 01..00 CHL[1..0] Character Length (00=8, 01=7) - * - */ - val = 0x00; - if (info->params.data_bits != 8) - val |= BIT0; /* 7 bits */ - if (info->params.stop_bits != 1) - val |= BIT5; - if (info->params.parity != ASYNC_PARITY_NONE) - { - val |= BIT2; /* Parity enable */ - if (info->params.parity == ASYNC_PARITY_ODD) - val |= BIT3; - else - val |= BIT4; - } - write_reg(info, CHA + DAFO, val); - - /* RFC Rx FIFO Control - * - * 07 Reserved, 0 - * 06 DPS, 1=parity bit not stored in data byte - * 05 DXS, 0=all data stored in FIFO (including XON/XOFF) - * 04 RFDF Rx FIFO Data Format, 1=status byte stored in FIFO - * 03..02 RFTH[1..0], rx threshold, 11=16 status + 16 data byte - * 01 Reserved, 0 - * 00 TCDE Terminate Char Detect Enable, 0=disabled - * - * 0101 1100 - */ - write_reg(info, CHA + RFC, 0x5c); - - /* RLCR Receive length check register - * - * Max frame length = (RL + 1) * 32 - */ - write_reg(info, CHA + RLCR, 0); - - /* XBCH Transmit Byte Count High - * - * 07 DMA mode, 0 = interrupt driven - * 06 NRM, 0=ABM (ignored) - * 05 CAS Carrier Auto Start - * 04 XC Transmit Continuously (ignored) - * 03..00 XBC[10..8] Transmit byte count bits 10..8 - * - * 0000 0000 - */ - val = 0x00; - if (info->params.flags & HDLC_FLAG_AUTO_DCD) - val |= BIT5; - write_reg(info, CHA + XBCH, val); - if (info->params.flags & HDLC_FLAG_AUTO_CTS) - irq_enable(info, CHA, IRQ_CTS); - - /* MODE:03 RAC Receiver Active, 1=active */ - set_reg_bits(info, CHA + MODE, BIT3); - enable_auxclk(info); - if (info->params.flags & HDLC_FLAG_AUTO_CTS) { - irq_enable(info, CHB, IRQ_CTS); - /* PVR[3] 1=AUTO CTS active */ - set_reg_bits(info, CHA + PVR, BIT3); - } else - clear_reg_bits(info, CHA + PVR, BIT3); - irq_enable(info, CHA, - IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME | - IRQ_ALLSENT | IRQ_TXFIFO); - issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); - wait_command_complete(info, CHA); - read_reg16(info, CHA + ISR); /* clear pending IRQs */ -} - -/* Set the HDLC idle mode for the transmitter. - */ -static void tx_set_idle(MGSLPC_INFO *info) -{ - /* Note: ESCC2 only supports flags and one idle modes */ - if (info->idle_mode == HDLC_TXIDLE_FLAGS) - set_reg_bits(info, CHA + CCR1, BIT3); - else - clear_reg_bits(info, CHA + CCR1, BIT3); -} - -/* get state of the V24 status (input) signals. - */ -static void get_signals(MGSLPC_INFO *info) -{ - unsigned char status = 0; - - /* preserve RTS and DTR */ - info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR; - - if (read_reg(info, CHB + VSTR) & BIT7) - info->serial_signals |= SerialSignal_DCD; - if (read_reg(info, CHB + STAR) & BIT1) - info->serial_signals |= SerialSignal_CTS; - - status = read_reg(info, CHA + PVR); - if (!(status & PVR_RI)) - info->serial_signals |= SerialSignal_RI; - if (!(status & PVR_DSR)) - info->serial_signals |= SerialSignal_DSR; -} - -/* Set the state of RTS and DTR based on contents of - * serial_signals member of device extension. - */ -static void set_signals(MGSLPC_INFO *info) -{ - unsigned char val; - - val = read_reg(info, CHA + MODE); - if (info->params.mode == MGSL_MODE_ASYNC) { - if (info->serial_signals & SerialSignal_RTS) - val &= ~BIT6; - else - val |= BIT6; - } else { - if (info->serial_signals & SerialSignal_RTS) - val |= BIT2; - else - val &= ~BIT2; - } - write_reg(info, CHA + MODE, val); - - if (info->serial_signals & SerialSignal_DTR) - clear_reg_bits(info, CHA + PVR, PVR_DTR); - else - set_reg_bits(info, CHA + PVR, PVR_DTR); -} - -static void rx_reset_buffers(MGSLPC_INFO *info) -{ - RXBUF *buf; - int i; - - info->rx_put = 0; - info->rx_get = 0; - info->rx_frame_count = 0; - for (i=0 ; i < info->rx_buf_count ; i++) { - buf = (RXBUF*)(info->rx_buf + (i * info->rx_buf_size)); - buf->status = buf->count = 0; - } -} - -/* Attempt to return a received HDLC frame - * Only frames received without errors are returned. - * - * Returns true if frame returned, otherwise false - */ -static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty) -{ - unsigned short status; - RXBUF *buf; - unsigned int framesize = 0; - unsigned long flags; - bool return_frame = false; - - if (info->rx_frame_count == 0) - return false; - - buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); - - status = buf->status; - - /* 07 VFR 1=valid frame - * 06 RDO 1=data overrun - * 05 CRC 1=OK, 0=error - * 04 RAB 1=frame aborted - */ - if ((status & 0xf0) != 0xA0) { - if (!(status & BIT7) || (status & BIT4)) - info->icount.rxabort++; - else if (status & BIT6) - info->icount.rxover++; - else if (!(status & BIT5)) { - info->icount.rxcrc++; - if (info->params.crc_type & HDLC_CRC_RETURN_EX) - return_frame = true; - } - framesize = 0; -#if SYNCLINK_GENERIC_HDLC - { - info->netdev->stats.rx_errors++; - info->netdev->stats.rx_frame_errors++; - } -#endif - } else - return_frame = true; - - if (return_frame) - framesize = buf->count; - - if (debug_level >= DEBUG_LEVEL_BH) - printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n", - __FILE__, __LINE__, info->device_name, status, framesize); - - if (debug_level >= DEBUG_LEVEL_DATA) - trace_block(info, buf->data, framesize, 0); - - if (framesize) { - if ((info->params.crc_type & HDLC_CRC_RETURN_EX && - framesize+1 > info->max_frame_size) || - framesize > info->max_frame_size) - info->icount.rxlong++; - else { - if (status & BIT5) - info->icount.rxok++; - - if (info->params.crc_type & HDLC_CRC_RETURN_EX) { - *(buf->data + framesize) = status & BIT5 ? RX_OK:RX_CRC_ERROR; - ++framesize; - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_rx(info, buf->data, framesize); - else -#endif - ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); - } - } - - spin_lock_irqsave(&info->lock, flags); - buf->status = buf->count = 0; - info->rx_frame_count--; - info->rx_get++; - if (info->rx_get >= info->rx_buf_count) - info->rx_get = 0; - spin_unlock_irqrestore(&info->lock, flags); - - return true; -} - -static bool register_test(MGSLPC_INFO *info) -{ - static unsigned char patterns[] = - { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; - static unsigned int count = ARRAY_SIZE(patterns); - unsigned int i; - bool rc = true; - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - reset_device(info); - - for (i = 0; i < count; i++) { - write_reg(info, XAD1, patterns[i]); - write_reg(info, XAD2, patterns[(i + 1) % count]); - if ((read_reg(info, XAD1) != patterns[i]) || - (read_reg(info, XAD2) != patterns[(i + 1) % count])) { - rc = false; - break; - } - } - - spin_unlock_irqrestore(&info->lock, flags); - return rc; -} - -static bool irq_test(MGSLPC_INFO *info) -{ - unsigned long end_time; - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - reset_device(info); - - info->testing_irq = true; - hdlc_mode(info); - - info->irq_occurred = false; - - /* init hdlc mode */ - - irq_enable(info, CHA, IRQ_TIMER); - write_reg(info, CHA + TIMR, 0); /* 512 cycles */ - issue_command(info, CHA, CMD_START_TIMER); - - spin_unlock_irqrestore(&info->lock, flags); - - end_time=100; - while(end_time-- && !info->irq_occurred) { - msleep_interruptible(10); - } - - info->testing_irq = false; - - spin_lock_irqsave(&info->lock, flags); - reset_device(info); - spin_unlock_irqrestore(&info->lock, flags); - - return info->irq_occurred; -} - -static int adapter_test(MGSLPC_INFO *info) -{ - if (!register_test(info)) { - info->init_error = DiagStatus_AddressFailure; - printk("%s(%d):Register test failure for device %s Addr=%04X\n", - __FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base)); - return -ENODEV; - } - - if (!irq_test(info)) { - info->init_error = DiagStatus_IrqFailure; - printk("%s(%d):Interrupt test failure for device %s IRQ=%d\n", - __FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level)); - return -ENODEV; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):device %s passed diagnostics\n", - __FILE__, __LINE__, info->device_name); - return 0; -} - -static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) -{ - int i; - int linecount; - if (xmit) - printk("%s tx data:\n", info->device_name); - else - printk("%s rx data:\n", info->device_name); - - while(count) { - if (count > 16) - linecount = 16; - else - linecount = count; - - for(i=0;i=040 && data[i]<=0176) - printk("%c", data[i]); - else - printk("."); - } - printk("\n"); - - data += linecount; - count -= linecount; - } -} - -/* HDLC frame time out - * update stats and do tx completion processing - */ -static void tx_timeout(struct timer_list *t) -{ - MGSLPC_INFO *info = from_timer(info, t, tx_timer); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):tx_timeout(%s)\n", - __FILE__, __LINE__, info->device_name); - if (info->tx_active && - info->params.mode == MGSL_MODE_HDLC) { - info->icount.txtimeout++; - } - spin_lock_irqsave(&info->lock, flags); - info->tx_active = false; - info->tx_count = info->tx_put = info->tx_get = 0; - - spin_unlock_irqrestore(&info->lock, flags); - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - { - struct tty_struct *tty = tty_port_tty_get(&info->port); - bh_transmit(info, tty); - tty_kref_put(tty); - } -} - -#if SYNCLINK_GENERIC_HDLC - -/* - * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) - * set encoding and frame check sequence (FCS) options - * - * dev pointer to network device structure - * encoding serial encoding setting - * parity FCS setting - * - * returns 0 if success, otherwise error code - */ -static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -{ - MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty; - unsigned char new_encoding; - unsigned short new_crctype; - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - switch (encoding) - { - case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; - case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; - case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; - case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; - case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; - default: return -EINVAL; - } - - switch (parity) - { - case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; - case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; - case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; - default: return -EINVAL; - } - - info->params.encoding = new_encoding; - info->params.crc_type = new_crctype; - - /* if network interface up, reprogram hardware */ - if (info->netcount) { - tty = tty_port_tty_get(&info->port); - mgslpc_program_hw(info, tty); - tty_kref_put(tty); - } - - return 0; -} - -/* - * called by generic HDLC layer to send frame - * - * skb socket buffer containing HDLC frame - * dev pointer to network device structure - */ -static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - MGSLPC_INFO *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk(KERN_INFO "%s:hdlc_xmit(%s)\n", __FILE__, dev->name); - - /* stop sending until this frame completes */ - netif_stop_queue(dev); - - /* copy data to device buffers */ - skb_copy_from_linear_data(skb, info->tx_buf, skb->len); - info->tx_get = 0; - info->tx_put = info->tx_count = skb->len; - - /* update network statistics */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - /* done with socket buffer, so free it */ - dev_kfree_skb(skb); - - /* save start time for transmit timeout detection */ - netif_trans_update(dev); - - /* start hardware transmitter if necessary */ - spin_lock_irqsave(&info->lock, flags); - if (!info->tx_active) { - struct tty_struct *tty = tty_port_tty_get(&info->port); - tx_start(info, tty); - tty_kref_put(tty); - } - spin_unlock_irqrestore(&info->lock, flags); - - return NETDEV_TX_OK; -} - -/* - * called by network layer when interface enabled - * claim resources and initialize hardware - * - * dev pointer to network device structure - * - * returns 0 if success, otherwise error code - */ -static int hdlcdev_open(struct net_device *dev) -{ - MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty; - int rc; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_open(%s)\n", __FILE__, dev->name); - - /* generic HDLC layer open processing */ - rc = hdlc_open(dev); - if (rc != 0) - return rc; - - /* arbitrate between network and tty opens */ - spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); - spin_unlock_irqrestore(&info->netlock, flags); - return -EBUSY; - } - info->netcount=1; - spin_unlock_irqrestore(&info->netlock, flags); - - tty = tty_port_tty_get(&info->port); - /* claim resources and init adapter */ - rc = startup(info, tty); - if (rc != 0) { - tty_kref_put(tty); - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return rc; - } - /* assert RTS and DTR, apply hardware settings */ - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - mgslpc_program_hw(info, tty); - tty_kref_put(tty); - - /* enable network layer transmit */ - netif_trans_update(dev); - netif_start_queue(dev); - - /* inform generic HDLC layer of current DCD status */ - spin_lock_irqsave(&info->lock, flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - if (info->serial_signals & SerialSignal_DCD) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - return 0; -} - -/* - * called by network layer when interface is disabled - * shutdown hardware and release resources - * - * dev pointer to network device structure - * - * returns 0 if success, otherwise error code - */ -static int hdlcdev_close(struct net_device *dev) -{ - MGSLPC_INFO *info = dev_to_port(dev); - struct tty_struct *tty = tty_port_tty_get(&info->port); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_close(%s)\n", __FILE__, dev->name); - - netif_stop_queue(dev); - - /* shutdown adapter and release resources */ - shutdown(info, tty); - tty_kref_put(tty); - hdlc_close(dev); - - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - - return 0; -} - -/* - * called by network layer to process IOCTL call to network device - * - * dev pointer to network device structure - * ifs pointer to network interface settings structure - * - * returns 0 if success, otherwise error code - */ -static int hdlcdev_wan_ioctl(struct net_device *dev, struct if_settings *ifs) -{ - const size_t size = sizeof(sync_serial_settings); - sync_serial_settings new_line; - sync_serial_settings __user *line = ifs->ifs_ifsu.sync; - MGSLPC_INFO *info = dev_to_port(dev); - unsigned int flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name); - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - memset(&new_line, 0, size); - - switch (ifs->type) { - case IF_GET_IFACE: /* return current sync_serial_settings */ - - ifs->type = IF_IFACE_SYNC_SERIAL; - if (ifs->size < size) { - ifs->size = size; /* data size wanted */ - return -ENOBUFS; - } - - flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); - - switch (flags){ - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; - case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; - default: new_line.clock_type = CLOCK_DEFAULT; - } - - new_line.clock_rate = info->params.clock_speed; - new_line.loopback = info->params.loopback ? 1:0; - - if (copy_to_user(line, &new_line, size)) - return -EFAULT; - return 0; - - case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&new_line, line, size)) - return -EFAULT; - - switch (new_line.clock_type) - { - case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; - case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; - case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; - case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; - case CLOCK_DEFAULT: flags = info->params.flags & - (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; - default: return -EINVAL; - } - - if (new_line.loopback != 0 && new_line.loopback != 1) - return -EINVAL; - - info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); - info->params.flags |= flags; - - info->params.loopback = new_line.loopback; - - if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) - info->params.clock_speed = new_line.clock_rate; - else - info->params.clock_speed = 0; - - /* if network interface up, reprogram hardware */ - if (info->netcount) { - struct tty_struct *tty = tty_port_tty_get(&info->port); - mgslpc_program_hw(info, tty); - tty_kref_put(tty); - } - return 0; - default: - return hdlc_ioctl(dev, ifs); - } -} - -/* - * called by network layer when transmit timeout is detected - * - * dev pointer to network device structure - */ -static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - MGSLPC_INFO *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_tx_timeout(%s)\n", dev->name); - - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - - spin_lock_irqsave(&info->lock, flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock, flags); - - netif_wake_queue(dev); -} - -/* - * called by device driver when transmit completes - * reenable network layer transmit if stopped - * - * info pointer to device instance information - */ -static void hdlcdev_tx_done(MGSLPC_INFO *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); -} - -/* - * called by device driver when frame received - * pass frame to network layer - * - * info pointer to device instance information - * buf pointer to buffer contianing frame data - * size count of data bytes in buf - */ -static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) -{ - struct sk_buff *skb = dev_alloc_skb(size); - struct net_device *dev = info->netdev; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_rx(%s)\n", dev->name); - - if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); - dev->stats.rx_dropped++; - return; - } - - skb_put_data(skb, buf, size); - - skb->protocol = hdlc_type_trans(skb, dev); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += size; - - netif_rx(skb); -} - -static const struct net_device_ops hdlcdev_ops = { - .ndo_open = hdlcdev_open, - .ndo_stop = hdlcdev_close, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlcdev_wan_ioctl, - .ndo_tx_timeout = hdlcdev_tx_timeout, -}; - -/* - * called by device driver when adding device instance - * do generic HDLC initialization - * - * info pointer to device instance information - * - * returns 0 if success, otherwise error code - */ -static int hdlcdev_init(MGSLPC_INFO *info) -{ - int rc; - struct net_device *dev; - hdlc_device *hdlc; - - /* allocate and initialize network and HDLC layer objects */ - - dev = alloc_hdlcdev(info); - if (dev == NULL) { - printk(KERN_ERR "%s:hdlc device allocation failure\n", __FILE__); - return -ENOMEM; - } - - /* for network layer reporting purposes only */ - dev->base_addr = info->io_base; - dev->irq = info->irq_level; - - /* network layer callbacks and settings */ - dev->netdev_ops = &hdlcdev_ops; - dev->watchdog_timeo = 10 * HZ; - dev->tx_queue_len = 50; - - /* generic HDLC layer callbacks and settings */ - hdlc = dev_to_hdlc(dev); - hdlc->attach = hdlcdev_attach; - hdlc->xmit = hdlcdev_xmit; - - /* register objects with HDLC layer */ - rc = register_hdlc_device(dev); - if (rc) { - printk(KERN_WARNING "%s:unable to register hdlc device\n", __FILE__); - free_netdev(dev); - return rc; - } - - info->netdev = dev; - return 0; -} - -/* - * called by device driver when removing device instance - * do generic HDLC cleanup - * - * info pointer to device instance information - */ -static void hdlcdev_exit(MGSLPC_INFO *info) -{ - unregister_hdlc_device(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; -} - -#endif /* CONFIG_HDLC */ - diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 38b46c7d1737..81ed58157b15 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -841,7 +841,7 @@ static int __init ppdev_init(void) pr_warn(CHRDEV ": unable to get major %d\n", PP_MAJOR); return -EIO; } - ppdev_class = class_create(THIS_MODULE, CHRDEV); + ppdev_class = class_create(CHRDEV); if (IS_ERR(ppdev_class)) { err = PTR_ERR(ppdev_class); goto out_chrdev; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 6fdfa65a00c3..cd48033b804a 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -282,7 +282,7 @@ static void tpm_dev_release(struct device *dev) * * Return: always 0 (i.e. success) */ -static int tpm_class_shutdown(struct device *dev) +int tpm_class_shutdown(struct device *dev) { struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); @@ -337,7 +337,6 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, device_initialize(&chip->dev); chip->dev.class = tpm_class; - chip->dev.class->shutdown_pre = tpm_class_shutdown; chip->dev.release = tpm_dev_release; chip->dev.parent = pdev; chip->dev.groups = chip->groups; @@ -572,6 +571,10 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); + /* Give back zero bytes, as TPM chip has not yet fully resumed: */ + if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) + return 0; + return tpm_get_random(chip, data, max); } @@ -606,13 +609,19 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip) } /* - * tpm_chip_startup() - performs auto startup and allocates the PCRs + * tpm_chip_bootstrap() - Boostrap TPM chip after power on * @chip: TPM chip to use. + * + * Initialize TPM chip after power on. This a one-shot function: subsequent + * calls will have no effect. */ -int tpm_chip_startup(struct tpm_chip *chip) +int tpm_chip_bootstrap(struct tpm_chip *chip) { int rc; + if (chip->flags & TPM_CHIP_FLAG_BOOTSTRAPPED) + return 0; + rc = tpm_chip_start(chip); if (rc) return rc; @@ -625,9 +634,15 @@ int tpm_chip_startup(struct tpm_chip *chip) stop: tpm_chip_stop(chip); + /* + * Unconditionally set, as driver initialization should cease, when the + * boostrapping process fails. + */ + chip->flags |= TPM_CHIP_FLAG_BOOTSTRAPPED; + return rc; } -EXPORT_SYMBOL_GPL(tpm_chip_startup); +EXPORT_SYMBOL_GPL(tpm_chip_bootstrap); /* * tpm_chip_register() - create a character device for the TPM chip @@ -644,6 +659,10 @@ int tpm_chip_register(struct tpm_chip *chip) { int rc; + rc = tpm_chip_bootstrap(chip); + if (rc) + return rc; + tpm_sysfs_add_device(chip); tpm_bios_log_setup(chip); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 7e513b771832..586ca10b0d72 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -412,6 +412,8 @@ int tpm_pm_suspend(struct device *dev) } suspended: + chip->flags |= TPM_CHIP_FLAG_SUSPENDED; + if (rc) dev_err(dev, "Ignoring error %d while suspending\n", rc); return 0; @@ -429,6 +431,14 @@ int tpm_pm_resume(struct device *dev) if (chip == NULL) return -ENODEV; + chip->flags &= ~TPM_CHIP_FLAG_SUSPENDED; + + /* + * Guarantee that SUSPENDED is written last, so that hwrng does not + * activate before the chip has been fully resumed. + */ + wmb(); + return 0; } EXPORT_SYMBOL_GPL(tpm_pm_resume); @@ -466,13 +476,15 @@ static int __init tpm_init(void) { int rc; - tpm_class = class_create(THIS_MODULE, "tpm"); + tpm_class = class_create("tpm"); if (IS_ERR(tpm_class)) { pr_err("couldn't create tpm class\n"); return PTR_ERR(tpm_class); } - tpmrm_class = class_create(THIS_MODULE, "tpmrm"); + tpm_class->shutdown_pre = tpm_class_shutdown; + + tpmrm_class = class_create("tpmrm"); if (IS_ERR(tpmrm_class)) { pr_err("couldn't create tpmrm class\n"); rc = PTR_ERR(tpmrm_class); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 88d3bd76e076..460bb85dd142 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -256,6 +256,7 @@ int tpm1_get_pcr_allocation(struct tpm_chip *chip); unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); int tpm_pm_suspend(struct device *dev); int tpm_pm_resume(struct device *dev); +int tpm_class_shutdown(struct device *dev); static inline void tpm_msleep(unsigned int delay_msec) { @@ -263,7 +264,7 @@ static inline void tpm_msleep(unsigned int delay_msec) delay_msec * 1000); }; -int tpm_chip_startup(struct tpm_chip *chip); +int tpm_chip_bootstrap(struct tpm_chip *chip); int tpm_chip_start(struct tpm_chip *chip); void tpm_chip_stop(struct tpm_chip *chip); struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 7af389806643..7db3593941ea 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -122,6 +122,29 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T490s"), }, }, + { + .callback = tpm_tis_disable_irq, + .ident = "ThinkStation P360 Tiny", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P360 Tiny"), + }, + }, + { + .callback = tpm_tis_disable_irq, + .ident = "ThinkPad L490", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"), + }, + }, + { + .callback = tpm_tis_disable_irq, + .ident = "UPX-TGL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + }, + }, {} }; diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index c2421162cf34..558144fa707a 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -1139,7 +1139,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->int_queue); - rc = tpm_chip_startup(chip); + rc = tpm_chip_bootstrap(chip); if (rc) goto out_err; @@ -1209,25 +1209,20 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) u32 intmask; int rc; - if (chip->ops->clk_enable != NULL) - chip->ops->clk_enable(chip, true); - - /* reenable interrupts that device may have lost or - * BIOS/firmware may have disabled + /* + * Re-enable interrupts that device may have lost or BIOS/firmware may + * have disabled. */ rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq); - if (rc < 0) - goto out; + if (rc < 0) { + dev_err(&chip->dev, "Setting IRQ failed.\n"); + return; + } intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE; - - tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); - -out: - if (chip->ops->clk_enable != NULL) - chip->ops->clk_enable(chip, false); - - return; + rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); + if (rc < 0) + dev_err(&chip->dev, "Enabling interrupts failed.\n"); } int tpm_tis_resume(struct device *dev) @@ -1235,27 +1230,27 @@ int tpm_tis_resume(struct device *dev) struct tpm_chip *chip = dev_get_drvdata(dev); int ret; - ret = tpm_tis_request_locality(chip, 0); - if (ret < 0) + ret = tpm_chip_start(chip); + if (ret) return ret; if (chip->flags & TPM_CHIP_FLAG_IRQ) tpm_tis_reenable_interrupts(chip); - ret = tpm_pm_resume(dev); - if (ret) - goto out; - /* * TPM 1.2 requires self-test on resume. This function actually returns * an error code but for unknown reason it isn't handled. */ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) tpm1_do_selftest(chip); -out: - tpm_tis_relinquish_locality(chip, 0); - return ret; + tpm_chip_stop(chip); + + ret = tpm_pm_resume(dev); + if (ret) + return ret; + + return 0; } EXPORT_SYMBOL_GPL(tpm_tis_resume); #endif diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index e978f457fd4d..610bfadb6acf 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -84,10 +84,10 @@ enum tis_defaults { #define ILB_REMAP_SIZE 0x100 enum tpm_tis_flags { - TPM_TIS_ITPM_WORKAROUND = BIT(0), - TPM_TIS_INVALID_STATUS = BIT(1), - TPM_TIS_DEFAULT_CANCELLATION = BIT(2), - TPM_TIS_IRQ_TESTED = BIT(3), + TPM_TIS_ITPM_WORKAROUND = 0, + TPM_TIS_INVALID_STATUS = 1, + TPM_TIS_DEFAULT_CANCELLATION = 2, + TPM_TIS_IRQ_TESTED = 3, }; struct tpm_tis_data { diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d5ac4d955bc8..b65c809a4e97 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2244,7 +2244,7 @@ static int __init virtio_console_init(void) { int err; - pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); + pdrvdata.class = class_create("virtio-ports"); if (IS_ERR(pdrvdata.class)) { err = PTR_ERR(pdrvdata.class); pr_err("Error %d creating virtio-ports class\n", err); diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 74a4928aea1d..a46f637da959 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -856,7 +856,7 @@ static int __init hwicap_module_init(void) dev_t devt; int retval; - icap_class = class_create(THIS_MODULE, "xilinx_config"); + icap_class = class_create("xilinx_config"); mutex_init(&icap_sem); devt = MKDEV(XHWICAP_MAJOR, XHWICAP_MINOR); diff --git a/drivers/char/xillybus/xillybus_class.c b/drivers/char/xillybus/xillybus_class.c index e9a288e61c15..89926fe9d813 100644 --- a/drivers/char/xillybus/xillybus_class.c +++ b/drivers/char/xillybus/xillybus_class.c @@ -242,7 +242,7 @@ EXPORT_SYMBOL(xillybus_find_inode); static int __init xillybus_class_init(void) { - xillybus_class = class_create(THIS_MODULE, "xillybus"); + xillybus_class = class_create("xillybus"); if (IS_ERR(xillybus_class)) { pr_warn("Failed to register xillybus class\n"); diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1eef05bb1f99..016814e15536 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -325,6 +325,15 @@ config COMMON_CLK_LOCHNAGAR This driver supports the clocking features of the Cirrus Logic Lochnagar audio development board. +config COMMON_CLK_LOONGSON2 + bool "Clock driver for Loongson-2 SoC" + depends on LOONGARCH || COMPILE_TEST + help + This driver provides support for clock controller on Loongson-2 SoC. + The clock controller can generates and supplies clock to various + peripherals within the SoC. + Say Y here to support Loongson-2 SoC clock driver. + config COMMON_CLK_NXP def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX) select REGMAP_MMIO if ARCH_LPC32XX @@ -367,6 +376,15 @@ config COMMON_CLK_RS9_PCIE This driver supports the Renesas 9-series PCIe clock generator models 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ. +config COMMON_CLK_SI521XX + tristate "Clock driver for SkyWorks Si521xx PCIe clock generators" + depends on I2C + depends on OF + select REGMAP_I2C + help + This driver supports the SkyWorks Si521xx PCIe clock generator + models Si52144/Si52146/Si52147. + config COMMON_CLK_VC5 tristate "Clock driver for IDT VersaClock 5,6 devices" depends on I2C @@ -436,6 +454,16 @@ config COMMON_CLK_K210 help Support for the Canaan Kendryte K210 RISC-V SoC clocks. +config COMMON_CLK_SP7021 + tristate "Clock driver for Sunplus SP7021 SoC" + depends on SOC_SP7021 || COMPILE_TEST + default SOC_SP7021 + help + This driver supports the Sunplus SP7021 SoC clocks. + It implements SP7021 PLLs/gate. + Not all features of the PLL are currently supported + by the driver. + source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e3ca0d058a25..0aebef17edc6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o obj-$(CONFIG_LMK04832) += clk-lmk04832.o obj-$(CONFIG_COMMON_CLK_LAN966X) += clk-lan966x.o obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o +obj-$(CONFIG_MACH_LOONGSON32) += clk-loongson1.o +obj-$(CONFIG_COMMON_CLK_LOONGSON2) += clk-loongson2.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o @@ -65,6 +67,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o obj-$(CONFIG_COMMON_CLK_SI544) += clk-si544.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o +obj-$(CONFIG_COMMON_CLK_SP7021) += clk-sp7021.o obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o @@ -72,6 +75,7 @@ obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_RS9_PCIE) += clk-renesas-pcie.o +obj-$(CONFIG_COMMON_CLK_SI521XX) += clk-si521xx.o obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o obj-$(CONFIG_COMMON_CLK_VC7) += clk-versaclock7.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o @@ -93,7 +97,6 @@ obj-y += imx/ obj-y += ingenic/ obj-$(CONFIG_ARCH_K3) += keystone/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ -obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ obj-y += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-y += microchip/ @@ -117,7 +120,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_STM32) += stm32/ -obj-$(CONFIG_SOC_STARFIVE) += starfive/ +obj-y += starfive/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-y += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index d757003004cb..0882ed01d5c2 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -668,7 +668,7 @@ sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock, ret = sam9x60_frac_pll_compute_mul_frac(&frac->core, FCORE_MIN, parent_rate, true); - if (ret <= 0) { + if (ret < 0) { hw = ERR_PTR(ret); goto free; } diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c index e1fda6ad5cd5..2334e6c334cf 100644 --- a/drivers/clk/axs10x/i2s_pll_clock.c +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -198,10 +198,9 @@ static int i2s_pll_clk_probe(struct platform_device *pdev) return of_clk_add_provider(node, of_clk_src_simple_get, clk); } -static int i2s_pll_clk_remove(struct platform_device *pdev) +static void i2s_pll_clk_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - return 0; } static const struct of_device_id i2s_pll_clk_id[] = { @@ -216,7 +215,7 @@ static struct platform_driver i2s_pll_clk_driver = { .of_match_table = i2s_pll_clk_id, }, .probe = i2s_pll_clk_probe, - .remove = i2s_pll_clk_remove, + .remove_new = i2s_pll_clk_remove, }; module_platform_driver(i2s_pll_clk_driver); diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c index 90fb0e6ff573..242bf5d75bab 100644 --- a/drivers/clk/axs10x/pll_clock.c +++ b/drivers/clk/axs10x/pll_clock.c @@ -253,14 +253,8 @@ static int axs10x_pll_clk_probe(struct platform_device *pdev) return ret; } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, - &pll_clk->hw); -} - -static int axs10x_pll_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &pll_clk->hw); } static void __init of_axs10x_pll_clk_setup(struct device_node *node) @@ -332,7 +326,6 @@ static struct platform_driver axs10x_pll_clk_driver = { .of_match_table = axs10x_pll_clk_id, }, .probe = axs10x_pll_clk_probe, - .remove = axs10x_pll_clk_remove, }; builtin_platform_driver(axs10x_pll_clk_driver); diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index 77266afb1c79..a972d763eb77 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig @@ -37,6 +37,15 @@ config CLK_BCM_63XX_GATE Enable common clock framework support for Broadcom BCM63xx DSL SoCs based on the MIPS architecture +config CLK_BCM63268_TIMER + bool "Broadcom BCM63268 timer clock and reset support" + depends on BMIPS_GENERIC || COMPILE_TEST + default BMIPS_GENERIC + select RESET_CONTROLLER + help + Enable timer clock and reset support for Broadcom BCM63268 DSL SoCs + based on the MIPS architecture. + config CLK_BCM_KONA bool "Broadcom Kona CCU clock support" depends on ARCH_BCM_MOBILE || COMPILE_TEST diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index edb66b44cb27..d0b6f4b1fb08 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o obj-$(CONFIG_CLK_BCM_63XX_GATE) += clk-bcm63xx-gate.o +obj-$(CONFIG_CLK_BCM63268_TIMER) += clk-bcm63268-timer.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-bcm2711-dvp.c index e63a42618ac2..e4fbbf3c40fe 100644 --- a/drivers/clk/bcm/clk-bcm2711-dvp.c +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c @@ -92,15 +92,13 @@ unregister_clk0: return ret; }; -static int clk_dvp_remove(struct platform_device *pdev) +static void clk_dvp_remove(struct platform_device *pdev) { struct clk_dvp *dvp = platform_get_drvdata(pdev); struct clk_hw_onecell_data *data = dvp->data; clk_hw_unregister_gate(data->hws[1]); clk_hw_unregister_gate(data->hws[0]); - - return 0; } static const struct of_device_id clk_dvp_dt_ids[] = { @@ -111,7 +109,7 @@ MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids); static struct platform_driver clk_dvp_driver = { .probe = clk_dvp_probe, - .remove = clk_dvp_remove, + .remove_new = clk_dvp_remove, .driver = { .name = "brcm2711-dvp", .of_match_table = clk_dvp_dt_ids, diff --git a/drivers/clk/bcm/clk-bcm63268-timer.c b/drivers/clk/bcm/clk-bcm63268-timer.c new file mode 100644 index 000000000000..463710d272a1 --- /dev/null +++ b/drivers/clk/bcm/clk-bcm63268-timer.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BCM63268 Timer Clock and Reset Controller Driver + * + * Copyright (C) 2023 Álvaro Fernández Rojas + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BCM63268_TIMER_RESET_SLEEP_MIN_US 10000 +#define BCM63268_TIMER_RESET_SLEEP_MAX_US 20000 + +struct bcm63268_tclkrst_hw { + void __iomem *regs; + spinlock_t lock; + + struct reset_controller_dev rcdev; + struct clk_hw_onecell_data data; +}; + +struct bcm63268_tclk_table_entry { + const char * const name; + u8 bit; +}; + +static const struct bcm63268_tclk_table_entry bcm63268_timer_clocks[] = { + { + .name = "ephy1", + .bit = BCM63268_TCLK_EPHY1, + }, { + .name = "ephy2", + .bit = BCM63268_TCLK_EPHY2, + }, { + .name = "ephy3", + .bit = BCM63268_TCLK_EPHY3, + }, { + .name = "gphy1", + .bit = BCM63268_TCLK_GPHY1, + }, { + .name = "dsl", + .bit = BCM63268_TCLK_DSL, + }, { + .name = "wakeon_ephy", + .bit = BCM63268_TCLK_WAKEON_EPHY, + }, { + .name = "wakeon_dsl", + .bit = BCM63268_TCLK_WAKEON_DSL, + }, { + .name = "fap1_pll", + .bit = BCM63268_TCLK_FAP1, + }, { + .name = "fap2_pll", + .bit = BCM63268_TCLK_FAP2, + }, { + .name = "uto_50", + .bit = BCM63268_TCLK_UTO_50, + }, { + .name = "uto_extin", + .bit = BCM63268_TCLK_UTO_EXTIN, + }, { + .name = "usb_ref", + .bit = BCM63268_TCLK_USB_REF, + }, { + /* sentinel */ + } +}; + +static inline struct bcm63268_tclkrst_hw * +to_bcm63268_timer_reset(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct bcm63268_tclkrst_hw, rcdev); +} + +static int bcm63268_timer_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); + unsigned long flags; + uint32_t val; + + spin_lock_irqsave(&reset->lock, flags); + val = __raw_readl(reset->regs); + if (assert) + val &= ~BIT(id); + else + val |= BIT(id); + __raw_writel(val, reset->regs); + spin_unlock_irqrestore(&reset->lock, flags); + + return 0; +} + +static int bcm63268_timer_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return bcm63268_timer_reset_update(rcdev, id, true); +} + +static int bcm63268_timer_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return bcm63268_timer_reset_update(rcdev, id, false); +} + +static int bcm63268_timer_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + bcm63268_timer_reset_update(rcdev, id, true); + usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, + BCM63268_TIMER_RESET_SLEEP_MAX_US); + + bcm63268_timer_reset_update(rcdev, id, false); + /* + * Ensure component is taken out reset state by sleeping also after + * deasserting the reset. Otherwise, the component may not be ready + * for operation. + */ + usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, + BCM63268_TIMER_RESET_SLEEP_MAX_US); + + return 0; +} + +static int bcm63268_timer_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); + + return !(__raw_readl(reset->regs) & BIT(id)); +} + +static const struct reset_control_ops bcm63268_timer_reset_ops = { + .assert = bcm63268_timer_reset_assert, + .deassert = bcm63268_timer_reset_deassert, + .reset = bcm63268_timer_reset_reset, + .status = bcm63268_timer_reset_status, +}; + +static int bcm63268_tclk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct bcm63268_tclk_table_entry *entry; + struct bcm63268_tclkrst_hw *hw; + struct clk_hw *clk; + u8 maxbit = 0; + int i, ret; + + for (entry = bcm63268_timer_clocks; entry->name; entry++) + maxbit = max(maxbit, entry->bit); + maxbit++; + + hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), + GFP_KERNEL); + if (!hw) + return -ENOMEM; + + platform_set_drvdata(pdev, hw); + + spin_lock_init(&hw->lock); + + hw->data.num = maxbit; + for (i = 0; i < maxbit; i++) + hw->data.hws[i] = ERR_PTR(-ENODEV); + + hw->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hw->regs)) + return PTR_ERR(hw->regs); + + for (entry = bcm63268_timer_clocks; entry->name; entry++) { + clk = devm_clk_hw_register_gate(dev, entry->name, NULL, 0, + hw->regs, entry->bit, + CLK_GATE_BIG_ENDIAN, + &hw->lock); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + hw->data.hws[entry->bit] = clk; + } + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &hw->data); + if (ret) + return ret; + + hw->rcdev.of_node = dev->of_node; + hw->rcdev.ops = &bcm63268_timer_reset_ops; + + ret = devm_reset_controller_register(dev, &hw->rcdev); + if (ret) + dev_err(dev, "Failed to register reset controller\n"); + + return 0; +} + +static const struct of_device_id bcm63268_tclk_dt_ids[] = { + { .compatible = "brcm,bcm63268-timer-clocks" }, + { /* sentinel */ } +}; + +static struct platform_driver bcm63268_tclk = { + .probe = bcm63268_tclk_probe, + .driver = { + .name = "bcm63268-timer-clock", + .of_match_table = bcm63268_tclk_dt_ids, + }, +}; +builtin_platform_driver(bcm63268_tclk); diff --git a/drivers/clk/bcm/clk-bcm63xx-gate.c b/drivers/clk/bcm/clk-bcm63xx-gate.c index 89297c57881e..0769f98767da 100644 --- a/drivers/clk/bcm/clk-bcm63xx-gate.c +++ b/drivers/clk/bcm/clk-bcm63xx-gate.c @@ -541,7 +541,7 @@ out_err: return ret; } -static int clk_bcm63xx_remove(struct platform_device *pdev) +static void clk_bcm63xx_remove(struct platform_device *pdev) { struct clk_bcm63xx_hw *hw = platform_get_drvdata(pdev); int i; @@ -552,8 +552,6 @@ static int clk_bcm63xx_remove(struct platform_device *pdev) if (!IS_ERR(hw->data.hws[i])) clk_hw_unregister_gate(hw->data.hws[i]); } - - return 0; } static const struct of_device_id clk_bcm63xx_dt_ids[] = { @@ -570,7 +568,7 @@ static const struct of_device_id clk_bcm63xx_dt_ids[] = { static struct platform_driver clk_bcm63xx = { .probe = clk_bcm63xx_probe, - .remove = clk_bcm63xx_remove, + .remove_new = clk_bcm63xx_remove, .driver = { .name = "bcm63xx-clock", .of_match_table = clk_bcm63xx_dt_ids, diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index ce2f93479736..eb399a4d141b 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -439,13 +439,11 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) return 0; } -static int raspberrypi_clk_remove(struct platform_device *pdev) +static void raspberrypi_clk_remove(struct platform_device *pdev) { struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); platform_device_unregister(rpi->cpufreq); - - return 0; } static const struct of_device_id raspberrypi_clk_match[] = { @@ -460,7 +458,7 @@ static struct platform_driver raspberrypi_clk_driver = { .of_match_table = raspberrypi_clk_match, }, .probe = raspberrypi_clk_probe, - .remove = raspberrypi_clk_remove, + .remove_new = raspberrypi_clk_remove, }; module_platform_driver(raspberrypi_clk_driver); diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c index 9c3305bcb27a..a094a2601a37 100644 --- a/drivers/clk/clk-ast2600.c +++ b/drivers/clk/clk-ast2600.c @@ -15,7 +15,11 @@ #include "clk-aspeed.h" -#define ASPEED_G6_NUM_CLKS 71 +/* + * This includes the gates (configured from aspeed_g6_gates), plus the + * explicitly-configured clocks (ASPEED_CLK_HPLL and up). + */ +#define ASPEED_G6_NUM_CLKS 72 #define ASPEED_G6_SILICON_REV 0x014 #define CHIP_REVISION_ID GENMASK(23, 16) @@ -32,6 +36,20 @@ #define ASPEED_G6_CLK_SELECTION1 0x300 #define ASPEED_G6_CLK_SELECTION2 0x304 #define ASPEED_G6_CLK_SELECTION4 0x310 +#define ASPEED_G6_CLK_SELECTION5 0x314 +#define I3C_CLK_SELECTION_SHIFT 31 +#define I3C_CLK_SELECTION BIT(31) +#define I3C_CLK_SELECT_HCLK (0 << I3C_CLK_SELECTION_SHIFT) +#define I3C_CLK_SELECT_APLL_DIV (1 << I3C_CLK_SELECTION_SHIFT) +#define APLL_DIV_SELECTION_SHIFT 28 +#define APLL_DIV_SELECTION GENMASK(30, 28) +#define APLL_DIV_2 (0b001 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_3 (0b010 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_4 (0b011 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_5 (0b100 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_6 (0b101 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_7 (0b110 << APLL_DIV_SELECTION_SHIFT) +#define APLL_DIV_8 (0b111 << APLL_DIV_SELECTION_SHIFT) #define ASPEED_HPLL_PARAM 0x200 #define ASPEED_APLL_PARAM 0x210 @@ -55,6 +73,27 @@ static void __iomem *scu_g6_base; static u8 soc_rev; /* + * The majority of the clocks in the system are gates paired with a reset + * controller that holds the IP in reset; this is represented by the @reset_idx + * member of entries here. + * + * This borrows from clk_hw_register_gate, but registers two 'gates', one + * to control the clock enable register and the other to control the reset + * IP. This allows us to enforce the ordering: + * + * 1. Place IP in reset + * 2. Enable clock + * 3. Delay + * 4. Release reset + * + * Consequently, if reset_idx is set, reset control is implicit: the clock + * consumer does not need its own reset handling, as enabling the clock will + * also deassert reset. + * + * There are some gates that do not have an associated reset; these are + * handled by using -1 as the index for the reset, and the consumer must + * explictly assert/deassert reset lines as required. + * * Clocks marked with CLK_IS_CRITICAL: * * ref0 and ref1 are essential for the SoC to operate @@ -97,14 +136,13 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = { [ASPEED_CLK_GATE_LHCCLK] = { 37, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ /* Reserved 38 RSA: no longer used */ /* Reserved 39 */ - [ASPEED_CLK_GATE_I3C0CLK] = { 40, 40, "i3c0clk-gate", NULL, 0 }, /* I3C0 */ - [ASPEED_CLK_GATE_I3C1CLK] = { 41, 41, "i3c1clk-gate", NULL, 0 }, /* I3C1 */ - [ASPEED_CLK_GATE_I3C2CLK] = { 42, 42, "i3c2clk-gate", NULL, 0 }, /* I3C2 */ - [ASPEED_CLK_GATE_I3C3CLK] = { 43, 43, "i3c3clk-gate", NULL, 0 }, /* I3C3 */ - [ASPEED_CLK_GATE_I3C4CLK] = { 44, 44, "i3c4clk-gate", NULL, 0 }, /* I3C4 */ - [ASPEED_CLK_GATE_I3C5CLK] = { 45, 45, "i3c5clk-gate", NULL, 0 }, /* I3C5 */ - [ASPEED_CLK_GATE_I3C6CLK] = { 46, 46, "i3c6clk-gate", NULL, 0 }, /* I3C6 */ - [ASPEED_CLK_GATE_I3C7CLK] = { 47, 47, "i3c7clk-gate", NULL, 0 }, /* I3C7 */ + [ASPEED_CLK_GATE_I3C0CLK] = { 40, 40, "i3c0clk-gate", "i3cclk", 0 }, /* I3C0 */ + [ASPEED_CLK_GATE_I3C1CLK] = { 41, 41, "i3c1clk-gate", "i3cclk", 0 }, /* I3C1 */ + [ASPEED_CLK_GATE_I3C2CLK] = { 42, 42, "i3c2clk-gate", "i3cclk", 0 }, /* I3C2 */ + [ASPEED_CLK_GATE_I3C3CLK] = { 43, 43, "i3c3clk-gate", "i3cclk", 0 }, /* I3C3 */ + [ASPEED_CLK_GATE_I3C4CLK] = { 44, 44, "i3c4clk-gate", "i3cclk", 0 }, /* I3C4 */ + [ASPEED_CLK_GATE_I3C5CLK] = { 45, 45, "i3c5clk-gate", "i3cclk", 0 }, /* I3C5 */ + /* Reserved: 46 & 47 */ [ASPEED_CLK_GATE_UART1CLK] = { 48, -1, "uart1clk-gate", "uart", 0 }, /* UART1 */ [ASPEED_CLK_GATE_UART2CLK] = { 49, -1, "uart2clk-gate", "uart", 0 }, /* UART2 */ [ASPEED_CLK_GATE_UART3CLK] = { 50, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ @@ -652,6 +690,9 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev) const struct aspeed_gate_data *gd = &aspeed_g6_gates[i]; u32 gate_flags; + if (!gd->name) + continue; + /* * Special case: the USB port 1 clock (bit 14) is always * working the opposite way from the other ones. @@ -772,6 +813,14 @@ static void __init aspeed_g6_cc(struct regmap *map) /* USB 2.0 port1 phy 40MHz clock */ hw = clk_hw_register_fixed_rate(NULL, "usb-phy-40m", NULL, 0, 40000000); aspeed_g6_clk_data->hws[ASPEED_CLK_USBPHY_40M] = hw; + + /* i3c clock: source from apll, divide by 8 */ + regmap_update_bits(map, ASPEED_G6_CLK_SELECTION5, + I3C_CLK_SELECTION | APLL_DIV_SELECTION, + I3C_CLK_SELECT_APLL_DIV | APLL_DIV_8); + + hw = clk_hw_register_fixed_factor(NULL, "i3cclk", "apll", 0, 1, 8); + aspeed_g6_clk_data->hws[ASPEED_CLK_I3C] = hw; }; static void __init aspeed_g6_cc_init(struct device_node *np) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index ac6ff736ac8f..a04a3d38c76e 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -553,15 +553,8 @@ static int axi_clkgen_probe(struct platform_device *pdev) if (ret) return ret; - return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get, - &axi_clkgen->clk_hw); -} - -static int axi_clkgen_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - - return 0; + return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, + &axi_clkgen->clk_hw); } static const struct of_device_id axi_clkgen_ids[] = { @@ -583,7 +576,6 @@ static struct platform_driver axi_clkgen_driver = { .of_match_table = axi_clkgen_ids, }, .probe = axi_clkgen_probe, - .remove = axi_clkgen_remove, }; module_platform_driver(axi_clkgen_driver); diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c index 07e80fe8c310..1afcfdf2e6f9 100644 --- a/drivers/clk/clk-axm5516.c +++ b/drivers/clk/clk-axm5516.c @@ -569,18 +569,11 @@ static int axmclk_probe(struct platform_device *pdev) return ret; } - return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL); -} - -static int axmclk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; + return devm_of_clk_add_hw_provider(dev, of_clk_axmclk_get, NULL); } static struct platform_driver axmclk_driver = { .probe = axmclk_probe, - .remove = axmclk_remove, .driver = { .name = "clk-axm5516", .of_match_table = axmclk_match_table, diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c index fad78a22218e..2a19e50fff68 100644 --- a/drivers/clk/clk-bm1880.c +++ b/drivers/clk/clk-bm1880.c @@ -949,4 +949,3 @@ module_platform_driver(bm1880_clk_driver); MODULE_AUTHOR("Manivannan Sadhasivam "); MODULE_DESCRIPTION("Clock driver for Bitmain BM1880 SoC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index 1449d0537674..d8bee8180a6b 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -661,16 +661,10 @@ static int cdce706_probe(struct i2c_client *client) ret = cdce706_register_clkouts(cdce); if (ret < 0) return ret; - return of_clk_add_hw_provider(client->dev.of_node, of_clk_cdce_get, - cdce); + return devm_of_clk_add_hw_provider(&client->dev, of_clk_cdce_get, + cdce); } -static void cdce706_remove(struct i2c_client *client) -{ - of_clk_del_provider(client->dev.of_node); -} - - #ifdef CONFIG_OF static const struct of_device_id cdce706_dt_match[] = { { .compatible = "ti,cdce706" }, @@ -691,7 +685,6 @@ static struct i2c_driver cdce706_i2c_driver = { .of_match_table = of_match_ptr(cdce706_dt_match), }, .probe_new = cdce706_probe, - .remove = cdce706_remove, .id_table = cdce706_id, }; module_i2c_driver(cdce706_i2c_driver); diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 2ef819606c41..1a4e6340f95c 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -33,9 +33,12 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) else return rc; } - if (clkspec.np == node && !clk_supplier) + if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); return 0; + } pclk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); if (IS_ERR(pclk)) { if (PTR_ERR(pclk) != -EPROBE_DEFER) pr_warn("clk: couldn't get parent clock %d for %pOF\n", @@ -48,10 +51,12 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) if (rc < 0) goto err; if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); rc = 0; goto err; } clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) pr_warn("clk: couldn't get assigned clock %d for %pOF\n", @@ -93,10 +98,13 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) else return rc; } - if (clkspec.np == node && !clk_supplier) + if (clkspec.np == node && !clk_supplier) { + of_node_put(clkspec.np); return 0; + } clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) pr_warn("clk: couldn't get clock %d for %pOF\n", diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index f734e34735a9..b3e66202b942 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -297,14 +297,12 @@ void __init of_fixed_factor_clk_setup(struct device_node *node) CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", of_fixed_factor_clk_setup); -static int of_fixed_factor_clk_remove(struct platform_device *pdev) +static void of_fixed_factor_clk_remove(struct platform_device *pdev) { struct clk_hw *clk = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); clk_hw_unregister_fixed_factor(clk); - - return 0; } static int of_fixed_factor_clk_probe(struct platform_device *pdev) @@ -336,7 +334,7 @@ static struct platform_driver of_fixed_factor_clk_driver = { .of_match_table = of_fixed_factor_clk_ids, }, .probe = of_fixed_factor_clk_probe, - .remove = of_fixed_factor_clk_remove, + .remove_new = of_fixed_factor_clk_remove, }; builtin_platform_driver(of_fixed_factor_clk_driver); #endif diff --git a/drivers/clk/clk-fixed-mmio.c b/drivers/clk/clk-fixed-mmio.c index 8609fca29cc4..0e08cb22c196 100644 --- a/drivers/clk/clk-fixed-mmio.c +++ b/drivers/clk/clk-fixed-mmio.c @@ -71,14 +71,12 @@ static int of_fixed_mmio_clk_probe(struct platform_device *pdev) return 0; } -static int of_fixed_mmio_clk_remove(struct platform_device *pdev) +static void of_fixed_mmio_clk_remove(struct platform_device *pdev) { struct clk_hw *clk = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); clk_hw_unregister_fixed_rate(clk); - - return 0; } static const struct of_device_id of_fixed_mmio_clk_ids[] = { @@ -93,7 +91,7 @@ static struct platform_driver of_fixed_mmio_clk_driver = { .of_match_table = of_fixed_mmio_clk_ids, }, .probe = of_fixed_mmio_clk_probe, - .remove = of_fixed_mmio_clk_remove, + .remove_new = of_fixed_mmio_clk_remove, }; module_platform_driver(of_fixed_mmio_clk_driver); diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 7d775954e26d..3481eb8cdeb3 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -196,14 +196,12 @@ void __init of_fixed_clk_setup(struct device_node *node) } CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); -static int of_fixed_clk_remove(struct platform_device *pdev) +static void of_fixed_clk_remove(struct platform_device *pdev) { struct clk_hw *hw = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); clk_hw_unregister_fixed_rate(hw); - - return 0; } static int of_fixed_clk_probe(struct platform_device *pdev) @@ -234,7 +232,7 @@ static struct platform_driver of_fixed_clk_driver = { .of_match_table = of_fixed_clk_ids, }, .probe = of_fixed_clk_probe, - .remove = of_fixed_clk_remove, + .remove_new = of_fixed_clk_remove, }; builtin_platform_driver(of_fixed_clk_driver); #endif diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 6affe3565025..479297763e70 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -71,6 +71,7 @@ static void clk_fd_get_div(struct clk_hw *hw, struct u32_fract *fract) struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long flags = 0; unsigned long m, n; + u32 mmask, nmask; u32 val; if (fd->lock) @@ -85,8 +86,11 @@ static void clk_fd_get_div(struct clk_hw *hw, struct u32_fract *fract) else __release(fd->lock); - m = (val & fd->mmask) >> fd->mshift; - n = (val & fd->nmask) >> fd->nshift; + mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; + nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; + + m = (val & mmask) >> fd->mshift; + n = (val & nmask) >> fd->nshift; if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { m++; @@ -166,6 +170,7 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long flags = 0; unsigned long m, n; + u32 mmask, nmask; u32 val; rational_best_approximation(rate, parent_rate, @@ -182,8 +187,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, else __acquire(fd->lock); + mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; + nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; + val = clk_fd_readl(fd); - val &= ~(fd->mmask | fd->nmask); + val &= ~(mmask | nmask); val |= (m << fd->mshift) | (n << fd->nshift); clk_fd_writel(fd, val); @@ -260,10 +268,8 @@ struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, fd->reg = reg; fd->mshift = mshift; fd->mwidth = mwidth; - fd->mmask = GENMASK(mwidth - 1, 0) << mshift; fd->nshift = nshift; fd->nwidth = nwidth; - fd->nmask = GENMASK(nwidth - 1, 0) << nshift; fd->flags = clk_divider_flags; fd->lock = lock; fd->hw.init = &init; diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c index 60007b508590..33b48ea5ea3d 100644 --- a/drivers/clk/clk-hsdk-pll.c +++ b/drivers/clk/clk-hsdk-pll.c @@ -346,14 +346,8 @@ static int hsdk_pll_clk_probe(struct platform_device *pdev) return ret; } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, - &pll_clk->hw); -} - -static int hsdk_pll_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &pll_clk->hw); } static void __init of_hsdk_pll_clk_setup(struct device_node *node) @@ -432,6 +426,5 @@ static struct platform_driver hsdk_pll_clk_driver = { .of_match_table = hsdk_pll_clk_id, }, .probe = hsdk_pll_clk_probe, - .remove = hsdk_pll_clk_remove, }; builtin_platform_driver(hsdk_pll_clk_driver); diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index 57485356de4c..afdfee3b365f 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -1522,8 +1522,8 @@ static int lmk04832_probe(struct spi_device *spi) } lmk->clk_data->num = info->num_channels; - ret = of_clk_add_hw_provider(lmk->dev->of_node, of_clk_hw_onecell_get, - lmk->clk_data); + ret = devm_of_clk_add_hw_provider(lmk->dev, of_clk_hw_onecell_get, + lmk->clk_data); if (ret) { dev_err(lmk->dev, "failed to add provider (%d)\n", ret); goto err_disable_vco; @@ -1547,7 +1547,6 @@ static void lmk04832_remove(struct spi_device *spi) struct lmk04832 *lmk = spi_get_drvdata(spi); clk_disable_unprepare(lmk->oscin); - of_clk_del_provider(spi->dev.of_node); } static const struct spi_device_id lmk04832_id[] = { diff --git a/drivers/clk/clk-loongson1.c b/drivers/clk/clk-loongson1.c new file mode 100644 index 000000000000..a3467aa6790f --- /dev/null +++ b/drivers/clk/clk-loongson1.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Clock driver for Loongson-1 SoC + * + * Copyright (C) 2012-2023 Keguang Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Loongson 1 Clock Register Definitions */ +#define CLK_PLL_FREQ 0x0 +#define CLK_PLL_DIV 0x4 + +static DEFINE_SPINLOCK(ls1x_clk_div_lock); + +struct ls1x_clk_pll_data { + u32 fixed; + u8 shift; + u8 int_shift; + u8 int_width; + u8 frac_shift; + u8 frac_width; +}; + +struct ls1x_clk_div_data { + u8 shift; + u8 width; + unsigned long flags; + const struct clk_div_table *table; + u8 bypass_shift; + u8 bypass_inv; + spinlock_t *lock; /* protect access to DIV registers */ +}; + +struct ls1x_clk { + void __iomem *reg; + unsigned int offset; + struct clk_hw hw; + const void *data; +}; + +#define to_ls1x_clk(_hw) container_of(_hw, struct ls1x_clk, hw) + +static inline unsigned long ls1x_pll_rate_part(unsigned int val, + unsigned int shift, + unsigned int width) +{ + return (val & GENMASK(shift + width, shift)) >> shift; +} + +static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_pll_data *d = ls1x_clk->data; + u32 val, rate; + + val = readl(ls1x_clk->reg); + rate = d->fixed; + rate += ls1x_pll_rate_part(val, d->int_shift, d->int_width); + if (d->frac_width) + rate += ls1x_pll_rate_part(val, d->frac_shift, d->frac_width); + rate *= parent_rate; + rate >>= d->shift; + + return rate; +} + +static const struct clk_ops ls1x_pll_clk_ops = { + .recalc_rate = ls1x_pll_recalc_rate, +}; + +static unsigned long ls1x_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_div_data *d = ls1x_clk->data; + unsigned int val; + + val = readl(ls1x_clk->reg) >> d->shift; + val &= clk_div_mask(d->width); + + return divider_recalc_rate(hw, parent_rate, val, d->table, + d->flags, d->width); +} + +static long ls1x_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_div_data *d = ls1x_clk->data; + + return divider_round_rate(hw, rate, prate, d->table, + d->width, d->flags); +} + +static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw); + const struct ls1x_clk_div_data *d = ls1x_clk->data; + int val, div_val; + unsigned long flags = 0; + + div_val = divider_get_val(rate, parent_rate, d->table, + d->width, d->flags); + if (div_val < 0) + return div_val; + + spin_lock_irqsave(d->lock, flags); + + /* Bypass the clock */ + val = readl(ls1x_clk->reg); + if (d->bypass_inv) + val &= ~BIT(d->bypass_shift); + else + val |= BIT(d->bypass_shift); + writel(val, ls1x_clk->reg); + + val = readl(ls1x_clk->reg); + val &= ~(clk_div_mask(d->width) << d->shift); + val |= (u32)div_val << d->shift; + writel(val, ls1x_clk->reg); + + /* Restore the clock */ + val = readl(ls1x_clk->reg); + if (d->bypass_inv) + val |= BIT(d->bypass_shift); + else + val &= ~BIT(d->bypass_shift); + writel(val, ls1x_clk->reg); + + spin_unlock_irqrestore(d->lock, flags); + + return 0; +} + +static const struct clk_ops ls1x_clk_divider_ops = { + .recalc_rate = ls1x_divider_recalc_rate, + .round_rate = ls1x_divider_round_rate, + .set_rate = ls1x_divider_set_rate, +}; + +#define LS1X_CLK_PLL(_name, _offset, _fixed, _shift, \ + f_shift, f_width, i_shift, i_width) \ +struct ls1x_clk _name = { \ + .offset = (_offset), \ + .data = &(const struct ls1x_clk_pll_data) { \ + .fixed = (_fixed), \ + .shift = (_shift), \ + .int_shift = (i_shift), \ + .int_width = (i_width), \ + .frac_shift = (f_shift), \ + .frac_width = (f_width), \ + }, \ + .hw.init = &(const struct clk_init_data) { \ + .name = #_name, \ + .ops = &ls1x_pll_clk_ops, \ + .parent_data = &(const struct clk_parent_data) { \ + .fw_name = "xtal", \ + .name = "xtal", \ + .index = -1, \ + }, \ + .num_parents = 1, \ + }, \ +} + +#define LS1X_CLK_DIV(_name, _pname, _offset, _shift, _width, \ + _table, _bypass_shift, _bypass_inv, _flags) \ +struct ls1x_clk _name = { \ + .offset = (_offset), \ + .data = &(const struct ls1x_clk_div_data){ \ + .shift = (_shift), \ + .width = (_width), \ + .table = (_table), \ + .flags = (_flags), \ + .bypass_shift = (_bypass_shift), \ + .bypass_inv = (_bypass_inv), \ + .lock = &ls1x_clk_div_lock, \ + }, \ + .hw.init = &(const struct clk_init_data) { \ + .name = #_name, \ + .ops = &ls1x_clk_divider_ops, \ + .parent_hws = (const struct clk_hw *[]) { _pname }, \ + .num_parents = 1, \ + .flags = CLK_GET_RATE_NOCACHE, \ + }, \ +} + +static LS1X_CLK_PLL(ls1b_clk_pll, CLK_PLL_FREQ, 12, 1, 0, 5, 0, 0); +static LS1X_CLK_DIV(ls1b_clk_cpu, &ls1b_clk_pll.hw, CLK_PLL_DIV, + 20, 4, NULL, 8, 0, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST); +static LS1X_CLK_DIV(ls1b_clk_dc, &ls1b_clk_pll.hw, CLK_PLL_DIV, + 26, 4, NULL, 12, 0, CLK_DIVIDER_ONE_BASED); +static LS1X_CLK_DIV(ls1b_clk_ahb, &ls1b_clk_pll.hw, CLK_PLL_DIV, + 14, 4, NULL, 10, 0, CLK_DIVIDER_ONE_BASED); +static CLK_FIXED_FACTOR(ls1b_clk_apb, "ls1b_clk_apb", "ls1b_clk_ahb", 2, 1, + CLK_SET_RATE_PARENT); + +static struct clk_hw_onecell_data ls1b_clk_hw_data = { + .hws = { + [LS1X_CLKID_PLL] = &ls1b_clk_pll.hw, + [LS1X_CLKID_CPU] = &ls1b_clk_cpu.hw, + [LS1X_CLKID_DC] = &ls1b_clk_dc.hw, + [LS1X_CLKID_AHB] = &ls1b_clk_ahb.hw, + [LS1X_CLKID_APB] = &ls1b_clk_apb.hw, + }, + .num = CLK_NR_CLKS, +}; + +static const struct clk_div_table ls1c_ahb_div_table[] = { + [0] = { .val = 0, .div = 2 }, + [1] = { .val = 1, .div = 4 }, + [2] = { .val = 2, .div = 3 }, + [3] = { .val = 3, .div = 3 }, + [4] = { /* sentinel */ } +}; + +static LS1X_CLK_PLL(ls1c_clk_pll, CLK_PLL_FREQ, 0, 2, 8, 8, 16, 8); +static LS1X_CLK_DIV(ls1c_clk_cpu, &ls1c_clk_pll.hw, CLK_PLL_DIV, + 8, 7, NULL, 0, 1, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST); +static LS1X_CLK_DIV(ls1c_clk_dc, &ls1c_clk_pll.hw, CLK_PLL_DIV, + 24, 7, NULL, 4, 1, CLK_DIVIDER_ONE_BASED); +static LS1X_CLK_DIV(ls1c_clk_ahb, &ls1c_clk_cpu.hw, CLK_PLL_FREQ, + 0, 2, ls1c_ahb_div_table, 0, 0, CLK_DIVIDER_ALLOW_ZERO); +static CLK_FIXED_FACTOR(ls1c_clk_apb, "ls1c_clk_apb", "ls1c_clk_ahb", 1, 1, + CLK_SET_RATE_PARENT); + +static struct clk_hw_onecell_data ls1c_clk_hw_data = { + .hws = { + [LS1X_CLKID_PLL] = &ls1c_clk_pll.hw, + [LS1X_CLKID_CPU] = &ls1c_clk_cpu.hw, + [LS1X_CLKID_DC] = &ls1c_clk_dc.hw, + [LS1X_CLKID_AHB] = &ls1c_clk_ahb.hw, + [LS1X_CLKID_APB] = &ls1c_clk_apb.hw, + }, + .num = CLK_NR_CLKS, +}; + +static void __init ls1x_clk_init(struct device_node *np, + struct clk_hw_onecell_data *hw_data) +{ + struct ls1x_clk *ls1x_clk; + void __iomem *reg; + int i, ret; + + reg = of_iomap(np, 0); + if (!reg) { + pr_err("Unable to map base for %pOF\n", np); + return; + } + + for (i = 0; i < hw_data->num; i++) { + /* array might be sparse */ + if (!hw_data->hws[i]) + continue; + + if (i != LS1X_CLKID_APB) { + ls1x_clk = to_ls1x_clk(hw_data->hws[i]); + ls1x_clk->reg = reg + ls1x_clk->offset; + } + + ret = of_clk_hw_register(np, hw_data->hws[i]); + if (ret) + goto err; + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, hw_data); + if (!ret) + return; + +err: + pr_err("Failed to register %pOF\n", np); + + while (--i >= 0) + clk_hw_unregister(hw_data->hws[i]); + + iounmap(reg); +} + +static void __init ls1b_clk_init(struct device_node *np) +{ + return ls1x_clk_init(np, &ls1b_clk_hw_data); +} + +static void __init ls1c_clk_init(struct device_node *np) +{ + return ls1x_clk_init(np, &ls1c_clk_hw_data); +} + +CLK_OF_DECLARE(ls1b_clk, "loongson,ls1b-clk", ls1b_clk_init); +CLK_OF_DECLARE(ls1c_clk, "loongson,ls1c-clk", ls1c_clk_init); diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c new file mode 100644 index 000000000000..70ae1dd2e474 --- /dev/null +++ b/drivers/clk/clk-loongson2.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Author: Yinbo Zhu + * Copyright (C) 2022-2023 Loongson Technology Corporation Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOONGSON2_PLL_MULT_SHIFT 32 +#define LOONGSON2_PLL_MULT_WIDTH 10 +#define LOONGSON2_PLL_DIV_SHIFT 26 +#define LOONGSON2_PLL_DIV_WIDTH 6 +#define LOONGSON2_APB_FREQSCALE_SHIFT 20 +#define LOONGSON2_APB_FREQSCALE_WIDTH 3 +#define LOONGSON2_USB_FREQSCALE_SHIFT 16 +#define LOONGSON2_USB_FREQSCALE_WIDTH 3 +#define LOONGSON2_SATA_FREQSCALE_SHIFT 12 +#define LOONGSON2_SATA_FREQSCALE_WIDTH 3 +#define LOONGSON2_BOOT_FREQSCALE_SHIFT 8 +#define LOONGSON2_BOOT_FREQSCALE_WIDTH 3 + +static void __iomem *loongson2_pll_base; + +static const struct clk_parent_data pdata[] = { + { .fw_name = "ref_100m",}, +}; + +static struct clk_hw *loongson2_clk_register(struct device *dev, + const char *name, + const char *parent_name, + const struct clk_ops *ops, + unsigned long flags) +{ + int ret; + struct clk_hw *hw; + struct clk_init_data init; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = ops; + init.flags = flags; + init.num_parents = 1; + + if (!parent_name) + init.parent_data = pdata; + else + init.parent_names = &parent_name; + + hw->init = &init; + + ret = devm_clk_hw_register(dev, hw); + if (ret) + hw = ERR_PTR(ret); + + return hw; +} + +static unsigned long loongson2_calc_pll_rate(int offset, unsigned long rate) +{ + u64 val; + u32 mult, div; + + val = readq(loongson2_pll_base + offset); + + mult = (val >> LOONGSON2_PLL_MULT_SHIFT) & + clk_div_mask(LOONGSON2_PLL_MULT_WIDTH); + div = (val >> LOONGSON2_PLL_DIV_SHIFT) & + clk_div_mask(LOONGSON2_PLL_DIV_WIDTH); + + return div_u64((u64)rate * mult, div); +} + +static unsigned long loongson2_node_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_pll_rate(0x0, parent_rate); +} + +static const struct clk_ops loongson2_node_clk_ops = { + .recalc_rate = loongson2_node_recalc_rate, +}; + +static unsigned long loongson2_ddr_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_pll_rate(0x10, parent_rate); +} + +static const struct clk_ops loongson2_ddr_clk_ops = { + .recalc_rate = loongson2_ddr_recalc_rate, +}; + +static unsigned long loongson2_dc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_pll_rate(0x20, parent_rate); +} + +static const struct clk_ops loongson2_dc_clk_ops = { + .recalc_rate = loongson2_dc_recalc_rate, +}; + +static unsigned long loongson2_pix0_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_pll_rate(0x30, parent_rate); +} + +static const struct clk_ops loongson2_pix0_clk_ops = { + .recalc_rate = loongson2_pix0_recalc_rate, +}; + +static unsigned long loongson2_pix1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_pll_rate(0x40, parent_rate); +} + +static const struct clk_ops loongson2_pix1_clk_ops = { + .recalc_rate = loongson2_pix1_recalc_rate, +}; + +static unsigned long loongson2_calc_rate(unsigned long rate, + int shift, int width) +{ + u64 val; + u32 mult; + + val = readq(loongson2_pll_base + 0x50); + + mult = (val >> shift) & clk_div_mask(width); + + return div_u64((u64)rate * (mult + 1), 8); +} + +static unsigned long loongson2_boot_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_rate(parent_rate, + LOONGSON2_BOOT_FREQSCALE_SHIFT, + LOONGSON2_BOOT_FREQSCALE_WIDTH); +} + +static const struct clk_ops loongson2_boot_clk_ops = { + .recalc_rate = loongson2_boot_recalc_rate, +}; + +static unsigned long loongson2_apb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_rate(parent_rate, + LOONGSON2_APB_FREQSCALE_SHIFT, + LOONGSON2_APB_FREQSCALE_WIDTH); +} + +static const struct clk_ops loongson2_apb_clk_ops = { + .recalc_rate = loongson2_apb_recalc_rate, +}; + +static unsigned long loongson2_usb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_rate(parent_rate, + LOONGSON2_USB_FREQSCALE_SHIFT, + LOONGSON2_USB_FREQSCALE_WIDTH); +} + +static const struct clk_ops loongson2_usb_clk_ops = { + .recalc_rate = loongson2_usb_recalc_rate, +}; + +static unsigned long loongson2_sata_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return loongson2_calc_rate(parent_rate, + LOONGSON2_SATA_FREQSCALE_SHIFT, + LOONGSON2_SATA_FREQSCALE_WIDTH); +} + +static const struct clk_ops loongson2_sata_clk_ops = { + .recalc_rate = loongson2_sata_recalc_rate, +}; + +static inline int loongson2_check_clk_hws(struct clk_hw *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (IS_ERR(clks[i])) { + pr_err("Loongson2 clk %u: register failed with %ld\n", + i, PTR_ERR(clks[i])); + return PTR_ERR(clks[i]); + } + + return 0; +} + +static int loongson2_clk_probe(struct platform_device *pdev) +{ + int ret; + struct clk_hw **hws; + struct clk_hw_onecell_data *clk_hw_data; + spinlock_t loongson2_clk_lock; + struct device *dev = &pdev->dev; + + loongson2_pll_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(loongson2_pll_base)) + return PTR_ERR(loongson2_pll_base); + + clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, LOONGSON2_CLK_END), + GFP_KERNEL); + if (WARN_ON(!clk_hw_data)) + return -ENOMEM; + + clk_hw_data->num = LOONGSON2_CLK_END; + hws = clk_hw_data->hws; + + hws[LOONGSON2_NODE_PLL] = loongson2_clk_register(dev, "node_pll", + NULL, + &loongson2_node_clk_ops, 0); + + hws[LOONGSON2_DDR_PLL] = loongson2_clk_register(dev, "ddr_pll", + NULL, + &loongson2_ddr_clk_ops, 0); + + hws[LOONGSON2_DC_PLL] = loongson2_clk_register(dev, "dc_pll", + NULL, + &loongson2_dc_clk_ops, 0); + + hws[LOONGSON2_PIX0_PLL] = loongson2_clk_register(dev, "pix0_pll", + NULL, + &loongson2_pix0_clk_ops, 0); + + hws[LOONGSON2_PIX1_PLL] = loongson2_clk_register(dev, "pix1_pll", + NULL, + &loongson2_pix1_clk_ops, 0); + + hws[LOONGSON2_BOOT_CLK] = loongson2_clk_register(dev, "boot", + NULL, + &loongson2_boot_clk_ops, 0); + + hws[LOONGSON2_NODE_CLK] = devm_clk_hw_register_divider(dev, "node", + "node_pll", 0, + loongson2_pll_base + 0x8, 0, + 6, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + /* + * The hda clk divisor in the upper 32bits and the clk-prodiver + * layer code doesn't support 64bit io operation thus a conversion + * is required that subtract shift by 32 and add 4byte to the hda + * address + */ + hws[LOONGSON2_HDA_CLK] = devm_clk_hw_register_divider(dev, "hda", + "ddr_pll", 0, + loongson2_pll_base + 0x22, 12, + 7, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_GPU_CLK] = devm_clk_hw_register_divider(dev, "gpu", + "ddr_pll", 0, + loongson2_pll_base + 0x18, 22, + 6, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_DDR_CLK] = devm_clk_hw_register_divider(dev, "ddr", + "ddr_pll", 0, + loongson2_pll_base + 0x18, 0, + 6, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_GMAC_CLK] = devm_clk_hw_register_divider(dev, "gmac", + "dc_pll", 0, + loongson2_pll_base + 0x28, 22, + 6, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_DC_CLK] = devm_clk_hw_register_divider(dev, "dc", + "dc_pll", 0, + loongson2_pll_base + 0x28, 0, + 6, CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_APB_CLK] = loongson2_clk_register(dev, "apb", + "gmac", + &loongson2_apb_clk_ops, 0); + + hws[LOONGSON2_USB_CLK] = loongson2_clk_register(dev, "usb", + "gmac", + &loongson2_usb_clk_ops, 0); + + hws[LOONGSON2_SATA_CLK] = loongson2_clk_register(dev, "sata", + "gmac", + &loongson2_sata_clk_ops, 0); + + hws[LOONGSON2_PIX0_CLK] = clk_hw_register_divider(NULL, "pix0", + "pix0_pll", 0, + loongson2_pll_base + 0x38, 0, 6, + CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + hws[LOONGSON2_PIX1_CLK] = clk_hw_register_divider(NULL, "pix1", + "pix1_pll", 0, + loongson2_pll_base + 0x48, 0, 6, + CLK_DIVIDER_ONE_BASED, + &loongson2_clk_lock); + + ret = loongson2_check_clk_hws(hws, LOONGSON2_CLK_END); + if (ret) + return ret; + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); +} + +static const struct of_device_id loongson2_clk_match_table[] = { + { .compatible = "loongson,ls2k-clk" }, + { } +}; +MODULE_DEVICE_TABLE(of, loongson2_clk_match_table); + +static struct platform_driver loongson2_clk_driver = { + .probe = loongson2_clk_probe, + .driver = { + .name = "loongson2-clk", + .of_match_table = loongson2_clk_match_table, + }, +}; +module_platform_driver(loongson2_clk_driver); + +MODULE_DESCRIPTION("Loongson2 clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c index 80b9d78493bc..050fd4fb588f 100644 --- a/drivers/clk/clk-milbeaut.c +++ b/drivers/clk/clk-milbeaut.c @@ -560,14 +560,12 @@ static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors *factors, static int m10v_clk_probe(struct platform_device *pdev) { int id; - struct resource *res; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; void __iomem *base; const char *parent_name; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index b8c3d0da1918..74a241b1e1f4 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -271,10 +271,9 @@ static int palmas_clks_probe(struct platform_device *pdev) return ret; } -static int palmas_clks_remove(struct platform_device *pdev) +static void palmas_clks_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - return 0; } static struct platform_driver palmas_clks_driver = { @@ -283,7 +282,7 @@ static struct platform_driver palmas_clks_driver = { .of_match_table = palmas_clks_of_match, }, .probe = palmas_clks_probe, - .remove = palmas_clks_remove, + .remove_new = palmas_clks_remove, }; module_platform_driver(palmas_clks_driver); diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index da2c8eddfd9f..3dd2b83d0404 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -129,11 +129,9 @@ static int clk_pwm_probe(struct platform_device *pdev) return of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clk_pwm->hw); } -static int clk_pwm_remove(struct platform_device *pdev) +static void clk_pwm_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - - return 0; } static const struct of_device_id clk_pwm_dt_ids[] = { @@ -144,7 +142,7 @@ MODULE_DEVICE_TABLE(of, clk_pwm_dt_ids); static struct platform_driver clk_pwm_driver = { .probe = clk_pwm_probe, - .remove = clk_pwm_remove, + .remove_new = clk_pwm_remove, .driver = { .name = "pwm-clock", .of_match_table = clk_pwm_dt_ids, diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index ff3a52d48479..10d31c222a1c 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -6,6 +6,7 @@ * - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ * Currently supported: * - 9FGV0241 + * - 9FGV0441 * * Copyright (C) 2022 Marek Vasut */ @@ -18,7 +19,6 @@ #include #define RS9_REG_OE 0x0 -#define RS9_REG_OE_DIF_OE(n) BIT((n) + 1) #define RS9_REG_SS 0x1 #define RS9_REG_SS_AMP_0V6 0x0 #define RS9_REG_SS_AMP_0V7 0x1 @@ -31,9 +31,6 @@ #define RS9_REG_SS_SSC_MASK (3 << 3) #define RS9_REG_SS_SSC_LOCK BIT(5) #define RS9_REG_SR 0x2 -#define RS9_REG_SR_2V0_DIF(n) 0 -#define RS9_REG_SR_3V0_DIF(n) BIT((n) + 1) -#define RS9_REG_SR_DIF_MASK(n) BIT((n) + 1) #define RS9_REG_REF 0x3 #define RS9_REG_REF_OE BIT(4) #define RS9_REG_REF_OD BIT(5) @@ -45,22 +42,31 @@ #define RS9_REG_DID 0x6 #define RS9_REG_BCP 0x7 +#define RS9_REG_VID_IDT 0x01 + +#define RS9_REG_DID_TYPE_FGV (0x0 << RS9_REG_DID_TYPE_SHIFT) +#define RS9_REG_DID_TYPE_DBV (0x1 << RS9_REG_DID_TYPE_SHIFT) +#define RS9_REG_DID_TYPE_DMV (0x2 << RS9_REG_DID_TYPE_SHIFT) +#define RS9_REG_DID_TYPE_SHIFT 0x6 + /* Supported Renesas 9-series models. */ enum rs9_model { RENESAS_9FGV0241, + RENESAS_9FGV0441, }; /* Structure to describe features of a particular 9-series model */ struct rs9_chip_info { const enum rs9_model model; unsigned int num_clks; + u8 did; }; struct rs9_driver_data { struct i2c_client *client; struct regmap *regmap; const struct rs9_chip_info *chip_info; - struct clk_hw *clk_dif[2]; + struct clk_hw *clk_dif[4]; u8 pll_amplitude; u8 pll_ssc; u8 clk_dif_sr; @@ -152,17 +158,29 @@ static const struct regmap_config rs9_regmap_config = { .reg_read = rs9_regmap_i2c_read, }; +static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx) +{ + enum rs9_model model = rs9->chip_info->model; + + if (model == RENESAS_9FGV0241) + return BIT(idx) + 1; + else if (model == RENESAS_9FGV0441) + return BIT(idx); + + return 0; +} + static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) { struct i2c_client *client = rs9->client; + u8 dif = rs9_calc_dif(rs9, idx); unsigned char name[5] = "DIF0"; struct device_node *np; int ret; u32 sr; /* Set defaults */ - rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); - rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx); + rs9->clk_dif_sr |= dif; snprintf(name, 5, "DIF%d", idx); np = of_get_child_by_name(client->dev.of_node, name); @@ -174,11 +192,9 @@ static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) of_node_put(np); if (!ret) { if (sr == 2000000) { /* 2V/ns */ - rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); - rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx); + rs9->clk_dif_sr &= ~dif; } else if (sr == 3000000) { /* 3V/ns (default) */ - rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); - rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx); + rs9->clk_dif_sr |= dif; } else ret = dev_err_probe(&client->dev, -EINVAL, "Invalid renesas,slew-rate value\n"); @@ -249,11 +265,13 @@ static void rs9_update_config(struct rs9_driver_data *rs9) } for (i = 0; i < rs9->chip_info->num_clks; i++) { - if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i)) + u8 dif = rs9_calc_dif(rs9, i); + + if (rs9->clk_dif_sr & dif) continue; - regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i), - rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i)); + regmap_update_bits(rs9->regmap, RS9_REG_SR, dif, + rs9->clk_dif_sr & dif); } } @@ -270,6 +288,7 @@ static int rs9_probe(struct i2c_client *client) { unsigned char name[5] = "DIF0"; struct rs9_driver_data *rs9; + unsigned int vid, did; struct clk_hw *hw; int i, ret; @@ -306,6 +325,20 @@ static int rs9_probe(struct i2c_client *client) if (ret < 0) return ret; + ret = regmap_read(rs9->regmap, RS9_REG_VID, &vid); + if (ret < 0) + return ret; + + ret = regmap_read(rs9->regmap, RS9_REG_DID, &did); + if (ret < 0) + return ret; + + if (vid != RS9_REG_VID_IDT || did != rs9->chip_info->did) + return dev_err_probe(&client->dev, -ENODEV, + "Incorrect VID/DID: %#02x, %#02x. Expected %#02x, %#02x\n", + vid, did, RS9_REG_VID_IDT, + rs9->chip_info->did); + /* Register clock */ for (i = 0; i < rs9->chip_info->num_clks; i++) { snprintf(name, 5, "DIF%d", i); @@ -349,16 +382,25 @@ static int __maybe_unused rs9_resume(struct device *dev) static const struct rs9_chip_info renesas_9fgv0241_info = { .model = RENESAS_9FGV0241, .num_clks = 2, + .did = RS9_REG_DID_TYPE_FGV | 0x02, +}; + +static const struct rs9_chip_info renesas_9fgv0441_info = { + .model = RENESAS_9FGV0441, + .num_clks = 4, + .did = RS9_REG_DID_TYPE_FGV | 0x04, }; static const struct i2c_device_id rs9_id[] = { { "9fgv0241", .driver_data = RENESAS_9FGV0241 }, + { "9fgv0441", .driver_data = RENESAS_9FGV0441 }, { } }; MODULE_DEVICE_TABLE(i2c, rs9_id); static const struct of_device_id clk_rs9_of_match[] = { { .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info }, + { .compatible = "renesas,9fgv0441", .data = &renesas_9fgv0441_info }, { } }; MODULE_DEVICE_TABLE(of, clk_rs9_of_match); diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index a3e883a9f406..38c456540d1b 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -202,7 +202,7 @@ err_reg: return ret; } -static int s2mps11_clk_remove(struct platform_device *pdev) +static void s2mps11_clk_remove(struct platform_device *pdev) { struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev); int i; @@ -217,8 +217,6 @@ static int s2mps11_clk_remove(struct platform_device *pdev) continue; clkdev_drop(s2mps11_clks[i].lookup); } - - return 0; } static const struct platform_device_id s2mps11_clk_id[] = { @@ -265,7 +263,7 @@ static struct platform_driver s2mps11_clk_driver = { .name = "s2mps11-clk", }, .probe = s2mps11_clk_probe, - .remove = s2mps11_clk_remove, + .remove_new = s2mps11_clk_remove, .id_table = s2mps11_clk_id, }; module_platform_driver(s2mps11_clk_driver); diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index a39af7616b13..3fb4003453ee 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -246,7 +246,7 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, return of_clk_add_hw_provider(np, scpi_of_clk_src_get, clk_data); } -static int scpi_clocks_remove(struct platform_device *pdev) +static void scpi_clocks_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child, *np = dev->of_node; @@ -258,7 +258,6 @@ static int scpi_clocks_remove(struct platform_device *pdev) for_each_available_child_of_node(np, child) of_clk_del_provider(np); - return 0; } static int scpi_clocks_probe(struct platform_device *pdev) @@ -305,7 +304,7 @@ static struct platform_driver scpi_clocks_driver = { .of_match_table = scpi_clocks_ids, }, .probe = scpi_clocks_probe, - .remove = scpi_clocks_remove, + .remove_new = scpi_clocks_remove, }; module_platform_driver(scpi_clocks_driver); diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index c028fa103bed..cabdd8e8f4db 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -360,8 +360,8 @@ static int si514_probe(struct i2c_client *client) dev_err(&client->dev, "clock registration failed\n"); return err; } - err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, - &data->hw); + err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; @@ -370,11 +370,6 @@ static int si514_probe(struct i2c_client *client) return 0; } -static void si514_remove(struct i2c_client *client) -{ - of_clk_del_provider(client->dev.of_node); -} - static const struct i2c_device_id si514_id[] = { { "si514", 0 }, { } @@ -393,7 +388,6 @@ static struct i2c_driver si514_driver = { .of_match_table = clk_si514_of_match, }, .probe_new = si514_probe, - .remove = si514_remove, .id_table = si514_id, }; module_i2c_driver(si514_driver); diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c new file mode 100644 index 000000000000..ac8d4c59cd3d --- /dev/null +++ b/drivers/clk/clk-si521xx.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Skyworks Si521xx PCIe clock generator driver + * + * The following series can be supported: + * - Si52144 - 4x DIFF + * - Si52146 - 6x DIFF + * - Si52147 - 9x DIFF + * Currently tested: + * - Si52144 + * + * Copyright (C) 2022 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* OE1 and OE2 register */ +#define SI521XX_REG_OE(n) (((n) & 0x1) + 1) +#define SI521XX_REG_ID 0x3 +#define SI521XX_REG_ID_PROG GENMASK(7, 4) +#define SI521XX_REG_ID_VENDOR GENMASK(3, 0) +#define SI521XX_REG_BC 0x4 +#define SI521XX_REG_DA 0x5 +#define SI521XX_REG_DA_AMP_SEL BIT(7) +#define SI521XX_REG_DA_AMP_MASK GENMASK(6, 4) +#define SI521XX_REG_DA_AMP_MIN 300000 +#define SI521XX_REG_DA_AMP_DEFAULT 800000 +#define SI521XX_REG_DA_AMP_MAX 1000000 +#define SI521XX_REG_DA_AMP_STEP 100000 +#define SI521XX_REG_DA_AMP(UV) \ + FIELD_PREP(SI521XX_REG_DA_AMP_MASK, \ + ((UV) - SI521XX_REG_DA_AMP_MIN) / SI521XX_REG_DA_AMP_STEP) +#define SI521XX_REG_DA_UNKNOWN BIT(3) /* Always set */ + +/* Count of populated OE bits in control register ref, 1 and 2 */ +#define SI521XX_OE_MAP(cr1, cr2) (((cr2) << 8) | (cr1)) +#define SI521XX_OE_MAP_GET_OE(oe, map) (((map) >> (((oe) - 1) * 8)) & 0xff) + +#define SI521XX_DIFF_MULT 4 +#define SI521XX_DIFF_DIV 1 + +/* Supported Skyworks Si521xx models. */ +enum si521xx_model { + SI52144 = 0x44, + SI52146 = 0x46, + SI52147 = 0x47, +}; + +struct si521xx; + +struct si_clk { + struct clk_hw hw; + struct si521xx *si; + u8 reg; + u8 bit; +}; + +struct si521xx { + struct i2c_client *client; + struct regmap *regmap; + struct si_clk clk_dif[9]; + u16 chip_info; + u8 pll_amplitude; +}; + +/* + * Si521xx i2c regmap + */ +static const struct regmap_range si521xx_readable_ranges[] = { + regmap_reg_range(SI521XX_REG_OE(0), SI521XX_REG_DA), +}; + +static const struct regmap_access_table si521xx_readable_table = { + .yes_ranges = si521xx_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(si521xx_readable_ranges), +}; + +static const struct regmap_range si521xx_writeable_ranges[] = { + regmap_reg_range(SI521XX_REG_OE(0), SI521XX_REG_OE(1)), + regmap_reg_range(SI521XX_REG_BC, SI521XX_REG_DA), +}; + +static const struct regmap_access_table si521xx_writeable_table = { + .yes_ranges = si521xx_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(si521xx_writeable_ranges), +}; + +static int si521xx_regmap_i2c_write(void *context, unsigned int reg, + unsigned int val) +{ + struct i2c_client *i2c = context; + const u8 data[3] = { reg, 1, val }; + const int count = ARRAY_SIZE(data); + int ret; + + ret = i2c_master_send(i2c, data, count); + if (ret == count) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} + +static int si521xx_regmap_i2c_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct i2c_client *i2c = context; + struct i2c_msg xfer[2]; + u8 txdata = reg; + u8 rxdata[2]; + int ret; + + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = (void *)&txdata; + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (void *)rxdata; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + /* + * Byte 0 is transfer length, which is always 1 due + * to BCP register programming to 1 in si521xx_probe(), + * ignore it and use data from Byte 1. + */ + *val = rxdata[1]; + return 0; +} + +static const struct regmap_config si521xx_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, + .max_register = SI521XX_REG_DA, + .rd_table = &si521xx_readable_table, + .wr_table = &si521xx_writeable_table, + .reg_write = si521xx_regmap_i2c_write, + .reg_read = si521xx_regmap_i2c_read, +}; + +static unsigned long si521xx_diff_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long long rate; + + rate = (unsigned long long)parent_rate * SI521XX_DIFF_MULT; + do_div(rate, SI521XX_DIFF_DIV); + return (unsigned long)rate; +} + +static long si521xx_diff_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long best_parent; + + best_parent = (rate / SI521XX_DIFF_MULT) * SI521XX_DIFF_DIV; + *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); + + return (*prate / SI521XX_DIFF_DIV) * SI521XX_DIFF_MULT; +} + +static int si521xx_diff_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + /* + * We must report success but we can do so unconditionally because + * si521xx_diff_round_rate returns values that ensure this call is a + * nop. + */ + + return 0; +} + +#define to_si521xx_clk(_hw) container_of(_hw, struct si_clk, hw) + +static int si521xx_diff_prepare(struct clk_hw *hw) +{ + struct si_clk *si_clk = to_si521xx_clk(hw); + struct si521xx *si = si_clk->si; + + regmap_set_bits(si->regmap, SI521XX_REG_OE(si_clk->reg), si_clk->bit); + + return 0; +} + +static void si521xx_diff_unprepare(struct clk_hw *hw) +{ + struct si_clk *si_clk = to_si521xx_clk(hw); + struct si521xx *si = si_clk->si; + + regmap_clear_bits(si->regmap, SI521XX_REG_OE(si_clk->reg), si_clk->bit); +} + +static const struct clk_ops si521xx_diff_clk_ops = { + .round_rate = si521xx_diff_round_rate, + .set_rate = si521xx_diff_set_rate, + .recalc_rate = si521xx_diff_recalc_rate, + .prepare = si521xx_diff_prepare, + .unprepare = si521xx_diff_unprepare, +}; + +static int si521xx_get_common_config(struct si521xx *si) +{ + struct i2c_client *client = si->client; + struct device_node *np = client->dev.of_node; + unsigned int amp; + int ret; + + /* Set defaults */ + si->pll_amplitude = SI521XX_REG_DA_AMP(SI521XX_REG_DA_AMP_DEFAULT); + + /* Output clock amplitude */ + ret = of_property_read_u32(np, "skyworks,out-amplitude-microvolt", + &); + if (!ret) { + if (amp < SI521XX_REG_DA_AMP_MIN || amp > SI521XX_REG_DA_AMP_MAX || + amp % SI521XX_REG_DA_AMP_STEP) { + return dev_err_probe(&client->dev, -EINVAL, + "Invalid skyworks,out-amplitude-microvolt value\n"); + } + si->pll_amplitude = SI521XX_REG_DA_AMP(amp); + } + + return 0; +} + +static void si521xx_update_config(struct si521xx *si) +{ + /* If amplitude is non-default, update it. */ + if (si->pll_amplitude == SI521XX_REG_DA_AMP(SI521XX_REG_DA_AMP_DEFAULT)) + return; + + regmap_update_bits(si->regmap, SI521XX_REG_DA, + SI521XX_REG_DA_AMP_MASK, si->pll_amplitude); +} + +static void si521xx_diff_idx_to_reg_bit(const u16 chip_info, const int idx, + struct si_clk *clk) +{ + unsigned long mask; + int oe, b, ctr = 0; + + for (oe = 1; oe <= 2; oe++) { + mask = bitrev8(SI521XX_OE_MAP_GET_OE(oe, chip_info)); + for_each_set_bit(b, &mask, 8) { + if (ctr++ != idx) + continue; + clk->reg = SI521XX_REG_OE(oe); + clk->bit = 7 - b; + return; + } + } +} + +static struct clk_hw * +si521xx_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct si521xx *si = data; + unsigned int idx = clkspec->args[0]; + + return &si->clk_dif[idx].hw; +} + +static int si521xx_probe(struct i2c_client *client) +{ + const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev); + const struct clk_parent_data clk_parent_data = { .index = 0 }; + struct si521xx *si; + unsigned char name[6] = "DIFF0"; + struct clk_init_data init = {}; + int i, ret; + + if (!chip_info) + return -EINVAL; + + si = devm_kzalloc(&client->dev, sizeof(*si), GFP_KERNEL); + if (!si) + return -ENOMEM; + + i2c_set_clientdata(client, si); + si->client = client; + + /* Fetch common configuration from DT (if specified) */ + ret = si521xx_get_common_config(si); + if (ret) + return ret; + + si->regmap = devm_regmap_init(&client->dev, NULL, client, + &si521xx_regmap_config); + if (IS_ERR(si->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(si->regmap), + "Failed to allocate register map\n"); + + /* Always read back 1 Byte via I2C */ + ret = regmap_write(si->regmap, SI521XX_REG_BC, 1); + if (ret < 0) + return ret; + + /* Register clock */ + for (i = 0; i < hweight16(chip_info); i++) { + memset(&init, 0, sizeof(init)); + snprintf(name, 6, "DIFF%d", i); + init.name = name; + init.ops = &si521xx_diff_clk_ops; + init.parent_data = &clk_parent_data; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + + si->clk_dif[i].hw.init = &init; + si->clk_dif[i].si = si; + + si521xx_diff_idx_to_reg_bit(chip_info, i, &si->clk_dif[i]); + + ret = devm_clk_hw_register(&client->dev, &si->clk_dif[i].hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&client->dev, si521xx_of_clk_get, si); + if (!ret) + si521xx_update_config(si); + + return ret; +} + +static int __maybe_unused si521xx_suspend(struct device *dev) +{ + struct si521xx *si = dev_get_drvdata(dev); + + regcache_cache_only(si->regmap, true); + regcache_mark_dirty(si->regmap); + + return 0; +} + +static int __maybe_unused si521xx_resume(struct device *dev) +{ + struct si521xx *si = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(si->regmap, false); + ret = regcache_sync(si->regmap); + if (ret) + dev_err(dev, "Failed to restore register map: %d\n", ret); + return ret; +} + +static const struct i2c_device_id si521xx_id[] = { + { "si52144", .driver_data = SI521XX_OE_MAP(0x5, 0xc0) }, + { "si52146", .driver_data = SI521XX_OE_MAP(0x15, 0xe0) }, + { "si52147", .driver_data = SI521XX_OE_MAP(0x17, 0xf8) }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si521xx_id); + +static const struct of_device_id clk_si521xx_of_match[] = { + { .compatible = "skyworks,si52144", .data = (void *)SI521XX_OE_MAP(0x5, 0xc0) }, + { .compatible = "skyworks,si52146", .data = (void *)SI521XX_OE_MAP(0x15, 0xe0) }, + { .compatible = "skyworks,si52147", .data = (void *)SI521XX_OE_MAP(0x15, 0xf8) }, + { } +}; +MODULE_DEVICE_TABLE(of, clk_si521xx_of_match); + +static SIMPLE_DEV_PM_OPS(si521xx_pm_ops, si521xx_suspend, si521xx_resume); + +static struct i2c_driver si521xx_driver = { + .driver = { + .name = "clk-si521xx", + .pm = &si521xx_pm_ops, + .of_match_table = clk_si521xx_of_match, + }, + .probe_new = si521xx_probe, + .id_table = si521xx_id, +}; +module_i2c_driver(si521xx_driver); + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("Skyworks Si521xx PCIe clock generator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 9e939c98a455..4fcf7056717e 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1641,8 +1641,8 @@ static int si5351_i2c_probe(struct i2c_client *client) } } - ret = of_clk_add_hw_provider(client->dev.of_node, si53351_of_clk_get, - drvdata); + ret = devm_of_clk_add_hw_provider(&client->dev, si53351_of_clk_get, + drvdata); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); return ret; @@ -1651,18 +1651,12 @@ static int si5351_i2c_probe(struct i2c_client *client) return 0; } -static void si5351_i2c_remove(struct i2c_client *client) -{ - of_clk_del_provider(client->dev.of_node); -} - static struct i2c_driver si5351_driver = { .driver = { .name = "si5351", .of_match_table = of_match_ptr(si5351_dt_ids), }, .probe_new = si5351_i2c_probe, - .remove = si5351_i2c_remove, .id_table = si5351_i2c_ids, }; module_i2c_driver(si5351_driver); diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index 0a6d70c49726..0b834e9efb4b 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -474,8 +474,8 @@ static int si570_probe(struct i2c_client *client) dev_err(&client->dev, "clock registration failed\n"); return err; } - err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, - &data->hw); + err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; @@ -485,10 +485,8 @@ static int si570_probe(struct i2c_client *client) if (!of_property_read_u32(client->dev.of_node, "clock-frequency", &initial_fout)) { err = clk_set_rate(data->hw.clk, initial_fout); - if (err) { - of_clk_del_provider(client->dev.of_node); + if (err) return err; - } } /* Display a message indicating that we've successfully registered */ @@ -498,11 +496,6 @@ static int si570_probe(struct i2c_client *client) return 0; } -static void si570_remove(struct i2c_client *client) -{ - of_clk_del_provider(client->dev.of_node); -} - static const struct of_device_id clk_si570_of_match[] = { { .compatible = "silabs,si570" }, { .compatible = "silabs,si571" }, @@ -518,7 +511,6 @@ static struct i2c_driver si570_driver = { .of_match_table = clk_si570_of_match, }, .probe_new = si570_probe, - .remove = si570_remove, .id_table = si570_id, }; module_i2c_driver(si570_driver); diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c new file mode 100644 index 000000000000..11d22043ddd7 --- /dev/null +++ b/drivers/clk/clk-sp7021.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright (C) Sunplus Technology Co., Ltd. + * All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* speical div_width values for PLLTV/PLLA */ +#define DIV_TV 33 +#define DIV_A 34 + +/* PLLTV parameters */ +enum { + SEL_FRA, + SDM_MOD, + PH_SEL, + NFRA, + DIVR, + DIVN, + DIVM, + P_MAX +}; + +#define MASK_SEL_FRA GENMASK(1, 1) +#define MASK_SDM_MOD GENMASK(2, 2) +#define MASK_PH_SEL GENMASK(4, 4) +#define MASK_NFRA GENMASK(12, 6) +#define MASK_DIVR GENMASK(8, 7) +#define MASK_DIVN GENMASK(7, 0) +#define MASK_DIVM GENMASK(14, 8) + +/* HIWORD_MASK FIELD_PREP */ +#define HWM_FIELD_PREP(mask, value) \ +({ \ + u64 _m = mask; \ + (_m << 16) | FIELD_PREP(_m, value); \ +}) + +struct sp_pll { + struct clk_hw hw; + void __iomem *reg; + spinlock_t lock; /* lock for reg */ + int div_shift; + int div_width; + int pd_bit; /* power down bit idx */ + int bp_bit; /* bypass bit idx */ + unsigned long brate; /* base rate, TODO: replace brate with muldiv */ + u32 p[P_MAX]; /* for hold PLLTV/PLLA parameters */ +}; + +#define to_sp_pll(_hw) container_of(_hw, struct sp_pll, hw) + +struct sp_clk_gate_info { + u16 reg; /* reg_index_shift */ + u16 ext_parent; /* parent is extclk */ +}; + +static const struct sp_clk_gate_info sp_clk_gates[] = { + { 0x02 }, + { 0x05 }, + { 0x06 }, + { 0x07 }, + { 0x09 }, + { 0x0b, 1 }, + { 0x0f, 1 }, + { 0x14 }, + { 0x15 }, + { 0x16 }, + { 0x17 }, + { 0x18, 1 }, + { 0x19, 1 }, + { 0x1a, 1 }, + { 0x1b, 1 }, + { 0x1c, 1 }, + { 0x1d, 1 }, + { 0x1e }, + { 0x1f, 1 }, + { 0x20 }, + { 0x21 }, + { 0x22 }, + { 0x23 }, + { 0x24 }, + { 0x25 }, + { 0x26 }, + { 0x2a }, + { 0x2b }, + { 0x2d }, + { 0x2e }, + { 0x30 }, + { 0x31 }, + { 0x32 }, + { 0x33 }, + { 0x3d }, + { 0x3e }, + { 0x3f }, + { 0x42 }, + { 0x44 }, + { 0x4b }, + { 0x4c }, + { 0x4d }, + { 0x4e }, + { 0x4f }, + { 0x50 }, + { 0x55 }, + { 0x60 }, + { 0x61 }, + { 0x6a }, + { 0x73 }, + { 0x86 }, + { 0x8a }, + { 0x8b }, + { 0x8d }, + { 0x8e }, + { 0x8f }, + { 0x90 }, + { 0x92 }, + { 0x93 }, + { 0x95 }, + { 0x96 }, + { 0x97 }, + { 0x98 }, + { 0x99 }, +}; + +#define _M 1000000UL +#define F_27M (27 * _M) + +/*********************************** PLL_TV **********************************/ + +/* TODO: set proper FVCO range */ +#define FVCO_MIN (100 * _M) +#define FVCO_MAX (200 * _M) + +#define F_MIN (FVCO_MIN / 8) +#define F_MAX (FVCO_MAX) + +static long plltv_integer_div(struct sp_pll *clk, unsigned long freq) +{ + /* valid m values: 27M must be divisible by m */ + static const u32 m_table[] = { + 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32 + }; + u32 m, n, r; + unsigned long fvco, nf; + long ret; + + freq = clamp(freq, F_MIN, F_MAX); + + /* DIVR 0~3 */ + for (r = 0; r <= 3; r++) { + fvco = freq << r; + if (fvco <= FVCO_MAX) + break; + } + + /* DIVM */ + for (m = 0; m < ARRAY_SIZE(m_table); m++) { + nf = fvco * m_table[m]; + n = nf / F_27M; + if ((n * F_27M) == nf) + break; + } + if (m >= ARRAY_SIZE(m_table)) { + ret = -EINVAL; + goto err_not_found; + } + + /* save parameters */ + clk->p[SEL_FRA] = 0; + clk->p[DIVR] = r; + clk->p[DIVN] = n; + clk->p[DIVM] = m_table[m]; + + return freq; + +err_not_found: + pr_err("%s: %s freq:%lu not found a valid setting\n", + __func__, clk_hw_get_name(&clk->hw), freq); + + return ret; +} + +/* parameters for PLLTV fractional divider */ +static const u32 pt[][5] = { + /* conventional fractional */ + { + 1, /* factor */ + 5, /* 5 * p0 (nint) */ + 1, /* 1 * p0 */ + F_27M, /* F_27M / p0 */ + 1, /* p0 / p2 */ + }, + /* phase rotation */ + { + 10, /* factor */ + 54, /* 5.4 * p0 (nint) */ + 2, /* 0.2 * p0 */ + F_27M / 10, /* F_27M / p0 */ + 5, /* p0 / p2 */ + }, +}; + +static const u32 sdm_mod_vals[] = { 91, 55 }; + +static long plltv_fractional_div(struct sp_pll *clk, unsigned long freq) +{ + u32 m, r; + u32 nint, nfra; + u32 df_quotient_min = 210000000; + u32 df_remainder_min = 0; + unsigned long fvco, nf, f, fout = 0; + int sdm, ph; + + freq = clamp(freq, F_MIN, F_MAX); + + /* DIVR 0~3 */ + for (r = 0; r <= 3; r++) { + fvco = freq << r; + if (fvco <= FVCO_MAX) + break; + } + f = F_27M >> r; + + /* PH_SEL */ + for (ph = ARRAY_SIZE(pt) - 1; ph >= 0; ph--) { + const u32 *pp = pt[ph]; + + /* SDM_MOD */ + for (sdm = 0; sdm < ARRAY_SIZE(sdm_mod_vals); sdm++) { + u32 mod = sdm_mod_vals[sdm]; + + /* DIVM 1~32 */ + for (m = 1; m <= 32; m++) { + u32 df; /* diff freq */ + u32 df_quotient, df_remainder; + + nf = fvco * m; + nint = nf / pp[3]; + + if (nint < pp[1]) + continue; + if (nint > pp[1]) + break; + + nfra = (((nf % pp[3]) * mod * pp[4]) + (F_27M / 2)) / F_27M; + if (nfra) { + u32 df0 = f * (nint + pp[2]) / pp[0]; + u32 df1 = f * (mod - nfra) / mod / pp[4]; + + df = df0 - df1; + } else { + df = f * (nint) / pp[0]; + } + + df_quotient = df / m; + df_remainder = ((df % m) * 1000) / m; + + if (freq > df_quotient) { + df_quotient = freq - df_quotient - 1; + df_remainder = 1000 - df_remainder; + } else { + df_quotient = df_quotient - freq; + } + + if (df_quotient_min > df_quotient || + (df_quotient_min == df_quotient && + df_remainder_min > df_remainder)) { + /* found a closer freq, save parameters */ + clk->p[SEL_FRA] = 1; + clk->p[SDM_MOD] = sdm; + clk->p[PH_SEL] = ph; + clk->p[NFRA] = nfra; + clk->p[DIVR] = r; + clk->p[DIVM] = m; + + fout = df / m; + df_quotient_min = df_quotient; + df_remainder_min = df_remainder; + } + } + } + } + + if (!fout) { + pr_err("%s: %s freq:%lu not found a valid setting\n", + __func__, clk_hw_get_name(&clk->hw), freq); + return -EINVAL; + } + + return fout; +} + +static long plltv_div(struct sp_pll *clk, unsigned long freq) +{ + if (freq % 100) + return plltv_fractional_div(clk, freq); + + return plltv_integer_div(clk, freq); +} + +static int plltv_set_rate(struct sp_pll *clk) +{ + unsigned long flags; + u32 r0, r1, r2; + + r0 = BIT(clk->bp_bit + 16); + r0 |= HWM_FIELD_PREP(MASK_SEL_FRA, clk->p[SEL_FRA]); + r0 |= HWM_FIELD_PREP(MASK_SDM_MOD, clk->p[SDM_MOD]); + r0 |= HWM_FIELD_PREP(MASK_PH_SEL, clk->p[PH_SEL]); + r0 |= HWM_FIELD_PREP(MASK_NFRA, clk->p[NFRA]); + + r1 = HWM_FIELD_PREP(MASK_DIVR, clk->p[DIVR]); + + r2 = HWM_FIELD_PREP(MASK_DIVN, clk->p[DIVN] - 1); + r2 |= HWM_FIELD_PREP(MASK_DIVM, clk->p[DIVM] - 1); + + spin_lock_irqsave(&clk->lock, flags); + writel(r0, clk->reg); + writel(r1, clk->reg + 4); + writel(r2, clk->reg + 8); + spin_unlock_irqrestore(&clk->lock, flags); + + return 0; +} + +/*********************************** PLL_A ***********************************/ + +/* from Q628_PLLs_REG_setting.xlsx */ +static const struct { + u32 rate; + u32 regs[5]; +} pa[] = { + { + .rate = 135475200, + .regs = { + 0x4801, + 0x02df, + 0x248f, + 0x0211, + 0x33e9 + } + }, + { + .rate = 147456000, + .regs = { + 0x4801, + 0x1adf, + 0x2490, + 0x0349, + 0x33e9 + } + }, + { + .rate = 196608000, + .regs = { + 0x4801, + 0x42ef, + 0x2495, + 0x01c6, + 0x33e9 + } + }, +}; + +static int plla_set_rate(struct sp_pll *clk) +{ + const u32 *pp = pa[clk->p[0]].regs; + unsigned long flags; + int i; + + spin_lock_irqsave(&clk->lock, flags); + for (i = 0; i < ARRAY_SIZE(pa->regs); i++) + writel(0xffff0000 | pp[i], clk->reg + (i * 4)); + spin_unlock_irqrestore(&clk->lock, flags); + + return 0; +} + +static long plla_round_rate(struct sp_pll *clk, unsigned long rate) +{ + int i = ARRAY_SIZE(pa); + + while (--i) { + if (rate >= pa[i].rate) + break; + } + clk->p[0] = i; + + return pa[i].rate; +} + +/********************************** SP_PLL ***********************************/ + +static long sp_pll_calc_div(struct sp_pll *clk, unsigned long rate) +{ + u32 fbdiv; + u32 max = 1 << clk->div_width; + + fbdiv = DIV_ROUND_CLOSEST(rate, clk->brate); + if (fbdiv > max) + fbdiv = max; + + return fbdiv; +} + +static long sp_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct sp_pll *clk = to_sp_pll(hw); + long ret; + + if (rate == *prate) { + ret = *prate; /* bypass */ + } else if (clk->div_width == DIV_A) { + ret = plla_round_rate(clk, rate); + } else if (clk->div_width == DIV_TV) { + ret = plltv_div(clk, rate); + if (ret < 0) + ret = *prate; + } else { + ret = sp_pll_calc_div(clk, rate) * clk->brate; + } + + return ret; +} + +static unsigned long sp_pll_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct sp_pll *clk = to_sp_pll(hw); + u32 reg = readl(clk->reg); + unsigned long ret; + + if (reg & BIT(clk->bp_bit)) { + ret = prate; /* bypass */ + } else if (clk->div_width == DIV_A) { + ret = pa[clk->p[0]].rate; + } else if (clk->div_width == DIV_TV) { + u32 m, r, reg2; + + r = FIELD_GET(MASK_DIVR, readl(clk->reg + 4)); + reg2 = readl(clk->reg + 8); + m = FIELD_GET(MASK_DIVM, reg2) + 1; + + if (reg & MASK_SEL_FRA) { + /* fractional divider */ + u32 sdm = FIELD_GET(MASK_SDM_MOD, reg); + u32 ph = FIELD_GET(MASK_PH_SEL, reg); + u32 nfra = FIELD_GET(MASK_NFRA, reg); + const u32 *pp = pt[ph]; + unsigned long r0, r1; + + ret = prate >> r; + r0 = ret * (pp[1] + pp[2]) / pp[0]; + r1 = ret * (sdm_mod_vals[sdm] - nfra) / sdm_mod_vals[sdm] / pp[4]; + ret = (r0 - r1) / m; + } else { + /* integer divider */ + u32 n = FIELD_GET(MASK_DIVN, reg2) + 1; + + ret = (prate / m * n) >> r; + } + } else { + u32 fbdiv = ((reg >> clk->div_shift) & ((1 << clk->div_width) - 1)) + 1; + + ret = clk->brate * fbdiv; + } + + return ret; +} + +static int sp_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct sp_pll *clk = to_sp_pll(hw); + unsigned long flags; + u32 reg; + + reg = BIT(clk->bp_bit + 16); /* HIWORD_MASK */ + + if (rate == prate) { + reg |= BIT(clk->bp_bit); /* bypass */ + } else if (clk->div_width == DIV_A) { + return plla_set_rate(clk); + } else if (clk->div_width == DIV_TV) { + return plltv_set_rate(clk); + } else if (clk->div_width) { + u32 fbdiv = sp_pll_calc_div(clk, rate); + u32 mask = GENMASK(clk->div_shift + clk->div_width - 1, clk->div_shift); + + reg |= mask << 16; + reg |= ((fbdiv - 1) << clk->div_shift) & mask; + } + + spin_lock_irqsave(&clk->lock, flags); + writel(reg, clk->reg); + spin_unlock_irqrestore(&clk->lock, flags); + + return 0; +} + +static int sp_pll_enable(struct clk_hw *hw) +{ + struct sp_pll *clk = to_sp_pll(hw); + + writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); + + return 0; +} + +static void sp_pll_disable(struct clk_hw *hw) +{ + struct sp_pll *clk = to_sp_pll(hw); + + writel(BIT(clk->pd_bit + 16), clk->reg); +} + +static int sp_pll_is_enabled(struct clk_hw *hw) +{ + struct sp_pll *clk = to_sp_pll(hw); + + return readl(clk->reg) & BIT(clk->pd_bit); +} + +static const struct clk_ops sp_pll_ops = { + .enable = sp_pll_enable, + .disable = sp_pll_disable, + .is_enabled = sp_pll_is_enabled, + .round_rate = sp_pll_round_rate, + .recalc_rate = sp_pll_recalc_rate, + .set_rate = sp_pll_set_rate +}; + +static const struct clk_ops sp_pll_sub_ops = { + .enable = sp_pll_enable, + .disable = sp_pll_disable, + .is_enabled = sp_pll_is_enabled, + .recalc_rate = sp_pll_recalc_rate, +}; + +static struct clk_hw *sp_pll_register(struct device *dev, const char *name, + const struct clk_parent_data *parent_data, + void __iomem *reg, int pd_bit, int bp_bit, + unsigned long brate, int shift, int width, + unsigned long flags) +{ + struct sp_pll *pll; + struct clk_hw *hw; + struct clk_init_data initd = { + .name = name, + .parent_data = parent_data, + .ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops, + .num_parents = 1, + .flags = flags, + }; + int ret; + + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->hw.init = &initd; + pll->reg = reg; + pll->pd_bit = pd_bit; + pll->bp_bit = bp_bit; + pll->brate = brate; + pll->div_shift = shift; + pll->div_width = width; + spin_lock_init(&pll->lock); + + hw = &pll->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ERR_PTR(ret); + + return hw; +} + +#define PLLA_CTL (pll_base + 0x1c) +#define PLLE_CTL (pll_base + 0x30) +#define PLLF_CTL (pll_base + 0x34) +#define PLLTV_CTL (pll_base + 0x38) + +static int sp7021_clk_probe(struct platform_device *pdev) +{ + static const u32 sp_clken[] = { + 0x67ef, 0x03ff, 0xff03, 0xfff0, 0x0004, /* G0.1~5 */ + 0x0000, 0x8000, 0xffff, 0x0040, 0x0000, /* G0.6~10 */ + }; + static struct clk_parent_data pd_ext, pd_sys, pd_e; + struct device *dev = &pdev->dev; + void __iomem *clk_base, *pll_base, *sys_base; + struct clk_hw_onecell_data *clk_data; + struct clk_hw **hws; + int i; + + clk_base = devm_platform_ioremap_resource(pdev, 0); + if (!clk_base) + return -ENXIO; + pll_base = devm_platform_ioremap_resource(pdev, 1); + if (!pll_base) + return -ENXIO; + sys_base = devm_platform_ioremap_resource(pdev, 2); + if (!sys_base) + return -ENXIO; + + /* enable default clks */ + for (i = 0; i < ARRAY_SIZE(sp_clken); i++) + writel((sp_clken[i] << 16) | sp_clken[i], clk_base + i * 4); + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, CLK_MAX), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + hws = clk_data->hws; + pd_ext.index = 0; + + /* PLLs */ + hws[PLL_A] = sp_pll_register(dev, "plla", &pd_ext, PLLA_CTL, + 11, 12, 27000000, 0, DIV_A, 0); + if (IS_ERR(hws[PLL_A])) + return PTR_ERR(hws[PLL_A]); + + hws[PLL_E] = sp_pll_register(dev, "plle", &pd_ext, PLLE_CTL, + 6, 2, 50000000, 0, 0, 0); + if (IS_ERR(hws[PLL_E])) + return PTR_ERR(hws[PLL_E]); + pd_e.hw = hws[PLL_E]; + hws[PLL_E_2P5] = sp_pll_register(dev, "plle_2p5", &pd_e, PLLE_CTL, + 13, -1, 2500000, 0, 0, 0); + if (IS_ERR(hws[PLL_E_2P5])) + return PTR_ERR(hws[PLL_E_2P5]); + hws[PLL_E_25] = sp_pll_register(dev, "plle_25", &pd_e, PLLE_CTL, + 12, -1, 25000000, 0, 0, 0); + if (IS_ERR(hws[PLL_E_25])) + return PTR_ERR(hws[PLL_E_25]); + hws[PLL_E_112P5] = sp_pll_register(dev, "plle_112p5", &pd_e, PLLE_CTL, + 11, -1, 112500000, 0, 0, 0); + if (IS_ERR(hws[PLL_E_112P5])) + return PTR_ERR(hws[PLL_E_112P5]); + + hws[PLL_F] = sp_pll_register(dev, "pllf", &pd_ext, PLLF_CTL, + 0, 10, 13500000, 1, 4, 0); + if (IS_ERR(hws[PLL_F])) + return PTR_ERR(hws[PLL_F]); + + hws[PLL_TV] = sp_pll_register(dev, "plltv", &pd_ext, PLLTV_CTL, + 0, 15, 27000000, 0, DIV_TV, 0); + if (IS_ERR(hws[PLL_TV])) + return PTR_ERR(hws[PLL_TV]); + hws[PLL_TV_A] = devm_clk_hw_register_divider(dev, "plltv_a", "plltv", 0, + PLLTV_CTL + 4, 5, 1, + CLK_DIVIDER_POWER_OF_TWO, + &to_sp_pll(hws[PLL_TV])->lock); + if (IS_ERR(hws[PLL_TV_A])) + return PTR_ERR(hws[PLL_TV_A]); + + /* system clock, should not be disabled */ + hws[PLL_SYS] = sp_pll_register(dev, "pllsys", &pd_ext, sys_base, + 10, 9, 13500000, 0, 4, CLK_IS_CRITICAL); + if (IS_ERR(hws[PLL_SYS])) + return PTR_ERR(hws[PLL_SYS]); + pd_sys.hw = hws[PLL_SYS]; + + /* gates */ + for (i = 0; i < ARRAY_SIZE(sp_clk_gates); i++) { + char name[10]; + u32 j = sp_clk_gates[i].reg; + struct clk_parent_data *pd = sp_clk_gates[i].ext_parent ? &pd_ext : &pd_sys; + + sprintf(name, "%02d_0x%02x", i, j); + hws[i] = devm_clk_hw_register_gate_parent_data(dev, name, pd, 0, + clk_base + (j >> 4) * 4, + j & 0x0f, + CLK_GATE_HIWORD_MASK, + NULL); + if (IS_ERR(hws[i])) + return PTR_ERR(hws[i]); + } + + clk_data->num = CLK_MAX; + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); +} + +static const struct of_device_id sp7021_clk_dt_ids[] = { + { .compatible = "sunplus,sp7021-clkc" }, + { } +}; +MODULE_DEVICE_TABLE(of, sp7021_clk_dt_ids); + +static struct platform_driver sp7021_clk_driver = { + .probe = sp7021_clk_probe, + .driver = { + .name = "sp7021-clk", + .of_match_table = sp7021_clk_dt_ids, + }, +}; +module_platform_driver(sp7021_clk_driver); + +MODULE_AUTHOR("Sunplus Technology"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Clock driver for Sunplus SP7021 SoC"); diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index 1a701eada0c1..04c18a1d45d3 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -667,7 +667,6 @@ struct stm32_fractional_divider { void __iomem *mreg; u8 mshift; u8 mwidth; - u32 mmask; void __iomem *nreg; u8 nshift; diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 01e5a466897f..939779f66867 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -2434,15 +2434,13 @@ static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) return ret; } -static int stm32mp1_rcc_clocks_remove(struct platform_device *pdev) +static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child, *np = dev_of_node(dev); for_each_available_child_of_node(np, child) of_clk_del_provider(child); - - return 0; } static struct platform_driver stm32mp1_rcc_clocks_driver = { @@ -2451,7 +2449,7 @@ static struct platform_driver stm32mp1_rcc_clocks_driver = { .of_match_table = stm32mp1_match_data, }, .probe = stm32mp1_rcc_clocks_probe, - .remove = stm32mp1_rcc_clocks_remove, + .remove_new = stm32mp1_rcc_clocks_remove, }; static int __init stm32mp1_clocks_init(void) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ae07685c7588..27c30a533759 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1406,6 +1406,8 @@ static int __init clk_disable_unused(void) return 0; } + pr_info("clk: Disabling unused clocks\n"); + clk_prepare_lock(); hlist_for_each_entry(core, &clk_root_list, child_node) @@ -3194,7 +3196,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, static int clk_summary_show(struct seq_file *s, void *data) { struct clk_core *c; - struct hlist_head **lists = (struct hlist_head **)s->private; + struct hlist_head **lists = s->private; seq_puts(s, " enable prepare protect duty hardware\n"); seq_puts(s, " clock count count count rate accuracy phase cycle enable\n"); @@ -3253,7 +3255,7 @@ static int clk_dump_show(struct seq_file *s, void *data) { struct clk_core *c; bool first_node = true; - struct hlist_head **lists = (struct hlist_head **)s->private; + struct hlist_head **lists = s->private; seq_putc(s, '{'); clk_prepare_lock(); @@ -4880,8 +4882,8 @@ static struct device_node *get_clk_provider_node(struct device *dev) np = dev->of_node; parent_np = dev->parent ? dev->parent->of_node : NULL; - if (!of_find_property(np, "#clock-cells", NULL)) - if (of_find_property(parent_np, "#clock-cells", NULL)) + if (!of_property_present(np, "#clock-cells")) + if (of_property_present(parent_np, "#clock-cells")) np = parent_np; return np; diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c index ad0c7f350cf0..b871872d9960 100644 --- a/drivers/clk/hisilicon/clk-hi3519.c +++ b/drivers/clk/hisilicon/clk-hi3519.c @@ -162,13 +162,12 @@ static int hi3519_clk_probe(struct platform_device *pdev) return 0; } -static int hi3519_clk_remove(struct platform_device *pdev) +static void hi3519_clk_remove(struct platform_device *pdev) { struct hi3519_crg_data *crg = platform_get_drvdata(pdev); hisi_reset_exit(crg->rstc); hi3519_clk_unregister(pdev); - return 0; } @@ -180,7 +179,7 @@ MODULE_DEVICE_TABLE(of, hi3519_clk_match_table); static struct platform_driver hi3519_clk_driver = { .probe = hi3519_clk_probe, - .remove = hi3519_clk_remove, + .remove_new = hi3519_clk_remove, .driver = { .name = "hi3519-clk", .of_match_table = hi3519_clk_match_table, diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c index 8036bd8cbb0a..ce4028102bc2 100644 --- a/drivers/clk/hisilicon/clk-hi3559a.c +++ b/drivers/clk/hisilicon/clk-hi3559a.c @@ -810,18 +810,17 @@ static int hi3559av100_crg_probe(struct platform_device *pdev) return 0; } -static int hi3559av100_crg_remove(struct platform_device *pdev) +static void hi3559av100_crg_remove(struct platform_device *pdev) { struct hisi_crg_dev *crg = platform_get_drvdata(pdev); hisi_reset_exit(crg->rstc); crg->funcs->unregister_clks(pdev); - return 0; } static struct platform_driver hi3559av100_crg_driver = { .probe = hi3559av100_crg_probe, - .remove = hi3559av100_crg_remove, + .remove_new = hi3559av100_crg_remove, .driver = { .name = "hi3559av100-clock", .of_match_table = hi3559av100_crg_match_table, diff --git a/drivers/clk/hisilicon/crg-hi3516cv300.c b/drivers/clk/hisilicon/crg-hi3516cv300.c index 5d4e61c7a429..fe1bd3e3f988 100644 --- a/drivers/clk/hisilicon/crg-hi3516cv300.c +++ b/drivers/clk/hisilicon/crg-hi3516cv300.c @@ -284,18 +284,17 @@ static int hi3516cv300_crg_probe(struct platform_device *pdev) return 0; } -static int hi3516cv300_crg_remove(struct platform_device *pdev) +static void hi3516cv300_crg_remove(struct platform_device *pdev) { struct hisi_crg_dev *crg = platform_get_drvdata(pdev); hisi_reset_exit(crg->rstc); crg->funcs->unregister_clks(pdev); - return 0; } static struct platform_driver hi3516cv300_crg_driver = { .probe = hi3516cv300_crg_probe, - .remove = hi3516cv300_crg_remove, + .remove_new = hi3516cv300_crg_remove, .driver = { .name = "hi3516cv300-crg", .of_match_table = hi3516cv300_crg_match_table, diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index 08a19ba776e6..a0b16be1e25d 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -367,18 +367,17 @@ static int hi3798cv200_crg_probe(struct platform_device *pdev) return 0; } -static int hi3798cv200_crg_remove(struct platform_device *pdev) +static void hi3798cv200_crg_remove(struct platform_device *pdev) { struct hisi_crg_dev *crg = platform_get_drvdata(pdev); hisi_reset_exit(crg->rstc); crg->funcs->unregister_clks(pdev); - return 0; } static struct platform_driver hi3798cv200_crg_driver = { .probe = hi3798cv200_crg_probe, - .remove = hi3798cv200_crg_remove, + .remove_new = hi3798cv200_crg_remove, .driver = { .name = "hi3798cv200-crg", .of_match_table = hi3798cv200_crg_match_table, diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index a75d59f7cb8a..ae9d84ef046b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_MXC_CLK) += mxc-clk.o obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o obj-$(CONFIG_CLK_IMX8MN) += clk-imx8mn.o -obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o +obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o clk-imx8mp-audiomix.o obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_CLK_IMX93) += clk-imx93.o diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c index 4eedd45dbaa8..e208ddc51133 100644 --- a/drivers/clk/imx/clk-composite-7ulp.c +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -19,10 +19,8 @@ #define PCG_CGC_SHIFT 30 #define PCG_FRAC_SHIFT 3 #define PCG_FRAC_WIDTH 1 -#define PCG_FRAC_MASK BIT(3) #define PCG_PCD_SHIFT 0 #define PCG_PCD_WIDTH 3 -#define PCG_PCD_MASK 0x7 #define SW_RST BIT(28) @@ -102,10 +100,8 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name, fd->reg = reg; fd->mshift = PCG_FRAC_SHIFT; fd->mwidth = PCG_FRAC_WIDTH; - fd->mmask = PCG_FRAC_MASK; fd->nshift = PCG_PCD_SHIFT; fd->nwidth = PCG_PCD_WIDTH; - fd->nmask = PCG_PCD_MASK; fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; if (has_swrst) fd->lock = &imx_ccm_lock; diff --git a/drivers/clk/imx/clk-composite-93.c b/drivers/clk/imx/clk-composite-93.c index 74a66b0203e4..81164bdcd6cc 100644 --- a/drivers/clk/imx/clk-composite-93.c +++ b/drivers/clk/imx/clk-composite-93.c @@ -222,7 +222,7 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, mux_hw, &clk_mux_ro_ops, div_hw, &clk_divider_ro_ops, NULL, NULL, flags); - } else { + } else if (!mcore_booted) { gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) goto fail; @@ -238,6 +238,12 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p &imx93_clk_composite_divider_ops, gate_hw, &imx93_clk_composite_gate_ops, flags | CLK_SET_RATE_NO_REPARENT); + } else { + hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, + mux_hw, &imx93_clk_composite_mux_ops, div_hw, + &imx93_clk_composite_divider_ops, NULL, + &imx93_clk_composite_gate_ops, + flags | CLK_SET_RATE_NO_REPARENT); } if (IS_ERR(hw)) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index a2aaa14fc1ae..c54f9999da04 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -15,6 +15,7 @@ #include "clk.h" #define PLL_CTRL 0x0 +#define HW_CTRL_SEL BIT(16) #define CLKMUX_BYPASS BIT(2) #define CLKMUX_EN BIT(1) #define POWERUP_MASK BIT(0) @@ -52,26 +53,40 @@ .odiv = (_odiv), \ } +#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \ + { \ + .rate = (_rate), \ + .mfi = (_mfi), \ + .mfn = 0, \ + .mfd = 0, \ + .rdiv = (_rdiv), \ + .odiv = (_odiv), \ + } + struct clk_fracn_gppll { struct clk_hw hw; void __iomem *base; const struct imx_fracn_gppll_rate_table *rate_table; int rate_count; + u32 flags; }; /* - * Fvco = Fref * (MFI + MFN / MFD) - * Fout = Fvco / (rdiv * odiv) + * Fvco = (Fref / rdiv) * (MFI + MFN / MFD) + * Fout = Fvco / odiv + * The (Fref / rdiv) should be in range 20MHz to 40MHz + * The Fvco should be in range 2.5Ghz to 5Ghz */ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { - PLL_FRACN_GP(650000000U, 81, 0, 1, 0, 3), + PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), - PLL_FRACN_GP(560000000U, 70, 0, 1, 0, 3), - PLL_FRACN_GP(498000000U, 83, 0, 1, 0, 4), + PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), + PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), - PLL_FRACN_GP(400000000U, 50, 0, 1, 0, 3), - PLL_FRACN_GP(393216000U, 81, 92, 100, 0, 5) + PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), + PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), + PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12) }; struct imx_fracn_gppll_clk imx_fracn_gppll = { @@ -80,6 +95,24 @@ struct imx_fracn_gppll_clk imx_fracn_gppll = { }; EXPORT_SYMBOL_GPL(imx_fracn_gppll); +/* + * Fvco = (Fref / rdiv) * MFI + * Fout = Fvco / odiv + * The (Fref / rdiv) should be in range 20MHz to 40MHz + * The Fvco should be in range 2.5Ghz to 5Ghz + */ +static const struct imx_fracn_gppll_rate_table int_tbl[] = { + PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), + PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), + PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), +}; + +struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { + .rate_table = int_tbl, + .rate_count = ARRAY_SIZE(int_tbl), +}; +EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer); + static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) { return container_of(hw, struct clk_fracn_gppll, hw); @@ -166,9 +199,15 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon break; } - /* Fvco = Fref * (MFI + MFN / MFD) */ - fvco = fvco * mfi * mfd + fvco * mfn; - do_div(fvco, mfd * rdiv * odiv); + if (pll->flags & CLK_FRACN_GPPLL_INTEGER) { + /* Fvco = (Fref / rdiv) * MFI */ + fvco = fvco * mfi; + do_div(fvco, rdiv * odiv); + } else { + /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */ + fvco = fvco * mfi * mfd + fvco * mfn; + do_div(fvco, mfd * rdiv * odiv); + } return (unsigned long)fvco; } @@ -191,6 +230,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, rate = imx_get_pll_settings(pll, drate); + /* Hardware control select disable. PLL is control by register */ + tmp = readl_relaxed(pll->base + PLL_CTRL); + tmp &= ~HW_CTRL_SEL; + writel_relaxed(tmp, pll->base + PLL_CTRL); + /* Disable output */ tmp = readl_relaxed(pll->base + PLL_CTRL); tmp &= ~CLKMUX_EN; @@ -207,8 +251,10 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | FIELD_PREP(PLL_MFI_MASK, rate->mfi); writel_relaxed(pll_div, pll->base + PLL_DIV); - writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); - writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + if (pll->flags & CLK_FRACN_GPPLL_FRACN) { + writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); + writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + } /* Wait for 5us according to fracn mode pll doc */ udelay(5); @@ -292,8 +338,10 @@ static const struct clk_ops clk_fracn_gppll_ops = { .set_rate = clk_fracn_gppll_set_rate, }; -struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, - const struct imx_fracn_gppll_clk *pll_clk) +static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk, + u32 pll_flags) { struct clk_fracn_gppll *pll; struct clk_hw *hw; @@ -314,6 +362,7 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo pll->hw.init = &init; pll->rate_table = pll_clk->rate_table; pll->rate_count = pll_clk->rate_count; + pll->flags = pll_flags; hw = &pll->hw; @@ -326,4 +375,18 @@ struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, vo return hw; } + +struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk) +{ + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN); +} EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); + +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk) +{ + return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER); +} +EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer); diff --git a/drivers/clk/imx/clk-gpr-mux.c b/drivers/clk/imx/clk-gpr-mux.c index c8d6090f15d6..0b5a97698b47 100644 --- a/drivers/clk/imx/clk-gpr-mux.c +++ b/drivers/clk/imx/clk-gpr-mux.c @@ -48,7 +48,8 @@ static u8 imx_clk_gpr_mux_get_parent(struct clk_hw *hw) return ret; get_parent_err: - pr_err("failed to get parent (%pe)\n", ERR_PTR(ret)); + pr_err("%s: failed to get parent (%pe)\n", + clk_hw_get_name(hw), ERR_PTR(ret)); /* return some realistic non negative value. Potentially we could * give index to some dummy error parent. diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index b618892170f2..075f643e3f35 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -468,7 +468,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) hws[IMX8MM_CLK_PCIE1_PHY] = imx8m_clk_hw_composite("pcie1_phy", imx8mm_pcie1_phy_sels, base + 0xa380); hws[IMX8MM_CLK_PCIE1_AUX] = imx8m_clk_hw_composite("pcie1_aux", imx8mm_pcie1_aux_sels, base + 0xa400); hws[IMX8MM_CLK_DC_PIXEL] = imx8m_clk_hw_composite("dc_pixel", imx8mm_dc_pixel_sels, base + 0xa480); - hws[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_hw_composite("lcdif_pixel", imx8mm_lcdif_pixel_sels, base + 0xa500); + hws[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_hw_composite_flags("lcdif_pixel", imx8mm_lcdif_pixel_sels, base + 0xa500, CLK_SET_RATE_PARENT); hws[IMX8MM_CLK_SAI1] = imx8m_clk_hw_composite("sai1", imx8mm_sai1_sels, base + 0xa580); hws[IMX8MM_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mm_sai2_sels, base + 0xa600); hws[IMX8MM_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mm_sai3_sels, base + 0xa680); diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index a042ed3a9d6c..4b23a4648600 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -470,7 +470,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_DRAM_ALT] = imx8m_clk_hw_fw_managed_composite("dram_alt", imx8mn_dram_alt_sels, base + 0xa000); hws[IMX8MN_CLK_DRAM_APB] = imx8m_clk_hw_fw_managed_composite_critical("dram_apb", imx8mn_dram_apb_sels, base + 0xa080); - hws[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_hw_composite("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500); + hws[IMX8MN_CLK_DISP_PIXEL] = imx8m_clk_hw_composite_flags("disp_pixel", imx8mn_disp_pixel_sels, base + 0xa500, CLK_SET_RATE_PARENT); hws[IMX8MN_CLK_SAI2] = imx8m_clk_hw_composite("sai2", imx8mn_sai2_sels, base + 0xa600); hws[IMX8MN_CLK_SAI3] = imx8m_clk_hw_composite("sai3", imx8mn_sai3_sels, base + 0xa680); hws[IMX8MN_CLK_SAI5] = imx8m_clk_hw_composite("sai5", imx8mn_sai5_sels, base + 0xa780); diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c new file mode 100644 index 000000000000..e4300df88f1a --- /dev/null +++ b/drivers/clk/imx/clk-imx8mp-audiomix.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for i.MX8M Plus Audio BLK_CTRL + * + * Copyright (C) 2022 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define CLKEN0 0x000 +#define CLKEN1 0x004 +#define SAI_MCLK_SEL(n) (0x300 + 4 * (n)) /* n in 0..5 */ +#define PDM_SEL 0x318 +#define SAI_PLL_GNRL_CTL 0x400 + +#define SAIn_MCLK1_PARENT(n) \ +static const struct clk_parent_data \ +clk_imx8mp_audiomix_sai##n##_mclk1_parents[] = { \ + { \ + .fw_name = "sai"__stringify(n), \ + .name = "sai"__stringify(n) \ + }, { \ + .fw_name = "sai"__stringify(n)"_mclk", \ + .name = "sai"__stringify(n)"_mclk" \ + }, \ +} + +SAIn_MCLK1_PARENT(1); +SAIn_MCLK1_PARENT(2); +SAIn_MCLK1_PARENT(3); +SAIn_MCLK1_PARENT(5); +SAIn_MCLK1_PARENT(6); +SAIn_MCLK1_PARENT(7); + +static const struct clk_parent_data clk_imx8mp_audiomix_sai_mclk2_parents[] = { + { .fw_name = "sai1", .name = "sai1" }, + { .fw_name = "sai2", .name = "sai2" }, + { .fw_name = "sai3", .name = "sai3" }, + { .name = "dummy" }, + { .fw_name = "sai5", .name = "sai5" }, + { .fw_name = "sai6", .name = "sai6" }, + { .fw_name = "sai7", .name = "sai7" }, + { .fw_name = "sai1_mclk", .name = "sai1_mclk" }, + { .fw_name = "sai2_mclk", .name = "sai2_mclk" }, + { .fw_name = "sai3_mclk", .name = "sai3_mclk" }, + { .name = "dummy" }, + { .fw_name = "sai5_mclk", .name = "sai5_mclk" }, + { .fw_name = "sai6_mclk", .name = "sai6_mclk" }, + { .fw_name = "sai7_mclk", .name = "sai7_mclk" }, + { .fw_name = "spdif_extclk", .name = "spdif_extclk" }, + { .name = "dummy" }, +}; + +static const struct clk_parent_data clk_imx8mp_audiomix_pdm_parents[] = { + { .fw_name = "pdm", .name = "pdm" }, + { .name = "sai_pll_out_div2" }, + { .fw_name = "sai1_mclk", .name = "sai1_mclk" }, + { .name = "dummy" }, +}; + + +static const struct clk_parent_data clk_imx8mp_audiomix_pll_parents[] = { + { .fw_name = "osc_24m", .name = "osc_24m" }, + { .name = "dummy" }, + { .name = "dummy" }, + { .name = "dummy" }, +}; + +static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = { + { .fw_name = "sai_pll", .name = "sai_pll" }, + { .fw_name = "sai_pll_ref_sel", .name = "sai_pll_ref_sel" }, +}; + +#define CLK_GATE(gname, cname) \ + { \ + gname"_cg", \ + IMX8MP_CLK_AUDIOMIX_##cname, \ + { .fw_name = "ahb", .name = "ahb" }, NULL, 1, \ + CLKEN0 + 4 * !!(IMX8MP_CLK_AUDIOMIX_##cname / 32), \ + 1, IMX8MP_CLK_AUDIOMIX_##cname % 32 \ + } + +#define CLK_SAIn(n) \ + { \ + "sai"__stringify(n)"_mclk1_sel", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK1_SEL, {}, \ + clk_imx8mp_audiomix_sai##n##_mclk1_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai##n##_mclk1_parents), \ + SAI_MCLK_SEL(n), 1, 0 \ + }, { \ + "sai"__stringify(n)"_mclk2_sel", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK2_SEL, {}, \ + clk_imx8mp_audiomix_sai_mclk2_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai_mclk2_parents), \ + SAI_MCLK_SEL(n), 4, 1 \ + }, { \ + "sai"__stringify(n)"_ipg_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_IPG, \ + { .fw_name = "ahb", .name = "ahb" }, NULL, 1, \ + CLKEN0, 1, IMX8MP_CLK_AUDIOMIX_SAI##n##_IPG \ + }, { \ + "sai"__stringify(n)"_mclk1_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK1, \ + { \ + .fw_name = "sai"__stringify(n)"_mclk1_sel", \ + .name = "sai"__stringify(n)"_mclk1_sel" \ + }, NULL, 1, \ + CLKEN0, 1, IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK1 \ + }, { \ + "sai"__stringify(n)"_mclk2_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK2, \ + { \ + .fw_name = "sai"__stringify(n)"_mclk2_sel", \ + .name = "sai"__stringify(n)"_mclk2_sel" \ + }, NULL, 1, \ + CLKEN0, 1, IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK2 \ + }, { \ + "sai"__stringify(n)"_mclk3_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK3, \ + { \ + .fw_name = "sai_pll_out_div2", \ + .name = "sai_pll_out_div2" \ + }, NULL, 1, \ + CLKEN0, 1, IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK3 \ + } + +#define CLK_PDM \ + { \ + "pdm_sel", IMX8MP_CLK_AUDIOMIX_PDM_SEL, {}, \ + clk_imx8mp_audiomix_pdm_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_pdm_parents), \ + PDM_SEL, 2, 0 \ + } + +struct clk_imx8mp_audiomix_sel { + const char *name; + int clkid; + const struct clk_parent_data parent; /* For gate */ + const struct clk_parent_data *parents; /* For mux */ + int num_parents; + u16 reg; + u8 width; + u8 shift; +}; + +static struct clk_imx8mp_audiomix_sel sels[] = { + CLK_GATE("asrc", ASRC_IPG), + CLK_GATE("pdm", PDM_IPG), + CLK_GATE("earc", EARC_IPG), + CLK_GATE("ocrama", OCRAMA_IPG), + CLK_GATE("aud2htx", AUD2HTX_IPG), + CLK_GATE("earc_phy", EARC_PHY), + CLK_GATE("sdma2", SDMA2_ROOT), + CLK_GATE("sdma3", SDMA3_ROOT), + CLK_GATE("spba2", SPBA2_ROOT), + CLK_GATE("dsp", DSP_ROOT), + CLK_GATE("dspdbg", DSPDBG_ROOT), + CLK_GATE("edma", EDMA_ROOT), + CLK_GATE("audpll", AUDPLL_ROOT), + CLK_GATE("mu2", MU2_ROOT), + CLK_GATE("mu3", MU3_ROOT), + CLK_PDM, + CLK_SAIn(1), + CLK_SAIn(2), + CLK_SAIn(3), + CLK_SAIn(5), + CLK_SAIn(6), + CLK_SAIn(7) +}; + +static int clk_imx8mp_audiomix_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *priv; + struct device *dev = &pdev->dev; + void __iomem *base; + struct clk_hw *hw; + int i; + + priv = devm_kzalloc(dev, + struct_size(priv, hws, IMX8MP_CLK_AUDIOMIX_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->num = IMX8MP_CLK_AUDIOMIX_END; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + for (i = 0; i < ARRAY_SIZE(sels); i++) { + if (sels[i].num_parents == 1) { + hw = devm_clk_hw_register_gate_parent_data(dev, + sels[i].name, &sels[i].parent, 0, + base + sels[i].reg, sels[i].shift, 0, NULL); + } else { + hw = devm_clk_hw_register_mux_parent_data_table(dev, + sels[i].name, sels[i].parents, + sels[i].num_parents, 0, + base + sels[i].reg, + sels[i].shift, sels[i].width, + 0, NULL, NULL); + } + + if (IS_ERR(hw)) + return PTR_ERR(hw); + + priv->hws[sels[i].clkid] = hw; + } + + /* SAI PLL */ + hw = devm_clk_hw_register_mux_parent_data_table(dev, + "sai_pll_ref_sel", clk_imx8mp_audiomix_pll_parents, + ARRAY_SIZE(clk_imx8mp_audiomix_pll_parents), + CLK_SET_RATE_NO_REPARENT, base + SAI_PLL_GNRL_CTL, + 0, 2, 0, NULL, NULL); + priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw; + + hw = imx_dev_clk_hw_pll14xx(dev, "sai_pll", "sai_pll_ref_sel", + base + 0x400, &imx_1443x_pll); + if (IS_ERR(hw)) + return PTR_ERR(hw); + priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL] = hw; + + hw = devm_clk_hw_register_mux_parent_data_table(dev, + "sai_pll_bypass", clk_imx8mp_audiomix_pll_bypass_sels, + ARRAY_SIZE(clk_imx8mp_audiomix_pll_bypass_sels), + CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + base + SAI_PLL_GNRL_CTL, 16, 1, 0, NULL, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw; + + hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass", + 0, base + SAI_PLL_GNRL_CTL, 13, + 0, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + priv->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw; + + hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2", + "sai_pll_out", 0, 1, 2); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, + priv); +} + +static const struct of_device_id clk_imx8mp_audiomix_of_match[] = { + { .compatible = "fsl,imx8mp-audio-blk-ctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, clk_imx8mp_audiomix_of_match); + +static struct platform_driver clk_imx8mp_audiomix_driver = { + .probe = clk_imx8mp_audiomix_probe, + .driver = { + .name = "imx8mp-audio-blk-ctrl", + .of_match_table = clk_imx8mp_audiomix_of_match, + }, +}; + +module_platform_driver(clk_imx8mp_audiomix_driver); + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("Freescale i.MX8MP Audio Block Controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 3253589851ff..f26ae8de4cc6 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -538,7 +538,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mp_main_axi_sels, ccm_base + 0x8800); hws[IMX8MP_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mp_enet_axi_sels, ccm_base + 0x8880); - hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900); + hws[IMX8MP_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mp_nand_usdhc_sels, ccm_base + 0x8900); hws[IMX8MP_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mp_vpu_bus_sels, ccm_base + 0x8980); hws[IMX8MP_CLK_MEDIA_AXI] = imx8m_clk_hw_composite_bus("media_axi", imx8mp_media_axi_sels, ccm_base + 0x8a00); hws[IMX8MP_CLK_MEDIA_APB] = imx8m_clk_hw_composite_bus("media_apb", imx8mp_media_apb_sels, ccm_base + 0x8a80); @@ -554,7 +554,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000); hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100); hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200); - hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300); + hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300); hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); @@ -696,6 +696,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp1_pix_root_clk", "media_disp1_pix", ccm_base + 0x45d0, 0, &share_count_media); hws[IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT] = imx_clk_hw_gate2_shared2("media_disp2_pix_root_clk", "media_disp2_pix", ccm_base + 0x45d0, 0, &share_count_media); hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT] = imx_clk_hw_gate2_shared2("media_mipi_phy1_ref_root", "media_mipi_phy1_ref", ccm_base + 0x45d0, 0, &share_count_media); + hws[IMX8MP_CLK_MEDIA_LDB_ROOT] = imx_clk_hw_gate2_shared2("media_ldb_root_clk", "media_ldb", ccm_base + 0x45d0, 0, &share_count_media); hws[IMX8MP_CLK_MEDIA_ISP_ROOT] = imx_clk_hw_gate2_shared2("media_isp_root_clk", "media_isp", ccm_base + 0x45d0, 0, &share_count_media); hws[IMX8MP_CLK_USDHC3_ROOT] = imx_clk_hw_gate4("usdhc3_root_clk", "usdhc3", ccm_base + 0x45e0, 0); diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c index a07df3b44703..e308c88cb801 100644 --- a/drivers/clk/imx/clk-imx8ulp.c +++ b/drivers/clk/imx/clk-imx8ulp.c @@ -198,10 +198,10 @@ static int imx8ulp_clk_cgc1_init(struct platform_device *pdev) clks[IMX8ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel", base + 0x34, 28, 2, nic_sels, ARRAY_SIZE(nic_sels)); clks[IMX8ULP_CLK_NIC_AD_DIVPLAT] = imx_clk_hw_divider_flags("nic_ad_divplat", "nic_sel", base + 0x34, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); - clks[IMX8ULP_CLK_NIC_PER_DIVPLAT] = imx_clk_hw_divider_flags("nic_per_divplat", "nic_ad_divplat", base + 0x34, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); - clks[IMX8ULP_CLK_XBAR_AD_DIVPLAT] = imx_clk_hw_divider_flags("xbar_ad_divplat", "nic_ad_divplat", base + 0x38, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); - clks[IMX8ULP_CLK_XBAR_DIVBUS] = imx_clk_hw_divider_flags("xbar_divbus", "nic_ad_divplat", base + 0x38, 7, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); - clks[IMX8ULP_CLK_XBAR_AD_SLOW] = imx_clk_hw_divider_flags("xbar_ad_slow", "nic_ad_divplat", base + 0x38, 0, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + clks[IMX8ULP_CLK_NIC_PER_DIVPLAT] = imx_clk_hw_divider_flags("nic_per_divplat", "nic_ad_divplat", base + 0x34, 14, 6, CLK_SET_RATE_PARENT); + clks[IMX8ULP_CLK_XBAR_AD_DIVPLAT] = imx_clk_hw_divider_flags("xbar_ad_divplat", "nic_ad_divplat", base + 0x38, 14, 6, CLK_SET_RATE_PARENT); + clks[IMX8ULP_CLK_XBAR_DIVBUS] = imx_clk_hw_divider_flags("xbar_divbus", "xbar_ad_divplat", base + 0x38, 7, 6, CLK_SET_RATE_PARENT); + clks[IMX8ULP_CLK_XBAR_AD_SLOW] = imx_clk_hw_divider_flags("xbar_ad_slow", "xbar_divbus", base + 0x38, 0, 6, CLK_SET_RATE_PARENT); clks[IMX8ULP_CLK_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("sosc_div1_gate", "sosc", base + 0x108, 7); clks[IMX8ULP_CLK_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("sosc_div2_gate", "sosc", base + 0x108, 15); @@ -255,9 +255,9 @@ static int imx8ulp_clk_cgc2_init(struct platform_device *pdev) clks[IMX8ULP_CLK_HIFI_DIVCORE] = imx_clk_hw_divider("hifi_core_div", "hifi_sel", base + 0x14, 21, 6); clks[IMX8ULP_CLK_HIFI_DIVPLAT] = imx_clk_hw_divider("hifi_plat_div", "hifi_core_div", base + 0x14, 14, 6); - clks[IMX8ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x40, 28, 3, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_PARENT_GATE); - clks[IMX8ULP_CLK_DDR_DIV] = imx_clk_hw_divider_flags("ddr_div", "ddr_sel", base + 0x40, 21, 6, CLK_IS_CRITICAL); - clks[IMX8ULP_CLK_LPAV_AXI_SEL] = imx_clk_hw_mux("lpav_sel", base + 0x3c, 28, 2, lpav_sels, ARRAY_SIZE(lpav_sels)); + clks[IMX8ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x40, 28, 3, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_GET_RATE_NOCACHE); + clks[IMX8ULP_CLK_DDR_DIV] = imx_clk_hw_divider_flags("ddr_div", "ddr_sel", base + 0x40, 21, 6, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE); + clks[IMX8ULP_CLK_LPAV_AXI_SEL] = imx_clk_hw_mux2("lpav_sel", base + 0x3c, 28, 2, lpav_sels, ARRAY_SIZE(lpav_sels)); clks[IMX8ULP_CLK_LPAV_AXI_DIV] = imx_clk_hw_divider_flags("lpav_axi_div", "lpav_sel", base + 0x3c, 21, 6, CLK_IS_CRITICAL); clks[IMX8ULP_CLK_LPAV_AHB_DIV] = imx_clk_hw_divider_flags("lpav_ahb_div", "lpav_axi_div", base + 0x3c, 14, 6, CLK_IS_CRITICAL); clks[IMX8ULP_CLK_LPAV_BUS_DIV] = imx_clk_hw_divider_flags("lpav_bus_div", "lpav_axi_div", base + 0x3c, 7, 6, CLK_IS_CRITICAL); @@ -275,14 +275,14 @@ static int imx8ulp_clk_cgc2_init(struct platform_device *pdev) clks[IMX8ULP_CLK_PLL4_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div2_gate", "pll4_pfd2", base + 0x60c, 15); clks[IMX8ULP_CLK_PLL4_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div1_gate", "pll4_pfd3", base + 0x60c, 23); clks[IMX8ULP_CLK_PLL4_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div2_gate", "pll4_pfd3", base + 0x60c, 31); - clks[IMX8ULP_CLK_PLL4_PFD0_DIV1] = imx_clk_hw_divider("pll4_pfd0_div1", "pll4_pfd0_div1_gate", base + 0x608, 0, 6); - clks[IMX8ULP_CLK_PLL4_PFD0_DIV2] = imx_clk_hw_divider("pll4_pfd0_div2", "pll4_pfd0_div2_gate", base + 0x608, 8, 6); - clks[IMX8ULP_CLK_PLL4_PFD1_DIV1] = imx_clk_hw_divider("pll4_pfd1_div1", "pll4_pfd1_div1_gate", base + 0x608, 16, 6); - clks[IMX8ULP_CLK_PLL4_PFD1_DIV2] = imx_clk_hw_divider("pll4_pfd1_div2", "pll4_pfd1_div2_gate", base + 0x608, 24, 6); - clks[IMX8ULP_CLK_PLL4_PFD2_DIV1] = imx_clk_hw_divider("pll4_pfd2_div1", "pll4_pfd2_div1_gate", base + 0x60c, 0, 6); - clks[IMX8ULP_CLK_PLL4_PFD2_DIV2] = imx_clk_hw_divider("pll4_pfd2_div2", "pll4_pfd2_div2_gate", base + 0x60c, 8, 6); - clks[IMX8ULP_CLK_PLL4_PFD3_DIV1] = imx_clk_hw_divider("pll4_pfd3_div1", "pll4_pfd3_div1_gate", base + 0x60c, 16, 6); - clks[IMX8ULP_CLK_PLL4_PFD3_DIV2] = imx_clk_hw_divider("pll4_pfd3_div2", "pll4_pfd3_div2_gate", base + 0x60c, 24, 6); + clks[IMX8ULP_CLK_PLL4_PFD0_DIV1] = imx_clk_hw_divider_closest("pll4_pfd0_div1", "pll4_pfd0_div1_gate", base + 0x608, 0, 6); + clks[IMX8ULP_CLK_PLL4_PFD0_DIV2] = imx_clk_hw_divider_closest("pll4_pfd0_div2", "pll4_pfd0_div2_gate", base + 0x608, 8, 6); + clks[IMX8ULP_CLK_PLL4_PFD1_DIV1] = imx_clk_hw_divider_closest("pll4_pfd1_div1", "pll4_pfd1_div1_gate", base + 0x608, 16, 6); + clks[IMX8ULP_CLK_PLL4_PFD1_DIV2] = imx_clk_hw_divider_closest("pll4_pfd1_div2", "pll4_pfd1_div2_gate", base + 0x608, 24, 6); + clks[IMX8ULP_CLK_PLL4_PFD2_DIV1] = imx_clk_hw_divider_closest("pll4_pfd2_div1", "pll4_pfd2_div1_gate", base + 0x60c, 0, 6); + clks[IMX8ULP_CLK_PLL4_PFD2_DIV2] = imx_clk_hw_divider_closest("pll4_pfd2_div2", "pll4_pfd2_div2_gate", base + 0x60c, 8, 6); + clks[IMX8ULP_CLK_PLL4_PFD3_DIV1] = imx_clk_hw_divider_closest("pll4_pfd3_div1", "pll4_pfd3_div1_gate", base + 0x60c, 16, 6); + clks[IMX8ULP_CLK_PLL4_PFD3_DIV2] = imx_clk_hw_divider_closest("pll4_pfd3_div2", "pll4_pfd3_div2_gate", base + 0x60c, 24, 6); clks[IMX8ULP_CLK_CGC2_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div1_gate", "sosc", base + 0x108, 7); clks[IMX8ULP_CLK_CGC2_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div2_gate", "sosc", base + 0x108, 15); @@ -333,7 +333,6 @@ static int imx8ulp_clk_pcc3_init(struct platform_device *pdev) clks[IMX8ULP_CLK_WDOG4] = imx8ulp_clk_hw_composite("wdog4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xac, 1); clks[IMX8ULP_CLK_LPIT1] = imx8ulp_clk_hw_composite("lpit1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xc8, 1); clks[IMX8ULP_CLK_TPM4] = imx8ulp_clk_hw_composite("tpm4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xcc, 1); - clks[IMX8ULP_CLK_TPM5] = imx8ulp_clk_hw_composite("tpm5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd0, 1); clks[IMX8ULP_CLK_FLEXIO1] = imx8ulp_clk_hw_composite("flexio1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd4, 1); clks[IMX8ULP_CLK_I3C2] = imx8ulp_clk_hw_composite("i3c2", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd8, 1); clks[IMX8ULP_CLK_LPI2C4] = imx8ulp_clk_hw_composite("lpi2c4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xdc, 1); @@ -376,8 +375,9 @@ static int imx8ulp_clk_pcc3_init(struct platform_device *pdev) clks[IMX8ULP_CLK_DMA1_CH29] = imx_clk_hw_gate("pcc_dma1_ch29", "xbar_ad_divplat", base + 0x7c, 30); clks[IMX8ULP_CLK_DMA1_CH30] = imx_clk_hw_gate("pcc_dma1_ch30", "xbar_ad_divplat", base + 0x80, 30); clks[IMX8ULP_CLK_DMA1_CH31] = imx_clk_hw_gate("pcc_dma1_ch31", "xbar_ad_divplat", base + 0x84, 30); - clks[IMX8ULP_CLK_MU0_B] = imx_clk_hw_gate("mu0_b", "xbar_ad_divplat", base + 0x88, 30); + clks[IMX8ULP_CLK_MU0_B] = imx_clk_hw_gate_flags("mu0_b", "xbar_ad_divplat", base + 0x88, 30, CLK_IS_CRITICAL); clks[IMX8ULP_CLK_MU3_A] = imx_clk_hw_gate("mu3_a", "xbar_ad_divplat", base + 0x8c, 30); + clks[IMX8ULP_CLK_TPM5] = imx_clk_hw_gate_flags("tpm5", "sosc_div2", base + 0xd0, 30, CLK_IS_CRITICAL); imx_check_clk_hws(clks, clk_data->num); diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index 8d0974db6bfd..07b4a043e449 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -33,6 +33,7 @@ static u32 share_count_sai2; static u32 share_count_sai3; static u32 share_count_mub; +static const char * const a55_core_sels[] = {"a55_alt", "arm_pll"}; static const char *parent_names[MAX_SEL][4] = { {"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "video_pll"}, {"osc_24m", "sys_pll_pfd0_div2", "sys_pll_pfd1_div2", "sys_pll_pfd2_div2"}, @@ -55,7 +56,7 @@ static const struct imx93_clk_root { /* a55/m33/bus critical clk for system run */ { IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_A55_MTR_BUS, "a55_mtr_bus_root", 0x0080, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, - { IMX93_CLK_A55, "a55_root", 0x0100, FAST_SEL, CLK_IS_CRITICAL }, + { IMX93_CLK_A55, "a55_alt_root", 0x0100, FAST_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_M33, "m33_root", 0x0180, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_BUS_WAKEUP, "bus_wakeup_root", 0x0280, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, @@ -117,6 +118,7 @@ static const struct imx93_clk_root { { IMX93_CLK_HSIO_USB_TEST_60M, "hsio_usb_test_60m_root", 0x1f00, LOW_SPEED_IO_SEL, }, { IMX93_CLK_HSIO_ACSCAN_80M, "hsio_acscan_80m_root", 0x1f80, LOW_SPEED_IO_SEL, }, { IMX93_CLK_HSIO_ACSCAN_480M, "hsio_acscan_480m_root", 0x2000, MISC_SEL, }, + { IMX93_CLK_NIC_AXI, "nic_axi_root", 0x2080, FAST_SEL, CLK_IS_CRITICAL, }, { IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, }, { IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, }, { IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, }, @@ -153,7 +155,7 @@ static const struct imx93_clk_ccgr { unsigned long flags; u32 *shared_count; } ccgr_array[] = { - { IMX93_CLK_A55_GATE, "a55", "a55_root", 0x8000, }, + { IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, }, /* M33 critical clk for system run */ { IMX93_CLK_CM33_GATE, "cm33", "m33_root", 0x8040, CLK_IS_CRITICAL }, { IMX93_CLK_ADC1_GATE, "adc1", "adc_root", 0x82c0, }, @@ -291,6 +293,9 @@ static int imx93_clocks_probe(struct platform_device *pdev) if (WARN_ON(!anatop_base)) return -ENOMEM; + clks[IMX93_CLK_ARM_PLL] = imx_clk_fracn_gppll_integer("arm_pll", "osc_24m", + anatop_base + 0x1000, + &imx_fracn_gppll_integer); clks[IMX93_CLK_AUDIO_PLL] = imx_clk_fracn_gppll("audio_pll", "osc_24m", anatop_base + 0x1200, &imx_fracn_gppll); clks[IMX93_CLK_VIDEO_PLL] = imx_clk_fracn_gppll("video_pll", "osc_24m", anatop_base + 0x1400, @@ -318,6 +323,14 @@ static int imx93_clocks_probe(struct platform_device *pdev) ccgr->shared_count); } + clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels, + ARRAY_SIZE(a55_core_sels)); + clks[IMX93_CLK_A55_CORE] = imx_clk_hw_cpu("a55_core", "a55_sel", + clks[IMX93_CLK_A55_SEL]->clk, + clks[IMX93_CLK_A55_SEL]->clk, + clks[IMX93_CLK_ARM_PLL]->clk, + clks[IMX93_CLK_A55_GATE]->clk); + imx_check_clk_hws(clks, IMX93_CLK_END); ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data); @@ -352,6 +365,8 @@ static struct platform_driver imx93_clk_driver = { }, }; module_platform_driver(imx93_clk_driver); +module_param(mcore_booted, bool, 0444); +MODULE_PARM_DESC(mcore_booted, "See Cortex-M core is booted or not"); MODULE_DESCRIPTION("NXP i.MX93 clock driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 3d94722bbf99..1031468701d7 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -73,6 +73,9 @@ extern struct imx_pll14xx_clk imx_1416x_pll; extern struct imx_pll14xx_clk imx_1443x_pll; extern struct imx_pll14xx_clk imx_1443x_dram_pll; +#define CLK_FRACN_GPPLL_INTEGER BIT(0) +#define CLK_FRACN_GPPLL_FRACN BIT(1) + /* NOTE: Rate table should be kept sorted in descending order. */ struct imx_fracn_gppll_rate_table { unsigned int rate; @@ -91,8 +94,12 @@ struct imx_fracn_gppll_clk { struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, const struct imx_fracn_gppll_clk *pll_clk); +struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk); extern struct imx_fracn_gppll_clk imx_fracn_gppll; +extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer; #define imx_clk_cpu(name, parent_name, div, mux, pll, step) \ to_clk(imx_clk_hw_cpu(name, parent_name, div, mux, pll, step)) @@ -153,9 +160,6 @@ extern struct imx_fracn_gppll_clk imx_fracn_gppll; #define imx_clk_pllv2(name, parent, base) \ to_clk(imx_clk_hw_pllv2(name, parent, base)) -#define imx_clk_mux_flags(name, reg, shift, width, parents, num_parents, flags) \ - to_clk(imx_clk_hw_mux_flags(name, reg, shift, width, parents, num_parents, flags)) - #define imx_clk_hw_gate(name, parent, reg, shift) \ imx_clk_hw_gate_flags(name, parent, reg, shift, 0) @@ -349,6 +353,15 @@ static inline struct clk_hw *imx_clk_hw_fixed_factor(const char *name, CLK_SET_RATE_PARENT, mult, div); } +static inline struct clk_hw *imx_clk_hw_divider_closest(const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width) +{ + return clk_hw_register_divider(NULL, name, parent, 0, + reg, shift, width, CLK_DIVIDER_ROUND_CLOSEST, &imx_ccm_lock); +} + static inline struct clk_hw *__imx_clk_hw_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, @@ -417,6 +430,10 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, _imx8m_clk_hw_composite(name, parent_names, reg, \ 0, IMX_COMPOSITE_CLK_FLAGS_DEFAULT) +#define imx8m_clk_hw_composite_flags(name, parent_names, reg, flags) \ + _imx8m_clk_hw_composite(name, parent_names, reg, \ + 0, IMX_COMPOSITE_CLK_FLAGS_DEFAULT | flags) + #define imx8m_clk_hw_composite_critical(name, parent_names, reg) \ _imx8m_clk_hw_composite(name, parent_names, reg, \ 0, IMX_COMPOSITE_CLK_FLAGS_CRITICAL) diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index d4b4e74e22da..910ecd58c4ca 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -689,16 +689,14 @@ static int ti_sci_clk_probe(struct platform_device *pdev) * via common clock framework. Any memory allocated for the device will * be free'd silently via the devm framework. Returns 0 always. */ -static int ti_sci_clk_remove(struct platform_device *pdev) +static void ti_sci_clk_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - - return 0; } static struct platform_driver ti_sci_clk_driver = { .probe = ti_sci_clk_probe, - .remove = ti_sci_clk_remove, + .remove_new = ti_sci_clk_remove, .driver = { .name = "ti-sci-clk", .of_match_table = of_match_ptr(ti_sci_clk_of_match), diff --git a/drivers/clk/loongson1/Makefile b/drivers/clk/loongson1/Makefile deleted file mode 100644 index 251d0fe9dcd1..000000000000 --- a/drivers/clk/loongson1/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += clk.o -obj-$(CONFIG_LOONGSON1_LS1B) += clk-loongson1b.o -obj-$(CONFIG_LOONGSON1_LS1C) += clk-loongson1c.o diff --git a/drivers/clk/loongson1/clk-loongson1b.c b/drivers/clk/loongson1/clk-loongson1b.c deleted file mode 100644 index 13a2ca23a159..000000000000 --- a/drivers/clk/loongson1/clk-loongson1b.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2012-2016 Zhang, Keguang - */ - -#include -#include -#include -#include - -#include -#include "clk.h" - -#define OSC (33 * 1000000) -#define DIV_APB 2 - -static DEFINE_SPINLOCK(_lock); - -static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - u32 pll, rate; - - pll = __raw_readl(LS1X_CLK_PLL_FREQ); - rate = 12 + (pll & GENMASK(5, 0)); - rate *= OSC; - rate >>= 1; - - return rate; -} - -static const struct clk_ops ls1x_pll_clk_ops = { - .recalc_rate = ls1x_pll_recalc_rate, -}; - -static const char *const cpu_parents[] = { "cpu_clk_div", "osc_clk", }; -static const char *const ahb_parents[] = { "ahb_clk_div", "osc_clk", }; -static const char *const dc_parents[] = { "dc_clk_div", "osc_clk", }; - -void __init ls1x_clk_init(void) -{ - struct clk_hw *hw; - - hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); - clk_hw_register_clkdev(hw, "osc_clk", NULL); - - /* clock derived from 33 MHz OSC clk */ - hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", - &ls1x_pll_clk_ops, 0); - clk_hw_register_clkdev(hw, "pll_clk", NULL); - - /* clock derived from PLL clk */ - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ CPU CLK - * \___ PLL ___ CPU DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", - CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, - DIV_CPU_SHIFT, DIV_CPU_WIDTH, - CLK_DIVIDER_ONE_BASED | - CLK_DIVIDER_ROUND_CLOSEST, &_lock); - clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "cpu_clk", cpu_parents, - ARRAY_SIZE(cpu_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "cpu_clk", NULL); - - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ DC CLK - * \___ PLL ___ DC DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", - 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, - DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_hw_register_clkdev(hw, "dc_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "dc_clk", dc_parents, - ARRAY_SIZE(dc_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "dc_clk", NULL); - - /* _____ - * _______________________| | - * OSC ___/ | MUX |___ DDR CLK - * \___ PLL ___ DDR DIV ___| | - * |_____| - */ - hw = clk_hw_register_divider(NULL, "ahb_clk_div", "pll_clk", - 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, - DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, - &_lock); - clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); - hw = clk_hw_register_mux(NULL, "ahb_clk", ahb_parents, - ARRAY_SIZE(ahb_parents), - CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, - BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); - clk_hw_register_clkdev(hw, "ahb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x-dma", NULL); - clk_hw_register_clkdev(hw, "stmmaceth", NULL); - - /* clock derived from AHB clk */ - /* APB clk is always half of the AHB clk */ - hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, - DIV_APB); - clk_hw_register_clkdev(hw, "apb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); - clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); - clk_hw_register_clkdev(hw, "ls1x-nand", NULL); - clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); - clk_hw_register_clkdev(hw, "ls1x-spi", NULL); - clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); - clk_hw_register_clkdev(hw, "serial8250", NULL); -} diff --git a/drivers/clk/loongson1/clk-loongson1c.c b/drivers/clk/loongson1/clk-loongson1c.c deleted file mode 100644 index 1ebf740380ef..000000000000 --- a/drivers/clk/loongson1/clk-loongson1c.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2016 Yang Ling - */ - -#include -#include -#include - -#include -#include "clk.h" - -#define OSC (24 * 1000000) -#define DIV_APB 1 - -static DEFINE_SPINLOCK(_lock); - -static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - u32 pll, rate; - - pll = __raw_readl(LS1X_CLK_PLL_FREQ); - rate = ((pll >> 8) & 0xff) + ((pll >> 16) & 0xff); - rate *= OSC; - rate >>= 2; - - return rate; -} - -static const struct clk_ops ls1x_pll_clk_ops = { - .recalc_rate = ls1x_pll_recalc_rate, -}; - -static const struct clk_div_table ahb_div_table[] = { - [0] = { .val = 0, .div = 2 }, - [1] = { .val = 1, .div = 4 }, - [2] = { .val = 2, .div = 3 }, - [3] = { .val = 3, .div = 3 }, - [4] = { /* sentinel */ } -}; - -void __init ls1x_clk_init(void) -{ - struct clk_hw *hw; - - hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); - clk_hw_register_clkdev(hw, "osc_clk", NULL); - - /* clock derived from 24 MHz OSC clk */ - hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", - &ls1x_pll_clk_ops, 0); - clk_hw_register_clkdev(hw, "pll_clk", NULL); - - hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", - CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, - DIV_CPU_SHIFT, DIV_CPU_WIDTH, - CLK_DIVIDER_ONE_BASED | - CLK_DIVIDER_ROUND_CLOSEST, &_lock); - clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); - hw = clk_hw_register_fixed_factor(NULL, "cpu_clk", "cpu_clk_div", - 0, 1, 1); - clk_hw_register_clkdev(hw, "cpu_clk", NULL); - - hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", - 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, - DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_hw_register_clkdev(hw, "dc_clk_div", NULL); - hw = clk_hw_register_fixed_factor(NULL, "dc_clk", "dc_clk_div", - 0, 1, 1); - clk_hw_register_clkdev(hw, "dc_clk", NULL); - - hw = clk_hw_register_divider_table(NULL, "ahb_clk_div", "cpu_clk_div", - 0, LS1X_CLK_PLL_FREQ, DIV_DDR_SHIFT, - DIV_DDR_WIDTH, CLK_DIVIDER_ALLOW_ZERO, - ahb_div_table, &_lock); - clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); - hw = clk_hw_register_fixed_factor(NULL, "ahb_clk", "ahb_clk_div", - 0, 1, 1); - clk_hw_register_clkdev(hw, "ahb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x-dma", NULL); - clk_hw_register_clkdev(hw, "stmmaceth", NULL); - - /* clock derived from AHB clk */ - hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, - DIV_APB); - clk_hw_register_clkdev(hw, "apb_clk", NULL); - clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); - clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); - clk_hw_register_clkdev(hw, "ls1x-nand", NULL); - clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); - clk_hw_register_clkdev(hw, "ls1x-spi", NULL); - clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); - clk_hw_register_clkdev(hw, "serial8250", NULL); -} diff --git a/drivers/clk/loongson1/clk.c b/drivers/clk/loongson1/clk.c deleted file mode 100644 index f336a3126d31..000000000000 --- a/drivers/clk/loongson1/clk.c +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2012-2016 Zhang, Keguang - */ - -#include -#include - -#include "clk.h" - -struct clk_hw *__init clk_hw_register_pll(struct device *dev, - const char *name, - const char *parent_name, - const struct clk_ops *ops, - unsigned long flags) -{ - int ret; - struct clk_hw *hw; - struct clk_init_data init; - - /* allocate the divider */ - hw = kzalloc(sizeof(*hw), GFP_KERNEL); - if (!hw) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = ops; - init.flags = flags; - init.parent_names = parent_name ? &parent_name : NULL; - init.num_parents = parent_name ? 1 : 0; - hw->init = &init; - - /* register the clock */ - ret = clk_hw_register(dev, hw); - if (ret) { - kfree(hw); - hw = ERR_PTR(ret); - } - - return hw; -} diff --git a/drivers/clk/loongson1/clk.h b/drivers/clk/loongson1/clk.h deleted file mode 100644 index 124642302b12..000000000000 --- a/drivers/clk/loongson1/clk.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2012-2016 Zhang, Keguang - */ - -#ifndef __LOONGSON1_CLK_H -#define __LOONGSON1_CLK_H - -struct clk_hw *clk_hw_register_pll(struct device *dev, - const char *name, - const char *parent_name, - const struct clk_ops *ops, - unsigned long flags); - -#endif /* __LOONGSON1_CLK_H */ diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 2d14855dd37e..99e67c07e638 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -75,7 +75,7 @@ config COMMON_CLK_MT2701_G3DSYS This driver supports MediaTek MT2701 g3dsys clocks. config COMMON_CLK_MT2712 - bool "Clock driver for MediaTek MT2712" + tristate "Clock driver for MediaTek MT2712" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 @@ -83,43 +83,43 @@ config COMMON_CLK_MT2712 This driver supports MediaTek MT2712 basic clocks. config COMMON_CLK_MT2712_BDPSYS - bool "Clock driver for MediaTek MT2712 bdpsys" + tristate "Clock driver for MediaTek MT2712 bdpsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 bdpsys clocks. config COMMON_CLK_MT2712_IMGSYS - bool "Clock driver for MediaTek MT2712 imgsys" + tristate "Clock driver for MediaTek MT2712 imgsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 imgsys clocks. config COMMON_CLK_MT2712_JPGDECSYS - bool "Clock driver for MediaTek MT2712 jpgdecsys" + tristate "Clock driver for MediaTek MT2712 jpgdecsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 jpgdecsys clocks. config COMMON_CLK_MT2712_MFGCFG - bool "Clock driver for MediaTek MT2712 mfgcfg" + tristate "Clock driver for MediaTek MT2712 mfgcfg" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 mfgcfg clocks. config COMMON_CLK_MT2712_MMSYS - bool "Clock driver for MediaTek MT2712 mmsys" + tristate "Clock driver for MediaTek MT2712 mmsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 mmsys clocks. config COMMON_CLK_MT2712_VDECSYS - bool "Clock driver for MediaTek MT2712 vdecsys" + tristate "Clock driver for MediaTek MT2712 vdecsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 vdecsys clocks. config COMMON_CLK_MT2712_VENCSYS - bool "Clock driver for MediaTek MT2712 vencsys" + tristate "Clock driver for MediaTek MT2712 vencsys" depends on COMMON_CLK_MT2712 help This driver supports MediaTek MT2712 vencsys clocks. @@ -133,79 +133,79 @@ config COMMON_CLK_MT6765 This driver supports MediaTek MT6765 basic clocks. config COMMON_CLK_MT6765_AUDIOSYS - bool "Clock driver for MediaTek MT6765 audiosys" + tristate "Clock driver for MediaTek MT6765 audiosys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 audiosys clocks. config COMMON_CLK_MT6765_CAMSYS - bool "Clock driver for MediaTek MT6765 camsys" + tristate "Clock driver for MediaTek MT6765 camsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 camsys clocks. config COMMON_CLK_MT6765_GCESYS - bool "Clock driver for MediaTek MT6765 gcesys" + tristate "Clock driver for MediaTek MT6765 gcesys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 gcesys clocks. config COMMON_CLK_MT6765_MMSYS - bool "Clock driver for MediaTek MT6765 mmsys" + tristate "Clock driver for MediaTek MT6765 mmsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mmsys clocks. config COMMON_CLK_MT6765_IMGSYS - bool "Clock driver for MediaTek MT6765 imgsys" + tristate "Clock driver for MediaTek MT6765 imgsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 imgsys clocks. config COMMON_CLK_MT6765_VCODECSYS - bool "Clock driver for MediaTek MT6765 vcodecsys" + tristate "Clock driver for MediaTek MT6765 vcodecsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 vcodecsys clocks. config COMMON_CLK_MT6765_MFGSYS - bool "Clock driver for MediaTek MT6765 mfgsys" + tristate "Clock driver for MediaTek MT6765 mfgsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mfgsys clocks. config COMMON_CLK_MT6765_MIPI0ASYS - bool "Clock driver for MediaTek MT6765 mipi0asys" + tristate "Clock driver for MediaTek MT6765 mipi0asys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi0asys clocks. config COMMON_CLK_MT6765_MIPI0BSYS - bool "Clock driver for MediaTek MT6765 mipi0bsys" + tristate "Clock driver for MediaTek MT6765 mipi0bsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi0bsys clocks. config COMMON_CLK_MT6765_MIPI1ASYS - bool "Clock driver for MediaTek MT6765 mipi1asys" + tristate "Clock driver for MediaTek MT6765 mipi1asys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi1asys clocks. config COMMON_CLK_MT6765_MIPI1BSYS - bool "Clock driver for MediaTek MT6765 mipi1bsys" + tristate "Clock driver for MediaTek MT6765 mipi1bsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi1bsys clocks. config COMMON_CLK_MT6765_MIPI2ASYS - bool "Clock driver for MediaTek MT6765 mipi2asys" + tristate "Clock driver for MediaTek MT6765 mipi2asys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi2asys clocks. config COMMON_CLK_MT6765_MIPI2BSYS - bool "Clock driver for MediaTek MT6765 mipi2bsys" + tristate "Clock driver for MediaTek MT6765 mipi2bsys" depends on COMMON_CLK_MT6765 help This driver supports MediaTek MT6765 mipi2bsys clocks. @@ -270,6 +270,7 @@ config COMMON_CLK_MT6795 tristate "Clock driver for MediaTek MT6795" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK + select COMMON_CLK_MEDIATEK_FHCTL default ARCH_MEDIATEK help This driver supports MediaTek MT6795 basic clocks and clocks @@ -312,31 +313,31 @@ config COMMON_CLK_MT6797 This driver supports MediaTek MT6797 basic clocks. config COMMON_CLK_MT6797_MMSYS - bool "Clock driver for MediaTek MT6797 mmsys" + tristate "Clock driver for MediaTek MT6797 mmsys" depends on COMMON_CLK_MT6797 help This driver supports MediaTek MT6797 mmsys clocks. config COMMON_CLK_MT6797_IMGSYS - bool "Clock driver for MediaTek MT6797 imgsys" + tristate "Clock driver for MediaTek MT6797 imgsys" depends on COMMON_CLK_MT6797 help This driver supports MediaTek MT6797 imgsys clocks. config COMMON_CLK_MT6797_VDECSYS - bool "Clock driver for MediaTek MT6797 vdecsys" + tristate "Clock driver for MediaTek MT6797 vdecsys" depends on COMMON_CLK_MT6797 help This driver supports MediaTek MT6797 vdecsys clocks. config COMMON_CLK_MT6797_VENCSYS - bool "Clock driver for MediaTek MT6797 vencsys" + tristate "Clock driver for MediaTek MT6797 vencsys" depends on COMMON_CLK_MT6797 help This driver supports MediaTek MT6797 vencsys clocks. config COMMON_CLK_MT7622 - bool "Clock driver for MediaTek MT7622" + tristate "Clock driver for MediaTek MT7622" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK @@ -345,21 +346,21 @@ config COMMON_CLK_MT7622 required for various periperals found on MediaTek. config COMMON_CLK_MT7622_ETHSYS - bool "Clock driver for MediaTek MT7622 ETHSYS" + tristate "Clock driver for MediaTek MT7622 ETHSYS" depends on COMMON_CLK_MT7622 help This driver add support for clocks for Ethernet and SGMII required on MediaTek MT7622 SoC. config COMMON_CLK_MT7622_HIFSYS - bool "Clock driver for MediaTek MT7622 HIFSYS" + tristate "Clock driver for MediaTek MT7622 HIFSYS" depends on COMMON_CLK_MT7622 help This driver supports MediaTek MT7622 HIFSYS clocks providing to PCI-E and USB. config COMMON_CLK_MT7622_AUDSYS - bool "Clock driver for MediaTek MT7622 AUDSYS" + tristate "Clock driver for MediaTek MT7622 AUDSYS" depends on COMMON_CLK_MT7622 help This driver supports MediaTek MT7622 AUDSYS clocks providing @@ -406,7 +407,7 @@ config COMMON_CLK_MT7981_ETHSYS required on MediaTek MT7981 SoC. config COMMON_CLK_MT7986 - bool "Clock driver for MediaTek MT7986" + tristate "Clock driver for MediaTek MT7986" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK @@ -415,7 +416,7 @@ config COMMON_CLK_MT7986 required for various peripherals found on MediaTek. config COMMON_CLK_MT7986_ETHSYS - bool "Clock driver for MediaTek MT7986 ETHSYS" + tristate "Clock driver for MediaTek MT7986 ETHSYS" depends on COMMON_CLK_MT7986 default COMMON_CLK_MT7986 help @@ -423,7 +424,7 @@ config COMMON_CLK_MT7986_ETHSYS required on MediaTek MT7986 SoC. config COMMON_CLK_MT8135 - bool "Clock driver for MediaTek MT8135" + tristate "Clock driver for MediaTek MT8135" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM @@ -431,7 +432,7 @@ config COMMON_CLK_MT8135 This driver supports MediaTek MT8135 clocks. config COMMON_CLK_MT8167 - bool "Clock driver for MediaTek MT8167" + tristate "Clock driver for MediaTek MT8167" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK @@ -439,35 +440,35 @@ config COMMON_CLK_MT8167 This driver supports MediaTek MT8167 basic clocks. config COMMON_CLK_MT8167_AUDSYS - bool "Clock driver for MediaTek MT8167 audsys" + tristate "Clock driver for MediaTek MT8167 audsys" depends on COMMON_CLK_MT8167 default COMMON_CLK_MT8167 help This driver supports MediaTek MT8167 audsys clocks. config COMMON_CLK_MT8167_IMGSYS - bool "Clock driver for MediaTek MT8167 imgsys" + tristate "Clock driver for MediaTek MT8167 imgsys" depends on COMMON_CLK_MT8167 default COMMON_CLK_MT8167 help This driver supports MediaTek MT8167 imgsys clocks. config COMMON_CLK_MT8167_MFGCFG - bool "Clock driver for MediaTek MT8167 mfgcfg" + tristate "Clock driver for MediaTek MT8167 mfgcfg" depends on COMMON_CLK_MT8167 default COMMON_CLK_MT8167 help This driver supports MediaTek MT8167 mfgcfg clocks. config COMMON_CLK_MT8167_MMSYS - bool "Clock driver for MediaTek MT8167 mmsys" + tristate "Clock driver for MediaTek MT8167 mmsys" depends on COMMON_CLK_MT8167 default COMMON_CLK_MT8167 help This driver supports MediaTek MT8167 mmsys clocks. config COMMON_CLK_MT8167_VDECSYS - bool "Clock driver for MediaTek MT8167 vdecsys" + tristate "Clock driver for MediaTek MT8167 vdecsys" depends on COMMON_CLK_MT8167 default COMMON_CLK_MT8167 help @@ -477,6 +478,7 @@ config COMMON_CLK_MT8173 tristate "Clock driver for MediaTek MT8173" depends on ARM64 || COMPILE_TEST select COMMON_CLK_MEDIATEK + select COMMON_CLK_MEDIATEK_FHCTL default ARCH_MEDIATEK help This driver supports MediaTek MT8173 basic clocks and clocks @@ -511,7 +513,7 @@ config COMMON_CLK_MT8173_VENCSYS This driver supports MediaTek MT8173 vencsys clocks. config COMMON_CLK_MT8183 - bool "Clock driver for MediaTek MT8183" + tristate "Clock driver for MediaTek MT8183" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK && ARM64 @@ -519,84 +521,84 @@ config COMMON_CLK_MT8183 This driver supports MediaTek MT8183 basic clocks. config COMMON_CLK_MT8183_AUDIOSYS - bool "Clock driver for MediaTek MT8183 audiosys" + tristate "Clock driver for MediaTek MT8183 audiosys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 audiosys clocks. config COMMON_CLK_MT8183_CAMSYS - bool "Clock driver for MediaTek MT8183 camsys" + tristate "Clock driver for MediaTek MT8183 camsys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 camsys clocks. config COMMON_CLK_MT8183_IMGSYS - bool "Clock driver for MediaTek MT8183 imgsys" + tristate "Clock driver for MediaTek MT8183 imgsys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 imgsys clocks. config COMMON_CLK_MT8183_IPU_CORE0 - bool "Clock driver for MediaTek MT8183 ipu_core0" + tristate "Clock driver for MediaTek MT8183 ipu_core0" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 ipu_core0 clocks. config COMMON_CLK_MT8183_IPU_CORE1 - bool "Clock driver for MediaTek MT8183 ipu_core1" + tristate "Clock driver for MediaTek MT8183 ipu_core1" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 ipu_core1 clocks. config COMMON_CLK_MT8183_IPU_ADL - bool "Clock driver for MediaTek MT8183 ipu_adl" + tristate "Clock driver for MediaTek MT8183 ipu_adl" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 ipu_adl clocks. config COMMON_CLK_MT8183_IPU_CONN - bool "Clock driver for MediaTek MT8183 ipu_conn" + tristate "Clock driver for MediaTek MT8183 ipu_conn" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 ipu_conn clocks. config COMMON_CLK_MT8183_MFGCFG - bool "Clock driver for MediaTek MT8183 mfgcfg" + tristate "Clock driver for MediaTek MT8183 mfgcfg" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 mfgcfg clocks. config COMMON_CLK_MT8183_MMSYS - bool "Clock driver for MediaTek MT8183 mmsys" + tristate "Clock driver for MediaTek MT8183 mmsys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 mmsys clocks. config COMMON_CLK_MT8183_VDECSYS - bool "Clock driver for MediaTek MT8183 vdecsys" + tristate "Clock driver for MediaTek MT8183 vdecsys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 vdecsys clocks. config COMMON_CLK_MT8183_VENCSYS - bool "Clock driver for MediaTek MT8183 vencsys" + tristate "Clock driver for MediaTek MT8183 vencsys" depends on COMMON_CLK_MT8183 default COMMON_CLK_MT8183 help This driver supports MediaTek MT8183 vencsys clocks. config COMMON_CLK_MT8186 - bool "Clock driver for MediaTek MT8186" + tristate "Clock driver for MediaTek MT8186" depends on ARM64 || COMPILE_TEST select COMMON_CLK_MEDIATEK select COMMON_CLK_MEDIATEK_FHCTL @@ -604,82 +606,246 @@ config COMMON_CLK_MT8186 help This driver supports MediaTek MT8186 clocks. -config COMMON_CLK_MT8192 - bool "Clock driver for MediaTek MT8192" +config COMMON_CLK_MT8186_CAMSYS + tristate "Clock driver for MediaTek MT8186 camsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 camsys and camsys_raw clocks. + +config COMMON_CLK_MT8186_IMGSYS + tristate "Clock driver for MediaTek MT8186 imgsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 imgsys and imgsys2 clocks. + +config COMMON_CLK_MT8186_IPESYS + tristate "Clock driver for MediaTek MT8186 ipesys" + depends on COMMON_CLK_MT8186_IMGSYS + default COMMON_CLK_MT8186_IMGSYS + help + This driver supports MediaTek MT8186 ipesys clocks. + +config COMMON_CLK_MT8186_WPESYS + tristate "Clock driver for MediaTek MT8186 wpesys" + depends on COMMON_CLK_MT8186_IMGSYS + default COMMON_CLK_MT8186_IMGSYS + help + This driver supports MediaTek MT8186 Warp Engine clocks. + +config COMMON_CLK_MT8186_IMP_IIC_WRAP + tristate "Clock driver for MediaTek MT8186 imp_iic_wrap" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 imp_iic_wrap clocks. + +config COMMON_CLK_MT8186_MCUSYS + tristate "Clock driver for MediaTek MT8186 mcusys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 mcusys clocks. + +config COMMON_CLK_MT8186_MDPSYS + tristate "Clock driver for MediaTek MT8186 mdpsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 mdpsys clocks. + +config COMMON_CLK_MT8186_MFGCFG + tristate "Clock driver for MediaTek MT8186 mfgcfg" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 mfgcfg clocks. + +config COMMON_CLK_MT8186_MMSYS + tristate "Clock driver for MediaTek MT8186 mmsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 mmsys clocks. + +config COMMON_CLK_MT8186_VDECSYS + tristate "Clock driver for MediaTek MT8186 vdecsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 vdecsys and vdecsys_soc clocks. + +config COMMON_CLK_MT8186_VENCSYS + tristate "Clock driver for MediaTek MT8186 vencsys" + depends on COMMON_CLK_MT8186 + default COMMON_CLK_MT8186 + help + This driver supports MediaTek MT8186 vencsys clocks. + +config COMMON_CLK_MT8188 + tristate "Clock driver for MediaTek MT8188" depends on ARM64 || COMPILE_TEST select COMMON_CLK_MEDIATEK + select COMMON_CLK_MEDIATEK_FHCTL + default ARCH_MEDIATEK + help + This driver supports MediaTek MT8188 clocks. + +config COMMON_CLK_MT8188_ADSP_AUDIO26M + tristate "Clock driver for MediaTek MT8188 adsp audio26m" + depends on COMMON_CLK_MT8188 + default COMMON_CLK_MT8188 + help + This driver supports MediaTek MT8188 adsp audio26m clocks. + +config COMMON_CLK_MT8188_CAMSYS + tristate "Clock driver for MediaTek MT8188 camsys" + depends on COMMON_CLK_MT8188_VPPSYS + default COMMON_CLK_MT8188_VPPSYS + help + This driver supports MediaTek MT8188 camsys and camsys_raw clocks. + +config COMMON_CLK_MT8188_IMGSYS + tristate "Clock driver for MediaTek MT8188 imgsys" + depends on COMMON_CLK_MT8188_VPPSYS + default COMMON_CLK_MT8188_VPPSYS + help + This driver supports MediaTek MT8188 imgsys and imgsys2 clocks. + +config COMMON_CLK_MT8188_IMP_IIC_WRAP + tristate "Clock driver for MediaTek MT8188 imp_iic_wrap" + depends on COMMON_CLK_MT8188 + default COMMON_CLK_MT8188 + help + This driver supports MediaTek MT8188 I2C/I3C clocks. + +config COMMON_CLK_MT8188_IPESYS + tristate "Clock driver for MediaTek MT8188 ipesys" + depends on COMMON_CLK_MT8188_IMGSYS + default COMMON_CLK_MT8188_IMGSYS + help + This driver supports MediaTek MT8188 ipesys clocks. + +config COMMON_CLK_MT8188_MFGCFG + tristate "Clock driver for MediaTek MT8188 mfgcfg" + depends on COMMON_CLK_MT8188 + default COMMON_CLK_MT8188 + help + This driver supports MediaTek MT8188 mfgcfg clocks. + +config COMMON_CLK_MT8188_VDECSYS + tristate "Clock driver for MediaTek MT8188 vdecsys" + depends on COMMON_CLK_MT8188_VPPSYS + default COMMON_CLK_MT8188_VPPSYS + help + This driver supports MediaTek MT8188 vdecsys and vdecsys_soc clocks. + +config COMMON_CLK_MT8188_VDOSYS + tristate "Clock driver for MediaTek MT8188 vdosys" + depends on COMMON_CLK_MT8188 + default COMMON_CLK_MT8188 + help + This driver supports MediaTek MT8188 vdosys0/1 (multimedia) clocks. + +config COMMON_CLK_MT8188_VENCSYS + tristate "Clock driver for MediaTek MT8188 vencsys" + depends on COMMON_CLK_MT8188_VPPSYS + default COMMON_CLK_MT8188_VPPSYS + help + This driver supports MediaTek MT8188 vencsys clocks. + +config COMMON_CLK_MT8188_VPPSYS + tristate "Clock driver for MediaTek MT8188 vppsys" + depends on COMMON_CLK_MT8188 + default COMMON_CLK_MT8188 + help + This driver supports MediaTek MT8188 vppsys0/1 clocks. + +config COMMON_CLK_MT8188_WPESYS + tristate "Clock driver for MediaTek MT8188 wpesys" + depends on COMMON_CLK_MT8188_IMGSYS + default COMMON_CLK_MT8188_IMGSYS + help + This driver supports MediaTek MT8188 Warp Engine clocks. + +config COMMON_CLK_MT8192 + tristate "Clock driver for MediaTek MT8192" + depends on ARM64 || COMPILE_TEST + select COMMON_CLK_MEDIATEK + select COMMON_CLK_MEDIATEK_FHCTL default ARM64 help This driver supports MediaTek MT8192 basic clocks. config COMMON_CLK_MT8192_AUDSYS - bool "Clock driver for MediaTek MT8192 audsys" + tristate "Clock driver for MediaTek MT8192 audsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 audsys clocks. config COMMON_CLK_MT8192_CAMSYS - bool "Clock driver for MediaTek MT8192 camsys" + tristate "Clock driver for MediaTek MT8192 camsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 camsys and camsys_raw clocks. config COMMON_CLK_MT8192_IMGSYS - bool "Clock driver for MediaTek MT8192 imgsys" + tristate "Clock driver for MediaTek MT8192 imgsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 imgsys and imgsys2 clocks. config COMMON_CLK_MT8192_IMP_IIC_WRAP - bool "Clock driver for MediaTek MT8192 imp_iic_wrap" + tristate "Clock driver for MediaTek MT8192 imp_iic_wrap" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 imp_iic_wrap clocks. config COMMON_CLK_MT8192_IPESYS - bool "Clock driver for MediaTek MT8192 ipesys" + tristate "Clock driver for MediaTek MT8192 ipesys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 ipesys clocks. config COMMON_CLK_MT8192_MDPSYS - bool "Clock driver for MediaTek MT8192 mdpsys" + tristate "Clock driver for MediaTek MT8192 mdpsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 mdpsys clocks. config COMMON_CLK_MT8192_MFGCFG - bool "Clock driver for MediaTek MT8192 mfgcfg" + tristate "Clock driver for MediaTek MT8192 mfgcfg" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 mfgcfg clocks. config COMMON_CLK_MT8192_MMSYS - bool "Clock driver for MediaTek MT8192 mmsys" + tristate "Clock driver for MediaTek MT8192 mmsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 mmsys clocks. config COMMON_CLK_MT8192_MSDC - bool "Clock driver for MediaTek MT8192 msdc" + tristate "Clock driver for MediaTek MT8192 msdc" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 msdc and msdc_top clocks. config COMMON_CLK_MT8192_SCP_ADSP - bool "Clock driver for MediaTek MT8192 scp_adsp" + tristate "Clock driver for MediaTek MT8192 scp_adsp" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 scp_adsp clocks. config COMMON_CLK_MT8192_VDECSYS - bool "Clock driver for MediaTek MT8192 vdecsys" + tristate "Clock driver for MediaTek MT8192 vdecsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 vdecsys and vdecsys_soc clocks. config COMMON_CLK_MT8192_VENCSYS - bool "Clock driver for MediaTek MT8192 vencsys" + tristate "Clock driver for MediaTek MT8192 vencsys" depends on COMMON_CLK_MT8192 help This driver supports MediaTek MT8192 vencsys clocks. @@ -688,10 +854,111 @@ config COMMON_CLK_MT8195 bool "Clock driver for MediaTek MT8195" depends on ARM64 || COMPILE_TEST select COMMON_CLK_MEDIATEK + select COMMON_CLK_MEDIATEK_FHCTL default ARCH_MEDIATEK help This driver supports MediaTek MT8195 clocks. +config COMMON_CLK_MT8195_APUSYS + tristate "Clock driver for MediaTek MT8195 apusys" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 AI Processor Unit System clocks. + +config COMMON_CLK_MT8195_AUDSYS + tristate "Clock driver for MediaTek MT8195 audsys" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 audsys clocks. + +config COMMON_CLK_MT8195_IMP_IIC_WRAP + tristate "Clock driver for MediaTek MT8195 imp_iic_wrap" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 I2C/I3C clocks. + +config COMMON_CLK_MT8195_MFGCFG + tristate "Clock driver for MediaTek MT8195 mfgcfg" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 mfgcfg clocks. + +config COMMON_CLK_MT8195_MSDC + tristate "Clock driver for MediaTek MT8195 msdc" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 MMC and SD Controller's + msdc and msdc_top clocks. + +config COMMON_CLK_MT8195_SCP_ADSP + tristate "Clock driver for MediaTek MT8195 scp_adsp" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 System Companion Processor + Audio DSP clocks. + +config COMMON_CLK_MT8195_VDOSYS + tristate "Clock driver for MediaTek MT8195 vdosys" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 vdosys0/1 (multimedia) clocks. + +config COMMON_CLK_MT8195_VPPSYS + tristate "Clock driver for MediaTek MT8195 vppsys" + depends on COMMON_CLK_MT8195 + default COMMON_CLK_MT8195 + help + This driver supports MediaTek MT8195 vppsys0/1 clocks. + +config COMMON_CLK_MT8195_CAMSYS + tristate "Clock driver for MediaTek MT8195 camsys" + depends on COMMON_CLK_MT8195_VPPSYS + default COMMON_CLK_MT8195_VPPSYS + help + This driver supports MediaTek MT8195 camsys and camsys_raw clocks. + +config COMMON_CLK_MT8195_IMGSYS + tristate "Clock driver for MediaTek MT8195 imgsys" + depends on COMMON_CLK_MT8195_VPPSYS + default COMMON_CLK_MT8195_VPPSYS + help + This driver supports MediaTek MT8195 imgsys and imgsys2 clocks. + +config COMMON_CLK_MT8195_IPESYS + tristate "Clock driver for MediaTek MT8195 ipesys" + depends on COMMON_CLK_MT8195_IMGSYS + default COMMON_CLK_MT8195_IMGSYS + help + This driver supports MediaTek MT8195 ipesys clocks. + +config COMMON_CLK_MT8195_WPESYS + tristate "Clock driver for MediaTek MT8195 wpesys" + depends on COMMON_CLK_MT8195_IMGSYS + default COMMON_CLK_MT8195_IMGSYS + help + This driver supports MediaTek MT8195 Warp Engine clocks. + +config COMMON_CLK_MT8195_VDECSYS + tristate "Clock driver for MediaTek MT8195 vdecsys" + depends on COMMON_CLK_MT8195_VPPSYS + default COMMON_CLK_MT8195_VPPSYS + help + This driver supports MediaTek MT8195 vdecsys and vdecsys_soc clocks. + +config COMMON_CLK_MT8195_VENCSYS + tristate "Clock driver for MediaTek MT8195 vencsys" + depends on COMMON_CLK_MT8195_VPPSYS + default COMMON_CLK_MT8195_VPPSYS + help + This driver supports MediaTek MT8195 vencsys clocks. + config COMMON_CLK_MT8365 tristate "Clock driver for MediaTek MT8365" depends on ARCH_MEDIATEK || COMPILE_TEST @@ -743,7 +1010,7 @@ config COMMON_CLK_MT8365_VENC This driver supports MediaTek MT8365 venc clocks. config COMMON_CLK_MT8516 - bool "Clock driver for MediaTek MT8516" + tristate "Clock driver for MediaTek MT8516" depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK @@ -751,7 +1018,7 @@ config COMMON_CLK_MT8516 This driver supports MediaTek MT8516 clocks. config COMMON_CLK_MT8516_AUDSYS - bool "Clock driver for MediaTek MT8516 audsys" + tristate "Clock driver for MediaTek MT8516 audsys" depends on COMMON_CLK_MT8516 help This driver supports MediaTek MT8516 audsys clocks. diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index e5d018270ed0..dbeaa5b41177 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_COMMON_CLK_MT2701_HIFSYS) += clk-mt2701-hif.o obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o obj-$(CONFIG_COMMON_CLK_MT2701_VDECSYS) += clk-mt2701-vdec.o -obj-$(CONFIG_COMMON_CLK_MT2712) += clk-mt2712.o +obj-$(CONFIG_COMMON_CLK_MT2712) += clk-mt2712-apmixedsys.o clk-mt2712.o obj-$(CONFIG_COMMON_CLK_MT2712_BDPSYS) += clk-mt2712-bdp.o obj-$(CONFIG_COMMON_CLK_MT2712_IMGSYS) += clk-mt2712-img.o obj-$(CONFIG_COMMON_CLK_MT2712_JPGDECSYS) += clk-mt2712-jpgdec.o @@ -46,7 +46,8 @@ obj-$(CONFIG_COMMON_CLK_MT2712_MFGCFG) += clk-mt2712-mfg.o obj-$(CONFIG_COMMON_CLK_MT2712_MMSYS) += clk-mt2712-mm.o obj-$(CONFIG_COMMON_CLK_MT2712_VDECSYS) += clk-mt2712-vdec.o obj-$(CONFIG_COMMON_CLK_MT2712_VENCSYS) += clk-mt2712-venc.o -obj-$(CONFIG_COMMON_CLK_MT7622) += clk-mt7622.o +obj-$(CONFIG_COMMON_CLK_MT7622) += clk-mt7622-apmixedsys.o clk-mt7622.o \ + clk-mt7622-infracfg.o obj-$(CONFIG_COMMON_CLK_MT7622_ETHSYS) += clk-mt7622-eth.o obj-$(CONFIG_COMMON_CLK_MT7622_HIFSYS) += clk-mt7622-hif.o obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) += clk-mt7622-aud.o @@ -61,8 +62,8 @@ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-apmixed.o obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o obj-$(CONFIG_COMMON_CLK_MT7986_ETHSYS) += clk-mt7986-eth.o -obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o -obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167.o +obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135-apmixedsys.o clk-mt8135.o +obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167-apmixedsys.o clk-mt8167.o obj-$(CONFIG_COMMON_CLK_MT8167_AUDSYS) += clk-mt8167-aud.o obj-$(CONFIG_COMMON_CLK_MT8167_IMGSYS) += clk-mt8167-img.o obj-$(CONFIG_COMMON_CLK_MT8167_MFGCFG) += clk-mt8167-mfgcfg.o @@ -74,7 +75,7 @@ obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o -obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o +obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183-apmixedsys.o clk-mt8183.o obj-$(CONFIG_COMMON_CLK_MT8183_AUDIOSYS) += clk-mt8183-audio.o obj-$(CONFIG_COMMON_CLK_MT8183_CAMSYS) += clk-mt8183-cam.o obj-$(CONFIG_COMMON_CLK_MT8183_IMGSYS) += clk-mt8183-img.o @@ -86,12 +87,33 @@ obj-$(CONFIG_COMMON_CLK_MT8183_MFGCFG) += clk-mt8183-mfgcfg.o obj-$(CONFIG_COMMON_CLK_MT8183_MMSYS) += clk-mt8183-mm.o obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o -obj-$(CONFIG_COMMON_CLK_MT8186) += clk-mt8186-mcu.o clk-mt8186-topckgen.o clk-mt8186-infra_ao.o \ - clk-mt8186-apmixedsys.o clk-mt8186-imp_iic_wrap.o \ - clk-mt8186-mfg.o clk-mt8186-mm.o clk-mt8186-wpe.o \ - clk-mt8186-img.o clk-mt8186-vdec.o clk-mt8186-venc.o \ - clk-mt8186-cam.o clk-mt8186-mdp.o clk-mt8186-ipe.o -obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192.o +obj-$(CONFIG_COMMON_CLK_MT8186) += clk-mt8186-apmixedsys.o clk-mt8186-topckgen.o \ + clk-mt8186-infra_ao.o +obj-$(CONFIG_COMMON_CLK_MT8186_CAMSYS) += clk-mt8186-cam.o +obj-$(CONFIG_COMMON_CLK_MT8186_IMGSYS) += clk-mt8186-img.o +obj-$(CONFIG_COMMON_CLK_MT8186_IMP_IIC_WRAP) += clk-mt8186-imp_iic_wrap.o +obj-$(CONFIG_COMMON_CLK_MT8186_IPESYS) += clk-mt8186-ipe.o +obj-$(CONFIG_COMMON_CLK_MT8186_MCUSYS) += clk-mt8186-mcu.o +obj-$(CONFIG_COMMON_CLK_MT8186_MDPSYS) += clk-mt8186-mdp.o +obj-$(CONFIG_COMMON_CLK_MT8186_MFGCFG) += clk-mt8186-mfg.o +obj-$(CONFIG_COMMON_CLK_MT8186_MMSYS) += clk-mt8186-mm.o +obj-$(CONFIG_COMMON_CLK_MT8186_VDECSYS) += clk-mt8186-vdec.o +obj-$(CONFIG_COMMON_CLK_MT8186_VENCSYS) += clk-mt8186-venc.o +obj-$(CONFIG_COMMON_CLK_MT8186_WPESYS) += clk-mt8186-wpe.o +obj-$(CONFIG_COMMON_CLK_MT8188) += clk-mt8188-apmixedsys.o clk-mt8188-topckgen.o \ + clk-mt8188-peri_ao.o clk-mt8188-infra_ao.o +obj-$(CONFIG_COMMON_CLK_MT8188_ADSP_AUDIO26M) += clk-mt8188-adsp_audio26m.o +obj-$(CONFIG_COMMON_CLK_MT8188_CAMSYS) += clk-mt8188-cam.o clk-mt8188-ccu.o +obj-$(CONFIG_COMMON_CLK_MT8188_IMGSYS) += clk-mt8188-img.o +obj-$(CONFIG_COMMON_CLK_MT8188_IMP_IIC_WRAP) += clk-mt8188-imp_iic_wrap.o +obj-$(CONFIG_COMMON_CLK_MT8188_IPESYS) += clk-mt8188-ipe.o +obj-$(CONFIG_COMMON_CLK_MT8188_MFGCFG) += clk-mt8188-mfg.o +obj-$(CONFIG_COMMON_CLK_MT8188_VDECSYS) += clk-mt8188-vdec.o +obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-mt8188-vdo0.o clk-mt8188-vdo1.o +obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o +obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o +obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o +obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o obj-$(CONFIG_COMMON_CLK_MT8192_IMGSYS) += clk-mt8192-img.o @@ -105,19 +127,25 @@ obj-$(CONFIG_COMMON_CLK_MT8192_SCP_ADSP) += clk-mt8192-scp_adsp.o obj-$(CONFIG_COMMON_CLK_MT8192_VDECSYS) += clk-mt8192-vdec.o obj-$(CONFIG_COMMON_CLK_MT8192_VENCSYS) += clk-mt8192-venc.o obj-$(CONFIG_COMMON_CLK_MT8195) += clk-mt8195-apmixedsys.o clk-mt8195-topckgen.o \ - clk-mt8195-peri_ao.o clk-mt8195-infra_ao.o \ - clk-mt8195-cam.o clk-mt8195-ccu.o clk-mt8195-img.o \ - clk-mt8195-ipe.o clk-mt8195-mfg.o clk-mt8195-scp_adsp.o \ - clk-mt8195-vdec.o clk-mt8195-vdo0.o clk-mt8195-vdo1.o \ - clk-mt8195-venc.o clk-mt8195-vpp0.o clk-mt8195-vpp1.o \ - clk-mt8195-wpe.o clk-mt8195-imp_iic_wrap.o \ - clk-mt8195-apusys_pll.o -obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365.o + clk-mt8195-peri_ao.o clk-mt8195-infra_ao.o +obj-$(CONFIG_COMMON_CLK_MT8195_APUSYS) += clk-mt8195-apusys_pll.o +obj-$(CONFIG_COMMON_CLK_MT8195_CAMSYS) += clk-mt8195-cam.o clk-mt8195-ccu.o +obj-$(CONFIG_COMMON_CLK_MT8195_IMGSYS) += clk-mt8195-img.o +obj-$(CONFIG_COMMON_CLK_MT8195_IMP_IIC_WRAP) += clk-mt8195-imp_iic_wrap.o +obj-$(CONFIG_COMMON_CLK_MT8195_IPESYS) += clk-mt8195-ipe.o +obj-$(CONFIG_COMMON_CLK_MT8195_MFGCFG) += clk-mt8195-mfg.o +obj-$(CONFIG_COMMON_CLK_MT8195_SCP_ADSP) += clk-mt8195-scp_adsp.o +obj-$(CONFIG_COMMON_CLK_MT8195_VDECSYS) += clk-mt8195-vdec.o +obj-$(CONFIG_COMMON_CLK_MT8195_VDOSYS) += clk-mt8195-vdo0.o clk-mt8195-vdo1.o +obj-$(CONFIG_COMMON_CLK_MT8195_VENCSYS) += clk-mt8195-venc.o +obj-$(CONFIG_COMMON_CLK_MT8195_VPPSYS) += clk-mt8195-vpp0.o clk-mt8195-vpp1.o +obj-$(CONFIG_COMMON_CLK_MT8195_WPESYS) += clk-mt8195-wpe.o +obj-$(CONFIG_COMMON_CLK_MT8365) += clk-mt8365-apmixedsys.o clk-mt8365.o obj-$(CONFIG_COMMON_CLK_MT8365_APU) += clk-mt8365-apu.o obj-$(CONFIG_COMMON_CLK_MT8365_CAM) += clk-mt8365-cam.o obj-$(CONFIG_COMMON_CLK_MT8365_MFG) += clk-mt8365-mfg.o obj-$(CONFIG_COMMON_CLK_MT8365_MMSYS) += clk-mt8365-mm.o obj-$(CONFIG_COMMON_CLK_MT8365_VDEC) += clk-mt8365-vdec.o obj-$(CONFIG_COMMON_CLK_MT8365_VENC) += clk-mt8365-venc.o -obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o +obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516-apmixedsys.o clk-mt8516.o obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o diff --git a/drivers/clk/mediatek/clk-fhctl.c b/drivers/clk/mediatek/clk-fhctl.c index 4f271acef5fe..33b6ad8fdc2e 100644 --- a/drivers/clk/mediatek/clk-fhctl.c +++ b/drivers/clk/mediatek/clk-fhctl.c @@ -14,7 +14,20 @@ #define PERCENT_TO_DDSLMT(dds, percent_m10) \ ((((dds) * (percent_m10)) >> 5) / 100) -static const struct fhctl_offset fhctl_offset = { +static const struct fhctl_offset fhctl_offset_v1 = { + .offset_hp_en = 0x0, + .offset_clk_con = 0x4, + .offset_rst_con = 0x8, + .offset_slope0 = 0xc, + .offset_slope1 = 0x10, + .offset_cfg = 0x0, + .offset_updnlmt = 0x4, + .offset_dds = 0x8, + .offset_dvfs = 0xc, + .offset_mon = 0x10, +}; + +static const struct fhctl_offset fhctl_offset_v2 = { .offset_hp_en = 0x0, .offset_clk_con = 0x8, .offset_rst_con = 0xc, @@ -27,9 +40,16 @@ static const struct fhctl_offset fhctl_offset = { .offset_mon = 0x10, }; -const struct fhctl_offset *fhctl_get_offset_table(void) +const struct fhctl_offset *fhctl_get_offset_table(enum fhctl_variant v) { - return &fhctl_offset; + switch (v) { + case FHCTL_PLLFH_V1: + return &fhctl_offset_v1; + case FHCTL_PLLFH_V2: + return &fhctl_offset_v2; + default: + return ERR_PTR(-EINVAL); + }; } static void dump_hw(struct mtk_clk_pll *pll, struct fh_pll_regs *regs, diff --git a/drivers/clk/mediatek/clk-fhctl.h b/drivers/clk/mediatek/clk-fhctl.h index 51275febf086..bfa6d281a3ee 100644 --- a/drivers/clk/mediatek/clk-fhctl.h +++ b/drivers/clk/mediatek/clk-fhctl.h @@ -7,6 +7,13 @@ #ifndef __CLK_FHCTL_H #define __CLK_FHCTL_H +#include "clk-pllfh.h" + +enum fhctl_variant { + FHCTL_PLLFH_V1, + FHCTL_PLLFH_V2, +}; + struct fhctl_offset { u32 offset_hp_en; u32 offset_clk_con; @@ -19,7 +26,7 @@ struct fhctl_offset { u32 offset_dvfs; u32 offset_mon; }; -const struct fhctl_offset *fhctl_get_offset_table(void); +const struct fhctl_offset *fhctl_get_offset_table(enum fhctl_variant v); const struct fh_operation *fhctl_get_ops(void); void fhctl_hw_init(struct mtk_fh *fh); diff --git a/drivers/clk/mediatek/clk-mt2701-aud.c b/drivers/clk/mediatek/clk-mt2701-aud.c index 1a32d8b7db84..5cd343b98685 100644 --- a/drivers/clk/mediatek/clk-mt2701-aud.c +++ b/drivers/clk/mediatek/clk-mt2701-aud.c @@ -15,41 +15,17 @@ #include -#define GATE_AUDIO0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio2_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio3_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate_regs audio0_cg_regs = { .set_ofs = 0x0, @@ -148,6 +124,7 @@ static const struct of_device_id of_match_clk_mt2701_aud[] = { { .compatible = "mediatek,mt2701-audsys", .data = &audio_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_aud); static int clk_mt2701_aud_probe(struct platform_device *pdev) { @@ -187,5 +164,5 @@ static struct platform_driver clk_mt2701_aud_drv = { .of_match_table = of_match_clk_mt2701_aud, }, }; - -builtin_platform_driver(clk_mt2701_aud_drv); +module_platform_driver(clk_mt2701_aud_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-bdp.c b/drivers/clk/mediatek/clk-mt2701-bdp.c index 435ed4819d56..4c5b70d48df9 100644 --- a/drivers/clk/mediatek/clk-mt2701-bdp.c +++ b/drivers/clk/mediatek/clk-mt2701-bdp.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs bdp1_cg_regs = { .sta_ofs = 0x0110, }; -#define GATE_BDP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &bdp0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_BDP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &bdp0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_BDP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &bdp1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_BDP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &bdp1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate bdp_clks[] = { GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0), @@ -107,6 +95,7 @@ static const struct of_device_id of_match_clk_mt2701_bdp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_bdp); static struct platform_driver clk_mt2701_bdp_drv = { .probe = mtk_clk_simple_probe, @@ -116,5 +105,5 @@ static struct platform_driver clk_mt2701_bdp_drv = { .of_match_table = of_match_clk_mt2701_bdp, }, }; - -builtin_platform_driver(clk_mt2701_bdp_drv); +module_platform_driver(clk_mt2701_bdp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-eth.c b/drivers/clk/mediatek/clk-mt2701-eth.c index f3cb78e7f6e9..9a1fb0c93964 100644 --- a/drivers/clk/mediatek/clk-mt2701-eth.c +++ b/drivers/clk/mediatek/clk-mt2701-eth.c @@ -16,14 +16,8 @@ static const struct mtk_gate_regs eth_cg_regs = { .sta_ofs = 0x0030, }; -#define GATE_ETH(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = ð_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_ETH(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, ð_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate eth_clks[] = { GATE_DUMMY(CLK_DUMMY, "eth_dummy"), @@ -55,6 +49,7 @@ static const struct of_device_id of_match_clk_mt2701_eth[] = { { .compatible = "mediatek,mt2701-ethsys", .data = ð_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_eth); static struct platform_driver clk_mt2701_eth_drv = { .probe = mtk_clk_simple_probe, @@ -64,5 +59,5 @@ static struct platform_driver clk_mt2701_eth_drv = { .of_match_table = of_match_clk_mt2701_eth, }, }; - -builtin_platform_driver(clk_mt2701_eth_drv); +module_platform_driver(clk_mt2701_eth_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-g3d.c b/drivers/clk/mediatek/clk-mt2701-g3d.c index 499a170ba5f9..c0006861a317 100644 --- a/drivers/clk/mediatek/clk-mt2701-g3d.c +++ b/drivers/clk/mediatek/clk-mt2701-g3d.c @@ -16,14 +16,8 @@ #include -#define GATE_G3D(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &g3d_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_G3D(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &g3d_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate_regs g3d_cg_regs = { .sta_ofs = 0x0, @@ -54,6 +48,7 @@ static const struct of_device_id of_match_clk_mt2701_g3d[] = { { .compatible = "mediatek,mt2701-g3dsys", .data = &g3d_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_g3d); static struct platform_driver clk_mt2701_g3d_drv = { .probe = mtk_clk_simple_probe, @@ -63,5 +58,5 @@ static struct platform_driver clk_mt2701_g3d_drv = { .of_match_table = of_match_clk_mt2701_g3d, }, }; - -builtin_platform_driver(clk_mt2701_g3d_drv); +module_platform_driver(clk_mt2701_g3d_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-hif.c b/drivers/clk/mediatek/clk-mt2701-hif.c index d5465d782993..ff7c0b3228e4 100644 --- a/drivers/clk/mediatek/clk-mt2701-hif.c +++ b/drivers/clk/mediatek/clk-mt2701-hif.c @@ -16,14 +16,8 @@ static const struct mtk_gate_regs hif_cg_regs = { .sta_ofs = 0x0030, }; -#define GATE_HIF(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &hif_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_HIF(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &hif_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate hif_clks[] = { GATE_DUMMY(CLK_DUMMY, "hif_dummy"), @@ -52,6 +46,7 @@ static const struct of_device_id of_match_clk_mt2701_hif[] = { { .compatible = "mediatek,mt2701-hifsys", .data = &hif_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_hif); static struct platform_driver clk_mt2701_hif_drv = { .probe = mtk_clk_simple_probe, @@ -61,5 +56,5 @@ static struct platform_driver clk_mt2701_hif_drv = { .of_match_table = of_match_clk_mt2701_hif, }, }; - -builtin_platform_driver(clk_mt2701_hif_drv); +module_platform_driver(clk_mt2701_hif_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-img.c b/drivers/clk/mediatek/clk-mt2701-img.c index 7e53deb7f990..baa1194eb01e 100644 --- a/drivers/clk/mediatek/clk-mt2701-img.c +++ b/drivers/clk/mediatek/clk-mt2701-img.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs img_cg_regs = { .sta_ofs = 0x0000, }; -#define GATE_IMG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &img_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate img_clks[] = { GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0), @@ -49,6 +43,7 @@ static const struct of_device_id of_match_clk_mt2701_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_img); static struct platform_driver clk_mt2701_img_drv = { .probe = mtk_clk_simple_probe, @@ -58,5 +53,5 @@ static struct platform_driver clk_mt2701_img_drv = { .of_match_table = of_match_clk_mt2701_img, }, }; - -builtin_platform_driver(clk_mt2701_img_drv); +module_platform_driver(clk_mt2701_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-mm.c b/drivers/clk/mediatek/clk-mt2701-mm.c index 23d5ddcc1d37..c62c56fd2b7e 100644 --- a/drivers/clk/mediatek/clk-mt2701-mm.c +++ b/drivers/clk/mediatek/clk-mt2701-mm.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs disp1_cg_regs = { .sta_ofs = 0x0110, }; -#define GATE_DISP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &disp0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_DISP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &disp0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_DISP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &disp1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_DISP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &disp1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mm_clks[] = { GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0), @@ -79,32 +67,24 @@ static const struct mtk_gate mm_clks[] = { GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14), }; -static int clk_mt2701_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR); - - mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - dev_err(&pdev->dev, - "could not register clock provider: %s: %d\n", - pdev->name, r); - - return r; -} +static const struct platform_device_id clk_mt2701_mm_id_table[] = { + { .name = "clk-mt2701-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt2701_mm_id_table); static struct platform_driver clk_mt2701_mm_drv = { - .probe = clk_mt2701_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt2701-mm", }, + .id_table = clk_mt2701_mm_id_table, }; - -builtin_platform_driver(clk_mt2701_mm_drv); +module_platform_driver(clk_mt2701_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701-vdec.c b/drivers/clk/mediatek/clk-mt2701-vdec.c index d3089da0ab62..b7f97bc51c16 100644 --- a/drivers/clk/mediatek/clk-mt2701-vdec.c +++ b/drivers/clk/mediatek/clk-mt2701-vdec.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs vdec1_cg_regs = { .sta_ofs = 0x0008, }; -#define GATE_VDEC0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_VDEC1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate vdec_clks[] = { GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0), @@ -60,6 +48,7 @@ static const struct of_device_id of_match_clk_mt2701_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701_vdec); static struct platform_driver clk_mt2701_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -69,5 +58,5 @@ static struct platform_driver clk_mt2701_vdec_drv = { .of_match_table = of_match_clk_mt2701_vdec, }, }; - -builtin_platform_driver(clk_mt2701_vdec_drv); +module_platform_driver(clk_mt2701_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 06ca81359d35..4a154da8a543 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -636,14 +636,8 @@ static const struct mtk_gate_regs top_aud_cg_regs = { .sta_ofs = 0x012C, }; -#define GATE_TOP_AUD(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top_aud_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP_AUD(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top_aud_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate top_clks[] = { GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", @@ -687,7 +681,7 @@ static int mtk_topckgen_init(struct platform_device *pdev) ARRAY_SIZE(top_muxes), base, &mt2701_clk_lock, clk_data); - mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), + mtk_clk_register_dividers(&pdev->dev, top_adj_divs, ARRAY_SIZE(top_adj_divs), base, &mt2701_clk_lock, clk_data); mtk_clk_register_gates(&pdev->dev, node, top_clks, @@ -702,14 +696,8 @@ static const struct mtk_gate_regs infra_cg_regs = { .sta_ofs = 0x0048, }; -#define GATE_ICG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_ICG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate infra_clks[] = { GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0), @@ -823,23 +811,11 @@ static const struct mtk_gate_regs peri1_cg_regs = { .sta_ofs = 0x001c, }; -#define GATE_PERI0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate peri_clks[] = { GATE_PERI0(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31), @@ -1023,6 +999,7 @@ static const struct of_device_id of_match_clk_mt2701[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2701); static int clk_mt2701_probe(struct platform_device *pdev) { @@ -1056,3 +1033,4 @@ static int __init clk_mt2701_init(void) } arch_initcall(clk_mt2701_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-apmixedsys.c b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c new file mode 100644 index 000000000000..9d2fcda285fb --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-apmixedsys.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 MediaTek Inc. + * Weiyi Lu + * Copyright (c) 2023 Collabora Ltd. + * AngeloGioacchino Del Regno + */ +#include +#include +#include + +#include "clk-pll.h" +#include "clk-mtk.h" + +#include + +#define MT2712_PLL_FMAX (3000UL * MHZ) + +#define CON0_MT2712_RST_BAR BIT(24) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT2712_RST_BAR, \ + .fmax = MT2712_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _pcwbits, _pd_reg, _pd_shift, _tuner_reg, \ + _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ + _pcw_shift, NULL) + +static const struct mtk_pll_div_table armca35pll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 1202500000 }, + { .div = 2, .freq = 500500000 }, + { .div = 3, .freq = 315250000 }, + { .div = 4, .freq = 157625000 }, + { /* sentinel */ } +}; + +static const struct mtk_pll_div_table armca72pll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 994500000 }, + { .div = 2, .freq = 520000000 }, + { .div = 3, .freq = 315250000 }, + { .div = 4, .freq = 157625000 }, + { /* sentinel */ } +}; + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 1001000000 }, + { .div = 2, .freq = 601250000 }, + { .div = 3, .freq = 250250000 }, + { .div = 4, .freq = 125125000 }, + { /* sentinel */ } +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0230, 0x023C, 0xf0000100, + HAVE_RST_BAR, 31, 0x0230, 4, 0, 0, 0, 0x0234, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0240, 0x024C, 0xfe000100, + HAVE_RST_BAR, 31, 0x0240, 4, 0, 0, 0, 0x0244, 0), + PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x0320, 0x032C, 0xc0000100, + 0, 31, 0x0320, 4, 0, 0, 0, 0x0324, 0), + PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x0280, 0x028C, 0x00000100, + 0, 31, 0x0280, 4, 0, 0, 0, 0x0284, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0330, 0x0340, 0x00000100, + 0, 31, 0x0330, 4, 0x0338, 0x0014, 0, 0x0334, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0350, 0x0360, 0x00000100, + 0, 31, 0x0350, 4, 0x0358, 0x0014, 1, 0x0354, 0), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0370, 0x037c, 0x00000100, + 0, 31, 0x0370, 4, 0, 0, 0, 0x0374, 0), + PLL(CLK_APMIXED_LVDSPLL2, "lvdspll2", 0x0390, 0x039C, 0x00000100, + 0, 31, 0x0390, 4, 0, 0, 0, 0x0394, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0270, 0x027C, 0x00000100, + 0, 31, 0x0270, 4, 0, 0, 0, 0x0274, 0), + PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x0410, 0x041C, 0x00000100, + 0, 31, 0x0410, 4, 0, 0, 0, 0x0414, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0290, 0x029C, 0xc0000100, + 0, 31, 0x0290, 4, 0, 0, 0, 0x0294, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0250, 0x0260, 0x00000100, + 0, 31, 0x0250, 4, 0, 0, 0, 0x0254, 0, mmpll_div_table), + PLL_B(CLK_APMIXED_ARMCA35PLL, "armca35pll", 0x0100, 0x0110, 0xf0000100, + HAVE_RST_BAR, 31, 0x0100, 4, 0, 0, 0, 0x0104, 0, armca35pll_div_table), + PLL_B(CLK_APMIXED_ARMCA72PLL, "armca72pll", 0x0210, 0x0220, 0x00000100, + 0, 31, 0x0210, 4, 0, 0, 0, 0x0214, 0, armca72pll_div_table), + PLL(CLK_APMIXED_ETHERPLL, "etherpll", 0x0300, 0x030C, 0xc0000100, + 0, 31, 0x0300, 4, 0, 0, 0, 0x0304, 0), +}; + +static int clk_mt2712_apmixed_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (r) + goto free_clk_data; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) { + dev_err(&pdev->dev, "Cannot register clock provider: %d\n", r); + goto unregister_plls; + } + + return 0; + +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + return r; +} + +static int clk_mt2712_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static const struct of_device_id of_match_clk_mt2712_apmixed[] = { + { .compatible = "mediatek,mt2712-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_apmixed); + +static struct platform_driver clk_mt2712_apmixed_drv = { + .probe = clk_mt2712_apmixed_probe, + .remove = clk_mt2712_apmixed_remove, + .driver = { + .name = "clk-mt2712-apmixed", + .of_match_table = of_match_clk_mt2712_apmixed, + }, +}; +module_platform_driver(clk_mt2712_apmixed_drv) +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-bdp.c b/drivers/clk/mediatek/clk-mt2712-bdp.c index 684d03e9f6de..f78e01819316 100644 --- a/drivers/clk/mediatek/clk-mt2712-bdp.c +++ b/drivers/clk/mediatek/clk-mt2712-bdp.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs bdp_cg_regs = { .sta_ofs = 0x100, }; -#define GATE_BDP(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &bdp_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_BDP(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &bdp_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate bdp_clks[] = { GATE_BDP(CLK_BDP_BRIDGE_B, "bdp_bridge_b", "mm_sel", 0), @@ -71,6 +65,7 @@ static const struct of_device_id of_match_clk_mt2712_bdp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_bdp); static struct platform_driver clk_mt2712_bdp_drv = { .probe = mtk_clk_simple_probe, @@ -80,5 +75,5 @@ static struct platform_driver clk_mt2712_bdp_drv = { .of_match_table = of_match_clk_mt2712_bdp, }, }; - -builtin_platform_driver(clk_mt2712_bdp_drv); +module_platform_driver(clk_mt2712_bdp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-img.c b/drivers/clk/mediatek/clk-mt2712-img.c index 335049cdc856..fbe7084886a0 100644 --- a/drivers/clk/mediatek/clk-mt2712-img.c +++ b/drivers/clk/mediatek/clk-mt2712-img.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs img_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_IMG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &img_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate img_clks[] = { GATE_IMG(CLK_IMG_SMI_LARB2, "img_smi_larb2", "mm_sel", 0), @@ -49,6 +43,7 @@ static const struct of_device_id of_match_clk_mt2712_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_img); static struct platform_driver clk_mt2712_img_drv = { .probe = mtk_clk_simple_probe, @@ -58,5 +53,5 @@ static struct platform_driver clk_mt2712_img_drv = { .of_match_table = of_match_clk_mt2712_img, }, }; - -builtin_platform_driver(clk_mt2712_img_drv); +module_platform_driver(clk_mt2712_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-jpgdec.c b/drivers/clk/mediatek/clk-mt2712-jpgdec.c index 07ba7c5e80af..7e8c2ebcdee0 100644 --- a/drivers/clk/mediatek/clk-mt2712-jpgdec.c +++ b/drivers/clk/mediatek/clk-mt2712-jpgdec.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs jpgdec_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_JPGDEC(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &jpgdec_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_JPGDEC(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &jpgdec_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate jpgdec_clks[] = { GATE_JPGDEC(CLK_JPGDEC_JPGDEC1, "jpgdec_jpgdec1", "jpgdec_sel", 0), @@ -45,6 +39,7 @@ static const struct of_device_id of_match_clk_mt2712_jpgdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_jpgdec); static struct platform_driver clk_mt2712_jpgdec_drv = { .probe = mtk_clk_simple_probe, @@ -54,5 +49,5 @@ static struct platform_driver clk_mt2712_jpgdec_drv = { .of_match_table = of_match_clk_mt2712_jpgdec, }, }; - -builtin_platform_driver(clk_mt2712_jpgdec_drv); +module_platform_driver(clk_mt2712_jpgdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-mfg.c b/drivers/clk/mediatek/clk-mt2712-mfg.c index 42f8cf3ecf4c..932ea449d299 100644 --- a/drivers/clk/mediatek/clk-mt2712-mfg.c +++ b/drivers/clk/mediatek/clk-mt2712-mfg.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs mfg_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_MFG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mfg_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MFG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mfg_clks[] = { GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_sel", 0), @@ -44,6 +38,7 @@ static const struct of_device_id of_match_clk_mt2712_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_mfg); static struct platform_driver clk_mt2712_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -53,5 +48,5 @@ static struct platform_driver clk_mt2712_mfg_drv = { .of_match_table = of_match_clk_mt2712_mfg, }, }; - -builtin_platform_driver(clk_mt2712_mfg_drv); +module_platform_driver(clk_mt2712_mfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-mm.c b/drivers/clk/mediatek/clk-mt2712-mm.c index 25b8af640c12..204a3eae08dc 100644 --- a/drivers/clk/mediatek/clk-mt2712-mm.c +++ b/drivers/clk/mediatek/clk-mt2712-mm.c @@ -30,32 +30,14 @@ static const struct mtk_gate_regs mm2_cg_regs = { .sta_ofs = 0x220, }; -#define GATE_MM0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_MM1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_MM2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mm_clks[] = { /* MM0 */ @@ -126,32 +108,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM2(CLK_MM_DSI3_DIGITAL, "mm_dsi3_digital", "dsi1_lntc", 6), }; -static int clk_mt2712_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - - mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r != 0) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - return r; -} +static const struct platform_device_id clk_mt2712_mm_id_table[] = { + { .name = "clk-mt2712-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt2712_mm_id_table); static struct platform_driver clk_mt2712_mm_drv = { - .probe = clk_mt2712_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt2712-mm", }, + .id_table = clk_mt2712_mm_id_table, }; - -builtin_platform_driver(clk_mt2712_mm_drv); +module_platform_driver(clk_mt2712_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-vdec.c b/drivers/clk/mediatek/clk-mt2712-vdec.c index 6296ed5c5b55..2fc1f82ebf5d 100644 --- a/drivers/clk/mediatek/clk-mt2712-vdec.c +++ b/drivers/clk/mediatek/clk-mt2712-vdec.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs vdec1_cg_regs = { .sta_ofs = 0x8, }; -#define GATE_VDEC0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_VDEC1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate vdec_clks[] = { /* VDEC0 */ @@ -63,6 +51,7 @@ static const struct of_device_id of_match_clk_mt2712_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_vdec); static struct platform_driver clk_mt2712_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -72,5 +61,5 @@ static struct platform_driver clk_mt2712_vdec_drv = { .of_match_table = of_match_clk_mt2712_vdec, }, }; - -builtin_platform_driver(clk_mt2712_vdec_drv); +module_platform_driver(clk_mt2712_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712-venc.c b/drivers/clk/mediatek/clk-mt2712-venc.c index b9bfc35de629..6d053a00cf95 100644 --- a/drivers/clk/mediatek/clk-mt2712-venc.c +++ b/drivers/clk/mediatek/clk-mt2712-venc.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs venc_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_VENC(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &venc_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VENC(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &venc_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate venc_clks[] = { GATE_VENC(CLK_VENC_SMI_COMMON_CON, "venc_smi", "mm_sel", 0), @@ -46,6 +40,7 @@ static const struct of_device_id of_match_clk_mt2712_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712_venc); static struct platform_driver clk_mt2712_venc_drv = { .probe = mtk_clk_simple_probe, @@ -55,5 +50,5 @@ static struct platform_driver clk_mt2712_venc_drv = { .of_match_table = of_match_clk_mt2712_venc, }, }; - -builtin_platform_driver(clk_mt2712_venc_drv); +module_platform_driver(clk_mt2712_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 94f8fc2a4f7b..74c529f6163d 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -14,7 +14,6 @@ #include #include "clk-gate.h" -#include "clk-pll.h" #include "clk-mtk.h" #include @@ -36,188 +35,96 @@ static const struct mtk_fixed_clk top_fixed_clks[] = { FIXED_CLK(CLK_TOP_CVBSPLL, "cvbspll", NULL, 108000000), }; -static const struct mtk_fixed_factor top_early_divs[] = { - FACTOR(CLK_TOP_SYS_26M, "sys_26m", "clk26m", 1, - 1), - FACTOR(CLK_TOP_CLK26M_D2, "clk26m_d2", "sys_26m", 1, - 2), -}; - static const struct mtk_fixed_factor top_divs[] = { - FACTOR(CLK_TOP_ARMCA35PLL, "armca35pll_ck", "armca35pll", 1, - 1), - FACTOR(CLK_TOP_ARMCA35PLL_600M, "armca35pll_600m", "armca35pll_ck", 1, - 2), - FACTOR(CLK_TOP_ARMCA35PLL_400M, "armca35pll_400m", "armca35pll_ck", 1, - 3), - FACTOR(CLK_TOP_ARMCA72PLL, "armca72pll_ck", "armca72pll", 1, - 1), - FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, - 1), - FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "syspll_ck", 1, - 2), - FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, - 2), - FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, - 4), - FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, - 8), - FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, - 16), - FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "syspll_ck", 1, - 3), - FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, - 2), - FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, - 4), - FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "syspll_ck", 1, - 5), - FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, - 2), - FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, - 4), - FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "syspll_ck", 1, - 7), - FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, - 2), - FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, - 4), - FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, - 1), - FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll_ck", 1, - 7), - FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll_ck", 1, - 26), - FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll_ck", 1, - 52), - FACTOR(CLK_TOP_UNIVPLL_D104, "univpll_d104", "univpll_ck", 1, - 104), - FACTOR(CLK_TOP_UNIVPLL_D208, "univpll_d208", "univpll_ck", 1, - 208), - FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll_ck", 1, - 2), - FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, - 2), - FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, - 4), - FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, - 8), - FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll_ck", 1, - 3), - FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, - 2), - FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, - 4), - FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, - 8), - FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll_ck", 1, - 5), - FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, - 2), - FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, - 4), - FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, - 8), - FACTOR(CLK_TOP_F_MP0_PLL1, "f_mp0_pll1_ck", "univpll_d2", 1, - 1), - FACTOR(CLK_TOP_F_MP0_PLL2, "f_mp0_pll2_ck", "univpll1_d2", 1, - 1), - FACTOR(CLK_TOP_F_BIG_PLL1, "f_big_pll1_ck", "univpll_d2", 1, - 1), - FACTOR(CLK_TOP_F_BIG_PLL2, "f_big_pll2_ck", "univpll1_d2", 1, - 1), - FACTOR(CLK_TOP_F_BUS_PLL1, "f_bus_pll1_ck", "univpll_d2", 1, - 1), - FACTOR(CLK_TOP_F_BUS_PLL2, "f_bus_pll2_ck", "univpll1_d2", 1, - 1), - FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, - 1), - FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1_ck", 1, - 2), - FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1_ck", 1, - 4), - FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1_ck", 1, - 8), - FACTOR(CLK_TOP_APLL1_D16, "apll1_d16", "apll1_ck", 1, - 16), - FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, - 1), - FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2_ck", 1, - 2), - FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2_ck", 1, - 4), - FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2_ck", 1, - 8), - FACTOR(CLK_TOP_APLL2_D16, "apll2_d16", "apll2_ck", 1, - 16), - FACTOR(CLK_TOP_LVDSPLL, "lvdspll_ck", "lvdspll", 1, - 1), - FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll_ck", 1, - 2), - FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll_ck", 1, - 4), - FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll_ck", 1, - 8), - FACTOR(CLK_TOP_LVDSPLL2, "lvdspll2_ck", "lvdspll2", 1, - 1), - FACTOR(CLK_TOP_LVDSPLL2_D2, "lvdspll2_d2", "lvdspll2_ck", 1, - 2), - FACTOR(CLK_TOP_LVDSPLL2_D4, "lvdspll2_d4", "lvdspll2_ck", 1, - 4), - FACTOR(CLK_TOP_LVDSPLL2_D8, "lvdspll2_d8", "lvdspll2_ck", 1, - 8), - FACTOR(CLK_TOP_ETHERPLL_125M, "etherpll_125m", "etherpll", 1, - 1), - FACTOR(CLK_TOP_ETHERPLL_50M, "etherpll_50m", "etherpll", 1, - 1), - FACTOR(CLK_TOP_CVBS, "cvbs", "cvbspll", 1, - 1), - FACTOR(CLK_TOP_CVBS_D2, "cvbs_d2", "cvbs", 1, - 2), - FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, - 1), - FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll_ck", 1, - 2), - FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, - 1), - FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll_ck", 1, - 2), - FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, - 1), - FACTOR(CLK_TOP_VCODECPLL_D2, "vcodecpll_d2", "vcodecpll_ck", 1, - 2), - FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, - 1), - FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_ck", 1, - 2), - FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_ck", 1, - 4), - FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_ck", 1, - 8), - FACTOR(CLK_TOP_TVDPLL_429M, "tvdpll_429m", "tvdpll", 1, - 1), - FACTOR(CLK_TOP_TVDPLL_429M_D2, "tvdpll_429m_d2", "tvdpll_429m", 1, - 2), - FACTOR(CLK_TOP_TVDPLL_429M_D4, "tvdpll_429m_d4", "tvdpll_429m", 1, - 4), - FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, - 1), - FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll_ck", 1, - 2), - FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll_ck", 1, - 4), - FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, - 1), - FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2_ck", 1, - 2), - FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2_ck", 1, - 4), - FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, - 4), - FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, - 3), - FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2_ck", 1, - 3), + FACTOR(CLK_TOP_SYS_26M, "sys_26m", "clk26m", 1, 1), + FACTOR(CLK_TOP_CLK26M_D2, "clk26m_d2", "sys_26m", 1, 2), + FACTOR(CLK_TOP_ARMCA35PLL, "armca35pll_ck", "armca35pll", 1, 1), + FACTOR(CLK_TOP_ARMCA35PLL_600M, "armca35pll_600m", "armca35pll_ck", 1, 2), + FACTOR(CLK_TOP_ARMCA35PLL_400M, "armca35pll_400m", "armca35pll_ck", 1, 3), + FACTOR(CLK_TOP_ARMCA72PLL, "armca72pll_ck", "armca72pll", 1, 1), + FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1), + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "syspll_ck", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8), + FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "syspll_ck", 1, 3), + FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "syspll_ck", 1, 5), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4), + FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "syspll_ck", 1, 7), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4), + FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll_ck", 1, 7), + FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll_ck", 1, 26), + FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll_ck", 1, 52), + FACTOR(CLK_TOP_UNIVPLL_D104, "univpll_d104", "univpll_ck", 1, 104), + FACTOR(CLK_TOP_UNIVPLL_D208, "univpll_d208", "univpll_ck", 1, 208), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll_ck", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll_ck", 1, 3), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll_ck", 1, 5), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4), + FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8), + FACTOR(CLK_TOP_F_MP0_PLL1, "f_mp0_pll1_ck", "univpll_d2", 1, 1), + FACTOR(CLK_TOP_F_MP0_PLL2, "f_mp0_pll2_ck", "univpll1_d2", 1, 1), + FACTOR(CLK_TOP_F_BIG_PLL1, "f_big_pll1_ck", "univpll_d2", 1, 1), + FACTOR(CLK_TOP_F_BIG_PLL2, "f_big_pll2_ck", "univpll1_d2", 1, 1), + FACTOR(CLK_TOP_F_BUS_PLL1, "f_bus_pll1_ck", "univpll_d2", 1, 1), + FACTOR(CLK_TOP_F_BUS_PLL2, "f_bus_pll2_ck", "univpll1_d2", 1, 1), + FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1), + FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1_ck", 1, 2), + FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1_ck", 1, 4), + FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1_ck", 1, 8), + FACTOR(CLK_TOP_APLL1_D16, "apll1_d16", "apll1_ck", 1, 16), + FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1), + FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2_ck", 1, 2), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2_ck", 1, 4), + FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2_ck", 1, 8), + FACTOR(CLK_TOP_APLL2_D16, "apll2_d16", "apll2_ck", 1, 16), + FACTOR(CLK_TOP_LVDSPLL, "lvdspll_ck", "lvdspll", 1, 1), + FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll_ck", 1, 2), + FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll_ck", 1, 4), + FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll_ck", 1, 8), + FACTOR(CLK_TOP_LVDSPLL2, "lvdspll2_ck", "lvdspll2", 1, 1), + FACTOR(CLK_TOP_LVDSPLL2_D2, "lvdspll2_d2", "lvdspll2_ck", 1, 2), + FACTOR(CLK_TOP_LVDSPLL2_D4, "lvdspll2_d4", "lvdspll2_ck", 1, 4), + FACTOR(CLK_TOP_LVDSPLL2_D8, "lvdspll2_d8", "lvdspll2_ck", 1, 8), + FACTOR(CLK_TOP_ETHERPLL_125M, "etherpll_125m", "etherpll", 1, 1), + FACTOR(CLK_TOP_ETHERPLL_50M, "etherpll_50m", "etherpll", 1, 1), + FACTOR(CLK_TOP_CVBS, "cvbs", "cvbspll", 1, 1), + FACTOR(CLK_TOP_CVBS_D2, "cvbs_d2", "cvbs", 1, 2), + FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll_ck", 1, 2), + FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1), + FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll_ck", 1, 2), + FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 1), + FACTOR(CLK_TOP_VCODECPLL_D2, "vcodecpll_d2", "vcodecpll_ck", 1, 2), + FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_ck", 1, 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_ck", 1, 4), + FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_ck", 1, 8), + FACTOR(CLK_TOP_TVDPLL_429M, "tvdpll_429m", "tvdpll", 1, 1), + FACTOR(CLK_TOP_TVDPLL_429M_D2, "tvdpll_429m_d2", "tvdpll_429m", 1, 2), + FACTOR(CLK_TOP_TVDPLL_429M_D4, "tvdpll_429m_d4", "tvdpll_429m", 1, 4), + FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll_ck", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll_ck", 1, 4), + FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1), + FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2_ck", 1, 2), + FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2_ck", 1, 4), + FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, 4), + FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, 3), + FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2_ck", 1, 3), }; static const char * const axi_parents[] = { @@ -737,169 +644,118 @@ static const char * const audull_vtx_parents[] = { static struct mtk_composite top_muxes[] = { /* CLK_CFG_0 */ MUX_GATE_FLAGS(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x040, 0, 3, - 7, CLK_IS_CRITICAL), + 7, CLK_IS_CRITICAL), MUX_GATE_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x040, 8, 1, - 15, CLK_IS_CRITICAL), - MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", - mm_parents, 0x040, 24, 3, 31), + 15, CLK_IS_CRITICAL), + MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x040, 24, 3, 31), /* CLK_CFG_1 */ - MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", - pwm_parents, 0x050, 0, 2, 7), - MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", - vdec_parents, 0x050, 8, 4, 15), - MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", - venc_parents, 0x050, 16, 4, 23), - MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", - mfg_parents, 0x050, 24, 4, 31), + MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x050, 0, 2, 7), + MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x050, 8, 4, 15), + MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x050, 16, 4, 23), + MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x050, 24, 4, 31), /* CLK_CFG_2 */ - MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", - camtg_parents, 0x060, 0, 4, 7), - MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", - uart_parents, 0x060, 8, 1, 15), - MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", - spi_parents, 0x060, 16, 3, 23), - MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", - usb20_parents, 0x060, 24, 2, 31), + MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x060, 0, 4, 7), + MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x060, 8, 1, 15), + MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x060, 16, 3, 23), + MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x060, 24, 2, 31), /* CLK_CFG_3 */ - MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", - usb30_parents, 0x070, 0, 2, 7), - MUX_GATE(CLK_TOP_MSDC50_0_HCLK_SEL, "msdc50_0_h_sel", - msdc50_0_h_parents, 0x070, 8, 3, 15), - MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", - msdc50_0_parents, 0x070, 16, 4, 23), - MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", - msdc30_1_parents, 0x070, 24, 3, 31), + MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x070, 0, 2, 7), + MUX_GATE(CLK_TOP_MSDC50_0_HCLK_SEL, "msdc50_0_h_sel", msdc50_0_h_parents, + 0x070, 8, 3, 15), + MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents, + 0x070, 16, 4, 23), + MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents, + 0x070, 24, 3, 31), /* CLK_CFG_4 */ - MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", - msdc30_1_parents, 0x080, 0, 3, 7), - MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", - msdc30_3_parents, 0x080, 8, 4, 15), - MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", - audio_parents, 0x080, 16, 2, 23), - MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", - aud_intbus_parents, 0x080, 24, 3, 31), + MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_1_parents, + 0x080, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents, + 0x080, 8, 4, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, + 0x080, 16, 2, 23), + MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, + 0x080, 24, 3, 31), /* CLK_CFG_5 */ - MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", - pmicspi_parents, 0x090, 0, 3, 7), - MUX_GATE(CLK_TOP_DPILVDS1_SEL, "dpilvds1_sel", - dpilvds1_parents, 0x090, 8, 3, 15), - MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", - atb_parents, 0x090, 16, 2, 23), - MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", - nr_parents, 0x090, 24, 3, 31), + MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x090, 0, 3, 7), + MUX_GATE(CLK_TOP_DPILVDS1_SEL, "dpilvds1_sel", dpilvds1_parents, + 0x090, 8, 3, 15), + MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x090, 16, 2, 23), + MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_parents, 0x090, 24, 3, 31), /* CLK_CFG_6 */ - MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", - nfi2x_parents, 0x0a0, 0, 4, 7), - MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", - irda_parents, 0x0a0, 8, 2, 15), - MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", - cci400_parents, 0x0a0, 16, 3, 23), - MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", - aud_1_parents, 0x0a0, 24, 2, 31), + MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, 0x0a0, 0, 4, 7), + MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x0a0, 8, 2, 15), + MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x0a0, 16, 3, 23), + MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x0a0, 24, 2, 31), /* CLK_CFG_7 */ - MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", - aud_2_parents, 0x0b0, 0, 2, 7), - MUX_GATE(CLK_TOP_MEM_MFG_IN_AS_SEL, "mem_mfg_sel", - mem_mfg_parents, 0x0b0, 8, 2, 15), - MUX_GATE(CLK_TOP_AXI_MFG_IN_AS_SEL, "axi_mfg_sel", - axi_mfg_parents, 0x0b0, 16, 2, 23), - MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", - scam_parents, 0x0b0, 24, 2, 31), + MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x0b0, 0, 2, 7), + MUX_GATE(CLK_TOP_MEM_MFG_IN_AS_SEL, "mem_mfg_sel", mem_mfg_parents, + 0x0b0, 8, 2, 15), + MUX_GATE(CLK_TOP_AXI_MFG_IN_AS_SEL, "axi_mfg_sel", axi_mfg_parents, + 0x0b0, 16, 2, 23), + MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x0b0, 24, 2, 31), /* CLK_CFG_8 */ - MUX_GATE(CLK_TOP_NFIECC_SEL, "nfiecc_sel", - nfiecc_parents, 0x0c0, 0, 3, 7), - MUX_GATE(CLK_TOP_PE2_MAC_P0_SEL, "pe2_mac_p0_sel", - pe2_mac_p0_parents, 0x0c0, 8, 3, 15), - MUX_GATE(CLK_TOP_PE2_MAC_P1_SEL, "pe2_mac_p1_sel", - pe2_mac_p0_parents, 0x0c0, 16, 3, 23), - MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", - dpilvds_parents, 0x0c0, 24, 3, 31), + MUX_GATE(CLK_TOP_NFIECC_SEL, "nfiecc_sel", nfiecc_parents, 0x0c0, 0, 3, 7), + MUX_GATE(CLK_TOP_PE2_MAC_P0_SEL, "pe2_mac_p0_sel", pe2_mac_p0_parents, + 0x0c0, 8, 3, 15), + MUX_GATE(CLK_TOP_PE2_MAC_P1_SEL, "pe2_mac_p1_sel", pe2_mac_p0_parents, + 0x0c0, 16, 3, 23), + MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x0c0, 24, 3, 31), /* CLK_CFG_9 */ - MUX_GATE(CLK_TOP_MSDC50_3_HCLK_SEL, "msdc50_3_h_sel", - msdc50_0_h_parents, 0x0d0, 0, 3, 7), - MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", - hdcp_parents, 0x0d0, 8, 2, 15), - MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", - hdcp_24m_parents, 0x0d0, 16, 2, 23), - MUX_GATE_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x0d0, 24, 2, - 31, CLK_IS_CRITICAL), + MUX_GATE(CLK_TOP_MSDC50_3_HCLK_SEL, "msdc50_3_h_sel", msdc50_0_h_parents, + 0x0d0, 0, 3, 7), + MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x0d0, 8, 2, 15), + MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents, + 0x0d0, 16, 2, 23), + MUX_GATE_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, + 0x0d0, 24, 2, 31, CLK_IS_CRITICAL), /* CLK_CFG_10 */ - MUX_GATE(CLK_TOP_SPINOR_SEL, "spinor_sel", - spinor_parents, 0x500, 0, 4, 7), - MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", - apll_parents, 0x500, 8, 4, 15), - MUX_GATE(CLK_TOP_APLL2_SEL, "apll2_sel", - apll_parents, 0x500, 16, 4, 23), - MUX_GATE(CLK_TOP_A1SYS_HP_SEL, "a1sys_hp_sel", - a1sys_hp_parents, 0x500, 24, 3, 31), + MUX_GATE(CLK_TOP_SPINOR_SEL, "spinor_sel", spinor_parents, 0x500, 0, 4, 7), + MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x500, 8, 4, 15), + MUX_GATE(CLK_TOP_APLL2_SEL, "apll2_sel", apll_parents, 0x500, 16, 4, 23), + MUX_GATE(CLK_TOP_A1SYS_HP_SEL, "a1sys_hp_sel", a1sys_hp_parents, + 0x500, 24, 3, 31), /* CLK_CFG_11 */ - MUX_GATE(CLK_TOP_A2SYS_HP_SEL, "a2sys_hp_sel", - a2sys_hp_parents, 0x510, 0, 3, 7), - MUX_GATE(CLK_TOP_ASM_L_SEL, "asm_l_sel", - asm_l_parents, 0x510, 8, 2, 15), - MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", - asm_l_parents, 0x510, 16, 2, 23), - MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", - asm_l_parents, 0x510, 24, 2, 31), + MUX_GATE(CLK_TOP_A2SYS_HP_SEL, "a2sys_hp_sel", a2sys_hp_parents, 0x510, 0, 3, 7), + MUX_GATE(CLK_TOP_ASM_L_SEL, "asm_l_sel", asm_l_parents, 0x510, 8, 2, 15), + MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_l_parents, 0x510, 16, 2, 23), + MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_l_parents, 0x510, 24, 2, 31), /* CLK_CFG_12 */ - MUX_GATE(CLK_TOP_I2SO1_SEL, "i2so1_sel", - i2so1_parents, 0x520, 0, 2, 7), - MUX_GATE(CLK_TOP_I2SO2_SEL, "i2so2_sel", - i2so1_parents, 0x520, 8, 2, 15), - MUX_GATE(CLK_TOP_I2SO3_SEL, "i2so3_sel", - i2so1_parents, 0x520, 16, 2, 23), - MUX_GATE(CLK_TOP_TDMO0_SEL, "tdmo0_sel", - i2so1_parents, 0x520, 24, 2, 31), + MUX_GATE(CLK_TOP_I2SO1_SEL, "i2so1_sel", i2so1_parents, 0x520, 0, 2, 7), + MUX_GATE(CLK_TOP_I2SO2_SEL, "i2so2_sel", i2so1_parents, 0x520, 8, 2, 15), + MUX_GATE(CLK_TOP_I2SO3_SEL, "i2so3_sel", i2so1_parents, 0x520, 16, 2, 23), + MUX_GATE(CLK_TOP_TDMO0_SEL, "tdmo0_sel", i2so1_parents, 0x520, 24, 2, 31), /* CLK_CFG_13 */ - MUX_GATE(CLK_TOP_TDMO1_SEL, "tdmo1_sel", - i2so1_parents, 0x530, 0, 2, 7), - MUX_GATE(CLK_TOP_I2SI1_SEL, "i2si1_sel", - i2so1_parents, 0x530, 8, 2, 15), - MUX_GATE(CLK_TOP_I2SI2_SEL, "i2si2_sel", - i2so1_parents, 0x530, 16, 2, 23), - MUX_GATE(CLK_TOP_I2SI3_SEL, "i2si3_sel", - i2so1_parents, 0x530, 24, 2, 31), + MUX_GATE(CLK_TOP_TDMO1_SEL, "tdmo1_sel", i2so1_parents, 0x530, 0, 2, 7), + MUX_GATE(CLK_TOP_I2SI1_SEL, "i2si1_sel", i2so1_parents, 0x530, 8, 2, 15), + MUX_GATE(CLK_TOP_I2SI2_SEL, "i2si2_sel", i2so1_parents, 0x530, 16, 2, 23), + MUX_GATE(CLK_TOP_I2SI3_SEL, "i2si3_sel", i2so1_parents, 0x530, 24, 2, 31), /* CLK_CFG_14 */ - MUX_GATE(CLK_TOP_ETHER_125M_SEL, "ether_125m_sel", - ether_125m_parents, 0x540, 0, 2, 7), - MUX_GATE(CLK_TOP_ETHER_50M_SEL, "ether_50m_sel", - ether_50m_parents, 0x540, 8, 2, 15), - MUX_GATE(CLK_TOP_JPGDEC_SEL, "jpgdec_sel", - jpgdec_parents, 0x540, 16, 4, 23), - MUX_GATE(CLK_TOP_SPISLV_SEL, "spislv_sel", - spislv_parents, 0x540, 24, 3, 31), + MUX_GATE(CLK_TOP_ETHER_125M_SEL, "ether_125m_sel", ether_125m_parents, + 0x540, 0, 2, 7), + MUX_GATE(CLK_TOP_ETHER_50M_SEL, "ether_50m_sel", ether_50m_parents, + 0x540, 8, 2, 15), + MUX_GATE(CLK_TOP_JPGDEC_SEL, "jpgdec_sel", jpgdec_parents, 0x540, 16, 4, 23), + MUX_GATE(CLK_TOP_SPISLV_SEL, "spislv_sel", spislv_parents, 0x540, 24, 3, 31), /* CLK_CFG_15 */ - MUX_GATE(CLK_TOP_ETHER_50M_RMII_SEL, "ether_sel", - ether_parents, 0x550, 0, 2, 7), - MUX_GATE(CLK_TOP_CAM2TG_SEL, "cam2tg_sel", - camtg_parents, 0x550, 8, 4, 15), - MUX_GATE(CLK_TOP_DI_SEL, "di_sel", - di_parents, 0x550, 16, 3, 23), - MUX_GATE(CLK_TOP_TVD_SEL, "tvd_sel", - tvd_parents, 0x550, 24, 2, 31), + MUX_GATE(CLK_TOP_ETHER_50M_RMII_SEL, "ether_sel", ether_parents, 0x550, 0, 2, 7), + MUX_GATE(CLK_TOP_CAM2TG_SEL, "cam2tg_sel", camtg_parents, 0x550, 8, 4, 15), + MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, 0x550, 16, 3, 23), + MUX_GATE(CLK_TOP_TVD_SEL, "tvd_sel", tvd_parents, 0x550, 24, 2, 31), /* CLK_CFG_16 */ - MUX_GATE(CLK_TOP_I2C_SEL, "i2c_sel", - i2c_parents, 0x560, 0, 3, 7), - MUX_GATE(CLK_TOP_PWM_INFRA_SEL, "pwm_infra_sel", - pwm_parents, 0x560, 8, 2, 15), - MUX_GATE(CLK_TOP_MSDC0P_AES_SEL, "msdc0p_aes_sel", - msdc0p_aes_parents, 0x560, 16, 2, 23), - MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", - cmsys_parents, 0x560, 24, 3, 31), + MUX_GATE(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x560, 0, 3, 7), + MUX_GATE(CLK_TOP_PWM_INFRA_SEL, "pwm_infra_sel", pwm_parents, 0x560, 8, 2, 15), + MUX_GATE(CLK_TOP_MSDC0P_AES_SEL, "msdc0p_aes_sel", msdc0p_aes_parents, + 0x560, 16, 2, 23), + MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, 0x560, 24, 3, 31), /* CLK_CFG_17 */ - MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", - gcpu_parents, 0x570, 0, 3, 7), + MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", gcpu_parents, 0x570, 0, 3, 7), /* CLK_AUDDIV_4 */ - MUX(CLK_TOP_AUD_APLL1_SEL, "aud_apll1_sel", - aud_apll1_parents, 0x134, 0, 1), - MUX(CLK_TOP_AUD_APLL2_SEL, "aud_apll2_sel", - aud_apll2_parents, 0x134, 1, 1), - MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", - audull_vtx_parents, 0x134, 31, 1), - MUX(CLK_TOP_APLL1_REF_SEL, "apll1_ref_sel", - apll1_ref_parents, 0x134, 4, 3), - MUX(CLK_TOP_APLL2_REF_SEL, "apll2_ref_sel", - apll1_ref_parents, 0x134, 7, 3), + MUX(CLK_TOP_AUD_APLL1_SEL, "aud_apll1_sel", aud_apll1_parents, 0x134, 0, 1), + MUX(CLK_TOP_AUD_APLL2_SEL, "aud_apll2_sel", aud_apll2_parents, 0x134, 1, 1), + MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", audull_vtx_parents, + 0x134, 31, 1), + MUX(CLK_TOP_APLL1_REF_SEL, "apll1_ref_sel", apll1_ref_parents, 0x134, 4, 3), + MUX(CLK_TOP_APLL2_REF_SEL, "apll2_ref_sel", apll1_ref_parents, 0x134, 7, 3), }; static const char * const mcu_mp0_parents[] = { @@ -926,13 +782,13 @@ static const char * const mcu_bus_parents[] = { static struct mtk_composite mcu_muxes[] = { /* mp0_pll_divider_cfg */ MUX_GATE_FLAGS(CLK_MCU_MP0_SEL, "mcu_mp0_sel", mcu_mp0_parents, 0x7A0, - 9, 2, -1, CLK_IS_CRITICAL), + 9, 2, -1, CLK_IS_CRITICAL), /* mp2_pll_divider_cfg */ MUX_GATE_FLAGS(CLK_MCU_MP2_SEL, "mcu_mp2_sel", mcu_mp2_parents, 0x7A8, - 9, 2, -1, CLK_IS_CRITICAL), + 9, 2, -1, CLK_IS_CRITICAL), /* bus_pll_divider_cfg */ MUX_GATE_FLAGS(CLK_MCU_BUS_SEL, "mcu_bus_sel", mcu_bus_parents, 0x7C0, - 9, 2, -1, CLK_IS_CRITICAL), + 9, 2, -1, CLK_IS_CRITICAL), }; static const struct mtk_clk_divider top_adj_divs[] = { @@ -958,23 +814,11 @@ static const struct mtk_gate_regs top1_cg_regs = { .sta_ofs = 0x424, }; -#define GATE_TOP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_TOP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate top_clks[] = { /* TOP0 */ @@ -998,14 +842,8 @@ static const struct mtk_gate_regs infra_cg_regs = { .sta_ofs = 0x48, }; -#define GATE_INFRA(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_INFRA(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate infra_clks[] = { GATE_INFRA(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0), @@ -1035,227 +873,65 @@ static const struct mtk_gate_regs peri2_cg_regs = { .sta_ofs = 0x42c, }; -#define GATE_PERI0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_PERI2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri2_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate peri_clks[] = { /* PERI0 */ - GATE_PERI0(CLK_PERI_NFI, "per_nfi", - "axi_sel", 0), - GATE_PERI0(CLK_PERI_THERM, "per_therm", - "axi_sel", 1), - GATE_PERI0(CLK_PERI_PWM0, "per_pwm0", - "pwm_sel", 2), - GATE_PERI0(CLK_PERI_PWM1, "per_pwm1", - "pwm_sel", 3), - GATE_PERI0(CLK_PERI_PWM2, "per_pwm2", - "pwm_sel", 4), - GATE_PERI0(CLK_PERI_PWM3, "per_pwm3", - "pwm_sel", 5), - GATE_PERI0(CLK_PERI_PWM4, "per_pwm4", - "pwm_sel", 6), - GATE_PERI0(CLK_PERI_PWM5, "per_pwm5", - "pwm_sel", 7), - GATE_PERI0(CLK_PERI_PWM6, "per_pwm6", - "pwm_sel", 8), - GATE_PERI0(CLK_PERI_PWM7, "per_pwm7", - "pwm_sel", 9), - GATE_PERI0(CLK_PERI_PWM, "per_pwm", - "pwm_sel", 10), - GATE_PERI0(CLK_PERI_AP_DMA, "per_ap_dma", - "axi_sel", 13), - GATE_PERI0(CLK_PERI_MSDC30_0, "per_msdc30_0", - "msdc50_0_sel", 14), - GATE_PERI0(CLK_PERI_MSDC30_1, "per_msdc30_1", - "msdc30_1_sel", 15), - GATE_PERI0(CLK_PERI_MSDC30_2, "per_msdc30_2", - "msdc30_2_sel", 16), - GATE_PERI0(CLK_PERI_MSDC30_3, "per_msdc30_3", - "msdc30_3_sel", 17), - GATE_PERI0(CLK_PERI_UART0, "per_uart0", - "uart_sel", 20), - GATE_PERI0(CLK_PERI_UART1, "per_uart1", - "uart_sel", 21), - GATE_PERI0(CLK_PERI_UART2, "per_uart2", - "uart_sel", 22), - GATE_PERI0(CLK_PERI_UART3, "per_uart3", - "uart_sel", 23), - GATE_PERI0(CLK_PERI_I2C0, "per_i2c0", - "axi_sel", 24), - GATE_PERI0(CLK_PERI_I2C1, "per_i2c1", - "axi_sel", 25), - GATE_PERI0(CLK_PERI_I2C2, "per_i2c2", - "axi_sel", 26), - GATE_PERI0(CLK_PERI_I2C3, "per_i2c3", - "axi_sel", 27), - GATE_PERI0(CLK_PERI_I2C4, "per_i2c4", - "axi_sel", 28), - GATE_PERI0(CLK_PERI_AUXADC, "per_auxadc", - "ltepll_fs26m", 29), - GATE_PERI0(CLK_PERI_SPI0, "per_spi0", - "spi_sel", 30), + GATE_PERI0(CLK_PERI_NFI, "per_nfi", "axi_sel", 0), + GATE_PERI0(CLK_PERI_THERM, "per_therm", "axi_sel", 1), + GATE_PERI0(CLK_PERI_PWM0, "per_pwm0", "pwm_sel", 2), + GATE_PERI0(CLK_PERI_PWM1, "per_pwm1", "pwm_sel", 3), + GATE_PERI0(CLK_PERI_PWM2, "per_pwm2", "pwm_sel", 4), + GATE_PERI0(CLK_PERI_PWM3, "per_pwm3", "pwm_sel", 5), + GATE_PERI0(CLK_PERI_PWM4, "per_pwm4", "pwm_sel", 6), + GATE_PERI0(CLK_PERI_PWM5, "per_pwm5", "pwm_sel", 7), + GATE_PERI0(CLK_PERI_PWM6, "per_pwm6", "pwm_sel", 8), + GATE_PERI0(CLK_PERI_PWM7, "per_pwm7", "pwm_sel", 9), + GATE_PERI0(CLK_PERI_PWM, "per_pwm", "pwm_sel", 10), + GATE_PERI0(CLK_PERI_AP_DMA, "per_ap_dma", "axi_sel", 13), + GATE_PERI0(CLK_PERI_MSDC30_0, "per_msdc30_0", "msdc50_0_sel", 14), + GATE_PERI0(CLK_PERI_MSDC30_1, "per_msdc30_1", "msdc30_1_sel", 15), + GATE_PERI0(CLK_PERI_MSDC30_2, "per_msdc30_2", "msdc30_2_sel", 16), + GATE_PERI0(CLK_PERI_MSDC30_3, "per_msdc30_3", "msdc30_3_sel", 17), + GATE_PERI0(CLK_PERI_UART0, "per_uart0", "uart_sel", 20), + GATE_PERI0(CLK_PERI_UART1, "per_uart1", "uart_sel", 21), + GATE_PERI0(CLK_PERI_UART2, "per_uart2", "uart_sel", 22), + GATE_PERI0(CLK_PERI_UART3, "per_uart3", "uart_sel", 23), + GATE_PERI0(CLK_PERI_I2C0, "per_i2c0", "axi_sel", 24), + GATE_PERI0(CLK_PERI_I2C1, "per_i2c1", "axi_sel", 25), + GATE_PERI0(CLK_PERI_I2C2, "per_i2c2", "axi_sel", 26), + GATE_PERI0(CLK_PERI_I2C3, "per_i2c3", "axi_sel", 27), + GATE_PERI0(CLK_PERI_I2C4, "per_i2c4", "axi_sel", 28), + GATE_PERI0(CLK_PERI_AUXADC, "per_auxadc", "ltepll_fs26m", 29), + GATE_PERI0(CLK_PERI_SPI0, "per_spi0", "spi_sel", 30), /* PERI1 */ - GATE_PERI1(CLK_PERI_SPI, "per_spi", - "spinor_sel", 1), - GATE_PERI1(CLK_PERI_I2C5, "per_i2c5", - "axi_sel", 3), - GATE_PERI1(CLK_PERI_SPI2, "per_spi2", - "spi_sel", 5), - GATE_PERI1(CLK_PERI_SPI3, "per_spi3", - "spi_sel", 6), - GATE_PERI1(CLK_PERI_SPI5, "per_spi5", - "spi_sel", 8), - GATE_PERI1(CLK_PERI_UART4, "per_uart4", - "uart_sel", 9), - GATE_PERI1(CLK_PERI_SFLASH, "per_sflash", - "uart_sel", 11), - GATE_PERI1(CLK_PERI_GMAC, "per_gmac", - "uart_sel", 12), - GATE_PERI1(CLK_PERI_PCIE0, "per_pcie0", - "uart_sel", 14), - GATE_PERI1(CLK_PERI_PCIE1, "per_pcie1", - "uart_sel", 15), - GATE_PERI1(CLK_PERI_GMAC_PCLK, "per_gmac_pclk", - "uart_sel", 16), + GATE_PERI1(CLK_PERI_SPI, "per_spi", "spinor_sel", 1), + GATE_PERI1(CLK_PERI_I2C5, "per_i2c5", "axi_sel", 3), + GATE_PERI1(CLK_PERI_SPI2, "per_spi2", "spi_sel", 5), + GATE_PERI1(CLK_PERI_SPI3, "per_spi3", "spi_sel", 6), + GATE_PERI1(CLK_PERI_SPI5, "per_spi5", "spi_sel", 8), + GATE_PERI1(CLK_PERI_UART4, "per_uart4", "uart_sel", 9), + GATE_PERI1(CLK_PERI_SFLASH, "per_sflash", "uart_sel", 11), + GATE_PERI1(CLK_PERI_GMAC, "per_gmac", "uart_sel", 12), + GATE_PERI1(CLK_PERI_PCIE0, "per_pcie0", "uart_sel", 14), + GATE_PERI1(CLK_PERI_PCIE1, "per_pcie1", "uart_sel", 15), + GATE_PERI1(CLK_PERI_GMAC_PCLK, "per_gmac_pclk", "uart_sel", 16), /* PERI2 */ - GATE_PERI2(CLK_PERI_MSDC50_0_EN, "per_msdc50_0_en", - "msdc50_0_sel", 0), - GATE_PERI2(CLK_PERI_MSDC30_1_EN, "per_msdc30_1_en", - "msdc30_1_sel", 1), - GATE_PERI2(CLK_PERI_MSDC30_2_EN, "per_msdc30_2_en", - "msdc30_2_sel", 2), - GATE_PERI2(CLK_PERI_MSDC30_3_EN, "per_msdc30_3_en", - "msdc30_3_sel", 3), - GATE_PERI2(CLK_PERI_MSDC50_0_HCLK_EN, "per_msdc50_0_h", - "msdc50_0_h_sel", 4), - GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", - "msdc50_3_h_sel", 5), - GATE_PERI2(CLK_PERI_MSDC30_0_QTR_EN, "per_msdc30_0_q", - "axi_sel", 6), - GATE_PERI2(CLK_PERI_MSDC30_3_QTR_EN, "per_msdc30_3_q", - "mem_sel", 7), -}; - -#define MT2712_PLL_FMAX (3000UL * MHZ) - -#define CON0_MT2712_RST_BAR BIT(24) - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift, \ - _div_table) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = CON0_MT2712_RST_BAR, \ - .fmax = MT2712_PLL_FMAX, \ - .pcwbits = _pcwbits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .tuner_en_reg = _tuner_en_reg, \ - .tuner_en_bit = _tuner_en_bit, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .div_table = _div_table, \ - } - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift) \ - PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _pcwbits, _pd_reg, _pd_shift, _tuner_reg, \ - _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ - _pcw_shift, NULL) - -static const struct mtk_pll_div_table armca35pll_div_table[] = { - { .div = 0, .freq = MT2712_PLL_FMAX }, - { .div = 1, .freq = 1202500000 }, - { .div = 2, .freq = 500500000 }, - { .div = 3, .freq = 315250000 }, - { .div = 4, .freq = 157625000 }, - { } /* sentinel */ -}; - -static const struct mtk_pll_div_table armca72pll_div_table[] = { - { .div = 0, .freq = MT2712_PLL_FMAX }, - { .div = 1, .freq = 994500000 }, - { .div = 2, .freq = 520000000 }, - { .div = 3, .freq = 315250000 }, - { .div = 4, .freq = 157625000 }, - { } /* sentinel */ -}; - -static const struct mtk_pll_div_table mmpll_div_table[] = { - { .div = 0, .freq = MT2712_PLL_FMAX }, - { .div = 1, .freq = 1001000000 }, - { .div = 2, .freq = 601250000 }, - { .div = 3, .freq = 250250000 }, - { .div = 4, .freq = 125125000 }, - { } /* sentinel */ -}; - -static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0230, 0x023C, 0xf0000100, - HAVE_RST_BAR, 31, 0x0230, 4, 0, 0, 0, 0x0234, 0), - PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0240, 0x024C, 0xfe000100, - HAVE_RST_BAR, 31, 0x0240, 4, 0, 0, 0, 0x0244, 0), - PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x0320, 0x032C, 0xc0000100, - 0, 31, 0x0320, 4, 0, 0, 0, 0x0324, 0), - PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x0280, 0x028C, 0x00000100, - 0, 31, 0x0280, 4, 0, 0, 0, 0x0284, 0), - PLL(CLK_APMIXED_APLL1, "apll1", 0x0330, 0x0340, 0x00000100, - 0, 31, 0x0330, 4, 0x0338, 0x0014, 0, 0x0334, 0), - PLL(CLK_APMIXED_APLL2, "apll2", 0x0350, 0x0360, 0x00000100, - 0, 31, 0x0350, 4, 0x0358, 0x0014, 1, 0x0354, 0), - PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0370, 0x037c, 0x00000100, - 0, 31, 0x0370, 4, 0, 0, 0, 0x0374, 0), - PLL(CLK_APMIXED_LVDSPLL2, "lvdspll2", 0x0390, 0x039C, 0x00000100, - 0, 31, 0x0390, 4, 0, 0, 0, 0x0394, 0), - PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0270, 0x027C, 0x00000100, - 0, 31, 0x0270, 4, 0, 0, 0, 0x0274, 0), - PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x0410, 0x041C, 0x00000100, - 0, 31, 0x0410, 4, 0, 0, 0, 0x0414, 0), - PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0290, 0x029C, 0xc0000100, - 0, 31, 0x0290, 4, 0, 0, 0, 0x0294, 0), - PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0250, 0x0260, 0x00000100, - 0, 31, 0x0250, 4, 0, 0, 0, 0x0254, 0, - mmpll_div_table), - PLL_B(CLK_APMIXED_ARMCA35PLL, "armca35pll", 0x0100, 0x0110, 0xf0000100, - HAVE_RST_BAR, 31, 0x0100, 4, 0, 0, 0, 0x0104, 0, - armca35pll_div_table), - PLL_B(CLK_APMIXED_ARMCA72PLL, "armca72pll", 0x0210, 0x0220, 0x00000100, - 0, 31, 0x0210, 4, 0, 0, 0, 0x0214, 0, - armca72pll_div_table), - PLL(CLK_APMIXED_ETHERPLL, "etherpll", 0x0300, 0x030C, 0xc0000100, - 0, 31, 0x0300, 4, 0, 0, 0, 0x0304, 0), + GATE_PERI2(CLK_PERI_MSDC50_0_EN, "per_msdc50_0_en", "msdc50_0_sel", 0), + GATE_PERI2(CLK_PERI_MSDC30_1_EN, "per_msdc30_1_en", "msdc30_1_sel", 1), + GATE_PERI2(CLK_PERI_MSDC30_2_EN, "per_msdc30_2_en", "msdc30_2_sel", 2), + GATE_PERI2(CLK_PERI_MSDC30_3_EN, "per_msdc30_3_en", "msdc30_3_sel", 3), + GATE_PERI2(CLK_PERI_MSDC50_0_HCLK_EN, "per_msdc50_0_h", "msdc50_0_h_sel", 4), + GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", "msdc50_3_h_sel", 5), + GATE_PERI2(CLK_PERI_MSDC30_0_QTR_EN, "per_msdc30_0_q", "axi_sel", 6), + GATE_PERI2(CLK_PERI_MSDC30_3_QTR_EN, "per_msdc30_3_q", "mem_sel", 7), }; static u16 infrasys_rst_ofs[] = { 0x30, 0x34, }; @@ -1276,155 +952,25 @@ static const struct mtk_clk_rst_desc clk_rst_desc[] = { }, }; -static int clk_mt2712_apmixed_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - int r; - struct device_node *node = pdev->dev.of_node; - - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r != 0) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - return r; -} - -static struct clk_hw_onecell_data *top_clk_data; - -static void clk_mt2712_top_init_early(struct device_node *node) -{ - int r, i; - - if (!top_clk_data) { - top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - - for (i = 0; i < CLK_TOP_NR_CLK; i++) - top_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); - } - - mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), - top_clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} - -CLK_OF_DECLARE_DRIVER(mt2712_topckgen, "mediatek,mt2712-topckgen", - clk_mt2712_top_init_early); - -static int clk_mt2712_top_probe(struct platform_device *pdev) -{ - int r, i; - struct device_node *node = pdev->dev.of_node; - void __iomem *base; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - pr_err("%s(): ioremap failed\n", __func__); - return PTR_ERR(base); - } - - if (!top_clk_data) { - top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - } else { - for (i = 0; i < CLK_TOP_NR_CLK; i++) { - if (top_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER)) - top_clk_data->hws[i] = ERR_PTR(-ENOENT); - } - } - - mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), - top_clk_data); - mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), - top_clk_data); - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); - mtk_clk_register_composites(&pdev->dev, top_muxes, - ARRAY_SIZE(top_muxes), base, - &mt2712_clk_lock, top_clk_data); - mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base, - &mt2712_clk_lock, top_clk_data); - mtk_clk_register_gates(&pdev->dev, node, top_clks, - ARRAY_SIZE(top_clks), top_clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data); - - if (r != 0) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - return r; -} - -static int clk_mt2712_mcu_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - int r; - struct device_node *node = pdev->dev.of_node; - void __iomem *base; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - pr_err("%s(): ioremap failed\n", __func__); - return PTR_ERR(base); - } - - clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); - - r = mtk_clk_register_composites(&pdev->dev, mcu_muxes, - ARRAY_SIZE(mcu_muxes), base, - &mt2712_clk_lock, clk_data); - if (r) - dev_err(&pdev->dev, "Could not register composites: %d\n", r); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r != 0) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - return r; -} - -static const struct of_device_id of_match_clk_mt2712[] = { - { - .compatible = "mediatek,mt2712-apmixedsys", - .data = clk_mt2712_apmixed_probe, - }, { - .compatible = "mediatek,mt2712-topckgen", - .data = clk_mt2712_top_probe, - }, { - .compatible = "mediatek,mt2712-mcucfg", - .data = clk_mt2712_mcu_probe, - }, { - /* sentinel */ - } +static const struct mtk_clk_desc topck_desc = { + .clks = top_clks, + .num_clks = ARRAY_SIZE(top_clks), + .fixed_clks = top_fixed_clks, + .num_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .composite_clks = top_muxes, + .num_composite_clks = ARRAY_SIZE(top_muxes), + .divider_clks = top_adj_divs, + .num_divider_clks = ARRAY_SIZE(top_adj_divs), + .clk_lock = &mt2712_clk_lock, }; -static int clk_mt2712_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *); - int r; - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - r = clk_probe(pdev); - if (r != 0) - dev_err(&pdev->dev, - "could not register clock provider: %s: %d\n", - pdev->name, r); - - return r; -} +static const struct mtk_clk_desc mcu_desc = { + .composite_clks = mcu_muxes, + .num_composite_clks = ARRAY_SIZE(mcu_muxes), + .clk_lock = &mt2712_clk_lock, +}; static const struct mtk_clk_desc infra_desc = { .clks = infra_clks, @@ -1438,36 +984,22 @@ static const struct mtk_clk_desc peri_desc = { .rst_desc = &clk_rst_desc[1], }; -static const struct of_device_id of_match_clk_mt2712_simple[] = { +static const struct of_device_id of_match_clk_mt2712[] = { { .compatible = "mediatek,mt2712-infracfg", .data = &infra_desc }, + { .compatible = "mediatek,mt2712-mcucfg", .data = &mcu_desc }, { .compatible = "mediatek,mt2712-pericfg", .data = &peri_desc, }, + { .compatible = "mediatek,mt2712-topckgen", .data = &topck_desc }, { /* sentinel */ } }; - -static struct platform_driver clk_mt2712_simple_drv = { - .probe = mtk_clk_simple_probe, - .remove = mtk_clk_simple_remove, - .driver = { - .name = "clk-mt2712-simple", - .of_match_table = of_match_clk_mt2712_simple, - }, -}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt2712); static struct platform_driver clk_mt2712_drv = { - .probe = clk_mt2712_probe, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt2712", .of_match_table = of_match_clk_mt2712, }, }; - -static int __init clk_mt2712_init(void) -{ - int ret = platform_driver_register(&clk_mt2712_drv); - - if (ret) - return ret; - return platform_driver_register(&clk_mt2712_simple_drv); -} - -arch_initcall(clk_mt2712_init); +module_platform_driver(clk_mt2712_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-audio.c b/drivers/clk/mediatek/clk-mt6765-audio.c index 0aa6c0d352ca..9e98d6997329 100644 --- a/drivers/clk/mediatek/clk-mt6765-audio.c +++ b/drivers/clk/mediatek/clk-mt6765-audio.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs audio1_cg_regs = { .sta_ofs = 0x4, }; -#define GATE_AUDIO0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate audio_clks[] = { /* AUDIO0 */ @@ -77,6 +65,7 @@ static const struct of_device_id of_match_clk_mt6765_audio[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_audio); static struct platform_driver clk_mt6765_audio_drv = { .probe = mtk_clk_simple_probe, @@ -86,5 +75,5 @@ static struct platform_driver clk_mt6765_audio_drv = { .of_match_table = of_match_clk_mt6765_audio, }, }; - -builtin_platform_driver(clk_mt6765_audio_drv); +module_platform_driver(clk_mt6765_audio_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-cam.c b/drivers/clk/mediatek/clk-mt6765-cam.c index 25f2bef38126..6f6b29d8b29a 100644 --- a/drivers/clk/mediatek/clk-mt6765-cam.c +++ b/drivers/clk/mediatek/clk-mt6765-cam.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs cam_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_CAM(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &cam_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_CAM(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &cam_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate cam_clks[] = { GATE_CAM(CLK_CAM_LARB3, "cam_larb3", "mm_ck", 0), @@ -52,6 +46,7 @@ static const struct of_device_id of_match_clk_mt6765_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_cam); static struct platform_driver clk_mt6765_cam_drv = { .probe = mtk_clk_simple_probe, @@ -61,5 +56,5 @@ static struct platform_driver clk_mt6765_cam_drv = { .of_match_table = of_match_clk_mt6765_cam, }, }; - -builtin_platform_driver(clk_mt6765_cam_drv); +module_platform_driver(clk_mt6765_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-img.c b/drivers/clk/mediatek/clk-mt6765-img.c index a62303ef4f41..984201077a20 100644 --- a/drivers/clk/mediatek/clk-mt6765-img.c +++ b/drivers/clk/mediatek/clk-mt6765-img.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs img_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_IMG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &img_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate img_clks[] = { GATE_IMG(CLK_IMG_LARB2, "img_larb2", "mm_ck", 0), @@ -48,6 +42,7 @@ static const struct of_device_id of_match_clk_mt6765_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_img); static struct platform_driver clk_mt6765_img_drv = { .probe = mtk_clk_simple_probe, @@ -57,5 +52,5 @@ static struct platform_driver clk_mt6765_img_drv = { .of_match_table = of_match_clk_mt6765_img, }, }; - -builtin_platform_driver(clk_mt6765_img_drv); +module_platform_driver(clk_mt6765_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-mipi0a.c b/drivers/clk/mediatek/clk-mt6765-mipi0a.c index 25c829fc3866..a47937f4efe5 100644 --- a/drivers/clk/mediatek/clk-mt6765-mipi0a.c +++ b/drivers/clk/mediatek/clk-mt6765-mipi0a.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs mipi0a_cg_regs = { .sta_ofs = 0x80, }; -#define GATE_MIPI0A(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mipi0a_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_MIPI0A(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mipi0a_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate mipi0a_clks[] = { GATE_MIPI0A(CLK_MIPI0A_CSR_CSI_EN_0A, @@ -45,6 +39,7 @@ static const struct of_device_id of_match_clk_mt6765_mipi0a[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_mipi0a); static struct platform_driver clk_mt6765_mipi0a_drv = { .probe = mtk_clk_simple_probe, @@ -54,5 +49,5 @@ static struct platform_driver clk_mt6765_mipi0a_drv = { .of_match_table = of_match_clk_mt6765_mipi0a, }, }; - -builtin_platform_driver(clk_mt6765_mipi0a_drv); +module_platform_driver(clk_mt6765_mipi0a_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-mm.c b/drivers/clk/mediatek/clk-mt6765-mm.c index bda774668a36..2b8fc052558e 100644 --- a/drivers/clk/mediatek/clk-mt6765-mm.c +++ b/drivers/clk/mediatek/clk-mt6765-mm.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs mm_cg_regs = { .sta_ofs = 0x100, }; -#define GATE_MM(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mm_clks[] = { /* MM */ @@ -74,6 +68,7 @@ static const struct of_device_id of_match_clk_mt6765_mm[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_mm); static struct platform_driver clk_mt6765_mm_drv = { .probe = mtk_clk_simple_probe, @@ -83,5 +78,5 @@ static struct platform_driver clk_mt6765_mm_drv = { .of_match_table = of_match_clk_mt6765_mm, }, }; - -builtin_platform_driver(clk_mt6765_mm_drv); +module_platform_driver(clk_mt6765_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765-vcodec.c b/drivers/clk/mediatek/clk-mt6765-vcodec.c index 2bc1fbde87da..36df9615b1be 100644 --- a/drivers/clk/mediatek/clk-mt6765-vcodec.c +++ b/drivers/clk/mediatek/clk-mt6765-vcodec.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs venc_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_VENC(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &venc_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VENC(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &venc_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate venc_clks[] = { GATE_VENC(CLK_VENC_SET0_LARB, "venc_set0_larb", "mm_ck", 0), @@ -47,6 +41,7 @@ static const struct of_device_id of_match_clk_mt6765_vcodec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765_vcodec); static struct platform_driver clk_mt6765_vcodec_drv = { .probe = mtk_clk_simple_probe, @@ -56,5 +51,5 @@ static struct platform_driver clk_mt6765_vcodec_drv = { .of_match_table = of_match_clk_mt6765_vcodec, }, }; - -builtin_platform_driver(clk_mt6765_vcodec_drv); +module_platform_driver(clk_mt6765_vcodec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index 6f5c92a7f620..fa7948ef1e68 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -483,32 +483,14 @@ static const struct mtk_gate_regs top2_cg_regs = { .sta_ofs = 0x320, }; -#define GATE_TOP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_TOP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -#define GATE_TOP2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate top_clks[] = { /* TOP0 */ @@ -559,41 +541,17 @@ static const struct mtk_gate_regs ifr5_cg_regs = { .sta_ofs = 0xc8, }; -#define GATE_IFR2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ifr2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_IFR3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ifr3_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_IFR4(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr4_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR4(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ifr4_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_IFR5(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr5_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR5(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ifr5_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate ifr_clks[] = { /* INFRA_TOPAXI */ @@ -674,14 +632,8 @@ static const struct mtk_gate_regs apmixed_cg_regs = { .sta_ofs = 0x14, }; -#define GATE_APMIXED(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &apmixed_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate apmixed_clks[] = { /* AUDIO0 */ @@ -888,6 +840,7 @@ static const struct of_device_id of_match_clk_mt6765[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6765); static int clk_mt6765_probe(struct platform_device *pdev) { @@ -921,3 +874,4 @@ static int __init clk_mt6765_init(void) } arch_initcall(clk_mt6765_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6779-aud.c b/drivers/clk/mediatek/clk-mt6779-aud.c index 6e473ae1fd90..6e3280d3a2e6 100644 --- a/drivers/clk/mediatek/clk-mt6779-aud.c +++ b/drivers/clk/mediatek/clk-mt6779-aud.c @@ -102,6 +102,7 @@ static const struct of_device_id of_match_clk_mt6779_aud[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_aud); static struct platform_driver clk_mt6779_aud_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-cam.c b/drivers/clk/mediatek/clk-mt6779-cam.c index 7be3db90fa4a..b4c4c7248672 100644 --- a/drivers/clk/mediatek/clk-mt6779-cam.c +++ b/drivers/clk/mediatek/clk-mt6779-cam.c @@ -51,6 +51,7 @@ static const struct of_device_id of_match_clk_mt6779_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_cam); static struct platform_driver clk_mt6779_cam_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-img.c b/drivers/clk/mediatek/clk-mt6779-img.c index 9bc51fc82dbd..b760a8af3462 100644 --- a/drivers/clk/mediatek/clk-mt6779-img.c +++ b/drivers/clk/mediatek/clk-mt6779-img.c @@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt6779_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_img); static struct platform_driver clk_mt6779_img_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-ipe.c b/drivers/clk/mediatek/clk-mt6779-ipe.c index 92e9d1ade422..9285a792c59b 100644 --- a/drivers/clk/mediatek/clk-mt6779-ipe.c +++ b/drivers/clk/mediatek/clk-mt6779-ipe.c @@ -45,6 +45,7 @@ static const struct of_device_id of_match_clk_mt6779_ipe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_ipe); static struct platform_driver clk_mt6779_ipe_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-mfg.c b/drivers/clk/mediatek/clk-mt6779-mfg.c index efc793a1969a..d20f32d4f827 100644 --- a/drivers/clk/mediatek/clk-mt6779-mfg.c +++ b/drivers/clk/mediatek/clk-mt6779-mfg.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt6779_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_mfg); static struct platform_driver clk_mt6779_mfg_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-mm.c b/drivers/clk/mediatek/clk-mt6779-mm.c index 2cccf62d3b36..c2f700ae6c2c 100644 --- a/drivers/clk/mediatek/clk-mt6779-mm.c +++ b/drivers/clk/mediatek/clk-mt6779-mm.c @@ -85,25 +85,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM1(CLK_MM_DISP_OVL_FBDC, "mm_disp_ovl_fbdc", "mm_sel", 16), }; -static int clk_mt6779_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - - mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} +static const struct platform_device_id clk_mt6779_mm_id_table[] = { + { .name = "clk-mt6779-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt6779_mm_id_table); static struct platform_driver clk_mt6779_mm_drv = { - .probe = clk_mt6779_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt6779-mm", }, + .id_table = clk_mt6779_mm_id_table, }; module_platform_driver(clk_mt6779_mm_drv); diff --git a/drivers/clk/mediatek/clk-mt6779-vdec.c b/drivers/clk/mediatek/clk-mt6779-vdec.c index 3209a6518d5b..e062ed5aa45f 100644 --- a/drivers/clk/mediatek/clk-mt6779-vdec.c +++ b/drivers/clk/mediatek/clk-mt6779-vdec.c @@ -52,6 +52,7 @@ static const struct of_device_id of_match_clk_mt6779_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_vdec); static struct platform_driver clk_mt6779_vdec_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779-venc.c b/drivers/clk/mediatek/clk-mt6779-venc.c index c25035c0f334..0ae8ac28f838 100644 --- a/drivers/clk/mediatek/clk-mt6779-venc.c +++ b/drivers/clk/mediatek/clk-mt6779-venc.c @@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt6779_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779_venc); static struct platform_driver clk_mt6779_venc_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c index 827025d127d9..1f5ea1508f61 100644 --- a/drivers/clk/mediatek/clk-mt6779.c +++ b/drivers/clk/mediatek/clk-mt6779.c @@ -1299,6 +1299,7 @@ static const struct of_device_id of_match_clk_mt6779_infra[] = { { .compatible = "mediatek,mt6779-infracfg_ao", .data = &infra_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6779); static struct platform_driver clk_mt6779_infra_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c index 59761c72d3bc..8b30109f253c 100644 --- a/drivers/clk/mediatek/clk-mt6795-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt6795-apmixedsys.c @@ -7,8 +7,10 @@ #include #include #include +#include "clk-fhctl.h" #include "clk-mtk.h" #include "clk-pll.h" +#include "clk-pllfh.h" #define REG_REF2USB 0x8 #define REG_AP_PLL_CON7 0x1c @@ -58,6 +60,56 @@ static const struct mtk_pll_data plls[] = { PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0, 0, 31, 0x2b4, 4, 0x2bc, 0x2b8, 0), }; +enum fh_pll_id { + FH_CA53PLL_LL, + FH_CA53PLL_BL, + FH_MAINPLL, + FH_MPLL, + FH_MSDCPLL, + FH_MMPLL, + FH_VENCPLL, + FH_TVDPLL, + FH_VCODECPLL, + FH_NR_FH, +}; + +#define _FH(_pllid, _fhid, _slope, _offset) { \ + .data = { \ + .pll_id = _pllid, \ + .fh_id = _fhid, \ + .fh_ver = FHCTL_PLLFH_V1, \ + .fhx_offset = _offset, \ + .dds_mask = GENMASK(21, 0), \ + .slope0_value = _slope, \ + .slope1_value = _slope, \ + .sfstrx_en = BIT(2), \ + .frddsx_en = BIT(1), \ + .fhctlx_en = BIT(0), \ + .tgl_org = BIT(31), \ + .dvfs_tri = BIT(31), \ + .pcwchg = BIT(31), \ + .dt_val = 0x0, \ + .df_val = 0x9, \ + .updnlmt_shft = 16, \ + .msk_frddsx_dys = GENMASK(23, 20), \ + .msk_frddsx_dts = GENMASK(19, 16), \ + }, \ + } + +#define FH(_pllid, _fhid, _offset) _FH(_pllid, _fhid, 0x6003c97, _offset) +#define FH_M(_pllid, _fhid, _offset) _FH(_pllid, _fhid, 0x6000140, _offset) + +static struct mtk_pllfh_data pllfhs[] = { + FH(CLK_APMIXED_ARMCA53PLL, FH_CA53PLL_BL, 0x38), + FH(CLK_APMIXED_MAINPLL, FH_MAINPLL, 0x60), + FH_M(CLK_APMIXED_MPLL, FH_MPLL, 0x74), + FH(CLK_APMIXED_MSDCPLL, FH_MSDCPLL, 0x88), + FH(CLK_APMIXED_MMPLL, FH_MMPLL, 0x9c), + FH(CLK_APMIXED_VENCPLL, FH_VENCPLL, 0xb0), + FH(CLK_APMIXED_TVDPLL, FH_TVDPLL, 0xc4), + FH(CLK_APMIXED_VCODECPLL, FH_VCODECPLL, 0xd8), +}; + static void clk_mt6795_apmixed_setup_md1(void __iomem *base) { void __iomem *reg = base + REG_AP_PLL_CON7; @@ -79,12 +131,14 @@ static const struct of_device_id of_match_clk_mt6795_apmixed[] = { { .compatible = "mediatek,mt6795-apmixedsys" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_apmixed); static int clk_mt6795_apmixed_probe(struct platform_device *pdev) { struct clk_hw_onecell_data *clk_data; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; + const u8 *fhctl_node = "mediatek,mt6795-fhctl"; void __iomem *base; struct clk_hw *hw; int ret; @@ -97,7 +151,9 @@ static int clk_mt6795_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); + ret = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (ret) goto free_clk_data; @@ -124,7 +180,8 @@ static int clk_mt6795_apmixed_probe(struct platform_device *pdev) unregister_ref2usb: mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]); unregister_plls: - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); free_clk_data: mtk_free_clk_data(clk_data); return ret; @@ -137,7 +194,8 @@ static int clk_mt6795_apmixed_remove(struct platform_device *pdev) of_clk_del_provider(node); mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]); - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); mtk_free_clk_data(clk_data); return 0; diff --git a/drivers/clk/mediatek/clk-mt6795-infracfg.c b/drivers/clk/mediatek/clk-mt6795-infracfg.c index 23d9fc057e61..086ea1438564 100644 --- a/drivers/clk/mediatek/clk-mt6795-infracfg.c +++ b/drivers/clk/mediatek/clk-mt6795-infracfg.c @@ -81,6 +81,7 @@ static const struct of_device_id of_match_clk_mt6795_infracfg[] = { { .compatible = "mediatek,mt6795-infracfg" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_infracfg); static int clk_mt6795_infracfg_probe(struct platform_device *pdev) { diff --git a/drivers/clk/mediatek/clk-mt6795-mfg.c b/drivers/clk/mediatek/clk-mt6795-mfg.c index ee7aab24eb24..1d658bb19e82 100644 --- a/drivers/clk/mediatek/clk-mt6795-mfg.c +++ b/drivers/clk/mediatek/clk-mt6795-mfg.c @@ -35,6 +35,7 @@ static const struct of_device_id of_match_clk_mt6795_mfg[] = { { .compatible = "mediatek,mt6795-mfgcfg", .data = &mfg_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_mfg); static struct platform_driver clk_mt6795_mfg_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt6795-mm.c b/drivers/clk/mediatek/clk-mt6795-mm.c index eebb6143ada2..8acc9cad2875 100644 --- a/drivers/clk/mediatek/clk-mt6795-mm.c +++ b/drivers/clk/mediatek/clk-mt6795-mm.c @@ -76,56 +76,24 @@ static const struct mtk_gate mm_gates[] = { GATE_MM1(CLK_MM_DPI_ENGINE, "mm_dpi_engine", "mm_sel", 9), }; -static int clk_mt6795_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int ret; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_gates, + .num_clks = ARRAY_SIZE(mm_gates), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - if (!clk_data) - return -ENOMEM; - - ret = mtk_clk_register_gates(&pdev->dev, node, mm_gates, - ARRAY_SIZE(mm_gates), clk_data); - if (ret) - goto free_clk_data; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return 0; - -unregister_gates: - mtk_clk_unregister_gates(mm_gates, ARRAY_SIZE(mm_gates), clk_data); -free_clk_data: - mtk_free_clk_data(clk_data); - return ret; -} - -static int clk_mt6795_mm_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(mm_gates, ARRAY_SIZE(mm_gates), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt6795_mm_id_table[] = { + { .name = "clk-mt6795-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt6795_mm_id_table); static struct platform_driver clk_mt6795_mm_drv = { .driver = { .name = "clk-mt6795-mm", }, - .probe = clk_mt6795_mm_probe, - .remove = clk_mt6795_mm_remove, + .id_table = clk_mt6795_mm_id_table, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, }; module_platform_driver(clk_mt6795_mm_drv); diff --git a/drivers/clk/mediatek/clk-mt6795-pericfg.c b/drivers/clk/mediatek/clk-mt6795-pericfg.c index 08aaa9b09c36..62cc19eee2c7 100644 --- a/drivers/clk/mediatek/clk-mt6795-pericfg.c +++ b/drivers/clk/mediatek/clk-mt6795-pericfg.c @@ -89,6 +89,7 @@ static const struct of_device_id of_match_clk_mt6795_pericfg[] = { { .compatible = "mediatek,mt6795-pericfg" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_pericfg); static int clk_mt6795_pericfg_probe(struct platform_device *pdev) { diff --git a/drivers/clk/mediatek/clk-mt6795-topckgen.c b/drivers/clk/mediatek/clk-mt6795-topckgen.c index e80fa588e309..9c6d63a80b19 100644 --- a/drivers/clk/mediatek/clk-mt6795-topckgen.c +++ b/drivers/clk/mediatek/clk-mt6795-topckgen.c @@ -539,6 +539,7 @@ static const struct of_device_id of_match_clk_mt6795_topckgen[] = { { .compatible = "mediatek,mt6795-topckgen", .data = &topck_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_topckgen); static struct platform_driver clk_mt6795_topckgen_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt6795-vdecsys.c b/drivers/clk/mediatek/clk-mt6795-vdecsys.c index d85d04e0d016..f2968f859dca 100644 --- a/drivers/clk/mediatek/clk-mt6795-vdecsys.c +++ b/drivers/clk/mediatek/clk-mt6795-vdecsys.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt6795_vdecsys[] = { { .compatible = "mediatek,mt6795-vdecsys", .data = &vdec_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_vdecsys); static struct platform_driver clk_mt6795_vdecsys_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt6795-vencsys.c b/drivers/clk/mediatek/clk-mt6795-vencsys.c index de40a982ca96..2f8d48da1a85 100644 --- a/drivers/clk/mediatek/clk-mt6795-vencsys.c +++ b/drivers/clk/mediatek/clk-mt6795-vencsys.c @@ -35,6 +35,7 @@ static const struct of_device_id of_match_clk_mt6795_vencsys[] = { { .compatible = "mediatek,mt6795-vencsys", .data = &venc_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6795_vencsys); static struct platform_driver clk_mt6795_vencsys_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt6797-img.c b/drivers/clk/mediatek/clk-mt6797-img.c index 7c6a53fbb8be..00fc0a03e646 100644 --- a/drivers/clk/mediatek/clk-mt6797-img.c +++ b/drivers/clk/mediatek/clk-mt6797-img.c @@ -16,14 +16,8 @@ static const struct mtk_gate_regs img_cg_regs = { .sta_ofs = 0x0000, }; -#define GATE_IMG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &img_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate img_clks[] = { GATE_IMG(CLK_IMG_FDVT, "img_fdvt", "mm_sel", 11), @@ -45,6 +39,7 @@ static const struct of_device_id of_match_clk_mt6797_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6797_img); static struct platform_driver clk_mt6797_img_drv = { .probe = mtk_clk_simple_probe, @@ -54,5 +49,5 @@ static struct platform_driver clk_mt6797_img_drv = { .of_match_table = of_match_clk_mt6797_img, }, }; - -builtin_platform_driver(clk_mt6797_img_drv); +module_platform_driver(clk_mt6797_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6797-mm.c b/drivers/clk/mediatek/clk-mt6797-mm.c index deb16a6b16a5..caacfa40a5bc 100644 --- a/drivers/clk/mediatek/clk-mt6797-mm.c +++ b/drivers/clk/mediatek/clk-mt6797-mm.c @@ -23,23 +23,11 @@ static const struct mtk_gate_regs mm1_cg_regs = { .sta_ofs = 0x0110, }; -#define GATE_MM0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ -} +#define GATE_MM0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_MM1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ -} +#define GATE_MM1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mm_clks[] = { GATE_MM0(CLK_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 0), @@ -92,32 +80,24 @@ static const struct mtk_gate mm_clks[] = { "clk26m", 3), }; -static int clk_mt6797_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR); - - mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - dev_err(&pdev->dev, - "could not register clock provider: %s: %d\n", - pdev->name, r); - - return r; -} +static const struct platform_device_id clk_mt6797_mm_id_table[] = { + { .name = "clk-mt6797-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt6797_mm_id_table); static struct platform_driver clk_mt6797_mm_drv = { - .probe = clk_mt6797_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt6797-mm", }, + .id_table = clk_mt6797_mm_id_table, }; - -builtin_platform_driver(clk_mt6797_mm_drv); +module_platform_driver(clk_mt6797_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6797-vdec.c b/drivers/clk/mediatek/clk-mt6797-vdec.c index 6120fccc859f..447fe6fa8e15 100644 --- a/drivers/clk/mediatek/clk-mt6797-vdec.c +++ b/drivers/clk/mediatek/clk-mt6797-vdec.c @@ -24,23 +24,11 @@ static const struct mtk_gate_regs vdec1_cg_regs = { .sta_ofs = 0x0008, }; -#define GATE_VDEC0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ -} +#define GATE_VDEC0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_VDEC1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ -} +#define GATE_VDEC1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate vdec_clks[] = { GATE_VDEC0(CLK_VDEC_CKEN_ENG, "vdec_cken_eng", "vdec_sel", 8), @@ -62,6 +50,7 @@ static const struct of_device_id of_match_clk_mt6797_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6797_vdec); static struct platform_driver clk_mt6797_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -71,5 +60,5 @@ static struct platform_driver clk_mt6797_vdec_drv = { .of_match_table = of_match_clk_mt6797_vdec, }, }; - -builtin_platform_driver(clk_mt6797_vdec_drv); +module_platform_driver(clk_mt6797_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6797-venc.c b/drivers/clk/mediatek/clk-mt6797-venc.c index 834d3834d2bb..95b89ff8fd19 100644 --- a/drivers/clk/mediatek/clk-mt6797-venc.c +++ b/drivers/clk/mediatek/clk-mt6797-venc.c @@ -18,14 +18,8 @@ static const struct mtk_gate_regs venc_cg_regs = { .sta_ofs = 0x0000, }; -#define GATE_VENC(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &venc_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VENC(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &venc_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) static const struct mtk_gate venc_clks[] = { GATE_VENC(CLK_VENC_0, "venc_0", "mm_sel", 0), @@ -47,6 +41,7 @@ static const struct of_device_id of_match_clk_mt6797_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6797_venc); static struct platform_driver clk_mt6797_venc_drv = { .probe = mtk_clk_simple_probe, @@ -56,5 +51,5 @@ static struct platform_driver clk_mt6797_venc_drv = { .of_match_table = of_match_clk_mt6797_venc, }, }; - -builtin_platform_driver(clk_mt6797_venc_drv); +module_platform_driver(clk_mt6797_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index 105a512857b3..4c87c0348e5f 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -421,40 +421,22 @@ static const struct mtk_gate_regs infra2_cg_regs = { .sta_ofs = 0x00b0, }; -#define GATE_ICG0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ -} +#define GATE_ICG0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_ICG1(_id, _name, _parent, _shift) \ - GATE_ICG1_FLAGS(_id, _name, _parent, _shift, 0) +#define GATE_ICG1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_ICG1_FLAGS(_id, _name, _parent, _shift, _flags) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - .flags = _flags, \ -} +#define GATE_ICG1_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flags) -#define GATE_ICG2(_id, _name, _parent, _shift) \ - GATE_ICG2_FLAGS(_id, _name, _parent, _shift, 0) +#define GATE_ICG2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_ICG2_FLAGS(_id, _name, _parent, _shift, _flags) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - .flags = _flags, \ -} +#define GATE_ICG2_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra2_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flags) /* * Clock gates dramc and dramc_b are needed by the DRAM controller. @@ -688,6 +670,7 @@ static const struct of_device_id of_match_clk_mt6797[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt6797); static int clk_mt6797_probe(struct platform_device *pdev) { @@ -721,3 +704,4 @@ static int __init clk_mt6797_init(void) } arch_initcall(clk_mt6797_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c new file mode 100644 index 000000000000..a36808d074d6 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 MediaTek Inc. + * Copyright (c) 2023 Collabora, Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" + +#define MT7622_PLL_FMAX (2500UL * MHZ) +#define CON0_MT7622_RST_BAR BIT(27) + +#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table, _parent_name) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT7622_RST_BAR, \ + .fmax = MT7622_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + .parent_name = _parent_name, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL, "clkxtal") + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x8, + .sta_ofs = 0x8, +}; + +#define GATE_APMIXED_AO(_id, _name, _parent, _shift) \ + GATE_MTK_FLAGS(_id, _name, _parent, &apmixed_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr_inv, CLK_IS_CRITICAL) + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0, + PLL_AO, 21, 0x0204, 24, 0, 0x0204, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0210, 0x021C, 0, + HAVE_RST_BAR, 21, 0x0214, 24, 0, 0x0214, 0), + PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0220, 0x022C, 0, + HAVE_RST_BAR, 7, 0x0224, 24, 0, 0x0224, 14), + PLL(CLK_APMIXED_ETH1PLL, "eth1pll", 0x0300, 0x0310, 0, + 0, 21, 0x0300, 1, 0, 0x0304, 0), + PLL(CLK_APMIXED_ETH2PLL, "eth2pll", 0x0314, 0x0320, 0, + 0, 21, 0x0314, 1, 0, 0x0318, 0), + PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x0324, 0x0330, 0, + 0, 31, 0x0324, 1, 0, 0x0328, 0), + PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x0334, 0x0340, 0, + 0, 31, 0x0334, 1, 0, 0x0338, 0), + PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x0344, 0x0354, 0, + 0, 21, 0x0344, 1, 0, 0x0348, 0), + PLL(CLK_APMIXED_SGMIPLL, "sgmipll", 0x0358, 0x0368, 0, + 0, 21, 0x0358, 1, 0, 0x035C, 0), +}; + +static const struct mtk_gate apmixed_clks[] = { + GATE_APMIXED_AO(CLK_APMIXED_MAIN_CORE_EN, "main_core_en", "mainpll", 5), +}; + +static int clk_mt7622_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(dev, CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, + ARRAY_SIZE(apmixed_clks), clk_data); + if (ret) + goto unregister_plls; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_gates; + + return 0; + +unregister_gates: + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static int clk_mt7622_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static const struct of_device_id of_match_clk_mt7622_apmixed[] = { + { .compatible = "mediatek,mt7622-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622_apmixed); + +static struct platform_driver clk_mt7622_apmixed_drv = { + .probe = clk_mt7622_apmixed_probe, + .remove = clk_mt7622_apmixed_remove, + .driver = { + .name = "clk-mt7622-apmixed", + .of_match_table = of_match_clk_mt7622_apmixed, + }, +}; +module_platform_driver(clk_mt7622_apmixed_drv) + +MODULE_DESCRIPTION("MediaTek MT7622 apmixedsys clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c index b8aabfeb1cba..dd1799dd8435 100644 --- a/drivers/clk/mediatek/clk-mt7622-aud.c +++ b/drivers/clk/mediatek/clk-mt7622-aud.c @@ -16,41 +16,17 @@ #include -#define GATE_AUDIO0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio2_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define GATE_AUDIO3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &audio3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUDIO3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &audio3_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) static const struct mtk_gate_regs audio0_cg_regs = { .set_ofs = 0x0, @@ -169,6 +145,7 @@ static const struct of_device_id of_match_clk_mt7622_aud[] = { { .compatible = "mediatek,mt7622-audsys", .data = &audio_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622_aud); static struct platform_driver clk_mt7622_aud_drv = { .probe = clk_mt7622_aud_probe, @@ -178,5 +155,5 @@ static struct platform_driver clk_mt7622_aud_drv = { .of_match_table = of_match_clk_mt7622_aud, }, }; - -builtin_platform_driver(clk_mt7622_aud_drv); +module_platform_driver(clk_mt7622_aud_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622-eth.c b/drivers/clk/mediatek/clk-mt7622-eth.c index aee583fa77d0..f96b36737029 100644 --- a/drivers/clk/mediatek/clk-mt7622-eth.c +++ b/drivers/clk/mediatek/clk-mt7622-eth.c @@ -16,14 +16,8 @@ #include -#define GATE_ETH(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = ð_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_ETH(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, ð_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate_regs eth_cg_regs = { .set_ofs = 0x30, @@ -45,14 +39,8 @@ static const struct mtk_gate_regs sgmii_cg_regs = { .sta_ofs = 0xE4, }; -#define GATE_SGMII(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &sgmii_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SGMII(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &sgmii_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate sgmii_clks[] = { GATE_SGMII(CLK_SGMII_TX250M_EN, "sgmii_tx250m_en", @@ -89,6 +77,7 @@ static const struct of_device_id of_match_clk_mt7622_eth[] = { { .compatible = "mediatek,mt7622-sgmiisys", .data = &sgmii_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622_eth); static struct platform_driver clk_mt7622_eth_drv = { .probe = mtk_clk_simple_probe, @@ -98,5 +87,5 @@ static struct platform_driver clk_mt7622_eth_drv = { .of_match_table = of_match_clk_mt7622_eth, }, }; - -builtin_platform_driver(clk_mt7622_eth_drv); +module_platform_driver(clk_mt7622_eth_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622-hif.c b/drivers/clk/mediatek/clk-mt7622-hif.c index ab5cad0c2b1c..f440943f0d46 100644 --- a/drivers/clk/mediatek/clk-mt7622-hif.c +++ b/drivers/clk/mediatek/clk-mt7622-hif.c @@ -16,23 +16,11 @@ #include -#define GATE_PCIE(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &pcie_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_PCIE(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &pcie_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -#define GATE_SSUSB(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ssusb_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SSUSB(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ssusb_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate_regs pcie_cg_regs = { .set_ofs = 0x30, @@ -101,6 +89,7 @@ static const struct of_device_id of_match_clk_mt7622_hif[] = { { .compatible = "mediatek,mt7622-ssusbsys", .data = &ssusb_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622_hif); static struct platform_driver clk_mt7622_hif_drv = { .probe = mtk_clk_simple_probe, @@ -110,5 +99,5 @@ static struct platform_driver clk_mt7622_hif_drv = { .of_match_table = of_match_clk_mt7622_hif, }, }; - -builtin_platform_driver(clk_mt7622_hif_drv); +module_platform_driver(clk_mt7622_hif_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622-infracfg.c b/drivers/clk/mediatek/clk-mt7622-infracfg.c new file mode 100644 index 000000000000..9dc05526f287 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622-infracfg.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017 MediaTek Inc. + * Copyright (c) 2023 Collabora, Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include + +#include "clk-cpumux.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "reset.h" + +#define GATE_INFRA(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +static const char * const infra_mux1_parents[] = { + "clkxtal", + "armpll", + "main_core_en", + "armpll" +}; + +static const struct mtk_composite cpu_muxes[] = { + MUX(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents, 0x000, 2, 2), +}; + +static const struct mtk_gate infra_clks[] = { + GATE_INFRA(CLK_INFRA_DBGCLK_PD, "infra_dbgclk_pd", "axi_sel", 0), + GATE_INFRA(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 2), + GATE_INFRA(CLK_INFRA_AUDIO_PD, "infra_audio_pd", "aud_intbus_sel", 5), + GATE_INFRA(CLK_INFRA_IRRX_PD, "infra_irrx_pd", "irrx_sel", 16), + GATE_INFRA(CLK_INFRA_APXGPT_PD, "infra_apxgpt_pd", "f10m_ref_sel", 18), + GATE_INFRA(CLK_INFRA_PMIC_PD, "infra_pmic_pd", "pmicspi_sel", 22), +}; + +static u16 infrasys_rst_ofs[] = { 0x30 }; + +static const struct mtk_clk_rst_desc clk_rst_desc = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = infrasys_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(infrasys_rst_ofs), +}; + +static const struct of_device_id of_match_clk_mt7622_infracfg[] = { + { .compatible = "mediatek,mt7622-infracfg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622_infracfg); + +static int clk_mt7622_infracfg_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + void __iomem *base; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc); + if (ret) + goto free_clk_data; + + ret = mtk_clk_register_gates(&pdev->dev, node, infra_clks, + ARRAY_SIZE(infra_clks), clk_data); + if (ret) + goto free_clk_data; + + ret = mtk_clk_register_cpumuxes(&pdev->dev, node, cpu_muxes, + ARRAY_SIZE(cpu_muxes), clk_data); + if (ret) + goto unregister_gates; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_cpumuxes; + + return 0; + +unregister_cpumuxes: + mtk_clk_unregister_cpumuxes(cpu_muxes, ARRAY_SIZE(cpu_muxes), clk_data); +unregister_gates: + mtk_clk_unregister_gates(infra_clks, ARRAY_SIZE(infra_clks), clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + return ret; +} + +static int clk_mt7622_infracfg_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_cpumuxes(cpu_muxes, ARRAY_SIZE(cpu_muxes), clk_data); + mtk_clk_unregister_gates(infra_clks, ARRAY_SIZE(infra_clks), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static struct platform_driver clk_mt7622_infracfg_drv = { + .driver = { + .name = "clk-mt7622-infracfg", + .of_match_table = of_match_clk_mt7622_infracfg, + }, + .probe = clk_mt7622_infracfg_probe, + .remove = clk_mt7622_infracfg_remove, +}; +module_platform_driver(clk_mt7622_infracfg_drv); + +MODULE_DESCRIPTION("MediaTek MT7622 infracfg clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c index 5a82c2270bfb..274895264427 100644 --- a/drivers/clk/mediatek/clk-mt7622.c +++ b/drivers/clk/mediatek/clk-mt7622.c @@ -14,105 +14,28 @@ #include "clk-cpumux.h" #include "clk-gate.h" #include "clk-mtk.h" -#include "clk-pll.h" #include #include /* for consumer */ -#define MT7622_PLL_FMAX (2500UL * MHZ) -#define CON0_MT7622_RST_BAR BIT(27) +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift, _div_table, _parent_name) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = CON0_MT7622_RST_BAR, \ - .fmax = MT7622_PLL_FMAX, \ - .pcwbits = _pcwbits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .div_table = _div_table, \ - .parent_name = _parent_name, \ - } +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift) \ - PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ - NULL, "clkxtal") +#define GATE_PERI0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_APMIXED(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &apmixed_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_PERI0_AO(_id, _name, _parent, _shift) \ + GATE_MTK_FLAGS(_id, _name, _parent, &peri0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL) -#define GATE_INFRA(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } - -#define GATE_TOP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } - -#define GATE_TOP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } - -#define GATE_PERI0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } - -#define GATE_PERI1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static DEFINE_SPINLOCK(mt7622_clk_lock); -static const char * const infra_mux1_parents[] = { - "clkxtal", - "armpll", - "main_core_en", - "armpll" -}; - static const char * const axi_parents[] = { "clkxtal", "syspll1_d2", @@ -292,18 +215,6 @@ static const char * const peribus_ck_parents[] = { "syspll1_d4" }; -static const struct mtk_gate_regs apmixed_cg_regs = { - .set_ofs = 0x8, - .clr_ofs = 0x8, - .sta_ofs = 0x8, -}; - -static const struct mtk_gate_regs infra_cg_regs = { - .set_ofs = 0x40, - .clr_ofs = 0x44, - .sta_ofs = 0x48, -}; - static const struct mtk_gate_regs top0_cg_regs = { .set_ofs = 0x120, .clr_ofs = 0x120, @@ -328,40 +239,6 @@ static const struct mtk_gate_regs peri1_cg_regs = { .sta_ofs = 0x1C, }; -static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0, - PLL_AO, 21, 0x0204, 24, 0, 0x0204, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0210, 0x021C, 0, - HAVE_RST_BAR, 21, 0x0214, 24, 0, 0x0214, 0), - PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0220, 0x022C, 0, - HAVE_RST_BAR, 7, 0x0224, 24, 0, 0x0224, 14), - PLL(CLK_APMIXED_ETH1PLL, "eth1pll", 0x0300, 0x0310, 0, - 0, 21, 0x0300, 1, 0, 0x0304, 0), - PLL(CLK_APMIXED_ETH2PLL, "eth2pll", 0x0314, 0x0320, 0, - 0, 21, 0x0314, 1, 0, 0x0318, 0), - PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x0324, 0x0330, 0, - 0, 31, 0x0324, 1, 0, 0x0328, 0), - PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x0334, 0x0340, 0, - 0, 31, 0x0334, 1, 0, 0x0338, 0), - PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x0344, 0x0354, 0, - 0, 21, 0x0344, 1, 0, 0x0348, 0), - PLL(CLK_APMIXED_SGMIPLL, "sgmipll", 0x0358, 0x0368, 0, - 0, 21, 0x0358, 1, 0, 0x035C, 0), -}; - -static const struct mtk_gate apmixed_clks[] = { - GATE_APMIXED(CLK_APMIXED_MAIN_CORE_EN, "main_core_en", "mainpll", 5), -}; - -static const struct mtk_gate infra_clks[] = { - GATE_INFRA(CLK_INFRA_DBGCLK_PD, "infra_dbgclk_pd", "axi_sel", 0), - GATE_INFRA(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 2), - GATE_INFRA(CLK_INFRA_AUDIO_PD, "infra_audio_pd", "aud_intbus_sel", 5), - GATE_INFRA(CLK_INFRA_IRRX_PD, "infra_irrx_pd", "irrx_sel", 16), - GATE_INFRA(CLK_INFRA_APXGPT_PD, "infra_apxgpt_pd", "f10m_ref_sel", 18), - GATE_INFRA(CLK_INFRA_PMIC_PD, "infra_pmic_pd", "pmicspi_sel", 22), -}; - static const struct mtk_fixed_clk top_fixed_clks[] = { FIXED_CLK(CLK_TOP_TO_U2_PHY, "to_u2_phy", "clkxtal", 31250000), @@ -485,7 +362,7 @@ static const struct mtk_gate peri_clks[] = { GATE_PERI0(CLK_PERI_AP_DMA_PD, "peri_ap_dma_pd", "axi_sel", 12), GATE_PERI0(CLK_PERI_MSDC30_0_PD, "peri_msdc30_0", "msdc30_0_sel", 13), GATE_PERI0(CLK_PERI_MSDC30_1_PD, "peri_msdc30_1", "msdc30_1_sel", 14), - GATE_PERI0(CLK_PERI_UART0_PD, "peri_uart0_pd", "axi_sel", 17), + GATE_PERI0_AO(CLK_PERI_UART0_PD, "peri_uart0_pd", "axi_sel", 17), GATE_PERI0(CLK_PERI_UART1_PD, "peri_uart1_pd", "axi_sel", 18), GATE_PERI0(CLK_PERI_UART2_PD, "peri_uart2_pd", "axi_sel", 19), GATE_PERI0(CLK_PERI_UART3_PD, "peri_uart3_pd", "axi_sel", 20), @@ -506,19 +383,14 @@ static const struct mtk_gate peri_clks[] = { GATE_PERI1(CLK_PERI_IRTX_PD, "peri_irtx_pd", "irtx_sel", 2), }; -static struct mtk_composite infra_muxes[] = { - MUX(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents, - 0x000, 2, 2), -}; - static struct mtk_composite top_muxes[] = { /* CLK_CFG_0 */ - MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, - 0x040, 0, 3, 7), - MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, - 0x040, 8, 1, 15), - MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, - 0x040, 16, 1, 23), + MUX_GATE_FLAGS(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, + 0x040, 0, 3, 7, CLK_IS_CRITICAL), + MUX_GATE_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, + 0x040, 8, 1, 15, CLK_IS_CRITICAL), + MUX_GATE_FLAGS(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, + 0x040, 16, 1, 23, CLK_IS_CRITICAL), MUX_GATE(CLK_TOP_ETH_SEL, "eth_sel", eth_parents, 0x040, 24, 3, 31), @@ -610,182 +482,53 @@ static struct mtk_composite peri_muxes[] = { MUX(CLK_PERIBUS_SEL, "peribus_ck_sel", peribus_ck_parents, 0x05C, 0, 1), }; -static u16 infrasys_rst_ofs[] = { 0x30, }; static u16 pericfg_rst_ofs[] = { 0x0, 0x4, }; -static const struct mtk_clk_rst_desc clk_rst_desc[] = { - /* infrasys */ - { - .version = MTK_RST_SIMPLE, - .rst_bank_ofs = infrasys_rst_ofs, - .rst_bank_nr = ARRAY_SIZE(infrasys_rst_ofs), - }, - /* pericfg */ - { - .version = MTK_RST_SIMPLE, - .rst_bank_ofs = pericfg_rst_ofs, - .rst_bank_nr = ARRAY_SIZE(pericfg_rst_ofs), - }, +static const struct mtk_clk_rst_desc clk_rst_desc = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = pericfg_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(pericfg_rst_ofs), }; -static int mtk_topckgen_init(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - void __iomem *base; - struct device_node *node = pdev->dev.of_node; +static const struct mtk_clk_desc topck_desc = { + .clks = top_clks, + .num_clks = ARRAY_SIZE(top_clks), + .fixed_clks = top_fixed_clks, + .num_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .composite_clks = top_muxes, + .num_composite_clks = ARRAY_SIZE(top_muxes), + .divider_clks = top_adj_divs, + .num_divider_clks = ARRAY_SIZE(top_adj_divs), + .clk_lock = &mt7622_clk_lock, +}; - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - - mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), - clk_data); - - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), - clk_data); - - mtk_clk_register_composites(&pdev->dev, top_muxes, - ARRAY_SIZE(top_muxes), base, - &mt7622_clk_lock, clk_data); - - mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), - base, &mt7622_clk_lock, clk_data); - - mtk_clk_register_gates(&pdev->dev, node, top_clks, - ARRAY_SIZE(top_clks), clk_data); - - clk_prepare_enable(clk_data->hws[CLK_TOP_AXI_SEL]->clk); - clk_prepare_enable(clk_data->hws[CLK_TOP_MEM_SEL]->clk); - clk_prepare_enable(clk_data->hws[CLK_TOP_DDRPHYCFG_SEL]->clk); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} - -static int mtk_infrasys_init(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - struct clk_hw_onecell_data *clk_data; - int r; - - clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); - - mtk_clk_register_gates(&pdev->dev, node, infra_clks, - ARRAY_SIZE(infra_clks), clk_data); - - mtk_clk_register_cpumuxes(&pdev->dev, node, infra_muxes, - ARRAY_SIZE(infra_muxes), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, - clk_data); - if (r) - return r; - - mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[0]); - - return 0; -} - -static int mtk_apmixedsys_init(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - if (!clk_data) - return -ENOMEM; - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), - clk_data); - - mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, - ARRAY_SIZE(apmixed_clks), clk_data); - - clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk); - clk_prepare_enable(clk_data->hws[CLK_APMIXED_MAIN_CORE_EN]->clk); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} - -static int mtk_pericfg_init(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - void __iomem *base; - int r; - struct device_node *node = pdev->dev.of_node; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); - - mtk_clk_register_gates(&pdev->dev, node, peri_clks, - ARRAY_SIZE(peri_clks), clk_data); - - mtk_clk_register_composites(&pdev->dev, peri_muxes, - ARRAY_SIZE(peri_muxes), base, - &mt7622_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - return r; - - clk_prepare_enable(clk_data->hws[CLK_PERI_UART0_PD]->clk); - - mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[1]); - - return 0; -} +static const struct mtk_clk_desc peri_desc = { + .clks = peri_clks, + .num_clks = ARRAY_SIZE(peri_clks), + .composite_clks = peri_muxes, + .num_composite_clks = ARRAY_SIZE(peri_muxes), + .rst_desc = &clk_rst_desc, + .clk_lock = &mt7622_clk_lock, +}; static const struct of_device_id of_match_clk_mt7622[] = { - { - .compatible = "mediatek,mt7622-apmixedsys", - .data = mtk_apmixedsys_init, - }, { - .compatible = "mediatek,mt7622-infracfg", - .data = mtk_infrasys_init, - }, { - .compatible = "mediatek,mt7622-topckgen", - .data = mtk_topckgen_init, - }, { - .compatible = "mediatek,mt7622-pericfg", - .data = mtk_pericfg_init, - }, { - /* sentinel */ - } + { .compatible = "mediatek,mt7622-topckgen", .data = &topck_desc }, + { .compatible = "mediatek,mt7622-pericfg", .data = &peri_desc }, + { /* sentinel */ } }; - -static int clk_mt7622_probe(struct platform_device *pdev) -{ - int (*clk_init)(struct platform_device *); - int r; - - clk_init = of_device_get_match_data(&pdev->dev); - if (!clk_init) - return -EINVAL; - - r = clk_init(pdev); - if (r) - dev_err(&pdev->dev, - "could not register clock provider: %s: %d\n", - pdev->name, r); - - return r; -} +MODULE_DEVICE_TABLE(of, of_match_clk_mt7622); static struct platform_driver clk_mt7622_drv = { - .probe = clk_mt7622_probe, .driver = { .name = "clk-mt7622", .of_match_table = of_match_clk_mt7622, }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, }; +module_platform_driver(clk_mt7622_drv) -static int clk_mt7622_init(void) -{ - return platform_driver_register(&clk_mt7622_drv); -} - -arch_initcall(clk_mt7622_init); +MODULE_DESCRIPTION("MediaTek MT7622 clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7629-eth.c b/drivers/clk/mediatek/clk-mt7629-eth.c index a4ae7d6c7a71..1e1c77cc14ba 100644 --- a/drivers/clk/mediatek/clk-mt7629-eth.c +++ b/drivers/clk/mediatek/clk-mt7629-eth.c @@ -16,14 +16,8 @@ #include -#define GATE_ETH(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = ð_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_ETH(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, ð_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate_regs eth_cg_regs = { .set_ofs = 0x30, @@ -45,14 +39,8 @@ static const struct mtk_gate_regs sgmii_cg_regs = { .sta_ofs = 0xE4, }; -#define GATE_SGMII(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &sgmii_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SGMII(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &sgmii_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate sgmii_clks[2][4] = { { @@ -138,6 +126,7 @@ static const struct of_device_id of_match_clk_mt7629_eth[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7629_eth); static int clk_mt7629_eth_probe(struct platform_device *pdev) { @@ -166,3 +155,4 @@ static struct platform_driver clk_mt7629_eth_drv = { }; builtin_platform_driver(clk_mt7629_eth_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7629-hif.c b/drivers/clk/mediatek/clk-mt7629-hif.c index c3eb09ea6036..c89036bee9a7 100644 --- a/drivers/clk/mediatek/clk-mt7629-hif.c +++ b/drivers/clk/mediatek/clk-mt7629-hif.c @@ -16,23 +16,11 @@ #include -#define GATE_PCIE(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &pcie_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_PCIE(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &pcie_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -#define GATE_SSUSB(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ssusb_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SSUSB(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ssusb_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) static const struct mtk_gate_regs pcie_cg_regs = { .set_ofs = 0x30, @@ -96,6 +84,7 @@ static const struct of_device_id of_match_clk_mt7629_hif[] = { { .compatible = "mediatek,mt7629-ssusbsys", .data = &ssusb_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7629_hif); static struct platform_driver clk_mt7629_hif_drv = { .probe = mtk_clk_simple_probe, @@ -105,5 +94,5 @@ static struct platform_driver clk_mt7629_hif_drv = { .of_match_table = of_match_clk_mt7629_hif, }, }; - -builtin_platform_driver(clk_mt7629_hif_drv); +module_platform_driver(clk_mt7629_hif_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index cf062d4a7ecc..0893fbbb68cc 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -50,41 +50,17 @@ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ NULL, "clk20m") -#define GATE_APMIXED(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &apmixed_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -#define GATE_INFRA(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_INFRA(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static DEFINE_SPINLOCK(mt7629_clk_lock); @@ -684,6 +660,7 @@ static const struct of_device_id of_match_clk_mt7629[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7629); static int clk_mt7629_probe(struct platform_device *pdev) { @@ -717,3 +694,4 @@ static int clk_mt7629_init(void) } arch_initcall(clk_mt7629_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7981-apmixed.c b/drivers/clk/mediatek/clk-mt7981-apmixed.c index 52b7123232bf..875813d8b4a9 100644 --- a/drivers/clk/mediatek/clk-mt7981-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c @@ -66,6 +66,7 @@ static const struct of_device_id of_match_clk_mt7981_apmixed[] = { { .compatible = "mediatek,mt7981-apmixedsys", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7981_apmixed); static int clk_mt7981_apmixed_probe(struct platform_device *pdev) { @@ -100,3 +101,4 @@ static struct platform_driver clk_mt7981_apmixed_drv = { }, }; builtin_platform_driver(clk_mt7981_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c index 773350911be2..b1f256b5ed4e 100644 --- a/drivers/clk/mediatek/clk-mt7981-eth.c +++ b/drivers/clk/mediatek/clk-mt7981-eth.c @@ -105,6 +105,7 @@ static const struct of_device_id of_match_clk_mt7981_eth[] = { { .compatible = "mediatek,mt7981-sgmiisys_1", .data = &sgmii1_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7981_eth); static struct platform_driver clk_mt7981_eth_drv = { .probe = mtk_clk_simple_probe, @@ -115,4 +116,4 @@ static struct platform_driver clk_mt7981_eth_drv = { }, }; module_platform_driver(clk_mt7981_eth_drv); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7981-infracfg.c b/drivers/clk/mediatek/clk-mt7981-infracfg.c index 8cf5057419e8..293261ef71e6 100644 --- a/drivers/clk/mediatek/clk-mt7981-infracfg.c +++ b/drivers/clk/mediatek/clk-mt7981-infracfg.c @@ -195,6 +195,7 @@ static const struct of_device_id of_match_clk_mt7981_infracfg[] = { { .compatible = "mediatek,mt7981-infracfg", .data = &infracfg_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7981_infracfg); static struct platform_driver clk_mt7981_infracfg_drv = { .probe = mtk_clk_simple_probe, @@ -204,4 +205,5 @@ static struct platform_driver clk_mt7981_infracfg_drv = { .of_match_table = of_match_clk_mt7981_infracfg, }, }; -builtin_platform_driver(clk_mt7981_infracfg_drv); +module_platform_driver(clk_mt7981_infracfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7981-topckgen.c b/drivers/clk/mediatek/clk-mt7981-topckgen.c index 74634d65f5f6..3aba1a9b9a36 100644 --- a/drivers/clk/mediatek/clk-mt7981-topckgen.c +++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c @@ -410,6 +410,7 @@ static const struct of_device_id of_match_clk_mt7981_topckgen[] = { { .compatible = "mediatek,mt7981-topckgen", .data = &topck_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7981_topckgen); static struct platform_driver clk_mt7981_topckgen_drv = { .probe = mtk_clk_simple_probe, @@ -419,4 +420,5 @@ static struct platform_driver clk_mt7981_topckgen_drv = { .of_match_table = of_match_clk_mt7981_topckgen, }, }; -builtin_platform_driver(clk_mt7981_topckgen_drv); +module_platform_driver(clk_mt7981_topckgen_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c index 62080ee4dbe3..6767e9c43886 100644 --- a/drivers/clk/mediatek/clk-mt7986-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c @@ -42,7 +42,7 @@ "clkxtal") static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x0, 0, 32, + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x0, PLL_AO, 32, 0x0200, 4, 0, 0x0204, 0), PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x0, 0, 32, 0x0210, 4, 0, 0x0214, 0), @@ -62,8 +62,9 @@ static const struct mtk_pll_data plls[] = { static const struct of_device_id of_match_clk_mt7986_apmixed[] = { { .compatible = "mediatek,mt7986-apmixedsys", }, - {} + { } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7986_apmixed); static int clk_mt7986_apmixed_probe(struct platform_device *pdev) { @@ -77,8 +78,6 @@ static int clk_mt7986_apmixed_probe(struct platform_device *pdev) mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk); - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (r) { pr_err("%s(): could not register clock provider: %d\n", @@ -100,3 +99,4 @@ static struct platform_driver clk_mt7986_apmixed_drv = { }, }; builtin_platform_driver(clk_mt7986_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7986-eth.c b/drivers/clk/mediatek/clk-mt7986-eth.c index 703872239ecc..0681988960cc 100644 --- a/drivers/clk/mediatek/clk-mt7986-eth.c +++ b/drivers/clk/mediatek/clk-mt7986-eth.c @@ -22,14 +22,10 @@ static const struct mtk_gate_regs sgmii0_cg_regs = { .sta_ofs = 0xe4, }; -#define GATE_SGMII0(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = &sgmii0_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SGMII0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &sgmii0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -static const struct mtk_gate sgmii0_clks[] __initconst = { +static const struct mtk_gate sgmii0_clks[] = { GATE_SGMII0(CLK_SGMII0_TX250M_EN, "sgmii0_tx250m_en", "top_xtal", 2), GATE_SGMII0(CLK_SGMII0_RX250M_EN, "sgmii0_rx250m_en", "top_xtal", 3), GATE_SGMII0(CLK_SGMII0_CDR_REF, "sgmii0_cdr_ref", "top_xtal", 4), @@ -42,14 +38,10 @@ static const struct mtk_gate_regs sgmii1_cg_regs = { .sta_ofs = 0xe4, }; -#define GATE_SGMII1(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = &sgmii1_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_SGMII1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &sgmii1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -static const struct mtk_gate sgmii1_clks[] __initconst = { +static const struct mtk_gate sgmii1_clks[] = { GATE_SGMII1(CLK_SGMII1_TX250M_EN, "sgmii1_tx250m_en", "top_xtal", 2), GATE_SGMII1(CLK_SGMII1_RX250M_EN, "sgmii1_rx250m_en", "top_xtal", 3), GATE_SGMII1(CLK_SGMII1_CDR_REF, "sgmii1_cdr_ref", "top_xtal", 4), @@ -62,14 +54,10 @@ static const struct mtk_gate_regs eth_cg_regs = { .sta_ofs = 0x30, }; -#define GATE_ETH(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = ð_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr_inv, \ - } +#define GATE_ETH(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, ð_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) -static const struct mtk_gate eth_clks[] __initconst = { +static const struct mtk_gate eth_clks[] = { GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x_sel", 6), GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m_sel", 7), GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m_sel", 8), @@ -77,56 +65,38 @@ static const struct mtk_gate eth_clks[] __initconst = { GATE_ETH(CLK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_mcu_sel", 15), }; -static void __init mtk_sgmiisys_0_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc eth_desc = { + .clks = eth_clks, + .num_clks = ARRAY_SIZE(eth_clks), +}; - clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii0_clks)); +static const struct mtk_clk_desc sgmii0_desc = { + .clks = sgmii0_clks, + .num_clks = ARRAY_SIZE(sgmii0_clks), +}; - mtk_clk_register_gates(NULL, node, sgmii0_clks, - ARRAY_SIZE(sgmii0_clks), clk_data); +static const struct mtk_clk_desc sgmii1_desc = { + .clks = sgmii1_clks, + .num_clks = ARRAY_SIZE(sgmii1_clks), +}; - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7986-sgmiisys_0", - mtk_sgmiisys_0_init); +static const struct of_device_id of_match_clk_mt7986_eth[] = { + { .compatible = "mediatek,mt7986-ethsys", .data = ð_desc }, + { .compatible = "mediatek,mt7986-sgmiisys_0", .data = &sgmii0_desc }, + { .compatible = "mediatek,mt7986-sgmiisys_1", .data = &sgmii1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7986_eth); -static void __init mtk_sgmiisys_1_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static struct platform_driver clk_mt7986_eth_drv = { + .driver = { + .name = "clk-mt7986-eth", + .of_match_table = of_match_clk_mt7986_eth, + }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, +}; +module_platform_driver(clk_mt7986_eth_drv); - clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii1_clks)); - - mtk_clk_register_gates(NULL, node, sgmii1_clks, - ARRAY_SIZE(sgmii1_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7986-sgmiisys_1", - mtk_sgmiisys_1_init); - -static void __init mtk_ethsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - - clk_data = mtk_alloc_clk_data(ARRAY_SIZE(eth_clks)); - - mtk_clk_register_gates(NULL, node, eth_clks, ARRAY_SIZE(eth_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt7986-ethsys", mtk_ethsys_init); +MODULE_DESCRIPTION("MediaTek MT7986 Ethernet clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7986-infracfg.c b/drivers/clk/mediatek/clk-mt7986-infracfg.c index e80c92167c8f..b7efa70c2d6c 100644 --- a/drivers/clk/mediatek/clk-mt7986-infracfg.c +++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c @@ -87,26 +87,14 @@ static const struct mtk_gate_regs infra2_cg_regs = { .sta_ofs = 0x68, }; -#define GATE_INFRA0(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = &infra0_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_INFRA0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_INFRA1(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = &infra1_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_INFRA1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_INFRA2(_id, _name, _parent, _shift) \ - { \ - .id = _id, .name = _name, .parent_name = _parent, \ - .regs = &infra2_cg_regs, .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_INFRA2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate infra_clks[] = { /* INFRA0 */ @@ -169,57 +157,31 @@ static const struct mtk_gate infra_clks[] = { GATE_INFRA2(CLK_INFRA_IPCIEB_CK, "infra_ipcieb", "sysaxi_sel", 15), }; -static int clk_mt7986_infracfg_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - int r; - void __iomem *base; - int nr = ARRAY_SIZE(infra_divs) + ARRAY_SIZE(infra_muxes) + - ARRAY_SIZE(infra_clks); - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return -ENOMEM; - } - - clk_data = mtk_alloc_clk_data(nr); - - if (!clk_data) - return -ENOMEM; - - mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data); - mtk_clk_register_muxes(&pdev->dev, infra_muxes, - ARRAY_SIZE(infra_muxes), node, - &mt7986_clk_lock, clk_data); - mtk_clk_register_gates(&pdev->dev, node, infra_clks, - ARRAY_SIZE(infra_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) { - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - goto free_infracfg_data; - } - return r; - -free_infracfg_data: - mtk_free_clk_data(clk_data); - return r; - -} - -static const struct of_device_id of_match_clk_mt7986_infracfg[] = { - { .compatible = "mediatek,mt7986-infracfg", }, - {} +static const struct mtk_clk_desc infra_desc = { + .clks = infra_clks, + .num_clks = ARRAY_SIZE(infra_clks), + .factor_clks = infra_divs, + .num_factor_clks = ARRAY_SIZE(infra_divs), + .mux_clks = infra_muxes, + .num_mux_clks = ARRAY_SIZE(infra_muxes), + .clk_lock = &mt7986_clk_lock, }; +static const struct of_device_id of_match_clk_mt7986_infracfg[] = { + { .compatible = "mediatek,mt7986-infracfg", .data = &infra_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7986_infracfg); + static struct platform_driver clk_mt7986_infracfg_drv = { - .probe = clk_mt7986_infracfg_probe, .driver = { .name = "clk-mt7986-infracfg", .of_match_table = of_match_clk_mt7986_infracfg, }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, }; -builtin_platform_driver(clk_mt7986_infracfg_drv); +module_platform_driver(clk_mt7986_infracfg_drv); + +MODULE_DESCRIPTION("MediaTek MT7986 infracfg clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7986-topckgen.c b/drivers/clk/mediatek/clk-mt7986-topckgen.c index dff9976fa689..fbca3feded8f 100644 --- a/drivers/clk/mediatek/clk-mt7986-topckgen.c +++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c @@ -304,6 +304,7 @@ static const struct of_device_id of_match_clk_mt7986_topckgen[] = { { .compatible = "mediatek,mt7986-topckgen", .data = &topck_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7986_topckgen); static struct platform_driver clk_mt7986_topckgen_drv = { .probe = mtk_clk_simple_probe, @@ -313,4 +314,5 @@ static struct platform_driver clk_mt7986_topckgen_drv = { .of_match_table = of_match_clk_mt7986_topckgen, }, }; -builtin_platform_driver(clk_mt7986_topckgen_drv); +module_platform_driver(clk_mt7986_topckgen_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c new file mode 100644 index 000000000000..744aae092281 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014 MediaTek Inc. + * James Liao + * Copyright (c) 2023 Collabora, Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +#define MT8135_PLL_FMAX (2000 * MHZ) +#define CON0_MT8135_RST_BAR BIT(27) + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8135_RST_BAR, \ + .fmax = MT8135_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + } + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL1, "armpll1", 0x200, 0x218, 0x80000000, 0, 21, 0x204, 24, 0x0, 0x204, 0), + PLL(CLK_APMIXED_ARMPLL2, "armpll2", 0x2cc, 0x2e4, 0x80000000, 0, 21, 0x2d0, 24, 0x0, 0x2d0, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x21c, 0x234, 0xf0000000, HAVE_RST_BAR, 21, 0x21c, 6, 0x0, 0x220, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x238, 0x250, 0xf3000000, HAVE_RST_BAR, 7, 0x238, 6, 0x0, 0x238, 9), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x254, 0x26c, 0xf0000000, HAVE_RST_BAR, 21, 0x254, 6, 0x0, 0x258, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x278, 0x290, 0x80000000, 0, 21, 0x278, 6, 0x0, 0x27c, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x294, 0x2ac, 0x80000000, 0, 31, 0x294, 6, 0x0, 0x298, 0), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2b0, 0x2c8, 0x80000000, 0, 21, 0x2b0, 6, 0x0, 0x2b4, 0), + PLL(CLK_APMIXED_AUDPLL, "audpll", 0x2e8, 0x300, 0x80000000, 0, 31, 0x2e8, 6, 0x2f8, 0x2ec, 0), + PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x304, 0x31c, 0x80000000, 0, 21, 0x2b0, 6, 0x0, 0x308, 0), +}; + +static int clk_mt8135_apmixed_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int ret; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_plls; + + return 0; + +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static int clk_mt8135_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static const struct of_device_id of_match_clk_mt8135_apmixed[] = { + { .compatible = "mediatek,mt8135-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8135_apmixed); + +static struct platform_driver clk_mt8135_apmixed_drv = { + .probe = clk_mt8135_apmixed_probe, + .remove = clk_mt8135_apmixed_remove, + .driver = { + .name = "clk-mt8135-apmixed", + .of_match_table = of_match_clk_mt8135_apmixed, + }, +}; +module_platform_driver(clk_mt8135_apmixed_drv) + +MODULE_DESCRIPTION("MediaTek MT8135 apmixedsys clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c index 2b9c925c2a2b..084e48a554c2 100644 --- a/drivers/clk/mediatek/clk-mt8135.c +++ b/drivers/clk/mediatek/clk-mt8135.c @@ -5,8 +5,10 @@ */ #include +#include #include #include +#include #include #include #include @@ -17,14 +19,13 @@ static DEFINE_SPINLOCK(mt8135_clk_lock); -static const struct mtk_fixed_factor root_clk_alias[] __initconst = { +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_DUMMY, "top_divs_dummy", "clk_null", 1, 1), FACTOR(CLK_TOP_DSI0_LNTC_DSICLK, "dsi0_lntc_dsiclk", "clk_null", 1, 1), FACTOR(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_clkdig_cts", "clk_null", 1, 1), FACTOR(CLK_TOP_CLKPH_MCK, "clkph_mck", "clk_null", 1, 1), FACTOR(CLK_TOP_CPUM_TCK_IN, "cpum_tck_in", "clk_null", 1, 1), -}; -static const struct mtk_fixed_factor top_divs[] __initconst = { FACTOR(CLK_TOP_MAINPLL_806M, "mainpll_806m", "mainpll", 1, 2), FACTOR(CLK_TOP_MAINPLL_537P3M, "mainpll_537p3m", "mainpll", 1, 3), FACTOR(CLK_TOP_MAINPLL_322P4M, "mainpll_322p4m", "mainpll", 1, 5), @@ -100,7 +101,7 @@ static const struct mtk_fixed_factor top_divs[] __initconst = { FACTOR(CLK_TOP_MEMPLL_MCK_D4, "mempll_mck_d4", "clkph_mck", 1, 4), }; -static const char * const axi_parents[] __initconst = { +static const char * const axi_parents[] = { "clk26m", "syspll_d3", "syspll_d4", @@ -110,7 +111,7 @@ static const char * const axi_parents[] __initconst = { "syspll_d3p5" }; -static const char * const smi_parents[] __initconst = { +static const char * const smi_parents[] = { "clk26m", "clkph_mck", "syspll_d2p5", @@ -128,7 +129,7 @@ static const char * const smi_parents[] __initconst = { "lvdspll" }; -static const char * const mfg_parents[] __initconst = { +static const char * const mfg_parents[] = { "clk26m", "univpll1_d4", "syspll_d2", @@ -144,13 +145,13 @@ static const char * const mfg_parents[] __initconst = { "mmpll_d7" }; -static const char * const irda_parents[] __initconst = { +static const char * const irda_parents[] = { "clk26m", "univpll2_d8", "univpll1_d6" }; -static const char * const cam_parents[] __initconst = { +static const char * const cam_parents[] = { "clk26m", "syspll_d3", "syspll_d3p5", @@ -161,13 +162,13 @@ static const char * const cam_parents[] __initconst = { "univpll1_d4" }; -static const char * const aud_intbus_parents[] __initconst = { +static const char * const aud_intbus_parents[] = { "clk26m", "syspll_d6", "univpll_d10" }; -static const char * const jpg_parents[] __initconst = { +static const char * const jpg_parents[] = { "clk26m", "syspll_d5", "syspll_d4", @@ -177,7 +178,7 @@ static const char * const jpg_parents[] __initconst = { "univpll_d5" }; -static const char * const disp_parents[] __initconst = { +static const char * const disp_parents[] = { "clk26m", "syspll_d3p5", "syspll_d3", @@ -188,7 +189,7 @@ static const char * const disp_parents[] __initconst = { "vdecpll" }; -static const char * const msdc30_parents[] __initconst = { +static const char * const msdc30_parents[] = { "clk26m", "syspll_d6", "syspll_d5", @@ -197,13 +198,13 @@ static const char * const msdc30_parents[] __initconst = { "msdcpll" }; -static const char * const usb20_parents[] __initconst = { +static const char * const usb20_parents[] = { "clk26m", "univpll2_d6", "univpll1_d10" }; -static const char * const venc_parents[] __initconst = { +static const char * const venc_parents[] = { "clk26m", "syspll_d3", "syspll_d8", @@ -214,7 +215,7 @@ static const char * const venc_parents[] __initconst = { "mmpll_d6" }; -static const char * const spi_parents[] __initconst = { +static const char * const spi_parents[] = { "clk26m", "syspll_d6", "syspll_d8", @@ -223,17 +224,17 @@ static const char * const spi_parents[] __initconst = { "univpll1_d8" }; -static const char * const uart_parents[] __initconst = { +static const char * const uart_parents[] = { "clk26m", "univpll2_d8" }; -static const char * const mem_parents[] __initconst = { +static const char * const mem_parents[] = { "clk26m", "clkph_mck" }; -static const char * const camtg_parents[] __initconst = { +static const char * const camtg_parents[] = { "clk26m", "univpll_d26", "univpll1_d6", @@ -241,12 +242,12 @@ static const char * const camtg_parents[] __initconst = { "syspll_d8" }; -static const char * const audio_parents[] __initconst = { +static const char * const audio_parents[] = { "clk26m", "syspll_d24" }; -static const char * const fix_parents[] __initconst = { +static const char * const fix_parents[] = { "rtc32k", "clk26m", "univpll_d5", @@ -257,7 +258,7 @@ static const char * const fix_parents[] __initconst = { "univpll1_d8" }; -static const char * const vdec_parents[] __initconst = { +static const char * const vdec_parents[] = { "clk26m", "vdecpll", "clkph_mck", @@ -276,13 +277,13 @@ static const char * const vdec_parents[] __initconst = { "lvdspll" }; -static const char * const ddrphycfg_parents[] __initconst = { +static const char * const ddrphycfg_parents[] = { "clk26m", "axi_sel", "syspll_d12" }; -static const char * const dpilvds_parents[] __initconst = { +static const char * const dpilvds_parents[] = { "clk26m", "lvdspll", "lvdspll_d2", @@ -290,7 +291,7 @@ static const char * const dpilvds_parents[] __initconst = { "lvdspll_d8" }; -static const char * const pmicspi_parents[] __initconst = { +static const char * const pmicspi_parents[] = { "clk26m", "univpll2_d6", "syspll_d8", @@ -301,14 +302,14 @@ static const char * const pmicspi_parents[] __initconst = { "syspll_d24" }; -static const char * const smi_mfg_as_parents[] __initconst = { +static const char * const smi_mfg_as_parents[] = { "clk26m", "smi_sel", "mfg_sel", "mem_sel" }; -static const char * const gcpu_parents[] __initconst = { +static const char * const gcpu_parents[] = { "clk26m", "syspll_d4", "univpll_d7", @@ -316,14 +317,14 @@ static const char * const gcpu_parents[] __initconst = { "syspll_d6" }; -static const char * const dpi1_parents[] __initconst = { +static const char * const dpi1_parents[] = { "clk26m", "tvhdmi_h_ck", "tvhdmi_d2", "tvhdmi_d4" }; -static const char * const cci_parents[] __initconst = { +static const char * const cci_parents[] = { "clk26m", "mainpll_537p3m", "univpll_d3", @@ -332,7 +333,7 @@ static const char * const cci_parents[] __initconst = { "syspll_d5" }; -static const char * const apll_parents[] __initconst = { +static const char * const apll_parents[] = { "clk26m", "apll_ck", "apll_d4", @@ -341,14 +342,14 @@ static const char * const apll_parents[] __initconst = { "apll_d24" }; -static const char * const hdmipll_parents[] __initconst = { +static const char * const hdmipll_parents[] = { "clk26m", "hdmitx_clkdig_cts", "hdmitx_clkdig_d2", "hdmitx_clkdig_d3" }; -static const struct mtk_composite top_muxes[] __initconst = { +static const struct mtk_composite top_muxes[] = { /* CLK_CFG_0 */ MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0140, 0, 3, INVALID_MUX_GATE_BIT), @@ -390,7 +391,7 @@ static const struct mtk_composite top_muxes[] __initconst = { MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", gcpu_parents, 0x0164, 24, 3, 31), /* CLK_CFG_9 */ MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0168, 0, 2, 7), - MUX_GATE(CLK_TOP_CCI_SEL, "cci_sel", cci_parents, 0x0168, 8, 3, 15), + MUX_GATE_FLAGS(CLK_TOP_CCI_SEL, "cci_sel", cci_parents, 0x0168, 8, 3, 15, CLK_IS_CRITICAL), MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0168, 16, 3, 23), MUX_GATE(CLK_TOP_HDMIPLL_SEL, "hdmipll_sel", hdmipll_parents, 0x0168, 24, 2, 31), }; @@ -401,23 +402,22 @@ static const struct mtk_gate_regs infra_cg_regs = { .sta_ofs = 0x0048, }; -#define GATE_ICG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_ICG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -static const struct mtk_gate infra_clks[] __initconst = { +#define GATE_ICG_AO(_id, _name, _parent, _shift) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL) + +static const struct mtk_gate infra_clks[] = { + GATE_DUMMY(CLK_DUMMY, "infra_dummy"), GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23), GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22), GATE_ICG(CLK_INFRA_CCIF1_AP_CTRL, "ccif1_ap_ctrl", "axi_sel", 21), GATE_ICG(CLK_INFRA_CCIF0_AP_CTRL, "ccif0_ap_ctrl", "axi_sel", 20), GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16), GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15), - GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8), + GATE_ICG_AO(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8), GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7), GATE_ICG(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6), GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5), @@ -438,25 +438,14 @@ static const struct mtk_gate_regs peri1_cg_regs = { .sta_ofs = 0x001c, }; -#define GATE_PERI0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_PERI1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &peri1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_PERI1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -static const struct mtk_gate peri_gates[] __initconst = { +static const struct mtk_gate peri_gates[] = { + GATE_DUMMY(CLK_DUMMY, "peri_dummy"), /* PERI0 */ GATE_PERI0(CLK_PERI_I2C5, "i2c5_ck", "axi_sel", 31), GATE_PERI0(CLK_PERI_I2C4, "i2c4_ck", "axi_sel", 30), @@ -502,12 +491,12 @@ static const struct mtk_gate peri_gates[] __initconst = { GATE_PERI1(CLK_PERI_I2C6, "i2c6_ck", "axi_sel", 0), }; -static const char * const uart_ck_sel_parents[] __initconst = { +static const char * const uart_ck_sel_parents[] = { "clk26m", "uart_sel", }; -static const struct mtk_composite peri_clks[] __initconst = { +static const struct mtk_composite peri_clks[] = { MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1), MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1), MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1), @@ -532,127 +521,46 @@ static const struct mtk_clk_rst_desc clk_rst_desc[] = { } }; -static void __init mtk_topckgen_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - void __iomem *base; - int r; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - - mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data); - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); - mtk_clk_register_composites(NULL, top_muxes, - ARRAY_SIZE(top_muxes), base, - &mt8135_clk_lock, clk_data); - - clk_prepare_enable(clk_data->hws[CLK_TOP_CCI_SEL]->clk); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8135-topckgen", mtk_topckgen_init); - -static void __init mtk_infrasys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - - clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); - - mtk_clk_register_gates(NULL, node, infra_clks, - ARRAY_SIZE(infra_clks), clk_data); - - clk_prepare_enable(clk_data->hws[CLK_INFRA_M4U]->clk); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - mtk_register_reset_controller(node, &clk_rst_desc[0]); -} -CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8135-infracfg", mtk_infrasys_init); - -static void __init mtk_pericfg_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - void __iomem *base; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); - - mtk_clk_register_gates(NULL, node, peri_gates, - ARRAY_SIZE(peri_gates), clk_data); - mtk_clk_register_composites(NULL, peri_clks, - ARRAY_SIZE(peri_clks), base, - &mt8135_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - - mtk_register_reset_controller(node, &clk_rst_desc[1]); -} -CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8135-pericfg", mtk_pericfg_init); - -#define MT8135_PLL_FMAX (2000 * MHZ) -#define CON0_MT8135_RST_BAR BIT(27) - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = CON0_MT8135_RST_BAR, \ - .fmax = MT8135_PLL_FMAX, \ - .pcwbits = _pcwbits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - } - -static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_ARMPLL1, "armpll1", 0x200, 0x218, 0x80000000, 0, 21, 0x204, 24, 0x0, 0x204, 0), - PLL(CLK_APMIXED_ARMPLL2, "armpll2", 0x2cc, 0x2e4, 0x80000000, 0, 21, 0x2d0, 24, 0x0, 0x2d0, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x21c, 0x234, 0xf0000000, HAVE_RST_BAR, 21, 0x21c, 6, 0x0, 0x220, 0), - PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x238, 0x250, 0xf3000000, HAVE_RST_BAR, 7, 0x238, 6, 0x0, 0x238, 9), - PLL(CLK_APMIXED_MMPLL, "mmpll", 0x254, 0x26c, 0xf0000000, HAVE_RST_BAR, 21, 0x254, 6, 0x0, 0x258, 0), - PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x278, 0x290, 0x80000000, 0, 21, 0x278, 6, 0x0, 0x27c, 0), - PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x294, 0x2ac, 0x80000000, 0, 31, 0x294, 6, 0x0, 0x298, 0), - PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2b0, 0x2c8, 0x80000000, 0, 21, 0x2b0, 6, 0x0, 0x2b4, 0), - PLL(CLK_APMIXED_AUDPLL, "audpll", 0x2e8, 0x300, 0x80000000, 0, 31, 0x2e8, 6, 0x2f8, 0x2ec, 0), - PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x304, 0x31c, 0x80000000, 0, 21, 0x2b0, 6, 0x0, 0x308, 0), +static const struct mtk_clk_desc infra_desc = { + .clks = infra_clks, + .num_clks = ARRAY_SIZE(infra_clks), + .rst_desc = &clk_rst_desc[0], }; -static void __init mtk_apmixedsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; +static const struct mtk_clk_desc peri_desc = { + .clks = peri_gates, + .num_clks = ARRAY_SIZE(peri_gates), + .composite_clks = peri_clks, + .num_composite_clks = ARRAY_SIZE(peri_clks), + .clk_lock = &mt8135_clk_lock, + .rst_desc = &clk_rst_desc[1], +}; - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - if (!clk_data) - return; +static const struct mtk_clk_desc topck_desc = { + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .composite_clks = top_muxes, + .num_composite_clks = ARRAY_SIZE(top_muxes), + .clk_lock = &mt8135_clk_lock, +}; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); -} -CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8135-apmixedsys", - mtk_apmixedsys_init); +static const struct of_device_id of_match_clk_mt8135[] = { + { .compatible = "mediatek,mt8135-infracfg", .data = &infra_desc }, + { .compatible = "mediatek,mt8135-pericfg", .data = &peri_desc }, + { .compatible = "mediatek,mt8135-topckgen", .data = &topck_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8135); + +static struct platform_driver clk_mt8135_drv = { + .driver = { + .name = "clk-mt8135", + .of_match_table = of_match_clk_mt8135, + }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, +}; +module_platform_driver(clk_mt8135_drv); + +MODULE_DESCRIPTION("MediaTek MT8135 clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-apmixedsys.c b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c new file mode 100644 index 000000000000..fca41f50d6ba --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8167-apmixedsys.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 MediaTek Inc. + * Copyright (c) 2020 BayLibre, SAS + * Copyright (c) 2023 Collabora, Ltd. + */ + +#include +#include +#include +#include + +#include "clk-pll.h" +#include "clk-mtk.h" + +static DEFINE_SPINLOCK(mt8167_apmixed_clk_lock); + +#define MT8167_PLL_FMAX (2500UL * MHZ) + +#define CON0_MT8167_RST_BAR BIT(27) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8167_RST_BAR, \ + .fmax = MT8167_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL) + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT8167_PLL_FMAX }, + { .div = 1, .freq = 1000000000 }, + { .div = 2, .freq = 604500000 }, + { .div = 3, .freq = 253500000 }, + { .div = 4, .freq = 126750000 }, + { /* sentinel */ } +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0100, 0x0110, 0, 0, + 21, 0x0104, 24, 0, 0x0104, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0120, 0x0130, 0, + HAVE_RST_BAR, 21, 0x0124, 24, 0, 0x0124, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0140, 0x0150, 0x30000000, + HAVE_RST_BAR, 7, 0x0144, 24, 0, 0x0144, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0160, 0x0170, 0, 0, + 21, 0x0164, 24, 0, 0x0164, 0, mmpll_div_table), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0180, 0x0190, 0, 0, + 31, 0x0180, 1, 0x0194, 0x0184, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x01A0, 0x01B0, 0, 0, + 31, 0x01A0, 1, 0x01B4, 0x01A4, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x01C0, 0x01D0, 0, 0, + 21, 0x01C4, 24, 0, 0x01C4, 0), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x01E0, 0x01F0, 0, 0, + 21, 0x01E4, 24, 0, 0x01E4, 0), +}; + +#define DIV_ADJ_FLAG(_id, _name, _parent, _reg, _shift, _width, _flag) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .div_reg = _reg, \ + .div_shift = _shift, \ + .div_width = _width, \ + .clk_divider_flags = _flag, \ +} + +static const struct mtk_clk_divider adj_divs[] = { + DIV_ADJ_FLAG(CLK_APMIXED_HDMI_REF, "hdmi_ref", "tvdpll", + 0x1c4, 24, 3, CLK_DIVIDER_POWER_OF_TWO), +}; + +static int clk_mt8167_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(dev, MT8167_CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = mtk_clk_register_dividers(dev, adj_divs, ARRAY_SIZE(adj_divs), base, + &mt8167_apmixed_clk_lock, clk_data); + if (ret) + goto unregister_plls; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_dividers; + + return 0; + +unregister_dividers: + mtk_clk_unregister_dividers(adj_divs, ARRAY_SIZE(adj_divs), clk_data); +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static const struct of_device_id of_match_clk_mt8167_apmixed[] = { + { .compatible = "mediatek,mt8167-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167_apmixed); + +static struct platform_driver clk_mt8167_apmixed_drv = { + .probe = clk_mt8167_apmixed_probe, + .driver = { + .name = "clk-mt8167-apmixed", + .of_match_table = of_match_clk_mt8167_apmixed, + }, +}; +builtin_platform_driver(clk_mt8167_apmixed_drv) +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-aud.c b/drivers/clk/mediatek/clk-mt8167-aud.c index f6bea6e9e6a4..86125635c8a6 100644 --- a/drivers/clk/mediatek/clk-mt8167-aud.c +++ b/drivers/clk/mediatek/clk-mt8167-aud.c @@ -23,16 +23,11 @@ static const struct mtk_gate_regs aud_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_AUD(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &aud_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUD(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &aud_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -static const struct mtk_gate aud_clks[] __initconst = { + +static const struct mtk_gate aud_clks[] = { GATE_AUD(CLK_AUD_AFE, "aud_afe", "clk26m_ck", 2), GATE_AUD(CLK_AUD_I2S, "aud_i2s", "i2s_infra_bck", 6), GATE_AUD(CLK_AUD_22M, "aud_22m", "rg_aud_engen1", 8), @@ -48,19 +43,24 @@ static const struct mtk_gate aud_clks[] __initconst = { GATE_AUD(CLK_AUD_TML, "aud_tml", "aud_afe", 27), }; -static void __init mtk_audsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc aud_desc = { + .clks = aud_clks, + .num_clks = ARRAY_SIZE(aud_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK); +static const struct of_device_id of_match_clk_mt8167_audsys[] = { + { .compatible = "mediatek,mt8167-audsys", .data = &aud_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167_audsys); - mtk_clk_register_gates(NULL, node, aud_clks, ARRAY_SIZE(aud_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_audsys, "mediatek,mt8167-audsys", mtk_audsys_init); +static struct platform_driver clk_mt8167_audsys_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8167-audsys", + .of_match_table = of_match_clk_mt8167_audsys, + }, +}; +module_platform_driver(clk_mt8167_audsys_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-img.c b/drivers/clk/mediatek/clk-mt8167-img.c index 77db13b177fc..315b7f64bad6 100644 --- a/drivers/clk/mediatek/clk-mt8167-img.c +++ b/drivers/clk/mediatek/clk-mt8167-img.c @@ -23,16 +23,10 @@ static const struct mtk_gate_regs img_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_IMG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &img_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IMG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -static const struct mtk_gate img_clks[] __initconst = { +static const struct mtk_gate img_clks[] = { GATE_IMG(CLK_IMG_LARB1_SMI, "img_larb1_smi", "smi_mm", 0), GATE_IMG(CLK_IMG_CAM_SMI, "img_cam_smi", "smi_mm", 5), GATE_IMG(CLK_IMG_CAM_CAM, "img_cam_cam", "smi_mm", 6), @@ -41,20 +35,24 @@ static const struct mtk_gate img_clks[] __initconst = { GATE_IMG(CLK_IMG_VENC, "img_venc", "smi_mm", 9), }; -static void __init mtk_imgsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc img_desc = { + .clks = img_clks, + .num_clks = ARRAY_SIZE(img_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_IMG_NR_CLK); +static const struct of_device_id of_match_clk_mt8167_imgsys[] = { + { .compatible = "mediatek,mt8167-imgsys", .data = &img_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167_imgsys); - mtk_clk_register_gates(NULL, node, img_clks, ARRAY_SIZE(img_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt8167-imgsys", mtk_imgsys_init); +static struct platform_driver clk_mt8167_imgsys_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8167-imgsys", + .of_match_table = of_match_clk_mt8167_imgsys, + }, +}; +module_platform_driver(clk_mt8167_imgsys_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c index 3c23591b02f7..4851f5bf3a90 100644 --- a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c +++ b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c @@ -23,36 +23,34 @@ static const struct mtk_gate_regs mfg_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_MFG(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mfg_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MFG(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -static const struct mtk_gate mfg_clks[] __initconst = { +static const struct mtk_gate mfg_clks[] = { GATE_MFG(CLK_MFG_BAXI, "mfg_baxi", "ahb_infra_sel", 0), GATE_MFG(CLK_MFG_BMEM, "mfg_bmem", "gfmux_emi1x_sel", 1), GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_mm", 2), GATE_MFG(CLK_MFG_B26M, "mfg_b26m", "clk26m_ck", 3), }; -static void __init mtk_mfgcfg_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mfg_desc = { + .clks = mfg_clks, + .num_clks = ARRAY_SIZE(mfg_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MFG_NR_CLK); +static const struct of_device_id of_match_clk_mt8167_mfgcfg[] = { + { .compatible = "mediatek,mt8167-mfgcfg", .data = &mfg_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167_mfgcfg); - mtk_clk_register_gates(NULL, node, mfg_clks, ARRAY_SIZE(mfg_clks), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_mfgcfg, "mediatek,mt8167-mfgcfg", mtk_mfgcfg_init); +static struct platform_driver clk_mt8167_mfgcfg_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8167-mfgcfg", + .of_match_table = of_match_clk_mt8167_mfgcfg, + }, +}; +module_platform_driver(clk_mt8167_mfgcfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-mm.c b/drivers/clk/mediatek/clk-mt8167-mm.c index c0b44104c765..4e053c61315d 100644 --- a/drivers/clk/mediatek/clk-mt8167-mm.c +++ b/drivers/clk/mediatek/clk-mt8167-mm.c @@ -29,23 +29,11 @@ static const struct mtk_gate_regs mm1_cg_regs = { .sta_ofs = 0x110, }; -#define GATE_MM0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_MM1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mm_clks[] = { /* MM0 */ @@ -86,47 +74,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmtx_dig_cts", 21), }; -struct clk_mt8167_mm_driver_data { - const struct mtk_gate *gates_clk; - int gates_num; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), }; -static const struct clk_mt8167_mm_driver_data mt8167_mmsys_driver_data = { - .gates_clk = mm_clks, - .gates_num = ARRAY_SIZE(mm_clks), +static const struct platform_device_id clk_mt8167_mm_id_table[] = { + { .name = "clk-mt8167-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } }; +MODULE_DEVICE_TABLE(platform, clk_mt8167_mm_id_table); -static int clk_mt8167_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - const struct clk_mt8167_mm_driver_data *data; - struct clk_hw_onecell_data *clk_data; - int ret; - - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - if (!clk_data) - return -ENOMEM; - - data = &mt8167_mmsys_driver_data; - - ret = mtk_clk_register_gates(&pdev->dev, node, data->gates_clk, - data->gates_num, clk_data); - if (ret) - return ret; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - return ret; - - return 0; -} - -static struct platform_driver clk_mt8173_mm_drv = { +static struct platform_driver clk_mt8167_mm_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8167-mm", }, - .probe = clk_mt8167_mm_probe, + .id_table = clk_mt8167_mm_id_table, }; - -builtin_platform_driver(clk_mt8173_mm_drv); +module_platform_driver(clk_mt8167_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167-vdec.c b/drivers/clk/mediatek/clk-mt8167-vdec.c index 759e5791599f..76900f393d31 100644 --- a/drivers/clk/mediatek/clk-mt8167-vdec.c +++ b/drivers/clk/mediatek/clk-mt8167-vdec.c @@ -29,46 +29,37 @@ static const struct mtk_gate_regs vdec1_cg_regs = { .sta_ofs = 0x8, }; -#define GATE_VDEC0_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC0_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_VDEC1_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &vdec1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_VDEC1_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -static const struct mtk_gate vdec_clks[] __initconst = { +static const struct mtk_gate vdec_clks[] = { /* VDEC0 */ GATE_VDEC0_I(CLK_VDEC_CKEN, "vdec_cken", "rg_vdec", 0), /* VDEC1 */ GATE_VDEC1_I(CLK_VDEC_LARB1_CKEN, "vdec_larb1_cken", "smi_mm", 0), }; -static void __init mtk_vdecsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc vdec_desc = { + .clks = vdec_clks, + .num_clks = ARRAY_SIZE(vdec_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_VDEC_NR_CLK); +static const struct of_device_id of_match_clk_mt8167_vdec[] = { + { .compatible = "mediatek,mt8167-vdecsys", .data = &vdec_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167_vdec); - mtk_clk_register_gates(NULL, node, vdec_clks, ARRAY_SIZE(vdec_clks), - clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt8167-vdecsys", mtk_vdecsys_init); +static struct platform_driver clk_mt8167_vdec_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8167-vdecsys", + .of_match_table = of_match_clk_mt8167_vdec, + }, +}; +module_platform_driver(clk_mt8167_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8167.c b/drivers/clk/mediatek/clk-mt8167.c index 91669ebafaf9..b9041f79cbbd 100644 --- a/drivers/clk/mediatek/clk-mt8167.c +++ b/drivers/clk/mediatek/clk-mt8167.c @@ -11,16 +11,16 @@ #include #include #include +#include #include "clk-gate.h" #include "clk-mtk.h" -#include "clk-pll.h" #include static DEFINE_SPINLOCK(mt8167_clk_lock); -static const struct mtk_fixed_clk fixed_clks[] __initconst = { +static const struct mtk_fixed_clk fixed_clks[] = { FIXED_CLK(CLK_TOP_CLK_NULL, "clk_null", NULL, 0), FIXED_CLK(CLK_TOP_I2S_INFRA_BCK, "i2s_infra_bck", "clk_null", 26000000), FIXED_CLK(CLK_TOP_MEMPLL, "mempll", "clk26m", 800000000), @@ -29,7 +29,7 @@ static const struct mtk_fixed_clk fixed_clks[] __initconst = { FIXED_CLK(CLK_TOP_LVDSTX_CLKDIG_CTS, "lvdstx_dig_cts", "clk26m", 52500000), }; -static const struct mtk_fixed_factor top_divs[] __initconst = { +static const struct mtk_fixed_factor top_divs[] = { FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "mempll", 1, 1), FACTOR(CLK_TOP_MAINPLL_D2, "mainpll_d2", "mainpll", 1, 2), FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4), @@ -85,22 +85,22 @@ static const struct mtk_fixed_factor top_divs[] __initconst = { FACTOR(CLK_TOP_ETH_D2, "eth_d2_ck", "eth_sel", 1, 2), }; -static const char * const uart0_parents[] __initconst = { +static const char * const uart0_parents[] = { "clk26m_ck", "univpll_d24" }; -static const char * const gfmux_emi1x_parents[] __initconst = { +static const char * const gfmux_emi1x_parents[] = { "clk26m_ck", "dmpll_ck" }; -static const char * const emi_ddrphy_parents[] __initconst = { +static const char * const emi_ddrphy_parents[] = { "gfmux_emi1x_sel", "gfmux_emi1x_sel" }; -static const char * const ahb_infra_parents[] __initconst = { +static const char * const ahb_infra_parents[] = { "clk_null", "clk26m_ck", "mainpll_d11", @@ -116,7 +116,7 @@ static const char * const ahb_infra_parents[] __initconst = { "mainpll_d10" }; -static const char * const csw_mux_mfg_parents[] __initconst = { +static const char * const csw_mux_mfg_parents[] = { "clk_null", "clk_null", "univpll_d3", @@ -127,7 +127,7 @@ static const char * const csw_mux_mfg_parents[] __initconst = { "mmpll380m" }; -static const char * const msdc0_parents[] __initconst = { +static const char * const msdc0_parents[] = { "clk26m_ck", "univpll_d6", "mainpll_d8", @@ -138,7 +138,7 @@ static const char * const msdc0_parents[] __initconst = { "mmpll_d2" }; -static const char * const camtg_mm_parents[] __initconst = { +static const char * const camtg_mm_parents[] = { "clk_null", "clk26m_ck", "usb_phy48m_ck", @@ -146,17 +146,17 @@ static const char * const camtg_mm_parents[] __initconst = { "univpll_d6" }; -static const char * const pwm_mm_parents[] __initconst = { +static const char * const pwm_mm_parents[] = { "clk26m_ck", "univpll_d12" }; -static const char * const uart1_parents[] __initconst = { +static const char * const uart1_parents[] = { "clk26m_ck", "univpll_d24" }; -static const char * const msdc1_parents[] __initconst = { +static const char * const msdc1_parents[] = { "clk26m_ck", "univpll_d6", "mainpll_d8", @@ -167,24 +167,24 @@ static const char * const msdc1_parents[] __initconst = { "mmpll_d2" }; -static const char * const spm_52m_parents[] __initconst = { +static const char * const spm_52m_parents[] = { "clk26m_ck", "univpll_d24" }; -static const char * const pmicspi_parents[] __initconst = { +static const char * const pmicspi_parents[] = { "univpll_d20", "usb_phy48m_ck", "univpll_d16", "clk26m_ck" }; -static const char * const qaxi_aud26m_parents[] __initconst = { +static const char * const qaxi_aud26m_parents[] = { "clk26m_ck", "ahb_infra_sel" }; -static const char * const aud_intbus_parents[] __initconst = { +static const char * const aud_intbus_parents[] = { "clk_null", "clk26m_ck", "mainpll_d22", @@ -192,7 +192,7 @@ static const char * const aud_intbus_parents[] __initconst = { "mainpll_d11" }; -static const char * const nfi2x_pad_parents[] __initconst = { +static const char * const nfi2x_pad_parents[] = { "clk_null", "clk_null", "clk_null", @@ -280,12 +280,12 @@ static const char * const nfi2x_pad_parents[] __initconst = { "mainpll_d5" }; -static const char * const nfi1x_pad_parents[] __initconst = { +static const char * const nfi1x_pad_parents[] = { "ahb_infra_sel", "nfi1x_ck" }; -static const char * const mfg_mm_parents[] __initconst = { +static const char * const mfg_mm_parents[] = { "clk_null", "clk_null", "clk_null", @@ -325,12 +325,12 @@ static const char * const mfg_mm_parents[] __initconst = { "mainpll_d14" }; -static const char * const ddrphycfg_parents[] __initconst = { +static const char * const ddrphycfg_parents[] = { "clk26m_ck", "mainpll_d16" }; -static const char * const smi_mm_parents[] __initconst = { +static const char * const smi_mm_parents[] = { "clk26m_ck", "clk_null", "clk_null", @@ -346,7 +346,7 @@ static const char * const smi_mm_parents[] __initconst = { "mainpll_d14" }; -static const char * const usb_78m_parents[] __initconst = { +static const char * const usb_78m_parents[] = { "clk_null", "clk26m_ck", "univpll_d16", @@ -354,7 +354,7 @@ static const char * const usb_78m_parents[] __initconst = { "mainpll_d20" }; -static const char * const scam_mm_parents[] __initconst = { +static const char * const scam_mm_parents[] = { "clk_null", "clk26m_ck", "mainpll_d14", @@ -362,7 +362,7 @@ static const char * const scam_mm_parents[] __initconst = { "mainpll_d12" }; -static const char * const spinor_parents[] __initconst = { +static const char * const spinor_parents[] = { "clk26m_d2", "clk26m_ck", "mainpll_d40", @@ -373,7 +373,7 @@ static const char * const spinor_parents[] __initconst = { "univpll_d12" }; -static const char * const msdc2_parents[] __initconst = { +static const char * const msdc2_parents[] = { "clk26m_ck", "univpll_d6", "mainpll_d8", @@ -384,7 +384,7 @@ static const char * const msdc2_parents[] __initconst = { "mmpll_d2" }; -static const char * const eth_parents[] __initconst = { +static const char * const eth_parents[] = { "clk26m_ck", "mainpll_d40", "univpll_d24", @@ -392,7 +392,7 @@ static const char * const eth_parents[] __initconst = { "mainpll_d20" }; -static const char * const vdec_mm_parents[] __initconst = { +static const char * const vdec_mm_parents[] = { "clk26m_ck", "univpll_d4", "mainpll_d4", @@ -401,7 +401,7 @@ static const char * const vdec_mm_parents[] __initconst = { "mainpll_d6" }; -static const char * const dpi0_mm_parents[] __initconst = { +static const char * const dpi0_mm_parents[] = { "clk26m_ck", "lvdspll_ck", "lvdspll_d2", @@ -409,7 +409,7 @@ static const char * const dpi0_mm_parents[] __initconst = { "lvdspll_d8" }; -static const char * const dpi1_mm_parents[] __initconst = { +static const char * const dpi1_mm_parents[] = { "clk26m_ck", "tvdpll_d2", "tvdpll_d4", @@ -417,85 +417,85 @@ static const char * const dpi1_mm_parents[] __initconst = { "tvdpll_d16" }; -static const char * const axi_mfg_in_parents[] __initconst = { +static const char * const axi_mfg_in_parents[] = { "clk26m_ck", "mainpll_d11", "univpll_d24", "mmpll380m" }; -static const char * const slow_mfg_parents[] __initconst = { +static const char * const slow_mfg_parents[] = { "clk26m_ck", "univpll_d12", "univpll_d24" }; -static const char * const aud1_parents[] __initconst = { +static const char * const aud1_parents[] = { "clk26m_ck", "apll1_ck" }; -static const char * const aud2_parents[] __initconst = { +static const char * const aud2_parents[] = { "clk26m_ck", "apll2_ck" }; -static const char * const aud_engen1_parents[] __initconst = { +static const char * const aud_engen1_parents[] = { "clk26m_ck", "rg_apll1_d2_en", "rg_apll1_d4_en", "rg_apll1_d8_en" }; -static const char * const aud_engen2_parents[] __initconst = { +static const char * const aud_engen2_parents[] = { "clk26m_ck", "rg_apll2_d2_en", "rg_apll2_d4_en", "rg_apll2_d8_en" }; -static const char * const i2c_parents[] __initconst = { +static const char * const i2c_parents[] = { "clk26m_ck", "univpll_d20", "univpll_d16", "univpll_d12" }; -static const char * const aud_i2s0_m_parents[] __initconst = { +static const char * const aud_i2s0_m_parents[] = { "rg_aud1", "rg_aud2" }; -static const char * const pwm_parents[] __initconst = { +static const char * const pwm_parents[] = { "clk26m_ck", "univpll_d12" }; -static const char * const spi_parents[] __initconst = { +static const char * const spi_parents[] = { "clk26m_ck", "univpll_d12", "univpll_d8", "univpll_d6" }; -static const char * const aud_spdifin_parents[] __initconst = { +static const char * const aud_spdifin_parents[] = { "clk26m_ck", "univpll_d2" }; -static const char * const uart2_parents[] __initconst = { +static const char * const uart2_parents[] = { "clk26m_ck", "univpll_d24" }; -static const char * const bsi_parents[] __initconst = { +static const char * const bsi_parents[] = { "clk26m_ck", "mainpll_d10", "mainpll_d12", "mainpll_d20" }; -static const char * const dbg_atclk_parents[] __initconst = { +static const char * const dbg_atclk_parents[] = { "clk_null", "clk26m_ck", "mainpll_d5", @@ -503,7 +503,7 @@ static const char * const dbg_atclk_parents[] __initconst = { "univpll_d5" }; -static const char * const csw_nfiecc_parents[] __initconst = { +static const char * const csw_nfiecc_parents[] = { "clk_null", "mainpll_d7", "mainpll_d6", @@ -511,7 +511,7 @@ static const char * const csw_nfiecc_parents[] __initconst = { "mainpll_d5" }; -static const char * const nfiecc_parents[] __initconst = { +static const char * const nfiecc_parents[] = { "clk_null", "nfi2x_pad_sel", "mainpll_d4", @@ -625,24 +625,24 @@ static struct mtk_composite top_muxes[] __initdata = { 0x07c, 13, 3), }; -static const char * const ifr_mux1_parents[] __initconst = { +static const char * const ifr_mux1_parents[] = { "clk26m_ck", "armpll", "univpll", "mainpll_d2" }; -static const char * const ifr_eth_25m_parents[] __initconst = { +static const char * const ifr_eth_25m_parents[] = { "eth_d2_ck", "rg_eth" }; -static const char * const ifr_i2c0_parents[] __initconst = { +static const char * const ifr_i2c0_parents[] = { "ahb_infra_d2", "rg_i2c" }; -static const struct mtk_composite ifr_muxes[] __initconst = { +static const struct mtk_composite ifr_muxes[] = { MUX(CLK_IFR_MUX1_SEL, "ifr_mux1_sel", ifr_mux1_parents, 0x000, 2, 2), MUX(CLK_IFR_ETH_25M_SEL, "ifr_eth_25m_sel", ifr_eth_25m_parents, 0x080, @@ -685,21 +685,6 @@ static const struct mtk_clk_divider top_adj_divs[] = { 0x0078, 0, 8), }; -#define DIV_ADJ_FLAG(_id, _name, _parent, _reg, _shift, _width, _flag) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .div_reg = _reg, \ - .div_shift = _shift, \ - .div_width = _width, \ - .clk_divider_flags = _flag, \ -} - -static const struct mtk_clk_divider apmixed_adj_divs[] = { - DIV_ADJ_FLAG(CLK_APMIXED_HDMI_REF, "hdmi_ref", "tvdpll", - 0x1c4, 24, 3, CLK_DIVIDER_POWER_OF_TWO), -}; - static const struct mtk_gate_regs top0_cg_regs = { .set_ofs = 0x50, .clr_ofs = 0x80, @@ -736,79 +721,31 @@ static const struct mtk_gate_regs top5_cg_regs = { .sta_ofs = 0x44, }; -#define GATE_TOP0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP0_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_TOP0_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_TOP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP2_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_TOP2_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_TOP3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top3_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP4_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top4_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_TOP4_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top4_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_TOP5(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top5_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP5(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -static const struct mtk_gate top_clks[] __initconst = { +static const struct mtk_gate top_clks[] = { /* TOP0 */ GATE_TOP0(CLK_TOP_PWM_MM, "pwm_mm", "pwm_mm_sel", 0), GATE_TOP0(CLK_TOP_CAM_MM, "cam_mm", "camtg_mm_sel", 1), @@ -921,145 +858,40 @@ static const struct mtk_gate top_clks[] __initconst = { GATE_TOP5(CLK_TOP_APLL12_DIV6, "apll12_div6", "apll12_ck_div6", 8), }; -static void __init mtk_topckgen_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - void __iomem *base; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(MT8167_CLK_TOP_NR_CLK); - - mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), - clk_data); - mtk_clk_register_gates(NULL, node, top_clks, ARRAY_SIZE(top_clks), clk_data); - - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); - mtk_clk_register_composites(NULL, top_muxes, - ARRAY_SIZE(top_muxes), base, - &mt8167_clk_lock, clk_data); - mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), - base, &mt8167_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8167-topckgen", mtk_topckgen_init); - -static void __init mtk_infracfg_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - void __iomem *base; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); - - mtk_clk_register_composites(NULL, ifr_muxes, - ARRAY_SIZE(ifr_muxes), base, - &mt8167_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt8167-infracfg", mtk_infracfg_init); - -#define MT8167_PLL_FMAX (2500UL * MHZ) - -#define CON0_MT8167_RST_BAR BIT(27) - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift, _div_table) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = CON0_MT8167_RST_BAR, \ - .fmax = MT8167_PLL_FMAX, \ - .pcwbits = _pcwbits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .div_table = _div_table, \ - } - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift) \ - PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ - NULL) - -static const struct mtk_pll_div_table mmpll_div_table[] = { - { .div = 0, .freq = MT8167_PLL_FMAX }, - { .div = 1, .freq = 1000000000 }, - { .div = 2, .freq = 604500000 }, - { .div = 3, .freq = 253500000 }, - { .div = 4, .freq = 126750000 }, - { } /* sentinel */ +static const struct mtk_clk_desc topck_desc = { + .clks = top_clks, + .num_clks = ARRAY_SIZE(top_clks), + .fixed_clks = fixed_clks, + .num_fixed_clks = ARRAY_SIZE(fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .composite_clks = top_muxes, + .num_composite_clks = ARRAY_SIZE(top_muxes), + .divider_clks = top_adj_divs, + .num_divider_clks = ARRAY_SIZE(top_adj_divs), + .clk_lock = &mt8167_clk_lock, }; -static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0100, 0x0110, 0, 0, - 21, 0x0104, 24, 0, 0x0104, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0120, 0x0130, 0, - HAVE_RST_BAR, 21, 0x0124, 24, 0, 0x0124, 0), - PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0140, 0x0150, 0x30000000, - HAVE_RST_BAR, 7, 0x0144, 24, 0, 0x0144, 0), - PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0160, 0x0170, 0, 0, - 21, 0x0164, 24, 0, 0x0164, 0, mmpll_div_table), - PLL(CLK_APMIXED_APLL1, "apll1", 0x0180, 0x0190, 0, 0, - 31, 0x0180, 1, 0x0194, 0x0184, 0), - PLL(CLK_APMIXED_APLL2, "apll2", 0x01A0, 0x01B0, 0, 0, - 31, 0x01A0, 1, 0x01B4, 0x01A4, 0), - PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x01C0, 0x01D0, 0, 0, - 21, 0x01C4, 24, 0, 0x01C4, 0), - PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x01E0, 0x01F0, 0, 0, - 21, 0x01E4, 24, 0, 0x01E4, 0), +static const struct mtk_clk_desc infra_desc = { + .composite_clks = ifr_muxes, + .num_composite_clks = ARRAY_SIZE(ifr_muxes), + .clk_lock = &mt8167_clk_lock, }; -static void __init mtk_apmixedsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - void __iomem *base; - int r; +static const struct of_device_id of_match_clk_mt8167[] = { + { .compatible = "mediatek,mt8167-topckgen", .data = &topck_desc }, + { .compatible = "mediatek,mt8167-infracfg", .data = &infra_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8167); - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(MT8167_CLK_APMIXED_NR_CLK); - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - mtk_clk_register_dividers(apmixed_adj_divs, ARRAY_SIZE(apmixed_adj_divs), - base, &mt8167_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8167-apmixedsys", - mtk_apmixedsys_init); +static struct platform_driver clk_mt8167_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8167", + .of_match_table = of_match_clk_mt8167, + }, +}; +module_platform_driver(clk_mt8167_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c index a56c5845d07a..8c2aa8b0f39e 100644 --- a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c @@ -9,8 +9,10 @@ #include #include #include +#include "clk-fhctl.h" #include "clk-mtk.h" #include "clk-pll.h" +#include "clk-pllfh.h" #define REGOFF_REF2USB 0x8 #define REGOFF_HDMI_REF 0x40 @@ -77,13 +79,67 @@ static const struct mtk_pll_data plls[] = { PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0), }; +enum fh_pll_id { + FH_ARMCA7PLL, + FH_ARMCA15PLL, + FH_MAINPLL, + FH_MPLL, + FH_MSDCPLL, + FH_MMPLL, + FH_VENCPLL, + FH_TVDPLL, + FH_VCODECPLL, + FH_LVDSPLL, + FH_MSDC2PLL, + FH_NR_FH, +}; + +#define FH(_pllid, _fhid, _offset) { \ + .data = { \ + .pll_id = _pllid, \ + .fh_id = _fhid, \ + .fh_ver = FHCTL_PLLFH_V1, \ + .fhx_offset = _offset, \ + .dds_mask = GENMASK(21, 0), \ + .slope0_value = 0x6003c97, \ + .slope1_value = 0x6003c97, \ + .sfstrx_en = BIT(2), \ + .frddsx_en = BIT(1), \ + .fhctlx_en = BIT(0), \ + .tgl_org = BIT(31), \ + .dvfs_tri = BIT(31), \ + .pcwchg = BIT(31), \ + .dt_val = 0x0, \ + .df_val = 0x9, \ + .updnlmt_shft = 16, \ + .msk_frddsx_dys = GENMASK(23, 20), \ + .msk_frddsx_dts = GENMASK(19, 16), \ + }, \ + } + +static struct mtk_pllfh_data pllfhs[] = { + FH(CLK_APMIXED_ARMCA7PLL, FH_ARMCA7PLL, 0x38), + FH(CLK_APMIXED_ARMCA15PLL, FH_ARMCA15PLL, 0x4c), + FH(CLK_APMIXED_MAINPLL, FH_MAINPLL, 0x60), + FH(CLK_APMIXED_MPLL, FH_MPLL, 0x74), + FH(CLK_APMIXED_MSDCPLL, FH_MSDCPLL, 0x88), + FH(CLK_APMIXED_MMPLL, FH_MMPLL, 0x9c), + FH(CLK_APMIXED_VENCPLL, FH_VENCPLL, 0xb0), + FH(CLK_APMIXED_TVDPLL, FH_TVDPLL, 0xc4), + FH(CLK_APMIXED_VCODECPLL, FH_VCODECPLL, 0xd8), + FH(CLK_APMIXED_LVDSPLL, FH_LVDSPLL, 0xec), + FH(CLK_APMIXED_MSDCPLL2, FH_MSDC2PLL, 0x100), +}; + static const struct of_device_id of_match_clk_mt8173_apmixed[] = { { .compatible = "mediatek,mt8173-apmixedsys" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_apmixed); static int clk_mt8173_apmixed_probe(struct platform_device *pdev) { + const u8 *fhctl_node = "mediatek,mt8173-fhctl"; struct device_node *node = pdev->dev.of_node; struct clk_hw_onecell_data *clk_data; void __iomem *base; @@ -98,7 +154,9 @@ static int clk_mt8173_apmixed_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(clk_data)) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); + r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_clk_data; @@ -124,7 +182,8 @@ static int clk_mt8173_apmixed_probe(struct platform_device *pdev) unregister_ref2usb: mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]); unregister_plls: - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); free_clk_data: mtk_free_clk_data(clk_data); return r; @@ -137,7 +196,8 @@ static int clk_mt8173_apmixed_remove(struct platform_device *pdev) of_clk_del_provider(node); mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]); - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); mtk_free_clk_data(clk_data); return 0; diff --git a/drivers/clk/mediatek/clk-mt8173-img.c b/drivers/clk/mediatek/clk-mt8173-img.c index 7b50ffb7a8a5..6db2b9ab2bc9 100644 --- a/drivers/clk/mediatek/clk-mt8173-img.c +++ b/drivers/clk/mediatek/clk-mt8173-img.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt8173_imgsys[] = { { .compatible = "mediatek,mt8173-imgsys", .data = &img_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_imgsys); static struct platform_driver clk_mt8173_vdecsys_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt8173-infracfg.c b/drivers/clk/mediatek/clk-mt8173-infracfg.c index 729b3c408c7b..4ed5043076ec 100644 --- a/drivers/clk/mediatek/clk-mt8173-infracfg.c +++ b/drivers/clk/mediatek/clk-mt8173-infracfg.c @@ -74,6 +74,7 @@ static const struct of_device_id of_match_clk_mt8173_infracfg[] = { { .compatible = "mediatek,mt8173-infracfg" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_infracfg); static void clk_mt8173_infra_init_early(struct device_node *node) { diff --git a/drivers/clk/mediatek/clk-mt8173-mm.c b/drivers/clk/mediatek/clk-mt8173-mm.c index 315430ad1581..18e466dbf610 100644 --- a/drivers/clk/mediatek/clk-mt8173-mm.c +++ b/drivers/clk/mediatek/clk-mt8173-mm.c @@ -25,25 +25,14 @@ static const struct mtk_gate_regs mm1_cg_regs = { .sta_ofs = 0x0110, }; -#define GATE_MM0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_MM1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &mm1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_MM1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &mm1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate mt8173_mm_clks[] = { + GATE_DUMMY(CLK_DUMMY, "mm_dummy"), /* MM0 */ GATE_MM0(CLK_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 0), GATE_MM0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), @@ -100,65 +89,26 @@ static const struct mtk_gate mt8173_mm_clks[] = { GATE_MM1(CLK_MM_HDMI_HDCP24M, "mm_hdmi_hdcp24m", "hdcp_24m_sel", 20), }; -struct clk_mt8173_mm_driver_data { - const struct mtk_gate *gates_clk; - int gates_num; +static const struct mtk_clk_desc mm_desc = { + .clks = mt8173_mm_clks, + .num_clks = ARRAY_SIZE(mt8173_mm_clks), }; -static const struct clk_mt8173_mm_driver_data mt8173_mmsys_driver_data = { - .gates_clk = mt8173_mm_clks, - .gates_num = ARRAY_SIZE(mt8173_mm_clks), +static const struct platform_device_id clk_mt8173_mm_id_table[] = { + { .name = "clk-mt8173-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } }; - -static int clk_mt8173_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - const struct clk_mt8173_mm_driver_data *data; - struct clk_hw_onecell_data *clk_data; - int ret; - - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - if (!clk_data) - return -ENOMEM; - - data = &mt8173_mmsys_driver_data; - - ret = mtk_clk_register_gates(&pdev->dev, node, data->gates_clk, - data->gates_num, clk_data); - if (ret) - return ret; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - return ret; - - return 0; -} - -static int clk_mt8173_mm_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - const struct clk_mt8173_mm_driver_data *data = &mt8173_mmsys_driver_data; - - of_clk_del_provider(node); - mtk_clk_unregister_gates(data->gates_clk, data->gates_num, clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +MODULE_DEVICE_TABLE(platform, clk_mt8173_mm_id_table); static struct platform_driver clk_mt8173_mm_drv = { .driver = { .name = "clk-mt8173-mm", }, - .probe = clk_mt8173_mm_probe, - .remove = clk_mt8173_mm_remove, + .id_table = clk_mt8173_mm_id_table, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, }; - -builtin_platform_driver(clk_mt8173_mm_drv); +module_platform_driver(clk_mt8173_mm_drv); MODULE_DESCRIPTION("MediaTek MT8173 MultiMedia clocks driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8173-pericfg.c b/drivers/clk/mediatek/clk-mt8173-pericfg.c index e87294b72c2c..bebda74d0f43 100644 --- a/drivers/clk/mediatek/clk-mt8173-pericfg.c +++ b/drivers/clk/mediatek/clk-mt8173-pericfg.c @@ -107,6 +107,7 @@ static const struct of_device_id of_match_clk_mt8173_pericfg[] = { { .compatible = "mediatek,mt8173-pericfg", .data = &peri_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_pericfg); static struct platform_driver clk_mt8173_pericfg_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt8173-topckgen.c b/drivers/clk/mediatek/clk-mt8173-topckgen.c index 257961528fe2..baa8fd6cb312 100644 --- a/drivers/clk/mediatek/clk-mt8173-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8173-topckgen.c @@ -638,6 +638,7 @@ static const struct of_device_id of_match_clk_mt8173_topckgen[] = { { .compatible = "mediatek,mt8173-topckgen", .data = &topck_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_topckgen); static struct platform_driver clk_mt8173_topckgen_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt8173-vdecsys.c b/drivers/clk/mediatek/clk-mt8173-vdecsys.c index 5105b8e0969d..625ca0b09cc2 100644 --- a/drivers/clk/mediatek/clk-mt8173-vdecsys.c +++ b/drivers/clk/mediatek/clk-mt8173-vdecsys.c @@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8173_vdecsys[] = { { .compatible = "mediatek,mt8173-vdecsys", .data = &vdec_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_vdecsys); static struct platform_driver clk_mt8173_vdecsys_drv = { .probe = mtk_clk_simple_probe, diff --git a/drivers/clk/mediatek/clk-mt8173-vencsys.c b/drivers/clk/mediatek/clk-mt8173-vencsys.c index ff4f1cb735de..87755dd1a337 100644 --- a/drivers/clk/mediatek/clk-mt8173-vencsys.c +++ b/drivers/clk/mediatek/clk-mt8173-vencsys.c @@ -49,6 +49,7 @@ static const struct of_device_id of_match_clk_mt8173_vencsys[] = { { .compatible = "mediatek,mt8173-vencltsys", .data = &venc_lt_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_vencsys); static struct platform_driver clk_mt8173_vencsys_drv = { .driver = { diff --git a/drivers/clk/mediatek/clk-mt8183-apmixedsys.c b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c new file mode 100644 index 000000000000..2b261c0e2b61 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8183-apmixedsys.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Weiyi Lu + * Copyright (c) 2023 Collabora, Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x20, + .clr_ofs = 0x20, + .sta_ofs = 0x20, +}; + +#define GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &apmixed_cg_regs, \ + _shift, &mtk_clk_gate_ops_no_setclr_inv, _flags) + +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, 0) + +/* + * CRITICAL CLOCK: + * apmixed_appll26m is the toppest clock gate of all PLLs. + */ +static const struct mtk_gate apmixed_clks[] = { + /* AUDIO0 */ + GATE_APMIXED(CLK_APMIXED_SSUSB_26M, "apmixed_ssusb26m", "f_f26m_ck", 4), + GATE_APMIXED_FLAGS(CLK_APMIXED_APPLL_26M, "apmixed_appll26m", + "f_f26m_ck", 5, CLK_IS_CRITICAL), + GATE_APMIXED(CLK_APMIXED_MIPIC0_26M, "apmixed_mipic026m", "f_f26m_ck", 6), + GATE_APMIXED(CLK_APMIXED_MDPLLGP_26M, "apmixed_mdpll26m", "f_f26m_ck", 7), + GATE_APMIXED(CLK_APMIXED_MMSYS_26M, "apmixed_mmsys26m", "f_f26m_ck", 8), + GATE_APMIXED(CLK_APMIXED_UFS_26M, "apmixed_ufs26m", "f_f26m_ck", 9), + GATE_APMIXED(CLK_APMIXED_MIPIC1_26M, "apmixed_mipic126m", "f_f26m_ck", 11), + GATE_APMIXED(CLK_APMIXED_MEMPLL_26M, "apmixed_mempll26m", "f_f26m_ck", 13), + GATE_APMIXED(CLK_APMIXED_CLKSQ_LVPLL_26M, "apmixed_lvpll26m", "f_f26m_ck", 14), + GATE_APMIXED(CLK_APMIXED_MIPID0_26M, "apmixed_mipid026m", "f_f26m_ck", 16), + GATE_APMIXED(CLK_APMIXED_MIPID1_26M, "apmixed_mipid126m", "f_f26m_ck", 17), +}; + +#define MT8183_PLL_FMAX (3800UL * MHZ) +#define MT8183_PLL_FMIN (1500UL * MHZ) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg, _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8183_PLL_FMAX, \ + .fmin = MT8183_PLL_FMIN, \ + .pcwbits = _pcwbits, \ + .pcwibits = _pcwibits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg, NULL) + +static const struct mtk_pll_div_table armpll_div_table[] = { + { .div = 0, .freq = MT8183_PLL_FMAX }, + { .div = 1, .freq = 1500 * MHZ }, + { .div = 2, .freq = 750 * MHZ }, + { .div = 3, .freq = 375 * MHZ }, + { .div = 4, .freq = 187500000 }, + { /* sentinel */ } +}; + +static const struct mtk_pll_div_table mfgpll_div_table[] = { + { .div = 0, .freq = MT8183_PLL_FMAX }, + { .div = 1, .freq = 1600 * MHZ }, + { .div = 2, .freq = 800 * MHZ }, + { .div = 3, .freq = 400 * MHZ }, + { .div = 4, .freq = 200 * MHZ }, + { /* sentinel */ } +}; + +static const struct mtk_pll_data plls[] = { + PLL_B(CLK_APMIXED_ARMPLL_LL, "armpll_ll", 0x0200, 0x020C, 0, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0204, 24, 0x0, 0x0, 0, + 0x0204, 0, 0, armpll_div_table), + PLL_B(CLK_APMIXED_ARMPLL_L, "armpll_l", 0x0210, 0x021C, 0, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0214, 24, 0x0, 0x0, 0, + 0x0214, 0, 0, armpll_div_table), + PLL(CLK_APMIXED_CCIPLL, "ccipll", 0x0290, 0x029C, 0, + HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0294, 24, 0x0, 0x0, 0, + 0x0294, 0, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0220, 0x022C, 0, + HAVE_RST_BAR, BIT(24), 22, 8, 0x0224, 24, 0x0, 0x0, 0, + 0x0224, 0, 0), + PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0230, 0x023C, 0, + HAVE_RST_BAR, BIT(24), 22, 8, 0x0234, 24, 0x0, 0x0, 0, + 0x0234, 0, 0), + PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0240, 0x024C, 0, + 0, 0, 22, 8, 0x0244, 24, 0x0, 0x0, 0, 0x0244, 0, 0, + mfgpll_div_table), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0250, 0x025C, 0, + 0, 0, 22, 8, 0x0254, 24, 0x0, 0x0, 0, 0x0254, 0, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0260, 0x026C, 0, + 0, 0, 22, 8, 0x0264, 24, 0x0, 0x0, 0, 0x0264, 0, 0), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0270, 0x027C, 0, + HAVE_RST_BAR, BIT(23), 22, 8, 0x0274, 24, 0x0, 0x0, 0, + 0x0274, 0, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x02A0, 0x02B0, 0, + 0, 0, 32, 8, 0x02A0, 1, 0x02A8, 0x0014, 0, 0x02A4, 0, 0x02A0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x02b4, 0x02c4, 0, + 0, 0, 32, 8, 0x02B4, 1, 0x02BC, 0x0014, 1, 0x02B8, 0, 0x02B4), +}; + +static int clk_mt8183_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(dev, CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, + ARRAY_SIZE(apmixed_clks), clk_data); + if (ret) + goto unregister_plls; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_gates; + + return 0; + +unregister_gates: + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static const struct of_device_id of_match_clk_mt8183_apmixed[] = { + { .compatible = "mediatek,mt8183-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_apmixed); + +static struct platform_driver clk_mt8183_apmixed_drv = { + .probe = clk_mt8183_apmixed_probe, + .driver = { + .name = "clk-mt8183-apmixed", + .of_match_table = of_match_clk_mt8183_apmixed, + }, +}; +builtin_platform_driver(clk_mt8183_apmixed_drv) +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-audio.c b/drivers/clk/mediatek/clk-mt8183-audio.c index 3f1630290b93..9938c6466e76 100644 --- a/drivers/clk/mediatek/clk-mt8183-audio.c +++ b/drivers/clk/mediatek/clk-mt8183-audio.c @@ -97,6 +97,7 @@ static const struct of_device_id of_match_clk_mt8183_audio[] = { { .compatible = "mediatek,mt8183-audiosys", .data = &audio_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_audio); static struct platform_driver clk_mt8183_audio_drv = { .probe = clk_mt8183_audio_probe, @@ -106,5 +107,5 @@ static struct platform_driver clk_mt8183_audio_drv = { .of_match_table = of_match_clk_mt8183_audio, }, }; - -builtin_platform_driver(clk_mt8183_audio_drv); +module_platform_driver(clk_mt8183_audio_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-cam.c b/drivers/clk/mediatek/clk-mt8183-cam.c index 6907b1a6a824..c0719624004f 100644 --- a/drivers/clk/mediatek/clk-mt8183-cam.c +++ b/drivers/clk/mediatek/clk-mt8183-cam.c @@ -47,6 +47,7 @@ static const struct of_device_id of_match_clk_mt8183_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_cam); static struct platform_driver clk_mt8183_cam_drv = { .probe = mtk_clk_simple_probe, @@ -56,5 +57,5 @@ static struct platform_driver clk_mt8183_cam_drv = { .of_match_table = of_match_clk_mt8183_cam, }, }; - -builtin_platform_driver(clk_mt8183_cam_drv); +module_platform_driver(clk_mt8183_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-img.c b/drivers/clk/mediatek/clk-mt8183-img.c index 8d884425d79f..55fc80615724 100644 --- a/drivers/clk/mediatek/clk-mt8183-img.c +++ b/drivers/clk/mediatek/clk-mt8183-img.c @@ -47,6 +47,7 @@ static const struct of_device_id of_match_clk_mt8183_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_img); static struct platform_driver clk_mt8183_img_drv = { .probe = mtk_clk_simple_probe, @@ -56,5 +57,5 @@ static struct platform_driver clk_mt8183_img_drv = { .of_match_table = of_match_clk_mt8183_img, }, }; - -builtin_platform_driver(clk_mt8183_img_drv); +module_platform_driver(clk_mt8183_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu0.c b/drivers/clk/mediatek/clk-mt8183-ipu0.c index 953a8a33d048..59255eab6fe2 100644 --- a/drivers/clk/mediatek/clk-mt8183-ipu0.c +++ b/drivers/clk/mediatek/clk-mt8183-ipu0.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt8183_ipu_core0[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_ipu_core0); static struct platform_driver clk_mt8183_ipu_core0_drv = { .probe = mtk_clk_simple_probe, @@ -49,5 +50,5 @@ static struct platform_driver clk_mt8183_ipu_core0_drv = { .of_match_table = of_match_clk_mt8183_ipu_core0, }, }; - -builtin_platform_driver(clk_mt8183_ipu_core0_drv); +module_platform_driver(clk_mt8183_ipu_core0_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu1.c b/drivers/clk/mediatek/clk-mt8183-ipu1.c index 221d12265974..c4baa052c809 100644 --- a/drivers/clk/mediatek/clk-mt8183-ipu1.c +++ b/drivers/clk/mediatek/clk-mt8183-ipu1.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt8183_ipu_core1[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_ipu_core1); static struct platform_driver clk_mt8183_ipu_core1_drv = { .probe = mtk_clk_simple_probe, @@ -49,5 +50,5 @@ static struct platform_driver clk_mt8183_ipu_core1_drv = { .of_match_table = of_match_clk_mt8183_ipu_core1, }, }; - -builtin_platform_driver(clk_mt8183_ipu_core1_drv); +module_platform_driver(clk_mt8183_ipu_core1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu_adl.c b/drivers/clk/mediatek/clk-mt8183-ipu_adl.c index 8c4fd96df821..74866e9c50d7 100644 --- a/drivers/clk/mediatek/clk-mt8183-ipu_adl.c +++ b/drivers/clk/mediatek/clk-mt8183-ipu_adl.c @@ -38,6 +38,7 @@ static const struct of_device_id of_match_clk_mt8183_ipu_adl[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_ipu_adl); static struct platform_driver clk_mt8183_ipu_adl_drv = { .probe = mtk_clk_simple_probe, @@ -47,5 +48,5 @@ static struct platform_driver clk_mt8183_ipu_adl_drv = { .of_match_table = of_match_clk_mt8183_ipu_adl, }, }; - -builtin_platform_driver(clk_mt8183_ipu_adl_drv); +module_platform_driver(clk_mt8183_ipu_adl_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-ipu_conn.c b/drivers/clk/mediatek/clk-mt8183-ipu_conn.c index 14a4c3ff82a1..bd7303105357 100644 --- a/drivers/clk/mediatek/clk-mt8183-ipu_conn.c +++ b/drivers/clk/mediatek/clk-mt8183-ipu_conn.c @@ -107,6 +107,7 @@ static const struct of_device_id of_match_clk_mt8183_ipu_conn[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_ipu_conn); static struct platform_driver clk_mt8183_ipu_conn_drv = { .probe = mtk_clk_simple_probe, @@ -116,5 +117,5 @@ static struct platform_driver clk_mt8183_ipu_conn_drv = { .of_match_table = of_match_clk_mt8183_ipu_conn, }, }; - -builtin_platform_driver(clk_mt8183_ipu_conn_drv); +module_platform_driver(clk_mt8183_ipu_conn_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-mfgcfg.c b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c index 730c9ae5ea12..816ecf1191ee 100644 --- a/drivers/clk/mediatek/clk-mt8183-mfgcfg.c +++ b/drivers/clk/mediatek/clk-mt8183-mfgcfg.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8183_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_mfg); static struct platform_driver clk_mt8183_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -48,5 +49,5 @@ static struct platform_driver clk_mt8183_mfg_drv = { .of_match_table = of_match_clk_mt8183_mfg, }, }; - -builtin_platform_driver(clk_mt8183_mfg_drv); +module_platform_driver(clk_mt8183_mfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-mm.c b/drivers/clk/mediatek/clk-mt8183-mm.c index 358031530913..2f99828bff1b 100644 --- a/drivers/clk/mediatek/clk-mt8183-mm.c +++ b/drivers/clk/mediatek/clk-mt8183-mm.c @@ -82,25 +82,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM1(CLK_MM_DBI_IF, "mm_dbi_if", "dpi0_sel", 13), }; -static int clk_mt8183_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - - mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} +static const struct platform_device_id clk_mt8183_mm_id_table[] = { + { .name = "clk-mt8183-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8183_mm_id_table); static struct platform_driver clk_mt8183_mm_drv = { - .probe = clk_mt8183_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8183-mm", }, + .id_table = clk_mt8183_mm_id_table, }; - -builtin_platform_driver(clk_mt8183_mm_drv); +module_platform_driver(clk_mt8183_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-vdec.c b/drivers/clk/mediatek/clk-mt8183-vdec.c index c294e50b96b7..513b7956cbea 100644 --- a/drivers/clk/mediatek/clk-mt8183-vdec.c +++ b/drivers/clk/mediatek/clk-mt8183-vdec.c @@ -51,6 +51,7 @@ static const struct of_device_id of_match_clk_mt8183_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_vdec); static struct platform_driver clk_mt8183_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -60,5 +61,5 @@ static struct platform_driver clk_mt8183_vdec_drv = { .of_match_table = of_match_clk_mt8183_vdec, }, }; - -builtin_platform_driver(clk_mt8183_vdec_drv); +module_platform_driver(clk_mt8183_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183-venc.c b/drivers/clk/mediatek/clk-mt8183-venc.c index 0051c5d92fc5..532f6e12a561 100644 --- a/drivers/clk/mediatek/clk-mt8183-venc.c +++ b/drivers/clk/mediatek/clk-mt8183-venc.c @@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8183_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183_venc); static struct platform_driver clk_mt8183_venc_drv = { .probe = mtk_clk_simple_probe, @@ -52,5 +53,5 @@ static struct platform_driver clk_mt8183_venc_drv = { .of_match_table = of_match_clk_mt8183_venc, }, }; - -builtin_platform_driver(clk_mt8183_venc_drv); +module_platform_driver(clk_mt8183_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c index 722d913f0b4d..2336a1b69c09 100644 --- a/drivers/clk/mediatek/clk-mt8183.c +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -14,7 +14,6 @@ #include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-pll.h" #include @@ -26,11 +25,14 @@ static const struct mtk_fixed_clk top_fixed_clks[] = { FIXED_CLK(CLK_TOP_UNIVP_192M, "univpll_192m", "univpll", 192000000), }; -static const struct mtk_fixed_factor top_early_divs[] = { - FACTOR(CLK_TOP_CLK13M, "clk13m", "clk26m", 1, 2), -}; - +/* + * To retain compatibility with older devicetrees, we keep CLK_TOP_CLK13M + * valid, but renamed from "clk13m" (defined as fixed clock in the new + * devicetrees) to "clk26m_d2", satisfying the older clock assignments. + * This means that on new devicetrees "clk26m_d2" is unused. + */ static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_CLK13M, "clk26m_d2", "clk26m", 1, 2), FACTOR(CLK_TOP_F26M_CK_D2, "csw_f26m_ck_d2", "clk26m", 1, 2), FACTOR_FLAGS(CLK_TOP_SYSPLL_CK, "syspll_ck", "mainpll", 1, 1, 0), FACTOR_FLAGS(CLK_TOP_SYSPLL_D2, "syspll_d2", "syspll_ck", 1, 2, 0), @@ -449,138 +451,97 @@ static const char * const aud_2_parents[] = { static const struct mtk_mux top_muxes[] = { /* CLK_CFG_0 */ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MUX_AXI, "axi_sel", - axi_parents, 0x40, - 0x44, 0x48, 0, 2, 7, 0x004, 0, CLK_IS_CRITICAL), + axi_parents, 0x40, 0x44, 0x48, 0, 2, 7, 0x004, 0, CLK_IS_CRITICAL), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MM, "mm_sel", - mm_parents, 0x40, - 0x44, 0x48, 8, 3, 15, 0x004, 1), + mm_parents, 0x40, 0x44, 0x48, 8, 3, 15, 0x004, 1), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_IMG, "img_sel", - img_parents, 0x40, - 0x44, 0x48, 16, 3, 23, 0x004, 2), + img_parents, 0x40, 0x44, 0x48, 16, 3, 23, 0x004, 2), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAM, "cam_sel", - cam_parents, 0x40, - 0x44, 0x48, 24, 4, 31, 0x004, 3), + cam_parents, 0x40, 0x44, 0x48, 24, 4, 31, 0x004, 3), /* CLK_CFG_1 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP, "dsp_sel", - dsp_parents, 0x50, - 0x54, 0x58, 0, 4, 7, 0x004, 4), + dsp_parents, 0x50, 0x54, 0x58, 0, 4, 7, 0x004, 4), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP1, "dsp1_sel", - dsp1_parents, 0x50, - 0x54, 0x58, 8, 4, 15, 0x004, 5), + dsp1_parents, 0x50, 0x54, 0x58, 8, 4, 15, 0x004, 5), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DSP2, "dsp2_sel", - dsp2_parents, 0x50, - 0x54, 0x58, 16, 4, 23, 0x004, 6), + dsp2_parents, 0x50, 0x54, 0x58, 16, 4, 23, 0x004, 6), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_IPU_IF, "ipu_if_sel", - ipu_if_parents, 0x50, - 0x54, 0x58, 24, 4, 31, 0x004, 7), + ipu_if_parents, 0x50, 0x54, 0x58, 24, 4, 31, 0x004, 7), /* CLK_CFG_2 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MFG, "mfg_sel", - mfg_parents, 0x60, - 0x64, 0x68, 0, 2, 7, 0x004, 8), + mfg_parents, 0x60, 0x64, 0x68, 0, 2, 7, 0x004, 8), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_F52M_MFG, "f52m_mfg_sel", - f52m_mfg_parents, 0x60, - 0x64, 0x68, 8, 2, 15, 0x004, 9), + f52m_mfg_parents, 0x60, 0x64, 0x68, 8, 2, 15, 0x004, 9), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG, "camtg_sel", - camtg_parents, 0x60, - 0x64, 0x68, 16, 3, 23, 0x004, 10), + camtg_parents, 0x60, 0x64, 0x68, 16, 3, 23, 0x004, 10), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG2, "camtg2_sel", - camtg2_parents, 0x60, - 0x64, 0x68, 24, 3, 31, 0x004, 11), + camtg2_parents, 0x60, 0x64, 0x68, 24, 3, 31, 0x004, 11), /* CLK_CFG_3 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG3, "camtg3_sel", - camtg3_parents, 0x70, - 0x74, 0x78, 0, 3, 7, 0x004, 12), + camtg3_parents, 0x70, 0x74, 0x78, 0, 3, 7, 0x004, 12), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_CAMTG4, "camtg4_sel", - camtg4_parents, 0x70, - 0x74, 0x78, 8, 3, 15, 0x004, 13), + camtg4_parents, 0x70, 0x74, 0x78, 8, 3, 15, 0x004, 13), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_UART, "uart_sel", - uart_parents, 0x70, - 0x74, 0x78, 16, 1, 23, 0x004, 14), + uart_parents, 0x70, 0x74, 0x78, 16, 1, 23, 0x004, 14), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SPI, "spi_sel", - spi_parents, 0x70, - 0x74, 0x78, 24, 2, 31, 0x004, 15), + spi_parents, 0x70, 0x74, 0x78, 24, 2, 31, 0x004, 15), /* CLK_CFG_4 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC50_0_HCLK, "msdc50_hclk_sel", - msdc50_hclk_parents, 0x80, - 0x84, 0x88, 0, 2, 7, 0x004, 16), + msdc50_hclk_parents, 0x80, 0x84, 0x88, 0, 2, 7, 0x004, 16), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC50_0, "msdc50_0_sel", - msdc50_0_parents, 0x80, - 0x84, 0x88, 8, 3, 15, 0x004, 17), + msdc50_0_parents, 0x80, 0x84, 0x88, 8, 3, 15, 0x004, 17), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC30_1, "msdc30_1_sel", - msdc30_1_parents, 0x80, - 0x84, 0x88, 16, 3, 23, 0x004, 18), + msdc30_1_parents, 0x80, 0x84, 0x88, 16, 3, 23, 0x004, 18), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_MSDC30_2, "msdc30_2_sel", - msdc30_2_parents, 0x80, - 0x84, 0x88, 24, 3, 31, 0x004, 19), + msdc30_2_parents, 0x80, 0x84, 0x88, 24, 3, 31, 0x004, 19), /* CLK_CFG_5 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUDIO, "audio_sel", - audio_parents, 0x90, - 0x94, 0x98, 0, 2, 7, 0x004, 20), + audio_parents, 0x90, 0x94, 0x98, 0, 2, 7, 0x004, 20), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_INTBUS, "aud_intbus_sel", - aud_intbus_parents, 0x90, - 0x94, 0x98, 8, 2, 15, 0x004, 21), + aud_intbus_parents, 0x90, 0x94, 0x98, 8, 2, 15, 0x004, 21), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_PMICSPI, "pmicspi_sel", - pmicspi_parents, 0x90, - 0x94, 0x98, 16, 2, 23, 0x004, 22), + pmicspi_parents, 0x90, 0x94, 0x98, 16, 2, 23, 0x004, 22), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FPWRAP_ULPOSC, "fpwrap_ulposc_sel", - fpwrap_ulposc_parents, 0x90, - 0x94, 0x98, 24, 2, 31, 0x004, 23), + fpwrap_ulposc_parents, 0x90, 0x94, 0x98, 24, 2, 31, 0x004, 23), /* CLK_CFG_6 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_ATB, "atb_sel", - atb_parents, 0xa0, - 0xa4, 0xa8, 0, 2, 7, 0x004, 24), + atb_parents, 0xa0, 0xa4, 0xa8, 0, 2, 7, 0x004, 24), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DPI0, "dpi0_sel", - dpi0_parents, 0xa0, - 0xa4, 0xa8, 16, 4, 23, 0x004, 26), + dpi0_parents, 0xa0, 0xa4, 0xa8, 16, 4, 23, 0x004, 26), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SCAM, "scam_sel", - scam_parents, 0xa0, - 0xa4, 0xa8, 24, 1, 31, 0x004, 27), + scam_parents, 0xa0, 0xa4, 0xa8, 24, 1, 31, 0x004, 27), /* CLK_CFG_7 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DISP_PWM, "disppwm_sel", - disppwm_parents, 0xb0, - 0xb4, 0xb8, 0, 3, 7, 0x004, 28), + disppwm_parents, 0xb0, 0xb4, 0xb8, 0, 3, 7, 0x004, 28), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_USB_TOP, "usb_top_sel", - usb_top_parents, 0xb0, - 0xb4, 0xb8, 8, 2, 15, 0x004, 29), + usb_top_parents, 0xb0, 0xb4, 0xb8, 8, 2, 15, 0x004, 29), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SSUSB_TOP_XHCI, "ssusb_top_xhci_sel", - ssusb_top_xhci_parents, 0xb0, - 0xb4, 0xb8, 16, 2, 23, 0x004, 30), + ssusb_top_xhci_parents, 0xb0, 0xb4, 0xb8, 16, 2, 23, 0x004, 30), MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MUX_SPM, "spm_sel", - spm_parents, 0xb0, - 0xb4, 0xb8, 24, 1, 31, 0x008, 0, CLK_IS_CRITICAL), + spm_parents, 0xb0, 0xb4, 0xb8, 24, 1, 31, 0x008, 0, CLK_IS_CRITICAL), /* CLK_CFG_8 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_I2C, "i2c_sel", - i2c_parents, 0xc0, - 0xc4, 0xc8, 0, 2, 7, 0x008, 1), + i2c_parents, 0xc0, 0xc4, 0xc8, 0, 2, 7, 0x008, 1), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SCP, "scp_sel", - scp_parents, 0xc0, - 0xc4, 0xc8, 8, 3, 15, 0x008, 2), + scp_parents, 0xc0, 0xc4, 0xc8, 8, 3, 15, 0x008, 2), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_SENINF, "seninf_sel", - seninf_parents, 0xc0, - 0xc4, 0xc8, 16, 2, 23, 0x008, 3), + seninf_parents, 0xc0, 0xc4, 0xc8, 16, 2, 23, 0x008, 3), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_DXCC, "dxcc_sel", - dxcc_parents, 0xc0, - 0xc4, 0xc8, 24, 2, 31, 0x008, 4), + dxcc_parents, 0xc0, 0xc4, 0xc8, 24, 2, 31, 0x008, 4), /* CLK_CFG_9 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_ENG1, "aud_eng1_sel", - aud_engen1_parents, 0xd0, - 0xd4, 0xd8, 0, 2, 7, 0x008, 5), + aud_engen1_parents, 0xd0, 0xd4, 0xd8, 0, 2, 7, 0x008, 5), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_ENG2, "aud_eng2_sel", - aud_engen2_parents, 0xd0, - 0xd4, 0xd8, 8, 2, 15, 0x008, 6), + aud_engen2_parents, 0xd0, 0xd4, 0xd8, 8, 2, 15, 0x008, 6), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FAES_UFSFDE, "faes_ufsfde_sel", - faes_ufsfde_parents, 0xd0, - 0xd4, 0xd8, 16, 3, 23, 0x008, 7), + faes_ufsfde_parents, 0xd0, 0xd4, 0xd8, 16, 3, 23, 0x008, 7), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_FUFS, "fufs_sel", - fufs_parents, 0xd0, - 0xd4, 0xd8, 24, 2, 31, 0x008, 8), + fufs_parents, 0xd0, 0xd4, 0xd8, 24, 2, 31, 0x008, 8), /* CLK_CFG_10 */ MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_1, "aud_1_sel", - aud_1_parents, 0xe0, - 0xe4, 0xe8, 0, 1, 7, 0x008, 9), + aud_1_parents, 0xe0, 0xe4, 0xe8, 0, 1, 7, 0x008, 9), MUX_GATE_CLR_SET_UPD(CLK_TOP_MUX_AUD_2, "aud_2_sel", - aud_2_parents, 0xe0, - 0xe4, 0xe8, 8, 1, 15, 0x008, 10), + aud_2_parents, 0xe0, 0xe4, 0xe8, 8, 1, 15, 0x008, 10), }; static const char * const apll_i2s0_parents[] = { @@ -644,30 +605,18 @@ static struct mtk_composite mcu_muxes[] = { }; static struct mtk_composite top_aud_comp[] = { - MUX(CLK_TOP_MUX_APLL_I2S0, "apll_i2s0_sel", apll_i2s0_parents, - 0x320, 8, 1), - MUX(CLK_TOP_MUX_APLL_I2S1, "apll_i2s1_sel", apll_i2s1_parents, - 0x320, 9, 1), - MUX(CLK_TOP_MUX_APLL_I2S2, "apll_i2s2_sel", apll_i2s2_parents, - 0x320, 10, 1), - MUX(CLK_TOP_MUX_APLL_I2S3, "apll_i2s3_sel", apll_i2s3_parents, - 0x320, 11, 1), - MUX(CLK_TOP_MUX_APLL_I2S4, "apll_i2s4_sel", apll_i2s4_parents, - 0x320, 12, 1), - MUX(CLK_TOP_MUX_APLL_I2S5, "apll_i2s5_sel", apll_i2s5_parents, - 0x328, 20, 1), - DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll_i2s0_sel", - 0x320, 2, 0x324, 8, 0), - DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll_i2s1_sel", - 0x320, 3, 0x324, 8, 8), - DIV_GATE(CLK_TOP_APLL12_DIV2, "apll12_div2", "apll_i2s2_sel", - 0x320, 4, 0x324, 8, 16), - DIV_GATE(CLK_TOP_APLL12_DIV3, "apll12_div3", "apll_i2s3_sel", - 0x320, 5, 0x324, 8, 24), - DIV_GATE(CLK_TOP_APLL12_DIV4, "apll12_div4", "apll_i2s4_sel", - 0x320, 6, 0x328, 8, 0), - DIV_GATE(CLK_TOP_APLL12_DIVB, "apll12_divb", "apll12_div4", - 0x320, 7, 0x328, 8, 8), + MUX(CLK_TOP_MUX_APLL_I2S0, "apll_i2s0_sel", apll_i2s0_parents, 0x320, 8, 1), + MUX(CLK_TOP_MUX_APLL_I2S1, "apll_i2s1_sel", apll_i2s1_parents, 0x320, 9, 1), + MUX(CLK_TOP_MUX_APLL_I2S2, "apll_i2s2_sel", apll_i2s2_parents, 0x320, 10, 1), + MUX(CLK_TOP_MUX_APLL_I2S3, "apll_i2s3_sel", apll_i2s3_parents, 0x320, 11, 1), + MUX(CLK_TOP_MUX_APLL_I2S4, "apll_i2s4_sel", apll_i2s4_parents, 0x320, 12, 1), + MUX(CLK_TOP_MUX_APLL_I2S5, "apll_i2s5_sel", apll_i2s5_parents, 0x328, 20, 1), + DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll_i2s0_sel", 0x320, 2, 0x324, 8, 0), + DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll_i2s1_sel", 0x320, 3, 0x324, 8, 8), + DIV_GATE(CLK_TOP_APLL12_DIV2, "apll12_div2", "apll_i2s2_sel", 0x320, 4, 0x324, 8, 16), + DIV_GATE(CLK_TOP_APLL12_DIV3, "apll12_div3", "apll_i2s3_sel", 0x320, 5, 0x324, 8, 24), + DIV_GATE(CLK_TOP_APLL12_DIV4, "apll12_div4", "apll_i2s4_sel", 0x320, 6, 0x328, 8, 0), + DIV_GATE(CLK_TOP_APLL12_DIVB, "apll12_divb", "apll12_div4", 0x320, 7, 0x328, 8, 8), }; static const struct mtk_gate_regs top_cg_regs = { @@ -728,203 +677,106 @@ static const struct mtk_gate_regs infra3_cg_regs = { static const struct mtk_gate infra_clks[] = { /* INFRA0 */ - GATE_INFRA0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr", - "axi_sel", 0), - GATE_INFRA0(CLK_INFRA_PMIC_AP, "infra_pmic_ap", - "axi_sel", 1), - GATE_INFRA0(CLK_INFRA_PMIC_MD, "infra_pmic_md", - "axi_sel", 2), - GATE_INFRA0(CLK_INFRA_PMIC_CONN, "infra_pmic_conn", - "axi_sel", 3), - GATE_INFRA0(CLK_INFRA_SCPSYS, "infra_scp", - "scp_sel", 4), - GATE_INFRA0(CLK_INFRA_SEJ, "infra_sej", - "f_f26m_ck", 5), - GATE_INFRA0(CLK_INFRA_APXGPT, "infra_apxgpt", - "axi_sel", 6), - GATE_INFRA0(CLK_INFRA_ICUSB, "infra_icusb", - "axi_sel", 8), - GATE_INFRA0(CLK_INFRA_GCE, "infra_gce", - "axi_sel", 9), - GATE_INFRA0(CLK_INFRA_THERM, "infra_therm", - "axi_sel", 10), - GATE_INFRA0(CLK_INFRA_I2C0, "infra_i2c0", - "i2c_sel", 11), - GATE_INFRA0(CLK_INFRA_I2C1, "infra_i2c1", - "i2c_sel", 12), - GATE_INFRA0(CLK_INFRA_I2C2, "infra_i2c2", - "i2c_sel", 13), - GATE_INFRA0(CLK_INFRA_I2C3, "infra_i2c3", - "i2c_sel", 14), - GATE_INFRA0(CLK_INFRA_PWM_HCLK, "infra_pwm_hclk", - "axi_sel", 15), - GATE_INFRA0(CLK_INFRA_PWM1, "infra_pwm1", - "i2c_sel", 16), - GATE_INFRA0(CLK_INFRA_PWM2, "infra_pwm2", - "i2c_sel", 17), - GATE_INFRA0(CLK_INFRA_PWM3, "infra_pwm3", - "i2c_sel", 18), - GATE_INFRA0(CLK_INFRA_PWM4, "infra_pwm4", - "i2c_sel", 19), - GATE_INFRA0(CLK_INFRA_PWM, "infra_pwm", - "i2c_sel", 21), - GATE_INFRA0(CLK_INFRA_UART0, "infra_uart0", - "uart_sel", 22), - GATE_INFRA0(CLK_INFRA_UART1, "infra_uart1", - "uart_sel", 23), - GATE_INFRA0(CLK_INFRA_UART2, "infra_uart2", - "uart_sel", 24), - GATE_INFRA0(CLK_INFRA_UART3, "infra_uart3", - "uart_sel", 25), - GATE_INFRA0(CLK_INFRA_GCE_26M, "infra_gce_26m", - "axi_sel", 27), - GATE_INFRA0(CLK_INFRA_CQ_DMA_FPC, "infra_cqdma_fpc", - "axi_sel", 28), - GATE_INFRA0(CLK_INFRA_BTIF, "infra_btif", - "axi_sel", 31), + GATE_INFRA0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr", "axi_sel", 0), + GATE_INFRA0(CLK_INFRA_PMIC_AP, "infra_pmic_ap", "axi_sel", 1), + GATE_INFRA0(CLK_INFRA_PMIC_MD, "infra_pmic_md", "axi_sel", 2), + GATE_INFRA0(CLK_INFRA_PMIC_CONN, "infra_pmic_conn", "axi_sel", 3), + GATE_INFRA0(CLK_INFRA_SCPSYS, "infra_scp", "scp_sel", 4), + GATE_INFRA0(CLK_INFRA_SEJ, "infra_sej", "f_f26m_ck", 5), + GATE_INFRA0(CLK_INFRA_APXGPT, "infra_apxgpt", "axi_sel", 6), + GATE_INFRA0(CLK_INFRA_ICUSB, "infra_icusb", "axi_sel", 8), + GATE_INFRA0(CLK_INFRA_GCE, "infra_gce", "axi_sel", 9), + GATE_INFRA0(CLK_INFRA_THERM, "infra_therm", "axi_sel", 10), + GATE_INFRA0(CLK_INFRA_I2C0, "infra_i2c0", "i2c_sel", 11), + GATE_INFRA0(CLK_INFRA_I2C1, "infra_i2c1", "i2c_sel", 12), + GATE_INFRA0(CLK_INFRA_I2C2, "infra_i2c2", "i2c_sel", 13), + GATE_INFRA0(CLK_INFRA_I2C3, "infra_i2c3", "i2c_sel", 14), + GATE_INFRA0(CLK_INFRA_PWM_HCLK, "infra_pwm_hclk", "axi_sel", 15), + GATE_INFRA0(CLK_INFRA_PWM1, "infra_pwm1", "i2c_sel", 16), + GATE_INFRA0(CLK_INFRA_PWM2, "infra_pwm2", "i2c_sel", 17), + GATE_INFRA0(CLK_INFRA_PWM3, "infra_pwm3", "i2c_sel", 18), + GATE_INFRA0(CLK_INFRA_PWM4, "infra_pwm4", "i2c_sel", 19), + GATE_INFRA0(CLK_INFRA_PWM, "infra_pwm", "i2c_sel", 21), + GATE_INFRA0(CLK_INFRA_UART0, "infra_uart0", "uart_sel", 22), + GATE_INFRA0(CLK_INFRA_UART1, "infra_uart1", "uart_sel", 23), + GATE_INFRA0(CLK_INFRA_UART2, "infra_uart2", "uart_sel", 24), + GATE_INFRA0(CLK_INFRA_UART3, "infra_uart3", "uart_sel", 25), + GATE_INFRA0(CLK_INFRA_GCE_26M, "infra_gce_26m", "axi_sel", 27), + GATE_INFRA0(CLK_INFRA_CQ_DMA_FPC, "infra_cqdma_fpc", "axi_sel", 28), + GATE_INFRA0(CLK_INFRA_BTIF, "infra_btif", "axi_sel", 31), /* INFRA1 */ - GATE_INFRA1(CLK_INFRA_SPI0, "infra_spi0", - "spi_sel", 1), - GATE_INFRA1(CLK_INFRA_MSDC0, "infra_msdc0", - "msdc50_hclk_sel", 2), - GATE_INFRA1(CLK_INFRA_MSDC1, "infra_msdc1", - "axi_sel", 4), - GATE_INFRA1(CLK_INFRA_MSDC2, "infra_msdc2", - "axi_sel", 5), - GATE_INFRA1(CLK_INFRA_MSDC0_SCK, "infra_msdc0_sck", - "msdc50_0_sel", 6), - GATE_INFRA1(CLK_INFRA_DVFSRC, "infra_dvfsrc", - "f_f26m_ck", 7), - GATE_INFRA1(CLK_INFRA_GCPU, "infra_gcpu", - "axi_sel", 8), - GATE_INFRA1(CLK_INFRA_TRNG, "infra_trng", - "axi_sel", 9), - GATE_INFRA1(CLK_INFRA_AUXADC, "infra_auxadc", - "f_f26m_ck", 10), - GATE_INFRA1(CLK_INFRA_CPUM, "infra_cpum", - "axi_sel", 11), - GATE_INFRA1(CLK_INFRA_CCIF1_AP, "infra_ccif1_ap", - "axi_sel", 12), - GATE_INFRA1(CLK_INFRA_CCIF1_MD, "infra_ccif1_md", - "axi_sel", 13), - GATE_INFRA1(CLK_INFRA_AUXADC_MD, "infra_auxadc_md", - "f_f26m_ck", 14), - GATE_INFRA1(CLK_INFRA_MSDC1_SCK, "infra_msdc1_sck", - "msdc30_1_sel", 16), - GATE_INFRA1(CLK_INFRA_MSDC2_SCK, "infra_msdc2_sck", - "msdc30_2_sel", 17), - GATE_INFRA1(CLK_INFRA_AP_DMA, "infra_apdma", - "axi_sel", 18), - GATE_INFRA1(CLK_INFRA_XIU, "infra_xiu", - "axi_sel", 19), - GATE_INFRA1(CLK_INFRA_DEVICE_APC, "infra_device_apc", - "axi_sel", 20), - GATE_INFRA1(CLK_INFRA_CCIF_AP, "infra_ccif_ap", - "axi_sel", 23), - GATE_INFRA1(CLK_INFRA_DEBUGSYS, "infra_debugsys", - "axi_sel", 24), - GATE_INFRA1(CLK_INFRA_AUDIO, "infra_audio", - "axi_sel", 25), - GATE_INFRA1(CLK_INFRA_CCIF_MD, "infra_ccif_md", - "axi_sel", 26), - GATE_INFRA1(CLK_INFRA_DXCC_SEC_CORE, "infra_dxcc_sec_core", - "dxcc_sel", 27), - GATE_INFRA1(CLK_INFRA_DXCC_AO, "infra_dxcc_ao", - "dxcc_sel", 28), - GATE_INFRA1(CLK_INFRA_DEVMPU_BCLK, "infra_devmpu_bclk", - "axi_sel", 30), - GATE_INFRA1(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", - "f_f26m_ck", 31), + GATE_INFRA1(CLK_INFRA_SPI0, "infra_spi0", "spi_sel", 1), + GATE_INFRA1(CLK_INFRA_MSDC0, "infra_msdc0", "msdc50_hclk_sel", 2), + GATE_INFRA1(CLK_INFRA_MSDC1, "infra_msdc1", "axi_sel", 4), + GATE_INFRA1(CLK_INFRA_MSDC2, "infra_msdc2", "axi_sel", 5), + GATE_INFRA1(CLK_INFRA_MSDC0_SCK, "infra_msdc0_sck", "msdc50_0_sel", 6), + GATE_INFRA1(CLK_INFRA_DVFSRC, "infra_dvfsrc", "f_f26m_ck", 7), + GATE_INFRA1(CLK_INFRA_GCPU, "infra_gcpu", "axi_sel", 8), + GATE_INFRA1(CLK_INFRA_TRNG, "infra_trng", "axi_sel", 9), + GATE_INFRA1(CLK_INFRA_AUXADC, "infra_auxadc", "f_f26m_ck", 10), + GATE_INFRA1(CLK_INFRA_CPUM, "infra_cpum", "axi_sel", 11), + GATE_INFRA1(CLK_INFRA_CCIF1_AP, "infra_ccif1_ap", "axi_sel", 12), + GATE_INFRA1(CLK_INFRA_CCIF1_MD, "infra_ccif1_md", "axi_sel", 13), + GATE_INFRA1(CLK_INFRA_AUXADC_MD, "infra_auxadc_md", "f_f26m_ck", 14), + GATE_INFRA1(CLK_INFRA_MSDC1_SCK, "infra_msdc1_sck", "msdc30_1_sel", 16), + GATE_INFRA1(CLK_INFRA_MSDC2_SCK, "infra_msdc2_sck", "msdc30_2_sel", 17), + GATE_INFRA1(CLK_INFRA_AP_DMA, "infra_apdma", "axi_sel", 18), + GATE_INFRA1(CLK_INFRA_XIU, "infra_xiu", "axi_sel", 19), + GATE_INFRA1(CLK_INFRA_DEVICE_APC, "infra_device_apc", "axi_sel", 20), + GATE_INFRA1(CLK_INFRA_CCIF_AP, "infra_ccif_ap", "axi_sel", 23), + GATE_INFRA1(CLK_INFRA_DEBUGSYS, "infra_debugsys", "axi_sel", 24), + GATE_INFRA1(CLK_INFRA_AUDIO, "infra_audio", "axi_sel", 25), + GATE_INFRA1(CLK_INFRA_CCIF_MD, "infra_ccif_md", "axi_sel", 26), + GATE_INFRA1(CLK_INFRA_DXCC_SEC_CORE, "infra_dxcc_sec_core", "dxcc_sel", 27), + GATE_INFRA1(CLK_INFRA_DXCC_AO, "infra_dxcc_ao", "dxcc_sel", 28), + GATE_INFRA1(CLK_INFRA_DEVMPU_BCLK, "infra_devmpu_bclk", "axi_sel", 30), + GATE_INFRA1(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "f_f26m_ck", 31), /* INFRA2 */ - GATE_INFRA2(CLK_INFRA_IRTX, "infra_irtx", - "f_f26m_ck", 0), - GATE_INFRA2(CLK_INFRA_USB, "infra_usb", - "usb_top_sel", 1), - GATE_INFRA2(CLK_INFRA_DISP_PWM, "infra_disppwm", - "axi_sel", 2), - GATE_INFRA2(CLK_INFRA_CLDMA_BCLK, "infra_cldma_bclk", - "axi_sel", 3), - GATE_INFRA2(CLK_INFRA_AUDIO_26M_BCLK, "infra_audio_26m_bclk", - "f_f26m_ck", 4), - GATE_INFRA2(CLK_INFRA_SPI1, "infra_spi1", - "spi_sel", 6), - GATE_INFRA2(CLK_INFRA_I2C4, "infra_i2c4", - "i2c_sel", 7), - GATE_INFRA2(CLK_INFRA_MODEM_TEMP_SHARE, "infra_md_tmp_share", - "f_f26m_ck", 8), - GATE_INFRA2(CLK_INFRA_SPI2, "infra_spi2", - "spi_sel", 9), - GATE_INFRA2(CLK_INFRA_SPI3, "infra_spi3", - "spi_sel", 10), - GATE_INFRA2(CLK_INFRA_UNIPRO_SCK, "infra_unipro_sck", - "ssusb_top_xhci_sel", 11), - GATE_INFRA2(CLK_INFRA_UNIPRO_TICK, "infra_unipro_tick", - "fufs_sel", 12), - GATE_INFRA2(CLK_INFRA_UFS_MP_SAP_BCLK, "infra_ufs_mp_sap_bck", - "fufs_sel", 13), - GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk", - "axi_sel", 14), - GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist", - "axi_sel", 16), - GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5", - "i2c_sel", 18), - GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter", - "i2c_sel", 19), - GATE_INFRA2(CLK_INFRA_I2C5_IMM, "infra_i2c5_imm", - "i2c_sel", 20), - GATE_INFRA2(CLK_INFRA_I2C1_ARBITER, "infra_i2c1_arbiter", - "i2c_sel", 21), - GATE_INFRA2(CLK_INFRA_I2C1_IMM, "infra_i2c1_imm", - "i2c_sel", 22), - GATE_INFRA2(CLK_INFRA_I2C2_ARBITER, "infra_i2c2_arbiter", - "i2c_sel", 23), - GATE_INFRA2(CLK_INFRA_I2C2_IMM, "infra_i2c2_imm", - "i2c_sel", 24), - GATE_INFRA2(CLK_INFRA_SPI4, "infra_spi4", - "spi_sel", 25), - GATE_INFRA2(CLK_INFRA_SPI5, "infra_spi5", - "spi_sel", 26), - GATE_INFRA2(CLK_INFRA_CQ_DMA, "infra_cqdma", - "axi_sel", 27), - GATE_INFRA2(CLK_INFRA_UFS, "infra_ufs", - "fufs_sel", 28), - GATE_INFRA2(CLK_INFRA_AES_UFSFDE, "infra_aes_ufsfde", - "faes_ufsfde_sel", 29), - GATE_INFRA2(CLK_INFRA_UFS_TICK, "infra_ufs_tick", - "fufs_sel", 30), + GATE_INFRA2(CLK_INFRA_IRTX, "infra_irtx", "f_f26m_ck", 0), + GATE_INFRA2(CLK_INFRA_USB, "infra_usb", "usb_top_sel", 1), + GATE_INFRA2(CLK_INFRA_DISP_PWM, "infra_disppwm", "axi_sel", 2), + GATE_INFRA2(CLK_INFRA_CLDMA_BCLK, "infra_cldma_bclk", "axi_sel", 3), + GATE_INFRA2(CLK_INFRA_AUDIO_26M_BCLK, "infra_audio_26m_bclk", "f_f26m_ck", 4), + GATE_INFRA2(CLK_INFRA_SPI1, "infra_spi1", "spi_sel", 6), + GATE_INFRA2(CLK_INFRA_I2C4, "infra_i2c4", "i2c_sel", 7), + GATE_INFRA2(CLK_INFRA_MODEM_TEMP_SHARE, "infra_md_tmp_share", "f_f26m_ck", 8), + GATE_INFRA2(CLK_INFRA_SPI2, "infra_spi2", "spi_sel", 9), + GATE_INFRA2(CLK_INFRA_SPI3, "infra_spi3", "spi_sel", 10), + GATE_INFRA2(CLK_INFRA_UNIPRO_SCK, "infra_unipro_sck", "ssusb_top_xhci_sel", 11), + GATE_INFRA2(CLK_INFRA_UNIPRO_TICK, "infra_unipro_tick", "fufs_sel", 12), + GATE_INFRA2(CLK_INFRA_UFS_MP_SAP_BCLK, "infra_ufs_mp_sap_bck", "fufs_sel", 13), + GATE_INFRA2(CLK_INFRA_MD32_BCLK, "infra_md32_bclk", "axi_sel", 14), + GATE_INFRA2(CLK_INFRA_UNIPRO_MBIST, "infra_unipro_mbist", "axi_sel", 16), + GATE_INFRA2(CLK_INFRA_I2C5, "infra_i2c5", "i2c_sel", 18), + GATE_INFRA2(CLK_INFRA_I2C5_ARBITER, "infra_i2c5_arbiter", "i2c_sel", 19), + GATE_INFRA2(CLK_INFRA_I2C5_IMM, "infra_i2c5_imm", "i2c_sel", 20), + GATE_INFRA2(CLK_INFRA_I2C1_ARBITER, "infra_i2c1_arbiter", "i2c_sel", 21), + GATE_INFRA2(CLK_INFRA_I2C1_IMM, "infra_i2c1_imm", "i2c_sel", 22), + GATE_INFRA2(CLK_INFRA_I2C2_ARBITER, "infra_i2c2_arbiter", "i2c_sel", 23), + GATE_INFRA2(CLK_INFRA_I2C2_IMM, "infra_i2c2_imm", "i2c_sel", 24), + GATE_INFRA2(CLK_INFRA_SPI4, "infra_spi4", "spi_sel", 25), + GATE_INFRA2(CLK_INFRA_SPI5, "infra_spi5", "spi_sel", 26), + GATE_INFRA2(CLK_INFRA_CQ_DMA, "infra_cqdma", "axi_sel", 27), + GATE_INFRA2(CLK_INFRA_UFS, "infra_ufs", "fufs_sel", 28), + GATE_INFRA2(CLK_INFRA_AES_UFSFDE, "infra_aes_ufsfde", "faes_ufsfde_sel", 29), + GATE_INFRA2(CLK_INFRA_UFS_TICK, "infra_ufs_tick", "fufs_sel", 30), /* INFRA3 */ - GATE_INFRA3(CLK_INFRA_MSDC0_SELF, "infra_msdc0_self", - "msdc50_0_sel", 0), - GATE_INFRA3(CLK_INFRA_MSDC1_SELF, "infra_msdc1_self", - "msdc50_0_sel", 1), - GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self", - "msdc50_0_sel", 2), - GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", - "axi_sel", 5), - GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", - "i2c_sel", 6), - GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", - "msdc50_hclk_sel", 7), - GATE_INFRA3(CLK_INFRA_MD_MSDC0, "infra_md_msdc0", - "msdc50_hclk_sel", 8), - GATE_INFRA3(CLK_INFRA_CCIF2_AP, "infra_ccif2_ap", - "axi_sel", 16), - GATE_INFRA3(CLK_INFRA_CCIF2_MD, "infra_ccif2_md", - "axi_sel", 17), - GATE_INFRA3(CLK_INFRA_CCIF3_AP, "infra_ccif3_ap", - "axi_sel", 18), - GATE_INFRA3(CLK_INFRA_CCIF3_MD, "infra_ccif3_md", - "axi_sel", 19), - GATE_INFRA3(CLK_INFRA_SEJ_F13M, "infra_sej_f13m", - "f_f26m_ck", 20), - GATE_INFRA3(CLK_INFRA_AES_BCLK, "infra_aes_bclk", - "axi_sel", 21), - GATE_INFRA3(CLK_INFRA_I2C7, "infra_i2c7", - "i2c_sel", 22), - GATE_INFRA3(CLK_INFRA_I2C8, "infra_i2c8", - "i2c_sel", 23), - GATE_INFRA3(CLK_INFRA_FBIST2FPC, "infra_fbist2fpc", - "msdc50_0_sel", 24), + GATE_INFRA3(CLK_INFRA_MSDC0_SELF, "infra_msdc0_self", "msdc50_0_sel", 0), + GATE_INFRA3(CLK_INFRA_MSDC1_SELF, "infra_msdc1_self", "msdc50_0_sel", 1), + GATE_INFRA3(CLK_INFRA_MSDC2_SELF, "infra_msdc2_self", "msdc50_0_sel", 2), + GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", "axi_sel", 5), + GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", "i2c_sel", 6), + GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", "msdc50_hclk_sel", 7), + GATE_INFRA3(CLK_INFRA_MD_MSDC0, "infra_md_msdc0", "msdc50_hclk_sel", 8), + GATE_INFRA3(CLK_INFRA_CCIF2_AP, "infra_ccif2_ap", "axi_sel", 16), + GATE_INFRA3(CLK_INFRA_CCIF2_MD, "infra_ccif2_md", "axi_sel", 17), + GATE_INFRA3(CLK_INFRA_CCIF3_AP, "infra_ccif3_ap", "axi_sel", 18), + GATE_INFRA3(CLK_INFRA_CCIF3_MD, "infra_ccif3_md", "axi_sel", 19), + GATE_INFRA3(CLK_INFRA_SEJ_F13M, "infra_sej_f13m", "f_f26m_ck", 20), + GATE_INFRA3(CLK_INFRA_AES_BCLK, "infra_aes_bclk", "axi_sel", 21), + GATE_INFRA3(CLK_INFRA_I2C7, "infra_i2c7", "i2c_sel", 22), + GATE_INFRA3(CLK_INFRA_I2C8, "infra_i2c8", "i2c_sel", 23), + GATE_INFRA3(CLK_INFRA_FBIST2FPC, "infra_fbist2fpc", "msdc50_0_sel", 24), }; static const struct mtk_gate_regs peri_cg_regs = { @@ -941,140 +793,6 @@ static const struct mtk_gate peri_clks[] = { GATE_PERI(CLK_PERI_AXI, "peri_axi", "axi_sel", 31), }; -static const struct mtk_gate_regs apmixed_cg_regs = { - .set_ofs = 0x20, - .clr_ofs = 0x20, - .sta_ofs = 0x20, -}; - -#define GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, _flags) \ - GATE_MTK_FLAGS(_id, _name, _parent, &apmixed_cg_regs, \ - _shift, &mtk_clk_gate_ops_no_setclr_inv, _flags) - -#define GATE_APMIXED(_id, _name, _parent, _shift) \ - GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, 0) - -/* - * CRITICAL CLOCK: - * apmixed_appll26m is the toppest clock gate of all PLLs. - */ -static const struct mtk_gate apmixed_clks[] = { - /* AUDIO0 */ - GATE_APMIXED(CLK_APMIXED_SSUSB_26M, "apmixed_ssusb26m", - "f_f26m_ck", 4), - GATE_APMIXED_FLAGS(CLK_APMIXED_APPLL_26M, "apmixed_appll26m", - "f_f26m_ck", 5, CLK_IS_CRITICAL), - GATE_APMIXED(CLK_APMIXED_MIPIC0_26M, "apmixed_mipic026m", - "f_f26m_ck", 6), - GATE_APMIXED(CLK_APMIXED_MDPLLGP_26M, "apmixed_mdpll26m", - "f_f26m_ck", 7), - GATE_APMIXED(CLK_APMIXED_MMSYS_26M, "apmixed_mmsys26m", - "f_f26m_ck", 8), - GATE_APMIXED(CLK_APMIXED_UFS_26M, "apmixed_ufs26m", - "f_f26m_ck", 9), - GATE_APMIXED(CLK_APMIXED_MIPIC1_26M, "apmixed_mipic126m", - "f_f26m_ck", 11), - GATE_APMIXED(CLK_APMIXED_MEMPLL_26M, "apmixed_mempll26m", - "f_f26m_ck", 13), - GATE_APMIXED(CLK_APMIXED_CLKSQ_LVPLL_26M, "apmixed_lvpll26m", - "f_f26m_ck", 14), - GATE_APMIXED(CLK_APMIXED_MIPID0_26M, "apmixed_mipid026m", - "f_f26m_ck", 16), - GATE_APMIXED(CLK_APMIXED_MIPID1_26M, "apmixed_mipid126m", - "f_f26m_ck", 17), -}; - -#define MT8183_PLL_FMAX (3800UL * MHZ) -#define MT8183_PLL_FMIN (1500UL * MHZ) - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ - _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift, \ - _pcw_chg_reg, _div_table) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = _rst_bar_mask, \ - .fmax = MT8183_PLL_FMAX, \ - .fmin = MT8183_PLL_FMIN, \ - .pcwbits = _pcwbits, \ - .pcwibits = _pcwibits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .tuner_en_reg = _tuner_en_reg, \ - .tuner_en_bit = _tuner_en_bit, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .pcw_chg_reg = _pcw_chg_reg, \ - .div_table = _div_table, \ - } - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ - _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift, \ - _pcw_chg_reg) \ - PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \ - _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift, \ - _pcw_chg_reg, NULL) - -static const struct mtk_pll_div_table armpll_div_table[] = { - { .div = 0, .freq = MT8183_PLL_FMAX }, - { .div = 1, .freq = 1500 * MHZ }, - { .div = 2, .freq = 750 * MHZ }, - { .div = 3, .freq = 375 * MHZ }, - { .div = 4, .freq = 187500000 }, - { } /* sentinel */ -}; - -static const struct mtk_pll_div_table mfgpll_div_table[] = { - { .div = 0, .freq = MT8183_PLL_FMAX }, - { .div = 1, .freq = 1600 * MHZ }, - { .div = 2, .freq = 800 * MHZ }, - { .div = 3, .freq = 400 * MHZ }, - { .div = 4, .freq = 200 * MHZ }, - { } /* sentinel */ -}; - -static const struct mtk_pll_data plls[] = { - PLL_B(CLK_APMIXED_ARMPLL_LL, "armpll_ll", 0x0200, 0x020C, 0, - HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0204, 24, 0x0, 0x0, 0, - 0x0204, 0, 0, armpll_div_table), - PLL_B(CLK_APMIXED_ARMPLL_L, "armpll_l", 0x0210, 0x021C, 0, - HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0214, 24, 0x0, 0x0, 0, - 0x0214, 0, 0, armpll_div_table), - PLL(CLK_APMIXED_CCIPLL, "ccipll", 0x0290, 0x029C, 0, - HAVE_RST_BAR | PLL_AO, BIT(24), 22, 8, 0x0294, 24, 0x0, 0x0, 0, - 0x0294, 0, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0220, 0x022C, 0, - HAVE_RST_BAR, BIT(24), 22, 8, 0x0224, 24, 0x0, 0x0, 0, - 0x0224, 0, 0), - PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0230, 0x023C, 0, - HAVE_RST_BAR, BIT(24), 22, 8, 0x0234, 24, 0x0, 0x0, 0, - 0x0234, 0, 0), - PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0240, 0x024C, 0, - 0, 0, 22, 8, 0x0244, 24, 0x0, 0x0, 0, 0x0244, 0, 0, - mfgpll_div_table), - PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0250, 0x025C, 0, - 0, 0, 22, 8, 0x0254, 24, 0x0, 0x0, 0, 0x0254, 0, 0), - PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0260, 0x026C, 0, - 0, 0, 22, 8, 0x0264, 24, 0x0, 0x0, 0, 0x0264, 0, 0), - PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0270, 0x027C, 0, - HAVE_RST_BAR, BIT(23), 22, 8, 0x0274, 24, 0x0, 0x0, 0, - 0x0274, 0, 0), - PLL(CLK_APMIXED_APLL1, "apll1", 0x02A0, 0x02B0, 0, - 0, 0, 32, 8, 0x02A0, 1, 0x02A8, 0x0014, 0, 0x02A4, 0, 0x02A0), - PLL(CLK_APMIXED_APLL2, "apll2", 0x02b4, 0x02c4, 0, - 0, 0, 32, 8, 0x02B4, 1, 0x02BC, 0x0014, 1, 0x02B8, 0, 0x02B4), -}; - static u16 infra_rst_ofs[] = { INFRA_RST0_SET_OFFSET, INFRA_RST1_SET_OFFSET, @@ -1088,41 +806,6 @@ static const struct mtk_clk_rst_desc clk_rst_desc = { .rst_bank_nr = ARRAY_SIZE(infra_rst_ofs), }; -static int clk_mt8183_apmixed_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - - mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, - ARRAY_SIZE(apmixed_clks), clk_data); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} - -static struct clk_hw_onecell_data *top_clk_data; - -static void clk_mt8183_top_init_early(struct device_node *node) -{ - int i; - - top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - - for (i = 0; i < CLK_TOP_NR_CLK; i++) - top_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); - - mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), - top_clk_data); - - of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data); -} - -CLK_OF_DECLARE_DRIVER(mt8183_topckgen, "mediatek,mt8183-topckgen", - clk_mt8183_top_init_early); - /* Register mux notifier for MFG mux */ static int clk_mt8183_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) { @@ -1145,137 +828,55 @@ static int clk_mt8183_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb); } -static int clk_mt8183_top_probe(struct platform_device *pdev) -{ - void __iomem *base; - struct device_node *node = pdev->dev.of_node; - int ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), - top_clk_data); - - mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), - top_clk_data); - - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); - - mtk_clk_register_muxes(&pdev->dev, top_muxes, - ARRAY_SIZE(top_muxes), node, - &mt8183_clk_lock, top_clk_data); - - mtk_clk_register_composites(&pdev->dev, top_aud_comp, - ARRAY_SIZE(top_aud_comp), base, - &mt8183_clk_lock, top_clk_data); - - mtk_clk_register_gates(&pdev->dev, node, top_clks, - ARRAY_SIZE(top_clks), top_clk_data); - - ret = clk_mt8183_reg_mfg_mux_notifier(&pdev->dev, - top_clk_data->hws[CLK_TOP_MUX_MFG]->clk); - if (ret) - return ret; - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, - top_clk_data); -} - -static int clk_mt8183_mcu_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - void __iomem *base; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); - - mtk_clk_register_composites(&pdev->dev, mcu_muxes, - ARRAY_SIZE(mcu_muxes), base, - &mt8183_clk_lock, clk_data); - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} - -static const struct of_device_id of_match_clk_mt8183[] = { - { - .compatible = "mediatek,mt8183-apmixedsys", - .data = clk_mt8183_apmixed_probe, - }, { - .compatible = "mediatek,mt8183-topckgen", - .data = clk_mt8183_top_probe, - }, { - .compatible = "mediatek,mt8183-mcucfg", - .data = clk_mt8183_mcu_probe, - }, { - /* sentinel */ - } -}; - -static int clk_mt8183_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *pdev); - int r; - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - r = clk_probe(pdev); - if (r) - dev_err(&pdev->dev, - "could not register clock provider: %s: %d\n", - pdev->name, r); - - return r; -} - static const struct mtk_clk_desc infra_desc = { .clks = infra_clks, .num_clks = ARRAY_SIZE(infra_clks), .rst_desc = &clk_rst_desc, }; +static const struct mtk_clk_desc mcu_desc = { + .composite_clks = mcu_muxes, + .num_composite_clks = ARRAY_SIZE(mcu_muxes), + .clk_lock = &mt8183_clk_lock, +}; + static const struct mtk_clk_desc peri_desc = { .clks = peri_clks, .num_clks = ARRAY_SIZE(peri_clks), }; -static const struct of_device_id of_match_clk_mt8183_simple[] = { +static const struct mtk_clk_desc topck_desc = { + .fixed_clks = top_fixed_clks, + .num_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .mux_clks = top_muxes, + .num_mux_clks = ARRAY_SIZE(top_muxes), + .composite_clks = top_aud_comp, + .num_composite_clks = ARRAY_SIZE(top_aud_comp), + .clks = top_clks, + .num_clks = ARRAY_SIZE(top_clks), + .clk_lock = &mt8183_clk_lock, + .clk_notifier_func = clk_mt8183_reg_mfg_mux_notifier, + .mfg_clk_idx = CLK_TOP_MUX_MFG, +}; + +static const struct of_device_id of_match_clk_mt8183[] = { { .compatible = "mediatek,mt8183-infracfg", .data = &infra_desc }, + { .compatible = "mediatek,mt8183-mcucfg", .data = &mcu_desc }, { .compatible = "mediatek,mt8183-pericfg", .data = &peri_desc, }, + { .compatible = "mediatek,mt8183-topckgen", .data = &topck_desc }, { /* sentinel */ } }; - -static struct platform_driver clk_mt8183_simple_drv = { - .probe = mtk_clk_simple_probe, - .remove = mtk_clk_simple_remove, - .driver = { - .name = "clk-mt8183-simple", - .of_match_table = of_match_clk_mt8183_simple, - }, -}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8183); static struct platform_driver clk_mt8183_drv = { - .probe = clk_mt8183_probe, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8183", .of_match_table = of_match_clk_mt8183, }, }; - -static int __init clk_mt8183_init(void) -{ - int ret = platform_driver_register(&clk_mt8183_drv); - - if (ret) - return ret; - return platform_driver_register(&clk_mt8183_simple_drv); -} - -arch_initcall(clk_mt8183_init); +module_platform_driver(clk_mt8183_drv) +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c index 1d673c6278a9..da7950d51c64 100644 --- a/drivers/clk/mediatek/clk-mt8186-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8186-apmixedsys.c @@ -7,6 +7,7 @@ #include #include +#include "clk-fhctl.h" #include "clk-mtk.h" #include "clk-pll.h" #include "clk-pllfh.h" @@ -98,6 +99,7 @@ enum fh_pll_id { .data = { \ .pll_id = _pllid, \ .fh_id = _fhid, \ + .fh_ver = FHCTL_PLLFH_V2, \ .fhx_offset = _offset, \ .dds_mask = GENMASK(21, 0), \ .slope0_value = 0x6003c97, \ @@ -134,6 +136,7 @@ static const struct of_device_id of_match_clk_mt8186_apmixed[] = { { .compatible = "mediatek,mt8186-apmixedsys", }, {} }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_apmixed); static int clk_mt8186_apmixed_probe(struct platform_device *pdev) { @@ -190,4 +193,5 @@ static struct platform_driver clk_mt8186_apmixed_drv = { .of_match_table = of_match_clk_mt8186_apmixed, }, }; -builtin_platform_driver(clk_mt8186_apmixed_drv); +module_platform_driver(clk_mt8186_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-cam.c b/drivers/clk/mediatek/clk-mt8186-cam.c index 9ec345a2ce66..656d9e6f3ee2 100644 --- a/drivers/clk/mediatek/clk-mt8186-cam.c +++ b/drivers/clk/mediatek/clk-mt8186-cam.c @@ -78,6 +78,7 @@ static const struct of_device_id of_match_clk_mt8186_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_cam); static struct platform_driver clk_mt8186_cam_drv = { .probe = mtk_clk_simple_probe, @@ -87,4 +88,5 @@ static struct platform_driver clk_mt8186_cam_drv = { .of_match_table = of_match_clk_mt8186_cam, }, }; -builtin_platform_driver(clk_mt8186_cam_drv); +module_platform_driver(clk_mt8186_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-img.c b/drivers/clk/mediatek/clk-mt8186-img.c index 08a625475aee..754b27f03817 100644 --- a/drivers/clk/mediatek/clk-mt8186-img.c +++ b/drivers/clk/mediatek/clk-mt8186-img.c @@ -56,6 +56,7 @@ static const struct of_device_id of_match_clk_mt8186_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_img); static struct platform_driver clk_mt8186_img_drv = { .probe = mtk_clk_simple_probe, @@ -65,4 +66,5 @@ static struct platform_driver clk_mt8186_img_drv = { .of_match_table = of_match_clk_mt8186_img, }, }; -builtin_platform_driver(clk_mt8186_img_drv); +module_platform_driver(clk_mt8186_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8186-imp_iic_wrap.c index 47f2e480a05e..7619c357b150 100644 --- a/drivers/clk/mediatek/clk-mt8186-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8186-imp_iic_wrap.c @@ -55,6 +55,7 @@ static const struct of_device_id of_match_clk_mt8186_imp_iic_wrap[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_imp_iic_wrap); static struct platform_driver clk_mt8186_imp_iic_wrap_drv = { .probe = mtk_clk_simple_probe, @@ -64,4 +65,5 @@ static struct platform_driver clk_mt8186_imp_iic_wrap_drv = { .of_match_table = of_match_clk_mt8186_imp_iic_wrap, }, }; -builtin_platform_driver(clk_mt8186_imp_iic_wrap_drv); +module_platform_driver(clk_mt8186_imp_iic_wrap_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-infra_ao.c b/drivers/clk/mediatek/clk-mt8186-infra_ao.c index df2a6bd1aefa..a907a5def5b8 100644 --- a/drivers/clk/mediatek/clk-mt8186-infra_ao.c +++ b/drivers/clk/mediatek/clk-mt8186-infra_ao.c @@ -227,6 +227,7 @@ static const struct of_device_id of_match_clk_mt8186_infra_ao[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_infra_ao); static struct platform_driver clk_mt8186_infra_ao_drv = { .probe = mtk_clk_simple_probe, @@ -236,4 +237,5 @@ static struct platform_driver clk_mt8186_infra_ao_drv = { .of_match_table = of_match_clk_mt8186_infra_ao, }, }; -builtin_platform_driver(clk_mt8186_infra_ao_drv); +module_platform_driver(clk_mt8186_infra_ao_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-ipe.c b/drivers/clk/mediatek/clk-mt8186-ipe.c index 8fca148effa6..50e340035aa7 100644 --- a/drivers/clk/mediatek/clk-mt8186-ipe.c +++ b/drivers/clk/mediatek/clk-mt8186-ipe.c @@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8186_ipe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_ipe); static struct platform_driver clk_mt8186_ipe_drv = { .probe = mtk_clk_simple_probe, @@ -52,4 +53,5 @@ static struct platform_driver clk_mt8186_ipe_drv = { .of_match_table = of_match_clk_mt8186_ipe, }, }; -builtin_platform_driver(clk_mt8186_ipe_drv); +module_platform_driver(clk_mt8186_ipe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-mcu.c b/drivers/clk/mediatek/clk-mt8186-mcu.c index e52a2d986c99..d1640e4dc2ad 100644 --- a/drivers/clk/mediatek/clk-mt8186-mcu.c +++ b/drivers/clk/mediatek/clk-mt8186-mcu.c @@ -43,67 +43,26 @@ static struct mtk_composite mcu_muxes[] = { MUX(CLK_MCU_ARMPLL_BUS_SEL, "mcu_armpll_bus_sel", mcu_armpll_bus_parents, 0x2E0, 9, 2), }; -static const struct of_device_id of_match_clk_mt8186_mcu[] = { - { .compatible = "mediatek,mt8186-mcusys", }, - {} +static const struct mtk_clk_desc mcu_desc = { + .composite_clks = mcu_muxes, + .num_composite_clks = ARRAY_SIZE(mcu_muxes), }; -static int clk_mt8186_mcu_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - int r; - void __iomem *base; - - clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); - if (!clk_data) - return -ENOMEM; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - r = PTR_ERR(base); - goto free_mcu_data; - } - - r = mtk_clk_register_composites(&pdev->dev, mcu_muxes, - ARRAY_SIZE(mcu_muxes), base, - NULL, clk_data); - if (r) - goto free_mcu_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_composite_muxes; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_composite_muxes: - mtk_clk_unregister_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), clk_data); -free_mcu_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8186_mcu_remove(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; - - of_clk_del_provider(node); - mtk_clk_unregister_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct of_device_id of_match_clk_mt8186_mcu[] = { + { .compatible = "mediatek,mt8186-mcusys", .data = &mcu_desc }, + { /* sentinel */} +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_mcu); static struct platform_driver clk_mt8186_mcu_drv = { - .probe = clk_mt8186_mcu_probe, - .remove = clk_mt8186_mcu_remove, .driver = { .name = "clk-mt8186-mcu", .of_match_table = of_match_clk_mt8186_mcu, }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, }; -builtin_platform_driver(clk_mt8186_mcu_drv); +module_platform_driver(clk_mt8186_mcu_drv); + +MODULE_DESCRIPTION("MediaTek MT8186 mcusys clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-mdp.c b/drivers/clk/mediatek/clk-mt8186-mdp.c index 05174088ef20..e1d19007e375 100644 --- a/drivers/clk/mediatek/clk-mt8186-mdp.c +++ b/drivers/clk/mediatek/clk-mt8186-mdp.c @@ -68,6 +68,7 @@ static const struct of_device_id of_match_clk_mt8186_mdp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_mdp); static struct platform_driver clk_mt8186_mdp_drv = { .probe = mtk_clk_simple_probe, @@ -77,4 +78,5 @@ static struct platform_driver clk_mt8186_mdp_drv = { .of_match_table = of_match_clk_mt8186_mdp, }, }; -builtin_platform_driver(clk_mt8186_mdp_drv); +module_platform_driver(clk_mt8186_mdp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-mfg.c b/drivers/clk/mediatek/clk-mt8186-mfg.c index 0142d741053a..aeb098b54585 100644 --- a/drivers/clk/mediatek/clk-mt8186-mfg.c +++ b/drivers/clk/mediatek/clk-mt8186-mfg.c @@ -37,6 +37,7 @@ static const struct of_device_id of_match_clk_mt8186_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_mfg); static struct platform_driver clk_mt8186_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -46,4 +47,5 @@ static struct platform_driver clk_mt8186_mfg_drv = { .of_match_table = of_match_clk_mt8186_mfg, }, }; -builtin_platform_driver(clk_mt8186_mfg_drv); +module_platform_driver(clk_mt8186_mfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-mm.c b/drivers/clk/mediatek/clk-mt8186-mm.c index 0b72607777fa..fc3bb6d1f714 100644 --- a/drivers/clk/mediatek/clk-mt8186-mm.c +++ b/drivers/clk/mediatek/clk-mt8186-mm.c @@ -58,55 +58,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM1(CLK_MM_DISP_26M, "mm_disp_26m_ck", "top_disp", 10), }; -static int clk_mt8186_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - if (r) - goto free_mm_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_gates: - mtk_clk_unregister_gates(mm_clks, ARRAY_SIZE(mm_clks), clk_data); -free_mm_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8186_mm_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(mm_clks, ARRAY_SIZE(mm_clks), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt8186_mm_id_table[] = { + { .name = "clk-mt8186-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8186_mm_id_table); static struct platform_driver clk_mt8186_mm_drv = { - .probe = clk_mt8186_mm_probe, - .remove = clk_mt8186_mm_remove, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8186-mm", }, + .id_table = clk_mt8186_mm_id_table, }; -builtin_platform_driver(clk_mt8186_mm_drv); +module_platform_driver(clk_mt8186_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-topckgen.c b/drivers/clk/mediatek/clk-mt8186-topckgen.c index c6786c8b315f..1a0340a20beb 100644 --- a/drivers/clk/mediatek/clk-mt8186-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8186-topckgen.c @@ -721,6 +721,7 @@ static const struct of_device_id of_match_clk_mt8186_topck[] = { { .compatible = "mediatek,mt8186-topckgen", .data = &topck_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_topck); static struct platform_driver clk_mt8186_topck_drv = { .probe = mtk_clk_simple_probe, @@ -730,4 +731,5 @@ static struct platform_driver clk_mt8186_topck_drv = { .of_match_table = of_match_clk_mt8186_topck, }, }; -builtin_platform_driver(clk_mt8186_topck_drv); +module_platform_driver(clk_mt8186_topck_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-vdec.c b/drivers/clk/mediatek/clk-mt8186-vdec.c index 5ad7e1ae0bac..9bf3b8632870 100644 --- a/drivers/clk/mediatek/clk-mt8186-vdec.c +++ b/drivers/clk/mediatek/clk-mt8186-vdec.c @@ -76,6 +76,7 @@ static const struct of_device_id of_match_clk_mt8186_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_vdec); static struct platform_driver clk_mt8186_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -85,4 +86,5 @@ static struct platform_driver clk_mt8186_vdec_drv = { .of_match_table = of_match_clk_mt8186_vdec, }, }; -builtin_platform_driver(clk_mt8186_vdec_drv); +module_platform_driver(clk_mt8186_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-venc.c b/drivers/clk/mediatek/clk-mt8186-venc.c index f5519f794c45..0c1bc94e84cf 100644 --- a/drivers/clk/mediatek/clk-mt8186-venc.c +++ b/drivers/clk/mediatek/clk-mt8186-venc.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8186_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_venc); static struct platform_driver clk_mt8186_venc_drv = { .probe = mtk_clk_simple_probe, @@ -48,4 +49,5 @@ static struct platform_driver clk_mt8186_venc_drv = { .of_match_table = of_match_clk_mt8186_venc, }, }; -builtin_platform_driver(clk_mt8186_venc_drv); +module_platform_driver(clk_mt8186_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8186-wpe.c b/drivers/clk/mediatek/clk-mt8186-wpe.c index 8db3e9178a1e..c4727b1cb64d 100644 --- a/drivers/clk/mediatek/clk-mt8186-wpe.c +++ b/drivers/clk/mediatek/clk-mt8186-wpe.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8186_wpe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8186_wpe); static struct platform_driver clk_mt8186_wpe_drv = { .probe = mtk_clk_simple_probe, @@ -48,4 +49,5 @@ static struct platform_driver clk_mt8186_wpe_drv = { .of_match_table = of_match_clk_mt8186_wpe, }, }; -builtin_platform_driver(clk_mt8186_wpe_drv); +module_platform_driver(clk_mt8186_wpe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c b/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c new file mode 100644 index 000000000000..808f2ad3b7ee --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs adsp_audio26m_cg_regs = { + .set_ofs = 0x80, + .clr_ofs = 0x80, + .sta_ofs = 0x80, +}; + +#define GATE_ADSP_FLAGS(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &adsp_audio26m_cg_regs, _shift, \ + &mtk_clk_gate_ops_no_setclr) + +static const struct mtk_gate adsp_audio26m_clks[] = { + GATE_ADSP_FLAGS(CLK_AUDIODSP_AUDIO26M, "audiodsp_audio26m", "clk26m", 3), +}; + +static const struct mtk_clk_desc adsp_audio26m_desc = { + .clks = adsp_audio26m_clks, + .num_clks = ARRAY_SIZE(adsp_audio26m_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_adsp_audio26m[] = { + { .compatible = "mediatek,mt8188-adsp-audio26m", .data = &adsp_audio26m_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_adsp_audio26m); + +static struct platform_driver clk_mt8188_adsp_audio26m_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-adsp_audio26m", + .of_match_table = of_match_clk_mt8188_adsp_audio26m, + }, +}; +module_platform_driver(clk_mt8188_adsp_audio26m_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c new file mode 100644 index 000000000000..9d21da2d9aa7 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x8, + .sta_ofs = 0x8, +}; + +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate apmixed_clks[] = { + GATE_APMIXED(CLK_APMIXED_PLL_SSUSB26M_EN, "pll_ssusb26m_en", "clk26m", 1), +}; + +#define MT8188_PLL_FMAX (3800UL * MHZ) +#define MT8188_PLL_FMIN (1500UL * MHZ) +#define MT8188_INTEGER_BITS 8 + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, _pcw_chg_reg, \ + _en_reg, _pll_en_bit) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8188_PLL_FMAX, \ + .fmin = MT8188_PLL_FMIN, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8188_INTEGER_BITS, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .en_reg = _en_reg, \ + .pll_en_bit = _pll_en_bit, \ + } + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x044C, 0x0458, 0, + 0, 0, 22, 0x0450, 24, 0, 0, 0, 0x0450, 0, 0, 0, 9), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0514, 0x0520, 0, + 0, 0, 22, 0x0518, 24, 0, 0, 0, 0x0518, 0, 0, 0, 9), + PLL(CLK_APMIXED_TVDPLL1, "tvdpll1", 0x0524, 0x0530, 0, + 0, 0, 22, 0x0528, 24, 0, 0, 0, 0x0528, 0, 0, 0, 9), + PLL(CLK_APMIXED_TVDPLL2, "tvdpll2", 0x0534, 0x0540, 0, + 0, 0, 22, 0x0538, 24, 0, 0, 0, 0x0538, 0, 0, 0, 9), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0544, 0x0550, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0548, 24, 0, 0, 0, 0x0548, 0, 0, 0, 9), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x045C, 0x0468, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0460, 24, 0, 0, 0, 0x0460, 0, 0, 0, 9), + PLL(CLK_APMIXED_IMGPLL, "imgpll", 0x0554, 0x0560, 0, + 0, 0, 22, 0x0558, 24, 0, 0, 0, 0x0558, 0, 0, 0, 9), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0504, 0x0510, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0508, 24, 0, 0, 0, 0x0508, 0, 0, 0, 9), + PLL(CLK_APMIXED_ADSPPLL, "adsppll", 0x042C, 0x0438, 0, + 0, 0, 22, 0x0430, 24, 0, 0, 0, 0x0430, 0, 0, 0, 9), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0304, 0x0314, 0, + 0, 0, 32, 0x0308, 24, 0x0034, 0x0000, 12, 0x030C, 0, 0, 0, 9), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0318, 0x0328, 0, + 0, 0, 32, 0x031C, 24, 0x0038, 0x0000, 13, 0x0320, 0, 0, 0, 9), + PLL(CLK_APMIXED_APLL3, "apll3", 0x032C, 0x033C, 0, + 0, 0, 32, 0x0330, 24, 0x003C, 0x0000, 14, 0x0334, 0, 0, 0, 9), + PLL(CLK_APMIXED_APLL4, "apll4", 0x0404, 0x0414, 0, + 0, 0, 32, 0x0408, 24, 0x0040, 0x0000, 15, 0x040C, 0, 0, 0, 9), + PLL(CLK_APMIXED_APLL5, "apll5", 0x0418, 0x0428, 0, + 0, 0, 32, 0x041C, 24, 0x0044, 0x0000, 16, 0x0420, 0, 0, 0, 9), + PLL(CLK_APMIXED_MFGPLL, "mfgpll", 0x0340, 0x034C, 0, + 0, 0, 22, 0x0344, 24, 0, 0, 0, 0x0344, 0, 0, 0, 9), +}; + +static const struct of_device_id of_match_clk_mt8188_apmixed[] = { + { .compatible = "mediatek,mt8188-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_apmixed); + +static int clk_mt8188_apmixed_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (r) + goto free_apmixed_data; + + r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, + ARRAY_SIZE(apmixed_clks), clk_data); + if (r) + goto unregister_plls; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_gates; + + platform_set_drvdata(pdev, clk_data); + + return 0; + +unregister_gates: + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); +free_apmixed_data: + mtk_free_clk_data(clk_data); + return r; +} + +static int clk_mt8188_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static struct platform_driver clk_mt8188_apmixed_drv = { + .probe = clk_mt8188_apmixed_probe, + .remove = clk_mt8188_apmixed_remove, + .driver = { + .name = "clk-mt8188-apmixed", + .of_match_table = of_match_clk_mt8188_apmixed, + }, +}; +module_platform_driver(clk_mt8188_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-cam.c b/drivers/clk/mediatek/clk-mt8188-cam.c new file mode 100644 index 000000000000..c5a3856bd223 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-cam.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs cam_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_CAM(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &cam_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate cam_main_clks[] = { + GATE_CAM(CLK_CAM_MAIN_LARB13, "cam_main_larb13", "top_cam", 0), + GATE_CAM(CLK_CAM_MAIN_LARB14, "cam_main_larb14", "top_cam", 1), + GATE_CAM(CLK_CAM_MAIN_CAM, "cam_main_cam", "top_cam", 2), + GATE_CAM(CLK_CAM_MAIN_CAM_SUBA, "cam_main_cam_suba", "top_cam", 3), + GATE_CAM(CLK_CAM_MAIN_CAM_SUBB, "cam_main_cam_subb", "top_cam", 4), + GATE_CAM(CLK_CAM_MAIN_CAMTG, "cam_main_camtg", "top_cam", 7), + GATE_CAM(CLK_CAM_MAIN_SENINF, "cam_main_seninf", "top_cam", 8), + GATE_CAM(CLK_CAM_MAIN_GCAMSVA, "cam_main_gcamsva", "top_cam", 9), + GATE_CAM(CLK_CAM_MAIN_GCAMSVB, "cam_main_gcamsvb", "top_cam", 10), + GATE_CAM(CLK_CAM_MAIN_GCAMSVC, "cam_main_gcamsvc", "top_cam", 11), + GATE_CAM(CLK_CAM_MAIN_GCAMSVD, "cam_main_gcamsvd", "top_cam", 12), + GATE_CAM(CLK_CAM_MAIN_GCAMSVE, "cam_main_gcamsve", "top_cam", 13), + GATE_CAM(CLK_CAM_MAIN_GCAMSVF, "cam_main_gcamsvf", "top_cam", 14), + GATE_CAM(CLK_CAM_MAIN_GCAMSVG, "cam_main_gcamsvg", "top_cam", 15), + GATE_CAM(CLK_CAM_MAIN_GCAMSVH, "cam_main_gcamsvh", "top_cam", 16), + GATE_CAM(CLK_CAM_MAIN_GCAMSVI, "cam_main_gcamsvi", "top_cam", 17), + GATE_CAM(CLK_CAM_MAIN_GCAMSVJ, "cam_main_gcamsvj", "top_cam", 18), + GATE_CAM(CLK_CAM_MAIN_CAMSV_TOP, "cam_main_camsv", "top_cam", 19), + GATE_CAM(CLK_CAM_MAIN_CAMSV_CQ_A, "cam_main_camsv_cq_a", "top_cam", 20), + GATE_CAM(CLK_CAM_MAIN_CAMSV_CQ_B, "cam_main_camsv_cq_b", "top_cam", 21), + GATE_CAM(CLK_CAM_MAIN_CAMSV_CQ_C, "cam_main_camsv_cq_c", "top_cam", 22), + GATE_CAM(CLK_CAM_MAIN_FAKE_ENG, "cam_main_fake_eng", "top_cam", 28), + GATE_CAM(CLK_CAM_MAIN_CAM2MM0_GALS, "cam_main_cam2mm0_gals", "top_cam", 29), + GATE_CAM(CLK_CAM_MAIN_CAM2MM1_GALS, "cam_main_cam2mm1_gals", "top_cam", 30), + GATE_CAM(CLK_CAM_MAIN_CAM2SYS_GALS, "cam_main_cam2sys_gals", "top_cam", 31), +}; + +static const struct mtk_gate cam_rawa_clks[] = { + GATE_CAM(CLK_CAM_RAWA_LARBX, "cam_rawa_larbx", "top_cam", 0), + GATE_CAM(CLK_CAM_RAWA_CAM, "cam_rawa_cam", "top_cam", 1), + GATE_CAM(CLK_CAM_RAWA_CAMTG, "cam_rawa_camtg", "top_cam", 2), +}; + +static const struct mtk_gate cam_rawb_clks[] = { + GATE_CAM(CLK_CAM_RAWB_LARBX, "cam_rawb_larbx", "top_cam", 0), + GATE_CAM(CLK_CAM_RAWB_CAM, "cam_rawb_cam", "top_cam", 1), + GATE_CAM(CLK_CAM_RAWB_CAMTG, "cam_rawb_camtg", "top_cam", 2), +}; + +static const struct mtk_gate cam_yuva_clks[] = { + GATE_CAM(CLK_CAM_YUVA_LARBX, "cam_yuva_larbx", "top_cam", 0), + GATE_CAM(CLK_CAM_YUVA_CAM, "cam_yuva_cam", "top_cam", 1), + GATE_CAM(CLK_CAM_YUVA_CAMTG, "cam_yuva_camtg", "top_cam", 2), +}; + +static const struct mtk_gate cam_yuvb_clks[] = { + GATE_CAM(CLK_CAM_YUVB_LARBX, "cam_yuvb_larbx", "top_cam", 0), + GATE_CAM(CLK_CAM_YUVB_CAM, "cam_yuvb_cam", "top_cam", 1), + GATE_CAM(CLK_CAM_YUVB_CAMTG, "cam_yuvb_camtg", "top_cam", 2), +}; + +static const struct mtk_clk_desc cam_main_desc = { + .clks = cam_main_clks, + .num_clks = ARRAY_SIZE(cam_main_clks), +}; + +static const struct mtk_clk_desc cam_rawa_desc = { + .clks = cam_rawa_clks, + .num_clks = ARRAY_SIZE(cam_rawa_clks), +}; + +static const struct mtk_clk_desc cam_rawb_desc = { + .clks = cam_rawb_clks, + .num_clks = ARRAY_SIZE(cam_rawb_clks), +}; + +static const struct mtk_clk_desc cam_yuva_desc = { + .clks = cam_yuva_clks, + .num_clks = ARRAY_SIZE(cam_yuva_clks), +}; + +static const struct mtk_clk_desc cam_yuvb_desc = { + .clks = cam_yuvb_clks, + .num_clks = ARRAY_SIZE(cam_yuvb_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_cam[] = { + { .compatible = "mediatek,mt8188-camsys", .data = &cam_main_desc }, + { .compatible = "mediatek,mt8188-camsys-rawa", .data = &cam_rawa_desc }, + { .compatible = "mediatek,mt8188-camsys-rawb", .data = &cam_rawb_desc }, + { .compatible = "mediatek,mt8188-camsys-yuva", .data = &cam_yuva_desc }, + { .compatible = "mediatek,mt8188-camsys-yuvb", .data = &cam_yuvb_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_cam); + +static struct platform_driver clk_mt8188_cam_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-cam", + .of_match_table = of_match_clk_mt8188_cam, + }, +}; + +module_platform_driver(clk_mt8188_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-ccu.c b/drivers/clk/mediatek/clk-mt8188-ccu.c new file mode 100644 index 000000000000..ebc0d3aeee11 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-ccu.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs ccu_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_CCU(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ccu_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate ccu_clks[] = { + GATE_CCU(CLK_CCU_LARB27, "ccu_larb27", "top_ccu", 0), + GATE_CCU(CLK_CCU_AHB, "ccu_ahb", "top_ccu", 1), + GATE_CCU(CLK_CCU_CCU0, "ccu_ccu0", "top_ccu", 2), +}; + +static const struct mtk_clk_desc ccu_desc = { + .clks = ccu_clks, + .num_clks = ARRAY_SIZE(ccu_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_ccu[] = { + { .compatible = "mediatek,mt8188-ccusys", .data = &ccu_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_ccu); + +static struct platform_driver clk_mt8188_ccu_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-ccu", + .of_match_table = of_match_clk_mt8188_ccu, + }, +}; + +module_platform_driver(clk_mt8188_ccu_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-img.c b/drivers/clk/mediatek/clk-mt8188-img.c new file mode 100644 index 000000000000..b4622875e14c --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-img.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs imgsys_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_IMGSYS(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &imgsys_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate imgsys_main_clks[] = { + GATE_IMGSYS(CLK_IMGSYS_MAIN_LARB9, "imgsys_main_larb9", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS_MAIN_TRAW0, "imgsys_main_traw0", "top_img", 1), + GATE_IMGSYS(CLK_IMGSYS_MAIN_TRAW1, "imgsys_main_traw1", "top_img", 2), + GATE_IMGSYS(CLK_IMGSYS_MAIN_VCORE_GALS, "imgsys_main_vcore_gals", "top_img", 3), + GATE_IMGSYS(CLK_IMGSYS_MAIN_DIP0, "imgsys_main_dip0", "top_img", 8), + GATE_IMGSYS(CLK_IMGSYS_MAIN_WPE0, "imgsys_main_wpe0", "top_img", 9), + GATE_IMGSYS(CLK_IMGSYS_MAIN_IPE, "imgsys_main_ipe", "top_img", 10), + GATE_IMGSYS(CLK_IMGSYS_MAIN_WPE1, "imgsys_main_wpe1", "top_img", 12), + GATE_IMGSYS(CLK_IMGSYS_MAIN_WPE2, "imgsys_main_wpe2", "top_img", 13), + GATE_IMGSYS(CLK_IMGSYS_MAIN_GALS, "imgsys_main_gals", "top_img", 31), +}; + +static const struct mtk_gate imgsys_wpe1_clks[] = { + GATE_IMGSYS(CLK_IMGSYS_WPE1_LARB11, "imgsys_wpe1_larb11", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS_WPE1, "imgsys_wpe1", "top_img", 1), +}; + +static const struct mtk_gate imgsys_wpe2_clks[] = { + GATE_IMGSYS(CLK_IMGSYS_WPE2_LARB11, "imgsys_wpe2_larb11", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS_WPE2, "imgsys_wpe2", "top_img", 1), +}; + +static const struct mtk_gate imgsys_wpe3_clks[] = { + GATE_IMGSYS(CLK_IMGSYS_WPE3_LARB11, "imgsys_wpe3_larb11", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS_WPE3, "imgsys_wpe3", "top_img", 1), +}; + +static const struct mtk_gate imgsys1_dip_top_clks[] = { + GATE_IMGSYS(CLK_IMGSYS1_DIP_TOP_LARB10, "imgsys1_dip_larb10", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS1_DIP_TOP_DIP_TOP, "imgsys1_dip_dip_top", "top_img", 1), +}; + +static const struct mtk_gate imgsys1_dip_nr_clks[] = { + GATE_IMGSYS(CLK_IMGSYS1_DIP_NR_LARB15, "imgsys1_dip_nr_larb15", "top_img", 0), + GATE_IMGSYS(CLK_IMGSYS1_DIP_NR_DIP_NR, "imgsys1_dip_nr_dip_nr", "top_img", 1), +}; + +static const struct mtk_clk_desc imgsys_main_desc = { + .clks = imgsys_main_clks, + .num_clks = ARRAY_SIZE(imgsys_main_clks), +}; + +static const struct mtk_clk_desc imgsys_wpe1_desc = { + .clks = imgsys_wpe1_clks, + .num_clks = ARRAY_SIZE(imgsys_wpe1_clks), +}; + +static const struct mtk_clk_desc imgsys_wpe2_desc = { + .clks = imgsys_wpe2_clks, + .num_clks = ARRAY_SIZE(imgsys_wpe2_clks), +}; + +static const struct mtk_clk_desc imgsys_wpe3_desc = { + .clks = imgsys_wpe3_clks, + .num_clks = ARRAY_SIZE(imgsys_wpe3_clks), +}; + +static const struct mtk_clk_desc imgsys1_dip_top_desc = { + .clks = imgsys1_dip_top_clks, + .num_clks = ARRAY_SIZE(imgsys1_dip_top_clks), +}; + +static const struct mtk_clk_desc imgsys1_dip_nr_desc = { + .clks = imgsys1_dip_nr_clks, + .num_clks = ARRAY_SIZE(imgsys1_dip_nr_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_imgsys_main[] = { + { .compatible = "mediatek,mt8188-imgsys", .data = &imgsys_main_desc }, + { .compatible = "mediatek,mt8188-imgsys-wpe1", .data = &imgsys_wpe1_desc }, + { .compatible = "mediatek,mt8188-imgsys-wpe2", .data = &imgsys_wpe2_desc }, + { .compatible = "mediatek,mt8188-imgsys-wpe3", .data = &imgsys_wpe3_desc }, + { .compatible = "mediatek,mt8188-imgsys1-dip-top", .data = &imgsys1_dip_top_desc }, + { .compatible = "mediatek,mt8188-imgsys1-dip-nr", .data = &imgsys1_dip_nr_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_imgsys_main); + +static struct platform_driver clk_mt8188_imgsys_main_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-imgsys_main", + .of_match_table = of_match_clk_mt8188_imgsys_main, + }, +}; + +module_platform_driver(clk_mt8188_imgsys_main_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c new file mode 100644 index 000000000000..da41a3c59919 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs imp_iic_wrap_cg_regs = { + .set_ofs = 0xe08, + .clr_ofs = 0xe04, + .sta_ofs = 0xe00, +}; + +#define GATE_IMP_IIC_WRAP(_id, _name, _parent, _shift) \ + GATE_MTK_FLAGS(_id, _name, _parent, &imp_iic_wrap_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, CLK_OPS_PARENT_ENABLE) + +static const struct mtk_gate imp_iic_wrap_c_clks[] = { + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C0, + "imp_iic_wrap_c_ap_clock_i2c0", "top_i2c", 0), + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C2, + "imp_iic_wrap_c_ap_clock_i2c2", "top_i2c", 1), + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C3, + "imp_iic_wrap_c_ap_clock_i2c3", "top_i2c", 2), +}; + +static const struct mtk_gate imp_iic_wrap_w_clks[] = { + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_W_AP_CLOCK_I2C1, + "imp_iic_wrap_w_ap_clock_i2c1", "top_i2c", 0), + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_W_AP_CLOCK_I2C4, + "imp_iic_wrap_w_ap_clock_i2c4", "top_i2c", 1), +}; + +static const struct mtk_gate imp_iic_wrap_en_clks[] = { + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_EN_AP_CLOCK_I2C5, + "imp_iic_wrap_en_ap_clock_i2c5", "top_i2c", 0), + GATE_IMP_IIC_WRAP(CLK_IMP_IIC_WRAP_EN_AP_CLOCK_I2C6, + "imp_iic_wrap_en_ap_clock_i2c6", "top_i2c", 1), +}; + +static const struct mtk_clk_desc imp_iic_wrap_c_desc = { + .clks = imp_iic_wrap_c_clks, + .num_clks = ARRAY_SIZE(imp_iic_wrap_c_clks), +}; + +static const struct mtk_clk_desc imp_iic_wrap_w_desc = { + .clks = imp_iic_wrap_w_clks, + .num_clks = ARRAY_SIZE(imp_iic_wrap_w_clks), +}; + +static const struct mtk_clk_desc imp_iic_wrap_en_desc = { + .clks = imp_iic_wrap_en_clks, + .num_clks = ARRAY_SIZE(imp_iic_wrap_en_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_imp_iic_wrap[] = { + { .compatible = "mediatek,mt8188-imp-iic-wrap-c", .data = &imp_iic_wrap_c_desc }, + { .compatible = "mediatek,mt8188-imp-iic-wrap-w", .data = &imp_iic_wrap_w_desc }, + { .compatible = "mediatek,mt8188-imp-iic-wrap-en", .data = &imp_iic_wrap_en_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_imp_iic_wrap); + +static struct platform_driver clk_mt8188_imp_iic_wrap_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-imp_iic_wrap", + .of_match_table = of_match_clk_mt8188_imp_iic_wrap, + }, +}; + +module_platform_driver(clk_mt8188_imp_iic_wrap_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-infra_ao.c b/drivers/clk/mediatek/clk-mt8188-infra_ao.c new file mode 100644 index 000000000000..91c35db40b4e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-infra_ao.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs infra_ao0_cg_regs = { + .set_ofs = 0x80, + .clr_ofs = 0x84, + .sta_ofs = 0x90, +}; + +static const struct mtk_gate_regs infra_ao1_cg_regs = { + .set_ofs = 0x88, + .clr_ofs = 0x8c, + .sta_ofs = 0x94, +}; + +static const struct mtk_gate_regs infra_ao2_cg_regs = { + .set_ofs = 0xa4, + .clr_ofs = 0xa8, + .sta_ofs = 0xac, +}; + +static const struct mtk_gate_regs infra_ao3_cg_regs = { + .set_ofs = 0xc0, + .clr_ofs = 0xc4, + .sta_ofs = 0xc8, +}; + +static const struct mtk_gate_regs infra_ao4_cg_regs = { + .set_ofs = 0xe0, + .clr_ofs = 0xe4, + .sta_ofs = 0xe8, +}; + +#define GATE_INFRA_AO0_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_ao0_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flag) + +#define GATE_INFRA_AO0(_id, _name, _parent, _shift) \ + GATE_INFRA_AO0_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA_AO1_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_ao1_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flag) + +#define GATE_INFRA_AO1(_id, _name, _parent, _shift) \ + GATE_INFRA_AO1_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA_AO2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_ao2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_INFRA_AO2_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_ao2_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flag) + +#define GATE_INFRA_AO3_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_ao3_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flag) + +#define GATE_INFRA_AO3(_id, _name, _parent, _shift) \ + GATE_INFRA_AO3_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA_AO4_FLAGS(_id, _name, _parent, _shift, _flag) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra_ao4_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flag) + +#define GATE_INFRA_AO4(_id, _name, _parent, _shift) \ + GATE_INFRA_AO4_FLAGS(_id, _name, _parent, _shift, 0) + +static const struct mtk_gate infra_ao_clks[] = { + /* INFRA_AO0 */ + GATE_INFRA_AO0(CLK_INFRA_AO_PMIC_TMR, "infra_ao_pmic_tmr", "top_pwrap_ulposc", 0), + GATE_INFRA_AO0(CLK_INFRA_AO_PMIC_AP, "infra_ao_pmic_ap", "top_pwrap_ulposc", 1), + GATE_INFRA_AO0(CLK_INFRA_AO_PMIC_MD, "infra_ao_pmic_md", "top_pwrap_ulposc", 2), + GATE_INFRA_AO0(CLK_INFRA_AO_PMIC_CONN, "infra_ao_pmic_conn", "top_pwrap_ulposc", 3), + /* infra_ao_sej is main clock is for secure engine with JTAG support */ + GATE_INFRA_AO0_FLAGS(CLK_INFRA_AO_SEJ, "infra_ao_sej", "top_axi", 5, CLK_IS_CRITICAL), + GATE_INFRA_AO0(CLK_INFRA_AO_APXGPT, "infra_ao_apxgpt", "top_axi", 6), + GATE_INFRA_AO0(CLK_INFRA_AO_GCE, "infra_ao_gce", "top_axi", 8), + GATE_INFRA_AO0(CLK_INFRA_AO_GCE2, "infra_ao_gce2", "top_axi", 9), + GATE_INFRA_AO0(CLK_INFRA_AO_THERM, "infra_ao_therm", "top_axi", 10), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM_HCLK, "infra_ao_pwm_h", "top_axi", 15), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM1, "infra_ao_pwm1", "top_pwm", 16), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM2, "infra_ao_pwm2", "top_pwm", 17), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM3, "infra_ao_pwm3", "top_pwm", 18), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM4, "infra_ao_pwm4", "top_pwm", 19), + GATE_INFRA_AO0(CLK_INFRA_AO_PWM, "infra_ao_pwm", "top_pwm", 21), + GATE_INFRA_AO0(CLK_INFRA_AO_UART0, "infra_ao_uart0", "top_uart", 22), + GATE_INFRA_AO0(CLK_INFRA_AO_UART1, "infra_ao_uart1", "top_uart", 23), + GATE_INFRA_AO0(CLK_INFRA_AO_UART2, "infra_ao_uart2", "top_uart", 24), + GATE_INFRA_AO0(CLK_INFRA_AO_UART3, "infra_ao_uart3", "top_uart", 25), + GATE_INFRA_AO0(CLK_INFRA_AO_UART4, "infra_ao_uart4", "top_uart", 26), + GATE_INFRA_AO0(CLK_INFRA_AO_GCE_26M, "infra_ao_gce_26m", "clk26m", 27), + GATE_INFRA_AO0(CLK_INFRA_AO_CQ_DMA_FPC, "infra_ao_dma", "pad_fpc_ck", 28), + GATE_INFRA_AO0(CLK_INFRA_AO_UART5, "infra_ao_uart5", "top_uart", 29), + /* INFRA_AO1 */ + GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_26M, "infra_ao_hdmi_26m", "clk26m", 0), + GATE_INFRA_AO1(CLK_INFRA_AO_SPI0, "infra_ao_spi0", "top_spi", 1), + GATE_INFRA_AO1(CLK_INFRA_AO_MSDC0, "infra_ao_msdc0", "top_msdc5hclk", 2), + GATE_INFRA_AO1(CLK_INFRA_AO_MSDC1, "infra_ao_msdc1", "top_axi", 4), + GATE_INFRA_AO1(CLK_INFRA_AO_MSDC2, "infra_ao_msdc2", "top_axi", 5), + GATE_INFRA_AO1(CLK_INFRA_AO_MSDC0_SRC, "infra_ao_msdc0_clk", "top_msdc50_0", 6), + /* infra_ao_dvfsrc is for internal DVFS usage, should not be handled by Linux. */ + GATE_INFRA_AO1_FLAGS(CLK_INFRA_AO_DVFSRC, "infra_ao_dvfsrc", + "clk26m", 7, CLK_IS_CRITICAL), + GATE_INFRA_AO1(CLK_INFRA_AO_TRNG, "infra_ao_trng", "top_axi", 9), + GATE_INFRA_AO1(CLK_INFRA_AO_AUXADC, "infra_ao_auxadc", "clk26m", 10), + GATE_INFRA_AO1(CLK_INFRA_AO_CPUM, "infra_ao_cpum", "top_axi", 11), + GATE_INFRA_AO1(CLK_INFRA_AO_HDMI_32K, "infra_ao_hdmi_32k", "clk32k", 12), + GATE_INFRA_AO1(CLK_INFRA_AO_CEC_66M_HCLK, "infra_ao_cec_66m_hclk", "top_axi", 13), + GATE_INFRA_AO1(CLK_INFRA_AO_PCIE_TL_26M, "infra_ao_pcie_tl_26m", "clk26m", 15), + GATE_INFRA_AO1(CLK_INFRA_AO_MSDC1_SRC, "infra_ao_msdc1_clk", "top_msdc30_1", 16), + GATE_INFRA_AO1(CLK_INFRA_AO_CEC_66M_BCLK, "infra_ao_cec_66m_bclk", "top_axi", 17), + GATE_INFRA_AO1(CLK_INFRA_AO_PCIE_TL_96M, "infra_ao_pcie_tl_96m", "top_tl", 18), + /* infra_ao_dapc is for device access permission control module */ + GATE_INFRA_AO1_FLAGS(CLK_INFRA_AO_DEVICE_APC, "infra_ao_dapc", + "top_axi", 20, CLK_IS_CRITICAL), + GATE_INFRA_AO1(CLK_INFRA_AO_ECC_66M_HCLK, "infra_ao_ecc_66m_hclk", "top_axi", 23), + GATE_INFRA_AO1(CLK_INFRA_AO_DEBUGSYS, "infra_ao_debugsys", "top_axi", 24), + GATE_INFRA_AO1(CLK_INFRA_AO_AUDIO, "infra_ao_audio", "top_axi", 25), + GATE_INFRA_AO1(CLK_INFRA_AO_PCIE_TL_32K, "infra_ao_pcie_tl_32k", "clk32k", 26), + GATE_INFRA_AO1(CLK_INFRA_AO_DBG_TRACE, "infra_ao_dbg_trace", "top_axi", 29), + GATE_INFRA_AO1(CLK_INFRA_AO_DRAMC_F26M, "infra_ao_dramc26", "clk26m", 31), + /* INFRA_AO2 */ + GATE_INFRA_AO2(CLK_INFRA_AO_IRTX, "infra_ao_irtx", "top_axi", 0), + GATE_INFRA_AO2(CLK_INFRA_AO_DISP_PWM, "infra_ao_disp_pwm", "top_disp_pwm0", 2), + GATE_INFRA_AO2(CLK_INFRA_AO_CLDMA_BCLK, "infra_ao_cldmabclk", "top_axi", 3), + GATE_INFRA_AO2(CLK_INFRA_AO_AUDIO_26M_BCLK, "infra_ao_audio26m", "clk26m", 4), + GATE_INFRA_AO2(CLK_INFRA_AO_SPI1, "infra_ao_spi1", "top_spi", 6), + GATE_INFRA_AO2(CLK_INFRA_AO_SPI2, "infra_ao_spi2", "top_spi", 9), + GATE_INFRA_AO2(CLK_INFRA_AO_SPI3, "infra_ao_spi3", "top_spi", 10), + GATE_INFRA_AO2_FLAGS(CLK_INFRA_AO_FSSPM, "infra_ao_fsspm", + "top_sspm", 15, CLK_IS_CRITICAL), + GATE_INFRA_AO2_FLAGS(CLK_INFRA_AO_SSPM_BUS_HCLK, "infra_ao_sspm_hclk", + "top_axi", 17, CLK_IS_CRITICAL), + GATE_INFRA_AO2(CLK_INFRA_AO_APDMA_BCLK, "infra_ao_apdma_bclk", "top_axi", 18), + GATE_INFRA_AO2(CLK_INFRA_AO_SPI4, "infra_ao_spi4", "top_spi", 25), + GATE_INFRA_AO2(CLK_INFRA_AO_SPI5, "infra_ao_spi5", "top_spi", 26), + GATE_INFRA_AO2(CLK_INFRA_AO_CQ_DMA, "infra_ao_cq_dma", "top_axi", 27), + /* INFRA_AO3 */ + GATE_INFRA_AO3(CLK_INFRA_AO_MSDC0_SELF, "infra_ao_msdc0sf", "top_msdc50_0", 0), + GATE_INFRA_AO3(CLK_INFRA_AO_MSDC1_SELF, "infra_ao_msdc1sf", "top_msdc50_0", 1), + GATE_INFRA_AO3(CLK_INFRA_AO_MSDC2_SELF, "infra_ao_msdc2sf", "top_msdc50_0", 2), + GATE_INFRA_AO3(CLK_INFRA_AO_I2S_DMA, "infra_ao_i2s_dma", "top_axi", 5), + GATE_INFRA_AO3(CLK_INFRA_AO_AP_MSDC0, "infra_ao_ap_msdc0", "top_msdc50_0", 7), + GATE_INFRA_AO3(CLK_INFRA_AO_MD_MSDC0, "infra_ao_md_msdc0", "top_msdc50_0", 8), + GATE_INFRA_AO3(CLK_INFRA_AO_MSDC30_2, "infra_ao_msdc30_2", "top_msdc30_2", 9), + GATE_INFRA_AO3(CLK_INFRA_AO_GCPU, "infra_ao_gcpu", "top_gcpu", 10), + GATE_INFRA_AO3(CLK_INFRA_AO_PCIE_PERI_26M, "infra_ao_pcie_peri_26m", "clk26m", 15), + GATE_INFRA_AO3(CLK_INFRA_AO_GCPU_66M_BCLK, "infra_ao_gcpu_66m_bclk", "top_axi", 16), + GATE_INFRA_AO3(CLK_INFRA_AO_GCPU_133M_BCLK, "infra_ao_gcpu_133m_bclk", "top_axi", 17), + GATE_INFRA_AO3(CLK_INFRA_AO_DISP_PWM1, "infra_ao_disp_pwm1", "top_disp_pwm1", 20), + GATE_INFRA_AO3(CLK_INFRA_AO_FBIST2FPC, "infra_ao_fbist2fpc", "top_msdc50_0", 24), + /* infra_ao_dapc_sync is for device access permission control module */ + GATE_INFRA_AO3_FLAGS(CLK_INFRA_AO_DEVICE_APC_SYNC, "infra_ao_dapc_sync", + "top_axi", 25, CLK_IS_CRITICAL), + GATE_INFRA_AO3(CLK_INFRA_AO_PCIE_P1_PERI_26M, "infra_ao_pcie_p1_peri_26m", "clk26m", 26), + /* INFRA_AO4 */ + /* infra_ao_133m_mclk_set/infra_ao_66m_mclk_set are main clocks of peripheral */ + GATE_INFRA_AO4_FLAGS(CLK_INFRA_AO_133M_MCLK_CK, "infra_ao_133m_mclk_set", + "top_axi", 0, CLK_IS_CRITICAL), + GATE_INFRA_AO4_FLAGS(CLK_INFRA_AO_66M_MCLK_CK, "infra_ao_66m_mclk_set", + "top_axi", 1, CLK_IS_CRITICAL), + GATE_INFRA_AO4(CLK_INFRA_AO_PCIE_PL_P_250M_P0, "infra_ao_pcie_pl_p_250m_p0", + "pextp_pipe", 7), + GATE_INFRA_AO4(CLK_INFRA_AO_RG_AES_MSDCFDE_CK_0P, + "infra_ao_aes_msdcfde_0p", "top_aes_msdcfde", 18), +}; + +static const struct mtk_clk_desc infra_ao_desc = { + .clks = infra_ao_clks, + .num_clks = ARRAY_SIZE(infra_ao_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_infra_ao[] = { + { .compatible = "mediatek,mt8188-infracfg-ao", .data = &infra_ao_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_infra_ao); + +static struct platform_driver clk_mt8188_infra_ao_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-infra_ao", + .of_match_table = of_match_clk_mt8188_infra_ao, + }, +}; +module_platform_driver(clk_mt8188_infra_ao_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-ipe.c b/drivers/clk/mediatek/clk-mt8188-ipe.c new file mode 100644 index 000000000000..c07afbd1429e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-ipe.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs ipe_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_IPE(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &ipe_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate ipe_clks[] = { + GATE_IPE(CLK_IPE_DPE, "ipe_dpe", "top_ipe", 0), + GATE_IPE(CLK_IPE_FDVT, "ipe_fdvt", "top_ipe", 1), + GATE_IPE(CLK_IPE_ME, "ipe_me", "top_ipe", 2), + GATE_IPE(CLK_IPESYS_TOP, "ipesys_top", "top_ipe", 3), + GATE_IPE(CLK_IPE_SMI_LARB12, "ipe_smi_larb12", "top_ipe", 4), +}; + +static const struct mtk_clk_desc ipe_desc = { + .clks = ipe_clks, + .num_clks = ARRAY_SIZE(ipe_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_ipe[] = { + { .compatible = "mediatek,mt8188-ipesys", .data = &ipe_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_ipe); + +static struct platform_driver clk_mt8188_ipe_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-ipe", + .of_match_table = of_match_clk_mt8188_ipe, + }, +}; + +module_platform_driver(clk_mt8188_ipe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-mfg.c b/drivers/clk/mediatek/clk-mt8188-mfg.c new file mode 100644 index 000000000000..e5a6eaf84672 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-mfg.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs mfgcfg_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_MFG(_id, _name, _parent, _shift) \ + GATE_MTK_FLAGS(_id, _name, _parent, &mfgcfg_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, CLK_SET_RATE_PARENT) + +static const struct mtk_gate mfgcfg_clks[] = { + GATE_MFG(CLK_MFGCFG_BG3D, "mfgcfg_bg3d", "mfg_ck_fast_ref", 0), +}; + +static const struct mtk_clk_desc mfgcfg_desc = { + .clks = mfgcfg_clks, + .num_clks = ARRAY_SIZE(mfgcfg_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_mfgcfg[] = { + { .compatible = "mediatek,mt8188-mfgcfg", .data = &mfgcfg_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_mfgcfg); + +static struct platform_driver clk_mt8188_mfgcfg_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-mfgcfg", + .of_match_table = of_match_clk_mt8188_mfgcfg, + }, +}; + +module_platform_driver(clk_mt8188_mfgcfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-peri_ao.c b/drivers/clk/mediatek/clk-mt8188-peri_ao.c new file mode 100644 index 000000000000..b00e1ae8bd26 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-peri_ao.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs peri_ao_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x14, + .sta_ofs = 0x18, +}; + +#define GATE_PERI_AO(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &peri_ao_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate peri_ao_clks[] = { + GATE_PERI_AO(CLK_PERI_AO_ETHERNET, "peri_ao_ethernet", "top_axi", 0), + GATE_PERI_AO(CLK_PERI_AO_ETHERNET_BUS, "peri_ao_ethernet_bus", "top_axi", 1), + GATE_PERI_AO(CLK_PERI_AO_FLASHIF_BUS, "peri_ao_flashif_bus", "top_axi", 3), + GATE_PERI_AO(CLK_PERI_AO_FLASHIF_26M, "peri_ao_flashif_26m", "clk26m", 4), + GATE_PERI_AO(CLK_PERI_AO_FLASHIFLASHCK, "peri_ao_flashiflashck", "top_spinor", 5), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_2P_BUS, "peri_ao_ssusb_2p_bus", "top_usb_top_2p", 9), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_2P_XHCI, "peri_ao_ssusb_2p_xhci", "top_ssusb_xhci_2p", 10), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_3P_BUS, "peri_ao_ssusb_3p_bus", "top_usb_top_3p", 11), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_3P_XHCI, "peri_ao_ssusb_3p_xhci", "top_ssusb_xhci_3p", 12), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_BUS, "peri_ao_ssusb_bus", "top_usb_top", 13), + GATE_PERI_AO(CLK_PERI_AO_SSUSB_XHCI, "peri_ao_ssusb_xhci", "top_ssusb_xhci", 14), + GATE_PERI_AO(CLK_PERI_AO_ETHERNET_MAC, "peri_ao_ethernet_mac_clk", "top_snps_eth_250m", 16), + GATE_PERI_AO(CLK_PERI_AO_PCIE_P0_FMEM, "peri_ao_pcie_p0_fmem", "hd_466m_fmem_ck", 24), +}; + +static const struct mtk_clk_desc peri_ao_desc = { + .clks = peri_ao_clks, + .num_clks = ARRAY_SIZE(peri_ao_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_peri_ao[] = { + { .compatible = "mediatek,mt8188-pericfg-ao", .data = &peri_ao_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_peri_ao); + +static struct platform_driver clk_mt8188_peri_ao_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-peri_ao", + .of_match_table = of_match_clk_mt8188_peri_ao, + }, +}; +module_platform_driver(clk_mt8188_peri_ao_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-topckgen.c b/drivers/clk/mediatek/clk-mt8188-topckgen.c new file mode 100644 index 000000000000..c56ec42cb15f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-topckgen.c @@ -0,0 +1,1350 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-mux.h" + +static DEFINE_SPINLOCK(mt8188_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_ULPOSC1, "ulposc_ck1", NULL, 260000000), + FIXED_CLK(CLK_TOP_MPHONE_SLAVE_BCK, "mphone_slave_bck", NULL, 49152000), + FIXED_CLK(CLK_TOP_PAD_FPC, "pad_fpc_ck", NULL, 50000000), + FIXED_CLK(CLK_TOP_466M_FMEM, "hd_466m_fmem_ck", NULL, 533000000), + FIXED_CLK(CLK_TOP_PEXTP_PIPE, "pextp_pipe", NULL, 250000000), + FIXED_CLK(CLK_TOP_DSI_PHY, "dsi_phy", NULL, 500000000), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3), + FACTOR(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D4_D2, "mainpll_d4_d2", "mainpll_d4", 1, 2), + FACTOR(CLK_TOP_MAINPLL_D4_D4, "mainpll_d4_d4", "mainpll_d4", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D4_D8, "mainpll_d4_d8", "mainpll_d4", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D5, "mainpll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_MAINPLL_D5_D2, "mainpll_d5_d2", "mainpll_d5", 1, 2), + FACTOR(CLK_TOP_MAINPLL_D5_D4, "mainpll_d5_d4", "mainpll_d5", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D5_D8, "mainpll_d5_d8", "mainpll_d5", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D6, "mainpll_d6", "mainpll", 1, 6), + FACTOR(CLK_TOP_MAINPLL_D6_D2, "mainpll_d6_d2", "mainpll_d6", 1, 2), + FACTOR(CLK_TOP_MAINPLL_D6_D4, "mainpll_d6_d4", "mainpll_d6", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D6_D8, "mainpll_d6_d8", "mainpll_d6", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D7, "mainpll_d7", "mainpll", 1, 7), + FACTOR(CLK_TOP_MAINPLL_D7_D2, "mainpll_d7_d2", "mainpll_d7", 1, 2), + FACTOR(CLK_TOP_MAINPLL_D7_D4, "mainpll_d7_d4", "mainpll_d7", 1, 4), + FACTOR(CLK_TOP_MAINPLL_D7_D8, "mainpll_d7_d8", "mainpll_d7", 1, 8), + FACTOR(CLK_TOP_MAINPLL_D9, "mainpll_d9", "mainpll", 1, 9), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), + FACTOR(CLK_TOP_UNIVPLL_D4, "univpll_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D4_D2, "univpll_d4_d2", "univpll_d4", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D4_D4, "univpll_d4_d4", "univpll_d4", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D4_D8, "univpll_d4_d8", "univpll_d4", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL_D5_D2, "univpll_d5_d2", "univpll_d5", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D5_D4, "univpll_d5_d4", "univpll_d5", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D5_D8, "univpll_d5_d8", "univpll_d5", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D6, "univpll_d6", "univpll", 1, 6), + FACTOR(CLK_TOP_UNIVPLL_D6_D2, "univpll_d6_d2", "univpll_d6", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D6_D4, "univpll_d6_d4", "univpll_d6", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D6_D8, "univpll_d6_d8", "univpll_d6", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7), + FACTOR(CLK_TOP_UNIVPLL_192M, "univpll_192m", "univpll", 1, 13), + FACTOR(CLK_TOP_UNIVPLL_192M_D4, "univpll_192m_d4", "univpll_192m", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_192M_D8, "univpll_192m_d8", "univpll_192m", 1, 8), + FACTOR(CLK_TOP_UNIVPLL_192M_D10, "univpll_192m_d10", "univpll_192m", 1, 10), + FACTOR(CLK_TOP_UNIVPLL_192M_D16, "univpll_192m_d16", "univpll_192m", 1, 16), + FACTOR(CLK_TOP_UNIVPLL_192M_D32, "univpll_192m_d32", "univpll_192m", 1, 32), + FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1", 1, 3), + FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1", 1, 4), + FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2", 1, 3), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4), + FACTOR(CLK_TOP_APLL3_D4, "apll3_d4", "apll3", 1, 4), + FACTOR(CLK_TOP_APLL4_D4, "apll4_d4", "apll4", 1, 4), + FACTOR(CLK_TOP_APLL5_D4, "apll5_d4", "apll5", 1, 4), + FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4), + FACTOR(CLK_TOP_MMPLL_D4_D2, "mmpll_d4_d2", "mmpll_d4", 1, 2), + FACTOR(CLK_TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5), + FACTOR(CLK_TOP_MMPLL_D5_D2, "mmpll_d5_d2", "mmpll_d5", 1, 2), + FACTOR(CLK_TOP_MMPLL_D5_D4, "mmpll_d5_d4", "mmpll_d5", 1, 4), + FACTOR(CLK_TOP_MMPLL_D6, "mmpll_d6", "mmpll", 1, 6), + FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll_d6", 1, 2), + FACTOR(CLK_TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7), + FACTOR(CLK_TOP_MMPLL_D9, "mmpll_d9", "mmpll", 1, 9), + FACTOR(CLK_TOP_TVDPLL1_D2, "tvdpll1_d2", "tvdpll1", 1, 2), + FACTOR(CLK_TOP_TVDPLL1_D4, "tvdpll1_d4", "tvdpll1", 1, 4), + FACTOR(CLK_TOP_TVDPLL1_D8, "tvdpll1_d8", "tvdpll1", 1, 8), + FACTOR(CLK_TOP_TVDPLL1_D16, "tvdpll1_d16", "tvdpll1", 1, 16), + FACTOR(CLK_TOP_TVDPLL2_D2, "tvdpll2_d2", "tvdpll2", 1, 2), + FACTOR(CLK_TOP_TVDPLL2_D4, "tvdpll2_d4", "tvdpll2", 1, 4), + FACTOR(CLK_TOP_TVDPLL2_D8, "tvdpll2_d8", "tvdpll2", 1, 8), + FACTOR(CLK_TOP_TVDPLL2_D16, "tvdpll2_d16", "tvdpll2", 1, 16), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D16, "msdcpll_d16", "msdcpll", 1, 16), + FACTOR(CLK_TOP_ETHPLL_D2, "ethpll_d2", "ethpll", 1, 2), + FACTOR(CLK_TOP_ETHPLL_D4, "ethpll_d4", "ethpll", 1, 4), + FACTOR(CLK_TOP_ETHPLL_D8, "ethpll_d8", "ethpll", 1, 8), + FACTOR(CLK_TOP_ETHPLL_D10, "ethpll_d10", "ethpll", 1, 10), + FACTOR(CLK_TOP_ADSPPLL_D2, "adsppll_d2", "adsppll", 1, 2), + FACTOR(CLK_TOP_ADSPPLL_D4, "adsppll_d4", "adsppll", 1, 4), + FACTOR(CLK_TOP_ADSPPLL_D8, "adsppll_d8", "adsppll", 1, 8), + FACTOR(CLK_TOP_ULPOSC1_D2, "ulposc1_d2", "ulposc_ck1", 1, 2), + FACTOR(CLK_TOP_ULPOSC1_D4, "ulposc1_d4", "ulposc_ck1", 1, 4), + FACTOR(CLK_TOP_ULPOSC1_D8, "ulposc1_d8", "ulposc_ck1", 1, 8), + FACTOR(CLK_TOP_ULPOSC1_D7, "ulposc1_d7", "ulposc_ck1", 1, 7), + FACTOR(CLK_TOP_ULPOSC1_D10, "ulposc1_d10", "ulposc_ck1", 1, 10), + FACTOR(CLK_TOP_ULPOSC1_D16, "ulposc1_d16", "ulposc_ck1", 1, 16), +}; + +static const char * const axi_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d7_d2", + "mainpll_d4_d2", + "mainpll_d5_d2", + "mainpll_d6_d2", + "ulposc1_d4" +}; + +static const char * const spm_parents[] = { + "clk26m", + "ulposc1_d10", + "mainpll_d7_d4", + "clk32k" +}; + +static const char * const scp_parents[] = { + "clk26m", + "univpll_d4", + "mainpll_d6", + "univpll_d6", + "univpll_d4_d2", + "mainpll_d4_d2", + "univpll_d3", + "mainpll_d3" +}; + +static const char * const bus_aximem_parents[] = { + "clk26m", + "mainpll_d7_d2", + "mainpll_d4_d2", + "mainpll_d5_d2", + "mainpll_d6" +}; + +static const char * const vpp_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d5_d2", + "mmpll_d6_d2", + "univpll_d5_d2", + "univpll_d4_d2", + "mmpll_d4_d2", + "mmpll_d7", + "univpll_d6", + "mainpll_d4", + "mmpll_d5", + "tvdpll1", + "tvdpll2", + "univpll_d4", + "mmpll_d4" +}; + +static const char * const ethdr_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d5_d2", + "mmpll_d6_d2", + "univpll_d5_d2", + "univpll_d4_d2", + "mmpll_d4_d2", + "mmpll_d7", + "univpll_d6", + "mainpll_d4", + "mmpll_d5_d4", + "tvdpll1", + "tvdpll2", + "univpll_d4", + "mmpll_d4" +}; + +static const char * const ipe_parents[] = { + "clk26m", + "imgpll", + "mainpll_d4", + "mmpll_d6", + "univpll_d6", + "mainpll_d6", + "mmpll_d4_d2", + "univpll_d4_d2", + "mainpll_d4_d2", + "mmpll_d6_d2", + "univpll_d5_d2", + "mainpll_d7" +}; + +static const char * const cam_parents[] = { + "clk26m", + "tvdpll1", + "mainpll_d4", + "mmpll_d4", + "univpll_d4", + "univpll_d5", + "univpll_d6", + "mmpll_d7", + "univpll_d4_d2", + "mainpll_d4_d2", + "imgpll" +}; + +static const char * const ccu_parents[] = { + "clk26m", + "univpll_d6", + "mainpll_d4_d2", + "mainpll_d4", + "univpll_d5", + "mainpll_d6", + "mmpll_d6", + "mmpll_d7", + "univpll_d4_d2", + "univpll_d7" +}; + +static const char * const ccu_ahb_parents[] = { + "clk26m", + "univpll_d6", + "mainpll_d4_d2", + "mainpll_d4", + "univpll_d5", + "mainpll_d6", + "mmpll_d6", + "mmpll_d7", + "univpll_d4_d2", + "univpll_d7" +}; + +static const char * const img_parents[] = { + "clk26m", + "imgpll", + "univpll_d4", + "mainpll_d4", + "univpll_d5", + "mmpll_d6", + "mmpll_d7", + "univpll_d6", + "mainpll_d6", + "mmpll_d4_d2", + "univpll_d4_d2", + "mainpll_d4_d2", + "univpll_d5_d2" +}; + +static const char * const camtm_parents[] = { + "clk26m", + "univpll_d4_d4", + "univpll_d6_d2", + "univpll_d6_d4" +}; + +static const char * const dsp_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d4_d2", + "univpll_d5", + "univpll_d4", + "mmpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp1_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d5", + "mmpll_d5", + "univpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp2_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d5", + "mmpll_d5", + "univpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp3_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d5", + "mmpll_d5", + "univpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp4_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d4_d2", + "mainpll_d4", + "univpll_d4", + "mmpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp5_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d4_d2", + "mainpll_d4", + "univpll_d4", + "mmpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp6_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d4_d2", + "mainpll_d4", + "univpll_d4", + "mmpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const dsp7_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d4_d2", + "univpll_d5", + "univpll_d4", + "mmpll_d4", + "mainpll_d3", + "univpll_d3" +}; + +static const char * const mfg_core_tmp_parents[] = { + "clk26m", + "mainpll_d5_d2", + "univpll_d6", + "univpll_d7" +}; + +static const char * const camtg_parents[] = { + "clk26m", + "univpll_192m_d8", + "univpll_d6_d8", + "univpll_192m_d4", + "univpll_192m_d10", + "clk13m", + "univpll_192m_d16", + "univpll_192m_d32" +}; + +static const char * const camtg2_parents[] = { + "clk26m", + "univpll_192m_d8", + "univpll_d6_d8", + "univpll_192m_d4", + "univpll_192m_d10", + "clk13m", + "univpll_192m_d16", + "univpll_192m_d32" +}; + +static const char * const camtg3_parents[] = { + "clk26m", + "univpll_192m_d8", + "univpll_d6_d8", + "univpll_192m_d4", + "univpll_192m_d10", + "clk13m", + "univpll_192m_d16", + "univpll_192m_d32" +}; + +static const char * const uart_parents[] = { + "clk26m", + "univpll_d6_d8" +}; + +static const char * const spi_parents[] = { + "clk26m", + "mainpll_d5_d4", + "mainpll_d6_d4", + "univpll_d6_d4", + "univpll_d6_d2", + "mainpll_d6_d2", + "mainpll_d4_d4", + "univpll_d5_d4" +}; + +static const char * const msdc5hclk_parents[] = { + "clk26m", + "mainpll_d4_d2", + "mainpll_d6_d2" +}; + +static const char * const msdc50_0_parents[] = { + "clk26m", + "msdcpll", + "msdcpll_d2", + "univpll_d4_d4", + "mainpll_d6_d2", + "univpll_d4_d2" +}; + +static const char * const msdc30_1_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d6_d2", + "mainpll_d7_d2", + "msdcpll_d2" +}; + +static const char * const msdc30_2_parents[] = { + "clk26m", + "univpll_d6_d2", + "mainpll_d6_d2", + "mainpll_d7_d2", + "msdcpll_d2" +}; + +static const char * const intdir_parents[] = { + "clk26m", + "univpll_d6", + "mainpll_d4", + "univpll_d4" +}; + +static const char * const aud_intbus_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d7_d4" +}; + +static const char * const audio_h_parents[] = { + "clk26m", + "univpll_d7", + "apll1", + "apll2" +}; + +static const char * const pwrap_ulposc_parents[] = { + "clk26m", + "ulposc1_d10", + "ulposc1_d7", + "ulposc1_d8", + "ulposc1_d16", + "mainpll_d4_d8", + "univpll_d5_d8", + "tvdpll1_d16" +}; + +static const char * const atb_parents[] = { + "clk26m", + "mainpll_d4_d2", + "mainpll_d5_d2" +}; + +static const char * const sspm_parents[] = { + "clk26m", + "mainpll_d7_d2", + "mainpll_d6_d2", + "mainpll_d5_d2", + "mainpll_d9", + "mainpll_d4_d2" +}; + +static const char * const dp_parents[] = { + "clk26m", + "tvdpll1_d2", + "tvdpll2_d2", + "tvdpll1_d4", + "tvdpll2_d4", + "tvdpll1_d8", + "tvdpll2_d8", + "tvdpll1_d16", + "tvdpll2_d16" +}; + +static const char * const edp_parents[] = { + "clk26m", + "tvdpll1_d2", + "tvdpll2_d2", + "tvdpll1_d4", + "tvdpll2_d4", + "tvdpll1_d8", + "tvdpll2_d8", + "tvdpll1_d16", + "tvdpll2_d16" +}; + +static const char * const dpi_parents[] = { + "clk26m", + "tvdpll1_d2", + "tvdpll2_d2", + "tvdpll1_d4", + "tvdpll2_d4", + "tvdpll1_d8", + "tvdpll2_d8", + "tvdpll1_d16", + "tvdpll2_d16" +}; + +static const char * const disp_pwm0_parents[] = { + "clk26m", + "univpll_d6_d4", + "ulposc1_d2", + "ulposc1_d4", + "ulposc1_d16", + "ethpll_d4" +}; + +static const char * const disp_pwm1_parents[] = { + "clk26m", + "univpll_d6_d4", + "ulposc1_d2", + "ulposc1_d4", + "ulposc1_d16" +}; + +static const char * const usb_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const ssusb_xhci_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const usb_2p_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const ssusb_xhci_2p_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const usb_3p_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const ssusb_xhci_3p_parents[] = { + "clk26m", + "univpll_d5_d4", + "univpll_d6_d4", + "univpll_d5_d2" +}; + +static const char * const i2c_parents[] = { + "clk26m", + "mainpll_d4_d8", + "univpll_d5_d4" +}; + +static const char * const seninf_parents[] = { + "clk26m", + "univpll_d4_d4", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d7", + "univpll_d6", + "mmpll_d6", + "univpll_d5" +}; + +static const char * const seninf1_parents[] = { + "clk26m", + "univpll_d4_d4", + "univpll_d6_d2", + "mainpll_d4_d2", + "univpll_d7", + "univpll_d6", + "mmpll_d6", + "univpll_d5" +}; + +static const char * const gcpu_parents[] = { + "clk26m", + "mainpll_d6", + "univpll_d4_d2", + "mmpll_d5_d2", + "univpll_d5_d2" +}; + +static const char * const venc_parents[] = { + "clk26m", + "mmpll_d4_d2", + "mainpll_d6", + "univpll_d4_d2", + "mainpll_d4_d2", + "univpll_d6", + "mmpll_d6", + "mainpll_d5_d2", + "mainpll_d6_d2", + "mmpll_d9", + "univpll_d4_d4", + "mainpll_d4", + "univpll_d4", + "univpll_d5", + "univpll_d5_d2", + "mainpll_d5" +}; + +static const char * const vdec_parents[] = { + "clk26m", + "mainpll_d5_d2", + "mmpll_d6_d2", + "univpll_d5_d2", + "univpll_d4_d2", + "mmpll_d4_d2", + "univpll_d6", + "mainpll_d5", + "univpll_d5", + "mmpll_d6", + "mainpll_d4", + "tvdpll2", + "univpll_d4", + "imgpll", + "univpll_d6_d2", + "mmpll_d9" +}; + +static const char * const pwm_parents[] = { + "clk32k", + "clk26m", + "univpll_d4_d8", + "univpll_d6_d4" +}; + +static const char * const mcupm_parents[] = { + "clk26m", + "mainpll_d6_d2", + "mainpll_d7_d4" +}; + +static const char * const spmi_p_mst_parents[] = { + "clk26m", + "clk13m", + "ulposc1_d8", + "ulposc1_d10", + "ulposc1_d16", + "ulposc1_d7", + "clk32k", + "mainpll_d7_d8", + "mainpll_d6_d8", + "mainpll_d5_d8" +}; + +static const char * const spmi_m_mst_parents[] = { + "clk26m", + "clk13m", + "ulposc1_d8", + "ulposc1_d10", + "ulposc1_d16", + "ulposc1_d7", + "clk32k", + "mainpll_d7_d8", + "mainpll_d6_d8", + "mainpll_d5_d8" +}; + +static const char * const dvfsrc_parents[] = { + "clk26m", + "ulposc1_d10", + "univpll_d6_d8", + "msdcpll_d16" +}; + +static const char * const tl_parents[] = { + "clk26m", + "univpll_d5_d4", + "mainpll_d4_d4" +}; + +static const char * const aes_msdcfde_parents[] = { + "clk26m", + "mainpll_d4_d2", + "mainpll_d6", + "mainpll_d4_d4", + "univpll_d4_d2", + "univpll_d6" +}; + +static const char * const dsi_occ_parents[] = { + "clk26m", + "univpll_d6_d2", + "univpll_d5_d2", + "univpll_d4_d2" +}; + +static const char * const wpe_vpp_parents[] = { + "clk26m", + "mainpll_d5_d2", + "mmpll_d6_d2", + "univpll_d5_d2", + "mainpll_d4_d2", + "univpll_d4_d2", + "mmpll_d4_d2", + "mainpll_d6", + "mmpll_d7", + "univpll_d6", + "mainpll_d5", + "univpll_d5", + "mainpll_d4", + "tvdpll1", + "univpll_d4" +}; + +static const char * const hdcp_parents[] = { + "clk26m", + "univpll_d4_d8", + "mainpll_d5_d8", + "univpll_d6_d4" +}; + +static const char * const hdcp_24m_parents[] = { + "clk26m", + "univpll_192m_d4", + "univpll_192m_d8", + "univpll_d6_d8" +}; + +static const char * const hdmi_apb_parents[] = { + "clk26m", + "univpll_d6_d4", + "msdcpll_d2" +}; + +static const char * const snps_eth_250m_parents[] = { + "clk26m", + "ethpll_d2" +}; + +static const char * const snps_eth_62p4m_ptp_parents[] = { + "apll2_d3", + "apll1_d3", + "clk26m", + "ethpll_d8" +}; + +static const char * const snps_eth_50m_rmii_parents[] = { + "clk26m", + "ethpll_d10" +}; + +static const char * const adsp_parents[] = { + "clk26m", + "clk13m", + "mainpll_d6", + "mainpll_d5_d2", + "univpll_d4_d4", + "univpll_d4", + "ulposc1_d2", + "ulposc1_ck1", + "adsppll", + "adsppll_d2", + "adsppll_d4", + "adsppll_d8" +}; + +static const char * const audio_local_bus_parents[] = { + "clk26m", + "clk13m", + "mainpll_d4_d4", + "mainpll_d7_d2", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d7", + "mainpll_d4", + "univpll_d6", + "ulposc1_ck1", + "ulposc1_d4", + "ulposc1_d2" +}; + +static const char * const asm_h_parents[] = { + "clk26m", + "univpll_d6_d4", + "univpll_d6_d2", + "mainpll_d5_d2" +}; + +static const char * const asm_l_parents[] = { + "clk26m", + "univpll_d6_d4", + "univpll_d6_d2", + "mainpll_d5_d2" +}; + +static const char * const apll1_parents[] = { + "clk26m", + "apll1_d4" +}; + +static const char * const apll2_parents[] = { + "clk26m", + "apll2_d4" +}; + +static const char * const apll3_parents[] = { + "clk26m", + "apll3_d4" +}; + +static const char * const apll4_parents[] = { + "clk26m", + "apll4_d4" +}; + +static const char * const apll5_parents[] = { + "clk26m", + "apll5_d4" +}; + +static const char * const i2so1_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const i2so2_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const i2si1_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const i2si2_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const dptx_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const aud_iec_parents[] = { + "clk26m", + "apll1", + "apll2", + "apll3", + "apll4", + "apll5" +}; + +static const char * const a1sys_hp_parents[] = { + "clk26m", + "apll1_d4" +}; + +static const char * const a2sys_parents[] = { + "clk26m", + "apll2_d4" +}; + +static const char * const a3sys_parents[] = { + "clk26m", + "apll3_d4", + "apll4_d4", + "apll5_d4" +}; + +static const char * const a4sys_parents[] = { + "clk26m", + "apll3_d4", + "apll4_d4", + "apll5_d4" +}; + +static const char * const ecc_parents[] = { + "clk26m", + "mainpll_d4_d4", + "mainpll_d5_d2", + "mainpll_d4_d2", + "mainpll_d6", + "univpll_d6" +}; + +static const char * const spinor_parents[] = { + "clk26m", + "clk13m", + "mainpll_d7_d8", + "univpll_d6_d8" +}; + +static const char * const ulposc_parents[] = { + "ulposc_ck1", + "ethpll_d2", + "mainpll_d4_d2", + "ethpll_d10" +}; + +static const char * const srck_parents[] = { + "ulposc1_d10", + "clk26m" +}; + +static const char * const mfg_fast_ref_parents[] = { + "top_mfg_core_tmp", + "mfgpll" +}; + +static const struct mtk_mux top_mtk_muxes[] = { + /* + * CLK_CFG_0 + * axi_sel and bus_aximem_sel are bus clocks, should not be closed by Linux. + * spm_sel and scp_sel are main clocks in always-on co-processor. + */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_AXI, "top_axi", axi_parents, + 0x020, 0x024, 0x028, 0, 4, 7, 0x04, 0, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SPM, "top_spm", spm_parents, + 0x020, 0x024, 0x028, 8, 4, 15, 0x04, 1, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SCP, "top_scp", scp_parents, + 0x020, 0x024, 0x028, 16, 4, 23, 0x04, 2, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_BUS_AXIMEM, "top_bus_aximem", bus_aximem_parents, + 0x020, 0x024, 0x028, 24, 4, 31, 0x04, 3, CLK_IS_CRITICAL), + /* CLK_CFG_1 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_VPP, "top_vpp", + vpp_parents, 0x02C, 0x030, 0x034, 0, 4, 7, 0x04, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETHDR, "top_ethdr", + ethdr_parents, 0x02C, 0x030, 0x034, 8, 4, 15, 0x04, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_IPE, "top_ipe", + ipe_parents, 0x02C, 0x030, 0x034, 16, 4, 23, 0x04, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAM, "top_cam", + cam_parents, 0x02C, 0x030, 0x034, 24, 4, 31, 0x04, 7), + /* CLK_CFG_2 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_CCU, "top_ccu", + ccu_parents, 0x038, 0x03C, 0x040, 0, 4, 7, 0x04, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CCU_AHB, "top_ccu_ahb", + ccu_ahb_parents, 0x038, 0x03C, 0x040, 8, 4, 15, 0x04, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_IMG, "top_img", + img_parents, 0x038, 0x03C, 0x040, 16, 4, 23, 0x04, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTM, "top_camtm", + camtm_parents, 0x038, 0x03C, 0x040, 24, 4, 31, 0x04, 11), + /* CLK_CFG_3 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP, "top_dsp", + dsp_parents, 0x044, 0x048, 0x04C, 0, 4, 7, 0x04, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP1, "top_dsp1", + dsp1_parents, 0x044, 0x048, 0x04C, 8, 4, 15, 0x04, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP2, "top_dsp2", + dsp2_parents, 0x044, 0x048, 0x04C, 16, 4, 23, 0x04, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP3, "top_dsp3", + dsp3_parents, 0x044, 0x048, 0x04C, 24, 4, 31, 0x04, 15), + /* CLK_CFG_4 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP4, "top_dsp4", + dsp4_parents, 0x050, 0x054, 0x058, 0, 4, 7, 0x04, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP5, "top_dsp5", + dsp5_parents, 0x050, 0x054, 0x058, 8, 4, 15, 0x04, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP6, "top_dsp6", + dsp6_parents, 0x050, 0x054, 0x058, 16, 4, 23, 0x04, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSP7, "top_dsp7", + dsp7_parents, 0x050, 0x054, 0x058, 24, 4, 31, 0x04, 19), + /* CLK_CFG_5 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_CORE_TMP, "top_mfg_core_tmp", + mfg_core_tmp_parents, 0x05C, 0x060, 0x064, 0, 4, 7, 0x04, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG, "top_camtg", + camtg_parents, 0x05C, 0x060, 0x064, 8, 4, 15, 0x04, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG2, "top_camtg2", + camtg2_parents, 0x05C, 0x060, 0x064, 16, 4, 23, 0x04, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG3, "top_camtg3", + camtg3_parents, 0x05C, 0x060, 0x064, 24, 4, 31, 0x04, 23), + /* CLK_CFG_6 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_UART, "top_uart", + uart_parents, 0x068, 0x06C, 0x070, 0, 4, 7, 0x04, 24), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI, "top_spi", + spi_parents, 0x068, 0x06C, 0x070, 8, 4, 15, 0x04, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_HCLK, "top_msdc5hclk", + msdc5hclk_parents, 0x068, 0x06C, 0x070, 16, 4, 23, 0x04, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0, "top_msdc50_0", + msdc50_0_parents, 0x068, 0x06C, 0x070, 24, 4, 31, 0x04, 27), + /* CLK_CFG_7 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1, "top_msdc30_1", + msdc30_1_parents, 0x074, 0x078, 0x07C, 0, 4, 7, 0x04, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2, "top_msdc30_2", + msdc30_2_parents, 0x074, 0x078, 0x07C, 8, 4, 15, 0x04, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_INTDIR, "top_intdir", + intdir_parents, 0x074, 0x078, 0x07C, 16, 4, 23, 0x04, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_INTBUS, "top_aud_intbus", + aud_intbus_parents, 0x074, 0x078, 0x07C, 24, 4, 31, 0x04, 31), + /* CLK_CFG_8 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_H, "top_audio_h", + audio_h_parents, 0x080, 0x084, 0x088, 0, 4, 7, 0x08, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWRAP_ULPOSC, "top_pwrap_ulposc", + pwrap_ulposc_parents, 0x080, 0x084, 0x088, 8, 4, 15, 0x08, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ATB, "top_atb", + atb_parents, 0x080, 0x084, 0x088, 16, 4, 23, 0x08, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPM, "top_sspm", + sspm_parents, 0x080, 0x084, 0x088, 24, 4, 31, 0x08, 3), + /* CLK_CFG_9 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DP, "top_dp", + dp_parents, 0x08C, 0x090, 0x094, 0, 4, 7, 0x08, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP, "top_edp", + edp_parents, 0x08C, 0x090, 0x094, 8, 4, 15, 0x08, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI, "top_dpi", + dpi_parents, 0x08C, 0x090, 0x094, 16, 4, 23, 0x08, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM0, "top_disp_pwm0", + disp_pwm0_parents, 0x08C, 0x090, 0x094, 24, 4, 31, 0x08, 7), + /* CLK_CFG_10 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM1, "top_disp_pwm1", + disp_pwm1_parents, 0x098, 0x09C, 0x0A0, 0, 4, 7, 0x08, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP, "top_usb_top", + usb_parents, 0x098, 0x09C, 0x0A0, 8, 4, 15, 0x08, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSUSB_XHCI, "top_ssusb_xhci", + ssusb_xhci_parents, 0x098, 0x09C, 0x0A0, 16, 4, 23, 0x08, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_2P, "top_usb_top_2p", + usb_2p_parents, 0x098, 0x09C, 0x0A0, 24, 4, 31, 0x08, 11), + /* CLK_CFG_11 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSUSB_XHCI_2P, "top_ssusb_xhci_2p", + ssusb_xhci_2p_parents, 0x0A4, 0x0A8, 0x0AC, 0, 4, 7, 0x08, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_TOP_3P, "top_usb_top_3p", + usb_3p_parents, 0x0A4, 0x0A8, 0x0AC, 8, 4, 15, 0x08, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSUSB_XHCI_3P, "top_ssusb_xhci_3p", + ssusb_xhci_3p_parents, 0x0A4, 0x0A8, 0x0AC, 16, 4, 23, 0x08, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C, "top_i2c", + i2c_parents, 0x0A4, 0x0A8, 0x0AC, 24, 4, 31, 0x08, 15), + /* CLK_CFG_12 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF, "top_seninf", + seninf_parents, 0x0B0, 0x0B4, 0x0B8, 0, 4, 7, 0x08, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SENINF1, "top_seninf1", + seninf1_parents, 0x0B0, 0x0B4, 0x0B8, 8, 4, 15, 0x08, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_GCPU, "top_gcpu", + gcpu_parents, 0x0B0, 0x0B4, 0x0B8, 16, 4, 23, 0x08, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_VENC, "top_venc", + venc_parents, 0x0B0, 0x0B4, 0x0B8, 24, 4, 31, 0x08, 19), + /* + * CLK_CFG_13 + * top_mcupm is main clock in co-processor, should not be handled by Linux. + */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC, "top_vdec", + vdec_parents, 0x0BC, 0x0C0, 0x0C4, 0, 4, 7, 0x08, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM, "top_pwm", + pwm_parents, 0x0BC, 0x0C0, 0x0C4, 8, 4, 15, 0x08, 21), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_MCUPM, "top_mcupm", mcupm_parents, + 0x0BC, 0x0C0, 0x0C4, 16, 4, 23, 0x08, 22, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPMI_P_MST, "top_spmi_p_mst", + spmi_p_mst_parents, 0x0BC, 0x0C0, 0x0C4, 24, 4, 31, 0x08, 23), + /* + * CLK_CFG_14 + * dvfsrc_sel is for internal DVFS usage, should not be handled by Linux. + */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPMI_M_MST, "top_spmi_m_mst", + spmi_m_mst_parents, 0x0C8, 0x0CC, 0x0D0, 0, 4, 7, 0x08, 24), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DVFSRC, "top_dvfsrc", dvfsrc_parents, + 0x0C8, 0x0CC, 0x0D0, 8, 4, 15, 0x08, 25, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_TL, "top_tl", + tl_parents, 0x0C8, 0x0CC, 0x0D0, 16, 4, 23, 0x08, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AES_MSDCFDE, "top_aes_msdcfde", + aes_msdcfde_parents, 0x0C8, 0x0CC, 0x0D0, 24, 4, 31, 0x08, 27), + /* CLK_CFG_15 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DSI_OCC, "top_dsi_occ", + dsi_occ_parents, 0x0D4, 0x0D8, 0x0DC, 0, 4, 7, 0x08, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_WPE_VPP, "top_wpe_vpp", + wpe_vpp_parents, 0x0D4, 0x0D8, 0x0DC, 8, 4, 15, 0x08, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_HDCP, "top_hdcp", + hdcp_parents, 0x0D4, 0x0D8, 0x0DC, 16, 4, 23, 0x08, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_HDCP_24M, "top_hdcp_24m", + hdcp_24m_parents, 0x0D4, 0x0D8, 0x0DC, 24, 4, 31, 0x08, 31), + /* CLK_CFG_16 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_HDMI_APB, "top_hdmi_apb", + hdmi_apb_parents, 0x0E0, 0x0E4, 0x0E8, 0, 4, 7, 0x0C, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SNPS_ETH_250M, "top_snps_eth_250m", + snps_eth_250m_parents, 0x0E0, 0x0E4, 0x0E8, 8, 4, 15, 0x0C, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SNPS_ETH_62P4M_PTP, "top_snps_eth_62p4m_ptp", + snps_eth_62p4m_ptp_parents, 0x0E0, 0x0E4, 0x0E8, 16, 4, 23, 0x0C, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SNPS_ETH_50M_RMII, "snps_eth_50m_rmii", + snps_eth_50m_rmii_parents, 0x0E0, 0x0E4, 0x0E8, 24, 4, 31, 0x0C, 3), + /* CLK_CFG_17 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ADSP, "top_adsp", + adsp_parents, 0x0EC, 0x0F0, 0x0F4, 0, 4, 7, 0x0C, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_LOCAL_BUS, "top_audio_local_bus", + audio_local_bus_parents, 0x0EC, 0x0F0, 0x0F4, 8, 4, 15, 0x0C, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ASM_H, "top_asm_h", + asm_h_parents, 0x0EC, 0x0F0, 0x0F4, 16, 4, 23, 0x0C, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ASM_L, "top_asm_l", + asm_l_parents, 0x0EC, 0x0F0, 0x0F4, 24, 4, 31, 0x0C, 7), + /* CLK_CFG_18 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_APLL1, "top_apll1", + apll1_parents, 0x0F8, 0x0FC, 0x100, 0, 4, 7, 0x0C, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_APLL2, "top_apll2", + apll2_parents, 0x0F8, 0x0FC, 0x100, 8, 4, 15, 0x0C, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_APLL3, "top_apll3", + apll3_parents, 0x0F8, 0x0FC, 0x100, 16, 4, 23, 0x0C, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_APLL4, "top_apll4", + apll4_parents, 0x0F8, 0x0FC, 0x100, 24, 4, 31, 0x0C, 11), + /* CLK_CFG_19 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_APLL5, "top_apll5", + apll5_parents, 0x0104, 0x0108, 0x010C, 0, 4, 7, 0x0C, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2SO1, "top_i2so1", + i2so1_parents, 0x0104, 0x0108, 0x010C, 8, 4, 15, 0x0C, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2SO2, "top_i2so2", + i2so2_parents, 0x0104, 0x0108, 0x010C, 16, 4, 23, 0x0C, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2SI1, "top_i2si1", + i2si1_parents, 0x0104, 0x0108, 0x010C, 24, 4, 31, 0x0C, 15), + /* CLK_CFG_20 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2SI2, "top_i2si2", + i2si2_parents, 0x0110, 0x0114, 0x0118, 0, 4, 7, 0x0C, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DPTX, "top_dptx", + dptx_parents, 0x0110, 0x0114, 0x0118, 8, 4, 15, 0x0C, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_IEC, "top_aud_iec", + aud_iec_parents, 0x0110, 0x0114, 0x0118, 16, 4, 23, 0x0C, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_HP, "top_a1sys_hp", + a1sys_hp_parents, 0x0110, 0x0114, 0x0118, 24, 4, 31, 0x0C, 19), + /* CLK_CFG_21 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_A2SYS, "top_a2sys", + a2sys_parents, 0x011C, 0x0120, 0x0124, 0, 4, 7, 0x0C, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A3SYS, "top_a3sys", + a3sys_parents, 0x011C, 0x0120, 0x0124, 8, 4, 15, 0x0C, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A4SYS, "top_a4sys", + a4sys_parents, 0x011C, 0x0120, 0x0124, 16, 4, 23, 0x0C, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ECC, "top_ecc", + ecc_parents, 0x011C, 0x0120, 0x0124, 24, 4, 31, 0x0C, 23), + /* + * CLK_CFG_22 + * top_ulposc/top_srck are clock source of always on co-processor, + * should not be closed by Linux. + */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINOR, "top_spinor", + spinor_parents, 0x0128, 0x012C, 0x0130, 0, 4, 7, 0x0C, 24), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_ULPOSC, "top_ulposc", ulposc_parents, + 0x0128, 0x012C, 0x0130, 8, 4, 15, 0x0C, 25, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SRCK, "top_srck", srck_parents, + 0x0128, 0x012C, 0x0130, 16, 4, 23, 0x0C, 26, CLK_IS_CRITICAL), +}; + +static const struct mtk_composite top_adj_divs[] = { + DIV_GATE(CLK_TOP_APLL12_CK_DIV0, "apll12_div0", "top_i2si1", 0x0320, 0, 0x0328, 8, 0), + DIV_GATE(CLK_TOP_APLL12_CK_DIV1, "apll12_div1", "top_i2si2", 0x0320, 1, 0x0328, 8, 8), + DIV_GATE(CLK_TOP_APLL12_CK_DIV2, "apll12_div2", "top_i2so1", 0x0320, 2, 0x0328, 8, 16), + DIV_GATE(CLK_TOP_APLL12_CK_DIV3, "apll12_div3", "top_i2so2", 0x0320, 3, 0x0328, 8, 24), + DIV_GATE(CLK_TOP_APLL12_CK_DIV4, "apll12_div4", "top_aud_iec", 0x0320, 4, 0x0334, 8, 0), + DIV_GATE(CLK_TOP_APLL12_CK_DIV9, "apll12_div9", "top_dptx", 0x0320, 9, 0x0338, 8, 8), +}; +static const struct mtk_gate_regs top0_cg_regs = { + .set_ofs = 0x238, + .clr_ofs = 0x238, + .sta_ofs = 0x238, +}; + +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x250, + .clr_ofs = 0x250, + .sta_ofs = 0x250, +}; + +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate top_clks[] = { + /* TOP0 */ + GATE_TOP0(CLK_TOP_CFGREG_CLOCK_EN_VPP0, "cfgreg_clock_vpp0", "top_vpp", 0), + GATE_TOP0(CLK_TOP_CFGREG_CLOCK_EN_VPP1, "cfgreg_clock_vpp1", "top_vpp", 1), + GATE_TOP0(CLK_TOP_CFGREG_CLOCK_EN_VDO0, "cfgreg_clock_vdo0", "top_vpp", 2), + GATE_TOP0(CLK_TOP_CFGREG_CLOCK_EN_VDO1, "cfgreg_clock_vdo1", "top_vpp", 3), + GATE_TOP0(CLK_TOP_CFGREG_CLOCK_ISP_AXI_GALS, "cfgreg_clock_isp_axi_gals", "top_vpp", 4), + GATE_TOP0(CLK_TOP_CFGREG_F26M_VPP0, "cfgreg_f26m_vpp0", "clk26m", 5), + GATE_TOP0(CLK_TOP_CFGREG_F26M_VPP1, "cfgreg_f26m_vpp1", "clk26m", 6), + GATE_TOP0(CLK_TOP_CFGREG_F26M_VDO0, "cfgreg_f26m_vdo0", "clk26m", 7), + GATE_TOP0(CLK_TOP_CFGREG_F26M_VDO1, "cfgreg_f26m_vdo1", "clk26m", 8), + GATE_TOP0(CLK_TOP_CFGREG_AUD_F26M_AUD, "cfgreg_aud_f26m_aud", "clk26m", 9), + GATE_TOP0(CLK_TOP_CFGREG_UNIPLL_SES, "cfgreg_unipll_ses", "univpll_d2", 15), + GATE_TOP0(CLK_TOP_CFGREG_F_PCIE_PHY_REF, "cfgreg_f_pcie_phy_ref", "clk26m", 18), + /* TOP1 */ + GATE_TOP1(CLK_TOP_SSUSB_TOP_REF, "ssusb_ref", "clk26m", 0), + GATE_TOP1(CLK_TOP_SSUSB_PHY_REF, "ssusb_phy_ref", "clk26m", 1), + GATE_TOP1(CLK_TOP_SSUSB_TOP_P1_REF, "ssusb_p1_ref", "clk26m", 2), + GATE_TOP1(CLK_TOP_SSUSB_PHY_P1_REF, "ssusb_phy_p1_ref", "clk26m", 3), + GATE_TOP1(CLK_TOP_SSUSB_TOP_P2_REF, "ssusb_p2_ref", "clk26m", 4), + GATE_TOP1(CLK_TOP_SSUSB_PHY_P2_REF, "ssusb_phy_p2_ref", "clk26m", 5), + GATE_TOP1(CLK_TOP_SSUSB_TOP_P3_REF, "ssusb_p3_ref", "clk26m", 6), + GATE_TOP1(CLK_TOP_SSUSB_PHY_P3_REF, "ssusb_phy_p3_ref", "clk26m", 7), +}; + +static const struct of_device_id of_match_clk_mt8188_topck[] = { + { .compatible = "mediatek,mt8188-topckgen" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_topck); + +/* Register mux notifier for MFG mux */ +static int clk_mt8188_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) +{ + struct mtk_mux_nb *mfg_mux_nb; + + mfg_mux_nb = devm_kzalloc(dev, sizeof(*mfg_mux_nb), GFP_KERNEL); + if (!mfg_mux_nb) + return -ENOMEM; + + mfg_mux_nb->ops = &clk_mux_ops; + mfg_mux_nb->bypass_index = 0; /* Bypass to TOP_MFG_CORE_TMP */ + + return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb); +} + +static int clk_mt8188_topck_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *top_clk_data; + struct device_node *node = pdev->dev.of_node; + struct clk_hw *hw; + int r; + void __iomem *base; + + top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + if (!top_clk_data) + return -ENOMEM; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) { + r = PTR_ERR(base); + goto free_top_data; + } + + r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + top_clk_data); + if (r) + goto free_top_data; + + r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); + if (r) + goto unregister_fixed_clks; + + r = mtk_clk_register_muxes(&pdev->dev, top_mtk_muxes, + ARRAY_SIZE(top_mtk_muxes), node, + &mt8188_clk_lock, top_clk_data); + if (r) + goto unregister_factors; + + hw = devm_clk_hw_register_mux(&pdev->dev, "mfg_ck_fast_ref", mfg_fast_ref_parents, + ARRAY_SIZE(mfg_fast_ref_parents), CLK_SET_RATE_PARENT, + (base + 0x250), 8, 1, 0, &mt8188_clk_lock); + if (IS_ERR(hw)) { + r = PTR_ERR(hw); + goto unregister_muxes; + } + top_clk_data->hws[CLK_TOP_MFG_CK_FAST_REF] = hw; + + r = clk_mt8188_reg_mfg_mux_notifier(&pdev->dev, + top_clk_data->hws[CLK_TOP_MFG_CK_FAST_REF]->clk); + if (r) + goto unregister_muxes; + + r = mtk_clk_register_composites(&pdev->dev, top_adj_divs, + ARRAY_SIZE(top_adj_divs), base, + &mt8188_clk_lock, top_clk_data); + if (r) + goto unregister_muxes; + + r = mtk_clk_register_gates(&pdev->dev, node, top_clks, + ARRAY_SIZE(top_clks), top_clk_data); + if (r) + goto unregister_composite_divs; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data); + if (r) + goto unregister_gates; + + platform_set_drvdata(pdev, top_clk_data); + + return r; + +unregister_gates: + mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data); +unregister_composite_divs: + mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data); +unregister_muxes: + mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data); +unregister_factors: + mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); +unregister_fixed_clks: + mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data); +free_top_data: + mtk_free_clk_data(top_clk_data); + return r; +} + +static int clk_mt8188_topck_remove(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *top_clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data); + mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data); + mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data); + mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); + mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data); + mtk_free_clk_data(top_clk_data); + + return 0; +} + +static struct platform_driver clk_mt8188_topck_drv = { + .probe = clk_mt8188_topck_probe, + .remove = clk_mt8188_topck_remove, + .driver = { + .name = "clk-mt8188-topck", + .of_match_table = of_match_clk_mt8188_topck, + }, +}; +module_platform_driver(clk_mt8188_topck_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-vdec.c b/drivers/clk/mediatek/clk-mt8188-vdec.c new file mode 100644 index 000000000000..8c3d76531753 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-vdec.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vdec0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x4, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs vdec1_cg_regs = { + .set_ofs = 0x200, + .clr_ofs = 0x204, + .sta_ofs = 0x200, +}; + +static const struct mtk_gate_regs vdec2_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x8, +}; + +#define GATE_VDEC0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec0_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) + +#define GATE_VDEC1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) + +#define GATE_VDEC2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdec2_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) + +static const struct mtk_gate vdec1_clks[] = { + /* VDEC1_0 */ + GATE_VDEC0(CLK_VDEC1_SOC_VDEC, "vdec1_soc_vdec", "top_vdec", 0), + GATE_VDEC0(CLK_VDEC1_SOC_VDEC_ACTIVE, "vdec1_soc_vdec_active", "top_vdec", 4), + GATE_VDEC0(CLK_VDEC1_SOC_VDEC_ENG, "vdec1_soc_vdec_eng", "top_vdec", 8), + /* VDEC1_1 */ + GATE_VDEC1(CLK_VDEC1_SOC_LAT, "vdec1_soc_lat", "top_vdec", 0), + GATE_VDEC1(CLK_VDEC1_SOC_LAT_ACTIVE, "vdec1_soc_lat_active", "top_vdec", 4), + GATE_VDEC1(CLK_VDEC1_SOC_LAT_ENG, "vdec1_soc_lat_eng", "top_vdec", 8), + /* VDEC1_2 */ + GATE_VDEC2(CLK_VDEC1_SOC_LARB1, "vdec1_soc_larb1", "top_vdec", 0), +}; + +static const struct mtk_gate vdec2_clks[] = { + /* VDEC2_0 */ + GATE_VDEC0(CLK_VDEC2_VDEC, "vdec2_vdec", "top_vdec", 0), + GATE_VDEC0(CLK_VDEC2_VDEC_ACTIVE, "vdec2_vdec_active", "top_vdec", 4), + GATE_VDEC0(CLK_VDEC2_VDEC_ENG, "vdec2_vdec_eng", "top_vdec", 8), + /* VDEC2_1 */ + GATE_VDEC1(CLK_VDEC2_LAT, "vdec2_lat", "top_vdec", 0), + /* VDEC2_2 */ + GATE_VDEC2(CLK_VDEC2_LARB1, "vdec2_larb1", "top_vdec", 0), +}; + +static const struct mtk_clk_desc vdec1_desc = { + .clks = vdec1_clks, + .num_clks = ARRAY_SIZE(vdec1_clks), +}; + +static const struct mtk_clk_desc vdec2_desc = { + .clks = vdec2_clks, + .num_clks = ARRAY_SIZE(vdec2_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_vdec[] = { + { .compatible = "mediatek,mt8188-vdecsys-soc", .data = &vdec1_desc }, + { .compatible = "mediatek,mt8188-vdecsys", .data = &vdec2_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_vdec); + +static struct platform_driver clk_mt8188_vdec_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-vdec", + .of_match_table = of_match_clk_mt8188_vdec, + }, +}; + +module_platform_driver(clk_mt8188_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-vdo0.c b/drivers/clk/mediatek/clk-mt8188-vdo0.c new file mode 100644 index 000000000000..d2be44c2f3f5 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-vdo0.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vdo0_0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs vdo0_1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs vdo0_2_cg_regs = { + .set_ofs = 0x124, + .clr_ofs = 0x128, + .sta_ofs = 0x120, +}; + +#define GATE_VDO0_0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo0_0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO0_1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo0_1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO0_2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo0_2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO0_2_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &vdo0_2_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flags) + +static const struct mtk_gate vdo0_clks[] = { + /* VDO0_0 */ + GATE_VDO0_0(CLK_VDO0_DISP_OVL0, "vdo0_disp_ovl0", "top_vpp", 0), + GATE_VDO0_0(CLK_VDO0_FAKE_ENG0, "vdo0_fake_eng0", "top_vpp", 2), + GATE_VDO0_0(CLK_VDO0_DISP_CCORR0, "vdo0_disp_ccorr0", "top_vpp", 4), + GATE_VDO0_0(CLK_VDO0_DISP_MUTEX0, "vdo0_disp_mutex0", "top_vpp", 6), + GATE_VDO0_0(CLK_VDO0_DISP_GAMMA0, "vdo0_disp_gamma0", "top_vpp", 8), + GATE_VDO0_0(CLK_VDO0_DISP_DITHER0, "vdo0_disp_dither0", "top_vpp", 10), + GATE_VDO0_0(CLK_VDO0_DISP_WDMA0, "vdo0_disp_wdma0", "top_vpp", 17), + GATE_VDO0_0(CLK_VDO0_DISP_RDMA0, "vdo0_disp_rdma0", "top_vpp", 19), + GATE_VDO0_0(CLK_VDO0_DSI0, "vdo0_dsi0", "top_vpp", 21), + GATE_VDO0_0(CLK_VDO0_DSI1, "vdo0_dsi1", "top_vpp", 22), + GATE_VDO0_0(CLK_VDO0_DSC_WRAP0, "vdo0_dsc_wrap0", "top_vpp", 23), + GATE_VDO0_0(CLK_VDO0_VPP_MERGE0, "vdo0_vpp_merge0", "top_vpp", 24), + GATE_VDO0_0(CLK_VDO0_DP_INTF0, "vdo0_dp_intf0", "top_vpp", 25), + GATE_VDO0_0(CLK_VDO0_DISP_AAL0, "vdo0_disp_aal0", "top_vpp", 26), + GATE_VDO0_0(CLK_VDO0_INLINEROT0, "vdo0_inlinerot0", "top_vpp", 27), + GATE_VDO0_0(CLK_VDO0_APB_BUS, "vdo0_apb_bus", "top_vpp", 28), + GATE_VDO0_0(CLK_VDO0_DISP_COLOR0, "vdo0_disp_color0", "top_vpp", 29), + GATE_VDO0_0(CLK_VDO0_MDP_WROT0, "vdo0_mdp_wrot0", "top_vpp", 30), + GATE_VDO0_0(CLK_VDO0_DISP_RSZ0, "vdo0_disp_rsz0", "top_vpp", 31), + /* VDO0_1 */ + GATE_VDO0_1(CLK_VDO0_DISP_POSTMASK0, "vdo0_disp_postmask0", "top_vpp", 0), + GATE_VDO0_1(CLK_VDO0_FAKE_ENG1, "vdo0_fake_eng1", "top_vpp", 1), + GATE_VDO0_1(CLK_VDO0_DL_ASYNC2, "vdo0_dl_async2", "top_vpp", 5), + GATE_VDO0_1(CLK_VDO0_DL_RELAY3, "vdo0_dl_relay3", "top_vpp", 6), + GATE_VDO0_1(CLK_VDO0_DL_RELAY4, "vdo0_dl_relay4", "top_vpp", 7), + GATE_VDO0_1(CLK_VDO0_SMI_GALS, "vdo0_smi_gals", "top_vpp", 10), + GATE_VDO0_1(CLK_VDO0_SMI_COMMON, "vdo0_smi_common", "top_vpp", 11), + GATE_VDO0_1(CLK_VDO0_SMI_EMI, "vdo0_smi_emi", "top_vpp", 12), + GATE_VDO0_1(CLK_VDO0_SMI_IOMMU, "vdo0_smi_iommu", "top_vpp", 13), + GATE_VDO0_1(CLK_VDO0_SMI_LARB, "vdo0_smi_larb", "top_vpp", 14), + GATE_VDO0_1(CLK_VDO0_SMI_RSI, "vdo0_smi_rsi", "top_vpp", 15), + /* VDO0_2 */ + GATE_VDO0_2(CLK_VDO0_DSI0_DSI, "vdo0_dsi0_dsi", "top_dsi_occ", 0), + GATE_VDO0_2(CLK_VDO0_DSI1_DSI, "vdo0_dsi1_dsi", "top_dsi_occ", 8), + GATE_VDO0_2_FLAGS(CLK_VDO0_DP_INTF0_DP_INTF, "vdo0_dp_intf0_dp_intf", + "top_edp", 16, CLK_SET_RATE_PARENT), +}; + +static const struct mtk_clk_desc vdo0_desc = { + .clks = vdo0_clks, + .num_clks = ARRAY_SIZE(vdo0_clks), +}; + +static const struct platform_device_id clk_mt8188_vdo0_id_table[] = { + { .name = "clk-mt8188-vdo0", .driver_data = (kernel_ulong_t)&vdo0_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8188_vdo0_id_table); + +static struct platform_driver clk_mt8188_vdo0_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8188-vdo0", + }, + .id_table = clk_mt8188_vdo0_id_table, +}; +module_platform_driver(clk_mt8188_vdo0_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-vdo1.c b/drivers/clk/mediatek/clk-mt8188-vdo1.c new file mode 100644 index 000000000000..2ef8cae2e16e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-vdo1.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vdo1_0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs vdo1_1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs vdo1_2_cg_regs = { + .set_ofs = 0x124, + .clr_ofs = 0x128, + .sta_ofs = 0x120, +}; + +static const struct mtk_gate_regs vdo1_3_cg_regs = { + .set_ofs = 0x134, + .clr_ofs = 0x138, + .sta_ofs = 0x130, +}; + +static const struct mtk_gate_regs vdo1_4_cg_regs = { + .set_ofs = 0x144, + .clr_ofs = 0x148, + .sta_ofs = 0x140, +}; + +#define GATE_VDO1_0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo1_0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO1_1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo1_1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO1_2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo1_2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO1_3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo1_3_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VDO1_3_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &vdo1_3_cg_regs, _shift, \ + &mtk_clk_gate_ops_setclr, _flags) + +#define GATE_VDO1_4(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vdo1_4_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate vdo1_clks[] = { + /* VDO1_0 */ + GATE_VDO1_0(CLK_VDO1_SMI_LARB2, "vdo1_smi_larb2", "top_vpp", 0), + GATE_VDO1_0(CLK_VDO1_SMI_LARB3, "vdo1_smi_larb3", "top_vpp", 1), + GATE_VDO1_0(CLK_VDO1_GALS, "vdo1_gals", "top_vpp", 2), + GATE_VDO1_0(CLK_VDO1_FAKE_ENG0, "vdo1_fake_eng0", "top_vpp", 3), + GATE_VDO1_0(CLK_VDO1_FAKE_ENG1, "vdo1_fake_eng1", "top_vpp", 4), + GATE_VDO1_0(CLK_VDO1_MDP_RDMA0, "vdo1_mdp_rdma0", "top_vpp", 5), + GATE_VDO1_0(CLK_VDO1_MDP_RDMA1, "vdo1_mdp_rdma1", "top_vpp", 6), + GATE_VDO1_0(CLK_VDO1_MDP_RDMA2, "vdo1_mdp_rdma2", "top_vpp", 7), + GATE_VDO1_0(CLK_VDO1_MDP_RDMA3, "vdo1_mdp_rdma3", "top_vpp", 8), + GATE_VDO1_0(CLK_VDO1_VPP_MERGE0, "vdo1_vpp_merge0", "top_vpp", 9), + GATE_VDO1_0(CLK_VDO1_VPP_MERGE1, "vdo1_vpp_merge1", "top_vpp", 10), + GATE_VDO1_0(CLK_VDO1_VPP_MERGE2, "vdo1_vpp_merge2", "top_vpp", 11), + /* VDO1_1 */ + GATE_VDO1_1(CLK_VDO1_VPP_MERGE3, "vdo1_vpp_merge3", "top_vpp", 0), + GATE_VDO1_1(CLK_VDO1_VPP_MERGE4, "vdo1_vpp_merge4", "top_vpp", 1), + GATE_VDO1_1(CLK_VDO1_VPP2_TO_VDO1_DL_ASYNC, "vdo1_vpp2_to_vdo1_dl_async", "top_vpp", 2), + GATE_VDO1_1(CLK_VDO1_VPP3_TO_VDO1_DL_ASYNC, "vdo1_vpp3_to_vdo1_dl_async", "top_vpp", 3), + GATE_VDO1_1(CLK_VDO1_DISP_MUTEX, "vdo1_disp_mutex", "top_vpp", 4), + GATE_VDO1_1(CLK_VDO1_MDP_RDMA4, "vdo1_mdp_rdma4", "top_vpp", 5), + GATE_VDO1_1(CLK_VDO1_MDP_RDMA5, "vdo1_mdp_rdma5", "top_vpp", 6), + GATE_VDO1_1(CLK_VDO1_MDP_RDMA6, "vdo1_mdp_rdma6", "top_vpp", 7), + GATE_VDO1_1(CLK_VDO1_MDP_RDMA7, "vdo1_mdp_rdma7", "top_vpp", 8), + GATE_VDO1_1(CLK_VDO1_DP_INTF0_MMCK, "vdo1_dp_intf0_mmck", "top_vpp", 9), + GATE_VDO1_1(CLK_VDO1_DPI0_MM, "vdo1_dpi0_mm_ck", "top_vpp", 10), + GATE_VDO1_1(CLK_VDO1_DPI1_MM, "vdo1_dpi1_mm_ck", "top_vpp", 11), + GATE_VDO1_1(CLK_VDO1_MERGE0_DL_ASYNC, "vdo1_merge0_dl_async", "top_vpp", 13), + GATE_VDO1_1(CLK_VDO1_MERGE1_DL_ASYNC, "vdo1_merge1_dl_async", "top_vpp", 14), + GATE_VDO1_1(CLK_VDO1_MERGE2_DL_ASYNC, "vdo1_merge2_dl_async", "top_vpp", 15), + GATE_VDO1_1(CLK_VDO1_MERGE3_DL_ASYNC, "vdo1_merge3_dl_async", "top_vpp", 16), + GATE_VDO1_1(CLK_VDO1_MERGE4_DL_ASYNC, "vdo1_merge4_dl_async", "top_vpp", 17), + GATE_VDO1_1(CLK_VDO1_DSC_VDO1_DL_ASYNC, "vdo1_dsc_vdo1_dl_async", "top_vpp", 18), + GATE_VDO1_1(CLK_VDO1_MERGE_VDO1_DL_ASYNC, "vdo1_merge_vdo1_dl_async", "top_vpp", 19), + GATE_VDO1_1(CLK_VDO1_PADDING0, "vdo1_padding0", "top_vpp", 20), + GATE_VDO1_1(CLK_VDO1_PADDING1, "vdo1_padding1", "top_vpp", 21), + GATE_VDO1_1(CLK_VDO1_PADDING2, "vdo1_padding2", "top_vpp", 22), + GATE_VDO1_1(CLK_VDO1_PADDING3, "vdo1_padding3", "top_vpp", 23), + GATE_VDO1_1(CLK_VDO1_PADDING4, "vdo1_padding4", "top_vpp", 24), + GATE_VDO1_1(CLK_VDO1_PADDING5, "vdo1_padding5", "top_vpp", 25), + GATE_VDO1_1(CLK_VDO1_PADDING6, "vdo1_padding6", "top_vpp", 26), + GATE_VDO1_1(CLK_VDO1_PADDING7, "vdo1_padding7", "top_vpp", 27), + GATE_VDO1_1(CLK_VDO1_DISP_RSZ0, "vdo1_disp_rsz0", "top_vpp", 28), + GATE_VDO1_1(CLK_VDO1_DISP_RSZ1, "vdo1_disp_rsz1", "top_vpp", 29), + GATE_VDO1_1(CLK_VDO1_DISP_RSZ2, "vdo1_disp_rsz2", "top_vpp", 30), + GATE_VDO1_1(CLK_VDO1_DISP_RSZ3, "vdo1_disp_rsz3", "top_vpp", 31), + /* VDO1_2 */ + GATE_VDO1_2(CLK_VDO1_HDR_VDO_FE0, "vdo1_hdr_vdo_fe0", "top_vpp", 0), + GATE_VDO1_2(CLK_VDO1_HDR_GFX_FE0, "vdo1_hdr_gfx_fe0", "top_vpp", 1), + GATE_VDO1_2(CLK_VDO1_HDR_VDO_BE, "vdo1_hdr_vdo_be", "top_vpp", 2), + GATE_VDO1_2(CLK_VDO1_HDR_VDO_FE1, "vdo1_hdr_vdo_fe1", "top_vpp", 16), + GATE_VDO1_2(CLK_VDO1_HDR_GFX_FE1, "vdo1_hdr_gfx_fe1", "top_vpp", 17), + GATE_VDO1_2(CLK_VDO1_DISP_MIXER, "vdo1_disp_mixer", "top_vpp", 18), + GATE_VDO1_2(CLK_VDO1_HDR_VDO_FE0_DL_ASYNC, "vdo1_hdr_vdo_fe0_dl_async", "top_vpp", 19), + GATE_VDO1_2(CLK_VDO1_HDR_VDO_FE1_DL_ASYNC, "vdo1_hdr_vdo_fe1_dl_async", "top_vpp", 20), + GATE_VDO1_2(CLK_VDO1_HDR_GFX_FE0_DL_ASYNC, "vdo1_hdr_gfx_fe0_dl_async", "top_vpp", 21), + GATE_VDO1_2(CLK_VDO1_HDR_GFX_FE1_DL_ASYNC, "vdo1_hdr_gfx_fe1_dl_async", "top_vpp", 22), + GATE_VDO1_2(CLK_VDO1_HDR_VDO_BE_DL_ASYNC, "vdo1_hdr_vdo_be_dl_async", "top_vpp", 23), + /* VDO1_3 */ + GATE_VDO1_3(CLK_VDO1_DPI0, "vdo1_dpi0_ck", "top_vpp", 0), + GATE_VDO1_3(CLK_VDO1_DISP_MONITOR_DPI0, "vdo1_disp_monitor_dpi0_ck", "top_vpp", 1), + GATE_VDO1_3(CLK_VDO1_DPI1, "vdo1_dpi1_ck", "top_vpp", 8), + GATE_VDO1_3(CLK_VDO1_DISP_MONITOR_DPI1, "vdo1_disp_monitor_dpi1_ck", "top_vpp", 9), + GATE_VDO1_3_FLAGS(CLK_VDO1_DPINTF, "vdo1_dpintf", "top_dp", 16, CLK_SET_RATE_PARENT), + GATE_VDO1_3(CLK_VDO1_DISP_MONITOR_DPINTF, "vdo1_disp_monitor_dpintf_ck", "top_vpp", 17), + /* VDO1_4 */ + GATE_VDO1_4(CLK_VDO1_26M_SLOW, "vdo1_26m_slow_ck", "clk26m", 8), +}; + +static const struct mtk_clk_desc vdo1_desc = { + .clks = vdo1_clks, + .num_clks = ARRAY_SIZE(vdo1_clks), +}; + +static const struct platform_device_id clk_mt8188_vdo1_id_table[] = { + { .name = "clk-mt8188-vdo1", .driver_data = (kernel_ulong_t)&vdo1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8188_vdo1_id_table); + +static struct platform_driver clk_mt8188_vdo1_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8188-vdo1", + }, + .id_table = clk_mt8188_vdo1_id_table, +}; +module_platform_driver(clk_mt8188_vdo1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-venc.c b/drivers/clk/mediatek/clk-mt8188-venc.c new file mode 100644 index 000000000000..245367f33fa5 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-venc.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs venc1_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_VENC1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &venc1_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) + +static const struct mtk_gate venc1_clks[] = { + GATE_VENC1(CLK_VENC1_LARB, "venc1_larb", "top_venc", 0), + GATE_VENC1(CLK_VENC1_VENC, "venc1_venc", "top_venc", 4), + GATE_VENC1(CLK_VENC1_JPGENC, "venc1_jpgenc", "top_venc", 8), + GATE_VENC1(CLK_VENC1_JPGDEC, "venc1_jpgdec", "top_venc", 12), + GATE_VENC1(CLK_VENC1_JPGDEC_C1, "venc1_jpgdec_c1", "top_venc", 16), + GATE_VENC1(CLK_VENC1_GALS, "venc1_gals", "top_venc", 28), + GATE_VENC1(CLK_VENC1_GALS_SRAM, "venc1_gals_sram", "top_venc", 31), +}; + +static const struct mtk_clk_desc venc1_desc = { + .clks = venc1_clks, + .num_clks = ARRAY_SIZE(venc1_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_venc1[] = { + { .compatible = "mediatek,mt8188-vencsys", .data = &venc1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_venc1); + +static struct platform_driver clk_mt8188_venc1_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-venc1", + .of_match_table = of_match_clk_mt8188_venc1, + }, +}; + +module_platform_driver(clk_mt8188_venc1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-vpp0.c b/drivers/clk/mediatek/clk-mt8188-vpp0.c new file mode 100644 index 000000000000..07bdedf6a21a --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-vpp0.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vpp0_0_cg_regs = { + .set_ofs = 0x24, + .clr_ofs = 0x28, + .sta_ofs = 0x20, +}; + +static const struct mtk_gate_regs vpp0_1_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x34, + .sta_ofs = 0x2c, +}; + +static const struct mtk_gate_regs vpp0_2_cg_regs = { + .set_ofs = 0x3c, + .clr_ofs = 0x40, + .sta_ofs = 0x38, +}; + +#define GATE_VPP0_0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vpp0_0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VPP0_1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vpp0_1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VPP0_2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vpp0_2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate vpp0_clks[] = { + /* VPP0_0 */ + GATE_VPP0_0(CLK_VPP0_MDP_FG, "vpp0_mdp_fg", "top_vpp", 1), + GATE_VPP0_0(CLK_VPP0_STITCH, "vpp0_stitch", "top_vpp", 2), + GATE_VPP0_0(CLK_VPP0_PADDING, "vpp0_padding", "top_vpp", 7), + GATE_VPP0_0(CLK_VPP0_MDP_TCC, "vpp0_mdp_tcc", "top_vpp", 8), + GATE_VPP0_0(CLK_VPP0_WARP0_ASYNC_TX, "vpp0_warp0_async_tx", "top_vpp", 10), + GATE_VPP0_0(CLK_VPP0_WARP1_ASYNC_TX, "vpp0_warp1_async_tx", "top_vpp", 11), + GATE_VPP0_0(CLK_VPP0_MUTEX, "vpp0_mutex", "top_vpp", 13), + GATE_VPP0_0(CLK_VPP02VPP1_RELAY, "vpp02vpp1_relay", "top_vpp", 14), + GATE_VPP0_0(CLK_VPP0_VPP12VPP0_ASYNC, "vpp0_vpp12vpp0_async", "top_vpp", 15), + GATE_VPP0_0(CLK_VPP0_MMSYSRAM_TOP, "vpp0_mmsysram_top", "top_vpp", 16), + GATE_VPP0_0(CLK_VPP0_MDP_AAL, "vpp0_mdp_aal", "top_vpp", 17), + GATE_VPP0_0(CLK_VPP0_MDP_RSZ, "vpp0_mdp_rsz", "top_vpp", 18), + /* VPP0_1 */ + GATE_VPP0_1(CLK_VPP0_SMI_COMMON_MMSRAM, "vpp0_smi_common_mmsram", "top_vpp", 0), + GATE_VPP0_1(CLK_VPP0_GALS_VDO0_LARB0_MMSRAM, "vpp0_gals_vdo0_larb0_mmsram", "top_vpp", 1), + GATE_VPP0_1(CLK_VPP0_GALS_VDO0_LARB1_MMSRAM, "vpp0_gals_vdo0_larb1_mmsram", "top_vpp", 2), + GATE_VPP0_1(CLK_VPP0_GALS_VENCSYS_MMSRAM, "vpp0_gals_vencsys_mmsram", "top_vpp", 3), + GATE_VPP0_1(CLK_VPP0_GALS_VENCSYS_CORE1_MMSRAM, + "vpp0_gals_vencsys_core1_mmsram", "top_vpp", 4), + GATE_VPP0_1(CLK_VPP0_GALS_INFRA_MMSRAM, "vpp0_gals_infra_mmsram", "top_vpp", 5), + GATE_VPP0_1(CLK_VPP0_GALS_CAMSYS_MMSRAM, "vpp0_gals_camsys_mmsram", "top_vpp", 6), + GATE_VPP0_1(CLK_VPP0_GALS_VPP1_LARB5_MMSRAM, "vpp0_gals_vpp1_larb5_mmsram", "top_vpp", 7), + GATE_VPP0_1(CLK_VPP0_GALS_VPP1_LARB6_MMSRAM, "vpp0_gals_vpp1_larb6_mmsram", "top_vpp", 8), + GATE_VPP0_1(CLK_VPP0_SMI_REORDER_MMSRAM, "vpp0_smi_reorder_mmsram", "top_vpp", 9), + GATE_VPP0_1(CLK_VPP0_SMI_IOMMU, "vpp0_smi_iommu", "top_vpp", 10), + GATE_VPP0_1(CLK_VPP0_GALS_IMGSYS_CAMSYS, "vpp0_gals_imgsys_camsys", "top_vpp", 11), + GATE_VPP0_1(CLK_VPP0_MDP_RDMA, "vpp0_mdp_rdma", "top_vpp", 12), + GATE_VPP0_1(CLK_VPP0_MDP_WROT, "vpp0_mdp_wrot", "top_vpp", 13), + GATE_VPP0_1(CLK_VPP0_GALS_EMI0_EMI1, "vpp0_gals_emi0_emi1", "top_vpp", 16), + GATE_VPP0_1(CLK_VPP0_SMI_SUB_COMMON_REORDER, "vpp0_smi_sub_common_reorder", "top_vpp", 17), + GATE_VPP0_1(CLK_VPP0_SMI_RSI, "vpp0_smi_rsi", "top_vpp", 18), + GATE_VPP0_1(CLK_VPP0_SMI_COMMON_LARB4, "vpp0_smi_common_larb4", "top_vpp", 19), + GATE_VPP0_1(CLK_VPP0_GALS_VDEC_VDEC_CORE1, "vpp0_gals_vdec_vdec_core1", "top_vpp", 20), + GATE_VPP0_1(CLK_VPP0_GALS_VPP1_WPESYS, "vpp0_gals_vpp1_wpesys", "top_vpp", 21), + GATE_VPP0_1(CLK_VPP0_GALS_VDO0_VDO1_VENCSYS_CORE1, + "vpp0_gals_vdo0_vdo1_vencsys_core1", "top_vpp", 22), + GATE_VPP0_1(CLK_VPP0_FAKE_ENG, "vpp0_fake_eng", "top_vpp", 23), + GATE_VPP0_1(CLK_VPP0_MDP_HDR, "vpp0_mdp_hdr", "top_vpp", 24), + GATE_VPP0_1(CLK_VPP0_MDP_TDSHP, "vpp0_mdp_tdshp", "top_vpp", 25), + GATE_VPP0_1(CLK_VPP0_MDP_COLOR, "vpp0_mdp_color", "top_vpp", 26), + GATE_VPP0_1(CLK_VPP0_MDP_OVL, "vpp0_mdp_ovl", "top_vpp", 27), + GATE_VPP0_1(CLK_VPP0_DSIP_RDMA, "vpp0_dsip_rdma", "top_vpp", 28), + GATE_VPP0_1(CLK_VPP0_DISP_WDMA, "vpp0_disp_wdma", "top_vpp", 29), + GATE_VPP0_1(CLK_VPP0_MDP_HMS, "vpp0_mdp_hms", "top_vpp", 30), + /* VPP0_2 */ + GATE_VPP0_2(CLK_VPP0_WARP0_RELAY, "vpp0_warp0_relay", "top_wpe_vpp", 0), + GATE_VPP0_2(CLK_VPP0_WARP0_ASYNC, "vpp0_warp0_async", "top_wpe_vpp", 1), + GATE_VPP0_2(CLK_VPP0_WARP1_RELAY, "vpp0_warp1_relay", "top_wpe_vpp", 2), + GATE_VPP0_2(CLK_VPP0_WARP1_ASYNC, "vpp0_warp1_async", "top_wpe_vpp", 3), +}; + +static const struct mtk_clk_desc vpp0_desc = { + .clks = vpp0_clks, + .num_clks = ARRAY_SIZE(vpp0_clks), +}; + +static const struct platform_device_id clk_mt8188_vpp0_id_table[] = { + { .name = "clk-mt8188-vpp0", .driver_data = (kernel_ulong_t)&vpp0_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8188_vpp0_id_table); + +static struct platform_driver clk_mt8188_vpp0_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8188-vpp0", + }, + .id_table = clk_mt8188_vpp0_id_table, +}; +module_platform_driver(clk_mt8188_vpp0_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-vpp1.c b/drivers/clk/mediatek/clk-mt8188-vpp1.c new file mode 100644 index 000000000000..d4e66b240573 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-vpp1.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs vpp1_0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs vpp1_1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +#define GATE_VPP1_0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vpp1_0_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +#define GATE_VPP1_1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &vpp1_1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) + +static const struct mtk_gate vpp1_clks[] = { + /* VPP1_0 */ + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_OVL, "vpp1_svpp1_mdp_ovl", "top_vpp", 0), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_TCC, "vpp1_svpp1_mdp_tcc", "top_vpp", 1), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_WROT, "vpp1_svpp1_mdp_wrot", "top_vpp", 2), + GATE_VPP1_0(CLK_VPP1_SVPP1_VPP_PAD, "vpp1_svpp1_vpp_pad", "top_vpp", 3), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_WROT, "vpp1_svpp2_mdp_wrot", "top_vpp", 4), + GATE_VPP1_0(CLK_VPP1_SVPP2_VPP_PAD, "vpp1_svpp2_vpp_pad", "top_vpp", 5), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_WROT, "vpp1_svpp3_mdp_wrot", "top_vpp", 6), + GATE_VPP1_0(CLK_VPP1_SVPP3_VPP_PAD, "vpp1_svpp3_vpp_pad", "top_vpp", 7), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_RDMA, "vpp1_svpp1_mdp_rdma", "top_vpp", 8), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_FG, "vpp1_svpp1_mdp_fg", "top_vpp", 9), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_RDMA, "vpp1_svpp2_mdp_rdma", "top_vpp", 10), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_FG, "vpp1_svpp2_mdp_fg", "top_vpp", 11), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_RDMA, "vpp1_svpp3_mdp_rdma", "top_vpp", 12), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_FG, "vpp1_svpp3_mdp_fg", "top_vpp", 13), + GATE_VPP1_0(CLK_VPP1_VPP_SPLIT, "vpp1_vpp_split", "top_vpp", 14), + GATE_VPP1_0(CLK_VPP1_SVPP2_VDO0_DL_RELAY, "vpp1_svpp2_vdo0_dl_relay", "top_vpp", 15), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_RSZ, "vpp1_svpp1_mdp_rsz", "top_vpp", 16), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_TDSHP, "vpp1_svpp1_mdp_tdshp", "top_vpp", 17), + GATE_VPP1_0(CLK_VPP1_SVPP1_MDP_COLOR, "vpp1_svpp1_mdp_color", "top_vpp", 18), + GATE_VPP1_0(CLK_VPP1_SVPP3_VDO1_DL_RELAY, "vpp1_svpp3_vdo1_dl_relay", "top_vpp", 19), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_RSZ, "vpp1_svpp2_mdp_rsz", "top_vpp", 20), + GATE_VPP1_0(CLK_VPP1_SVPP2_VPP_MERGE, "vpp1_svpp2_vpp_merge", "top_vpp", 21), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_TDSHP, "vpp1_svpp2_mdp_tdshp", "top_vpp", 22), + GATE_VPP1_0(CLK_VPP1_SVPP2_MDP_COLOR, "vpp1_svpp2_mdp_color", "top_vpp", 23), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_RSZ, "vpp1_svpp3_mdp_rsz", "top_vpp", 24), + GATE_VPP1_0(CLK_VPP1_SVPP3_VPP_MERGE, "vpp1_svpp3_vpp_merge", "top_vpp", 25), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_TDSHP, "vpp1_svpp3_mdp_tdshp", "top_vpp", 26), + GATE_VPP1_0(CLK_VPP1_SVPP3_MDP_COLOR, "vpp1_svpp3_mdp_color", "top_vpp", 27), + GATE_VPP1_0(CLK_VPP1_GALS5, "vpp1_gals5", "top_vpp", 28), + GATE_VPP1_0(CLK_VPP1_GALS6, "vpp1_gals6", "top_vpp", 29), + GATE_VPP1_0(CLK_VPP1_LARB5, "vpp1_larb5", "top_vpp", 30), + GATE_VPP1_0(CLK_VPP1_LARB6, "vpp1_larb6", "top_vpp", 31), + /* VPP1_1 */ + GATE_VPP1_1(CLK_VPP1_SVPP1_MDP_HDR, "vpp1_svpp1_mdp_hdr", "top_vpp", 0), + GATE_VPP1_1(CLK_VPP1_SVPP1_MDP_AAL, "vpp1_svpp1_mdp_aal", "top_vpp", 1), + GATE_VPP1_1(CLK_VPP1_SVPP2_MDP_HDR, "vpp1_svpp2_mdp_hdr", "top_vpp", 2), + GATE_VPP1_1(CLK_VPP1_SVPP2_MDP_AAL, "vpp1_svpp2_mdp_aal", "top_vpp", 3), + GATE_VPP1_1(CLK_VPP1_SVPP3_MDP_HDR, "vpp1_svpp3_mdp_hdr", "top_vpp", 4), + GATE_VPP1_1(CLK_VPP1_SVPP3_MDP_AAL, "vpp1_svpp3_mdp_aal", "top_vpp", 5), + GATE_VPP1_1(CLK_VPP1_DISP_MUTEX, "vpp1_disp_mutex", "top_vpp", 7), + GATE_VPP1_1(CLK_VPP1_SVPP2_VDO1_DL_RELAY, "vpp1_svpp2_vdo1_dl_relay", "top_vpp", 8), + GATE_VPP1_1(CLK_VPP1_SVPP3_VDO0_DL_RELAY, "vpp1_svpp3_vdo0_dl_relay", "top_vpp", 9), + GATE_VPP1_1(CLK_VPP1_VPP0_DL_ASYNC, "vpp1_vpp0_dl_async", "top_vpp", 10), + GATE_VPP1_1(CLK_VPP1_VPP0_DL1_RELAY, "vpp1_vpp0_dl1_relay", "top_vpp", 11), + GATE_VPP1_1(CLK_VPP1_LARB5_FAKE_ENG, "vpp1_larb5_fake_eng", "top_vpp", 12), + GATE_VPP1_1(CLK_VPP1_LARB6_FAKE_ENG, "vpp1_larb6_fake_eng", "top_vpp", 13), + GATE_VPP1_1(CLK_VPP1_HDMI_META, "vpp1_hdmi_meta", "top_vpp", 16), + GATE_VPP1_1(CLK_VPP1_VPP_SPLIT_HDMI, "vpp1_vpp_split_hdmi", "top_vpp", 17), + GATE_VPP1_1(CLK_VPP1_DGI_IN, "vpp1_dgi_in", "top_vpp", 18), + GATE_VPP1_1(CLK_VPP1_DGI_OUT, "vpp1_dgi_out", "top_vpp", 19), + GATE_VPP1_1(CLK_VPP1_VPP_SPLIT_DGI, "vpp1_vpp_split_dgi", "top_vpp", 20), + GATE_VPP1_1(CLK_VPP1_DL_CON_OCC, "vpp1_dl_con_occ", "top_vpp", 21), + GATE_VPP1_1(CLK_VPP1_VPP_SPLIT_26M, "vpp1_vpp_split_26m", "top_vpp", 26), +}; + +static const struct mtk_clk_desc vpp1_desc = { + .clks = vpp1_clks, + .num_clks = ARRAY_SIZE(vpp1_clks), +}; + +static const struct platform_device_id clk_mt8188_vpp1_id_table[] = { + { .name = "clk-mt8188-vpp1", .driver_data = (kernel_ulong_t)&vpp1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8188_vpp1_id_table); + +static struct platform_driver clk_mt8188_vpp1_drv = { + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, + .driver = { + .name = "clk-mt8188-vpp1", + }, + .id_table = clk_mt8188_vpp1_id_table, +}; +module_platform_driver(clk_mt8188_vpp1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-wpe.c b/drivers/clk/mediatek/clk-mt8188-wpe.c new file mode 100644 index 000000000000..393ac38a2172 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8188-wpe.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Garmin Chang + */ + +#include +#include +#include + +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +static const struct mtk_gate_regs wpe_top_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x0, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs wpe_vpp0_0_cg_regs = { + .set_ofs = 0x58, + .clr_ofs = 0x58, + .sta_ofs = 0x58, +}; + +static const struct mtk_gate_regs wpe_vpp0_1_cg_regs = { + .set_ofs = 0x5c, + .clr_ofs = 0x5c, + .sta_ofs = 0x5c, +}; + +#define GATE_WPE_TOP(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &wpe_top_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_WPE_VPP0_0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &wpe_vpp0_0_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_WPE_VPP0_1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &wpe_vpp0_1_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate wpe_top_clks[] = { + GATE_WPE_TOP(CLK_WPE_TOP_WPE_VPP0, "wpe_wpe_vpp0", "top_wpe_vpp", 16), + GATE_WPE_TOP(CLK_WPE_TOP_SMI_LARB7, "wpe_smi_larb7", "top_wpe_vpp", 18), + GATE_WPE_TOP(CLK_WPE_TOP_WPESYS_EVENT_TX, "wpe_wpesys_event_tx", "top_wpe_vpp", 20), + GATE_WPE_TOP(CLK_WPE_TOP_SMI_LARB7_PCLK_EN, "wpe_smi_larb7_p_en", "top_wpe_vpp", 24), +}; + +static const struct mtk_gate wpe_vpp0_clks[] = { + /* WPE_VPP00 */ + GATE_WPE_VPP0_0(CLK_WPE_VPP0_VGEN, "wpe_vpp0_vgen", "top_img", 0), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_EXT, "wpe_vpp0_ext", "top_img", 1), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_VFC, "wpe_vpp0_vfc", "top_img", 2), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH0_TOP, "wpe_vpp0_cach0_top", "top_img", 3), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH0_DMA, "wpe_vpp0_cach0_dma", "top_img", 4), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH1_TOP, "wpe_vpp0_cach1_top", "top_img", 5), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH1_DMA, "wpe_vpp0_cach1_dma", "top_img", 6), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH2_TOP, "wpe_vpp0_cach2_top", "top_img", 7), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH2_DMA, "wpe_vpp0_cach2_dma", "top_img", 8), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH3_TOP, "wpe_vpp0_cach3_top", "top_img", 9), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_CACH3_DMA, "wpe_vpp0_cach3_dma", "top_img", 10), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_PSP, "wpe_vpp0_psp", "top_img", 11), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_PSP2, "wpe_vpp0_psp2", "top_img", 12), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_SYNC, "wpe_vpp0_sync", "top_img", 13), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_C24, "wpe_vpp0_c24", "top_img", 14), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_MDP_CROP, "wpe_vpp0_mdp_crop", "top_img", 15), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_ISP_CROP, "wpe_vpp0_isp_crop", "top_img", 16), + GATE_WPE_VPP0_0(CLK_WPE_VPP0_TOP, "wpe_vpp0_top", "top_img", 17), + /* WPE_VPP0_1 */ + GATE_WPE_VPP0_1(CLK_WPE_VPP0_VECI, "wpe_vpp0_veci", "top_img", 0), + GATE_WPE_VPP0_1(CLK_WPE_VPP0_VEC2I, "wpe_vpp0_vec2i", "top_img", 1), + GATE_WPE_VPP0_1(CLK_WPE_VPP0_VEC3I, "wpe_vpp0_vec3i", "top_img", 2), + GATE_WPE_VPP0_1(CLK_WPE_VPP0_WPEO, "wpe_vpp0_wpeo", "top_img", 3), + GATE_WPE_VPP0_1(CLK_WPE_VPP0_MSKO, "wpe_vpp0_msko", "top_img", 4), +}; + +static const struct mtk_clk_desc wpe_top_desc = { + .clks = wpe_top_clks, + .num_clks = ARRAY_SIZE(wpe_top_clks), +}; + +static const struct mtk_clk_desc wpe_vpp0_desc = { + .clks = wpe_vpp0_clks, + .num_clks = ARRAY_SIZE(wpe_vpp0_clks), +}; + +static const struct of_device_id of_match_clk_mt8188_wpe[] = { + { .compatible = "mediatek,mt8188-wpesys", .data = &wpe_top_desc }, + { .compatible = "mediatek,mt8188-wpesys-vpp0", .data = &wpe_vpp0_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8188_wpe); + +static struct platform_driver clk_mt8188_wpe_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8188-wpe", + .of_match_table = of_match_clk_mt8188_wpe, + }, +}; + +module_platform_driver(clk_mt8188_wpe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-apmixedsys.c b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c new file mode 100644 index 000000000000..eafd34297b9a --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8192-apmixedsys.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 MediaTek Inc. + * Chun-Jie Chen + * Copyright (c) 2023 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include "clk-fhctl.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" +#include "clk-pllfh.h" + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x14, + .clr_ofs = 0x14, + .sta_ofs = 0x14, +}; + +#define GATE_APMIXED(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) + +static const struct mtk_gate apmixed_clks[] = { + GATE_APMIXED(CLK_APMIXED_MIPID26M, "mipid26m", "clk26m", 16), +}; + +#define MT8192_PLL_FMAX (3800UL * MHZ) +#define MT8192_PLL_FMIN (1500UL * MHZ) +#define MT8192_INTEGER_BITS 8 + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, _pcw_chg_reg, \ + _en_reg, _pll_en_bit) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8192_PLL_FMAX, \ + .fmin = MT8192_PLL_FMIN, \ + .pcwbits = _pcwbits, \ + .pcwibits = MT8192_INTEGER_BITS, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .en_reg = _en_reg, \ + .pll_en_bit = _pll_en_bit, \ + } + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift) \ + PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, 0, 0, 0) + +static const struct mtk_pll_data plls[] = { + PLL_B(CLK_APMIXED_MAINPLL, "mainpll", 0x0340, 0x034c, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0344, 24, 0, 0, 0, 0x0344, 0), + PLL_B(CLK_APMIXED_UNIVPLL, "univpll", 0x0308, 0x0314, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x030c, 24, 0, 0, 0, 0x030c, 0), + PLL(CLK_APMIXED_USBPLL, "usbpll", 0x03c4, 0x03cc, 0x00000000, + 0, 0, 22, 0x03c4, 24, 0, 0, 0, 0x03c4, 0, 0x03c4, 0x03cc, 2), + PLL_B(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0350, 0x035c, 0x00000000, + 0, 0, 22, 0x0354, 24, 0, 0, 0, 0x0354, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0360, 0x036c, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0364, 24, 0, 0, 0, 0x0364, 0), + PLL_B(CLK_APMIXED_ADSPPLL, "adsppll", 0x0370, 0x037c, 0xff000000, + HAVE_RST_BAR, BIT(23), 22, 0x0374, 24, 0, 0, 0, 0x0374, 0), + PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0268, 0x0274, 0x00000000, + 0, 0, 22, 0x026c, 24, 0, 0, 0, 0x026c, 0), + PLL_B(CLK_APMIXED_TVDPLL, "tvdpll", 0x0380, 0x038c, 0x00000000, + 0, 0, 22, 0x0384, 24, 0, 0, 0, 0x0384, 0), + PLL_B(CLK_APMIXED_APLL1, "apll1", 0x0318, 0x0328, 0x00000000, + 0, 0, 32, 0x031c, 24, 0x0040, 0x000c, 0, 0x0320, 0), + PLL_B(CLK_APMIXED_APLL2, "apll2", 0x032c, 0x033c, 0x00000000, + 0, 0, 32, 0x0330, 24, 0, 0, 0, 0x0334, 0), +}; + +enum fh_pll_id { + FH_ARMPLL_LL, + FH_ARMPLL_BL0, + FH_ARMPLL_BL1, + FH_ARMPLL_BL2, + FH_ARMPLL_BL3, + FH_CCIPLL, + FH_MFGPLL, + FH_MEMPLL, + FH_MPLL, + FH_MMPLL, + FH_MAINPLL, + FH_MSDCPLL, + FH_ADSPPLL, + FH_APUPLL, + FH_TVDPLL, + FH_NR_FH, +}; + +#define FH(_pllid, _fhid, _offset) { \ + .data = { \ + .pll_id = _pllid, \ + .fh_id = _fhid, \ + .fh_ver = FHCTL_PLLFH_V2, \ + .fhx_offset = _offset, \ + .dds_mask = GENMASK(21, 0), \ + .slope0_value = 0x6003c97, \ + .slope1_value = 0x6003c97, \ + .sfstrx_en = BIT(2), \ + .frddsx_en = BIT(1), \ + .fhctlx_en = BIT(0), \ + .tgl_org = BIT(31), \ + .dvfs_tri = BIT(31), \ + .pcwchg = BIT(31), \ + .dt_val = 0x0, \ + .df_val = 0x9, \ + .updnlmt_shft = 16, \ + .msk_frddsx_dys = GENMASK(23, 20), \ + .msk_frddsx_dts = GENMASK(19, 16), \ + }, \ + } + +static struct mtk_pllfh_data pllfhs[] = { + FH(CLK_APMIXED_MFGPLL, FH_MFGPLL, 0xb4), + FH(CLK_APMIXED_MMPLL, FH_MMPLL, 0xf0), + FH(CLK_APMIXED_MAINPLL, FH_MAINPLL, 0x104), + FH(CLK_APMIXED_MSDCPLL, FH_MSDCPLL, 0x118), + FH(CLK_APMIXED_ADSPPLL, FH_ADSPPLL, 0x12c), + FH(CLK_APMIXED_TVDPLL, FH_TVDPLL, 0x154), +}; + +static const struct of_device_id of_match_clk_mt8192_apmixed[] = { + { .compatible = "mediatek,mt8192-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_apmixed); + +static int clk_mt8192_apmixed_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + const u8 *fhctl_node = "mediatek,mt8192-fhctl"; + int r; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); + + r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + pllfhs, ARRAY_SIZE(pllfhs), clk_data); + if (r) + goto free_clk_data; + + r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, + ARRAY_SIZE(apmixed_clks), clk_data); + if (r) + goto unregister_plls; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_gates; + + return r; + +unregister_gates: + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); +unregister_plls: + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + return r; +} + +static int clk_mt8192_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + +static struct platform_driver clk_mt8192_apmixed_drv = { + .driver = { + .name = "clk-mt8192-apmixed", + .of_match_table = of_match_clk_mt8192_apmixed, + }, + .probe = clk_mt8192_apmixed_probe, + .remove = clk_mt8192_apmixed_remove, +}; +module_platform_driver(clk_mt8192_apmixed_drv); +MODULE_DESCRIPTION("MediaTek MT8192 apmixed clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-aud.c b/drivers/clk/mediatek/clk-mt8192-aud.c index 29affb68e854..ee251492d4f1 100644 --- a/drivers/clk/mediatek/clk-mt8192-aud.c +++ b/drivers/clk/mediatek/clk-mt8192-aud.c @@ -107,6 +107,7 @@ static const struct of_device_id of_match_clk_mt8192_aud[] = { { .compatible = "mediatek,mt8192-audsys", .data = &aud_desc }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_aud); static struct platform_driver clk_mt8192_aud_drv = { .probe = clk_mt8192_aud_probe, @@ -116,5 +117,5 @@ static struct platform_driver clk_mt8192_aud_drv = { .of_match_table = of_match_clk_mt8192_aud, }, }; - -builtin_platform_driver(clk_mt8192_aud_drv); +module_platform_driver(clk_mt8192_aud_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-cam.c b/drivers/clk/mediatek/clk-mt8192-cam.c index 90b57d46eef7..7befd6ee8c79 100644 --- a/drivers/clk/mediatek/clk-mt8192-cam.c +++ b/drivers/clk/mediatek/clk-mt8192-cam.c @@ -95,6 +95,7 @@ static const struct of_device_id of_match_clk_mt8192_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_cam); static struct platform_driver clk_mt8192_cam_drv = { .probe = mtk_clk_simple_probe, @@ -104,5 +105,5 @@ static struct platform_driver clk_mt8192_cam_drv = { .of_match_table = of_match_clk_mt8192_cam, }, }; - -builtin_platform_driver(clk_mt8192_cam_drv); +module_platform_driver(clk_mt8192_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-img.c b/drivers/clk/mediatek/clk-mt8192-img.c index da82d65a7650..a7505150a9d0 100644 --- a/drivers/clk/mediatek/clk-mt8192-img.c +++ b/drivers/clk/mediatek/clk-mt8192-img.c @@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8192_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_img); static struct platform_driver clk_mt8192_img_drv = { .probe = mtk_clk_simple_probe, @@ -67,5 +68,5 @@ static struct platform_driver clk_mt8192_img_drv = { .of_match_table = of_match_clk_mt8192_img, }, }; - -builtin_platform_driver(clk_mt8192_img_drv); +module_platform_driver(clk_mt8192_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c index ff8e20bb44bb..cd5d00a7c54b 100644 --- a/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c @@ -107,6 +107,7 @@ static const struct of_device_id of_match_clk_mt8192_imp_iic_wrap[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_imp_iic_wrap); static struct platform_driver clk_mt8192_imp_iic_wrap_drv = { .probe = mtk_clk_simple_probe, @@ -116,5 +117,5 @@ static struct platform_driver clk_mt8192_imp_iic_wrap_drv = { .of_match_table = of_match_clk_mt8192_imp_iic_wrap, }, }; - -builtin_platform_driver(clk_mt8192_imp_iic_wrap_drv); +module_platform_driver(clk_mt8192_imp_iic_wrap_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-ipe.c b/drivers/clk/mediatek/clk-mt8192-ipe.c index 0225abe4170a..dee671ae38e6 100644 --- a/drivers/clk/mediatek/clk-mt8192-ipe.c +++ b/drivers/clk/mediatek/clk-mt8192-ipe.c @@ -45,6 +45,7 @@ static const struct of_device_id of_match_clk_mt8192_ipe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_ipe); static struct platform_driver clk_mt8192_ipe_drv = { .probe = mtk_clk_simple_probe, @@ -54,5 +55,5 @@ static struct platform_driver clk_mt8192_ipe_drv = { .of_match_table = of_match_clk_mt8192_ipe, }, }; - -builtin_platform_driver(clk_mt8192_ipe_drv); +module_platform_driver(clk_mt8192_ipe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-mdp.c b/drivers/clk/mediatek/clk-mt8192-mdp.c index 4675788d7816..f7b27264e378 100644 --- a/drivers/clk/mediatek/clk-mt8192-mdp.c +++ b/drivers/clk/mediatek/clk-mt8192-mdp.c @@ -70,6 +70,7 @@ static const struct of_device_id of_match_clk_mt8192_mdp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_mdp); static struct platform_driver clk_mt8192_mdp_drv = { .probe = mtk_clk_simple_probe, @@ -79,5 +80,5 @@ static struct platform_driver clk_mt8192_mdp_drv = { .of_match_table = of_match_clk_mt8192_mdp, }, }; - -builtin_platform_driver(clk_mt8192_mdp_drv); +module_platform_driver(clk_mt8192_mdp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-mfg.c b/drivers/clk/mediatek/clk-mt8192-mfg.c index ec5b44ffa458..85f76a2bbac4 100644 --- a/drivers/clk/mediatek/clk-mt8192-mfg.c +++ b/drivers/clk/mediatek/clk-mt8192-mfg.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt8192_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_mfg); static struct platform_driver clk_mt8192_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -49,5 +50,5 @@ static struct platform_driver clk_mt8192_mfg_drv = { .of_match_table = of_match_clk_mt8192_mfg, }, }; - -builtin_platform_driver(clk_mt8192_mfg_drv); +module_platform_driver(clk_mt8192_mfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-mm.c b/drivers/clk/mediatek/clk-mt8192-mm.c index e9eb4cf8349a..47335d517714 100644 --- a/drivers/clk/mediatek/clk-mt8192-mm.c +++ b/drivers/clk/mediatek/clk-mt8192-mm.c @@ -80,30 +80,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM2(CLK_MM_32KHZ, "mm_32khz", "clk32k", 25), }; -static int clk_mt8192_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(&pdev->dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - if (r) - return r; - - return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); -} +static const struct platform_device_id clk_mt8192_mm_id_table[] = { + { .name = "clk-mt8192-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8192_mm_id_table); static struct platform_driver clk_mt8192_mm_drv = { - .probe = clk_mt8192_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8192-mm", }, + .id_table = clk_mt8192_mm_id_table, }; - -builtin_platform_driver(clk_mt8192_mm_drv); +module_platform_driver(clk_mt8192_mm_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-msdc.c b/drivers/clk/mediatek/clk-mt8192-msdc.c index a72e1b73fce8..60d65f96d39a 100644 --- a/drivers/clk/mediatek/clk-mt8192-msdc.c +++ b/drivers/clk/mediatek/clk-mt8192-msdc.c @@ -52,6 +52,7 @@ static const struct of_device_id of_match_clk_mt8192_msdc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_msdc); static struct platform_driver clk_mt8192_msdc_drv = { .probe = mtk_clk_simple_probe, @@ -61,5 +62,5 @@ static struct platform_driver clk_mt8192_msdc_drv = { .of_match_table = of_match_clk_mt8192_msdc, }, }; - -builtin_platform_driver(clk_mt8192_msdc_drv); +module_platform_driver(clk_mt8192_msdc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-scp_adsp.c b/drivers/clk/mediatek/clk-mt8192-scp_adsp.c index 18a8679108b8..6aad57797c39 100644 --- a/drivers/clk/mediatek/clk-mt8192-scp_adsp.c +++ b/drivers/clk/mediatek/clk-mt8192-scp_adsp.c @@ -38,6 +38,7 @@ static const struct of_device_id of_match_clk_mt8192_scp_adsp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_scp_adsp); static struct platform_driver clk_mt8192_scp_adsp_drv = { .probe = mtk_clk_simple_probe, @@ -47,5 +48,5 @@ static struct platform_driver clk_mt8192_scp_adsp_drv = { .of_match_table = of_match_clk_mt8192_scp_adsp, }, }; - -builtin_platform_driver(clk_mt8192_scp_adsp_drv); +module_platform_driver(clk_mt8192_scp_adsp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-vdec.c b/drivers/clk/mediatek/clk-mt8192-vdec.c index e149962dbbf9..473afd58495c 100644 --- a/drivers/clk/mediatek/clk-mt8192-vdec.c +++ b/drivers/clk/mediatek/clk-mt8192-vdec.c @@ -82,6 +82,7 @@ static const struct of_device_id of_match_clk_mt8192_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_vdec); static struct platform_driver clk_mt8192_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -91,5 +92,5 @@ static struct platform_driver clk_mt8192_vdec_drv = { .of_match_table = of_match_clk_mt8192_vdec, }, }; - -builtin_platform_driver(clk_mt8192_vdec_drv); +module_platform_driver(clk_mt8192_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192-venc.c b/drivers/clk/mediatek/clk-mt8192-venc.c index 80b8bb170996..57b1b16e2310 100644 --- a/drivers/clk/mediatek/clk-mt8192-venc.c +++ b/drivers/clk/mediatek/clk-mt8192-venc.c @@ -41,6 +41,7 @@ static const struct of_device_id of_match_clk_mt8192_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192_venc); static struct platform_driver clk_mt8192_venc_drv = { .probe = mtk_clk_simple_probe, @@ -50,5 +51,5 @@ static struct platform_driver clk_mt8192_venc_drv = { .of_match_table = of_match_clk_mt8192_venc, }, }; - -builtin_platform_driver(clk_mt8192_venc_drv); +module_platform_driver(clk_mt8192_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c index 61299960d28a..aa11291463f7 100644 --- a/drivers/clk/mediatek/clk-mt8192.c +++ b/drivers/clk/mediatek/clk-mt8192.c @@ -15,7 +15,6 @@ #include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-pll.h" #include #include @@ -712,19 +711,6 @@ static struct mtk_composite top_muxes[] = { DIV_GATE(CLK_TOP_APLL12_DIV9, "apll12_div9", "apll_i2s9_m_sel", 0x320, 10, 0x338, 8, 16), }; -static const struct mtk_gate_regs apmixed_cg_regs = { - .set_ofs = 0x14, - .clr_ofs = 0x14, - .sta_ofs = 0x14, -}; - -#define GATE_APMIXED(_id, _name, _parent, _shift) \ - GATE_MTK(_id, _name, _parent, &apmixed_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr_inv) - -static const struct mtk_gate apmixed_clks[] = { - GATE_APMIXED(CLK_APMIXED_MIPID26M, "mipid26m", "clk26m", 16), -}; - static const struct mtk_gate_regs infra0_cg_regs = { .set_ofs = 0x80, .clr_ofs = 0x84, @@ -978,70 +964,6 @@ static const struct mtk_clk_rst_desc clk_rst_desc = { .rst_idx_map_nr = ARRAY_SIZE(infra_ao_idx_map), }; -#define MT8192_PLL_FMAX (3800UL * MHZ) -#define MT8192_PLL_FMIN (1500UL * MHZ) -#define MT8192_INTEGER_BITS 8 - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ - _pcw_reg, _pcw_shift, _pcw_chg_reg, \ - _en_reg, _pll_en_bit) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = _rst_bar_mask, \ - .fmax = MT8192_PLL_FMAX, \ - .fmin = MT8192_PLL_FMIN, \ - .pcwbits = _pcwbits, \ - .pcwibits = MT8192_INTEGER_BITS, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .tuner_en_reg = _tuner_en_reg, \ - .tuner_en_bit = _tuner_en_bit, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .pcw_chg_reg = _pcw_chg_reg, \ - .en_reg = _en_reg, \ - .pll_en_bit = _pll_en_bit, \ - } - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ - _pcw_reg, _pcw_shift) \ - PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _rst_bar_mask, _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ - _pcw_reg, _pcw_shift, 0, 0, 0) - -static const struct mtk_pll_data plls[] = { - PLL_B(CLK_APMIXED_MAINPLL, "mainpll", 0x0340, 0x034c, 0xff000000, - HAVE_RST_BAR, BIT(23), 22, 0x0344, 24, 0, 0, 0, 0x0344, 0), - PLL_B(CLK_APMIXED_UNIVPLL, "univpll", 0x0308, 0x0314, 0xff000000, - HAVE_RST_BAR, BIT(23), 22, 0x030c, 24, 0, 0, 0, 0x030c, 0), - PLL(CLK_APMIXED_USBPLL, "usbpll", 0x03c4, 0x03cc, 0x00000000, - 0, 0, 22, 0x03c4, 24, 0, 0, 0, 0x03c4, 0, 0x03c4, 0x03cc, 2), - PLL_B(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0350, 0x035c, 0x00000000, - 0, 0, 22, 0x0354, 24, 0, 0, 0, 0x0354, 0), - PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0360, 0x036c, 0xff000000, - HAVE_RST_BAR, BIT(23), 22, 0x0364, 24, 0, 0, 0, 0x0364, 0), - PLL_B(CLK_APMIXED_ADSPPLL, "adsppll", 0x0370, 0x037c, 0xff000000, - HAVE_RST_BAR, BIT(23), 22, 0x0374, 24, 0, 0, 0, 0x0374, 0), - PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0268, 0x0274, 0x00000000, - 0, 0, 22, 0x026c, 24, 0, 0, 0, 0x026c, 0), - PLL_B(CLK_APMIXED_TVDPLL, "tvdpll", 0x0380, 0x038c, 0x00000000, - 0, 0, 22, 0x0384, 24, 0, 0, 0, 0x0384, 0), - PLL_B(CLK_APMIXED_APLL1, "apll1", 0x0318, 0x0328, 0x00000000, - 0, 0, 32, 0x031c, 24, 0x0040, 0x000c, 0, 0x0320, 0), - PLL_B(CLK_APMIXED_APLL2, "apll2", 0x032c, 0x033c, 0x00000000, - 0, 0, 32, 0x0330, 24, 0, 0, 0, 0x0334, 0), -}; - /* Register mux notifier for MFG mux */ static int clk_mt8192_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) { @@ -1064,60 +986,6 @@ static int clk_mt8192_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb); } -static int clk_mt8192_apmixed_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - int r; - - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - if (!clk_data) - return -ENOMEM; - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks, - ARRAY_SIZE(apmixed_clks), clk_data); - if (r) - goto free_clk_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - return r; - -unregister_gates: - mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); -free_clk_data: - mtk_free_clk_data(clk_data); - return r; -} - -static const struct of_device_id of_match_clk_mt8192[] = { - { - .compatible = "mediatek,mt8192-apmixedsys", - .data = clk_mt8192_apmixed_probe, - }, { - /* sentinel */ - } -}; - -static int clk_mt8192_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *pdev); - int r; - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - r = clk_probe(pdev); - if (r) - dev_err(&pdev->dev, "could not register clock provider: %s: %d\n", pdev->name, r); - - return r; -} - static const struct mtk_clk_desc infra_desc = { .clks = infra_clks, .num_clks = ARRAY_SIZE(infra_clks), @@ -1145,37 +1013,21 @@ static const struct mtk_clk_desc topck_desc = { .mfg_clk_idx = CLK_TOP_MFG_PLL_SEL, }; -static const struct of_device_id of_match_clk_mt8192_simple[] = { +static const struct of_device_id of_match_clk_mt8192[] = { { .compatible = "mediatek,mt8192-infracfg", .data = &infra_desc }, { .compatible = "mediatek,mt8192-pericfg", .data = &peri_desc }, { .compatible = "mediatek,mt8192-topckgen", .data = &topck_desc }, { /* sentinel */ } }; - -static struct platform_driver clk_mt8192_simple_drv = { - .probe = mtk_clk_simple_probe, - .remove = mtk_clk_simple_remove, - .driver = { - .name = "clk-mt8192-simple", - .of_match_table = of_match_clk_mt8192_simple, - }, -}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8192); static struct platform_driver clk_mt8192_drv = { - .probe = clk_mt8192_probe, .driver = { .name = "clk-mt8192", .of_match_table = of_match_clk_mt8192, }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, }; - -static int __init clk_mt8192_init(void) -{ - int ret = platform_driver_register(&clk_mt8192_drv); - - if (ret) - return ret; - return platform_driver_register(&clk_mt8192_simple_drv); -} - -arch_initcall(clk_mt8192_init); +module_platform_driver(clk_mt8192_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c index 1bc917f2667e..8b9b5d820286 100644 --- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c @@ -3,9 +3,11 @@ // Copyright (c) 2021 MediaTek Inc. // Author: Chun-Jie Chen +#include "clk-fhctl.h" #include "clk-gate.h" #include "clk-mtk.h" #include "clk-pll.h" +#include "clk-pllfh.h" #include #include @@ -105,22 +107,82 @@ static const struct mtk_pll_data plls[] = { 0, 0, 22, 0x0158, 24, 0, 0, 0, 0x0158, 0, 0x0158, 0, 9), }; +enum fh_pll_id { + FH_ARMPLL_LL, + FH_ARMPLL_BL, + FH_MEMPLL, + FH_ADSPPLL, + FH_NNAPLL, + FH_CCIPLL, + FH_MFGPLL, + FH_TVDPLL2, + FH_MPLL, + FH_MMPLL, + FH_MAINPLL, + FH_MSDCPLL, + FH_IMGPLL, + FH_VDECPLL, + FH_TVDPLL1, + FH_NR_FH, +}; + +#define FH(_pllid, _fhid, _offset) { \ + .data = { \ + .pll_id = _pllid, \ + .fh_id = _fhid, \ + .fh_ver = FHCTL_PLLFH_V2, \ + .fhx_offset = _offset, \ + .dds_mask = GENMASK(21, 0), \ + .slope0_value = 0x6003c97, \ + .slope1_value = 0x6003c97, \ + .sfstrx_en = BIT(2), \ + .frddsx_en = BIT(1), \ + .fhctlx_en = BIT(0), \ + .tgl_org = BIT(31), \ + .dvfs_tri = BIT(31), \ + .pcwchg = BIT(31), \ + .dt_val = 0x0, \ + .df_val = 0x9, \ + .updnlmt_shft = 16, \ + .msk_frddsx_dys = GENMASK(23, 20), \ + .msk_frddsx_dts = GENMASK(19, 16), \ + }, \ + } + +static struct mtk_pllfh_data pllfhs[] = { + FH(CLK_APMIXED_ADSPPLL, FH_ADSPPLL, 0x78), + FH(CLK_APMIXED_NNAPLL, FH_NNAPLL, 0x8c), + FH(CLK_APMIXED_MFGPLL, FH_MFGPLL, 0xb4), + FH(CLK_APMIXED_TVDPLL2, FH_TVDPLL2, 0xc8), + FH(CLK_APMIXED_MMPLL, FH_MMPLL, 0xf0), + FH(CLK_APMIXED_MAINPLL, FH_MAINPLL, 0x104), + FH(CLK_APMIXED_MSDCPLL, FH_MSDCPLL, 0x118), + FH(CLK_APMIXED_IMGPLL, FH_IMGPLL, 0x12c), + FH(CLK_APMIXED_VDECPLL, FH_VDECPLL, 0x140), + FH(CLK_APMIXED_TVDPLL2, FH_TVDPLL1, 0x154), +}; + static const struct of_device_id of_match_clk_mt8195_apmixed[] = { { .compatible = "mediatek,mt8195-apmixedsys", }, {} }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_apmixed); static int clk_mt8195_apmixed_probe(struct platform_device *pdev) { struct clk_hw_onecell_data *clk_data; struct device_node *node = pdev->dev.of_node; + const u8 *fhctl_node = "mediatek,mt8195-fhctl"; int r; clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); if (!clk_data) return -ENOMEM; - r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs)); + + r = mtk_clk_register_pllfhs(node, plls, ARRAY_SIZE(plls), + pllfhs, ARRAY_SIZE(pllfhs), clk_data); if (r) goto free_apmixed_data; @@ -140,7 +202,8 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev) unregister_gates: mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); unregister_plls: - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); free_apmixed_data: mtk_free_clk_data(clk_data); return r; @@ -153,7 +216,8 @@ static int clk_mt8195_apmixed_remove(struct platform_device *pdev) of_clk_del_provider(node); mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_clk_unregister_pllfhs(plls, ARRAY_SIZE(plls), pllfhs, + ARRAY_SIZE(pllfhs), clk_data); mtk_free_clk_data(clk_data); return 0; @@ -167,4 +231,5 @@ static struct platform_driver clk_mt8195_apmixed_drv = { .of_match_table = of_match_clk_mt8195_apmixed, }, }; -builtin_platform_driver(clk_mt8195_apmixed_drv); +module_platform_driver(clk_mt8195_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c index 0b52f6a009c4..de04c087c8c3 100644 --- a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c +++ b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c @@ -101,6 +101,7 @@ static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = { { .compatible = "mediatek,mt8195-apusys_pll", }, {} }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_apusys_pll); static struct platform_driver clk_mt8195_apusys_pll_drv = { .probe = clk_mt8195_apusys_pll_probe, @@ -110,4 +111,5 @@ static struct platform_driver clk_mt8195_apusys_pll_drv = { .of_match_table = of_match_clk_mt8195_apusys_pll, }, }; -builtin_platform_driver(clk_mt8195_apusys_pll_drv); +module_platform_driver(clk_mt8195_apusys_pll_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-cam.c b/drivers/clk/mediatek/clk-mt8195-cam.c index e4d00fe6e757..77e608be579a 100644 --- a/drivers/clk/mediatek/clk-mt8195-cam.c +++ b/drivers/clk/mediatek/clk-mt8195-cam.c @@ -131,6 +131,7 @@ static const struct of_device_id of_match_clk_mt8195_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_cam); static struct platform_driver clk_mt8195_cam_drv = { .probe = mtk_clk_simple_probe, @@ -140,4 +141,5 @@ static struct platform_driver clk_mt8195_cam_drv = { .of_match_table = of_match_clk_mt8195_cam, }, }; -builtin_platform_driver(clk_mt8195_cam_drv); +module_platform_driver(clk_mt8195_cam_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-ccu.c b/drivers/clk/mediatek/clk-mt8195-ccu.c index 4e326b6301ba..bdc2e6f3e9ce 100644 --- a/drivers/clk/mediatek/clk-mt8195-ccu.c +++ b/drivers/clk/mediatek/clk-mt8195-ccu.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_ccu[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_ccu); static struct platform_driver clk_mt8195_ccu_drv = { .probe = mtk_clk_simple_probe, @@ -48,4 +49,5 @@ static struct platform_driver clk_mt8195_ccu_drv = { .of_match_table = of_match_clk_mt8195_ccu, }, }; -builtin_platform_driver(clk_mt8195_ccu_drv); +module_platform_driver(clk_mt8195_ccu_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-img.c b/drivers/clk/mediatek/clk-mt8195-img.c index 12f5c436d075..d853e0e63d87 100644 --- a/drivers/clk/mediatek/clk-mt8195-img.c +++ b/drivers/clk/mediatek/clk-mt8195-img.c @@ -85,6 +85,7 @@ static const struct of_device_id of_match_clk_mt8195_img[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_img); static struct platform_driver clk_mt8195_img_drv = { .probe = mtk_clk_simple_probe, @@ -94,4 +95,5 @@ static struct platform_driver clk_mt8195_img_drv = { .of_match_table = of_match_clk_mt8195_img, }, }; -builtin_platform_driver(clk_mt8195_img_drv); +module_platform_driver(clk_mt8195_img_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c index fbc809d05072..1d808876f5c5 100644 --- a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c @@ -55,6 +55,7 @@ static const struct of_device_id of_match_clk_mt8195_imp_iic_wrap[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_imp_iic_wrap); static struct platform_driver clk_mt8195_imp_iic_wrap_drv = { .probe = mtk_clk_simple_probe, @@ -64,4 +65,5 @@ static struct platform_driver clk_mt8195_imp_iic_wrap_drv = { .of_match_table = of_match_clk_mt8195_imp_iic_wrap, }, }; -builtin_platform_driver(clk_mt8195_imp_iic_wrap_drv); +module_platform_driver(clk_mt8195_imp_iic_wrap_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-infra_ao.c b/drivers/clk/mediatek/clk-mt8195-infra_ao.c index fcd410461d3b..f3ee4390707d 100644 --- a/drivers/clk/mediatek/clk-mt8195-infra_ao.c +++ b/drivers/clk/mediatek/clk-mt8195-infra_ao.c @@ -229,6 +229,7 @@ static const struct of_device_id of_match_clk_mt8195_infra_ao[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_infra_ao); static struct platform_driver clk_mt8195_infra_ao_drv = { .probe = mtk_clk_simple_probe, @@ -238,4 +239,5 @@ static struct platform_driver clk_mt8195_infra_ao_drv = { .of_match_table = of_match_clk_mt8195_infra_ao, }, }; -builtin_platform_driver(clk_mt8195_infra_ao_drv); +module_platform_driver(clk_mt8195_infra_ao_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-ipe.c b/drivers/clk/mediatek/clk-mt8195-ipe.c index b0d745cf7752..4c47f6521275 100644 --- a/drivers/clk/mediatek/clk-mt8195-ipe.c +++ b/drivers/clk/mediatek/clk-mt8195-ipe.c @@ -40,6 +40,7 @@ static const struct of_device_id of_match_clk_mt8195_ipe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_ipe); static struct platform_driver clk_mt8195_ipe_drv = { .probe = mtk_clk_simple_probe, @@ -49,4 +50,5 @@ static struct platform_driver clk_mt8195_ipe_drv = { .of_match_table = of_match_clk_mt8195_ipe, }, }; -builtin_platform_driver(clk_mt8195_ipe_drv); +module_platform_driver(clk_mt8195_ipe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-mfg.c b/drivers/clk/mediatek/clk-mt8195-mfg.c index c94cb71bd9b9..038acf0b1167 100644 --- a/drivers/clk/mediatek/clk-mt8195-mfg.c +++ b/drivers/clk/mediatek/clk-mt8195-mfg.c @@ -38,6 +38,7 @@ static const struct of_device_id of_match_clk_mt8195_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_mfg); static struct platform_driver clk_mt8195_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -47,4 +48,5 @@ static struct platform_driver clk_mt8195_mfg_drv = { .of_match_table = of_match_clk_mt8195_mfg, }, }; -builtin_platform_driver(clk_mt8195_mfg_drv); +module_platform_driver(clk_mt8195_mfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-peri_ao.c b/drivers/clk/mediatek/clk-mt8195-peri_ao.c index 2f6b3bb657db..0de162593c01 100644 --- a/drivers/clk/mediatek/clk-mt8195-peri_ao.c +++ b/drivers/clk/mediatek/clk-mt8195-peri_ao.c @@ -51,6 +51,7 @@ static const struct of_device_id of_match_clk_mt8195_peri_ao[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_peri_ao); static struct platform_driver clk_mt8195_peri_ao_drv = { .probe = mtk_clk_simple_probe, @@ -60,4 +61,5 @@ static struct platform_driver clk_mt8195_peri_ao_drv = { .of_match_table = of_match_clk_mt8195_peri_ao, }, }; -builtin_platform_driver(clk_mt8195_peri_ao_drv); +module_platform_driver(clk_mt8195_peri_ao_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c index e16c383f631b..d0d3e3b09780 100644 --- a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c +++ b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c @@ -36,6 +36,7 @@ static const struct of_device_id of_match_clk_mt8195_scp_adsp[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_scp_adsp); static struct platform_driver clk_mt8195_scp_adsp_drv = { .probe = mtk_clk_simple_probe, @@ -45,4 +46,5 @@ static struct platform_driver clk_mt8195_scp_adsp_drv = { .of_match_table = of_match_clk_mt8195_scp_adsp, }, }; -builtin_platform_driver(clk_mt8195_scp_adsp_drv); +module_platform_driver(clk_mt8195_scp_adsp_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c index cf520f85de73..3c2174c3e742 100644 --- a/drivers/clk/mediatek/clk-mt8195-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c @@ -1219,6 +1219,7 @@ static const struct of_device_id of_match_clk_mt8195_topck[] = { { .compatible = "mediatek,mt8195-topckgen", }, {} }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_topck); /* Register mux notifier for MFG mux */ static int clk_mt8195_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) @@ -1340,4 +1341,5 @@ static struct platform_driver clk_mt8195_topck_drv = { .of_match_table = of_match_clk_mt8195_topck, }, }; -builtin_platform_driver(clk_mt8195_topck_drv); +module_platform_driver(clk_mt8195_topck_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-vdec.c b/drivers/clk/mediatek/clk-mt8195-vdec.c index a1446b666385..2bcbceb10326 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdec.c +++ b/drivers/clk/mediatek/clk-mt8195-vdec.c @@ -93,6 +93,7 @@ static const struct of_device_id of_match_clk_mt8195_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_vdec); static struct platform_driver clk_mt8195_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -102,4 +103,5 @@ static struct platform_driver clk_mt8195_vdec_drv = { .of_match_table = of_match_clk_mt8195_vdec, }, }; -builtin_platform_driver(clk_mt8195_vdec_drv); +module_platform_driver(clk_mt8195_vdec_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-vdo0.c b/drivers/clk/mediatek/clk-mt8195-vdo0.c index 839b730688ac..509780750e43 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdo0.c +++ b/drivers/clk/mediatek/clk-mt8195-vdo0.c @@ -93,55 +93,24 @@ static const struct mtk_gate vdo0_clks[] = { "top_edp", 16, CLK_SET_RATE_PARENT), }; -static int clk_mt8195_vdo0_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc vdo0_desc = { + .clks = vdo0_clks, + .num_clks = ARRAY_SIZE(vdo0_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_VDO0_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(&pdev->dev, node, vdo0_clks, - ARRAY_SIZE(vdo0_clks), clk_data); - if (r) - goto free_vdo0_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_gates: - mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data); -free_vdo0_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8195_vdo0_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt8195_vdo0_id_table[] = { + { .name = "clk-mt8195-vdo0", .driver_data = (kernel_ulong_t)&vdo0_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8195_vdo0_id_table); static struct platform_driver clk_mt8195_vdo0_drv = { - .probe = clk_mt8195_vdo0_probe, - .remove = clk_mt8195_vdo0_remove, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8195-vdo0", }, + .id_table = clk_mt8195_vdo0_id_table, }; -builtin_platform_driver(clk_mt8195_vdo0_drv); +module_platform_driver(clk_mt8195_vdo0_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-vdo1.c b/drivers/clk/mediatek/clk-mt8195-vdo1.c index 7df695b28925..0a5214a1ed25 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdo1.c +++ b/drivers/clk/mediatek/clk-mt8195-vdo1.c @@ -120,55 +120,24 @@ static const struct mtk_gate vdo1_clks[] = { GATE_VDO1_4(CLK_VDO1_DPI1_HDMI, "vdo1_dpi1_hdmi", "hdmi_txpll", 0), }; -static int clk_mt8195_vdo1_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc vdo1_desc = { + .clks = vdo1_clks, + .num_clks = ARRAY_SIZE(vdo1_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_VDO1_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(&pdev->dev, node, vdo1_clks, - ARRAY_SIZE(vdo1_clks), clk_data); - if (r) - goto free_vdo1_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_gates: - mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data); -free_vdo1_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8195_vdo1_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt8195_vdo1_id_table[] = { + { .name = "clk-mt8195-vdo1", .driver_data = (kernel_ulong_t)&vdo1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8195_vdo1_id_table); static struct platform_driver clk_mt8195_vdo1_drv = { - .probe = clk_mt8195_vdo1_probe, - .remove = clk_mt8195_vdo1_remove, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8195-vdo1", }, + .id_table = clk_mt8195_vdo1_id_table, }; -builtin_platform_driver(clk_mt8195_vdo1_drv); +module_platform_driver(clk_mt8195_vdo1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-venc.c b/drivers/clk/mediatek/clk-mt8195-venc.c index 622f57804f96..0991a6968765 100644 --- a/drivers/clk/mediatek/clk-mt8195-venc.c +++ b/drivers/clk/mediatek/clk-mt8195-venc.c @@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8195_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_venc); static struct platform_driver clk_mt8195_venc_drv = { .probe = mtk_clk_simple_probe, @@ -67,4 +68,5 @@ static struct platform_driver clk_mt8195_venc_drv = { .of_match_table = of_match_clk_mt8195_venc, }, }; -builtin_platform_driver(clk_mt8195_venc_drv); +module_platform_driver(clk_mt8195_venc_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-vpp0.c b/drivers/clk/mediatek/clk-mt8195-vpp0.c index e19664af09b6..1a98fb9a25e8 100644 --- a/drivers/clk/mediatek/clk-mt8195-vpp0.c +++ b/drivers/clk/mediatek/clk-mt8195-vpp0.c @@ -86,54 +86,24 @@ static const struct mtk_gate vpp0_clks[] = { GATE_VPP0_2(CLK_VPP0_WARP1_MDP_DL_ASYNC, "vpp0_warp1_mdp_dl_async", "top_wpe_vpp", 3), }; -static int clk_mt8195_vpp0_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc vpp0_desc = { + .clks = vpp0_clks, + .num_clks = ARRAY_SIZE(vpp0_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_VPP0_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(dev, node, vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data); - if (r) - goto free_vpp0_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_gates: - mtk_clk_unregister_gates(vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data); -free_vpp0_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8195_vpp0_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt8195_vpp0_id_table[] = { + { .name = "clk-mt8195-vpp0", .driver_data = (kernel_ulong_t)&vpp0_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8195_vpp0_id_table); static struct platform_driver clk_mt8195_vpp0_drv = { - .probe = clk_mt8195_vpp0_probe, - .remove = clk_mt8195_vpp0_remove, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8195-vpp0", }, + .id_table = clk_mt8195_vpp0_id_table, }; -builtin_platform_driver(clk_mt8195_vpp0_drv); +module_platform_driver(clk_mt8195_vpp0_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-vpp1.c b/drivers/clk/mediatek/clk-mt8195-vpp1.c index e6c458fc1531..c2d5b582f53a 100644 --- a/drivers/clk/mediatek/clk-mt8195-vpp1.c +++ b/drivers/clk/mediatek/clk-mt8195-vpp1.c @@ -84,54 +84,24 @@ static const struct mtk_gate vpp1_clks[] = { GATE_VPP1_1(CLK_VPP1_VPP_SPLIT_26M, "vpp1_vpp_split_26m", "clk26m", 26), }; -static int clk_mt8195_vpp1_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc vpp1_desc = { + .clks = vpp1_clks, + .num_clks = ARRAY_SIZE(vpp1_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_VPP1_NR_CLK); - if (!clk_data) - return -ENOMEM; - - r = mtk_clk_register_gates(dev, node, vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data); - if (r) - goto free_vpp1_data; - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - goto unregister_gates; - - platform_set_drvdata(pdev, clk_data); - - return r; - -unregister_gates: - mtk_clk_unregister_gates(vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data); -free_vpp1_data: - mtk_free_clk_data(clk_data); - return r; -} - -static int clk_mt8195_vpp1_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - - of_clk_del_provider(node); - mtk_clk_unregister_gates(vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data); - mtk_free_clk_data(clk_data); - - return 0; -} +static const struct platform_device_id clk_mt8195_vpp1_id_table[] = { + { .name = "clk-mt8195-vpp1", .driver_data = (kernel_ulong_t)&vpp1_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8195_vpp1_id_table); static struct platform_driver clk_mt8195_vpp1_drv = { - .probe = clk_mt8195_vpp1_probe, - .remove = clk_mt8195_vpp1_remove, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8195-vpp1", }, + .id_table = clk_mt8195_vpp1_id_table, }; -builtin_platform_driver(clk_mt8195_vpp1_drv); +module_platform_driver(clk_mt8195_vpp1_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8195-wpe.c b/drivers/clk/mediatek/clk-mt8195-wpe.c index b483fab10e18..289896cb2f6c 100644 --- a/drivers/clk/mediatek/clk-mt8195-wpe.c +++ b/drivers/clk/mediatek/clk-mt8195-wpe.c @@ -132,6 +132,7 @@ static const struct of_device_id of_match_clk_mt8195_wpe[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8195_wpe); static struct platform_driver clk_mt8195_wpe_drv = { .probe = mtk_clk_simple_probe, @@ -141,4 +142,5 @@ static struct platform_driver clk_mt8195_wpe_drv = { .of_match_table = of_match_clk_mt8195_wpe, }, }; -builtin_platform_driver(clk_mt8195_wpe_drv); +module_platform_driver(clk_mt8195_wpe_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-apmixedsys.c b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c new file mode 100644 index 000000000000..9b0bc5daeac0 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8365-apmixedsys.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2023 Collabora Ltd. + */ + +#include +#include +#include +#include + +#include "clk-pll.h" +#include "clk-mtk.h" + +#define MT8365_PLL_FMAX (3800UL * MHZ) +#define MT8365_PLL_FMIN (1500UL * MHZ) +#define CON0_MT8365_RST_BAR BIT(23) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, _div_table, \ + _rst_bar_mask, _pcw_chg_reg) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = _rst_bar_mask, \ + .fmax = MT8365_PLL_FMAX, \ + .fmin = MT8365_PLL_FMIN, \ + .pcwbits = _pcwbits, \ + .pcwibits = 8, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, \ + _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ + _pcw_shift, _rst_bar_mask, _pcw_chg_reg) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _pcwbits, _pd_reg, _pd_shift, \ + _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ + _pcw_reg, _pcw_shift, NULL, _rst_bar_mask, \ + _pcw_chg_reg) \ + +static const struct mtk_pll_div_table armpll_div_table[] = { + { .div = 0, .freq = MT8365_PLL_FMAX }, + { .div = 1, .freq = 1500 * MHZ }, + { .div = 2, .freq = 750 * MHZ }, + { .div = 3, .freq = 375 * MHZ }, + { .div = 4, .freq = 182500000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_div_table mfgpll_div_table[] = { + { .div = 0, .freq = MT8365_PLL_FMAX }, + { .div = 1, .freq = 1600 * MHZ }, + { .div = 2, .freq = 800 * MHZ }, + { .div = 3, .freq = 400 * MHZ }, + { .div = 4, .freq = 200 * MHZ }, + { } /* sentinel */ +}; + +static const struct mtk_pll_div_table dsppll_div_table[] = { + { .div = 0, .freq = MT8365_PLL_FMAX }, + { .div = 1, .freq = 1600 * MHZ }, + { .div = 2, .freq = 600 * MHZ }, + { .div = 3, .freq = 400 * MHZ }, + { .div = 4, .freq = 200 * MHZ }, + { } /* sentinel */ +}; + +static const struct mtk_pll_data plls[] = { + PLL_B(CLK_APMIXED_ARMPLL, "armpll", 0x030C, 0x0318, 0x00000001, PLL_AO, + 22, 0x0310, 24, 0, 0, 0, 0x0310, 0, armpll_div_table, 0, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0228, 0x0234, 0xFF000001, + HAVE_RST_BAR, 22, 0x022C, 24, 0, 0, 0, 0x022C, 0, CON0_MT8365_RST_BAR, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll2", 0x0208, 0x0214, 0xFF000001, + HAVE_RST_BAR, 22, 0x020C, 24, 0, 0, 0, 0x020C, 0, CON0_MT8365_RST_BAR, 0), + PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0218, 0x0224, 0x00000001, 0, 22, + 0x021C, 24, 0, 0, 0, 0x021C, 0, mfgpll_div_table, 0, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0350, 0x035C, 0x00000001, 0, 22, + 0x0354, 24, 0, 0, 0, 0x0354, 0, 0, 0), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0330, 0x033C, 0x00000001, 0, 22, + 0x0334, 24, 0, 0, 0, 0x0334, 0, 0, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x031C, 0x032C, 0x00000001, 0, 32, + 0x0320, 24, 0x0040, 0x000C, 0, 0x0324, 0, 0, 0x0320), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0360, 0x0370, 0x00000001, 0, 32, + 0x0364, 24, 0x004C, 0x000C, 5, 0x0368, 0, 0, 0x0364), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0374, 0x0380, 0x00000001, 0, 22, + 0x0378, 24, 0, 0, 0, 0x0378, 0, 0, 0), + PLL_B(CLK_APMIXED_DSPPLL, "dsppll", 0x0390, 0x039C, 0x00000001, 0, 22, + 0x0394, 24, 0, 0, 0, 0x0394, 0, dsppll_div_table, 0, 0), + PLL(CLK_APMIXED_APUPLL, "apupll", 0x03A0, 0x03AC, 0x00000001, 0, 22, + 0x03A4, 24, 0, 0, 0, 0x03A4, 0, 0, 0), +}; + +static int clk_mt8365_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct clk_hw *hw; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(dev, CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + hw = devm_clk_hw_register_gate(dev, "univ_en", "univpll2", 0, + base + 0x204, 0, 0, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[CLK_APMIXED_UNIV_EN] = hw; + + hw = devm_clk_hw_register_gate(dev, "usb20_en", "univ_en", 0, + base + 0x204, 1, 0, NULL); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[CLK_APMIXED_USB20_EN] = hw; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_plls; + + return 0; + +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static const struct of_device_id of_match_clk_mt8365_apmixed[] = { + { .compatible = "mediatek,mt8365-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_apmixed); + +static struct platform_driver clk_mt8365_apmixed_drv = { + .probe = clk_mt8365_apmixed_probe, + .driver = { + .name = "clk-mt8365-apmixed", + .of_match_table = of_match_clk_mt8365_apmixed, + }, +}; +builtin_platform_driver(clk_mt8365_apmixed_drv) +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-apu.c b/drivers/clk/mediatek/clk-mt8365-apu.c index 91ffe89d9721..74f7fb22c87f 100644 --- a/drivers/clk/mediatek/clk-mt8365-apu.c +++ b/drivers/clk/mediatek/clk-mt8365-apu.c @@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8365_apu[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_apu); static struct platform_driver clk_mt8365_apu_drv = { .probe = mtk_clk_simple_probe, @@ -51,5 +52,5 @@ static struct platform_driver clk_mt8365_apu_drv = { .of_match_table = of_match_clk_mt8365_apu, }, }; -builtin_platform_driver(clk_mt8365_apu_drv); +module_platform_driver(clk_mt8365_apu_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-cam.c b/drivers/clk/mediatek/clk-mt8365-cam.c index 31d5b5cd6de1..61516e19acd1 100644 --- a/drivers/clk/mediatek/clk-mt8365-cam.c +++ b/drivers/clk/mediatek/clk-mt8365-cam.c @@ -44,6 +44,7 @@ static const struct of_device_id of_match_clk_mt8365_cam[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_cam); static struct platform_driver clk_mt8365_cam_drv = { .probe = mtk_clk_simple_probe, @@ -53,5 +54,5 @@ static struct platform_driver clk_mt8365_cam_drv = { .of_match_table = of_match_clk_mt8365_cam, }, }; -builtin_platform_driver(clk_mt8365_cam_drv); +module_platform_driver(clk_mt8365_cam_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-mfg.c b/drivers/clk/mediatek/clk-mt8365-mfg.c index 587b49128b03..4c836c69db4f 100644 --- a/drivers/clk/mediatek/clk-mt8365-mfg.c +++ b/drivers/clk/mediatek/clk-mt8365-mfg.c @@ -50,6 +50,7 @@ static const struct of_device_id of_match_clk_mt8365_mfg[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_mfg); static struct platform_driver clk_mt8365_mfg_drv = { .probe = mtk_clk_simple_probe, @@ -59,5 +60,5 @@ static struct platform_driver clk_mt8365_mfg_drv = { .of_match_table = of_match_clk_mt8365_mfg, }, }; -builtin_platform_driver(clk_mt8365_mfg_drv); +module_platform_driver(clk_mt8365_mfg_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-mm.c b/drivers/clk/mediatek/clk-mt8365-mm.c index 22c75a03a645..44427120846f 100644 --- a/drivers/clk/mediatek/clk-mt8365-mm.c +++ b/drivers/clk/mediatek/clk-mt8365-mm.c @@ -72,40 +72,24 @@ static const struct mtk_gate mm_clks[] = { GATE_MM1(CLK_MM_LVDSTX_CTS, "mm_flvdstx_cts", "lvdstx_dig_cts", 3), }; -static int clk_mt8365_mm_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; - struct clk_hw_onecell_data *clk_data; - int ret; +static const struct mtk_clk_desc mm_desc = { + .clks = mm_clks, + .num_clks = ARRAY_SIZE(mm_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); - - ret = mtk_clk_register_gates(dev, node, mm_clks, - ARRAY_SIZE(mm_clks), clk_data); - if (ret) - goto err_free_clk_data; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto err_unregister_gates; - - return 0; - -err_unregister_gates: - mtk_clk_unregister_gates(mm_clks, ARRAY_SIZE(mm_clks), clk_data); - -err_free_clk_data: - mtk_free_clk_data(clk_data); - - return ret; -} +static const struct platform_device_id clk_mt8365_mm_id_table[] = { + { .name = "clk-mt8365-mm", .driver_data = (kernel_ulong_t)&mm_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, clk_mt8365_mm_id_table); static struct platform_driver clk_mt8365_mm_drv = { - .probe = clk_mt8365_mm_probe, + .probe = mtk_clk_pdev_probe, + .remove = mtk_clk_pdev_remove, .driver = { .name = "clk-mt8365-mm", }, + .id_table = clk_mt8365_mm_id_table, }; -builtin_platform_driver(clk_mt8365_mm_drv); +module_platform_driver(clk_mt8365_mm_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-vdec.c b/drivers/clk/mediatek/clk-mt8365-vdec.c index cdc678e8941c..b51571e9da00 100644 --- a/drivers/clk/mediatek/clk-mt8365-vdec.c +++ b/drivers/clk/mediatek/clk-mt8365-vdec.c @@ -50,6 +50,7 @@ static const struct of_device_id of_match_clk_mt8365_vdec[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_vdec); static struct platform_driver clk_mt8365_vdec_drv = { .probe = mtk_clk_simple_probe, @@ -59,5 +60,5 @@ static struct platform_driver clk_mt8365_vdec_drv = { .of_match_table = of_match_clk_mt8365_vdec, }, }; -builtin_platform_driver(clk_mt8365_vdec_drv); +module_platform_driver(clk_mt8365_vdec_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365-venc.c b/drivers/clk/mediatek/clk-mt8365-venc.c index 0e080c22119d..572344645c86 100644 --- a/drivers/clk/mediatek/clk-mt8365-venc.c +++ b/drivers/clk/mediatek/clk-mt8365-venc.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8365_venc[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365_venc); static struct platform_driver clk_mt8365_venc_drv = { .probe = mtk_clk_simple_probe, @@ -48,5 +49,5 @@ static struct platform_driver clk_mt8365_venc_drv = { .of_match_table = of_match_clk_mt8365_venc, }, }; -builtin_platform_driver(clk_mt8365_venc_drv); +module_platform_driver(clk_mt8365_venc_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8365.c b/drivers/clk/mediatek/clk-mt8365.c index c9faa07ec0a6..6b4e193f648d 100644 --- a/drivers/clk/mediatek/clk-mt8365.c +++ b/drivers/clk/mediatek/clk-mt8365.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022 MediaTek Inc. + * Copyright (C) 2023 Collabora Ltd. + * AngeloGioacchino Del Regno */ #include @@ -17,7 +19,6 @@ #include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-pll.h" static DEFINE_SPINLOCK(mt8365_clk_lock); @@ -383,31 +384,23 @@ static const char * const mbist_diag_parents[] = { "univpll2_d8" }; -static const char * const apll_i2s0_parents[] = { +static const char * const apll_i2s_parents[] = { "aud_1_sel", "aud_2_sel" }; -static struct mtk_composite top_misc_mux_gates[] = { +static struct mtk_composite top_misc_muxes[] = { /* CLK_CFG_11 */ MUX_GATE(CLK_TOP_MBIST_DIAG_SEL, "mbist_diag_sel", mbist_diag_parents, 0x0ec, 0, 2, 7), -}; - -struct mt8365_clk_audio_mux { - int id; - const char *name; - u8 shift; -}; - -static struct mt8365_clk_audio_mux top_misc_muxes[] = { - { CLK_TOP_APLL_I2S0_SEL, "apll_i2s0_sel", 11}, - { CLK_TOP_APLL_I2S1_SEL, "apll_i2s1_sel", 12}, - { CLK_TOP_APLL_I2S2_SEL, "apll_i2s2_sel", 13}, - { CLK_TOP_APLL_I2S3_SEL, "apll_i2s3_sel", 14}, - { CLK_TOP_APLL_TDMOUT_SEL, "apll_tdmout_sel", 15}, - { CLK_TOP_APLL_TDMIN_SEL, "apll_tdmin_sel", 16}, - { CLK_TOP_APLL_SPDIF_SEL, "apll_spdif_sel", 17}, + /* Audio MUX */ + MUX(CLK_TOP_APLL_I2S0_SEL, "apll_i2s0_sel", apll_i2s_parents, 0x0320, 11, 1), + MUX(CLK_TOP_APLL_I2S1_SEL, "apll_i2s1_sel", apll_i2s_parents, 0x0320, 12, 1), + MUX(CLK_TOP_APLL_I2S2_SEL, "apll_i2s2_sel", apll_i2s_parents, 0x0320, 13, 1), + MUX(CLK_TOP_APLL_I2S3_SEL, "apll_i2s3_sel", apll_i2s_parents, 0x0320, 14, 1), + MUX(CLK_TOP_APLL_TDMOUT_SEL, "apll_tdmout_sel", apll_i2s_parents, 0x0320, 15, 1), + MUX(CLK_TOP_APLL_TDMIN_SEL, "apll_tdmin_sel", apll_i2s_parents, 0x0320, 16, 1), + MUX(CLK_TOP_APLL_SPDIF_SEL, "apll_spdif_sel", apll_i2s_parents, 0x0320, 17, 1), }; #define CLK_CFG_UPDATE 0x004 @@ -570,35 +563,56 @@ static const struct mtk_clk_divider top_adj_divs[] = { 0x32c, 0, 8, CLK_DIVIDER_ROUND_CLOSEST), }; -struct mtk_simple_gate { - int id; - const char *name; - const char *parent; - u32 reg; - u8 shift; - unsigned long gate_flags; +static const struct mtk_gate_regs top0_cg_regs = { + .set_ofs = 0, + .clr_ofs = 0, + .sta_ofs = 0, }; -static const struct mtk_simple_gate top_clk_gates[] = { - { CLK_TOP_CONN_32K, "conn_32k", "clk32k", 0x0, 10, CLK_GATE_SET_TO_DISABLE }, - { CLK_TOP_CONN_26M, "conn_26m", "clk26m", 0x0, 11, CLK_GATE_SET_TO_DISABLE }, - { CLK_TOP_DSP_32K, "dsp_32k", "clk32k", 0x0, 16, CLK_GATE_SET_TO_DISABLE }, - { CLK_TOP_DSP_26M, "dsp_26m", "clk26m", 0x0, 17, CLK_GATE_SET_TO_DISABLE }, - { CLK_TOP_USB20_48M_EN, "usb20_48m_en", "usb20_192m_d4", 0x104, 8, 0 }, - { CLK_TOP_UNIVPLL_48M_EN, "univpll_48m_en", "usb20_192m_d4", 0x104, 9, 0 }, - { CLK_TOP_LVDSTX_CLKDIG_EN, "lvdstx_dig_en", "lvdstx_dig_cts", 0x104, 20, 0 }, - { CLK_TOP_VPLL_DPIX_EN, "vpll_dpix_en", "vpll_dpix", 0x104, 21, 0 }, - { CLK_TOP_SSUSB_TOP_CK_EN, "ssusb_top_ck_en", NULL, 0x104, 22, 0 }, - { CLK_TOP_SSUSB_PHY_CK_EN, "ssusb_phy_ck_en", NULL, 0x104, 23, 0 }, - { CLK_TOP_AUD_I2S0_M, "aud_i2s0_m_ck", "apll12_ck_div0", 0x320, 0, 0 }, - { CLK_TOP_AUD_I2S1_M, "aud_i2s1_m_ck", "apll12_ck_div1", 0x320, 1, 0 }, - { CLK_TOP_AUD_I2S2_M, "aud_i2s2_m_ck", "apll12_ck_div2", 0x320, 2, 0 }, - { CLK_TOP_AUD_I2S3_M, "aud_i2s3_m_ck", "apll12_ck_div3", 0x320, 3, 0 }, - { CLK_TOP_AUD_TDMOUT_M, "aud_tdmout_m_ck", "apll12_ck_div4", 0x320, 4, 0 }, - { CLK_TOP_AUD_TDMOUT_B, "aud_tdmout_b_ck", "apll12_ck_div4b", 0x320, 5, 0 }, - { CLK_TOP_AUD_TDMIN_M, "aud_tdmin_m_ck", "apll12_ck_div5", 0x320, 6, 0 }, - { CLK_TOP_AUD_TDMIN_B, "aud_tdmin_b_ck", "apll12_ck_div5b", 0x320, 7, 0 }, - { CLK_TOP_AUD_SPDIF_M, "aud_spdif_m_ck", "apll12_ck_div6", 0x320, 8, 0 }, +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x104, + .sta_ofs = 0x104, +}; + +static const struct mtk_gate_regs top2_cg_regs = { + .set_ofs = 0x320, + .clr_ofs = 0x320, + .sta_ofs = 0x320, +}; + +#define GATE_TOP0(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top0_cg_regs, \ + _shift, &mtk_clk_gate_ops_no_setclr_inv) + +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, \ + _shift, &mtk_clk_gate_ops_no_setclr) + +#define GATE_TOP2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, \ + _shift, &mtk_clk_gate_ops_no_setclr) + +static const struct mtk_gate top_clk_gates[] = { + GATE_TOP0(CLK_TOP_CONN_32K, "conn_32k", "clk32k", 10), + GATE_TOP0(CLK_TOP_CONN_26M, "conn_26m", "clk26m", 11), + GATE_TOP0(CLK_TOP_DSP_32K, "dsp_32k", "clk32k", 16), + GATE_TOP0(CLK_TOP_DSP_26M, "dsp_26m", "clk26m", 17), + GATE_TOP1(CLK_TOP_USB20_48M_EN, "usb20_48m_en", "usb20_192m_d4", 8), + GATE_TOP1(CLK_TOP_UNIVPLL_48M_EN, "univpll_48m_en", "usb20_192m_d4", 9), + GATE_TOP1(CLK_TOP_LVDSTX_CLKDIG_EN, "lvdstx_dig_en", "lvdstx_dig_cts", 20), + GATE_TOP1(CLK_TOP_VPLL_DPIX_EN, "vpll_dpix_en", "vpll_dpix", 21), + GATE_TOP1(CLK_TOP_SSUSB_TOP_CK_EN, "ssusb_top_ck_en", NULL, 22), + GATE_TOP1(CLK_TOP_SSUSB_PHY_CK_EN, "ssusb_phy_ck_en", NULL, 23), + GATE_TOP2(CLK_TOP_AUD_I2S0_M, "aud_i2s0_m_ck", "apll12_ck_div0", 0), + GATE_TOP2(CLK_TOP_AUD_I2S1_M, "aud_i2s1_m_ck", "apll12_ck_div1", 1), + GATE_TOP2(CLK_TOP_AUD_I2S2_M, "aud_i2s2_m_ck", "apll12_ck_div2", 2), + GATE_TOP2(CLK_TOP_AUD_I2S3_M, "aud_i2s3_m_ck", "apll12_ck_div3", 3), + GATE_TOP2(CLK_TOP_AUD_TDMOUT_M, "aud_tdmout_m_ck", "apll12_ck_div4", 4), + GATE_TOP2(CLK_TOP_AUD_TDMOUT_B, "aud_tdmout_b_ck", "apll12_ck_div4b", 5), + GATE_TOP2(CLK_TOP_AUD_TDMIN_M, "aud_tdmin_m_ck", "apll12_ck_div5", 6), + GATE_TOP2(CLK_TOP_AUD_TDMIN_B, "aud_tdmin_b_ck", "apll12_ck_div5b", 7), + GATE_TOP2(CLK_TOP_AUD_SPDIF_M, "aud_spdif_m_ck", "apll12_ck_div6", 8), }; static const struct mtk_gate_regs ifr2_cg_regs = { @@ -631,50 +645,24 @@ static const struct mtk_gate_regs ifr6_cg_regs = { .sta_ofs = 0xd8, }; -#define GATE_IFR2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFRX(_id, _name, _parent, _shift, _regs) \ + GATE_MTK(_id, _name, _parent, _regs, _shift, \ + &mtk_clk_gate_ops_setclr) -#define GATE_IFR3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR2(_id, _name, _parent, _shift) \ + GATE_IFRX(_id, _name, _parent, _shift, &ifr2_cg_regs) -#define GATE_IFR4(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr4_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR3(_id, _name, _parent, _shift) \ + GATE_IFRX(_id, _name, _parent, _shift, &ifr3_cg_regs) -#define GATE_IFR5(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr5_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR4(_id, _name, _parent, _shift) \ + GATE_IFRX(_id, _name, _parent, _shift, &ifr4_cg_regs) -#define GATE_IFR6(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &ifr6_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_IFR5(_id, _name, _parent, _shift) \ + GATE_IFRX(_id, _name, _parent, _shift, &ifr5_cg_regs) + +#define GATE_IFR6(_id, _name, _parent, _shift) \ + GATE_IFRX(_id, _name, _parent, _shift, &ifr6_cg_regs) static const struct mtk_gate ifr_clks[] = { /* IFR2 */ @@ -753,405 +741,65 @@ static const struct mtk_gate ifr_clks[] = { GATE_IFR6(CLK_IFR_SSUSB_XHCI, "ifr_ssusb_xhci", "ssusb_xhci_sel", 11), }; -static const struct mtk_simple_gate peri_clks[] = { - { CLK_PERIAXI, "periaxi", "axi_sel", 0x20c, 31, 0 }, +static const struct mtk_gate_regs peri_cg_regs = { + .set_ofs = 0x20c, + .clr_ofs = 0x20c, + .sta_ofs = 0x20c, }; -#define MT8365_PLL_FMAX (3800UL * MHZ) -#define MT8365_PLL_FMIN (1500UL * MHZ) -#define CON0_MT8365_RST_BAR BIT(23) - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ - _tuner_en_bit, _pcw_reg, _pcw_shift, _div_table, \ - _rst_bar_mask, _pcw_chg_reg) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = _rst_bar_mask, \ - .fmax = MT8365_PLL_FMAX, \ - .fmin = MT8365_PLL_FMIN, \ - .pcwbits = _pcwbits, \ - .pcwibits = 8, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .tuner_en_reg = _tuner_en_reg, \ - .tuner_en_bit = _tuner_en_bit, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .pcw_chg_reg = _pcw_chg_reg, \ - .div_table = _div_table, \ - } - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, \ - _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ - _pcw_shift, _rst_bar_mask, _pcw_chg_reg) \ - PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ - _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _tuner_en_reg, _tuner_en_bit, \ - _pcw_reg, _pcw_shift, NULL, _rst_bar_mask, \ - _pcw_chg_reg) \ - -static const struct mtk_pll_div_table armpll_div_table[] = { - { .div = 0, .freq = MT8365_PLL_FMAX }, - { .div = 1, .freq = 1500 * MHZ }, - { .div = 2, .freq = 750 * MHZ }, - { .div = 3, .freq = 375 * MHZ }, - { .div = 4, .freq = 182500000 }, - { } /* sentinel */ +static const struct mtk_gate peri_clks[] = { + GATE_MTK(CLK_PERIAXI, "periaxi", "axi_sel", &peri_cg_regs, 31, + &mtk_clk_gate_ops_no_setclr), }; -static const struct mtk_pll_div_table mfgpll_div_table[] = { - { .div = 0, .freq = MT8365_PLL_FMAX }, - { .div = 1, .freq = 1600 * MHZ }, - { .div = 2, .freq = 800 * MHZ }, - { .div = 3, .freq = 400 * MHZ }, - { .div = 4, .freq = 200 * MHZ }, - { } /* sentinel */ +static const struct mtk_clk_desc topck_desc = { + .clks = top_clk_gates, + .num_clks = ARRAY_SIZE(top_clk_gates), + .fixed_clks = top_fixed_clks, + .num_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .mux_clks = top_muxes, + .num_mux_clks = ARRAY_SIZE(top_muxes), + .composite_clks = top_misc_muxes, + .num_composite_clks = ARRAY_SIZE(top_misc_muxes), + .divider_clks = top_adj_divs, + .num_divider_clks = ARRAY_SIZE(top_adj_divs), + .clk_lock = &mt8365_clk_lock, }; -static const struct mtk_pll_div_table dsppll_div_table[] = { - { .div = 0, .freq = MT8365_PLL_FMAX }, - { .div = 1, .freq = 1600 * MHZ }, - { .div = 2, .freq = 600 * MHZ }, - { .div = 3, .freq = 400 * MHZ }, - { .div = 4, .freq = 200 * MHZ }, - { } /* sentinel */ +static const struct mtk_clk_desc infra_desc = { + .clks = ifr_clks, + .num_clks = ARRAY_SIZE(ifr_clks), }; -static const struct mtk_pll_data plls[] = { - PLL_B(CLK_APMIXED_ARMPLL, "armpll", 0x030C, 0x0318, 0x00000001, PLL_AO, - 22, 0x0310, 24, 0, 0, 0, 0x0310, 0, armpll_div_table, 0, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0228, 0x0234, 0xFF000001, - HAVE_RST_BAR, 22, 0x022C, 24, 0, 0, 0, 0x022C, 0, - CON0_MT8365_RST_BAR, 0), - PLL(CLK_APMIXED_UNIVPLL, "univpll2", 0x0208, 0x0214, 0xFF000001, - HAVE_RST_BAR, 22, 0x020C, 24, 0, 0, 0, 0x020C, 0, - CON0_MT8365_RST_BAR, 0), - PLL_B(CLK_APMIXED_MFGPLL, "mfgpll", 0x0218, 0x0224, 0x00000001, 0, 22, - 0x021C, 24, 0, 0, 0, 0x021C, 0, mfgpll_div_table, 0, 0), - PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0350, 0x035C, 0x00000001, 0, 22, - 0x0354, 24, 0, 0, 0, 0x0354, 0, 0, 0), - PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0330, 0x033C, 0x00000001, 0, 22, - 0x0334, 24, 0, 0, 0, 0x0334, 0, 0, 0), - PLL(CLK_APMIXED_APLL1, "apll1", 0x031C, 0x032C, 0x00000001, 0, 32, - 0x0320, 24, 0x0040, 0x000C, 0, 0x0324, 0, 0, 0x0320), - PLL(CLK_APMIXED_APLL2, "apll2", 0x0360, 0x0370, 0x00000001, 0, 32, - 0x0364, 24, 0x004C, 0x000C, 5, 0x0368, 0, 0, 0x0364), - PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0374, 0x0380, 0x00000001, 0, 22, - 0x0378, 24, 0, 0, 0, 0x0378, 0, 0, 0), - PLL_B(CLK_APMIXED_DSPPLL, "dsppll", 0x0390, 0x039C, 0x00000001, 0, 22, - 0x0394, 24, 0, 0, 0, 0x0394, 0, dsppll_div_table, 0, 0), - PLL(CLK_APMIXED_APUPLL, "apupll", 0x03A0, 0x03AC, 0x00000001, 0, 22, - 0x03A4, 24, 0, 0, 0, 0x03A4, 0, 0, 0), +static const struct mtk_clk_desc peri_desc = { + .clks = peri_clks, + .num_clks = ARRAY_SIZE(peri_clks), }; -static int clk_mt8365_apmixed_probe(struct platform_device *pdev) -{ - void __iomem *base; - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct clk_hw *hw; - int ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_devm_alloc_clk_data(dev, CLK_APMIXED_NR_CLK); - if (!clk_data) - return -ENOMEM; - - hw = devm_clk_hw_register_gate(dev, "univ_en", "univpll2", 0, - base + 0x204, 0, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - clk_data->hws[CLK_APMIXED_UNIV_EN] = hw; - - hw = devm_clk_hw_register_gate(dev, "usb20_en", "univ_en", 0, - base + 0x204, 1, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - clk_data->hws[CLK_APMIXED_USB20_EN] = hw; - - ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - if (ret) - return ret; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto unregister_plls; - - return 0; - -unregister_plls: - mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); - - return ret; -} - -static int -clk_mt8365_register_mtk_simple_gates(struct device *dev, void __iomem *base, - struct clk_hw_onecell_data *clk_data, - const struct mtk_simple_gate *gates, - unsigned int num_gates) -{ - unsigned int i; - - for (i = 0; i != num_gates; ++i) { - const struct mtk_simple_gate *gate = &gates[i]; - struct clk_hw *hw; - - hw = devm_clk_hw_register_gate(dev, gate->name, gate->parent, 0, - base + gate->reg, gate->shift, - gate->gate_flags, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); - - clk_data->hws[gate->id] = hw; - } - - return 0; -} - -static int clk_mt8365_top_probe(struct platform_device *pdev) -{ - void __iomem *base; - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - struct device *dev = &pdev->dev; - int ret; - int i; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - if (!clk_data) - return -ENOMEM; - - ret = mtk_clk_register_fixed_clks(top_fixed_clks, - ARRAY_SIZE(top_fixed_clks), clk_data); - if (ret) - goto free_clk_data; - - ret = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), - clk_data); - if (ret) - goto unregister_fixed_clks; - - ret = mtk_clk_register_muxes(&pdev->dev, top_muxes, - ARRAY_SIZE(top_muxes), node, - &mt8365_clk_lock, clk_data); - if (ret) - goto unregister_factors; - - ret = mtk_clk_register_composites(&pdev->dev, top_misc_mux_gates, - ARRAY_SIZE(top_misc_mux_gates), base, - &mt8365_clk_lock, clk_data); - if (ret) - goto unregister_muxes; - - for (i = 0; i != ARRAY_SIZE(top_misc_muxes); ++i) { - struct mt8365_clk_audio_mux *mux = &top_misc_muxes[i]; - struct clk_hw *hw; - - hw = devm_clk_hw_register_mux(dev, mux->name, apll_i2s0_parents, - ARRAY_SIZE(apll_i2s0_parents), - CLK_SET_RATE_PARENT, base + 0x320, - mux->shift, 1, 0, NULL); - if (IS_ERR(hw)) { - ret = PTR_ERR(hw); - goto unregister_composites; - } - - clk_data->hws[mux->id] = hw; - } - - ret = mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), - base, &mt8365_clk_lock, clk_data); - if (ret) - goto unregister_composites; - - ret = clk_mt8365_register_mtk_simple_gates(dev, base, clk_data, - top_clk_gates, - ARRAY_SIZE(top_clk_gates)); - if (ret) - goto unregister_dividers; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto unregister_dividers; - - return 0; -unregister_dividers: - mtk_clk_unregister_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), - clk_data); -unregister_composites: - mtk_clk_unregister_composites(top_misc_mux_gates, - ARRAY_SIZE(top_misc_mux_gates), clk_data); -unregister_muxes: - mtk_clk_unregister_muxes(top_muxes, ARRAY_SIZE(top_muxes), clk_data); -unregister_factors: - mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); -unregister_fixed_clks: - mtk_clk_unregister_fixed_clks(top_fixed_clks, - ARRAY_SIZE(top_fixed_clks), clk_data); -free_clk_data: - mtk_free_clk_data(clk_data); - - return ret; -} - -static int clk_mt8365_infra_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - int ret; - - clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); - if (!clk_data) - return -ENOMEM; - - ret = mtk_clk_register_gates(&pdev->dev, node, ifr_clks, - ARRAY_SIZE(ifr_clks), clk_data); - if (ret) - goto free_clk_data; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto unregister_gates; - - return 0; - -unregister_gates: - mtk_clk_unregister_gates(ifr_clks, ARRAY_SIZE(ifr_clks), clk_data); -free_clk_data: - mtk_free_clk_data(clk_data); - - return ret; -} - -static int clk_mt8365_peri_probe(struct platform_device *pdev) -{ - void __iomem *base; - struct clk_hw_onecell_data *clk_data; - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - int ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_devm_alloc_clk_data(dev, CLK_PERI_NR_CLK); - if (!clk_data) - return -ENOMEM; - - ret = clk_mt8365_register_mtk_simple_gates(dev, base, clk_data, - peri_clks, - ARRAY_SIZE(peri_clks)); - if (ret) - return ret; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - - return ret; -} - -static int clk_mt8365_mcu_probe(struct platform_device *pdev) -{ - struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; - void __iomem *base; - int ret; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); - if (!clk_data) - return -ENOMEM; - - ret = mtk_clk_register_composites(&pdev->dev, mcu_muxes, - ARRAY_SIZE(mcu_muxes), base, - &mt8365_clk_lock, clk_data); - if (ret) - goto free_clk_data; - - ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (ret) - goto unregister_composites; - - return 0; - -unregister_composites: - mtk_clk_unregister_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), - clk_data); -free_clk_data: - mtk_free_clk_data(clk_data); - - return ret; -} +static const struct mtk_clk_desc mcu_desc = { + .composite_clks = mcu_muxes, + .num_composite_clks = ARRAY_SIZE(mcu_muxes), + .clk_lock = &mt8365_clk_lock, +}; static const struct of_device_id of_match_clk_mt8365[] = { - { - .compatible = "mediatek,mt8365-apmixedsys", - .data = clk_mt8365_apmixed_probe, - }, { - .compatible = "mediatek,mt8365-topckgen", - .data = clk_mt8365_top_probe, - }, { - .compatible = "mediatek,mt8365-infracfg", - .data = clk_mt8365_infra_probe, - }, { - .compatible = "mediatek,mt8365-pericfg", - .data = clk_mt8365_peri_probe, - }, { - .compatible = "mediatek,mt8365-mcucfg", - .data = clk_mt8365_mcu_probe, - }, { - /* sentinel */ - } + { .compatible = "mediatek,mt8365-topckgen", .data = &topck_desc }, + { .compatible = "mediatek,mt8365-infracfg", .data = &infra_desc }, + { .compatible = "mediatek,mt8365-pericfg", .data = &peri_desc }, + { .compatible = "mediatek,mt8365-mcucfg", .data = &mcu_desc }, + { /* sentinel */ } }; - -static int clk_mt8365_probe(struct platform_device *pdev) -{ - int (*clk_probe)(struct platform_device *pdev); - int ret; - - clk_probe = of_device_get_match_data(&pdev->dev); - if (!clk_probe) - return -EINVAL; - - ret = clk_probe(pdev); - if (ret) - dev_err(&pdev->dev, - "%s: could not register clock provider: %d\n", - pdev->name, ret); - - return ret; -} +MODULE_DEVICE_TABLE(of, of_match_clk_mt8365); static struct platform_driver clk_mt8365_drv = { - .probe = clk_mt8365_probe, .driver = { .name = "clk-mt8365", .of_match_table = of_match_clk_mt8365, }, + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, }; - -static int __init clk_mt8365_init(void) -{ - return platform_driver_register(&clk_mt8365_drv); -} -arch_initcall(clk_mt8365_init); +module_platform_driver(clk_mt8365_drv); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8516-apmixedsys.c b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c new file mode 100644 index 000000000000..edd9174d2f2f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt8516-apmixedsys.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019 MediaTek Inc. + * James Liao + * Fabien Parent + * + * Copyright (c) 2023 Collabora, Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +#define MT8516_PLL_FMAX (1502UL * MHZ) + +#define CON0_MT8516_RST_BAR BIT(27) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8516_RST_BAR, \ + .fmax = MT8516_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL) + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT8516_PLL_FMAX }, + { .div = 1, .freq = 1000000000 }, + { .div = 2, .freq = 604500000 }, + { .div = 3, .freq = 253500000 }, + { .div = 4, .freq = 126750000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0100, 0x0110, 0, 0, + 21, 0x0104, 24, 0, 0x0104, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0120, 0x0130, 0, + HAVE_RST_BAR, 21, 0x0124, 24, 0, 0x0124, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0140, 0x0150, 0x30000000, + HAVE_RST_BAR, 7, 0x0144, 24, 0, 0x0144, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0160, 0x0170, 0, 0, + 21, 0x0164, 24, 0, 0x0164, 0, mmpll_div_table), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0180, 0x0190, 0, 0, + 31, 0x0180, 1, 0x0194, 0x0184, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x01A0, 0x01B0, 0, 0, + 31, 0x01A0, 1, 0x01B4, 0x01A4, 0), +}; + +static int clk_mt8516_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct clk_hw_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(dev, CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) + goto unregister_plls; + + return 0; + +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + + return ret; +} + +static const struct of_device_id of_match_clk_mt8516_apmixed[] = { + { .compatible = "mediatek,mt8516-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8516_apmixed); + +static struct platform_driver clk_mt8516_apmixed_drv = { + .probe = clk_mt8516_apmixed_probe, + .driver = { + .name = "clk-mt8516-apmixed", + .of_match_table = of_match_clk_mt8516_apmixed, + }, +}; +builtin_platform_driver(clk_mt8516_apmixed_drv) + +MODULE_DESCRIPTION("MediaTek MT8516 apmixedsys clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c index 00f356fe7c7a..48340fc7430d 100644 --- a/drivers/clk/mediatek/clk-mt8516-aud.c +++ b/drivers/clk/mediatek/clk-mt8516-aud.c @@ -3,6 +3,7 @@ * Copyright (c) 2019 MediaTek Inc. * Author: James Liao * Fabien Parent + * Copyright (c) 2023 Collabora Ltd. */ #include @@ -22,16 +23,10 @@ static const struct mtk_gate_regs aud_cg_regs = { .sta_ofs = 0x0, }; -#define GATE_AUD(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &aud_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_AUD(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &aud_cg_regs, _shift, &mtk_clk_gate_ops_no_setclr) -static const struct mtk_gate aud_clks[] __initconst = { +static const struct mtk_gate aud_clks[] = { GATE_AUD(CLK_AUD_AFE, "aud_afe", "clk26m_ck", 2), GATE_AUD(CLK_AUD_I2S, "aud_i2s", "i2s_infra_bck", 6), GATE_AUD(CLK_AUD_22M, "aud_22m", "rg_aud_engen1", 8), @@ -47,19 +42,26 @@ static const struct mtk_gate aud_clks[] __initconst = { GATE_AUD(CLK_AUD_TML, "aud_tml", "aud_afe", 27), }; -static void __init mtk_audsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; +static const struct mtk_clk_desc aud_desc = { + .clks = aud_clks, + .num_clks = ARRAY_SIZE(aud_clks), +}; - clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK); +static const struct of_device_id of_match_clk_mt8516_aud[] = { + { .compatible = "mediatek,mt8516-audsys", .data = &aud_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8516_aud); - mtk_clk_register_gates(NULL, node, aud_clks, ARRAY_SIZE(aud_clks), clk_data); +static struct platform_driver clk_mt8516_aud_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8516-aud", + .of_match_table = of_match_clk_mt8516_aud, + }, +}; +module_platform_driver(clk_mt8516_aud_drv); - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_audsys, "mediatek,mt8516-audsys", mtk_audsys_init); +MODULE_DESCRIPTION("MediaTek MT8516 audiosys clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c index 2c0cae7b3bcf..21eb052b0a53 100644 --- a/drivers/clk/mediatek/clk-mt8516.c +++ b/drivers/clk/mediatek/clk-mt8516.c @@ -3,6 +3,7 @@ * Copyright (c) 2019 MediaTek Inc. * Author: James Liao * Fabien Parent + * Copyright (c) 2023 Collabora Ltd. */ #include @@ -10,10 +11,10 @@ #include #include #include +#include #include "clk-gate.h" #include "clk-mtk.h" -#include "clk-pll.h" #include @@ -525,59 +526,23 @@ static const struct mtk_gate_regs top5_cg_regs = { .sta_ofs = 0x44, }; -#define GATE_TOP1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP1(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top1_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP2(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP2_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_TOP2_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top2_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_TOP3(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top3_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ - } +#define GATE_TOP3(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top3_cg_regs, _shift, &mtk_clk_gate_ops_setclr) -#define GATE_TOP4_I(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top4_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr_inv, \ - } +#define GATE_TOP4_I(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top4_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) -#define GATE_TOP5(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &top5_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_no_setclr, \ - } +#define GATE_TOP5(_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &top5_cg_regs, _shift, &mtk_clk_gate_ops_setclr) static const struct mtk_gate top_clks[] __initconst = { /* TOP1 */ @@ -675,139 +640,42 @@ static const struct mtk_gate top_clks[] __initconst = { GATE_TOP5(CLK_TOP_APLL12_DIV6, "apll12_div6", "apll12_ck_div6", 8), }; -static void __init mtk_topckgen_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - void __iomem *base; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); - - mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), - clk_data); - mtk_clk_register_gates(NULL, node, top_clks, ARRAY_SIZE(top_clks), clk_data); - - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); - mtk_clk_register_composites(NULL, top_muxes, - ARRAY_SIZE(top_muxes), base, - &mt8516_clk_lock, clk_data); - mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), - base, &mt8516_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8516-topckgen", mtk_topckgen_init); - -static void __init mtk_infracfg_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - int r; - void __iomem *base; - - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } - - clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); - - mtk_clk_register_composites(NULL, ifr_muxes, - ARRAY_SIZE(ifr_muxes), base, - &mt8516_clk_lock, clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -} -CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt8516-infracfg", mtk_infracfg_init); - -#define MT8516_PLL_FMAX (1502UL * MHZ) - -#define CON0_MT8516_RST_BAR BIT(27) - -#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift, _div_table) { \ - .id = _id, \ - .name = _name, \ - .reg = _reg, \ - .pwr_reg = _pwr_reg, \ - .en_mask = _en_mask, \ - .flags = _flags, \ - .rst_bar_mask = CON0_MT8516_RST_BAR, \ - .fmax = MT8516_PLL_FMAX, \ - .pcwbits = _pcwbits, \ - .pd_reg = _pd_reg, \ - .pd_shift = _pd_shift, \ - .tuner_reg = _tuner_reg, \ - .pcw_reg = _pcw_reg, \ - .pcw_shift = _pcw_shift, \ - .div_table = _div_table, \ - } - -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ - _pcw_shift) \ - PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ - _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ - NULL) - -static const struct mtk_pll_div_table mmpll_div_table[] = { - { .div = 0, .freq = MT8516_PLL_FMAX }, - { .div = 1, .freq = 1000000000 }, - { .div = 2, .freq = 604500000 }, - { .div = 3, .freq = 253500000 }, - { .div = 4, .freq = 126750000 }, - { } /* sentinel */ +static const struct mtk_clk_desc topck_desc = { + .clks = top_clks, + .num_clks = ARRAY_SIZE(top_clks), + .fixed_clks = fixed_clks, + .num_fixed_clks = ARRAY_SIZE(fixed_clks), + .factor_clks = top_divs, + .num_factor_clks = ARRAY_SIZE(top_divs), + .composite_clks = top_muxes, + .num_composite_clks = ARRAY_SIZE(top_muxes), + .divider_clks = top_adj_divs, + .num_divider_clks = ARRAY_SIZE(top_adj_divs), + .clk_lock = &mt8516_clk_lock, }; -static const struct mtk_pll_data plls[] = { - PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0100, 0x0110, 0, 0, - 21, 0x0104, 24, 0, 0x0104, 0), - PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0120, 0x0130, 0, - HAVE_RST_BAR, 21, 0x0124, 24, 0, 0x0124, 0), - PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0140, 0x0150, 0x30000000, - HAVE_RST_BAR, 7, 0x0144, 24, 0, 0x0144, 0), - PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0160, 0x0170, 0, 0, - 21, 0x0164, 24, 0, 0x0164, 0, mmpll_div_table), - PLL(CLK_APMIXED_APLL1, "apll1", 0x0180, 0x0190, 0, 0, - 31, 0x0180, 1, 0x0194, 0x0184, 0), - PLL(CLK_APMIXED_APLL2, "apll2", 0x01A0, 0x01B0, 0, 0, - 31, 0x01A0, 1, 0x01B4, 0x01A4, 0), +static const struct mtk_clk_desc infra_desc = { + .composite_clks = ifr_muxes, + .num_composite_clks = ARRAY_SIZE(ifr_muxes), + .clk_lock = &mt8516_clk_lock, }; -static void __init mtk_apmixedsys_init(struct device_node *node) -{ - struct clk_hw_onecell_data *clk_data; - void __iomem *base; - int r; +static const struct of_device_id of_match_clk_mt8516[] = { + { .compatible = "mediatek,mt8516-topckgen", .data = &topck_desc }, + { .compatible = "mediatek,mt8516-infracfg", .data = &infra_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt8516); - base = of_iomap(node, 0); - if (!base) { - pr_err("%s(): ioremap failed\n", __func__); - return; - } +static struct platform_driver clk_mt8516_drv = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt8516", + .of_match_table = of_match_clk_mt8516, + }, +}; +module_platform_driver(clk_mt8516_drv); - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); - - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); - -} -CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8516-apmixedsys", - mtk_apmixedsys_init); +MODULE_DESCRIPTION("MediaTek MT8516 clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 14e8b64a32a3..fd2214c3242f 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -394,7 +393,8 @@ void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, } EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites); -int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, +int mtk_clk_register_dividers(struct device *dev, + const struct mtk_clk_divider *mcds, int num, void __iomem *base, spinlock_t *lock, struct clk_hw_onecell_data *clk_data) { @@ -413,7 +413,7 @@ int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, continue; } - hw = clk_hw_register_divider(NULL, mcd->name, mcd->parent_name, + hw = clk_hw_register_divider(dev, mcd->name, mcd->parent_name, mcd->flags, base + mcd->div_reg, mcd->div_shift, mcd->div_width, mcd->clk_divider_flags, lock); @@ -463,17 +463,25 @@ void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, } EXPORT_SYMBOL_GPL(mtk_clk_unregister_dividers); -int mtk_clk_simple_probe(struct platform_device *pdev) +static int __mtk_clk_simple_probe(struct platform_device *pdev, + struct device_node *node) { + const struct platform_device_id *id; const struct mtk_clk_desc *mcd; struct clk_hw_onecell_data *clk_data; - struct device_node *node = pdev->dev.of_node; void __iomem *base; int num_clks, r; - mcd = of_device_get_match_data(&pdev->dev); - if (!mcd) - return -EINVAL; + mcd = device_get_match_data(&pdev->dev); + if (!mcd) { + /* Clock driver wasn't registered from devicetree */ + id = platform_get_device_id(pdev); + if (id) + mcd = (const struct mtk_clk_desc *)id->driver_data; + + if (!mcd) + return -EINVAL; + } /* Composite clocks needs us to pass iomem pointer */ if (mcd->composite_clks) { @@ -489,7 +497,7 @@ int mtk_clk_simple_probe(struct platform_device *pdev) /* Calculate how many clk_hw_onecell_data entries to allocate */ num_clks = mcd->num_clks + mcd->num_composite_clks; num_clks += mcd->num_fixed_clks + mcd->num_factor_clks; - num_clks += mcd->num_mux_clks; + num_clks += mcd->num_mux_clks + mcd->num_divider_clks; clk_data = mtk_alloc_clk_data(num_clks); if (!clk_data) @@ -527,11 +535,20 @@ int mtk_clk_simple_probe(struct platform_device *pdev) goto unregister_muxes; } + if (mcd->divider_clks) { + r = mtk_clk_register_dividers(&pdev->dev, + mcd->divider_clks, + mcd->num_divider_clks, + base, mcd->clk_lock, clk_data); + if (r) + goto unregister_composites; + } + if (mcd->clks) { r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks, mcd->num_clks, clk_data); if (r) - goto unregister_composites; + goto unregister_dividers; } if (mcd->clk_notifier_func) { @@ -560,6 +577,10 @@ int mtk_clk_simple_probe(struct platform_device *pdev) unregister_clks: if (mcd->clks) mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); +unregister_dividers: + if (mcd->divider_clks) + mtk_clk_unregister_dividers(mcd->divider_clks, + mcd->num_divider_clks, clk_data); unregister_composites: if (mcd->composite_clks) mtk_clk_unregister_composites(mcd->composite_clks, @@ -582,17 +603,19 @@ free_data: iounmap(base); return r; } -EXPORT_SYMBOL_GPL(mtk_clk_simple_probe); -int mtk_clk_simple_remove(struct platform_device *pdev) +static int __mtk_clk_simple_remove(struct platform_device *pdev, + struct device_node *node) { - const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev); struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); - struct device_node *node = pdev->dev.of_node; + const struct mtk_clk_desc *mcd = device_get_match_data(&pdev->dev); of_clk_del_provider(node); if (mcd->clks) mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); + if (mcd->divider_clks) + mtk_clk_unregister_dividers(mcd->divider_clks, + mcd->num_divider_clks, clk_data); if (mcd->composite_clks) mtk_clk_unregister_composites(mcd->composite_clks, mcd->num_composite_clks, clk_data); @@ -609,6 +632,37 @@ int mtk_clk_simple_remove(struct platform_device *pdev) return 0; } + +int mtk_clk_pdev_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->parent->of_node; + + return __mtk_clk_simple_probe(pdev, node); +} +EXPORT_SYMBOL_GPL(mtk_clk_pdev_probe); + +int mtk_clk_simple_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + + return __mtk_clk_simple_probe(pdev, node); +} +EXPORT_SYMBOL_GPL(mtk_clk_simple_probe); + +int mtk_clk_pdev_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->parent->of_node; + + return __mtk_clk_simple_remove(pdev, node); +} +EXPORT_SYMBOL_GPL(mtk_clk_pdev_remove); + +int mtk_clk_simple_remove(struct platform_device *pdev) +{ + return __mtk_clk_simple_remove(pdev, pdev->dev.of_node); +} EXPORT_SYMBOL_GPL(mtk_clk_simple_remove); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 41f4fa3b0c21..b7a751861fce 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -202,7 +202,8 @@ struct mtk_clk_divider { .div_width = _width, \ } -int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, +int mtk_clk_register_dividers(struct device *dev, + const struct mtk_clk_divider *mcds, int num, void __iomem *base, spinlock_t *lock, struct clk_hw_onecell_data *clk_data); void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, @@ -222,6 +223,8 @@ struct mtk_clk_desc { size_t num_clks; const struct mtk_composite *composite_clks; size_t num_composite_clks; + const struct mtk_clk_divider *divider_clks; + size_t num_divider_clks; const struct mtk_fixed_clk *fixed_clks; size_t num_fixed_clks; const struct mtk_fixed_factor *factor_clks; @@ -236,6 +239,8 @@ struct mtk_clk_desc { unsigned int mfg_clk_idx; }; +int mtk_clk_pdev_probe(struct platform_device *pdev); +int mtk_clk_pdev_remove(struct platform_device *pdev); int mtk_clk_simple_probe(struct platform_device *pdev); int mtk_clk_simple_remove(struct platform_device *pdev); diff --git a/drivers/clk/mediatek/clk-pllfh.c b/drivers/clk/mediatek/clk-pllfh.c index f48780bec507..3a2b3f90be25 100644 --- a/drivers/clk/mediatek/clk-pllfh.c +++ b/drivers/clk/mediatek/clk-pllfh.c @@ -75,13 +75,13 @@ void fhctl_parse_dt(const u8 *compatible_node, struct mtk_pllfh_data *pllfhs, base = of_iomap(node, 0); if (!base) { pr_err("%s(): ioremap failed\n", __func__); - return; + goto out_node_put; } num_clocks = of_clk_get_parent_count(node); if (!num_clocks) { pr_err("%s(): failed to get clocks property\n", __func__); - return; + goto err; } for (i = 0; i < num_clocks; i++) { @@ -102,16 +102,26 @@ void fhctl_parse_dt(const u8 *compatible_node, struct mtk_pllfh_data *pllfhs, pllfh->state.ssc_rate = ssc_rate; pllfh->state.base = base; } -} -static void pllfh_init(struct mtk_fh *fh, struct mtk_pllfh_data *pllfh_data) +out_node_put: + of_node_put(node); + return; +err: + iounmap(base); + goto out_node_put; +} +EXPORT_SYMBOL_GPL(fhctl_parse_dt); + +static int pllfh_init(struct mtk_fh *fh, struct mtk_pllfh_data *pllfh_data) { struct fh_pll_regs *regs = &fh->regs; const struct fhctl_offset *offset; void __iomem *base = pllfh_data->state.base; void __iomem *fhx_base = base + pllfh_data->data.fhx_offset; - offset = fhctl_get_offset_table(); + offset = fhctl_get_offset_table(pllfh_data->data.fh_ver); + if (IS_ERR(offset)) + return PTR_ERR(offset); regs->reg_hp_en = base + offset->offset_hp_en; regs->reg_clk_con = base + offset->offset_clk_con; @@ -129,6 +139,8 @@ static void pllfh_init(struct mtk_fh *fh, struct mtk_pllfh_data *pllfh_data) fh->lock = &pllfh_lock; fh->ops = fhctl_get_ops(); + + return 0; } static bool fhctl_is_supported_and_enabled(const struct mtk_pllfh_data *pllfh) @@ -142,20 +154,29 @@ mtk_clk_register_pllfh(const struct mtk_pll_data *pll_data, { struct clk_hw *hw; struct mtk_fh *fh; + int ret; fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (!fh) return ERR_PTR(-ENOMEM); - pllfh_init(fh, pllfh_data); + ret = pllfh_init(fh, pllfh_data); + if (ret) { + hw = ERR_PTR(ret); + goto out; + } hw = mtk_clk_register_pll_ops(&fh->clk_pll, pll_data, base, &mtk_pllfh_ops); + if (IS_ERR(hw)) + goto out; + + fhctl_hw_init(fh); + +out: if (IS_ERR(hw)) kfree(fh); - else - fhctl_hw_init(fh); return hw; } @@ -234,6 +255,7 @@ err: return PTR_ERR(hw); } +EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs); void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls, struct mtk_pllfh_data *pllfhs, int num_fhs, @@ -273,3 +295,4 @@ void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls, iounmap(base); } +EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs); diff --git a/drivers/clk/mediatek/clk-pllfh.h b/drivers/clk/mediatek/clk-pllfh.h index c0a6e1537034..5f419c2ec01f 100644 --- a/drivers/clk/mediatek/clk-pllfh.h +++ b/drivers/clk/mediatek/clk-pllfh.h @@ -18,6 +18,7 @@ struct fh_pll_state { struct fh_pll_data { int pll_id; int fh_id; + int fh_ver; u32 fhx_offset; u32 dds_mask; u32 slope0_value; diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c index 4f0a19db7ed7..c8ffa755b58d 100644 --- a/drivers/clk/microchip/clk-mpfs.c +++ b/drivers/clk/microchip/clk-mpfs.c @@ -374,14 +374,13 @@ static void mpfs_reset_unregister_adev(void *_adev) struct auxiliary_device *adev = _adev; auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); } static void mpfs_reset_adev_release(struct device *dev) { struct auxiliary_device *adev = to_auxiliary_dev(dev); - auxiliary_device_uninit(adev); - kfree(adev); } @@ -513,4 +512,3 @@ MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver"); MODULE_AUTHOR("Padmarao Begari "); MODULE_AUTHOR("Daire McNamara "); MODULE_AUTHOR("Conor Dooley "); -MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mmp/clk-audio.c b/drivers/clk/mmp/clk-audio.c index 7aa7f4a9564f..6fb1aa9487b5 100644 --- a/drivers/clk/mmp/clk-audio.c +++ b/drivers/clk/mmp/clk-audio.c @@ -384,12 +384,10 @@ disable_pm_runtime: return ret; } -static int mmp2_audio_clk_remove(struct platform_device *pdev) +static void mmp2_audio_clk_remove(struct platform_device *pdev) { pm_clk_destroy(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM @@ -436,7 +434,7 @@ static struct platform_driver mmp2_audio_clk_driver = { .pm = &mmp2_audio_clk_pm_ops, }, .probe = mmp2_audio_clk_probe, - .remove = mmp2_audio_clk_remove, + .remove_new = mmp2_audio_clk_remove, }; module_platform_driver(mmp2_audio_clk_driver); diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index e3777ca65912..3ae6078f6ff7 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -781,7 +781,7 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) return 0; } -static int armada_3700_periph_clock_remove(struct platform_device *pdev) +static void armada_3700_periph_clock_remove(struct platform_device *pdev) { struct clk_periph_driver_data *data = platform_get_drvdata(pdev); struct clk_hw_onecell_data *hw_data = data->hw_data; @@ -791,13 +791,11 @@ static int armada_3700_periph_clock_remove(struct platform_device *pdev) for (i = 0; i < hw_data->num; i++) clk_hw_unregister(hw_data->hws[i]); - - return 0; } static struct platform_driver armada_3700_periph_clock_driver = { .probe = armada_3700_periph_clock_probe, - .remove = armada_3700_periph_clock_remove, + .remove_new = armada_3700_periph_clock_remove, .driver = { .name = "marvell-armada-3700-periph-clock", .of_match_table = armada_3700_periph_clock_of_match, diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c index fc403ad735ad..eccc1aeefbaf 100644 --- a/drivers/clk/mvebu/armada-37xx-tbg.c +++ b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -126,7 +126,7 @@ static int armada_3700_tbg_clock_probe(struct platform_device *pdev) return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, hw_tbg_data); } -static int armada_3700_tbg_clock_remove(struct platform_device *pdev) +static void armada_3700_tbg_clock_remove(struct platform_device *pdev) { int i; struct clk_hw_onecell_data *hw_tbg_data = platform_get_drvdata(pdev); @@ -134,8 +134,6 @@ static int armada_3700_tbg_clock_remove(struct platform_device *pdev) of_clk_del_provider(pdev->dev.of_node); for (i = 0; i < hw_tbg_data->num; i++) clk_hw_unregister_fixed_factor(hw_tbg_data->hws[i]); - - return 0; } static const struct of_device_id armada_3700_tbg_clock_of_match[] = { @@ -145,7 +143,7 @@ static const struct of_device_id armada_3700_tbg_clock_of_match[] = { static struct platform_driver armada_3700_tbg_clock_driver = { .probe = armada_3700_tbg_clock_probe, - .remove = armada_3700_tbg_clock_remove, + .remove_new = armada_3700_tbg_clock_remove, .driver = { .name = "marvell-armada-3700-tbg-clock", .of_match_table = armada_3700_tbg_clock_of_match, diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c index 41271351cf1f..0e2e7d00ae11 100644 --- a/drivers/clk/mvebu/armada-37xx-xtal.c +++ b/drivers/clk/mvebu/armada-37xx-xtal.c @@ -65,11 +65,9 @@ static int armada_3700_xtal_clock_probe(struct platform_device *pdev) return ret; } -static int armada_3700_xtal_clock_remove(struct platform_device *pdev) +static void armada_3700_xtal_clock_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - - return 0; } static const struct of_device_id armada_3700_xtal_clock_of_match[] = { @@ -79,7 +77,7 @@ static const struct of_device_id armada_3700_xtal_clock_of_match[] = { static struct platform_driver armada_3700_xtal_clock_driver = { .probe = armada_3700_xtal_clock_probe, - .remove = armada_3700_xtal_clock_remove, + .remove_new = armada_3700_xtal_clock_remove, .driver = { .name = "marvell-armada-3700-xtal-clock", .of_match_table = armada_3700_xtal_clock_of_match, diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 5ab4b7dfe3c2..12be3e2371b3 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -141,6 +141,14 @@ config IPQ_GCC_4019 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, etc. +config IPQ_GCC_5332 + tristate "IPQ5332 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + help + Support for the global clock controller on ipq5332 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. + config IPQ_GCC_6018 tristate "IPQ6018 Global Clock Controller" help @@ -173,6 +181,14 @@ config IPQ_GCC_8074 i2c, USB, SD/eMMC, etc. Select this for the root clock of ipq8074. +config IPQ_GCC_9574 + tristate "IPQ9574 Global Clock Controller" + help + Support for global clock controller on ipq9574 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, SD/eMMC, etc. Select this for the root clock + of ipq9574. + config MSM_GCC_8660 tristate "MSM8660 Global Clock Controller" help @@ -196,6 +212,16 @@ config MSM_GCC_8916 Say Y if you want to use devices such as UART, SPI i2c, USB, SD/eMMC, display, graphics, camera etc. +config MSM_GCC_8917 + tristate "MSM8917/QM215 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on msm8917 and qm215 + devices. + Say Y if you want to use devices such as UART, SPI i2c, USB, + SD/eMMC, display, graphics, camera etc. + config MSM_GCC_8939 tristate "MSM8939 Global Clock Controller" select QCOM_GDSC @@ -419,6 +445,15 @@ config SA_GCC_8775P Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, UFS, SDCC, etc. +config SA_GPUCC_8775P + tristate "SA8775P Graphics clock controller" + select QCOM_GDSC + select SA_GCC_8775P + help + Support for the graphics clock controller on SA8775P devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SC_GCC_7180 tristate "SC7180 Global Clock Controller" select QCOM_GDSC @@ -759,6 +794,14 @@ config SM_GCC_6375 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS etc. +config SM_GCC_7150 + tristate "SM7150 Global Clock Controller" + select QCOM_GDSC + help + Support for the global clock controller on SM7150 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SM_GCC_8150 tristate "SM8150 Global Clock Controller" help @@ -798,6 +841,33 @@ config SM_GCC_8550 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS, PCIe etc. +config SM_GPUCC_6115 + tristate "SM6115 Graphics Clock Controller" + select SM_GCC_6115 + depends on ARM64 || COMPILE_TEST + help + Support for the graphics clock controller on SM6115 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + +config SM_GPUCC_6125 + tristate "SM6125 Graphics Clock Controller" + select SM_GCC_6125 + depends on ARM64 || COMPILE_TEST + help + Support for the graphics clock controller on SM6125 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + +config SM_GPUCC_6375 + tristate "SM6375 Graphics Clock Controller" + select SM_GCC_6375 + depends on ARM64 || COMPILE_TEST + help + Support for the graphics clock controller on SM6375 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SM_GPUCC_6350 tristate "SM6350 Graphics Clock Controller" select SM_GCC_6350 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index c743805a9cbb..9ff4c373ad95 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -24,9 +24,11 @@ obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o +obj-$(CONFIG_IPQ_GCC_5332) += gcc-ipq5332.o obj-$(CONFIG_IPQ_GCC_6018) += gcc-ipq6018.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o +obj-$(CONFIG_IPQ_GCC_9574) += gcc-ipq9574.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MDM_GCC_9607) += gcc-mdm9607.o obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o @@ -34,6 +36,7 @@ obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8909) += gcc-msm8909.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o +obj-$(CONFIG_MSM_GCC_8917) += gcc-msm8917.o obj-$(CONFIG_MSM_GCC_8939) += gcc-msm8939.o obj-$(CONFIG_MSM_GCC_8953) += gcc-msm8953.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o @@ -69,6 +72,7 @@ obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_DISPCC_7280) += dispcc-sc7280.o obj-$(CONFIG_SC_DISPCC_8280XP) += dispcc-sc8280xp.o obj-$(CONFIG_SA_GCC_8775P) += gcc-sa8775p.o +obj-$(CONFIG_SA_GPUCC_8775P) += gpucc-sa8775p.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o obj-$(CONFIG_SC_GCC_7280) += gcc-sc7280.o obj-$(CONFIG_SC_GCC_8180X) += gcc-sc8180x.o @@ -107,12 +111,16 @@ obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o obj-$(CONFIG_SM_GCC_6350) += gcc-sm6350.o obj-$(CONFIG_SM_GCC_6375) += gcc-sm6375.o +obj-$(CONFIG_SM_GCC_7150) += gcc-sm7150.o obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SM_GCC_8350) += gcc-sm8350.o obj-$(CONFIG_SM_GCC_8450) += gcc-sm8450.o obj-$(CONFIG_SM_GCC_8550) += gcc-sm8550.o +obj-$(CONFIG_SM_GPUCC_6115) += gpucc-sm6115.o +obj-$(CONFIG_SM_GPUCC_6125) += gpucc-sm6125.o obj-$(CONFIG_SM_GPUCC_6350) += gpucc-sm6350.o +obj-$(CONFIG_SM_GPUCC_6375) += gpucc-sm6375.o obj-$(CONFIG_SM_GPUCC_8150) += gpucc-sm8150.o obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o diff --git a/drivers/clk/qcom/apcs-msm8916.c b/drivers/clk/qcom/apcs-msm8916.c index 89e0730810ac..ce57b333ec99 100644 --- a/drivers/clk/qcom/apcs-msm8916.c +++ b/drivers/clk/qcom/apcs-msm8916.c @@ -119,18 +119,16 @@ err: return ret; } -static int qcom_apcs_msm8916_clk_remove(struct platform_device *pdev) +static void qcom_apcs_msm8916_clk_remove(struct platform_device *pdev) { struct clk_regmap_mux_div *a53cc = platform_get_drvdata(pdev); clk_notifier_unregister(a53cc->pclk, &a53cc->clk_nb); - - return 0; } static struct platform_driver qcom_apcs_msm8916_clk_driver = { .probe = qcom_apcs_msm8916_clk_probe, - .remove = qcom_apcs_msm8916_clk_remove, + .remove_new = qcom_apcs_msm8916_clk_remove, .driver = { .name = "qcom-apcs-msm8916-clk", }, diff --git a/drivers/clk/qcom/apcs-sdx55.c b/drivers/clk/qcom/apcs-sdx55.c index e599f862ec44..d644e6e1f8b7 100644 --- a/drivers/clk/qcom/apcs-sdx55.c +++ b/drivers/clk/qcom/apcs-sdx55.c @@ -120,20 +120,18 @@ err: return ret; } -static int qcom_apcs_sdx55_clk_remove(struct platform_device *pdev) +static void qcom_apcs_sdx55_clk_remove(struct platform_device *pdev) { struct device *cpu_dev = get_cpu_device(0); struct clk_regmap_mux_div *a7cc = platform_get_drvdata(pdev); clk_notifier_unregister(a7cc->pclk, &a7cc->clk_nb); dev_pm_domain_detach(cpu_dev, true); - - return 0; } static struct platform_driver qcom_apcs_sdx55_clk_driver = { .probe = qcom_apcs_sdx55_clk_probe, - .remove = qcom_apcs_sdx55_clk_remove, + .remove_new = qcom_apcs_sdx55_clk_remove, .driver = { .name = "qcom-sdx55-acps-clk", }, diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index a5aea27eb867..cf4f0d340cbf 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -8,20 +8,38 @@ #include "clk-alpha-pll.h" -static const u8 ipq_pll_offsets[] = { - [PLL_OFF_L_VAL] = 0x08, - [PLL_OFF_ALPHA_VAL] = 0x10, - [PLL_OFF_USER_CTL] = 0x18, - [PLL_OFF_CONFIG_CTL] = 0x20, - [PLL_OFF_CONFIG_CTL_U] = 0x24, - [PLL_OFF_STATUS] = 0x28, - [PLL_OFF_TEST_CTL] = 0x30, - [PLL_OFF_TEST_CTL_U] = 0x34, +/* + * Even though APSS PLL type is of existing one (like Huayra), its offsets + * are different from the one mentioned in the clk-alpha-pll.c, since the + * PLL is specific to APSS, so lets the define the same. + */ +static const u8 ipq_pll_offsets[][PLL_OFF_MAX_REGS] = { + [CLK_ALPHA_PLL_TYPE_HUAYRA] = { + [PLL_OFF_L_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL] = 0x10, + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_CONFIG_CTL] = 0x20, + [PLL_OFF_CONFIG_CTL_U] = 0x24, + [PLL_OFF_STATUS] = 0x28, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + }, + [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { + [PLL_OFF_L_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL] = 0x10, + [PLL_OFF_ALPHA_VAL_U] = 0x14, + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_USER_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL] = 0x20, + [PLL_OFF_STATUS] = 0x28, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + }, }; -static struct clk_alpha_pll ipq_pll = { +static struct clk_alpha_pll ipq_pll_huayra = { .offset = 0x0, - .regs = ipq_pll_offsets, + .regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_HUAYRA], .flags = SUPPORTS_DYNAMIC_UPDATE, .clkr = { .enable_reg = 0x0, @@ -37,6 +55,38 @@ static struct clk_alpha_pll ipq_pll = { }, }; +static struct clk_alpha_pll ipq_pll_stromer_plus = { + .offset = 0x0, + .regs = ipq_pll_offsets[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "a53pll", + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_stromer_ops, + }, + }, +}; + +static const struct alpha_pll_config ipq5332_pll_config = { + .l = 0x3e, + .config_ctl_val = 0x4001075b, + .config_ctl_hi_val = 0x304, + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), + .early_output_mask = BIT(3), + .alpha_en_mask = BIT(24), + .status_val = 0x3, + .status_mask = GENMASK(10, 8), + .lock_det = BIT(2), + .test_ctl_hi_val = 0x00400003, +}; + static const struct alpha_pll_config ipq6018_pll_config = { .l = 0x37, .config_ctl_val = 0x240d4828, @@ -61,6 +111,30 @@ static const struct alpha_pll_config ipq8074_pll_config = { .test_ctl_hi_val = 0x4000, }; +struct apss_pll_data { + int pll_type; + struct clk_alpha_pll *pll; + const struct alpha_pll_config *pll_config; +}; + +static struct apss_pll_data ipq5332_pll_data = { + .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, + .pll = &ipq_pll_stromer_plus, + .pll_config = &ipq5332_pll_config, +}; + +static struct apss_pll_data ipq8074_pll_data = { + .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA, + .pll = &ipq_pll_huayra, + .pll_config = &ipq8074_pll_config, +}; + +static struct apss_pll_data ipq6018_pll_data = { + .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA, + .pll = &ipq_pll_huayra, + .pll_config = &ipq6018_pll_config, +}; + static const struct regmap_config ipq_pll_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -71,7 +145,7 @@ static const struct regmap_config ipq_pll_regmap_config = { static int apss_ipq_pll_probe(struct platform_device *pdev) { - const struct alpha_pll_config *ipq_pll_config; + const struct apss_pll_data *data; struct device *dev = &pdev->dev; struct regmap *regmap; void __iomem *base; @@ -85,23 +159,27 @@ static int apss_ipq_pll_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - ipq_pll_config = of_device_get_match_data(&pdev->dev); - if (!ipq_pll_config) + data = of_device_get_match_data(&pdev->dev); + if (!data) return -ENODEV; - clk_alpha_pll_configure(&ipq_pll, regmap, ipq_pll_config); + if (data->pll_type == CLK_ALPHA_PLL_TYPE_HUAYRA) + clk_alpha_pll_configure(data->pll, regmap, data->pll_config); + else if (data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER_PLUS) + clk_stromer_pll_configure(data->pll, regmap, data->pll_config); - ret = devm_clk_register_regmap(dev, &ipq_pll.clkr); + ret = devm_clk_register_regmap(dev, &data->pll->clkr); if (ret) return ret; return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, - &ipq_pll.clkr.hw); + &data->pll->clkr.hw); } static const struct of_device_id apss_ipq_pll_match_table[] = { - { .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_config }, - { .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_config }, + { .compatible = "qcom,ipq5332-a53pll", .data = &ipq5332_pll_data }, + { .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_data }, + { .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_data }, { } }; MODULE_DEVICE_TABLE(of, apss_ipq_pll_match_table); diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index e266379427f2..b9f6535a7ba7 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -204,6 +204,29 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_CONFIG_CTL] = 0x1C, [PLL_OFF_STATUS] = 0x20, }, + [CLK_ALPHA_PLL_TYPE_STROMER] = { + [PLL_OFF_L_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL] = 0x10, + [PLL_OFF_ALPHA_VAL_U] = 0x14, + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_USER_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL] = 0x20, + [PLL_OFF_CONFIG_CTL_U] = 0xff, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + [PLL_OFF_STATUS] = 0x28, + }, + [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_USER_CTL] = 0x08, + [PLL_OFF_USER_CTL_U] = 0x0c, + [PLL_OFF_CONFIG_CTL] = 0x10, + [PLL_OFF_TEST_CTL] = 0x14, + [PLL_OFF_TEST_CTL_U] = 0x18, + [PLL_OFF_STATUS] = 0x1c, + [PLL_OFF_ALPHA_VAL] = 0x24, + [PLL_OFF_ALPHA_VAL_U] = 0x28, + }, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); @@ -215,6 +238,8 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define ALPHA_BITWIDTH 32U #define ALPHA_SHIFT(w) min(w, ALPHA_BITWIDTH) +#define ALPHA_PLL_STATUS_REG_SHIFT 8 + #define PLL_HUAYRA_M_WIDTH 8 #define PLL_HUAYRA_M_SHIFT 8 #define PLL_HUAYRA_M_MASK 0xff @@ -2329,3 +2354,115 @@ const struct clk_ops clk_alpha_pll_rivian_evo_ops = { .round_rate = clk_rivian_evo_pll_round_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_rivian_evo_ops); + +void clk_stromer_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + u32 val, val_u, mask, mask_u; + + regmap_write(regmap, PLL_L_VAL(pll), config->l); + regmap_write(regmap, PLL_ALPHA_VAL(pll), config->alpha); + regmap_write(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + + if (pll_has_64bit_config(pll)) + regmap_write(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + + if (pll_alpha_width(pll) > 32) + regmap_write(regmap, PLL_ALPHA_VAL_U(pll), config->alpha_hi); + + val = config->main_output_mask; + val |= config->aux_output_mask; + val |= config->aux2_output_mask; + val |= config->early_output_mask; + val |= config->pre_div_val; + val |= config->post_div_val; + val |= config->vco_val; + val |= config->alpha_en_mask; + val |= config->alpha_mode_mask; + + mask = config->main_output_mask; + mask |= config->aux_output_mask; + mask |= config->aux2_output_mask; + mask |= config->early_output_mask; + mask |= config->pre_div_mask; + mask |= config->post_div_mask; + mask |= config->vco_mask; + mask |= config->alpha_en_mask; + mask |= config->alpha_mode_mask; + + regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val); + + /* Stromer APSS PLL does not enable LOCK_DET by default, so enable it */ + val_u = config->status_val << ALPHA_PLL_STATUS_REG_SHIFT; + val_u |= config->lock_det; + + mask_u = config->status_mask; + mask_u |= config->lock_det; + + regmap_update_bits(regmap, PLL_USER_CTL_U(pll), mask_u, val_u); + regmap_write(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); + regmap_write(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); + + if (pll->flags & SUPPORTS_FSM_MODE) + qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0); +} +EXPORT_SYMBOL_GPL(clk_stromer_pll_configure); + +static int clk_alpha_pll_stromer_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + u32 l; + u64 a; + + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, + &l, &a, ALPHA_REG_BITWIDTH); + + return 0; +} + +static int clk_alpha_pll_stromer_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + int ret; + u32 l; + u64 a; + + rate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_BITWIDTH); + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), + a >> ALPHA_BITWIDTH); + + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_ALPHA_EN, PLL_ALPHA_EN); + + if (!clk_hw_is_enabled(hw)) + return 0; + + /* + * Stromer PLL supports Dynamic programming. + * It allows the PLL frequency to be changed on-the-fly without first + * execution of a shutdown procedure followed by a bring up procedure. + */ + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE, + PLL_UPDATE); + + ret = wait_for_pll_update(pll); + if (ret) + return ret; + + return wait_for_pll_enable_lock(pll); +} + +const struct clk_ops clk_alpha_pll_stromer_ops = { + .enable = clk_alpha_pll_enable, + .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = clk_alpha_pll_recalc_rate, + .determine_rate = clk_alpha_pll_stromer_determine_rate, + .set_rate = clk_alpha_pll_stromer_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index c67cfda27ecb..d07b17186b90 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -1,5 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. */ +/* + * Copyright (c) 2015, 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + #ifndef __QCOM_CLK_ALPHA_PLL_H__ #define __QCOM_CLK_ALPHA_PLL_H__ @@ -22,6 +26,8 @@ enum { CLK_ALPHA_PLL_TYPE_RIVIAN_EVO, CLK_ALPHA_PLL_TYPE_DEFAULT_EVO, CLK_ALPHA_PLL_TYPE_BRAMMO_EVO, + CLK_ALPHA_PLL_TYPE_STROMER, + CLK_ALPHA_PLL_TYPE_STROMER_PLUS, CLK_ALPHA_PLL_TYPE_MAX, }; @@ -131,6 +137,9 @@ struct alpha_pll_config { u32 post_div_mask; u32 vco_val; u32 vco_mask; + u32 status_val; + u32 status_mask; + u32 lock_det; }; extern const struct clk_ops clk_alpha_pll_ops; @@ -139,6 +148,7 @@ extern const struct clk_ops clk_alpha_pll_hwfsm_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ops; extern const struct clk_ops clk_alpha_pll_huayra_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; +extern const struct clk_ops clk_alpha_pll_stromer_ops; extern const struct clk_ops clk_alpha_pll_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; @@ -188,5 +198,7 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma const struct alpha_pll_config *config); void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); +void clk_stromer_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); #endif diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index f869fc6aaed6..ca896ebf7e1b 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -39,27 +39,22 @@ static bool clk_branch_check_halt(const struct clk_branch *br, bool enabling) return !!val == !enabling; } -#define BRANCH_CLK_OFF BIT(31) -#define BRANCH_NOC_FSM_STATUS_SHIFT 28 -#define BRANCH_NOC_FSM_STATUS_MASK 0x7 -#define BRANCH_NOC_FSM_STATUS_ON (0x2 << BRANCH_NOC_FSM_STATUS_SHIFT) - static bool clk_branch2_check_halt(const struct clk_branch *br, bool enabling) { u32 val; u32 mask; - mask = BRANCH_NOC_FSM_STATUS_MASK << BRANCH_NOC_FSM_STATUS_SHIFT; - mask |= BRANCH_CLK_OFF; + mask = CBCR_NOC_FSM_STATUS; + mask |= CBCR_CLK_OFF; regmap_read(br->clkr.regmap, br->halt_reg, &val); if (enabling) { val &= mask; - return (val & BRANCH_CLK_OFF) == 0 || - val == BRANCH_NOC_FSM_STATUS_ON; + return (val & CBCR_CLK_OFF) == 0 || + FIELD_GET(CBCR_NOC_FSM_STATUS, val) == FSM_STATUS_ON; } else { - return val & BRANCH_CLK_OFF; + return val & CBCR_CLK_OFF; } } diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 17a58119165e..0cf800b9d08d 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -4,6 +4,7 @@ #ifndef __QCOM_CLK_BRANCH_H__ #define __QCOM_CLK_BRANCH_H__ +#include #include #include "clk-regmap.h" @@ -37,6 +38,49 @@ struct clk_branch { struct clk_regmap clkr; }; +/* Branch clock common bits for HLOS-owned clocks */ +#define CBCR_CLK_OFF BIT(31) +#define CBCR_NOC_FSM_STATUS GENMASK(30, 28) + #define FSM_STATUS_ON BIT(1) +#define CBCR_FORCE_MEM_CORE_ON BIT(14) +#define CBCR_FORCE_MEM_PERIPH_ON BIT(13) +#define CBCR_FORCE_MEM_PERIPH_OFF BIT(12) +#define CBCR_WAKEUP GENMASK(11, 8) +#define CBCR_SLEEP GENMASK(7, 4) + +static inline void qcom_branch_set_force_mem_core(struct regmap *regmap, + struct clk_branch clk, bool on) +{ + regmap_update_bits(regmap, clk.halt_reg, CBCR_FORCE_MEM_CORE_ON, + on ? CBCR_FORCE_MEM_CORE_ON : 0); +} + +static inline void qcom_branch_set_force_periph_on(struct regmap *regmap, + struct clk_branch clk, bool on) +{ + regmap_update_bits(regmap, clk.halt_reg, CBCR_FORCE_MEM_PERIPH_ON, + on ? CBCR_FORCE_MEM_PERIPH_ON : 0); +} + +static inline void qcom_branch_set_force_periph_off(struct regmap *regmap, + struct clk_branch clk, bool on) +{ + regmap_update_bits(regmap, clk.halt_reg, CBCR_FORCE_MEM_PERIPH_OFF, + on ? CBCR_FORCE_MEM_PERIPH_OFF : 0); +} + +static inline void qcom_branch_set_wakeup(struct regmap *regmap, struct clk_branch clk, u32 val) +{ + regmap_update_bits(regmap, clk.halt_reg, CBCR_WAKEUP, + FIELD_PREP(CBCR_WAKEUP, val)); +} + +static inline void qcom_branch_set_sleep(struct regmap *regmap, struct clk_branch clk, u32 val) +{ + regmap_update_bits(regmap, clk.halt_reg, CBCR_SLEEP, + FIELD_PREP(CBCR_SLEEP, val)); +} + extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch_simple_ops; diff --git a/drivers/clk/qcom/clk-hfpll.c b/drivers/clk/qcom/clk-hfpll.c index 7dd17c184b69..86f728dc69e5 100644 --- a/drivers/clk/qcom/clk-hfpll.c +++ b/drivers/clk/qcom/clk-hfpll.c @@ -128,20 +128,20 @@ static void clk_hfpll_disable(struct clk_hw *hw) spin_unlock_irqrestore(&h->lock, flags); } -static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_hfpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_hfpll *h = to_clk_hfpll(hw); struct hfpll_data const *hd = h->d; unsigned long rrate; - rate = clamp(rate, hd->min_rate, hd->max_rate); + req->rate = clamp(req->rate, hd->min_rate, hd->max_rate); - rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate; + rrate = DIV_ROUND_UP(req->rate, req->best_parent_rate) * req->best_parent_rate; if (rrate > hd->max_rate) - rrate -= *parent_rate; + rrate -= req->best_parent_rate; - return rrate; + req->rate = rrate; + return 0; } /* @@ -241,7 +241,7 @@ const struct clk_ops clk_ops_hfpll = { .enable = clk_hfpll_enable, .disable = clk_hfpll_disable, .is_enabled = hfpll_is_enabled, - .round_rate = clk_hfpll_round_rate, + .determine_rate = clk_hfpll_determine_rate, .set_rate = clk_hfpll_set_rate, .recalc_rate = clk_hfpll_recalc_rate, .init = clk_hfpll_init, diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c index 293a9dfa7151..f5ce403e1e27 100644 --- a/drivers/clk/qcom/clk-krait.c +++ b/drivers/clk/qcom/clk-krait.c @@ -97,11 +97,11 @@ const struct clk_ops krait_mux_clk_ops = { EXPORT_SYMBOL_GPL(krait_mux_clk_ops); /* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */ -static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int krait_div2_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); - return DIV_ROUND_UP(*parent_rate, 2); + req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), req->rate * 2); + req->rate = DIV_ROUND_UP(req->best_parent_rate, 2); + return 0; } static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, @@ -142,7 +142,7 @@ krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) } const struct clk_ops krait_div2_clk_ops = { - .round_rate = krait_div2_round_rate, + .determine_rate = krait_div2_determine_rate, .set_rate = krait_div2_set_rate, .recalc_rate = krait_div2_recalc_rate, }; diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index b1be5b664bf3..cac623e27b0e 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -580,8 +580,8 @@ static int rpm_clk_probe(struct platform_device *pdev) goto err; } - ret = of_clk_add_hw_provider(pdev->dev.of_node, qcom_rpm_clk_hw_get, - rcc); + ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_rpm_clk_hw_get, + rcc); if (ret) goto err; @@ -591,19 +591,12 @@ err: return ret; } -static int rpm_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; -} - static struct platform_driver rpm_clk_driver = { .driver = { .name = "qcom-clk-rpm", .of_match_table = rpm_clk_match_table, }, .probe = rpm_clk_probe, - .remove = rpm_clk_remove, }; static int __init rpm_clk_init(void) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 198886c1b6c8..887b945a6fb7 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -573,6 +573,40 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = { .num_clks = ARRAY_SIZE(msm8916_clks), }; +static struct clk_smd_rpm *msm8917_clks[] = { + [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo, + [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a, + [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk, + [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk, + [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk, + [RPM_SMD_BIMC_GPU_CLK] = &clk_smd_rpm_bimc_gpu_clk, + [RPM_SMD_BIMC_GPU_A_CLK] = &clk_smd_rpm_bimc_gpu_a_clk, + [RPM_SMD_SYSMMNOC_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_clk, + [RPM_SMD_SYSMMNOC_A_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_a_clk, + [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk, + [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1, + [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a, + [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2, + [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a, + [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2, + [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a, + [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2, + [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a, + [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin, + [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin, + [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin, + [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8917 = { + .clks = msm8917_clks, + .num_clks = ARRAY_SIZE(msm8917_clks), +}; + static struct clk_smd_rpm *msm8936_clks[] = { [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo, [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a, @@ -610,6 +644,8 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8936 = { }; static struct clk_smd_rpm *msm8974_clks[] = { + [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo, + [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a, [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk, [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk, [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk, @@ -1228,6 +1264,7 @@ static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8226", .data = &rpm_clk_msm8974 }, { .compatible = "qcom,rpmcc-msm8909", .data = &rpm_clk_msm8909 }, { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, + { .compatible = "qcom,rpmcc-msm8917", .data = &rpm_clk_msm8917 }, { .compatible = "qcom,rpmcc-msm8936", .data = &rpm_clk_msm8936 }, { .compatible = "qcom,rpmcc-msm8953", .data = &rpm_clk_msm8953 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, diff --git a/drivers/clk/qcom/dispcc-qcm2290.c b/drivers/clk/qcom/dispcc-qcm2290.c index 2ebd9a02b895..e9cfe41c0442 100644 --- a/drivers/clk/qcom/dispcc-qcm2290.c +++ b/drivers/clk/qcom/dispcc-qcm2290.c @@ -20,13 +20,13 @@ #include "clk-regmap-divider.h" #include "common.h" #include "gdsc.h" +#include "reset.h" enum { P_BI_TCXO, P_DISP_CC_PLL0_OUT_MAIN, P_DSI0_PHY_PLL_OUT_BYTECLK, P_DSI0_PHY_PLL_OUT_DSICLK, - P_DSI1_PHY_PLL_OUT_DSICLK, P_GPLL0_OUT_MAIN, P_SLEEP_CLK, }; @@ -106,13 +106,11 @@ static const struct clk_parent_data disp_cc_parent_data_3[] = { static const struct parent_map disp_cc_parent_map_4[] = { { P_BI_TCXO, 0 }, { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, - { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, }; static const struct clk_parent_data disp_cc_parent_data_4[] = { { .fw_name = "bi_tcxo" }, { .fw_name = "dsi0_phy_pll_out_dsiclk" }, - { .fw_name = "dsi1_phy_pll_out_dsiclk" }, }; static const struct parent_map disp_cc_parent_map_5[] = { @@ -445,6 +443,10 @@ static struct clk_branch disp_cc_sleep_clk = { }, }; +static const struct qcom_reset_map disp_cc_qcm2290_resets[] = { + [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, +}; + static struct gdsc mdss_gdsc = { .gdscr = 0x3000, .pd = { @@ -494,6 +496,8 @@ static const struct qcom_cc_desc disp_cc_qcm2290_desc = { .num_clks = ARRAY_SIZE(disp_cc_qcm2290_clocks), .gdscs = disp_cc_qcm2290_gdscs, .num_gdscs = ARRAY_SIZE(disp_cc_qcm2290_gdscs), + .resets = disp_cc_qcm2290_resets, + .num_resets = ARRAY_SIZE(disp_cc_qcm2290_resets), }; static const struct of_device_id disp_cc_qcm2290_match_table[] = { diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 5675c60525a7..5657e29464ad 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -77,1134 +77,12 @@ struct clk_fepll { const struct freq_tbl *freq_tbl; }; -static struct parent_map gcc_xo_200_500_map[] = { - { P_XO, 0 }, - { P_FEPLL200, 1 }, - { P_FEPLL500, 2 }, -}; - -static const char * const gcc_xo_200_500[] = { - "xo", - "fepll200", - "fepll500", -}; - -static struct parent_map gcc_xo_200_map[] = { - { P_XO, 0 }, - { P_FEPLL200, 1 }, -}; - -static const char * const gcc_xo_200[] = { - "xo", - "fepll200", -}; - -static struct parent_map gcc_xo_200_spi_map[] = { - { P_XO, 0 }, - { P_FEPLL200, 2 }, -}; - -static const char * const gcc_xo_200_spi[] = { - "xo", - "fepll200", -}; - -static struct parent_map gcc_xo_sdcc1_500_map[] = { - { P_XO, 0 }, - { P_DDRPLL, 1 }, - { P_FEPLL500, 2 }, -}; - -static const char * const gcc_xo_sdcc1_500[] = { - "xo", - "ddrpllsdcc", - "fepll500", -}; - -static struct parent_map gcc_xo_wcss2g_map[] = { - { P_XO, 0 }, - { P_FEPLLWCSS2G, 1 }, -}; - -static const char * const gcc_xo_wcss2g[] = { - "xo", - "fepllwcss2g", -}; - -static struct parent_map gcc_xo_wcss5g_map[] = { - { P_XO, 0 }, - { P_FEPLLWCSS5G, 1 }, -}; - -static const char * const gcc_xo_wcss5g[] = { - "xo", - "fepllwcss5g", -}; - -static struct parent_map gcc_xo_125_dly_map[] = { - { P_XO, 0 }, - { P_FEPLL125DLY, 1 }, -}; - -static const char * const gcc_xo_125_dly[] = { - "xo", - "fepll125dly", -}; - -static struct parent_map gcc_xo_ddr_500_200_map[] = { - { P_XO, 0 }, - { P_FEPLL200, 3 }, - { P_FEPLL500, 2 }, - { P_DDRPLLAPSS, 1 }, -}; - /* * Contains index for safe clock during APSS freq change. * fepll500 is being used as safe clock so initialize it * with its index in parents list gcc_xo_ddr_500_200. */ static const int gcc_ipq4019_cpu_safe_parent = 2; -static const char * const gcc_xo_ddr_500_200[] = { - "xo", - "fepll200", - "fepll500", - "ddrpllapss", -}; - -static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = { - F(48000000, P_XO, 1, 0, 0), - F(200000000, P_FEPLL200, 1, 0, 0), - { } -}; - -static struct clk_rcg2 audio_clk_src = { - .cmd_rcgr = 0x1b000, - .hid_width = 5, - .parent_map = gcc_xo_200_map, - .freq_tbl = ftbl_gcc_audio_pwm_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "audio_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - - }, -}; - -static struct clk_branch gcc_audio_ahb_clk = { - .halt_reg = 0x1b010, - .clkr = { - .enable_reg = 0x1b010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_audio_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .flags = CLK_SET_RATE_PARENT, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_audio_pwm_clk = { - .halt_reg = 0x1b00C, - .clkr = { - .enable_reg = 0x1b00C, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_audio_pwm_clk", - .parent_names = (const char *[]){ - "audio_clk_src", - }, - .flags = CLK_SET_RATE_PARENT, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_i2c_apps_clk[] = { - F(19050000, P_FEPLL200, 10.5, 1, 1), - { } -}; - -static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { - .cmd_rcgr = 0x200c, - .hid_width = 5, - .parent_map = gcc_xo_200_map, - .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_qup1_i2c_apps_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { - .halt_reg = 0x2008, - .clkr = { - .enable_reg = 0x2008, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_qup1_i2c_apps_clk", - .parent_names = (const char *[]){ - "blsp1_qup1_i2c_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { - .cmd_rcgr = 0x3000, - .hid_width = 5, - .parent_map = gcc_xo_200_map, - .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_qup2_i2c_apps_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { - .halt_reg = 0x3010, - .clkr = { - .enable_reg = 0x3010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_qup2_i2c_apps_clk", - .parent_names = (const char *[]){ - "blsp1_qup2_i2c_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_spi_apps_clk[] = { - F(960000, P_XO, 12, 1, 4), - F(4800000, P_XO, 1, 1, 10), - F(9600000, P_XO, 1, 1, 5), - F(15000000, P_XO, 1, 1, 3), - F(19200000, P_XO, 1, 2, 5), - F(24000000, P_XO, 1, 1, 2), - F(48000000, P_XO, 1, 0, 0), - { } -}; - -static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { - .cmd_rcgr = 0x2024, - .mnd_width = 8, - .hid_width = 5, - .parent_map = gcc_xo_200_spi_map, - .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_qup1_spi_apps_clk_src", - .parent_names = gcc_xo_200_spi, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { - .halt_reg = 0x2004, - .clkr = { - .enable_reg = 0x2004, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_qup1_spi_apps_clk", - .parent_names = (const char *[]){ - "blsp1_qup1_spi_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { - .cmd_rcgr = 0x3014, - .mnd_width = 8, - .hid_width = 5, - .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, - .parent_map = gcc_xo_200_spi_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_qup2_spi_apps_clk_src", - .parent_names = gcc_xo_200_spi, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { - .halt_reg = 0x300c, - .clkr = { - .enable_reg = 0x300c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_qup2_spi_apps_clk", - .parent_names = (const char *[]){ - "blsp1_qup2_spi_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = { - F(1843200, P_FEPLL200, 1, 144, 15625), - F(3686400, P_FEPLL200, 1, 288, 15625), - F(7372800, P_FEPLL200, 1, 576, 15625), - F(14745600, P_FEPLL200, 1, 1152, 15625), - F(16000000, P_FEPLL200, 1, 2, 25), - F(24000000, P_XO, 1, 1, 2), - F(32000000, P_FEPLL200, 1, 4, 25), - F(40000000, P_FEPLL200, 1, 1, 5), - F(46400000, P_FEPLL200, 1, 29, 125), - F(48000000, P_XO, 1, 0, 0), - { } -}; - -static struct clk_rcg2 blsp1_uart1_apps_clk_src = { - .cmd_rcgr = 0x2044, - .mnd_width = 16, - .hid_width = 5, - .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, - .parent_map = gcc_xo_200_spi_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_uart1_apps_clk_src", - .parent_names = gcc_xo_200_spi, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_uart1_apps_clk = { - .halt_reg = 0x203c, - .clkr = { - .enable_reg = 0x203c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_uart1_apps_clk", - .parent_names = (const char *[]){ - "blsp1_uart1_apps_clk_src", - }, - .flags = CLK_SET_RATE_PARENT, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_rcg2 blsp1_uart2_apps_clk_src = { - .cmd_rcgr = 0x3034, - .mnd_width = 16, - .hid_width = 5, - .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, - .parent_map = gcc_xo_200_spi_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "blsp1_uart2_apps_clk_src", - .parent_names = gcc_xo_200_spi, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_blsp1_uart2_apps_clk = { - .halt_reg = 0x302c, - .clkr = { - .enable_reg = 0x302c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_uart2_apps_clk", - .parent_names = (const char *[]){ - "blsp1_uart2_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_gp_clk[] = { - F(1250000, P_FEPLL200, 1, 16, 0), - F(2500000, P_FEPLL200, 1, 8, 0), - F(5000000, P_FEPLL200, 1, 4, 0), - { } -}; - -static struct clk_rcg2 gp1_clk_src = { - .cmd_rcgr = 0x8004, - .mnd_width = 8, - .hid_width = 5, - .freq_tbl = ftbl_gcc_gp_clk, - .parent_map = gcc_xo_200_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gp1_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_gp1_clk = { - .halt_reg = 0x8000, - .clkr = { - .enable_reg = 0x8000, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_gp1_clk", - .parent_names = (const char *[]){ - "gp1_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_rcg2 gp2_clk_src = { - .cmd_rcgr = 0x9004, - .mnd_width = 8, - .hid_width = 5, - .freq_tbl = ftbl_gcc_gp_clk, - .parent_map = gcc_xo_200_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gp2_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_gp2_clk = { - .halt_reg = 0x9000, - .clkr = { - .enable_reg = 0x9000, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_gp2_clk", - .parent_names = (const char *[]){ - "gp2_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_rcg2 gp3_clk_src = { - .cmd_rcgr = 0xa004, - .mnd_width = 8, - .hid_width = 5, - .freq_tbl = ftbl_gcc_gp_clk, - .parent_map = gcc_xo_200_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gp3_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_gp3_clk = { - .halt_reg = 0xa000, - .clkr = { - .enable_reg = 0xa000, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_gp3_clk", - .parent_names = (const char *[]){ - "gp3_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { - F(144000, P_XO, 1, 3, 240), - F(400000, P_XO, 1, 1, 0), - F(20000000, P_FEPLL500, 1, 1, 25), - F(25000000, P_FEPLL500, 1, 1, 20), - F(50000000, P_FEPLL500, 1, 1, 10), - F(100000000, P_FEPLL500, 1, 1, 5), - F(192000000, P_DDRPLL, 1, 0, 0), - { } -}; - -static struct clk_rcg2 sdcc1_apps_clk_src = { - .cmd_rcgr = 0x18004, - .hid_width = 5, - .freq_tbl = ftbl_gcc_sdcc1_apps_clk, - .parent_map = gcc_xo_sdcc1_500_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "sdcc1_apps_clk_src", - .parent_names = gcc_xo_sdcc1_500, - .num_parents = 3, - .ops = &clk_rcg2_ops, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static const struct freq_tbl ftbl_gcc_apps_clk[] = { - F(48000000, P_XO, 1, 0, 0), - F(200000000, P_FEPLL200, 1, 0, 0), - F(384000000, P_DDRPLLAPSS, 1, 0, 0), - F(413000000, P_DDRPLLAPSS, 1, 0, 0), - F(448000000, P_DDRPLLAPSS, 1, 0, 0), - F(488000000, P_DDRPLLAPSS, 1, 0, 0), - F(500000000, P_FEPLL500, 1, 0, 0), - F(512000000, P_DDRPLLAPSS, 1, 0, 0), - F(537000000, P_DDRPLLAPSS, 1, 0, 0), - F(565000000, P_DDRPLLAPSS, 1, 0, 0), - F(597000000, P_DDRPLLAPSS, 1, 0, 0), - F(632000000, P_DDRPLLAPSS, 1, 0, 0), - F(672000000, P_DDRPLLAPSS, 1, 0, 0), - F(716000000, P_DDRPLLAPSS, 1, 0, 0), - { } -}; - -static struct clk_rcg2 apps_clk_src = { - .cmd_rcgr = 0x1900c, - .hid_width = 5, - .freq_tbl = ftbl_gcc_apps_clk, - .parent_map = gcc_xo_ddr_500_200_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "apps_clk_src", - .parent_names = gcc_xo_ddr_500_200, - .num_parents = 4, - .ops = &clk_rcg2_ops, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static const struct freq_tbl ftbl_gcc_apps_ahb_clk[] = { - F(48000000, P_XO, 1, 0, 0), - F(100000000, P_FEPLL200, 2, 0, 0), - { } -}; - -static struct clk_rcg2 apps_ahb_clk_src = { - .cmd_rcgr = 0x19014, - .hid_width = 5, - .parent_map = gcc_xo_200_500_map, - .freq_tbl = ftbl_gcc_apps_ahb_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "apps_ahb_clk_src", - .parent_names = gcc_xo_200_500, - .num_parents = 3, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_apss_ahb_clk = { - .halt_reg = 0x19004, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(14), - .hw.init = &(struct clk_init_data){ - .name = "gcc_apss_ahb_clk", - .parent_names = (const char *[]){ - "apps_ahb_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_blsp1_ahb_clk = { - .halt_reg = 0x1008, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(10), - .hw.init = &(struct clk_init_data){ - .name = "gcc_blsp1_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_dcd_xo_clk = { - .halt_reg = 0x2103c, - .clkr = { - .enable_reg = 0x2103c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_dcd_xo_clk", - .parent_names = (const char *[]){ - "xo", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_boot_rom_ahb_clk = { - .halt_reg = 0x1300c, - .clkr = { - .enable_reg = 0x1300c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_boot_rom_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_crypto_ahb_clk = { - .halt_reg = 0x16024, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_crypto_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_crypto_axi_clk = { - .halt_reg = 0x16020, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gcc_crypto_axi_clk", - .parent_names = (const char *[]){ - "fepll125", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_crypto_clk = { - .halt_reg = 0x1601c, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(2), - .hw.init = &(struct clk_init_data){ - .name = "gcc_crypto_clk", - .parent_names = (const char *[]){ - "fepll125", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_ess_clk = { - .halt_reg = 0x12010, - .clkr = { - .enable_reg = 0x12010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_ess_clk", - .parent_names = (const char *[]){ - "fephy_125m_dly_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_imem_axi_clk = { - .halt_reg = 0xe004, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(17), - .hw.init = &(struct clk_init_data){ - .name = "gcc_imem_axi_clk", - .parent_names = (const char *[]){ - "fepll200", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_imem_cfg_ahb_clk = { - .halt_reg = 0xe008, - .clkr = { - .enable_reg = 0xe008, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_imem_cfg_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_pcie_ahb_clk = { - .halt_reg = 0x1d00c, - .clkr = { - .enable_reg = 0x1d00c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_pcie_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_pcie_axi_m_clk = { - .halt_reg = 0x1d004, - .clkr = { - .enable_reg = 0x1d004, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_pcie_axi_m_clk", - .parent_names = (const char *[]){ - "fepll200", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_pcie_axi_s_clk = { - .halt_reg = 0x1d008, - .clkr = { - .enable_reg = 0x1d008, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_pcie_axi_s_clk", - .parent_names = (const char *[]){ - "fepll200", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_prng_ahb_clk = { - .halt_reg = 0x13004, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(8), - .hw.init = &(struct clk_init_data){ - .name = "gcc_prng_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_qpic_ahb_clk = { - .halt_reg = 0x1c008, - .clkr = { - .enable_reg = 0x1c008, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_qpic_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_qpic_clk = { - .halt_reg = 0x1c004, - .clkr = { - .enable_reg = 0x1c004, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_qpic_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_sdcc1_ahb_clk = { - .halt_reg = 0x18010, - .clkr = { - .enable_reg = 0x18010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_sdcc1_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_sdcc1_apps_clk = { - .halt_reg = 0x1800c, - .clkr = { - .enable_reg = 0x1800c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_sdcc1_apps_clk", - .parent_names = (const char *[]){ - "sdcc1_apps_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_tlmm_ahb_clk = { - .halt_reg = 0x5004, - .halt_check = BRANCH_HALT_VOTED, - .clkr = { - .enable_reg = 0x6000, - .enable_mask = BIT(5), - .hw.init = &(struct clk_init_data){ - .name = "gcc_tlmm_ahb_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_usb2_master_clk = { - .halt_reg = 0x1e00c, - .clkr = { - .enable_reg = 0x1e00c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb2_master_clk", - .parent_names = (const char *[]){ - "pcnoc_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_usb2_sleep_clk = { - .halt_reg = 0x1e010, - .clkr = { - .enable_reg = 0x1e010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb2_sleep_clk", - .parent_names = (const char *[]){ - "gcc_sleep_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_usb2_mock_utmi_clk = { - .halt_reg = 0x1e014, - .clkr = { - .enable_reg = 0x1e014, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb2_mock_utmi_clk", - .parent_names = (const char *[]){ - "usb30_mock_utmi_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = { - F(2000000, P_FEPLL200, 10, 0, 0), - { } -}; - -static struct clk_rcg2 usb30_mock_utmi_clk_src = { - .cmd_rcgr = 0x1e000, - .hid_width = 5, - .parent_map = gcc_xo_200_map, - .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "usb30_mock_utmi_clk_src", - .parent_names = gcc_xo_200, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_usb3_master_clk = { - .halt_reg = 0x1e028, - .clkr = { - .enable_reg = 0x1e028, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb3_master_clk", - .parent_names = (const char *[]){ - "fepll125", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_usb3_sleep_clk = { - .halt_reg = 0x1e02C, - .clkr = { - .enable_reg = 0x1e02C, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb3_sleep_clk", - .parent_names = (const char *[]){ - "gcc_sleep_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_usb3_mock_utmi_clk = { - .halt_reg = 0x1e030, - .clkr = { - .enable_reg = 0x1e030, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_usb3_mock_utmi_clk", - .parent_names = (const char *[]){ - "usb30_mock_utmi_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_fephy_dly_clk[] = { - F(125000000, P_FEPLL125DLY, 1, 0, 0), - { } -}; - -static struct clk_rcg2 fephy_125m_dly_clk_src = { - .cmd_rcgr = 0x12000, - .hid_width = 5, - .parent_map = gcc_xo_125_dly_map, - .freq_tbl = ftbl_gcc_fephy_dly_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "fephy_125m_dly_clk_src", - .parent_names = gcc_xo_125_dly, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - - -static const struct freq_tbl ftbl_gcc_wcss2g_clk[] = { - F(48000000, P_XO, 1, 0, 0), - F(250000000, P_FEPLLWCSS2G, 1, 0, 0), - { } -}; - -static struct clk_rcg2 wcss2g_clk_src = { - .cmd_rcgr = 0x1f000, - .hid_width = 5, - .freq_tbl = ftbl_gcc_wcss2g_clk, - .parent_map = gcc_xo_wcss2g_map, - .clkr.hw.init = &(struct clk_init_data){ - .name = "wcss2g_clk_src", - .parent_names = gcc_xo_wcss2g, - .num_parents = 2, - .ops = &clk_rcg2_ops, - .flags = CLK_SET_RATE_PARENT, - }, -}; - -static struct clk_branch gcc_wcss2g_clk = { - .halt_reg = 0x1f00C, - .clkr = { - .enable_reg = 0x1f00C, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss2g_clk", - .parent_names = (const char *[]){ - "wcss2g_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_wcss2g_ref_clk = { - .halt_reg = 0x1f00C, - .clkr = { - .enable_reg = 0x1f00C, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss2g_ref_clk", - .parent_names = (const char *[]){ - "xo", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_wcss2g_rtc_clk = { - .halt_reg = 0x1f010, - .clkr = { - .enable_reg = 0x1f010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss2g_rtc_clk", - .parent_names = (const char *[]){ - "gcc_sleep_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - -static const struct freq_tbl ftbl_gcc_wcss5g_clk[] = { - F(48000000, P_XO, 1, 0, 0), - F(250000000, P_FEPLLWCSS5G, 1, 0, 0), - { } -}; - -static struct clk_rcg2 wcss5g_clk_src = { - .cmd_rcgr = 0x20000, - .hid_width = 5, - .parent_map = gcc_xo_wcss5g_map, - .freq_tbl = ftbl_gcc_wcss5g_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "wcss5g_clk_src", - .parent_names = gcc_xo_wcss5g, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, -}; - -static struct clk_branch gcc_wcss5g_clk = { - .halt_reg = 0x2000c, - .clkr = { - .enable_reg = 0x2000c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss5g_clk", - .parent_names = (const char *[]){ - "wcss5g_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_wcss5g_ref_clk = { - .halt_reg = 0x2000c, - .clkr = { - .enable_reg = 0x2000c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss5g_ref_clk", - .parent_names = (const char *[]){ - "xo", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; - -static struct clk_branch gcc_wcss5g_rtc_clk = { - .halt_reg = 0x20010, - .clkr = { - .enable_reg = 0x20010, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_wcss5g_rtc_clk", - .parent_names = (const char *[]){ - "gcc_sleep_clk_src", - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - .flags = CLK_SET_RATE_PARENT, - }, - }, -}; /* Calculates the VCO rate for FEPLL. */ static u64 clk_fepll_vco_calc_rate(struct clk_fepll *pll_div, @@ -1360,8 +238,9 @@ static struct clk_fepll gcc_apss_cpu_plldiv_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "ddrpllapss", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_regmap_cpu_div_ops, @@ -1412,8 +291,9 @@ static struct clk_fepll gcc_apss_sdcc_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "ddrpllsdcc", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1427,8 +307,9 @@ static struct clk_fepll gcc_fepll125_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepll125", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1442,8 +323,9 @@ static struct clk_fepll gcc_fepll125dly_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepll125dly", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1457,8 +339,9 @@ static struct clk_fepll gcc_fepll200_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepll200", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1472,8 +355,9 @@ static struct clk_fepll gcc_fepll500_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepll500", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1497,8 +381,9 @@ static struct clk_fepll gcc_fepllwcss2g_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepllwcss2g", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1515,8 +400,9 @@ static struct clk_fepll gcc_fepllwcss5g_clk = { .cdiv.clkr = { .hw.init = &(struct clk_init_data){ .name = "fepllwcss5g", - .parent_names = (const char *[]){ - "xo", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", }, .num_parents = 1, .ops = &clk_fepll_div_ops, @@ -1526,6 +412,18 @@ static struct clk_fepll gcc_fepllwcss5g_clk = { .pll_vco = &gcc_fepll_vco, }; +static struct parent_map gcc_xo_200_500_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 1 }, + { P_FEPLL500, 2 }, +}; + +static const struct clk_parent_data gcc_xo_200_500[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepll200_clk.cdiv.clkr.hw }, + { .hw = &gcc_fepll500_clk.cdiv.clkr.hw }, +}; + static const struct freq_tbl ftbl_gcc_pcnoc_ahb_clk[] = { F(48000000, P_XO, 1, 0, 0), F(100000000, P_FEPLL200, 2, 0, 0), @@ -1539,8 +437,8 @@ static struct clk_rcg2 gcc_pcnoc_ahb_clk_src = { .freq_tbl = ftbl_gcc_pcnoc_ahb_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_pcnoc_ahb_clk_src", - .parent_names = gcc_xo_200_500, - .num_parents = 3, + .parent_data = gcc_xo_200_500, + .num_parents = ARRAY_SIZE(gcc_xo_200_500), .ops = &clk_rcg2_ops, }, }; @@ -1552,9 +450,8 @@ static struct clk_branch pcnoc_clk_src = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "pcnoc_clk_src", - .parent_names = (const char *[]){ - "gcc_pcnoc_ahb_clk_src", - }, + .parent_hws = (const struct clk_hw *[]){ + &gcc_pcnoc_ahb_clk_src.clkr.hw }, .num_parents = 1, .ops = &clk_branch2_ops, .flags = CLK_SET_RATE_PARENT | @@ -1563,6 +460,1088 @@ static struct clk_branch pcnoc_clk_src = { }, }; +static struct parent_map gcc_xo_200_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 1 }, +}; + +static const struct clk_parent_data gcc_xo_200[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepll200_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(200000000, P_FEPLL200, 1, 0, 0), + { } +}; + +static struct clk_rcg2 audio_clk_src = { + .cmd_rcgr = 0x1b000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_audio_pwm_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "audio_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + + }, +}; + +static struct clk_branch gcc_audio_ahb_clk = { + .halt_reg = 0x1b010, + .clkr = { + .enable_reg = 0x1b010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_audio_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_audio_pwm_clk = { + .halt_reg = 0x1b00C, + .clkr = { + .enable_reg = 0x1b00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_audio_pwm_clk", + .parent_hws = (const struct clk_hw *[]){ + &audio_clk_src.clkr.hw }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_i2c_apps_clk[] = { + F(19050000, P_FEPLL200, 10.5, 1, 1), + { } +}; + +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x200c, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x2008, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_qup1_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x3000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_i2c_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x3010, + .clkr = { + .enable_reg = 0x3010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_qup2_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct parent_map gcc_xo_200_spi_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 2 }, +}; + +static const struct clk_parent_data gcc_xo_200_spi[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepll200_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_spi_apps_clk[] = { + F(960000, P_XO, 12, 1, 4), + F(4800000, P_XO, 1, 1, 10), + F(9600000, P_XO, 1, 1, 5), + F(15000000, P_XO, 1, 1, 3), + F(19200000, P_XO, 1, 2, 5), + F(24000000, P_XO, 1, 1, 2), + F(48000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x2024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_200_spi_map, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_data = gcc_xo_200_spi, + .num_parents = ARRAY_SIZE(gcc_xo_200_spi), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x2004, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_qup1_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x3014, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_qup1_2_spi_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_data = gcc_xo_200_spi, + .num_parents = ARRAY_SIZE(gcc_xo_200_spi), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x300c, + .clkr = { + .enable_reg = 0x300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_qup2_spi_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_2_apps_clk[] = { + F(1843200, P_FEPLL200, 1, 144, 15625), + F(3686400, P_FEPLL200, 1, 288, 15625), + F(7372800, P_FEPLL200, 1, 576, 15625), + F(14745600, P_FEPLL200, 1, 1152, 15625), + F(16000000, P_FEPLL200, 1, 2, 25), + F(24000000, P_XO, 1, 1, 2), + F(32000000, P_FEPLL200, 1, 4, 25), + F(40000000, P_FEPLL200, 1, 1, 5), + F(46400000, P_FEPLL200, 1, 29, 125), + F(48000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x2044, + .mnd_width = 16, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart1_apps_clk_src", + .parent_data = gcc_xo_200_spi, + .num_parents = ARRAY_SIZE(gcc_xo_200_spi), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x203c, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_uart1_apps_clk_src.clkr.hw }, + .flags = CLK_SET_RATE_PARENT, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x3034, + .mnd_width = 16, + .hid_width = 5, + .freq_tbl = ftbl_gcc_blsp1_uart1_2_apps_clk, + .parent_map = gcc_xo_200_spi_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart2_apps_clk_src", + .parent_data = gcc_xo_200_spi, + .num_parents = ARRAY_SIZE(gcc_xo_200_spi), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x302c, + .clkr = { + .enable_reg = 0x302c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_uart2_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp_clk[] = { + F(1250000, P_FEPLL200, 1, 16, 0), + F(2500000, P_FEPLL200, 1, 8, 0), + F(5000000, P_FEPLL200, 1, 4, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x8004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp1_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x8000, + .clkr = { + .enable_reg = 0x8000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw *[]){ + &gp1_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x9004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp2_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x9000, + .clkr = { + .enable_reg = 0x9000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw *[]){ + &gp2_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0xa004, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_gcc_gp_clk, + .parent_map = gcc_xo_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp3_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0xa000, + .clkr = { + .enable_reg = 0xa000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw *[]){ + &gp3_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct parent_map gcc_xo_sdcc1_500_map[] = { + { P_XO, 0 }, + { P_DDRPLL, 1 }, + { P_FEPLL500, 2 }, +}; + +static const struct clk_parent_data gcc_xo_sdcc1_500[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_apss_sdcc_clk.cdiv.clkr.hw }, + { .hw = &gcc_fepll500_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk[] = { + F(144000, P_XO, 1, 3, 240), + F(400000, P_XO, 1, 1, 0), + F(20000000, P_FEPLL500, 1, 1, 25), + F(25000000, P_FEPLL500, 1, 1, 20), + F(50000000, P_FEPLL500, 1, 1, 10), + F(100000000, P_FEPLL500, 1, 1, 5), + F(192000000, P_DDRPLL, 1, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x18004, + .hid_width = 5, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk, + .parent_map = gcc_xo_sdcc1_500_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_apps_clk_src", + .parent_data = gcc_xo_sdcc1_500, + .num_parents = ARRAY_SIZE(gcc_xo_sdcc1_500), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_gcc_apps_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(200000000, P_FEPLL200, 1, 0, 0), + F(384000000, P_DDRPLLAPSS, 1, 0, 0), + F(413000000, P_DDRPLLAPSS, 1, 0, 0), + F(448000000, P_DDRPLLAPSS, 1, 0, 0), + F(488000000, P_DDRPLLAPSS, 1, 0, 0), + F(500000000, P_FEPLL500, 1, 0, 0), + F(512000000, P_DDRPLLAPSS, 1, 0, 0), + F(537000000, P_DDRPLLAPSS, 1, 0, 0), + F(565000000, P_DDRPLLAPSS, 1, 0, 0), + F(597000000, P_DDRPLLAPSS, 1, 0, 0), + F(632000000, P_DDRPLLAPSS, 1, 0, 0), + F(672000000, P_DDRPLLAPSS, 1, 0, 0), + F(716000000, P_DDRPLLAPSS, 1, 0, 0), + { } +}; + +static struct parent_map gcc_xo_ddr_500_200_map[] = { + { P_XO, 0 }, + { P_FEPLL200, 3 }, + { P_FEPLL500, 2 }, + { P_DDRPLLAPSS, 1 }, +}; + +static const struct clk_parent_data gcc_xo_ddr_500_200[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepll200_clk.cdiv.clkr.hw }, + { .hw = &gcc_fepll500_clk.cdiv.clkr.hw }, + { .hw = &gcc_apss_cpu_plldiv_clk.cdiv.clkr.hw }, +}; + +static struct clk_rcg2 apps_clk_src = { + .cmd_rcgr = 0x1900c, + .hid_width = 5, + .freq_tbl = ftbl_gcc_apps_clk, + .parent_map = gcc_xo_ddr_500_200_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apps_clk_src", + .parent_data = gcc_xo_ddr_500_200, + .num_parents = ARRAY_SIZE(gcc_xo_ddr_500_200), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct freq_tbl ftbl_gcc_apps_ahb_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(100000000, P_FEPLL200, 2, 0, 0), + { } +}; + +static struct clk_rcg2 apps_ahb_clk_src = { + .cmd_rcgr = 0x19014, + .hid_width = 5, + .parent_map = gcc_xo_200_500_map, + .freq_tbl = ftbl_gcc_apps_ahb_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apps_ahb_clk_src", + .parent_data = gcc_xo_200_500, + .num_parents = ARRAY_SIZE(gcc_xo_200_500), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_apss_ahb_clk = { + .halt_reg = 0x19004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apss_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &apps_ahb_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x1008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_dcd_xo_clk = { + .halt_reg = 0x2103c, + .clkr = { + .enable_reg = 0x2103c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_dcd_xo_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1300c, + .clkr = { + .enable_reg = 0x1300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_crypto_ahb_clk = { + .halt_reg = 0x16024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_axi_clk = { + .halt_reg = 0x16020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_axi_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll125_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_crypto_clk = { + .halt_reg = 0x1601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_crypto_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll125_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct parent_map gcc_xo_125_dly_map[] = { + { P_XO, 0 }, + { P_FEPLL125DLY, 1 }, +}; + +static const struct clk_parent_data gcc_xo_125_dly[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepll125dly_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_fephy_dly_clk[] = { + F(125000000, P_FEPLL125DLY, 1, 0, 0), + { } +}; + +static struct clk_rcg2 fephy_125m_dly_clk_src = { + .cmd_rcgr = 0x12000, + .hid_width = 5, + .parent_map = gcc_xo_125_dly_map, + .freq_tbl = ftbl_gcc_fephy_dly_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "fephy_125m_dly_clk_src", + .parent_data = gcc_xo_125_dly, + .num_parents = ARRAY_SIZE(gcc_xo_125_dly), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ess_clk = { + .halt_reg = 0x12010, + .clkr = { + .enable_reg = 0x12010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ess_clk", + .parent_hws = (const struct clk_hw *[]){ + &fephy_125m_dly_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_imem_axi_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "gcc_imem_axi_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll200_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_imem_cfg_ahb_clk = { + .halt_reg = 0xe008, + .clkr = { + .enable_reg = 0xe008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_imem_cfg_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_ahb_clk = { + .halt_reg = 0x1d00c, + .clkr = { + .enable_reg = 0x1d00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_axi_m_clk = { + .halt_reg = 0x1d004, + .clkr = { + .enable_reg = 0x1d004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_axi_m_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll200_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_axi_s_clk = { + .halt_reg = 0x1d008, + .clkr = { + .enable_reg = 0x1d008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_axi_s_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll200_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_ahb_clk = { + .halt_reg = 0x1c008, + .clkr = { + .enable_reg = 0x1c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qpic_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_clk = { + .halt_reg = 0x1c004, + .clkr = { + .enable_reg = 0x1c004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qpic_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x18010, + .clkr = { + .enable_reg = 0x18010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x1800c, + .clkr = { + .enable_reg = 0x1800c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &sdcc1_apps_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_tlmm_ahb_clk = { + .halt_reg = 0x5004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tlmm_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2_master_clk = { + .halt_reg = 0x1e00c, + .clkr = { + .enable_reg = 0x1e00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_master_clk", + .parent_hws = (const struct clk_hw *[]){ + &pcnoc_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2_sleep_clk = { + .halt_reg = 0x1e010, + .clkr = { + .enable_reg = 0x1e010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_sleep_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "sleep_clk", + .name = "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = { + F(2000000, P_FEPLL200, 10, 0, 0), + { } +}; + +static struct clk_rcg2 usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0x1e000, + .hid_width = 5, + .parent_map = gcc_xo_200_map, + .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb30_mock_utmi_clk_src", + .parent_data = gcc_xo_200, + .num_parents = ARRAY_SIZE(gcc_xo_200), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_usb2_mock_utmi_clk = { + .halt_reg = 0x1e014, + .clkr = { + .enable_reg = 0x1e014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2_mock_utmi_clk", + .parent_hws = (const struct clk_hw *[]){ + &usb30_mock_utmi_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_usb3_master_clk = { + .halt_reg = 0x1e028, + .clkr = { + .enable_reg = 0x1e028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_master_clk", + .parent_hws = (const struct clk_hw *[]){ + &gcc_fepll125_clk.cdiv.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_sleep_clk = { + .halt_reg = 0x1e02C, + .clkr = { + .enable_reg = 0x1e02C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sleep_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "sleep_clk", + .name = "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mock_utmi_clk = { + .halt_reg = 0x1e030, + .clkr = { + .enable_reg = 0x1e030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_mock_utmi_clk", + .parent_hws = (const struct clk_hw *[]){ + &usb30_mock_utmi_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct parent_map gcc_xo_wcss2g_map[] = { + { P_XO, 0 }, + { P_FEPLLWCSS2G, 1 }, +}; + +static const struct clk_parent_data gcc_xo_wcss2g[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepllwcss2g_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_wcss2g_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(250000000, P_FEPLLWCSS2G, 1, 0, 0), + { } +}; + +static struct clk_rcg2 wcss2g_clk_src = { + .cmd_rcgr = 0x1f000, + .hid_width = 5, + .freq_tbl = ftbl_gcc_wcss2g_clk, + .parent_map = gcc_xo_wcss2g_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "wcss2g_clk_src", + .parent_data = gcc_xo_wcss2g, + .num_parents = ARRAY_SIZE(gcc_xo_wcss2g), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_branch gcc_wcss2g_clk = { + .halt_reg = 0x1f00C, + .clkr = { + .enable_reg = 0x1f00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_clk", + .parent_hws = (const struct clk_hw *[]){ + &wcss2g_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss2g_ref_clk = { + .halt_reg = 0x1f00C, + .clkr = { + .enable_reg = 0x1f00C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_ref_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss2g_rtc_clk = { + .halt_reg = 0x1f010, + .clkr = { + .enable_reg = 0x1f010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss2g_rtc_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "sleep_clk", + .name = "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct parent_map gcc_xo_wcss5g_map[] = { + { P_XO, 0 }, + { P_FEPLLWCSS5G, 1 }, +}; + +static const struct clk_parent_data gcc_xo_wcss5g[] = { + { .fw_name = "xo", .name = "xo" }, + { .hw = &gcc_fepllwcss5g_clk.cdiv.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_wcss5g_clk[] = { + F(48000000, P_XO, 1, 0, 0), + F(250000000, P_FEPLLWCSS5G, 1, 0, 0), + { } +}; + +static struct clk_rcg2 wcss5g_clk_src = { + .cmd_rcgr = 0x20000, + .hid_width = 5, + .parent_map = gcc_xo_wcss5g_map, + .freq_tbl = ftbl_gcc_wcss5g_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "wcss5g_clk_src", + .parent_data = gcc_xo_wcss5g, + .num_parents = ARRAY_SIZE(gcc_xo_wcss5g), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_wcss5g_clk = { + .halt_reg = 0x2000c, + .clkr = { + .enable_reg = 0x2000c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_clk", + .parent_hws = (const struct clk_hw *[]){ + &wcss5g_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss5g_ref_clk = { + .halt_reg = 0x2000c, + .clkr = { + .enable_reg = 0x2000c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_ref_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "xo", + .name = "xo", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch gcc_wcss5g_rtc_clk = { + .halt_reg = 0x20010, + .clkr = { + .enable_reg = 0x20010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_wcss5g_rtc_clk", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "sleep_clk", + .name = "gcc_sleep_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_regmap *gcc_ipq4019_clocks[] = { [AUDIO_CLK_SRC] = &audio_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c new file mode 100644 index 000000000000..bdb4a0a11d07 --- /dev/null +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -0,0 +1,3824 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "reset.h" + +enum { + DT_SLEEP_CLK, + DT_XO, + DT_PCIE_2LANE_PHY_PIPE_CLK, + DT_PCIE_2LANE_PHY_PIPE_CLK_X1, + DT_USB_PCIE_WRAPPER_PIPE_CLK, +}; + +enum { + P_PCIE3X2_PIPE, + P_PCIE3X1_0_PIPE, + P_PCIE3X1_1_PIPE, + P_USB3PHY_0_PIPE, + P_CORE_BI_PLL_TEST_SE, + P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, + P_GPLL0_OUT_AUX, + P_GPLL0_OUT_MAIN, + P_GPLL2_OUT_AUX, + P_GPLL2_OUT_MAIN, + P_GPLL4_OUT_AUX, + P_GPLL4_OUT_MAIN, + P_SLEEP_CLK, + P_XO, +}; + +static const struct clk_parent_data gcc_parent_data_xo = { .index = DT_XO }; + +static struct clk_alpha_pll gpll0_main = { + .offset = 0x20000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpll0_main", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_alpha_pll_stromer_ops, + }, + }, +}; + +static struct clk_fixed_factor gpll0_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "gpll0_div2", + .parent_hws = (const struct clk_hw *[]) { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll_postdiv gpll0 = { + .offset = 0x20000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll0", + .parent_hws = (const struct clk_hw *[]) { + &gpll0_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll gpll2_main = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gpll2", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_alpha_pll_stromer_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll2 = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll2_main", + .parent_hws = (const struct clk_hw *[]) { + &gpll2_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll gpll4_main = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gpll4_main", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_alpha_pll_stromer_ops, + /* + * There are no consumers for this GPLL in kernel yet, + * (will be added soon), so the clock framework + * disables this source. But some of the clocks + * initialized by boot loaders uses this source. So we + * need to keep this clock ON. Add the + * CLK_IGNORE_UNUSED flag so the clock will not be + * disabled. Once the consumer in kernel is added, we + * can get rid of this flag. + */ + .flags = CLK_IGNORE_UNUSED, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER_PLUS], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll4", + .parent_hws = (const struct clk_hw *[]) { + &gpll4_main.clkr.hw }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct parent_map gcc_parent_map_xo[] = { + { P_XO, 0 }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_MAIN, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_XO, 0 }, + { P_GPLL4_OUT_MAIN, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL2_OUT_AUX, 2 }, + { P_GPLL4_OUT_AUX, 3 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, + { P_GPLL0_OUT_AUX, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0_div2.hw }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL2_OUT_AUX, 2 }, + { P_GPLL4_OUT_AUX, 3 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL2_OUT_AUX, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL2_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, +}; + +static const struct clk_parent_data gcc_parent_data_9[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 3 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_13[] = { + { P_XO, 0 }, + { P_GPLL4_OUT_AUX, 1 }, + { P_GPLL0_OUT_MAIN, 3 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, +}; + +static const struct clk_parent_data gcc_parent_data_13[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct freq_tbl ftbl_gcc_adss_pwm_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_adss_pwm_clk_src = { + .cmd_rcgr = 0x1c004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_adss_pwm_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_adss_pwm_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_apss_axi_clk_src[] = { + F(480000000, P_GPLL4_OUT_MAIN, 2.5, 0, 0), + F(533333333, P_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_apss_axi_clk_src = { + .cmd_rcgr = 0x24004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_apss_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_apss_axi_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk_src[] = { + F(960000, P_XO, 1, 1, 25), + F(4800000, P_XO, 5, 0, 0), + F(9600000, P_XO, 2.5, 0, 0), + F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5), + F(24000000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x2004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup1_spi_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x3004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup2_spi_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x4004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup3_spi_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_apps_clk_src[] = { + F(3686400, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 144, 15625), + F(7372800, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 288, 15625), + F(14745600, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 576, 15625), + F(24000000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 1, 1, 25), + F(40000000, P_GPLL0_OUT_MAIN, 1, 1, 20), + F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 500), + F(48000000, P_GPLL0_OUT_MAIN, 1, 3, 50), + F(51200000, P_GPLL0_OUT_MAIN, 1, 8, 125), + F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 100), + F(58982400, P_GPLL0_OUT_MAIN, 1, 1152, 15625), + F(60000000, P_GPLL0_OUT_MAIN, 1, 3, 40), + F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x202c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart1_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x302c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart2_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x402c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart3_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x8004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x9004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_lpass_sway_clk_src[] = { + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_lpass_sway_clk_src = { + .cmd_rcgr = 0x27004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_lpass_sway_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_lpass_sway_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_nss_ts_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_nss_ts_clk_src = { + .cmd_rcgr = 0x17088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_xo, + .freq_tbl = ftbl_gcc_nss_ts_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_nss_ts_clk_src", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie3x1_0_axi_clk_src[] = { + F(240000000, P_GPLL4_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie3x1_0_axi_clk_src = { + .cmd_rcgr = 0x29018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie3x1_0_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_axi_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie3x1_0_rchg_clk_src = { + .cmd_rcgr = 0x2907c, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_adss_pwm_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_rchg_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_rchg_clk = { + .halt_reg = 0x2907c, + .clkr = { + .enable_reg = 0x2907c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x1_0_rchg_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie3x1_0_rchg_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 gcc_pcie3x1_1_axi_clk_src = { + .cmd_rcgr = 0x2a004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie3x1_0_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_axi_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie3x1_1_rchg_clk_src = { + .cmd_rcgr = 0x2a078, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_adss_pwm_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_rchg_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_rchg_clk = { + .halt_reg = 0x2a078, + .clkr = { + .enable_reg = 0x2a078, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x1_1_rchg_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie3x1_1_rchg_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie3x2_axi_m_clk_src[] = { + F(266666667, P_GPLL4_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie3x2_axi_m_clk_src = { + .cmd_rcgr = 0x28018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie3x2_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_axi_m_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie3x2_axi_s_clk_src = { + .cmd_rcgr = 0x28084, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie3x1_0_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_axi_s_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie3x2_rchg_clk_src = { + .cmd_rcgr = 0x28078, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_adss_pwm_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_rchg_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3x2_rchg_clk = { + .halt_reg = 0x28078, + .clkr = { + .enable_reg = 0x28078, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x2_rchg_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie3x2_rchg_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_aux_clk_src[] = { + F(2000000, P_XO, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_aux_clk_src = { + .cmd_rcgr = 0x28004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_pcie_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_aux_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie3x2_pipe_clk_src = { + .reg = 0x28064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x2_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_2LANE_PHY_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie3x1_0_pipe_clk_src = { + .reg = 0x29064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x1_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_USB_PCIE_WRAPPER_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie3x1_1_pipe_clk_src = { + .reg = 0x2a064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3x1_1_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_2LANE_PHY_PIPE_CLK_X1, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcnoc_bfdcd_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcnoc_bfdcd_clk_src = { + .cmd_rcgr = 0x31004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcnoc_bfdcd_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcnoc_bfdcd_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_q6_axim_clk_src = { + .cmd_rcgr = 0x25004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_apss_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_axim_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qdss_at_clk_src[] = { + F(240000000, P_GPLL4_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qdss_at_clk_src = { + .cmd_rcgr = 0x2d004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_qdss_at_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_at_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qdss_tsctr_clk_src[] = { + F(600000000, P_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qdss_tsctr_clk_src = { + .cmd_rcgr = 0x2d01c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_qdss_tsctr_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_tsctr_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div2_clk_src = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div2_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div3_clk_src = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div3_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div4_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div4_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div8_clk_src = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div8_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div16_clk_src = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div16_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qpic_io_macro_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qpic_io_macro_clk_src = { + .cmd_rcgr = 0x32004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_qpic_io_macro_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_io_macro_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(143713, P_XO, 1, 1, 167), + F(400000, P_XO, 1, 1, 60), + F(24000000, P_XO, 1, 0, 0), + F(48000000, P_GPLL2_OUT_MAIN, 12, 1, 2), + F(96000000, P_GPLL2_OUT_MAIN, 12, 0, 0), + F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(192000000, P_GPLL2_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x33004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sleep_clk_src = { + .cmd_rcgr = 0x3400c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_system_noc_bfdcd_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(266666667, P_GPLL4_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_system_noc_bfdcd_clk_src = { + .cmd_rcgr = 0x2e004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_system_noc_bfdcd_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_system_noc_bfdcd_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor gcc_system_noc_bfdcd_div2_clk_src = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "gcc_system_noc_bfdcd_div2_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_rcg2 gcc_uniphy_sys_clk_src = { + .cmd_rcgr = 0x16004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_xo, + .freq_tbl = ftbl_gcc_nss_ts_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy_sys_clk_src", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb0_aux_clk_src = { + .cmd_rcgr = 0x2c018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_12, + .freq_tbl = ftbl_gcc_pcie_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_aux_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb0_lfps_clk_src[] = { + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + { } +}; + +static struct clk_rcg2 gcc_usb0_lfps_clk_src = { + .cmd_rcgr = 0x2c07c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_usb0_lfps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_lfps_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb0_master_clk_src = { + .cmd_rcgr = 0x2c004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb0_mock_utmi_clk_src[] = { + F(60000000, P_GPLL4_OUT_AUX, 10, 1, 2), + { } +}; + +static struct clk_rcg2 gcc_usb0_mock_utmi_clk_src = { + .cmd_rcgr = 0x2c02c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_13, + .freq_tbl = ftbl_gcc_usb0_mock_utmi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_mock_utmi_clk_src", + .parent_data = gcc_parent_data_13, + .num_parents = ARRAY_SIZE(gcc_parent_data_13), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_usb0_pipe_clk_src = { + .reg = 0x2c074, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_USB_PCIE_WRAPPER_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_rcg2 gcc_wcss_ahb_clk_src = { + .cmd_rcgr = 0x25030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_lpass_sway_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_ahb_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_xo_clk_src = { + .cmd_rcgr = 0x34004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_xo, + .freq_tbl = ftbl_gcc_nss_ts_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_xo_clk_src", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor gcc_xo_div4_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data) { + .name = "gcc_xo_div4_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_clk_src.clkr.hw }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap_div gcc_qdss_dap_div_clk_src = { + .reg = 0x2d028, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_dap_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_tsctr_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb0_mock_utmi_div_clk_src = { + .reg = 0x2c040, + .shift = 0, + .width = 2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_mock_utmi_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_adss_pwm_clk = { + .halt_reg = 0x1c00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1c00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_adss_pwm_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_adss_pwm_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ahb_clk = { + .halt_reg = 0x34024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x34024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x1008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x2020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x3024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x3020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x4024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x4020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_sleep_clk = { + .halt_reg = 0x1010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_sleep_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x2040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart1_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_uart1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x3040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_uart2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x4054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_blsp1_uart3_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_blsp1_uart3_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce_ahb_clk = { + .halt_reg = 0x25074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ce_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_div2_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce_axi_clk = { + .halt_reg = 0x25068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ce_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce_pcnoc_ahb_clk = { + .halt_reg = 0x25070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ce_pcnoc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_ahb_clk = { + .halt_reg = 0x3a004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3a004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cmn_12gpll_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_apu_clk = { + .halt_reg = 0x3a00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3a00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cmn_12gpll_apu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_sys_clk = { + .halt_reg = 0x3a008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3a008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cmn_12gpll_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_uniphy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x8018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x9018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_core_axim_clk = { + .halt_reg = 0x27018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x27018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_lpass_core_axim_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_lpass_sway_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x27014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x27014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_lpass_sway_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_lpass_sway_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdio_ahb_clk = { + .halt_reg = 0x12004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mdio_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdio_slave_ahb_clk = { + .halt_reg = 0x1200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mdio_slave_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_q6_axi_clk = { + .halt_reg = 0x19010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x19010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mem_noc_q6_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_q6_axim_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_ts_clk = { + .halt_reg = 0x19028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x19028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mem_noc_ts_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_tsctr_div8_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_ts_clk = { + .halt_reg = 0x17018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x17018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nss_ts_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_nss_ts_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nsscc_clk = { + .halt_reg = 0x17034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nsscc_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nsscfg_clk = { + .halt_reg = 0x1702c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1702c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nsscfg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_atb_clk = { + .halt_reg = 0x17014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_atb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_nsscc_clk = { + .halt_reg = 0x17030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_nsscc_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_qosgen_ref_clk = { + .halt_reg = 0x1701c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1701c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_qosgen_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_div4_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_snoc_1_clk = { + .halt_reg = 0x1707c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1707c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_snoc_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_snoc_clk = { + .halt_reg = 0x17028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_snoc_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_timeout_ref_clk = { + .halt_reg = 0x17020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_timeout_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_div4_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_xo_dcd_clk = { + .halt_reg = 0x17074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_xo_dcd_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_ahb_clk = { + .halt_reg = 0x29030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_aux_clk = { + .halt_reg = 0x29070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_axi_m_clk = { + .halt_reg = 0x29038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_axi_s_bridge_clk = { + .halt_reg = 0x29048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_axi_s_clk = { + .halt_reg = 0x29040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_0_pipe_clk = { + .halt_reg = 0x29068, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x29068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_ahb_clk = { + .halt_reg = 0x2a00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_aux_clk = { + .halt_reg = 0x2a070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_axi_m_clk = { + .halt_reg = 0x2a014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_axi_s_bridge_clk = { + .halt_reg = 0x2a024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_axi_s_clk = { + .halt_reg = 0x2a01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_1_pipe_clk = { + .halt_reg = 0x2a068, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2a068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_1_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x1_phy_ahb_clk = { + .halt_reg = 0x29078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x1_phy_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_ahb_clk = { + .halt_reg = 0x28030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_aux_clk = { + .halt_reg = 0x28070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_axi_m_clk = { + .halt_reg = 0x28038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_axi_m_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_axi_s_bridge_clk = { + .halt_reg = 0x28048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_axi_s_clk = { + .halt_reg = 0x28040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_phy_ahb_clk = { + .halt_reg = 0x28080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_phy_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3x2_pipe_clk = { + .halt_reg = 0x28068, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x28068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3x2_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcnoc_at_clk = { + .halt_reg = 0x31024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x31024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcnoc_at_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcnoc_lpass_clk = { + .halt_reg = 0x31020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcnoc_lpass_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_lpass_sway_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_prng_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_ahb_clk = { + .halt_reg = 0x25014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x25014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_wcss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_ahb_s_clk = { + .halt_reg = 0x25018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x25018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_ahb_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_wcss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_axim_clk = { + .halt_reg = 0x2500c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2500c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_axim_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_q6_axim_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_axis_clk = { + .halt_reg = 0x25010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x25010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_axis_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_tsctr_1to2_clk = { + .halt_reg = 0x25020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x25020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6_tsctr_1to2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_tsctr_div2_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6ss_atbm_clk = { + .halt_reg = 0x2501c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2501c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6ss_atbm_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6ss_pclkdbg_clk = { + .halt_reg = 0x25024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x25024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6ss_pclkdbg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6ss_trig_clk = { + .halt_reg = 0x250a0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x250a0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_q6ss_trig_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_at_clk = { + .halt_reg = 0x2d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2d038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_at_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_cfg_ahb_clk = { + .halt_reg = 0x2d06c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2d06c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_cfg_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_dap_ahb_clk = { + .halt_reg = 0x2d068, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2d068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_dap_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_dap_clk = { + .halt_reg = 0x2d05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_dap_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_etr_usb_clk = { + .halt_reg = 0x2d064, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2d064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_etr_usb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor gcc_eud_at_div_clk_src = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data) { + .name = "gcc_eud_at_div_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_at_clk_src.clkr.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_qdss_eud_at_clk = { + .halt_reg = 0x2d070, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2d070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_eud_at_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_eud_at_div_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_io_macro_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_io_macro_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qpic_io_macro_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_sleep_clk = { + .halt_reg = 0x3201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3201c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_sleep_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x33034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x3302c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3302c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_lpass_cfg_clk = { + .halt_reg = 0x2e028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_lpass_cfg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_lpass_sway_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_nssnoc_1_clk = { + .halt_reg = 0x17090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_nssnoc_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_nssnoc_clk = { + .halt_reg = 0x17084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_nssnoc_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_1lane_1_m_clk = { + .halt_reg = 0x2e050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_1lane_1_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_1lane_1_s_clk = { + .halt_reg = 0x2e0ac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e0ac, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_1lane_1_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_1_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_1lane_m_clk = { + .halt_reg = 0x2e080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_1lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_1lane_s_clk = { + .halt_reg = 0x2e04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e04c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_1lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x1_0_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_2lane_m_clk = { + .halt_reg = 0x2e07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_2lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_axi_m_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_2lane_s_clk = { + .halt_reg = 0x2e048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_pcie3_2lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3x2_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_usb_clk = { + .halt_reg = 0x2e058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2e058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_usb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_at_clk = { + .halt_reg = 0x2e038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2e038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sys_noc_at_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_wcss_ahb_clk = { + .halt_reg = 0x2e030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sys_noc_wcss_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_wcss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_ahb_clk = { + .halt_reg = 0x16010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy0_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_sys_clk = { + .halt_reg = 0x1600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy0_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_uniphy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_ahb_clk = { + .halt_reg = 0x1601c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1601c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy1_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_sys_clk = { + .halt_reg = 0x16018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy1_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_uniphy_sys_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_aux_clk = { + .halt_reg = 0x2c050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_eud_at_clk = { + .halt_reg = 0x30004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x30004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_eud_at_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_eud_at_div_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_lfps_clk = { + .halt_reg = 0x2c090, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_lfps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_lfps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_master_clk = { + .halt_reg = 0x2c048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_mock_utmi_clk = { + .halt_reg = 0x2c054, + .clkr = { + .enable_reg = 0x2c054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_mock_utmi_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_phy_cfg_ahb_clk = { + .halt_reg = 0x2c05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_phy_cfg_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_pipe_clk = { + .halt_reg = 0x2c078, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2c078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_sleep_clk = { + .halt_reg = 0x2c058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_sleep_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_axim_clk = { + .halt_reg = 0x2505c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2505c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_axim_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_axis_clk = { + .halt_reg = 0x25060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_axis_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_apb_bdg_clk = { + .halt_reg = 0x25048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_apb_bdg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_apb_clk = { + .halt_reg = 0x25038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_apb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_atb_bdg_clk = { + .halt_reg = 0x2504c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2504c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_atb_bdg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_atb_clk = { + .halt_reg = 0x2503c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2503c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_atb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_at_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_nts_bdg_clk = { + .halt_reg = 0x25050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_nts_bdg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_tsctr_div2_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_nts_clk = { + .halt_reg = 0x25040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_nts_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_tsctr_div2_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_ecahb_clk = { + .halt_reg = 0x25058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x25058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_ecahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_wcss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_mst_async_bdg_clk = { + .halt_reg = 0x2e0b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e0b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_mst_async_bdg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_slv_async_bdg_clk = { + .halt_reg = 0x2e0b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e0b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_wcss_slv_async_bdg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_system_noc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_clk = { + .halt_reg = 0x34018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x34018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_div4_clk = { + .halt_reg = 0x3401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3401c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_xo_div4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_div4_clk_src.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_im_sleep_clk = { + .halt_reg = 0x34020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x34020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_im_sleep_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_pcnoc_1_clk = { + .halt_reg = 0x17080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_nssnoc_pcnoc_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_ahb_clk = { + .halt_reg = 0x1900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1900c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mem_noc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcnoc_bfdcd_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_apss_axi_clk = { + .halt_reg = 0x1901c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mem_noc_apss_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_apss_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_snoc_qosgen_extref_div_clk_src = { + .reg = 0x2e010, + .shift = 0, + .width = 2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_qosgen_extref_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_mem_noc_qosgen_extref_clk = { + .halt_reg = 0x19024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x19024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_mem_noc_qosgen_extref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_snoc_qosgen_extref_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gcc_ipq5332_clocks[] = { + [GPLL0_MAIN] = &gpll0_main.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL2_MAIN] = &gpll2_main.clkr, + [GPLL2] = &gpll2.clkr, + [GPLL4_MAIN] = &gpll4_main.clkr, + [GPLL4] = &gpll4.clkr, + [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr, + [GCC_ADSS_PWM_CLK_SRC] = &gcc_adss_pwm_clk_src.clkr, + [GCC_AHB_CLK] = &gcc_ahb_clk.clkr, + [GCC_APSS_AXI_CLK_SRC] = &gcc_apss_axi_clk_src.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] = &gcc_blsp1_qup1_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] = &gcc_blsp1_qup2_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] = &gcc_blsp1_qup3_spi_apps_clk_src.clkr, + [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK_SRC] = &gcc_blsp1_uart1_apps_clk_src.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK_SRC] = &gcc_blsp1_uart2_apps_clk_src.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK_SRC] = &gcc_blsp1_uart3_apps_clk_src.clkr, + [GCC_CE_AHB_CLK] = &gcc_ce_ahb_clk.clkr, + [GCC_CE_AXI_CLK] = &gcc_ce_axi_clk.clkr, + [GCC_CE_PCNOC_AHB_CLK] = &gcc_ce_pcnoc_ahb_clk.clkr, + [GCC_CMN_12GPLL_AHB_CLK] = &gcc_cmn_12gpll_ahb_clk.clkr, + [GCC_CMN_12GPLL_APU_CLK] = &gcc_cmn_12gpll_apu_clk.clkr, + [GCC_CMN_12GPLL_SYS_CLK] = &gcc_cmn_12gpll_sys_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_LPASS_CORE_AXIM_CLK] = &gcc_lpass_core_axim_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, + [GCC_LPASS_SWAY_CLK_SRC] = &gcc_lpass_sway_clk_src.clkr, + [GCC_MDIO_AHB_CLK] = &gcc_mdio_ahb_clk.clkr, + [GCC_MDIO_SLAVE_AHB_CLK] = &gcc_mdio_slave_ahb_clk.clkr, + [GCC_MEM_NOC_Q6_AXI_CLK] = &gcc_mem_noc_q6_axi_clk.clkr, + [GCC_MEM_NOC_TS_CLK] = &gcc_mem_noc_ts_clk.clkr, + [GCC_NSS_TS_CLK] = &gcc_nss_ts_clk.clkr, + [GCC_NSS_TS_CLK_SRC] = &gcc_nss_ts_clk_src.clkr, + [GCC_NSSCC_CLK] = &gcc_nsscc_clk.clkr, + [GCC_NSSCFG_CLK] = &gcc_nsscfg_clk.clkr, + [GCC_NSSNOC_ATB_CLK] = &gcc_nssnoc_atb_clk.clkr, + [GCC_NSSNOC_NSSCC_CLK] = &gcc_nssnoc_nsscc_clk.clkr, + [GCC_NSSNOC_QOSGEN_REF_CLK] = &gcc_nssnoc_qosgen_ref_clk.clkr, + [GCC_NSSNOC_SNOC_1_CLK] = &gcc_nssnoc_snoc_1_clk.clkr, + [GCC_NSSNOC_SNOC_CLK] = &gcc_nssnoc_snoc_clk.clkr, + [GCC_NSSNOC_TIMEOUT_REF_CLK] = &gcc_nssnoc_timeout_ref_clk.clkr, + [GCC_NSSNOC_XO_DCD_CLK] = &gcc_nssnoc_xo_dcd_clk.clkr, + [GCC_PCIE3X1_0_AHB_CLK] = &gcc_pcie3x1_0_ahb_clk.clkr, + [GCC_PCIE3X1_0_AUX_CLK] = &gcc_pcie3x1_0_aux_clk.clkr, + [GCC_PCIE3X1_0_AXI_CLK_SRC] = &gcc_pcie3x1_0_axi_clk_src.clkr, + [GCC_PCIE3X1_0_AXI_M_CLK] = &gcc_pcie3x1_0_axi_m_clk.clkr, + [GCC_PCIE3X1_0_AXI_S_BRIDGE_CLK] = &gcc_pcie3x1_0_axi_s_bridge_clk.clkr, + [GCC_PCIE3X1_0_AXI_S_CLK] = &gcc_pcie3x1_0_axi_s_clk.clkr, + [GCC_PCIE3X1_0_PIPE_CLK] = &gcc_pcie3x1_0_pipe_clk.clkr, + [GCC_PCIE3X1_0_RCHG_CLK] = &gcc_pcie3x1_0_rchg_clk.clkr, + [GCC_PCIE3X1_0_RCHG_CLK_SRC] = &gcc_pcie3x1_0_rchg_clk_src.clkr, + [GCC_PCIE3X1_1_AHB_CLK] = &gcc_pcie3x1_1_ahb_clk.clkr, + [GCC_PCIE3X1_1_AUX_CLK] = &gcc_pcie3x1_1_aux_clk.clkr, + [GCC_PCIE3X1_1_AXI_CLK_SRC] = &gcc_pcie3x1_1_axi_clk_src.clkr, + [GCC_PCIE3X1_1_AXI_M_CLK] = &gcc_pcie3x1_1_axi_m_clk.clkr, + [GCC_PCIE3X1_1_AXI_S_BRIDGE_CLK] = &gcc_pcie3x1_1_axi_s_bridge_clk.clkr, + [GCC_PCIE3X1_1_AXI_S_CLK] = &gcc_pcie3x1_1_axi_s_clk.clkr, + [GCC_PCIE3X1_1_PIPE_CLK] = &gcc_pcie3x1_1_pipe_clk.clkr, + [GCC_PCIE3X1_1_RCHG_CLK] = &gcc_pcie3x1_1_rchg_clk.clkr, + [GCC_PCIE3X1_1_RCHG_CLK_SRC] = &gcc_pcie3x1_1_rchg_clk_src.clkr, + [GCC_PCIE3X1_PHY_AHB_CLK] = &gcc_pcie3x1_phy_ahb_clk.clkr, + [GCC_PCIE3X2_AHB_CLK] = &gcc_pcie3x2_ahb_clk.clkr, + [GCC_PCIE3X2_AUX_CLK] = &gcc_pcie3x2_aux_clk.clkr, + [GCC_PCIE3X2_AXI_M_CLK] = &gcc_pcie3x2_axi_m_clk.clkr, + [GCC_PCIE3X2_AXI_M_CLK_SRC] = &gcc_pcie3x2_axi_m_clk_src.clkr, + [GCC_PCIE3X2_AXI_S_BRIDGE_CLK] = &gcc_pcie3x2_axi_s_bridge_clk.clkr, + [GCC_PCIE3X2_AXI_S_CLK] = &gcc_pcie3x2_axi_s_clk.clkr, + [GCC_PCIE3X2_AXI_S_CLK_SRC] = &gcc_pcie3x2_axi_s_clk_src.clkr, + [GCC_PCIE3X2_PHY_AHB_CLK] = &gcc_pcie3x2_phy_ahb_clk.clkr, + [GCC_PCIE3X2_PIPE_CLK] = &gcc_pcie3x2_pipe_clk.clkr, + [GCC_PCIE3X2_RCHG_CLK] = &gcc_pcie3x2_rchg_clk.clkr, + [GCC_PCIE3X2_RCHG_CLK_SRC] = &gcc_pcie3x2_rchg_clk_src.clkr, + [GCC_PCIE_AUX_CLK_SRC] = &gcc_pcie_aux_clk_src.clkr, + [GCC_PCNOC_AT_CLK] = &gcc_pcnoc_at_clk.clkr, + [GCC_PCNOC_BFDCD_CLK_SRC] = &gcc_pcnoc_bfdcd_clk_src.clkr, + [GCC_PCNOC_LPASS_CLK] = &gcc_pcnoc_lpass_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_Q6_AHB_CLK] = &gcc_q6_ahb_clk.clkr, + [GCC_Q6_AHB_S_CLK] = &gcc_q6_ahb_s_clk.clkr, + [GCC_Q6_AXIM_CLK] = &gcc_q6_axim_clk.clkr, + [GCC_Q6_AXIM_CLK_SRC] = &gcc_q6_axim_clk_src.clkr, + [GCC_Q6_AXIS_CLK] = &gcc_q6_axis_clk.clkr, + [GCC_Q6_TSCTR_1TO2_CLK] = &gcc_q6_tsctr_1to2_clk.clkr, + [GCC_Q6SS_ATBM_CLK] = &gcc_q6ss_atbm_clk.clkr, + [GCC_Q6SS_PCLKDBG_CLK] = &gcc_q6ss_pclkdbg_clk.clkr, + [GCC_Q6SS_TRIG_CLK] = &gcc_q6ss_trig_clk.clkr, + [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr, + [GCC_QDSS_AT_CLK_SRC] = &gcc_qdss_at_clk_src.clkr, + [GCC_QDSS_CFG_AHB_CLK] = &gcc_qdss_cfg_ahb_clk.clkr, + [GCC_QDSS_DAP_AHB_CLK] = &gcc_qdss_dap_ahb_clk.clkr, + [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, + [GCC_QDSS_DAP_DIV_CLK_SRC] = &gcc_qdss_dap_div_clk_src.clkr, + [GCC_QDSS_ETR_USB_CLK] = &gcc_qdss_etr_usb_clk.clkr, + [GCC_QDSS_EUD_AT_CLK] = &gcc_qdss_eud_at_clk.clkr, + [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, + [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr, + [GCC_QPIC_IO_MACRO_CLK] = &gcc_qpic_io_macro_clk.clkr, + [GCC_QPIC_IO_MACRO_CLK_SRC] = &gcc_qpic_io_macro_clk_src.clkr, + [GCC_QPIC_SLEEP_CLK] = &gcc_qpic_sleep_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr, + [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr, + [GCC_SNOC_LPASS_CFG_CLK] = &gcc_snoc_lpass_cfg_clk.clkr, + [GCC_SNOC_NSSNOC_1_CLK] = &gcc_snoc_nssnoc_1_clk.clkr, + [GCC_SNOC_NSSNOC_CLK] = &gcc_snoc_nssnoc_clk.clkr, + [GCC_SNOC_PCIE3_1LANE_1_M_CLK] = &gcc_snoc_pcie3_1lane_1_m_clk.clkr, + [GCC_SNOC_PCIE3_1LANE_1_S_CLK] = &gcc_snoc_pcie3_1lane_1_s_clk.clkr, + [GCC_SNOC_PCIE3_1LANE_M_CLK] = &gcc_snoc_pcie3_1lane_m_clk.clkr, + [GCC_SNOC_PCIE3_1LANE_S_CLK] = &gcc_snoc_pcie3_1lane_s_clk.clkr, + [GCC_SNOC_PCIE3_2LANE_M_CLK] = &gcc_snoc_pcie3_2lane_m_clk.clkr, + [GCC_SNOC_PCIE3_2LANE_S_CLK] = &gcc_snoc_pcie3_2lane_s_clk.clkr, + [GCC_SNOC_USB_CLK] = &gcc_snoc_usb_clk.clkr, + [GCC_SYS_NOC_AT_CLK] = &gcc_sys_noc_at_clk.clkr, + [GCC_SYS_NOC_WCSS_AHB_CLK] = &gcc_sys_noc_wcss_ahb_clk.clkr, + [GCC_SYSTEM_NOC_BFDCD_CLK_SRC] = &gcc_system_noc_bfdcd_clk_src.clkr, + [GCC_UNIPHY0_AHB_CLK] = &gcc_uniphy0_ahb_clk.clkr, + [GCC_UNIPHY0_SYS_CLK] = &gcc_uniphy0_sys_clk.clkr, + [GCC_UNIPHY1_AHB_CLK] = &gcc_uniphy1_ahb_clk.clkr, + [GCC_UNIPHY1_SYS_CLK] = &gcc_uniphy1_sys_clk.clkr, + [GCC_UNIPHY_SYS_CLK_SRC] = &gcc_uniphy_sys_clk_src.clkr, + [GCC_USB0_AUX_CLK] = &gcc_usb0_aux_clk.clkr, + [GCC_USB0_AUX_CLK_SRC] = &gcc_usb0_aux_clk_src.clkr, + [GCC_USB0_EUD_AT_CLK] = &gcc_usb0_eud_at_clk.clkr, + [GCC_USB0_LFPS_CLK] = &gcc_usb0_lfps_clk.clkr, + [GCC_USB0_LFPS_CLK_SRC] = &gcc_usb0_lfps_clk_src.clkr, + [GCC_USB0_MASTER_CLK] = &gcc_usb0_master_clk.clkr, + [GCC_USB0_MASTER_CLK_SRC] = &gcc_usb0_master_clk_src.clkr, + [GCC_USB0_MOCK_UTMI_CLK] = &gcc_usb0_mock_utmi_clk.clkr, + [GCC_USB0_MOCK_UTMI_CLK_SRC] = &gcc_usb0_mock_utmi_clk_src.clkr, + [GCC_USB0_MOCK_UTMI_DIV_CLK_SRC] = &gcc_usb0_mock_utmi_div_clk_src.clkr, + [GCC_USB0_PHY_CFG_AHB_CLK] = &gcc_usb0_phy_cfg_ahb_clk.clkr, + [GCC_USB0_PIPE_CLK] = &gcc_usb0_pipe_clk.clkr, + [GCC_USB0_SLEEP_CLK] = &gcc_usb0_sleep_clk.clkr, + [GCC_WCSS_AHB_CLK_SRC] = &gcc_wcss_ahb_clk_src.clkr, + [GCC_WCSS_AXIM_CLK] = &gcc_wcss_axim_clk.clkr, + [GCC_WCSS_AXIS_CLK] = &gcc_wcss_axis_clk.clkr, + [GCC_WCSS_DBG_IFC_APB_BDG_CLK] = &gcc_wcss_dbg_ifc_apb_bdg_clk.clkr, + [GCC_WCSS_DBG_IFC_APB_CLK] = &gcc_wcss_dbg_ifc_apb_clk.clkr, + [GCC_WCSS_DBG_IFC_ATB_BDG_CLK] = &gcc_wcss_dbg_ifc_atb_bdg_clk.clkr, + [GCC_WCSS_DBG_IFC_ATB_CLK] = &gcc_wcss_dbg_ifc_atb_clk.clkr, + [GCC_WCSS_DBG_IFC_NTS_BDG_CLK] = &gcc_wcss_dbg_ifc_nts_bdg_clk.clkr, + [GCC_WCSS_DBG_IFC_NTS_CLK] = &gcc_wcss_dbg_ifc_nts_clk.clkr, + [GCC_WCSS_ECAHB_CLK] = &gcc_wcss_ecahb_clk.clkr, + [GCC_WCSS_MST_ASYNC_BDG_CLK] = &gcc_wcss_mst_async_bdg_clk.clkr, + [GCC_WCSS_SLV_ASYNC_BDG_CLK] = &gcc_wcss_slv_async_bdg_clk.clkr, + [GCC_XO_CLK] = &gcc_xo_clk.clkr, + [GCC_XO_CLK_SRC] = &gcc_xo_clk_src.clkr, + [GCC_XO_DIV4_CLK] = &gcc_xo_div4_clk.clkr, + [GCC_IM_SLEEP_CLK] = &gcc_im_sleep_clk.clkr, + [GCC_NSSNOC_PCNOC_1_CLK] = &gcc_nssnoc_pcnoc_1_clk.clkr, + [GCC_MEM_NOC_AHB_CLK] = &gcc_mem_noc_ahb_clk.clkr, + [GCC_MEM_NOC_APSS_AXI_CLK] = &gcc_mem_noc_apss_axi_clk.clkr, + [GCC_SNOC_QOSGEN_EXTREF_DIV_CLK_SRC] = &gcc_snoc_qosgen_extref_div_clk_src.clkr, + [GCC_MEM_NOC_QOSGEN_EXTREF_CLK] = &gcc_mem_noc_qosgen_extref_clk.clkr, + [GCC_PCIE3X2_PIPE_CLK_SRC] = &gcc_pcie3x2_pipe_clk_src.clkr, + [GCC_PCIE3X1_0_PIPE_CLK_SRC] = &gcc_pcie3x1_0_pipe_clk_src.clkr, + [GCC_PCIE3X1_1_PIPE_CLK_SRC] = &gcc_pcie3x1_1_pipe_clk_src.clkr, + [GCC_USB0_PIPE_CLK_SRC] = &gcc_usb0_pipe_clk_src.clkr, +}; + +static const struct qcom_reset_map gcc_ipq5332_resets[] = { + [GCC_ADSS_BCR] = { 0x1c000 }, + [GCC_ADSS_PWM_CLK_ARES] = { 0x1c00c, 2 }, + [GCC_AHB_CLK_ARES] = { 0x34024, 2 }, + [GCC_APC0_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x38000 }, + [GCC_APC0_VOLTAGE_DROOP_DETECTOR_GPLL0_CLK_ARES] = { 0x3800c, 2 }, + [GCC_APSS_AHB_CLK_ARES] = { 0x24018, 2 }, + [GCC_APSS_AXI_CLK_ARES] = { 0x2401c, 2 }, + [GCC_BLSP1_AHB_CLK_ARES] = { 0x1008, 2 }, + [GCC_BLSP1_BCR] = { 0x1000 }, + [GCC_BLSP1_QUP1_BCR] = { 0x2000 }, + [GCC_BLSP1_QUP1_I2C_APPS_CLK_ARES] = { 0x2024, 2 }, + [GCC_BLSP1_QUP1_SPI_APPS_CLK_ARES] = { 0x2020, 2 }, + [GCC_BLSP1_QUP2_BCR] = { 0x3000 }, + [GCC_BLSP1_QUP2_I2C_APPS_CLK_ARES] = { 0x3024, 2 }, + [GCC_BLSP1_QUP2_SPI_APPS_CLK_ARES] = { 0x3020, 2 }, + [GCC_BLSP1_QUP3_BCR] = { 0x4000 }, + [GCC_BLSP1_QUP3_I2C_APPS_CLK_ARES] = { 0x4024, 2 }, + [GCC_BLSP1_QUP3_SPI_APPS_CLK_ARES] = { 0x4020, 2 }, + [GCC_BLSP1_SLEEP_CLK_ARES] = { 0x1010, 2 }, + [GCC_BLSP1_UART1_APPS_CLK_ARES] = { 0x2040, 2 }, + [GCC_BLSP1_UART1_BCR] = { 0x2028 }, + [GCC_BLSP1_UART2_APPS_CLK_ARES] = { 0x3040, 2 }, + [GCC_BLSP1_UART2_BCR] = { 0x3028 }, + [GCC_BLSP1_UART3_APPS_CLK_ARES] = { 0x4054, 2 }, + [GCC_BLSP1_UART3_BCR] = { 0x4028 }, + [GCC_CE_BCR] = { 0x18008 }, + [GCC_CMN_BLK_BCR] = { 0x3a000 }, + [GCC_CMN_LDO0_BCR] = { 0x1d000 }, + [GCC_CMN_LDO1_BCR] = { 0x1d008 }, + [GCC_DCC_BCR] = { 0x35000 }, + [GCC_GP1_CLK_ARES] = { 0x8018, 2 }, + [GCC_GP2_CLK_ARES] = { 0x9018, 2 }, + [GCC_LPASS_BCR] = { 0x27000 }, + [GCC_LPASS_CORE_AXIM_CLK_ARES] = { 0x27018, 2 }, + [GCC_LPASS_SWAY_CLK_ARES] = { 0x27014, 2 }, + [GCC_MDIOM_BCR] = { 0x12000 }, + [GCC_MDIOS_BCR] = { 0x12008 }, + [GCC_NSS_BCR] = { 0x17000 }, + [GCC_NSS_TS_CLK_ARES] = { 0x17018, 2 }, + [GCC_NSSCC_CLK_ARES] = { 0x17034, 2 }, + [GCC_NSSCFG_CLK_ARES] = { 0x1702c, 2 }, + [GCC_NSSNOC_ATB_CLK_ARES] = { 0x17014, 2 }, + [GCC_NSSNOC_NSSCC_CLK_ARES] = { 0x17030, 2 }, + [GCC_NSSNOC_QOSGEN_REF_CLK_ARES] = { 0x1701c, 2 }, + [GCC_NSSNOC_SNOC_1_CLK_ARES] = { 0x1707c, 2 }, + [GCC_NSSNOC_SNOC_CLK_ARES] = { 0x17028, 2 }, + [GCC_NSSNOC_TIMEOUT_REF_CLK_ARES] = { 0x17020, 2 }, + [GCC_NSSNOC_XO_DCD_CLK_ARES] = { 0x17074, 2 }, + [GCC_PCIE3X1_0_AHB_CLK_ARES] = { 0x29030, 2 }, + [GCC_PCIE3X1_0_AUX_CLK_ARES] = { 0x29070, 2 }, + [GCC_PCIE3X1_0_AXI_M_CLK_ARES] = { 0x29038, 2 }, + [GCC_PCIE3X1_0_AXI_S_BRIDGE_CLK_ARES] = { 0x29048, 2 }, + [GCC_PCIE3X1_0_AXI_S_CLK_ARES] = { 0x29040, 2 }, + [GCC_PCIE3X1_0_BCR] = { 0x29000 }, + [GCC_PCIE3X1_0_LINK_DOWN_BCR] = { 0x29054 }, + [GCC_PCIE3X1_0_PHY_BCR] = { 0x29060 }, + [GCC_PCIE3X1_0_PHY_PHY_BCR] = { 0x2905c }, + [GCC_PCIE3X1_1_AHB_CLK_ARES] = { 0x2a00c, 2 }, + [GCC_PCIE3X1_1_AUX_CLK_ARES] = { 0x2a070, 2 }, + [GCC_PCIE3X1_1_AXI_M_CLK_ARES] = { 0x2a014, 2 }, + [GCC_PCIE3X1_1_AXI_S_BRIDGE_CLK_ARES] = { 0x2a024, 2 }, + [GCC_PCIE3X1_1_AXI_S_CLK_ARES] = { 0x2a01c, 2 }, + [GCC_PCIE3X1_1_BCR] = { 0x2a000 }, + [GCC_PCIE3X1_1_LINK_DOWN_BCR] = { 0x2a028 }, + [GCC_PCIE3X1_1_PHY_BCR] = { 0x2a030 }, + [GCC_PCIE3X1_1_PHY_PHY_BCR] = { 0x2a02c }, + [GCC_PCIE3X1_PHY_AHB_CLK_ARES] = { 0x29078, 2 }, + [GCC_PCIE3X2_AHB_CLK_ARES] = { 0x28030, 2 }, + [GCC_PCIE3X2_AUX_CLK_ARES] = { 0x28070, 2 }, + [GCC_PCIE3X2_AXI_M_CLK_ARES] = { 0x28038, 2 }, + [GCC_PCIE3X2_AXI_S_BRIDGE_CLK_ARES] = { 0x28048, 2 }, + [GCC_PCIE3X2_AXI_S_CLK_ARES] = { 0x28040, 2 }, + [GCC_PCIE3X2_BCR] = { 0x28000 }, + [GCC_PCIE3X2_LINK_DOWN_BCR] = { 0x28054 }, + [GCC_PCIE3X2_PHY_AHB_CLK_ARES] = { 0x28080, 2 }, + [GCC_PCIE3X2_PHY_BCR] = { 0x28060 }, + [GCC_PCIE3X2PHY_PHY_BCR] = { 0x2805c }, + [GCC_PCNOC_BCR] = { 0x31000 }, + [GCC_PCNOC_LPASS_CLK_ARES] = { 0x31020, 2 }, + [GCC_PRNG_AHB_CLK_ARES] = { 0x13024, 2 }, + [GCC_PRNG_BCR] = { 0x13020 }, + [GCC_Q6_AHB_CLK_ARES] = { 0x25014, 2 }, + [GCC_Q6_AHB_S_CLK_ARES] = { 0x25018, 2 }, + [GCC_Q6_AXIM_CLK_ARES] = { 0x2500c, 2 }, + [GCC_Q6_AXIS_CLK_ARES] = { 0x25010, 2 }, + [GCC_Q6_TSCTR_1TO2_CLK_ARES] = { 0x25020, 2 }, + [GCC_Q6SS_ATBM_CLK_ARES] = { 0x2501c, 2 }, + [GCC_Q6SS_PCLKDBG_CLK_ARES] = { 0x25024, 2 }, + [GCC_Q6SS_TRIG_CLK_ARES] = { 0x250a0, 2 }, + [GCC_QDSS_APB2JTAG_CLK_ARES] = { 0x2d060, 2 }, + [GCC_QDSS_AT_CLK_ARES] = { 0x2d038, 2 }, + [GCC_QDSS_BCR] = { 0x2d000 }, + [GCC_QDSS_CFG_AHB_CLK_ARES] = { 0x2d06c, 2 }, + [GCC_QDSS_DAP_AHB_CLK_ARES] = { 0x2d068, 2 }, + [GCC_QDSS_DAP_CLK_ARES] = { 0x2d05c, 2 }, + [GCC_QDSS_ETR_USB_CLK_ARES] = { 0x2d064, 2 }, + [GCC_QDSS_EUD_AT_CLK_ARES] = { 0x2d070, 2 }, + [GCC_QDSS_STM_CLK_ARES] = { 0x2d040, 2 }, + [GCC_QDSS_TRACECLKIN_CLK_ARES] = { 0x2d044, 2 }, + [GCC_QDSS_TS_CLK_ARES] = { 0x2d078, 2 }, + [GCC_QDSS_TSCTR_DIV16_CLK_ARES] = { 0x2d058, 2 }, + [GCC_QDSS_TSCTR_DIV2_CLK_ARES] = { 0x2d048, 2 }, + [GCC_QDSS_TSCTR_DIV3_CLK_ARES] = { 0x2d04c, 2 }, + [GCC_QDSS_TSCTR_DIV4_CLK_ARES] = { 0x2d050, 2 }, + [GCC_QDSS_TSCTR_DIV8_CLK_ARES] = { 0x2d054, 2 }, + [GCC_QPIC_AHB_CLK_ARES] = { 0x32010, 2 }, + [GCC_QPIC_CLK_ARES] = { 0x32014, 2 }, + [GCC_QPIC_BCR] = { 0x32000 }, + [GCC_QPIC_IO_MACRO_CLK_ARES] = { 0x3200c, 2 }, + [GCC_QPIC_SLEEP_CLK_ARES] = { 0x3201c, 2 }, + [GCC_QUSB2_0_PHY_BCR] = { 0x2c068 }, + [GCC_SDCC1_AHB_CLK_ARES] = { 0x33034, 2 }, + [GCC_SDCC1_APPS_CLK_ARES] = { 0x3302c, 2 }, + [GCC_SDCC_BCR] = { 0x33000 }, + [GCC_SNOC_BCR] = { 0x2e000 }, + [GCC_SNOC_LPASS_CFG_CLK_ARES] = { 0x2e028, 2 }, + [GCC_SNOC_NSSNOC_1_CLK_ARES] = { 0x17090, 2 }, + [GCC_SNOC_NSSNOC_CLK_ARES] = { 0x17084, 2 }, + [GCC_SYS_NOC_QDSS_STM_AXI_CLK_ARES] = { 0x2e034, 2 }, + [GCC_SYS_NOC_WCSS_AHB_CLK_ARES] = { 0x2e030, 2 }, + [GCC_UNIPHY0_AHB_CLK_ARES] = { 0x16010, 2 }, + [GCC_UNIPHY0_BCR] = { 0x16000 }, + [GCC_UNIPHY0_SYS_CLK_ARES] = { 0x1600c, 2 }, + [GCC_UNIPHY1_AHB_CLK_ARES] = { 0x1601c, 2 }, + [GCC_UNIPHY1_BCR] = { 0x16014 }, + [GCC_UNIPHY1_SYS_CLK_ARES] = { 0x16018, 2 }, + [GCC_USB0_AUX_CLK_ARES] = { 0x2c050, 2 }, + [GCC_USB0_EUD_AT_CLK_ARES] = { 0x30004, 2 }, + [GCC_USB0_LFPS_CLK_ARES] = { 0x2c090, 2 }, + [GCC_USB0_MASTER_CLK_ARES] = { 0x2c048, 2 }, + [GCC_USB0_MOCK_UTMI_CLK_ARES] = { 0x2c054, 2 }, + [GCC_USB0_PHY_BCR] = { 0x2c06c }, + [GCC_USB0_PHY_CFG_AHB_CLK_ARES] = { 0x2c05c, 2 }, + [GCC_USB0_SLEEP_CLK_ARES] = { 0x2c058, 2 }, + [GCC_USB3PHY_0_PHY_BCR] = { 0x2c070 }, + [GCC_USB_BCR] = { 0x2c000 }, + [GCC_WCSS_AXIM_CLK_ARES] = { 0x2505c, 2 }, + [GCC_WCSS_AXIS_CLK_ARES] = { 0x25060, 2 }, + [GCC_WCSS_BCR] = { 0x18004 }, + [GCC_WCSS_DBG_IFC_APB_BDG_CLK_ARES] = { 0x25048, 2 }, + [GCC_WCSS_DBG_IFC_APB_CLK_ARES] = { 0x25038, 2 }, + [GCC_WCSS_DBG_IFC_ATB_BDG_CLK_ARES] = { 0x2504c, 2 }, + [GCC_WCSS_DBG_IFC_ATB_CLK_ARES] = { 0x2503c, 2 }, + [GCC_WCSS_DBG_IFC_NTS_BDG_CLK_ARES] = { 0x25050, 2 }, + [GCC_WCSS_DBG_IFC_NTS_CLK_ARES] = { 0x25040, 2 }, + [GCC_WCSS_ECAHB_CLK_ARES] = { 0x25058, 2 }, + [GCC_WCSS_MST_ASYNC_BDG_CLK_ARES] = { 0x2e0b0, 2 }, + [GCC_WCSS_Q6_BCR] = { 0x18000 }, + [GCC_WCSS_SLV_ASYNC_BDG_CLK_ARES] = { 0x2e0b4, 2 }, + [GCC_XO_CLK_ARES] = { 0x34018, 2 }, + [GCC_XO_DIV4_CLK_ARES] = { 0x3401c, 2 }, + [GCC_Q6SS_DBG_ARES] = { 0x25094 }, + [GCC_WCSS_DBG_BDG_ARES] = { 0x25098, 0 }, + [GCC_WCSS_DBG_ARES] = { 0x25098, 1 }, + [GCC_WCSS_AXI_S_ARES] = { 0x25098, 2 }, + [GCC_WCSS_AXI_M_ARES] = { 0x25098, 3 }, + [GCC_WCSSAON_ARES] = { 0x2509C }, + [GCC_PCIE3X2_PIPE_ARES] = { 0x28058, 0 }, + [GCC_PCIE3X2_CORE_STICKY_ARES] = { 0x28058, 1 }, + [GCC_PCIE3X2_AXI_S_STICKY_ARES] = { 0x28058, 2 }, + [GCC_PCIE3X2_AXI_M_STICKY_ARES] = { 0x28058, 3 }, + [GCC_PCIE3X1_0_PIPE_ARES] = { 0x29058, 0 }, + [GCC_PCIE3X1_0_CORE_STICKY_ARES] = { 0x29058, 1 }, + [GCC_PCIE3X1_0_AXI_S_STICKY_ARES] = { 0x29058, 2 }, + [GCC_PCIE3X1_0_AXI_M_STICKY_ARES] = { 0x29058, 3 }, + [GCC_PCIE3X1_1_PIPE_ARES] = { 0x2a058, 0 }, + [GCC_PCIE3X1_1_CORE_STICKY_ARES] = { 0x2a058, 1 }, + [GCC_PCIE3X1_1_AXI_S_STICKY_ARES] = { 0x2a058, 2 }, + [GCC_PCIE3X1_1_AXI_M_STICKY_ARES] = { 0x2a058, 3 }, + [GCC_IM_SLEEP_CLK_ARES] = { 0x34020, 2 }, + [GCC_NSSNOC_PCNOC_1_CLK_ARES] = { 0x17080, 2 }, + [GCC_UNIPHY0_XPCS_ARES] = { 0x16050 }, + [GCC_UNIPHY1_XPCS_ARES] = { 0x16060 }, +}; + +static const struct regmap_config gcc_ipq5332_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3f024, + .fast_io = true, +}; + +static struct clk_hw *gcc_ipq5332_hws[] = { + &gpll0_div2.hw, + &gcc_xo_div4_clk_src.hw, + &gcc_system_noc_bfdcd_div2_clk_src.hw, + &gcc_qdss_tsctr_div2_clk_src.hw, + &gcc_qdss_tsctr_div3_clk_src.hw, + &gcc_qdss_tsctr_div4_clk_src.hw, + &gcc_qdss_tsctr_div8_clk_src.hw, + &gcc_qdss_tsctr_div16_clk_src.hw, + &gcc_eud_at_div_clk_src.hw, +}; + +static const struct qcom_cc_desc gcc_ipq5332_desc = { + .config = &gcc_ipq5332_regmap_config, + .clks = gcc_ipq5332_clocks, + .num_clks = ARRAY_SIZE(gcc_ipq5332_clocks), + .resets = gcc_ipq5332_resets, + .num_resets = ARRAY_SIZE(gcc_ipq5332_resets), + .clk_hws = gcc_ipq5332_hws, + .num_clk_hws = ARRAY_SIZE(gcc_ipq5332_hws), +}; + +static int gcc_ipq5332_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_ipq5332_desc); +} + +static const struct of_device_id gcc_ipq5332_match_table[] = { + { .compatible = "qcom,ipq5332-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_ipq5332_match_table); + +static struct platform_driver gcc_ipq5332_driver = { + .probe = gcc_ipq5332_probe, + .driver = { + .name = "gcc-ipq5332", + .of_match_table = gcc_ipq5332_match_table, + }, +}; + +static int __init gcc_ipq5332_init(void) +{ + return platform_driver_register(&gcc_ipq5332_driver); +} +core_initcall(gcc_ipq5332_init); + +static void __exit gcc_ipq5332_exit(void) +{ + platform_driver_unregister(&gcc_ipq5332_driver); +} +module_exit(gcc_ipq5332_exit); + +MODULE_DESCRIPTION("QTI GCC IPQ5332 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c new file mode 100644 index 000000000000..b2a2d618a5ec --- /dev/null +++ b/drivers/clk/qcom/gcc-ipq9574.c @@ -0,0 +1,4248 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright (c) 2023 The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-alpha-pll.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "reset.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_XO, + DT_SLEEP_CLK, + DT_BIAS_PLL_UBI_NC_CLK, + DT_PCIE30_PHY0_PIPE_CLK, + DT_PCIE30_PHY1_PIPE_CLK, + DT_PCIE30_PHY2_PIPE_CLK, + DT_PCIE30_PHY3_PIPE_CLK, + DT_USB3PHY_0_CC_PIPE_CLK, +}; + +enum { + P_XO, + P_PCIE30_PHY0_PIPE, + P_PCIE30_PHY1_PIPE, + P_PCIE30_PHY2_PIPE, + P_PCIE30_PHY3_PIPE, + P_USB3PHY_0_PIPE, + P_GPLL0, + P_GPLL0_DIV2, + P_GPLL0_OUT_AUX, + P_GPLL2, + P_GPLL4, + P_PI_SLEEP, + P_BIAS_PLL_UBI_NC_CLK, +}; + +static const struct parent_map gcc_xo_map[] = { + { P_XO, 0 }, +}; + +static const struct clk_parent_data gcc_xo_data[] = { + { .index = DT_XO }, +}; + +static const struct clk_parent_data gcc_sleep_clk_data[] = { + { .index = DT_SLEEP_CLK }, +}; + +static struct clk_alpha_pll gpll0_main = { + .offset = 0x20000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gpll0_main", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_fixed_factor gpll0_out_main_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "gpll0_out_main_div2", + .parent_hws = (const struct clk_hw *[]) { + &gpll0_main.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_alpha_pll_postdiv gpll0 = { + .offset = 0x20000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll0", + .parent_hws = (const struct clk_hw *[]) { + &gpll0_main.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_alpha_pll gpll4_main = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data) { + .name = "gpll4_main", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll4", + .parent_hws = (const struct clk_hw *[]) { + &gpll4_main.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_alpha_pll gpll2_main = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x0b000, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gpll2_main", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll2 = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .width = 4, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gpll2", + .parent_hws = (const struct clk_hw *[]) { + &gpll2_main.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_branch gcc_sleep_clk_src = { + .halt_reg = 0x3400c, + .clkr = { + .enable_reg = 0x3400c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sleep_clk_src", + .parent_data = gcc_sleep_clk_data, + .num_parents = ARRAY_SIZE(gcc_sleep_clk_data), + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll0_out_main_div2[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll4[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll0_div2_gpll0[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll0_div2_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_DIV2, 4 }, + { P_GPLL0, 5 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll0_sleep_clk[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll0_sleep_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_DIV2, 4 }, + { P_PI_SLEEP, 6 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_core_pi_sleep_clk[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_xo_gpll0_core_pi_sleep_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 2 }, + { P_PI_SLEEP, 6 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .index = DT_BIAS_PLL_UBI_NC_CLK }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, + { P_BIAS_PLL_UBI_NC_CLK, 3 }, +}; + +static const struct clk_parent_data + gcc_xo_gpll0_gpll0_aux_core_pi_sleep_clk[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map + gcc_xo_gpll0_gpll0_aux_core_pi_sleep_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_PI_SLEEP, 6 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_out_main_div2_gpll0[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_out_main_div2_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data + gcc_xo_gpll4_gpll0_gpll0_out_main_div2[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll4_gpll0_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL4, 1 }, + { P_GPLL0, 3 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = { + { .index = DT_USB3PHY_0_CC_PIPE_CLK }, + { .index = DT_XO }, +}; + +static const struct parent_map gcc_usb3phy_0_cc_pipe_clk_xo_map[] = { + { P_USB3PHY_0_PIPE, 0 }, + { P_XO, 2 }, +}; + +static const struct clk_parent_data + gcc_xo_gpll0_gpll2_gpll0_out_main_div2[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL2, 2 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll4_gpll0_div2[] = { + { .index = DT_XO}, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_gpll0_div2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data gcc_xo_gpll4_gpll0_gpll0_div2[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_main_div2.hw }, +}; + +static const struct parent_map gcc_xo_gpll4_gpll0_gpll0_div2_map[] = { + { P_XO, 0 }, + { P_GPLL4, 1 }, + { P_GPLL0, 2 }, + { P_GPLL0_DIV2, 4 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll2[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL2, 2 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll2_gpll4_pi_sleep[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, + { .hw = &gpll4.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll2_gpll4_pi_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL2, 2 }, + { P_GPLL4, 3 }, + { P_PI_SLEEP, 6 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll0_aux_gpll2[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll0_aux_gpll2_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_GPLL2, 3 }, +}; + +static const struct freq_tbl ftbl_apss_ahb_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 apss_ahb_clk_src = { + .cmd_rcgr = 0x2400c, + .freq_tbl = ftbl_apss_ahb_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apss_ahb_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_apss_axi_clk_src[] = { + F(533000000, P_GPLL0, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 apss_axi_clk_src = { + .cmd_rcgr = 0x24004, + .freq_tbl = ftbl_apss_axi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_div2_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apss_axi_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_div2_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_div2_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_blsp1_qup_i2c_apps_clk_src[] = { + F(9600000, P_XO, 2.5, 0, 0), + F(24000000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x02018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_blsp1_qup_spi_apps_clk_src[] = { + F(960000, P_XO, 10, 2, 5), + F(4800000, P_XO, 5, 0, 0), + F(9600000, P_XO, 2, 4, 5), + F(16000000, P_GPLL0, 10, 1, 5), + F(24000000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0, 16, 1, 2), + F(50000000, P_GPLL0, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x02004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x03018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x03004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x04018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup3_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x04004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup3_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x05018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup4_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x05004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup4_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = { + .cmd_rcgr = 0x06018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup5_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = { + .cmd_rcgr = 0x06004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup5_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = { + .cmd_rcgr = 0x07018, + .freq_tbl = ftbl_blsp1_qup_i2c_apps_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup6_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = { + .cmd_rcgr = 0x07004, + .freq_tbl = ftbl_blsp1_qup_spi_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup6_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_blsp1_uart_apps_clk_src[] = { + F(3686400, P_GPLL0_DIV2, 1, 144, 15625), + F(7372800, P_GPLL0_DIV2, 1, 288, 15625), + F(14745600, P_GPLL0_DIV2, 1, 576, 15625), + F(24000000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0, 16, 1, 2), + F(32000000, P_GPLL0, 1, 1, 25), + F(40000000, P_GPLL0, 1, 1, 20), + F(46400000, P_GPLL0, 1, 29, 500), + F(48000000, P_GPLL0, 1, 3, 50), + F(51200000, P_GPLL0, 1, 8, 125), + F(56000000, P_GPLL0, 1, 7, 100), + F(58982400, P_GPLL0, 1, 1152, 15625), + F(60000000, P_GPLL0, 1, 3, 40), + F(64000000, P_GPLL0, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x0202c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart1_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x0302c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart2_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x0402c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart3_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart4_apps_clk_src = { + .cmd_rcgr = 0x0502c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart4_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart5_apps_clk_src = { + .cmd_rcgr = 0x0602c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart5_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart6_apps_clk_src = { + .cmd_rcgr = 0x0702c, + .freq_tbl = ftbl_blsp1_uart_apps_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart6_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_apss_ahb_clk = { + .halt_reg = 0x24018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_apss_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &apss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_apss_axi_clk = { + .halt_reg = 0x2401c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_apss_axi_clk", + .parent_hws = (const struct clk_hw *[]) { + &apss_axi_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x2024, + .clkr = { + .enable_reg = 0x2024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup1_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x02020, + .clkr = { + .enable_reg = 0x02020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup1_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x03024, + .clkr = { + .enable_reg = 0x03024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup2_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x03020, + .clkr = { + .enable_reg = 0x03020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup2_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x04024, + .clkr = { + .enable_reg = 0x04024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup3_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x04020, + .clkr = { + .enable_reg = 0x04020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup3_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x05024, + .clkr = { + .enable_reg = 0x05024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup4_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x05020, + .clkr = { + .enable_reg = 0x05020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup4_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = { + .halt_reg = 0x06024, + .clkr = { + .enable_reg = 0x06024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup5_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup5_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = { + .halt_reg = 0x06020, + .clkr = { + .enable_reg = 0x06020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup5_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup5_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = { + .halt_reg = 0x07024, + .clkr = { + .enable_reg = 0x07024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup6_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup6_i2c_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = { + .halt_reg = 0x07020, + .clkr = { + .enable_reg = 0x07020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup6_spi_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_qup6_spi_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x02040, + .clkr = { + .enable_reg = 0x02040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart1_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart1_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x03040, + .clkr = { + .enable_reg = 0x03040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart2_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart2_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x04054, + .clkr = { + .enable_reg = 0x04054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart3_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart3_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart4_apps_clk = { + .halt_reg = 0x05040, + .clkr = { + .enable_reg = 0x05040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart4_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart4_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart5_apps_clk = { + .halt_reg = 0x06040, + .clkr = { + .enable_reg = 0x06040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart5_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart5_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart6_apps_clk = { + .halt_reg = 0x07040, + .clkr = { + .enable_reg = 0x07040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart6_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &blsp1_uart6_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_pcie0_axi_m_clk_src[] = { + F(240000000, P_GPLL4, 5, 0, 0), + { } +}; + +static struct clk_rcg2 pcie0_axi_m_clk_src = { + .cmd_rcgr = 0x28018, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie0_axi_m_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie0_axi_m_clk = { + .halt_reg = 0x28038, + .clkr = { + .enable_reg = 0x28038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_axi_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_anoc_pcie0_1lane_m_clk = { + .halt_reg = 0x2e07c, + .clkr = { + .enable_reg = 0x2e07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_pcie0_1lane_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie1_axi_m_clk_src = { + .cmd_rcgr = 0x29018, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie1_axi_m_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie1_axi_m_clk = { + .halt_reg = 0x29038, + .clkr = { + .enable_reg = 0x29038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_axi_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_anoc_pcie1_1lane_m_clk = { + .halt_reg = 0x2e08c, + .clkr = { + .enable_reg = 0x2e08c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_pcie1_1lane_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_pcie2_axi_m_clk_src[] = { + F(342857143, P_GPLL4, 3.5, 0, 0), + { } +}; + +static struct clk_rcg2 pcie2_axi_m_clk_src = { + .cmd_rcgr = 0x2a018, + .freq_tbl = ftbl_pcie2_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie2_axi_m_clk_src", + .parent_data = gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie2_axi_m_clk = { + .halt_reg = 0x2a038, + .clkr = { + .enable_reg = 0x2a038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_axi_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_anoc_pcie2_2lane_m_clk = { + .halt_reg = 0x2e080, + .clkr = { + .enable_reg = 0x2e080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_pcie2_2lane_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie3_axi_m_clk_src = { + .cmd_rcgr = 0x2b018, + .freq_tbl = ftbl_pcie2_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie3_axi_m_clk_src", + .parent_data = gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3_axi_m_clk = { + .halt_reg = 0x2b038, + .clkr = { + .enable_reg = 0x2b038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_axi_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_anoc_pcie3_2lane_m_clk = { + .halt_reg = 0x2e090, + .clkr = { + .enable_reg = 0x2e090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_pcie3_2lane_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie0_axi_s_clk_src = { + .cmd_rcgr = 0x28020, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie0_axi_s_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie0_axi_s_clk = { + .halt_reg = 0x2803c, + .clkr = { + .enable_reg = 0x2803c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_axi_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_axi_s_bridge_clk = { + .halt_reg = 0x28040, + .clkr = { + .enable_reg = 0x28040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie0_1lane_s_clk = { + .halt_reg = 0x2e048, + .clkr = { + .enable_reg = 0x2e048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_snoc_pcie0_1lane_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie1_axi_s_clk_src = { + .cmd_rcgr = 0x29020, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie1_axi_s_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie1_axi_s_clk = { + .halt_reg = 0x2903c, + .clkr = { + .enable_reg = 0x2903c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_axi_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_axi_s_bridge_clk = { + .halt_reg = 0x29040, + .clkr = { + .enable_reg = 0x29040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie1_1lane_s_clk = { + .halt_reg = 0x2e04c, + .clkr = { + .enable_reg = 0x2e04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_snoc_pcie1_1lane_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie2_axi_s_clk_src = { + .cmd_rcgr = 0x2a020, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie2_axi_s_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie2_axi_s_clk = { + .halt_reg = 0x2a03c, + .clkr = { + .enable_reg = 0x2a03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_axi_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_axi_s_bridge_clk = { + .halt_reg = 0x2a040, + .clkr = { + .enable_reg = 0x2a040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie2_2lane_s_clk = { + .halt_reg = 0x2e050, + .clkr = { + .enable_reg = 0x2e050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_snoc_pcie2_2lane_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie3_axi_s_clk_src = { + .cmd_rcgr = 0x2b020, + .freq_tbl = ftbl_pcie0_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie3_axi_s_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3_axi_s_clk = { + .halt_reg = 0x2b03c, + .clkr = { + .enable_reg = 0x2b03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_axi_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3_axi_s_bridge_clk = { + .halt_reg = 0x2b040, + .clkr = { + .enable_reg = 0x2b040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_pcie3_2lane_s_clk = { + .halt_reg = 0x2e054, + .clkr = { + .enable_reg = 0x2e054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_snoc_pcie3_2lane_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_axi_s_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux pcie0_pipe_clk_src = { + .reg = 0x28064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "pcie0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE30_PHY0_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux pcie1_pipe_clk_src = { + .reg = 0x29064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "pcie1_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE30_PHY1_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux pcie2_pipe_clk_src = { + .reg = 0x2a064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "pcie2_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE30_PHY2_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux pcie3_pipe_clk_src = { + .reg = 0x2b064, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "pcie3_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE30_PHY3_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 pcie0_rchng_clk_src = { + .cmd_rcgr = 0x28028, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie0_rchng_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie0_rchng_clk = { + .halt_reg = 0x28028, + .clkr = { + .enable_reg = 0x28028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie0_rchng_clk_src.clkr.hw + + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie1_rchng_clk_src = { + .cmd_rcgr = 0x29028, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie1_rchng_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie1_rchng_clk = { + .halt_reg = 0x29028, + .clkr = { + .enable_reg = 0x29028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie1_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie2_rchng_clk_src = { + .cmd_rcgr = 0x2a028, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie2_rchng_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie2_rchng_clk = { + .halt_reg = 0x2a028, + .clkr = { + .enable_reg = 0x2a028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie2_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 pcie3_rchng_clk_src = { + .cmd_rcgr = 0x2b028, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie3_rchng_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie3_rchng_clk = { + .halt_reg = 0x2b028, + .clkr = { + .enable_reg = 0x2b028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie3_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_pcie_aux_clk_src[] = { + F(20000000, P_GPLL0, 10, 1, 4), + { } +}; + +static struct clk_rcg2 pcie_aux_clk_src = { + .cmd_rcgr = 0x28004, + .freq_tbl = ftbl_pcie_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_aux_core_pi_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcie_aux_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_aux_core_pi_sleep_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_aux_core_pi_sleep_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_pcie0_aux_clk = { + .halt_reg = 0x28034, + .clkr = { + .enable_reg = 0x28034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_aux_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie_aux_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_aux_clk = { + .halt_reg = 0x29034, + .clkr = { + .enable_reg = 0x29034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_aux_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie_aux_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_aux_clk = { + .halt_reg = 0x2a034, + .clkr = { + .enable_reg = 0x2a034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_aux_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie_aux_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3_aux_clk = { + .halt_reg = 0x2b034, + .clkr = { + .enable_reg = 0x2b034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_aux_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcie_aux_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_usb_aux_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 usb0_aux_clk_src = { + .cmd_rcgr = 0x2c018, + .freq_tbl = ftbl_usb_aux_clk_src, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_core_pi_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "usb0_aux_clk_src", + .parent_data = gcc_xo_gpll0_core_pi_sleep_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_core_pi_sleep_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_usb0_aux_clk = { + .halt_reg = 0x2c048, + .clkr = { + .enable_reg = 0x2c048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_aux_clk", + .parent_hws = (const struct clk_hw *[]) { + &usb0_aux_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_usb0_master_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 usb0_master_clk_src = { + .cmd_rcgr = 0x2c004, + .freq_tbl = ftbl_usb0_master_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_out_main_div2_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "usb0_master_clk_src", + .parent_data = gcc_xo_gpll0_out_main_div2_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_out_main_div2_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_usb0_master_clk = { + .halt_reg = 0x2c044, + .clkr = { + .enable_reg = 0x2c044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_master_clk", + .parent_hws = (const struct clk_hw *[]) { + &usb0_master_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_usb_clk = { + .halt_reg = 0x2e058, + .clkr = { + .enable_reg = 0x2e058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_snoc_usb_clk", + .parent_hws = (const struct clk_hw *[]) { + &usb0_master_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_anoc_usb_axi_clk = { + .halt_reg = 0x2e084, + .clkr = { + .enable_reg = 0x2e084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_usb_axi_clk", + .parent_hws = (const struct clk_hw *[]) { + &usb0_master_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_usb0_mock_utmi_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(60000000, P_GPLL4, 10, 1, 2), + { } +}; + +static struct clk_rcg2 usb0_mock_utmi_clk_src = { + .cmd_rcgr = 0x2c02c, + .freq_tbl = ftbl_usb0_mock_utmi_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll4_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "usb0_mock_utmi_clk_src", + .parent_data = gcc_xo_gpll4_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll4_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div usb0_mock_utmi_div_clk_src = { + .reg = 0x2c040, + .shift = 0, + .width = 2, + .clkr.hw.init = &(struct clk_init_data) { + .name = "usb0_mock_utmi_div_clk_src", + .parent_data = &(const struct clk_parent_data) { + .hw = &usb0_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_usb0_mock_utmi_clk = { + .halt_reg = 0x2c04c, + .clkr = { + .enable_reg = 0x2c04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_mock_utmi_clk", + .parent_hws = (const struct clk_hw *[]) { + &usb0_mock_utmi_div_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_mux usb0_pipe_clk_src = { + .reg = 0x2C074, + .shift = 8, + .width = 2, + .parent_map = gcc_usb3phy_0_cc_pipe_clk_xo_map, + .clkr = { + .hw.init = &(struct clk_init_data) { + .name = "usb0_pipe_clk_src", + .parent_data = gcc_usb3phy_0_cc_pipe_clk_xo, + .num_parents = ARRAY_SIZE(gcc_usb3phy_0_cc_pipe_clk_xo), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_sdcc_apps_clk_src[] = { + F(144000, P_XO, 16, 12, 125), + F(400000, P_XO, 12, 1, 5), + F(24000000, P_GPLL2, 12, 1, 4), + F(48000000, P_GPLL2, 12, 1, 2), + F(96000000, P_GPLL2, 12, 0, 0), + F(177777778, P_GPLL0, 4.5, 0, 0), + F(192000000, P_GPLL2, 6, 0, 0), + F(384000000, P_GPLL2, 3, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x33004, + .freq_tbl = ftbl_sdcc_apps_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll2_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "sdcc1_apps_clk_src", + .parent_data = gcc_xo_gpll0_gpll2_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll0_out_main_div2), + .ops = &clk_rcg2_floor_ops, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x3302c, + .clkr = { + .enable_reg = 0x3302c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw *[]) { + &sdcc1_apps_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_sdcc_ice_core_clk_src[] = { + F(150000000, P_GPLL4, 8, 0, 0), + F(300000000, P_GPLL4, 4, 0, 0), +}; + +static struct clk_rcg2 sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x33018, + .freq_tbl = ftbl_sdcc_ice_core_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_gpll0_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "sdcc1_ice_core_clk_src", + .parent_data = gcc_xo_gpll0_gpll4_gpll0_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4_gpll0_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x33030, + .clkr = { + .enable_reg = 0x33030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk", + .parent_hws = (const struct clk_hw *[]) { + &sdcc1_ice_core_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_pcnoc_bfdcd_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 pcnoc_bfdcd_clk_src = { + .cmd_rcgr = 0x31004, + .freq_tbl = ftbl_pcnoc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pcnoc_bfdcd_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .flags = CLK_IS_CRITICAL, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_nsscfg_clk = { + .halt_reg = 0x1702c, + .clkr = { + .enable_reg = 0x1702c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nsscfg_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_nsscc_clk = { + .halt_reg = 0x17030, + .clkr = { + .enable_reg = 0x17030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_nsscc_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nsscc_clk = { + .halt_reg = 0x17034, + .clkr = { + .enable_reg = 0x17034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nsscc_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_pcnoc_1_clk = { + .halt_reg = 0x17080, + .clkr = { + .enable_reg = 0x17080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_pcnoc_1_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_dap_ahb_clk = { + .halt_reg = 0x2d064, + .clkr = { + .enable_reg = 0x2d064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_dap_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_cfg_ahb_clk = { + .halt_reg = 0x2d068, + .clkr = { + .enable_reg = 0x2d068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_cfg_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_ahb_clk = { + .halt_reg = 0x32010, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qpic_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qpic_clk = { + .halt_reg = 0x32014, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qpic_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdio_ahb_clk = { + .halt_reg = 0x17040, + .clkr = { + .enable_reg = 0x17040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdio_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x0b004, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data) { + .name = "gcc_prng_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_ahb_clk = { + .halt_reg = 0x1704c, + .clkr = { + .enable_reg = 0x1704c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy0_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_ahb_clk = { + .halt_reg = 0x1705c, + .clkr = { + .enable_reg = 0x1705c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy1_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_ahb_clk = { + .halt_reg = 0x1706c, + .clkr = { + .enable_reg = 0x1706c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy2_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_ahb_clk = { + .halt_reg = 0x3a004, + .clkr = { + .enable_reg = 0x3a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cmn_12gpll_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_apu_clk = { + .halt_reg = 0x3a00c, + .clkr = { + .enable_reg = 0x3a00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cmn_12gpll_apu_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_ahb_clk = { + .halt_reg = 0x28030, + .clkr = { + .enable_reg = 0x28030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie0_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_ahb_clk = { + .halt_reg = 0x29030, + .clkr = { + .enable_reg = 0x29030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie1_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_ahb_clk = { + .halt_reg = 0x2a030, + .clkr = { + .enable_reg = 0x2a030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie2_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3_ahb_clk = { + .halt_reg = 0x2b030, + .clkr = { + .enable_reg = 0x2b030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcie3_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb0_phy_cfg_ahb_clk = { + .halt_reg = 0x2c05c, + .clkr = { + .enable_reg = 0x2c05c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_phy_cfg_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x33034, + .clkr = { + .enable_reg = 0x33034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &pcnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_system_noc_bfdcd_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(342850000, P_GPLL4, 3.5, 0, 0), + { } +}; + +static struct clk_rcg2 system_noc_bfdcd_clk_src = { + .cmd_rcgr = 0x2e004, + .freq_tbl = ftbl_system_noc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "system_noc_bfdcd_clk_src", + .parent_data = gcc_xo_gpll0_gpll4, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4), + .flags = CLK_IS_CRITICAL, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_q6ss_boot_clk = { + .halt_reg = 0x25080, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x25080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6ss_boot_clk", + .parent_hws = (const struct clk_hw *[]) { + &system_noc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_snoc_clk = { + .halt_reg = 0x17028, + .clkr = { + .enable_reg = 0x17028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_snoc_clk", + .parent_hws = (const struct clk_hw *[]) { + &system_noc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_snoc_1_clk = { + .halt_reg = 0x1707c, + .clkr = { + .enable_reg = 0x1707c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_snoc_1_clk", + .parent_hws = (const struct clk_hw *[]) { + &system_noc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_etr_usb_clk = { + .halt_reg = 0x2d060, + .clkr = { + .enable_reg = 0x2d060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_etr_usb_clk", + .parent_hws = (const struct clk_hw *[]) { + &system_noc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_wcss_ahb_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + { } +}; + +static struct clk_rcg2 wcss_ahb_clk_src = { + .cmd_rcgr = 0x25030, + .freq_tbl = ftbl_wcss_ahb_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "wcss_ahb_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_q6_ahb_clk = { + .halt_reg = 0x25014, + .clkr = { + .enable_reg = 0x25014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6_ahb_s_clk = { + .halt_reg = 0x25018, + .clkr = { + .enable_reg = 0x25018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6_ahb_s_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_ecahb_clk = { + .halt_reg = 0x25058, + .clkr = { + .enable_reg = 0x25058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_ecahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_acmt_clk = { + .halt_reg = 0x2505c, + .clkr = { + .enable_reg = 0x2505c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_acmt_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_wcss_ahb_clk = { + .halt_reg = 0x2e030, + .clkr = { + .enable_reg = 0x2e030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sys_noc_wcss_ahb_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_ahb_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_wcss_axi_m_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0, 6, 0, 0), + F(266666667, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 wcss_axi_m_clk_src = { + .cmd_rcgr = 0x25078, + .freq_tbl = ftbl_wcss_axi_m_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "wcss_axi_m_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_anoc_wcss_axi_m_clk = { + .halt_reg = 0x2e0a8, + .clkr = { + .enable_reg = 0x2e0a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_anoc_wcss_axi_m_clk", + .parent_hws = (const struct clk_hw *[]) { + &wcss_axi_m_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_qdss_at_clk_src[] = { + F(240000000, P_GPLL4, 5, 0, 0), + { } +}; + +static struct clk_rcg2 qdss_at_clk_src = { + .cmd_rcgr = 0x2d004, + .freq_tbl = ftbl_qdss_at_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll4_gpll0_gpll0_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "qdss_at_clk_src", + .parent_data = gcc_xo_gpll4_gpll0_gpll0_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll4_gpll0_gpll0_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_q6ss_atbm_clk = { + .halt_reg = 0x2501c, + .clkr = { + .enable_reg = 0x2501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6ss_atbm_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_atb_clk = { + .halt_reg = 0x2503c, + .clkr = { + .enable_reg = 0x2503c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_atb_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_atb_clk = { + .halt_reg = 0x17014, + .clkr = { + .enable_reg = 0x17014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_atb_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_at_clk = { + .halt_reg = 0x2d038, + .clkr = { + .enable_reg = 0x2d038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_at_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_at_clk = { + .halt_reg = 0x2e038, + .clkr = { + .enable_reg = 0x2e038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sys_noc_at_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcnoc_at_clk = { + .halt_reg = 0x31024, + .clkr = { + .enable_reg = 0x31024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pcnoc_at_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor gcc_eud_at_div_clk_src = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data) { + .name = "gcc_eud_at_div_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_at_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_usb0_eud_at_clk = { + .halt_reg = 0x30004, + .clkr = { + .enable_reg = 0x30004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_usb0_eud_at_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_eud_at_div_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_eud_at_clk = { + .halt_reg = 0x2d06c, + .clkr = { + .enable_reg = 0x2d06c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_eud_at_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_eud_at_div_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_qdss_stm_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 qdss_stm_clk_src = { + .cmd_rcgr = 0x2d00c, + .freq_tbl = ftbl_qdss_stm_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_out_main_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "qdss_stm_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_out_main_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_out_main_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_qdss_stm_clk = { + .halt_reg = 0x2d03c, + .clkr = { + .enable_reg = 0x2d03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_stm_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_stm_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_qdss_stm_axi_clk = { + .halt_reg = 0x2e034, + .clkr = { + .enable_reg = 0x2e034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sys_noc_qdss_stm_axi_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_stm_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_qdss_traceclkin_clk_src[] = { + F(300000000, P_GPLL4, 4, 0, 0), + { } +}; + +static struct clk_rcg2 qdss_traceclkin_clk_src = { + .cmd_rcgr = 0x2d014, + .freq_tbl = ftbl_qdss_traceclkin_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll4_gpll0_gpll0_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "qdss_traceclkin_clk_src", + .parent_data = gcc_xo_gpll4_gpll0_gpll0_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll4_gpll0_gpll0_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_qdss_traceclkin_clk = { + .halt_reg = 0x2d040, + .clkr = { + .enable_reg = 0x2d040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_traceclkin_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_traceclkin_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_qdss_tsctr_clk_src[] = { + F(600000000, P_GPLL4, 2, 0, 0), + { } +}; + +static struct clk_rcg2 qdss_tsctr_clk_src = { + .cmd_rcgr = 0x2d01c, + .freq_tbl = ftbl_qdss_tsctr_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll4_gpll0_gpll0_div2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "qdss_tsctr_clk_src", + .parent_data = gcc_xo_gpll4_gpll0_gpll0_div2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll4_gpll0_gpll0_div2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor qdss_tsctr_div2_clk_src = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data) { + .name = "qdss_tsctr_div2_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_q6_tsctr_1to2_clk = { + .halt_reg = 0x25020, + .clkr = { + .enable_reg = 0x25020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6_tsctr_1to2_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div2_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_nts_clk = { + .halt_reg = 0x25040, + .clkr = { + .enable_reg = 0x25040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_nts_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div2_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_tsctr_div2_clk = { + .halt_reg = 0x2d044, + .clkr = { + .enable_reg = 0x2d044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div2_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div2_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_uniphy_sys_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 uniphy_sys_clk_src = { + .cmd_rcgr = 0x17090, + .freq_tbl = ftbl_uniphy_sys_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "uniphy_sys_clk_src", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 nss_ts_clk_src = { + .cmd_rcgr = 0x17088, + .freq_tbl = ftbl_uniphy_sys_clk_src, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "nss_ts_clk_src", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_qdss_ts_clk = { + .halt_reg = 0x2d078, + .clkr = { + .enable_reg = 0x2d078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_ts_clk", + .parent_hws = (const struct clk_hw *[]) { + &nss_ts_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor qdss_dap_sync_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data) { + .name = "qdss_dap_sync_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_clk_src.clkr.hw + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_qdss_tsctr_div4_clk = { + .halt_reg = 0x2d04c, + .clkr = { + .enable_reg = 0x2d04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div4_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor qdss_tsctr_div8_clk_src = { + .mult = 1, + .div = 8, + .hw.init = &(struct clk_init_data) { + .name = "qdss_tsctr_div8_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_clk_src.clkr.hw + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_nss_ts_clk = { + .halt_reg = 0x17018, + .clkr = { + .enable_reg = 0x17018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nss_ts_clk", + .parent_hws = (const struct clk_hw *[]) { + &nss_ts_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_tsctr_div8_clk = { + .halt_reg = 0x2d050, + .clkr = { + .enable_reg = 0x2d050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div8_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div8_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor qdss_tsctr_div16_clk_src = { + .mult = 1, + .div = 16, + .hw.init = &(struct clk_init_data) { + .name = "qdss_tsctr_div16_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_clk_src.clkr.hw + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_qdss_tsctr_div16_clk = { + .halt_reg = 0x2d054, + .clkr = { + .enable_reg = 0x2d054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div16_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div16_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6ss_pclkdbg_clk = { + .halt_reg = 0x25024, + .clkr = { + .enable_reg = 0x25024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6ss_pclkdbg_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_q6ss_trig_clk = { + .halt_reg = 0x25068, + .clkr = { + .enable_reg = 0x25068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6ss_trig_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_apb_clk = { + .halt_reg = 0x25038, + .clkr = { + .enable_reg = 0x25038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_apb_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_dbg_ifc_dapbus_clk = { + .halt_reg = 0x25044, + .clkr = { + .enable_reg = 0x25044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_dbg_ifc_dapbus_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_dap_clk = { + .halt_reg = 0x2d058, + .clkr = { + .enable_reg = 0x2d058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_dap_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_apb2jtag_clk = { + .halt_reg = 0x2d05c, + .clkr = { + .enable_reg = 0x2d05c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_apb2jtag_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor qdss_tsctr_div3_clk_src = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data) { + .name = "qdss_tsctr_div3_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_clk_src.clkr.hw + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_qdss_tsctr_div3_clk = { + .halt_reg = 0x2d048, + .clkr = { + .enable_reg = 0x2d048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_tsctr_div3_clk", + .parent_hws = (const struct clk_hw *[]) { + &qdss_tsctr_div3_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_qpic_io_macro_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + { } +}; + +static struct clk_rcg2 qpic_io_macro_clk_src = { + .cmd_rcgr = 0x32004, + .freq_tbl = ftbl_qpic_io_macro_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "qpic_io_macro_clk_src", + .parent_data = gcc_xo_gpll0_gpll2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_qpic_io_macro_clk = { + .halt_reg = 0x3200c, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qpic_io_macro_clk", + .parent_hws = (const struct clk_hw *[]){ + &qpic_io_macro_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_q6_axi_clk_src[] = { + F(533333333, P_GPLL0, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 q6_axi_clk_src = { + .cmd_rcgr = 0x25004, + .freq_tbl = ftbl_q6_axi_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll2_gpll4_pi_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "q6_axi_clk_src", + .parent_data = gcc_xo_gpll0_gpll2_gpll4_pi_sleep, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2_gpll4_pi_sleep), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_q6_axim_clk = { + .halt_reg = 0x2500c, + .clkr = { + .enable_reg = 0x2500c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_q6_axim_clk", + .parent_hws = (const struct clk_hw *[]) { + &q6_axi_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_wcss_q6_tbu_clk = { + .halt_reg = 0x12050, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xb00c, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data) { + .name = "gcc_wcss_q6_tbu_clk", + .parent_hws = (const struct clk_hw *[]) { + &q6_axi_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_q6_axi_clk = { + .halt_reg = 0x19010, + .clkr = { + .enable_reg = 0x19010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mem_noc_q6_axi_clk", + .parent_hws = (const struct clk_hw *[]) { + &q6_axi_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_q6_axim2_clk_src[] = { + F(342857143, P_GPLL4, 3.5, 0, 0), + { } +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_bias_pll_ubinc_clk_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, + { P_BIAS_PLL_UBI_NC_CLK, 4 }, +}; + +static struct clk_rcg2 q6_axim2_clk_src = { + .cmd_rcgr = 0x25028, + .freq_tbl = ftbl_q6_axim2_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_bias_pll_ubinc_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "q6_axim2_clk_src", + .parent_data = gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4_bias_pll_ubi_nc_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_nssnoc_memnoc_bfdcd_clk_src[] = { + F(533333333, P_GPLL0, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 nssnoc_memnoc_bfdcd_clk_src = { + .cmd_rcgr = 0x17004, + .freq_tbl = ftbl_nssnoc_memnoc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_aux_gpll2_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "nssnoc_memnoc_bfdcd_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_aux_gpll2, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_aux_gpll2), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_nssnoc_memnoc_clk = { + .halt_reg = 0x17024, + .clkr = { + .enable_reg = 0x17024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_memnoc_clk", + .parent_hws = (const struct clk_hw *[]) { + &nssnoc_memnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_mem_noc_1_clk = { + .halt_reg = 0x17084, + .clkr = { + .enable_reg = 0x17084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_mem_noc_1_clk", + .parent_hws = (const struct clk_hw *[]) { + &nssnoc_memnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nss_tbu_clk = { + .halt_reg = 0x12040, + .clkr = { + .enable_reg = 0xb00c, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nss_tbu_clk", + .parent_hws = (const struct clk_hw *[]) { + &nssnoc_memnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mem_noc_nssnoc_clk = { + .halt_reg = 0x19014, + .clkr = { + .enable_reg = 0x19014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mem_noc_nssnoc_clk", + .parent_hws = (const struct clk_hw *[]) { + &nssnoc_memnoc_bfdcd_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_lpass_axim_clk_src[] = { + F(133333333, P_GPLL0, 6, 0, 0), + { } +}; + +static struct clk_rcg2 lpass_axim_clk_src = { + .cmd_rcgr = 0x2700c, + .freq_tbl = ftbl_lpass_axim_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "lpass_axim_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 lpass_sway_clk_src = { + .cmd_rcgr = 0x27004, + .freq_tbl = ftbl_lpass_axim_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "lpass_sway_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_adss_pwm_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 adss_pwm_clk_src = { + .cmd_rcgr = 0x1c004, + .freq_tbl = ftbl_adss_pwm_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "adss_pwm_clk_src", + .parent_data = gcc_xo_gpll0, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_adss_pwm_clk = { + .halt_reg = 0x1c00c, + .clkr = { + .enable_reg = 0x1c00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_adss_pwm_clk", + .parent_hws = (const struct clk_hw *[]) { + &adss_pwm_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gp1_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x8004, + .freq_tbl = ftbl_gp1_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp1_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_sleep_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_sleep_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x9004, + .freq_tbl = ftbl_gp1_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp2_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_sleep_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_sleep_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0xa004, + .freq_tbl = ftbl_gp1_clk_src, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll0_sleep_clk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp3_clk_src", + .parent_data = gcc_xo_gpll0_gpll0_sleep_clk, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_sleep_clk), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_xo_clk_src = { + .halt_reg = 0x34004, + .clkr = { + .enable_reg = 0x34004, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_xo_clk_src", + .parent_data = gcc_xo_data, + .num_parents = ARRAY_SIZE(gcc_xo_data), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_xo_dcd_clk = { + .halt_reg = 0x17074, + .clkr = { + .enable_reg = 0x17074, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_xo_dcd_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_clk = { + .halt_reg = 0x34018, + .clkr = { + .enable_reg = 0x34018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_xo_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy0_sys_clk = { + .halt_reg = 0x17048, + .clkr = { + .enable_reg = 0x17048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy0_sys_clk", + .parent_hws = (const struct clk_hw *[]) { + &uniphy_sys_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy1_sys_clk = { + .halt_reg = 0x17058, + .clkr = { + .enable_reg = 0x17058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy1_sys_clk", + .parent_hws = (const struct clk_hw *[]) { + &uniphy_sys_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_uniphy2_sys_clk = { + .halt_reg = 0x17068, + .clkr = { + .enable_reg = 0x17068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_uniphy2_sys_clk", + .parent_hws = (const struct clk_hw *[]) { + &uniphy_sys_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cmn_12gpll_sys_clk = { + .halt_reg = 0x3a008, + .clkr = { + .enable_reg = 0x3a008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cmn_12gpll_sys_clk", + .parent_hws = (const struct clk_hw *[]) { + &uniphy_sys_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_fixed_factor gcc_xo_div4_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data) { + .name = "gcc_xo_div4_clk_src", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_branch gcc_nssnoc_qosgen_ref_clk = { + .halt_reg = 0x1701c, + .clkr = { + .enable_reg = 0x1701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_qosgen_ref_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_div4_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_nssnoc_timeout_ref_clk = { + .halt_reg = 0x17020, + .clkr = { + .enable_reg = 0x17020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_nssnoc_timeout_ref_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_div4_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_div4_clk = { + .halt_reg = 0x3401c, + .clkr = { + .enable_reg = 0x3401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_xo_div4_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_xo_div4_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_hw *gcc_ipq9574_hws[] = { + &gpll0_out_main_div2.hw, + &gcc_xo_div4_clk_src.hw, + &qdss_dap_sync_clk_src.hw, + &qdss_tsctr_div2_clk_src.hw, + &qdss_tsctr_div8_clk_src.hw, + &qdss_tsctr_div16_clk_src.hw, + &qdss_tsctr_div3_clk_src.hw, + &gcc_eud_at_div_clk_src.hw, +}; + +static struct clk_regmap *gcc_ipq9574_clks[] = { + [GPLL0_MAIN] = &gpll0_main.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL4_MAIN] = &gpll4_main.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL2_MAIN] = &gpll2_main.clkr, + [GPLL2] = &gpll2.clkr, + [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr, + [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, + [APSS_AXI_CLK_SRC] = &apss_axi_clk_src.clkr, + [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, + [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr, + [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr, + [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr, + [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr, + [BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr, + [BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr, + [BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr, + [BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr, + [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr, + [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr, + [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr, + [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr, + [GCC_APSS_AXI_CLK] = &gcc_apss_axi_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr, + [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr, + [GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr, + [GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr, + [PCIE0_AXI_M_CLK_SRC] = &pcie0_axi_m_clk_src.clkr, + [GCC_PCIE0_AXI_M_CLK] = &gcc_pcie0_axi_m_clk.clkr, + [PCIE1_AXI_M_CLK_SRC] = &pcie1_axi_m_clk_src.clkr, + [GCC_PCIE1_AXI_M_CLK] = &gcc_pcie1_axi_m_clk.clkr, + [PCIE2_AXI_M_CLK_SRC] = &pcie2_axi_m_clk_src.clkr, + [GCC_PCIE2_AXI_M_CLK] = &gcc_pcie2_axi_m_clk.clkr, + [PCIE3_AXI_M_CLK_SRC] = &pcie3_axi_m_clk_src.clkr, + [GCC_PCIE3_AXI_M_CLK] = &gcc_pcie3_axi_m_clk.clkr, + [PCIE0_AXI_S_CLK_SRC] = &pcie0_axi_s_clk_src.clkr, + [GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr, + [GCC_PCIE0_AXI_S_CLK] = &gcc_pcie0_axi_s_clk.clkr, + [PCIE1_AXI_S_CLK_SRC] = &pcie1_axi_s_clk_src.clkr, + [GCC_PCIE1_AXI_S_BRIDGE_CLK] = &gcc_pcie1_axi_s_bridge_clk.clkr, + [GCC_PCIE1_AXI_S_CLK] = &gcc_pcie1_axi_s_clk.clkr, + [PCIE2_AXI_S_CLK_SRC] = &pcie2_axi_s_clk_src.clkr, + [GCC_PCIE2_AXI_S_BRIDGE_CLK] = &gcc_pcie2_axi_s_bridge_clk.clkr, + [GCC_PCIE2_AXI_S_CLK] = &gcc_pcie2_axi_s_clk.clkr, + [PCIE3_AXI_S_CLK_SRC] = &pcie3_axi_s_clk_src.clkr, + [GCC_PCIE3_AXI_S_BRIDGE_CLK] = &gcc_pcie3_axi_s_bridge_clk.clkr, + [GCC_PCIE3_AXI_S_CLK] = &gcc_pcie3_axi_s_clk.clkr, + [PCIE0_PIPE_CLK_SRC] = &pcie0_pipe_clk_src.clkr, + [PCIE1_PIPE_CLK_SRC] = &pcie1_pipe_clk_src.clkr, + [PCIE2_PIPE_CLK_SRC] = &pcie2_pipe_clk_src.clkr, + [PCIE3_PIPE_CLK_SRC] = &pcie3_pipe_clk_src.clkr, + [PCIE_AUX_CLK_SRC] = &pcie_aux_clk_src.clkr, + [GCC_PCIE0_AUX_CLK] = &gcc_pcie0_aux_clk.clkr, + [GCC_PCIE1_AUX_CLK] = &gcc_pcie1_aux_clk.clkr, + [GCC_PCIE2_AUX_CLK] = &gcc_pcie2_aux_clk.clkr, + [GCC_PCIE3_AUX_CLK] = &gcc_pcie3_aux_clk.clkr, + [PCIE0_RCHNG_CLK_SRC] = &pcie0_rchng_clk_src.clkr, + [GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr, + [PCIE1_RCHNG_CLK_SRC] = &pcie1_rchng_clk_src.clkr, + [GCC_PCIE1_RCHNG_CLK] = &gcc_pcie1_rchng_clk.clkr, + [PCIE2_RCHNG_CLK_SRC] = &pcie2_rchng_clk_src.clkr, + [GCC_PCIE2_RCHNG_CLK] = &gcc_pcie2_rchng_clk.clkr, + [PCIE3_RCHNG_CLK_SRC] = &pcie3_rchng_clk_src.clkr, + [GCC_PCIE3_RCHNG_CLK] = &gcc_pcie3_rchng_clk.clkr, + [GCC_PCIE0_AHB_CLK] = &gcc_pcie0_ahb_clk.clkr, + [GCC_PCIE1_AHB_CLK] = &gcc_pcie1_ahb_clk.clkr, + [GCC_PCIE2_AHB_CLK] = &gcc_pcie2_ahb_clk.clkr, + [GCC_PCIE3_AHB_CLK] = &gcc_pcie3_ahb_clk.clkr, + [USB0_AUX_CLK_SRC] = &usb0_aux_clk_src.clkr, + [GCC_USB0_AUX_CLK] = &gcc_usb0_aux_clk.clkr, + [USB0_MASTER_CLK_SRC] = &usb0_master_clk_src.clkr, + [GCC_USB0_MASTER_CLK] = &gcc_usb0_master_clk.clkr, + [GCC_SNOC_USB_CLK] = &gcc_snoc_usb_clk.clkr, + [GCC_ANOC_USB_AXI_CLK] = &gcc_anoc_usb_axi_clk.clkr, + [USB0_MOCK_UTMI_CLK_SRC] = &usb0_mock_utmi_clk_src.clkr, + [USB0_MOCK_UTMI_DIV_CLK_SRC] = &usb0_mock_utmi_div_clk_src.clkr, + [GCC_USB0_MOCK_UTMI_CLK] = &gcc_usb0_mock_utmi_clk.clkr, + [USB0_PIPE_CLK_SRC] = &usb0_pipe_clk_src.clkr, + [GCC_USB0_PHY_CFG_AHB_CLK] = &gcc_usb0_phy_cfg_ahb_clk.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr, + [GCC_NSSCFG_CLK] = &gcc_nsscfg_clk.clkr, + [GCC_NSSNOC_NSSCC_CLK] = &gcc_nssnoc_nsscc_clk.clkr, + [GCC_NSSCC_CLK] = &gcc_nsscc_clk.clkr, + [GCC_NSSNOC_PCNOC_1_CLK] = &gcc_nssnoc_pcnoc_1_clk.clkr, + [GCC_QDSS_DAP_AHB_CLK] = &gcc_qdss_dap_ahb_clk.clkr, + [GCC_QDSS_CFG_AHB_CLK] = &gcc_qdss_cfg_ahb_clk.clkr, + [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, + [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_MDIO_AHB_CLK] = &gcc_mdio_ahb_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_UNIPHY0_AHB_CLK] = &gcc_uniphy0_ahb_clk.clkr, + [GCC_UNIPHY1_AHB_CLK] = &gcc_uniphy1_ahb_clk.clkr, + [GCC_UNIPHY2_AHB_CLK] = &gcc_uniphy2_ahb_clk.clkr, + [GCC_CMN_12GPLL_AHB_CLK] = &gcc_cmn_12gpll_ahb_clk.clkr, + [GCC_CMN_12GPLL_APU_CLK] = &gcc_cmn_12gpll_apu_clk.clkr, + [SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr, + [GCC_NSSNOC_SNOC_CLK] = &gcc_nssnoc_snoc_clk.clkr, + [GCC_NSSNOC_SNOC_1_CLK] = &gcc_nssnoc_snoc_1_clk.clkr, + [GCC_QDSS_ETR_USB_CLK] = &gcc_qdss_etr_usb_clk.clkr, + [WCSS_AHB_CLK_SRC] = &wcss_ahb_clk_src.clkr, + [GCC_Q6_AHB_CLK] = &gcc_q6_ahb_clk.clkr, + [GCC_Q6_AHB_S_CLK] = &gcc_q6_ahb_s_clk.clkr, + [GCC_WCSS_ECAHB_CLK] = &gcc_wcss_ecahb_clk.clkr, + [GCC_WCSS_ACMT_CLK] = &gcc_wcss_acmt_clk.clkr, + [GCC_SYS_NOC_WCSS_AHB_CLK] = &gcc_sys_noc_wcss_ahb_clk.clkr, + [WCSS_AXI_M_CLK_SRC] = &wcss_axi_m_clk_src.clkr, + [GCC_ANOC_WCSS_AXI_M_CLK] = &gcc_anoc_wcss_axi_m_clk.clkr, + [QDSS_AT_CLK_SRC] = &qdss_at_clk_src.clkr, + [GCC_Q6SS_ATBM_CLK] = &gcc_q6ss_atbm_clk.clkr, + [GCC_WCSS_DBG_IFC_ATB_CLK] = &gcc_wcss_dbg_ifc_atb_clk.clkr, + [GCC_NSSNOC_ATB_CLK] = &gcc_nssnoc_atb_clk.clkr, + [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr, + [GCC_SYS_NOC_AT_CLK] = &gcc_sys_noc_at_clk.clkr, + [GCC_PCNOC_AT_CLK] = &gcc_pcnoc_at_clk.clkr, + [GCC_USB0_EUD_AT_CLK] = &gcc_usb0_eud_at_clk.clkr, + [GCC_QDSS_EUD_AT_CLK] = &gcc_qdss_eud_at_clk.clkr, + [QDSS_STM_CLK_SRC] = &qdss_stm_clk_src.clkr, + [GCC_QDSS_STM_CLK] = &gcc_qdss_stm_clk.clkr, + [GCC_SYS_NOC_QDSS_STM_AXI_CLK] = &gcc_sys_noc_qdss_stm_axi_clk.clkr, + [QDSS_TRACECLKIN_CLK_SRC] = &qdss_traceclkin_clk_src.clkr, + [GCC_QDSS_TRACECLKIN_CLK] = &gcc_qdss_traceclkin_clk.clkr, + [QDSS_TSCTR_CLK_SRC] = &qdss_tsctr_clk_src.clkr, + [GCC_Q6_TSCTR_1TO2_CLK] = &gcc_q6_tsctr_1to2_clk.clkr, + [GCC_WCSS_DBG_IFC_NTS_CLK] = &gcc_wcss_dbg_ifc_nts_clk.clkr, + [GCC_QDSS_TSCTR_DIV2_CLK] = &gcc_qdss_tsctr_div2_clk.clkr, + [GCC_QDSS_TS_CLK] = &gcc_qdss_ts_clk.clkr, + [GCC_QDSS_TSCTR_DIV4_CLK] = &gcc_qdss_tsctr_div4_clk.clkr, + [GCC_NSS_TS_CLK] = &gcc_nss_ts_clk.clkr, + [GCC_QDSS_TSCTR_DIV8_CLK] = &gcc_qdss_tsctr_div8_clk.clkr, + [GCC_QDSS_TSCTR_DIV16_CLK] = &gcc_qdss_tsctr_div16_clk.clkr, + [GCC_Q6SS_PCLKDBG_CLK] = &gcc_q6ss_pclkdbg_clk.clkr, + [GCC_Q6SS_TRIG_CLK] = &gcc_q6ss_trig_clk.clkr, + [GCC_WCSS_DBG_IFC_APB_CLK] = &gcc_wcss_dbg_ifc_apb_clk.clkr, + [GCC_WCSS_DBG_IFC_DAPBUS_CLK] = &gcc_wcss_dbg_ifc_dapbus_clk.clkr, + [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, + [GCC_QDSS_APB2JTAG_CLK] = &gcc_qdss_apb2jtag_clk.clkr, + [GCC_QDSS_TSCTR_DIV3_CLK] = &gcc_qdss_tsctr_div3_clk.clkr, + [QPIC_IO_MACRO_CLK_SRC] = &qpic_io_macro_clk_src.clkr, + [GCC_QPIC_IO_MACRO_CLK] = &gcc_qpic_io_macro_clk.clkr, + [Q6_AXI_CLK_SRC] = &q6_axi_clk_src.clkr, + [GCC_Q6_AXIM_CLK] = &gcc_q6_axim_clk.clkr, + [GCC_WCSS_Q6_TBU_CLK] = &gcc_wcss_q6_tbu_clk.clkr, + [GCC_MEM_NOC_Q6_AXI_CLK] = &gcc_mem_noc_q6_axi_clk.clkr, + [Q6_AXIM2_CLK_SRC] = &q6_axim2_clk_src.clkr, + [NSSNOC_MEMNOC_BFDCD_CLK_SRC] = &nssnoc_memnoc_bfdcd_clk_src.clkr, + [GCC_NSSNOC_MEMNOC_CLK] = &gcc_nssnoc_memnoc_clk.clkr, + [GCC_NSSNOC_MEM_NOC_1_CLK] = &gcc_nssnoc_mem_noc_1_clk.clkr, + [GCC_NSS_TBU_CLK] = &gcc_nss_tbu_clk.clkr, + [GCC_MEM_NOC_NSSNOC_CLK] = &gcc_mem_noc_nssnoc_clk.clkr, + [LPASS_AXIM_CLK_SRC] = &lpass_axim_clk_src.clkr, + [LPASS_SWAY_CLK_SRC] = &lpass_sway_clk_src.clkr, + [ADSS_PWM_CLK_SRC] = &adss_pwm_clk_src.clkr, + [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [GCC_XO_CLK_SRC] = &gcc_xo_clk_src.clkr, + [GCC_NSSNOC_XO_DCD_CLK] = &gcc_nssnoc_xo_dcd_clk.clkr, + [GCC_XO_CLK] = &gcc_xo_clk.clkr, + [GCC_NSSNOC_QOSGEN_REF_CLK] = &gcc_nssnoc_qosgen_ref_clk.clkr, + [GCC_NSSNOC_TIMEOUT_REF_CLK] = &gcc_nssnoc_timeout_ref_clk.clkr, + [GCC_XO_DIV4_CLK] = &gcc_xo_div4_clk.clkr, + [GCC_UNIPHY0_SYS_CLK] = &gcc_uniphy0_sys_clk.clkr, + [GCC_UNIPHY1_SYS_CLK] = &gcc_uniphy1_sys_clk.clkr, + [GCC_UNIPHY2_SYS_CLK] = &gcc_uniphy2_sys_clk.clkr, + [GCC_CMN_12GPLL_SYS_CLK] = &gcc_cmn_12gpll_sys_clk.clkr, + [GCC_Q6SS_BOOT_CLK] = &gcc_q6ss_boot_clk.clkr, + [UNIPHY_SYS_CLK_SRC] = &uniphy_sys_clk_src.clkr, + [NSS_TS_CLK_SRC] = &nss_ts_clk_src.clkr, + [GCC_ANOC_PCIE0_1LANE_M_CLK] = &gcc_anoc_pcie0_1lane_m_clk.clkr, + [GCC_ANOC_PCIE1_1LANE_M_CLK] = &gcc_anoc_pcie1_1lane_m_clk.clkr, + [GCC_ANOC_PCIE2_2LANE_M_CLK] = &gcc_anoc_pcie2_2lane_m_clk.clkr, + [GCC_ANOC_PCIE3_2LANE_M_CLK] = &gcc_anoc_pcie3_2lane_m_clk.clkr, + [GCC_SNOC_PCIE0_1LANE_S_CLK] = &gcc_snoc_pcie0_1lane_s_clk.clkr, + [GCC_SNOC_PCIE1_1LANE_S_CLK] = &gcc_snoc_pcie1_1lane_s_clk.clkr, + [GCC_SNOC_PCIE2_2LANE_S_CLK] = &gcc_snoc_pcie2_2lane_s_clk.clkr, + [GCC_SNOC_PCIE3_2LANE_S_CLK] = &gcc_snoc_pcie3_2lane_s_clk.clkr, +}; + +static const struct qcom_reset_map gcc_ipq9574_resets[] = { + [GCC_ADSS_BCR] = { 0x1c000, 0 }, + [GCC_ANOC0_TBU_BCR] = { 0x1203c, 0 }, + [GCC_ANOC1_TBU_BCR] = { 0x1204c, 0 }, + [GCC_ANOC_BCR] = { 0x2e074, 0 }, + [GCC_APC0_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x38000, 0 }, + [GCC_APSS_TCU_BCR] = { 0x12014, 0 }, + [GCC_BLSP1_BCR] = { 0x01000, 0 }, + [GCC_BLSP1_QUP1_BCR] = { 0x02000, 0 }, + [GCC_BLSP1_QUP2_BCR] = { 0x03000, 0 }, + [GCC_BLSP1_QUP3_BCR] = { 0x04000, 0 }, + [GCC_BLSP1_QUP4_BCR] = { 0x05000, 0 }, + [GCC_BLSP1_QUP5_BCR] = { 0x06000, 0 }, + [GCC_BLSP1_QUP6_BCR] = { 0x07000, 0 }, + [GCC_BLSP1_UART1_BCR] = { 0x02028, 0 }, + [GCC_BLSP1_UART2_BCR] = { 0x03028, 0 }, + [GCC_BLSP1_UART3_BCR] = { 0x04028, 0 }, + [GCC_BLSP1_UART4_BCR] = { 0x05028, 0 }, + [GCC_BLSP1_UART5_BCR] = { 0x06028, 0 }, + [GCC_BLSP1_UART6_BCR] = { 0x07028, 0 }, + [GCC_BOOT_ROM_BCR] = { 0x13028, 0 }, + [GCC_CMN_BLK_BCR] = { 0x3a000, 0 }, + [GCC_CMN_BLK_AHB_ARES] = { 0x3a010, 0 }, + [GCC_CMN_BLK_SYS_ARES] = { 0x3a010, 1 }, + [GCC_CMN_BLK_APU_ARES] = { 0x3a010, 2 }, + [GCC_DCC_BCR] = { 0x35000, 0 }, + [GCC_DDRSS_BCR] = { 0x11000, 0 }, + [GCC_IMEM_BCR] = { 0x0e000, 0 }, + [GCC_LPASS_BCR] = { 0x27000, 0 }, + [GCC_MDIO_BCR] = { 0x1703c, 0 }, + [GCC_MPM_BCR] = { 0x37000, 0 }, + [GCC_MSG_RAM_BCR] = { 0x26000, 0 }, + [GCC_NSS_BCR] = { 0x17000, 0 }, + [GCC_NSS_TBU_BCR] = { 0x12044, 0 }, + [GCC_NSSNOC_MEMNOC_1_ARES] = { 0x17038, 13 }, + [GCC_NSSNOC_PCNOC_1_ARES] = { 0x17038, 12 }, + [GCC_NSSNOC_SNOC_1_ARES] = { 0x17038, 11 }, + [GCC_NSSNOC_XO_DCD_ARES] = { 0x17038, 10 }, + [GCC_NSSNOC_TS_ARES] = { 0x17038, 9 }, + [GCC_NSSCC_ARES] = { 0x17038, 8 }, + [GCC_NSSNOC_NSSCC_ARES] = { 0x17038, 7 }, + [GCC_NSSNOC_ATB_ARES] = { 0x17038, 6 }, + [GCC_NSSNOC_MEMNOC_ARES] = { 0x17038, 5 }, + [GCC_NSSNOC_QOSGEN_REF_ARES] = { 0x17038, 4 }, + [GCC_NSSNOC_SNOC_ARES] = { 0x17038, 3 }, + [GCC_NSSNOC_TIMEOUT_REF_ARES] = { 0x17038, 2 }, + [GCC_NSS_CFG_ARES] = { 0x17038, 1 }, + [GCC_UBI0_DBG_ARES] = { 0x17038, 0 }, + [GCC_PCIE0PHY_PHY_BCR] = { 0x2805c, 0 }, + [GCC_PCIE0_AHB_ARES] = { 0x28058, 7 }, + [GCC_PCIE0_AUX_ARES] = { 0x28058, 6 }, + [GCC_PCIE0_AXI_M_ARES] = { 0x28058, 5 }, + [GCC_PCIE0_AXI_M_STICKY_ARES] = { 0x28058, 4 }, + [GCC_PCIE0_AXI_S_ARES] = { 0x28058, 3 }, + [GCC_PCIE0_AXI_S_STICKY_ARES] = { 0x28058, 2 }, + [GCC_PCIE0_CORE_STICKY_ARES] = { 0x28058, 1 }, + [GCC_PCIE0_PIPE_ARES] = { 0x28058, 0 }, + [GCC_PCIE1_AHB_ARES] = { 0x29058, 7 }, + [GCC_PCIE1_AUX_ARES] = { 0x29058, 6 }, + [GCC_PCIE1_AXI_M_ARES] = { 0x29058, 5 }, + [GCC_PCIE1_AXI_M_STICKY_ARES] = { 0x29058, 4 }, + [GCC_PCIE1_AXI_S_ARES] = { 0x29058, 3 }, + [GCC_PCIE1_AXI_S_STICKY_ARES] = { 0x29058, 2 }, + [GCC_PCIE1_CORE_STICKY_ARES] = { 0x29058, 1 }, + [GCC_PCIE1_PIPE_ARES] = { 0x29058, 0 }, + [GCC_PCIE2_AHB_ARES] = { 0x2a058, 7 }, + [GCC_PCIE2_AUX_ARES] = { 0x2a058, 6 }, + [GCC_PCIE2_AXI_M_ARES] = { 0x2a058, 5 }, + [GCC_PCIE2_AXI_M_STICKY_ARES] = { 0x2a058, 4 }, + [GCC_PCIE2_AXI_S_ARES] = { 0x2a058, 3 }, + [GCC_PCIE2_AXI_S_STICKY_ARES] = { 0x2a058, 2 }, + [GCC_PCIE2_CORE_STICKY_ARES] = { 0x2a058, 1 }, + [GCC_PCIE2_PIPE_ARES] = { 0x2a058, 0 }, + [GCC_PCIE3_AHB_ARES] = { 0x2b058, 7 }, + [GCC_PCIE3_AUX_ARES] = { 0x2b058, 6 }, + [GCC_PCIE3_AXI_M_ARES] = { 0x2b058, 5 }, + [GCC_PCIE3_AXI_M_STICKY_ARES] = { 0x2b058, 4 }, + [GCC_PCIE3_AXI_S_ARES] = { 0x2b058, 3 }, + [GCC_PCIE3_AXI_S_STICKY_ARES] = { 0x2b058, 2 }, + [GCC_PCIE3_CORE_STICKY_ARES] = { 0x2b058, 1 }, + [GCC_PCIE3_PIPE_ARES] = { 0x2b058, 0 }, + [GCC_PCIE0_BCR] = { 0x28000, 0 }, + [GCC_PCIE0_LINK_DOWN_BCR] = { 0x28054, 0 }, + [GCC_PCIE0_PHY_BCR] = { 0x28060, 0 }, + [GCC_PCIE1_BCR] = { 0x29000, 0 }, + [GCC_PCIE1_LINK_DOWN_BCR] = { 0x29054, 0 }, + [GCC_PCIE1_PHY_BCR] = { 0x29060, 0 }, + [GCC_PCIE1PHY_PHY_BCR] = { 0x2905c, 0 }, + [GCC_PCIE2_BCR] = { 0x2a000, 0 }, + [GCC_PCIE2_LINK_DOWN_BCR] = { 0x2a054, 0 }, + [GCC_PCIE2_PHY_BCR] = { 0x2a060, 0 }, + [GCC_PCIE2PHY_PHY_BCR] = { 0x2a05c, 0 }, + [GCC_PCIE3_BCR] = { 0x2b000, 0 }, + [GCC_PCIE3_LINK_DOWN_BCR] = { 0x2b054, 0 }, + [GCC_PCIE3PHY_PHY_BCR] = { 0x2b05c, 0 }, + [GCC_PCIE3_PHY_BCR] = { 0x2b060, 0 }, + [GCC_PCNOC_BCR] = { 0x31000, 0 }, + [GCC_PCNOC_BUS_TIMEOUT0_BCR] = { 0x31030, 0 }, + [GCC_PCNOC_BUS_TIMEOUT1_BCR] = { 0x31038, 0 }, + [GCC_PCNOC_BUS_TIMEOUT2_BCR] = { 0x31040, 0 }, + [GCC_PCNOC_BUS_TIMEOUT3_BCR] = { 0x31048, 0 }, + [GCC_PCNOC_BUS_TIMEOUT4_BCR] = { 0x31050, 0 }, + [GCC_PCNOC_BUS_TIMEOUT5_BCR] = { 0x31058, 0 }, + [GCC_PCNOC_BUS_TIMEOUT6_BCR] = { 0x31060, 0 }, + [GCC_PCNOC_BUS_TIMEOUT7_BCR] = { 0x31068, 0 }, + [GCC_PCNOC_BUS_TIMEOUT8_BCR] = { 0x31070, 0 }, + [GCC_PCNOC_BUS_TIMEOUT9_BCR] = { 0x31078, 0 }, + [GCC_PCNOC_TBU_BCR] = { 0x12034, 0 }, + [GCC_PRNG_BCR] = { 0x13020, 0 }, + [GCC_Q6SS_DBG_ARES] = { 0x2506c, 4 }, + [GCC_Q6_AHB_ARES] = { 0x2506c, 3 }, + [GCC_Q6_AHB_S_ARES] = { 0x2506c, 2 }, + [GCC_Q6_AXIM2_ARES] = { 0x2506c, 1 }, + [GCC_Q6_AXIM_ARES] = { 0x2506c, 0 }, + [GCC_QDSS_BCR] = { 0x2d000, 0 }, + [GCC_QPIC_BCR] = { 0x32000, 0 }, + [GCC_QPIC_AHB_ARES] = { 0x3201c, 1 }, + [GCC_QPIC_ARES] = { 0x3201c, 0 }, + [GCC_QUSB2_0_PHY_BCR] = { 0x2c068, 0 }, + [GCC_RBCPR_BCR] = { 0x39000, 0 }, + [GCC_RBCPR_MX_BCR] = { 0x39014, 0 }, + [GCC_SDCC_BCR] = { 0x33000, 0 }, + [GCC_SEC_CTRL_BCR] = { 0x1a000, 0 }, + [GCC_SMMU_CFG_BCR] = { 0x1202c, 0 }, + [GCC_SNOC_BCR] = { 0x2e000, 0 }, + [GCC_SPDM_BCR] = { 0x36000, 0 }, + [GCC_TCSR_BCR] = { 0x3d000, 0 }, + [GCC_TLMM_BCR] = { 0x3e000, 0 }, + [GCC_TME_BCR] = { 0x10000, 0 }, + [GCC_UNIPHY0_BCR] = { 0x17044, 0 }, + [GCC_UNIPHY0_SYS_RESET] = { 0x17050, 0 }, + [GCC_UNIPHY0_AHB_RESET] = { 0x17050, 1 }, + [GCC_UNIPHY0_XPCS_RESET] = { 0x17050, 2 }, + [GCC_UNIPHY1_SYS_RESET] = { 0x17060, 0 }, + [GCC_UNIPHY1_AHB_RESET] = { 0x17060, 1 }, + [GCC_UNIPHY1_XPCS_RESET] = { 0x17060, 2 }, + [GCC_UNIPHY2_SYS_RESET] = { 0x17070, 0 }, + [GCC_UNIPHY2_AHB_RESET] = { 0x17070, 1 }, + [GCC_UNIPHY2_XPCS_RESET] = { 0x17070, 2 }, + [GCC_UNIPHY1_BCR] = { 0x17054, 0 }, + [GCC_UNIPHY2_BCR] = { 0x17064, 0 }, + [GCC_USB0_PHY_BCR] = { 0x2c06c, 0 }, + [GCC_USB3PHY_0_PHY_BCR] = { 0x2c070, 0 }, + [GCC_USB_BCR] = { 0x2c000, 0 }, + [GCC_USB_MISC_RESET] = { 0x2c064, 0 }, + [GCC_WCSSAON_RESET] = { 0x25074, 0 }, + [GCC_WCSS_ACMT_ARES] = { 0x25070, 5 }, + [GCC_WCSS_AHB_S_ARES] = { 0x25070, 4 }, + [GCC_WCSS_AXI_M_ARES] = { 0x25070, 3 }, + [GCC_WCSS_BCR] = { 0x18004, 0 }, + [GCC_WCSS_DBG_ARES] = { 0x25070, 2 }, + [GCC_WCSS_DBG_BDG_ARES] = { 0x25070, 1 }, + [GCC_WCSS_ECAHB_ARES] = { 0x25070, 0 }, + [GCC_WCSS_Q6_BCR] = { 0x18000, 0 }, + [GCC_WCSS_Q6_TBU_BCR] = { 0x12054, 0 }, +}; + +static const struct of_device_id gcc_ipq9574_match_table[] = { + { .compatible = "qcom,ipq9574-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_ipq9574_match_table); + +static const struct regmap_config gcc_ipq9574_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x7fffc, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_ipq9574_desc = { + .config = &gcc_ipq9574_regmap_config, + .clks = gcc_ipq9574_clks, + .num_clks = ARRAY_SIZE(gcc_ipq9574_clks), + .resets = gcc_ipq9574_resets, + .num_resets = ARRAY_SIZE(gcc_ipq9574_resets), + .clk_hws = gcc_ipq9574_hws, + .num_clk_hws = ARRAY_SIZE(gcc_ipq9574_hws), +}; + +static int gcc_ipq9574_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_ipq9574_desc); +} + +static struct platform_driver gcc_ipq9574_driver = { + .probe = gcc_ipq9574_probe, + .driver = { + .name = "qcom,gcc-ipq9574", + .of_match_table = gcc_ipq9574_match_table, + }, +}; + +static int __init gcc_ipq9574_init(void) +{ + return platform_driver_register(&gcc_ipq9574_driver); +} +core_initcall(gcc_ipq9574_init); + +static void __exit gcc_ipq9574_exit(void) +{ + platform_driver_unregister(&gcc_ipq9574_driver); +} +module_exit(gcc_ipq9574_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. GCC IPQ9574 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-msm8917.c b/drivers/clk/qcom/gcc-msm8917.c new file mode 100644 index 000000000000..a4c33a2ce61c --- /dev/null +++ b/drivers/clk/qcom/gcc-msm8917.c @@ -0,0 +1,3303 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Otto Pflüger + * + * Based on gcc-msm8953.c: + * Copyright 2021, The Linux Foundation. All rights reserved. + * with parts taken from gcc-qcs404.c: + * Copyright 2018, The Linux Foundation. All rights reserved. + * and gcc-msm8939.c: + * Copyright 2020 Linaro Limited + * adapted with data from clock-gcc-8952.c in Qualcomm's msm-4.9 release: + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_XO, + DT_SLEEP_CLK, + DT_DSI0PLL, + DT_DSI0PLL_BYTE, +}; + +enum { + P_XO, + P_SLEEP_CLK, + P_GPLL0, + P_GPLL3, + P_GPLL4, + P_GPLL6, + P_DSI0PLL, + P_DSI0PLL_BYTE, +}; + +static struct clk_alpha_pll gpll0_sleep_clk_src = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x45008, + .enable_mask = BIT(23), + .enable_is_inverted = true, + .hw.init = &(struct clk_init_data){ + .name = "gpll0_sleep_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll0_early = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gpll0_early", + .parent_hws = (const struct clk_hw*[]){ + &gpll0_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll0 = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0", + .parent_hws = (const struct clk_hw*[]){ + &gpll0_early.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static const struct pll_vco gpll3_p_vco[] = { + { 700000000, 1400000000, 0 }, +}; + +static const struct alpha_pll_config gpll3_early_config = { + .l = 63, + .config_ctl_val = 0x4001055b, + .early_output_mask = 0, + .post_div_mask = GENMASK(11, 8), + .post_div_val = BIT(8), +}; + +static struct clk_alpha_pll gpll3_early = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .vco_table = gpll3_p_vco, + .num_vco = ARRAY_SIZE(gpll3_p_vco), + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpll3_early", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll3 = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll3", + .parent_hws = (const struct clk_hw*[]){ + &gpll3_early.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ops, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_alpha_pll gpll4_early = { + .offset = 0x24000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gpll4_early", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x24000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_hws = (const struct clk_hw*[]){ + &gpll4_early.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_pll gpll6_early = { + .l_reg = 0x37004, + .m_reg = 0x37008, + .n_reg = 0x3700c, + .config_reg = 0x37014, + .mode_reg = 0x37000, + .status_reg = 0x3701c, + .status_bit = 17, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll6_early", + .parent_data = &(const struct clk_parent_data) { + .index = DT_XO, + }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap gpll6 = { + .enable_reg = 0x45000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll6", + .parent_hws = (const struct clk_hw*[]){ + &gpll6_early.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static const struct parent_map gcc_xo_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, +}; + +static const struct parent_map gcc_xo_gpll0_out_aux_map[] = { + { P_XO, 0 }, + { P_GPLL0, 2 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll6_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll6_sleep_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll6.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_xo_gpll0_gpll6_gpll4_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 2 }, + { P_GPLL4, 3 }, +}; + +static const struct clk_parent_data gcc_xo_gpll0_gpll6_gpll4_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll6.hw }, + { .hw = &gpll4.clkr.hw }, +}; + +static const struct freq_tbl ftbl_apss_ahb_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133330000, P_GPLL0, 6, 0, 0), + { } +}; + +static struct clk_rcg2 apss_ahb_clk_src = { + .cmd_rcgr = 0x46000, + .hid_width = 5, + .freq_tbl = ftbl_apss_ahb_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apss_ahb_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_blsp_i2c_apps_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x03000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x04000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup3_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x05000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup4_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x0c00c, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup1_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x0d000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup2_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x0f000, + .hid_width = 5, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup3_i2c_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_blsp_spi_apps_clk_src[] = { + F(960000, P_XO, 10, 1, 2), + F(4800000, P_XO, 4, 0, 0), + F(9600000, P_XO, 2, 0, 0), + F(16000000, P_GPLL0, 10, 1, 5), + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0, 16, 1, 2), + F(50000000, P_GPLL0, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x03014, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x04024, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup3_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x05024, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_qup4_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x0c024, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup1_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x0d014, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup2_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x0f024, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_blsp_spi_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_qup3_spi_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_blsp_uart_apps_clk_src[] = { + F(3686400, P_GPLL0, 1, 72, 15625), + F(7372800, P_GPLL0, 1, 144, 15625), + F(14745600, P_GPLL0, 1, 288, 15625), + F(16000000, P_GPLL0, 10, 1, 5), + F(19200000, P_XO, 1, 0, 0), + F(24000000, P_GPLL0, 1, 3, 100), + F(25000000, P_GPLL0, 16, 1, 2), + F(32000000, P_GPLL0, 1, 1, 25), + F(40000000, P_GPLL0, 1, 1, 20), + F(46400000, P_GPLL0, 1, 29, 500), + F(48000000, P_GPLL0, 1, 3, 50), + F(51200000, P_GPLL0, 1, 8, 125), + F(56000000, P_GPLL0, 1, 7, 100), + F(58982400, P_GPLL0, 1, 1152, 15625), + F(60000000, P_GPLL0, 1, 3, 40), + F(64000000, P_GPLL0, 1, 2, 25), + { } +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x02044, + .hid_width = 5, + .mnd_width = 16, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart1_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x03034, + .hid_width = 5, + .mnd_width = 16, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp1_uart2_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_uart1_apps_clk_src = { + .cmd_rcgr = 0x0c044, + .hid_width = 5, + .mnd_width = 16, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_uart1_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 blsp2_uart2_apps_clk_src = { + .cmd_rcgr = 0x0d034, + .hid_width = 5, + .mnd_width = 16, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "blsp2_uart2_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct parent_map gcc_byte0_map[] = { + { P_XO, 0 }, + { P_DSI0PLL_BYTE, 1 }, +}; + +static const struct clk_parent_data gcc_byte_data[] = { + { .index = DT_XO }, + { .index = DT_DSI0PLL_BYTE }, +}; + +static struct clk_rcg2 byte0_clk_src = { + .cmd_rcgr = 0x4d044, + .hid_width = 5, + .parent_map = gcc_byte0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "byte0_clk_src", + .parent_data = gcc_byte_data, + .num_parents = ARRAY_SIZE(gcc_byte_data), + .ops = &clk_byte2_ops, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static const struct freq_tbl ftbl_camss_gp_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 camss_gp0_clk_src = { + .cmd_rcgr = 0x54000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_camss_gp_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "camss_gp0_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 camss_gp1_clk_src = { + .cmd_rcgr = 0x55000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_camss_gp_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "camss_gp1_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_camss_top_ahb_clk_src[] = { + F(40000000, P_GPLL0, 10, 1, 2), + F(61540000, P_GPLL0, 13, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + { } +}; + +static struct clk_rcg2 camss_top_ahb_clk_src = { + .cmd_rcgr = 0x5a000, + .hid_width = 5, + .freq_tbl = ftbl_camss_top_ahb_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "camss_top_ahb_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_cci_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(37500000, P_GPLL0, 1, 3, 64), + { } +}; + +static struct clk_rcg2 cci_clk_src = { + .cmd_rcgr = 0x51000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_cci_clk_src, + .parent_map = gcc_xo_gpll0_out_aux_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "cci_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct parent_map gcc_cpp_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL6, 3 }, +}; + +static const struct clk_parent_data gcc_cpp_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll6.hw }, +}; + +static const struct freq_tbl ftbl_cpp_clk_src[] = { + F(133330000, P_GPLL0, 6, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(308570000, P_GPLL0, 3.5, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cpp_clk_src = { + .cmd_rcgr = 0x58018, + .hid_width = 5, + .freq_tbl = ftbl_cpp_clk_src, + .parent_map = gcc_cpp_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "cpp_clk_src", + .parent_data = gcc_cpp_data, + .num_parents = ARRAY_SIZE(gcc_cpp_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_crypto_clk_src[] = { + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + { } +}; + +static struct clk_rcg2 crypto_clk_src = { + .cmd_rcgr = 0x16004, + .hid_width = 5, + .freq_tbl = ftbl_crypto_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "crypto_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_csi_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 csi0_clk_src = { + .cmd_rcgr = 0x4e020, + .hid_width = 5, + .freq_tbl = ftbl_csi_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "csi0_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 csi1_clk_src = { + .cmd_rcgr = 0x4f020, + .hid_width = 5, + .freq_tbl = ftbl_csi_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "csi1_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 csi2_clk_src = { + .cmd_rcgr = 0x3c020, + .hid_width = 5, + .freq_tbl = ftbl_csi_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "csi2_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_csi_phytimer_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 csi0phytimer_clk_src = { + .cmd_rcgr = 0x4e000, + .hid_width = 5, + .freq_tbl = ftbl_csi_phytimer_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "csi0phytimer_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 csi1phytimer_clk_src = { + .cmd_rcgr = 0x4f000, + .hid_width = 5, + .freq_tbl = ftbl_csi_phytimer_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "csi1phytimer_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_esc0_1_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 esc0_clk_src = { + .cmd_rcgr = 0x4d05c, + .hid_width = 5, + .freq_tbl = ftbl_esc0_1_clk_src, + .parent_map = gcc_xo_gpll0_out_aux_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "esc0_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct parent_map gcc_gfx3d_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL3, 2 }, + { P_GPLL6, 3 }, +}; + +static const struct parent_map gcc_gfx3d_map_qm215[] = { + { P_XO, 0 }, + { P_GPLL0, 5 }, + { P_GPLL3, 2 }, + { P_GPLL6, 6 }, +}; + +static const struct clk_parent_data gcc_gfx3d_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll3.clkr.hw }, + { .hw = &gpll6.hw }, +}; + +static const struct freq_tbl ftbl_gfx3d_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(228570000, P_GPLL0, 3.5, 0, 0), + F(240000000, P_GPLL6, 4.5, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(270000000, P_GPLL6, 4, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + F(465000000, P_GPLL3, 1, 0, 0), + F(484800000, P_GPLL3, 1, 0, 0), + F(500000000, P_GPLL3, 1, 0, 0), + F(523200000, P_GPLL3, 1, 0, 0), + F(550000000, P_GPLL3, 1, 0, 0), + F(598000000, P_GPLL3, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gfx3d_clk_src = { + .cmd_rcgr = 0x59000, + .hid_width = 5, + .freq_tbl = ftbl_gfx3d_clk_src, + .parent_map = gcc_gfx3d_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gfx3d_clk_src", + .parent_data = gcc_gfx3d_data, + .num_parents = ARRAY_SIZE(gcc_gfx3d_data), + .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + } +}; + +static const struct freq_tbl ftbl_gp_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x08004, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_gp_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp1_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x09004, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_gp_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp2_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0x0a004, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_gp_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "gp3_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_jpeg0_clk_src[] = { + F(133330000, P_GPLL0, 6, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 jpeg0_clk_src = { + .cmd_rcgr = 0x57000, + .hid_width = 5, + .freq_tbl = ftbl_jpeg0_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "jpeg0_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_mclk_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(24000000, P_GPLL6, 1, 1, 45), + F(66667000, P_GPLL0, 12, 0, 0), + { } +}; + +static struct clk_rcg2 mclk0_clk_src = { + .cmd_rcgr = 0x52000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_mclk_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "mclk0_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 mclk1_clk_src = { + .cmd_rcgr = 0x53000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_mclk_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "mclk1_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 mclk2_clk_src = { + .cmd_rcgr = 0x5c000, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_mclk_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_sleep_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "mclk2_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_sleep_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_sleep_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_mdp_clk_src[] = { + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(145450000, P_GPLL0, 5.5, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(177780000, P_GPLL0, 4.5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 mdp_clk_src = { + .cmd_rcgr = 0x4d014, + .hid_width = 5, + .freq_tbl = ftbl_mdp_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "mdp_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct parent_map gcc_pclk_map[] = { + { P_XO, 0 }, + { P_DSI0PLL, 1 }, +}; + +static const struct clk_parent_data gcc_pclk_data[] = { + { .index = DT_XO }, + { .index = DT_DSI0PLL }, +}; + +static struct clk_rcg2 pclk0_clk_src = { + .cmd_rcgr = 0x4d000, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_pclk_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pclk0_clk_src", + .parent_data = gcc_pclk_data, + .num_parents = ARRAY_SIZE(gcc_pclk_data), + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static const struct freq_tbl ftbl_pdm2_clk_src[] = { + F(64000000, P_GPLL0, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 pdm2_clk_src = { + .cmd_rcgr = 0x44010, + .hid_width = 5, + .freq_tbl = ftbl_pdm2_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "pdm2_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = { + F(100000000, P_GPLL0, 8, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x5d000, + .hid_width = 5, + .freq_tbl = ftbl_sdcc1_ice_core_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "sdcc1_ice_core_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct parent_map gcc_sdcc1_apps_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 2 }, +}; + +static const struct clk_parent_data gcc_sdcc1_apss_data[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll4.clkr.hw }, +}; + +static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0, 10, 1, 4), + F(25000000, P_GPLL0, 16, 1, 2), + F(50000000, P_GPLL0, 16, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(177770000, P_GPLL0, 4.5, 0, 0), + F(192000000, P_GPLL4, 6, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(384000000, P_GPLL4, 3, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x42004, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_sdcc1_apps_clk_src, + .parent_map = gcc_sdcc1_apps_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "sdcc1_apps_clk_src", + .parent_data = gcc_sdcc1_apss_data, + .num_parents = ARRAY_SIZE(gcc_sdcc1_apss_data), + .ops = &clk_rcg2_floor_ops, + } +}; + +static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0, 10, 1, 4), + F(25000000, P_GPLL0, 16, 1, 2), + F(50000000, P_GPLL0, 16, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(177770000, P_GPLL0, 4.5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc2_apps_clk_src = { + .cmd_rcgr = 0x43004, + .hid_width = 5, + .mnd_width = 8, + .freq_tbl = ftbl_sdcc2_apps_clk_src, + .parent_map = gcc_xo_gpll0_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "sdcc2_apps_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_floor_ops, + } +}; + +static const struct freq_tbl ftbl_usb_hs_system_clk_src[] = { + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133330000, P_GPLL0, 6, 0, 0), + F(177780000, P_GPLL0, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 usb_hs_system_clk_src = { + .cmd_rcgr = 0x41010, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_usb_hs_system_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb_hs_system_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_vcodec0_clk_src[] = { + F(133330000, P_GPLL0, 6, 0, 0), + F(180000000, P_GPLL6, 6, 0, 0), + F(228570000, P_GPLL0, 3.5, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), + F(329140000, P_GPLL4, 3.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + { } +}; + +static struct clk_rcg2 vcodec0_clk_src = { + .cmd_rcgr = 0x4c000, + .hid_width = 5, + .freq_tbl = ftbl_vcodec0_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "vcodec0_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_gpll4_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll4_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_vfe_clk_src[] = { + F(50000000, P_GPLL0, 16, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(133330000, P_GPLL0, 6, 0, 0), + F(160000000, P_GPLL0, 5, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266670000, P_GPLL0, 3, 0, 0), + F(308570000, P_GPLL6, 3.5, 0, 0), + F(320000000, P_GPLL0, 2.5, 0, 0), + F(329140000, P_GPLL4, 3.5, 0, 0), + F(360000000, P_GPLL6, 3, 0, 0), + { } +}; + +static struct clk_rcg2 vfe0_clk_src = { + .cmd_rcgr = 0x58000, + .hid_width = 5, + .freq_tbl = ftbl_vfe_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "vfe0_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_gpll4_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll4_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_rcg2 vfe1_clk_src = { + .cmd_rcgr = 0x58054, + .hid_width = 5, + .freq_tbl = ftbl_vfe_clk_src, + .parent_map = gcc_xo_gpll0_gpll6_gpll4_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "vfe1_clk_src", + .parent_data = gcc_xo_gpll0_gpll6_gpll4_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll6_gpll4_data), + .ops = &clk_rcg2_ops, + } +}; + +static const struct freq_tbl ftbl_vsync_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 vsync_clk_src = { + .cmd_rcgr = 0x4d02c, + .hid_width = 5, + .freq_tbl = ftbl_vsync_clk_src, + .parent_map = gcc_xo_gpll0_out_aux_map, + .clkr.hw.init = &(struct clk_init_data) { + .name = "vsync_clk_src", + .parent_data = gcc_xo_gpll0_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_data), + .ops = &clk_rcg2_ops, + } +}; + +static struct clk_branch gcc_apss_tcu_clk = { + .halt_reg = 0x12018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_apss_tcu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_bimc_gfx_clk = { + .halt_reg = 0x59034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_bimc_gfx_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_bimc_gpu_clk = { + .halt_reg = 0x59030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_bimc_gpu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_blsp2_ahb_clk = { + .halt_reg = 0x0b008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(20), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x03010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x03010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup2_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x04020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x04020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup3_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x05020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x05020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup4_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = { + .halt_reg = 0x0c008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup1_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup1_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = { + .halt_reg = 0x0d010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0d010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup2_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup2_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = { + .halt_reg = 0x0f020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0f020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup3_i2c_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup3_i2c_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x0300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup2_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x0401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup3_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x0501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_qup4_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = { + .halt_reg = 0x0c004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0c004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup1_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup1_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { + .halt_reg = 0x0d00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0d00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup2_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup2_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = { + .halt_reg = 0x0f01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0f01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_qup3_spi_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_qup3_spi_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x0203c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart1_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_uart1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x0302c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0302c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp1_uart2_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp1_uart2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_uart1_apps_clk = { + .halt_reg = 0x0c03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0c03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_uart1_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_uart1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_blsp2_uart2_apps_clk = { + .halt_reg = 0x0d02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0d02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_blsp2_uart2_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &blsp2_uart2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1300c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_camss_ahb_clk = { + .halt_reg = 0x56004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x56004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_camss_cci_ahb_clk = { + .halt_reg = 0x5101c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5101c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_cci_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_cci_clk = { + .halt_reg = 0x51018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x51018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_cci_clk", + .parent_hws = (const struct clk_hw*[]){ + &cci_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_cpp_ahb_clk = { + .halt_reg = 0x58040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_cpp_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_cpp_clk = { + .halt_reg = 0x5803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5803c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_cpp_clk", + .parent_hws = (const struct clk_hw*[]){ + &cpp_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0_ahb_clk = { + .halt_reg = 0x4e040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1_ahb_clk = { + .halt_reg = 0x4f040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi2_ahb_clk = { + .halt_reg = 0x3c040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3c040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi2_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0_clk = { + .halt_reg = 0x4e03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1_clk = { + .halt_reg = 0x4f03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi2_clk = { + .halt_reg = 0x3c03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3c03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi2_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0phy_clk = { + .halt_reg = 0x4e048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0phy_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1phy_clk = { + .halt_reg = 0x4f048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1phy_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi2phy_clk = { + .halt_reg = 0x3c048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3c048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi2phy_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0phytimer_clk = { + .halt_reg = 0x4e01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi0phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1phytimer_clk = { + .halt_reg = 0x4f01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1phytimer_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi1phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0pix_clk = { + .halt_reg = 0x4e058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0pix_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1pix_clk = { + .halt_reg = 0x4f058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1pix_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi2pix_clk = { + .halt_reg = 0x3c058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3c058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi2pix_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi0rdi_clk = { + .halt_reg = 0x4e050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi0rdi_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi1rdi_clk = { + .halt_reg = 0x4f050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4f050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi1rdi_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi2rdi_clk = { + .halt_reg = 0x3c050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3c050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi2rdi_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi_vfe0_clk = { + .halt_reg = 0x58050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi_vfe0_clk", + .parent_hws = (const struct clk_hw*[]){ + &vfe0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_csi_vfe1_clk = { + .halt_reg = 0x58074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58074, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_csi_vfe1_clk", + .parent_hws = (const struct clk_hw*[]){ + &vfe1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_gp0_clk = { + .halt_reg = 0x54018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x54018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_gp0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_gp0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_gp1_clk = { + .halt_reg = 0x55018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x55018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_gp1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_ispif_ahb_clk = { + .halt_reg = 0x50004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_ispif_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_jpeg0_clk = { + .halt_reg = 0x57020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_jpeg0_clk", + .parent_hws = (const struct clk_hw*[]){ + &jpeg0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_jpeg_ahb_clk = { + .halt_reg = 0x57024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x57024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_jpeg_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_jpeg_axi_clk = { + .halt_reg = 0x57028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x57028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_jpeg_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_camss_mclk0_clk = { + .halt_reg = 0x52018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_mclk0_clk", + .parent_hws = (const struct clk_hw*[]){ + &mclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_mclk1_clk = { + .halt_reg = 0x53018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x53018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_mclk1_clk", + .parent_hws = (const struct clk_hw*[]){ + &mclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_mclk2_clk = { + .halt_reg = 0x5c018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5c018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_mclk2_clk", + .parent_hws = (const struct clk_hw*[]){ + &mclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_micro_ahb_clk = { + .halt_reg = 0x5600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_micro_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_top_ahb_clk = { + .halt_reg = 0x5a014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5a014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_top_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_vfe0_ahb_clk = { + .halt_reg = 0x58044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe0_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_vfe0_axi_clk = { + .halt_reg = 0x58048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe0_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_camss_vfe0_clk = { + .halt_reg = 0x58038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe0_clk", + .parent_hws = (const struct clk_hw*[]){ + &vfe0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_vfe1_ahb_clk = { + .halt_reg = 0x58060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe1_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_top_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_camss_vfe1_axi_clk = { + .halt_reg = 0x58068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x58068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe1_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_camss_vfe1_clk = { + .halt_reg = 0x5805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5805c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_camss_vfe1_clk", + .parent_hws = (const struct clk_hw*[]){ + &vfe1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_cpp_tbu_clk = { + .halt_reg = 0x12040, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data) { + .name = "gcc_cpp_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_crypto_ahb_clk = { + .halt_reg = 0x16024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_crypto_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_crypto_axi_clk = { + .halt_reg = 0x16020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data) { + .name = "gcc_crypto_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_crypto_clk = { + .halt_reg = 0x1601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data) { + .name = "gcc_crypto_clk", + .parent_hws = (const struct clk_hw*[]){ + &crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_dcc_clk = { + .halt_reg = 0x77004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x77004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_dcc_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_gfx_tbu_clk = { + .halt_reg = 0x12010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gfx_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gfx_tcu_clk = { + .halt_reg = 0x12020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gfx_tcu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gtcu_ahb_clk = { + .halt_reg = 0x12044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gtcu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x08000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x08000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]){ + &gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x09000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x09000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]){ + &gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x0a000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0a000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]){ + &gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_jpeg_tbu_clk = { + .halt_reg = 0x12034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data) { + .name = "gcc_jpeg_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_mdp_tbu_clk = { + .halt_reg = 0x1201c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdp_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_mdss_ahb_clk = { + .halt_reg = 0x4d07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_mdss_axi_clk = { + .halt_reg = 0x4d080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_mdss_byte0_clk = { + .halt_reg = 0x4d094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_byte0_clk", + .parent_hws = (const struct clk_hw*[]){ + &byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_mdss_esc0_clk = { + .halt_reg = 0x4d098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_esc0_clk", + .parent_hws = (const struct clk_hw*[]){ + &esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_mdss_mdp_clk = { + .halt_reg = 0x4d088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_mdp_clk", + .parent_hws = (const struct clk_hw*[]){ + &mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_mdss_pclk0_clk = { + .halt_reg = 0x4d084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_pclk0_clk", + .parent_hws = (const struct clk_hw*[]){ + &pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_mdss_vsync_clk = { + .halt_reg = 0x4d090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mdss_vsync_clk", + .parent_hws = (const struct clk_hw*[]){ + &vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_mss_cfg_ahb_clk = { + .halt_reg = 0x49000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mss_cfg_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_mss_q6_bimc_axi_clk = { + .halt_reg = 0x49004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_mss_q6_bimc_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_oxili_ahb_clk = { + .halt_reg = 0x59028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_oxili_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_oxili_gfx3d_clk = { + .halt_reg = 0x59020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_oxili_gfx3d_clk", + .parent_hws = (const struct clk_hw*[]){ + &gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x4400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4400c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]){ + &pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x44004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x44004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data) { + .name = "gcc_prng_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_qdss_dap_clk = { + .halt_reg = 0x29084, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data) { + .name = "gcc_qdss_dap_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x5d014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5d014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk", + .parent_hws = (const struct clk_hw*[]){ + &sdcc1_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x4201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x4301c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4301c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x42018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x42018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &sdcc1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x43018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x43018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_smmu_cfg_clk = { + .halt_reg = 0x12038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data) { + .name = "gcc_smmu_cfg_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_usb2a_phy_sleep_clk = { + .halt_reg = 0x4102c, + .clkr = { + .enable_reg = 0x4102c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2a_phy_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_ahb_clk = { + .halt_reg = 0x41008, + .clkr = { + .enable_reg = 0x41008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_phy_cfg_ahb_clk = { + .halt_reg = 0x41030, + .clkr = { + .enable_reg = 0x41030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_phy_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_system_clk = { + .halt_reg = 0x41004, + .clkr = { + .enable_reg = 0x41004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_system_clk", + .parent_hws = (const struct clk_hw*[]){ + &usb_hs_system_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_venus0_ahb_clk = { + .halt_reg = 0x4c020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4c020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_venus0_ahb_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_venus0_axi_clk = { + .halt_reg = 0x4c024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4c024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_venus0_axi_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_venus0_core0_vcodec0_clk = { + .halt_reg = 0x4c02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4c02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_venus0_core0_vcodec0_clk", + .parent_hws = (const struct clk_hw*[]){ + &vcodec0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_venus0_vcodec0_clk = { + .halt_reg = 0x4c01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4c01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_venus0_vcodec0_clk", + .parent_hws = (const struct clk_hw*[]){ + &vcodec0_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + } + } +}; + +static struct clk_branch gcc_venus_tbu_clk = { + .halt_reg = 0x12014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data) { + .name = "gcc_venus_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_vfe1_tbu_clk = { + .halt_reg = 0x12090, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data) { + .name = "gcc_vfe1_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct clk_branch gcc_vfe_tbu_clk = { + .halt_reg = 0x1203c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data) { + .name = "gcc_vfe_tbu_clk", + .ops = &clk_branch2_ops, + } + } +}; + +static struct gdsc venus_gdsc = { + .gdscr = 0x4c018, + .cxcs = (unsigned int []){ 0x4c024, 0x4c01c }, + .cxc_count = 2, + .pd = { + .name = "venus_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc venus_core0_gdsc = { + .gdscr = 0x4c028, + .cxcs = (unsigned int []){ 0x4c02c }, + .cxc_count = 1, + .pd = { + .name = "venus_core0", + }, + .flags = HW_CTRL, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x4d078, + .cxcs = (unsigned int []){ 0x4d080, 0x4d088 }, + .cxc_count = 2, + .pd = { + .name = "mdss_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc jpeg_gdsc = { + .gdscr = 0x5701c, + .cxcs = (unsigned int []){ 0x57020, 0x57028 }, + .cxc_count = 2, + .pd = { + .name = "jpeg_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc vfe0_gdsc = { + .gdscr = 0x58034, + .cxcs = (unsigned int []){ 0x58038, 0x58048, 0x5600c, 0x58050 }, + .cxc_count = 4, + .pd = { + .name = "vfe0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc vfe1_gdsc = { + .gdscr = 0x5806c, + .cxcs = (unsigned int []){ 0x5805c, 0x58068, 0x5600c, 0x58074 }, + .cxc_count = 4, + .pd = { + .name = "vfe1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxili_gx_gdsc = { + .gdscr = 0x5901c, + .clamp_io_ctrl = 0x5b00c, + .cxcs = (unsigned int []){ 0x59000, 0x59020 }, + .cxc_count = 2, + .pd = { + .name = "oxili_gx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO, +}; + +static struct gdsc cpp_gdsc = { + .gdscr = 0x58078, + .cxcs = (unsigned int []){ 0x5803c, 0x58064 }, + .cxc_count = 2, + .pd = { + .name = "cpp_gdsc", + }, + .flags = ALWAYS_ON, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct clk_regmap *gcc_msm8917_clocks[] = { + [GPLL0] = &gpll0.clkr, + [GPLL0_EARLY] = &gpll0_early.clkr, + [GPLL3] = &gpll3.clkr, + [GPLL3_EARLY] = &gpll3_early.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL4_EARLY] = &gpll4_early.clkr, + [GPLL6] = &gpll6, + [GPLL6_EARLY] = &gpll6_early.clkr, + [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr, + [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr, + [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr, + [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr, + [BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr, + [BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr, + [BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr, + [BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr, + [BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr, + [BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr, + [BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr, + [BYTE0_CLK_SRC] = &byte0_clk_src.clkr, + [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr, + [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr, + [CAMSS_TOP_AHB_CLK_SRC] = &camss_top_ahb_clk_src.clkr, + [CCI_CLK_SRC] = &cci_clk_src.clkr, + [CPP_CLK_SRC] = &cpp_clk_src.clkr, + [CRYPTO_CLK_SRC] = &crypto_clk_src.clkr, + [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr, + [CSI0_CLK_SRC] = &csi0_clk_src.clkr, + [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr, + [CSI1_CLK_SRC] = &csi1_clk_src.clkr, + [CSI2_CLK_SRC] = &csi2_clk_src.clkr, + [ESC0_CLK_SRC] = &esc0_clk_src.clkr, + [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr, + [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr, + [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr, + [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr, + [MDP_CLK_SRC] = &mdp_clk_src.clkr, + [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr, + [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr, + [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, + [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, + [VCODEC0_CLK_SRC] = &vcodec0_clk_src.clkr, + [VFE0_CLK_SRC] = &vfe0_clk_src.clkr, + [VFE1_CLK_SRC] = &vfe1_clk_src.clkr, + [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, + [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_clk.clkr, + [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr, + [GCC_BIMC_GPU_CLK] = &gcc_bimc_gpu_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr, + [GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr, + [GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr, + [GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr, + [GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr, + [GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMSS_AHB_CLK] = &gcc_camss_ahb_clk.clkr, + [GCC_CAMSS_CCI_AHB_CLK] = &gcc_camss_cci_ahb_clk.clkr, + [GCC_CAMSS_CCI_CLK] = &gcc_camss_cci_clk.clkr, + [GCC_CAMSS_CPP_AHB_CLK] = &gcc_camss_cpp_ahb_clk.clkr, + [GCC_CAMSS_CPP_CLK] = &gcc_camss_cpp_clk.clkr, + [GCC_CAMSS_CSI0PHYTIMER_CLK] = &gcc_camss_csi0phytimer_clk.clkr, + [GCC_CAMSS_CSI0PHY_CLK] = &gcc_camss_csi0phy_clk.clkr, + [GCC_CAMSS_CSI0PIX_CLK] = &gcc_camss_csi0pix_clk.clkr, + [GCC_CAMSS_CSI0RDI_CLK] = &gcc_camss_csi0rdi_clk.clkr, + [GCC_CAMSS_CSI0_AHB_CLK] = &gcc_camss_csi0_ahb_clk.clkr, + [GCC_CAMSS_CSI0_CLK] = &gcc_camss_csi0_clk.clkr, + [GCC_CAMSS_CSI1PHYTIMER_CLK] = &gcc_camss_csi1phytimer_clk.clkr, + [GCC_CAMSS_CSI1PHY_CLK] = &gcc_camss_csi1phy_clk.clkr, + [GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr, + [GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr, + [GCC_CAMSS_CSI1_AHB_CLK] = &gcc_camss_csi1_ahb_clk.clkr, + [GCC_CAMSS_CSI1_CLK] = &gcc_camss_csi1_clk.clkr, + [GCC_CAMSS_CSI2PHY_CLK] = &gcc_camss_csi2phy_clk.clkr, + [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr, + [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr, + [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr, + [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr, + [GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr, + [GCC_CAMSS_CSI_VFE1_CLK] = &gcc_camss_csi_vfe1_clk.clkr, + [GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr, + [GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr, + [GCC_CAMSS_ISPIF_AHB_CLK] = &gcc_camss_ispif_ahb_clk.clkr, + [GCC_CAMSS_JPEG0_CLK] = &gcc_camss_jpeg0_clk.clkr, + [GCC_CAMSS_JPEG_AHB_CLK] = &gcc_camss_jpeg_ahb_clk.clkr, + [GCC_CAMSS_JPEG_AXI_CLK] = &gcc_camss_jpeg_axi_clk.clkr, + [GCC_CAMSS_MCLK0_CLK] = &gcc_camss_mclk0_clk.clkr, + [GCC_CAMSS_MCLK1_CLK] = &gcc_camss_mclk1_clk.clkr, + [GCC_CAMSS_MCLK2_CLK] = &gcc_camss_mclk2_clk.clkr, + [GCC_CAMSS_MICRO_AHB_CLK] = &gcc_camss_micro_ahb_clk.clkr, + [GCC_CAMSS_TOP_AHB_CLK] = &gcc_camss_top_ahb_clk.clkr, + [GCC_CAMSS_VFE0_AHB_CLK] = &gcc_camss_vfe0_ahb_clk.clkr, + [GCC_CAMSS_VFE0_AXI_CLK] = &gcc_camss_vfe0_axi_clk.clkr, + [GCC_CAMSS_VFE0_CLK] = &gcc_camss_vfe0_clk.clkr, + [GCC_CAMSS_VFE1_AHB_CLK] = &gcc_camss_vfe1_ahb_clk.clkr, + [GCC_CAMSS_VFE1_AXI_CLK] = &gcc_camss_vfe1_axi_clk.clkr, + [GCC_CAMSS_VFE1_CLK] = &gcc_camss_vfe1_clk.clkr, + [GCC_CPP_TBU_CLK] = &gcc_cpp_tbu_clk.clkr, + [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr, + [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr, + [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr, + [GCC_DCC_CLK] = &gcc_dcc_clk.clkr, + [GCC_GFX_TBU_CLK] = &gcc_gfx_tbu_clk.clkr, + [GCC_GFX_TCU_CLK] = &gcc_gfx_tcu_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GTCU_AHB_CLK] = &gcc_gtcu_ahb_clk.clkr, + [GCC_JPEG_TBU_CLK] = &gcc_jpeg_tbu_clk.clkr, + [GCC_MDP_TBU_CLK] = &gcc_mdp_tbu_clk.clkr, + [GCC_MDSS_AHB_CLK] = &gcc_mdss_ahb_clk.clkr, + [GCC_MDSS_AXI_CLK] = &gcc_mdss_axi_clk.clkr, + [GCC_MDSS_BYTE0_CLK] = &gcc_mdss_byte0_clk.clkr, + [GCC_MDSS_ESC0_CLK] = &gcc_mdss_esc0_clk.clkr, + [GCC_MDSS_MDP_CLK] = &gcc_mdss_mdp_clk.clkr, + [GCC_MDSS_PCLK0_CLK] = &gcc_mdss_pclk0_clk.clkr, + [GCC_MDSS_VSYNC_CLK] = &gcc_mdss_vsync_clk.clkr, + [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr, + [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr, + [GCC_OXILI_AHB_CLK] = &gcc_oxili_ahb_clk.clkr, + [GCC_OXILI_GFX3D_CLK] = &gcc_oxili_gfx3d_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SMMU_CFG_CLK] = &gcc_smmu_cfg_clk.clkr, + [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr, + [GCC_USB_HS_AHB_CLK] = &gcc_usb_hs_ahb_clk.clkr, + [GCC_USB_HS_PHY_CFG_AHB_CLK] = &gcc_usb_hs_phy_cfg_ahb_clk.clkr, + [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr, + [GCC_VENUS0_AHB_CLK] = &gcc_venus0_ahb_clk.clkr, + [GCC_VENUS0_AXI_CLK] = &gcc_venus0_axi_clk.clkr, + [GCC_VENUS0_CORE0_VCODEC0_CLK] = &gcc_venus0_core0_vcodec0_clk.clkr, + [GCC_VENUS0_VCODEC0_CLK] = &gcc_venus0_vcodec0_clk.clkr, + [GCC_VENUS_TBU_CLK] = &gcc_venus_tbu_clk.clkr, + [GCC_VFE1_TBU_CLK] = &gcc_vfe1_tbu_clk.clkr, + [GCC_VFE_TBU_CLK] = &gcc_vfe_tbu_clk.clkr, +}; + +static const struct qcom_reset_map gcc_msm8917_resets[] = { + [GCC_CAMSS_MICRO_BCR] = { 0x56008 }, + [GCC_MSS_BCR] = { 0x71000 }, + [GCC_QUSB2_PHY_BCR] = { 0x4103c }, + [GCC_USB_HS_BCR] = { 0x41000 }, + [GCC_USB2_HS_PHY_ONLY_BCR] = { 0x41034 }, +}; + +static const struct regmap_config gcc_msm8917_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x80000, + .fast_io = true, +}; + +static struct gdsc *gcc_msm8917_gdscs[] = { + [CPP_GDSC] = &cpp_gdsc, + [JPEG_GDSC] = &jpeg_gdsc, + [MDSS_GDSC] = &mdss_gdsc, + [OXILI_GX_GDSC] = &oxili_gx_gdsc, + [VENUS_CORE0_GDSC] = &venus_core0_gdsc, + [VENUS_GDSC] = &venus_gdsc, + [VFE0_GDSC] = &vfe0_gdsc, + [VFE1_GDSC] = &vfe1_gdsc, +}; + +static const struct qcom_cc_desc gcc_msm8917_desc = { + .config = &gcc_msm8917_regmap_config, + .clks = gcc_msm8917_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8917_clocks), + .resets = gcc_msm8917_resets, + .num_resets = ARRAY_SIZE(gcc_msm8917_resets), + .gdscs = gcc_msm8917_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8917_gdscs), +}; + +static const struct qcom_cc_desc gcc_qm215_desc = { + .config = &gcc_msm8917_regmap_config, + .clks = gcc_msm8917_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8917_clocks), + .resets = gcc_msm8917_resets, + .num_resets = ARRAY_SIZE(gcc_msm8917_resets), + .gdscs = gcc_msm8917_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8917_gdscs), +}; + +static int gcc_msm8917_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + const struct qcom_cc_desc *gcc_desc; + + gcc_desc = of_device_get_match_data(&pdev->dev); + + if (gcc_desc == &gcc_qm215_desc) + gfx3d_clk_src.parent_map = gcc_gfx3d_map_qm215; + + regmap = qcom_cc_map(pdev, gcc_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_alpha_pll_configure(&gpll3_early, regmap, &gpll3_early_config); + + return qcom_cc_really_probe(pdev, gcc_desc, regmap); +} + +static const struct of_device_id gcc_msm8917_match_table[] = { + { .compatible = "qcom,gcc-msm8917", .data = &gcc_msm8917_desc }, + { .compatible = "qcom,gcc-qm215", .data = &gcc_qm215_desc }, + {}, +}; + +static struct platform_driver gcc_msm8917_driver = { + .probe = gcc_msm8917_probe, + .driver = { + .name = "gcc-msm8917", + .of_match_table = gcc_msm8917_match_table, + }, +}; + +static int __init gcc_msm8917_init(void) +{ + return platform_driver_register(&gcc_msm8917_driver); +} +core_initcall(gcc_msm8917_init); + +static void __exit gcc_msm8917_exit(void) +{ + platform_driver_unregister(&gcc_msm8917_driver); +} +module_exit(gcc_msm8917_exit); + +MODULE_DESCRIPTION("Qualcomm GCC MSM8917 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index 9dd4e7ffa1f8..dbc7093ab9cc 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -3754,19 +3754,17 @@ static int gcc_msm8960_probe(struct platform_device *pdev) return 0; } -static int gcc_msm8960_remove(struct platform_device *pdev) +static void gcc_msm8960_remove(struct platform_device *pdev) { struct platform_device *tsens = platform_get_drvdata(pdev); if (tsens) platform_device_unregister(tsens); - - return 0; } static struct platform_driver gcc_msm8960_driver = { .probe = gcc_msm8960_probe, - .remove = gcc_msm8960_remove, + .remove_new = gcc_msm8960_remove, .driver = { .name = "gcc-msm8960", .of_match_table = gcc_msm8960_match_table, diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index e16163706735..5e44d1bcca9e 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3455,7 +3455,8 @@ static struct gdsc usb30_gdsc = { .pd = { .name = "usb30", }, - .pwrsts = PWRSTS_OFF_ON, + /* TODO: Change to OFF_ON when USB drivers get proper suspend support */ + .pwrsts = PWRSTS_RET_ON, }; static struct gdsc pcie0_gdsc = { diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 908e996841c2..be024f8093c5 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -2898,7 +2898,8 @@ static struct gdsc usb_30_gdsc = { .pd = { .name = "usb_30_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + /* TODO: Change to OFF_ON when USB drivers get proper suspend support */ + .pwrsts = PWRSTS_RET_ON, .flags = VOTABLE, }; diff --git a/drivers/clk/qcom/gcc-qcm2290.c b/drivers/clk/qcom/gcc-qcm2290.c index 7792b8f23704..096deff2ba25 100644 --- a/drivers/clk/qcom/gcc-qcm2290.c +++ b/drivers/clk/qcom/gcc-qcm2290.c @@ -1243,7 +1243,8 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .name = "gcc_sdcc2_apps_clk_src", .parent_data = gcc_parents_12, .num_parents = ARRAY_SIZE(gcc_parents_12), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_floor_ops, + .flags = CLK_OPS_PARENT_ENABLE, }, }; diff --git a/drivers/clk/qcom/gcc-sc8280xp.c b/drivers/clk/qcom/gcc-sc8280xp.c index b3198784e1c3..04a99dbaa57e 100644 --- a/drivers/clk/qcom/gcc-sc8280xp.c +++ b/drivers/clk/qcom/gcc-sc8280xp.c @@ -6873,6 +6873,22 @@ static struct gdsc usb30_sec_gdsc = { .pwrsts = PWRSTS_RET_ON, }; +static struct gdsc emac_0_gdsc = { + .gdscr = 0xaa004, + .pd = { + .name = "emac_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc emac_1_gdsc = { + .gdscr = 0xba004, + .pd = { + .name = "emac_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_sc8280xp_clocks[] = { [GCC_AGGRE_NOC_PCIE0_TUNNEL_AXI_CLK] = &gcc_aggre_noc_pcie0_tunnel_axi_clk.clkr, [GCC_AGGRE_NOC_PCIE1_TUNNEL_AXI_CLK] = &gcc_aggre_noc_pcie1_tunnel_axi_clk.clkr, @@ -7351,6 +7367,8 @@ static struct gdsc *gcc_sc8280xp_gdscs[] = { [USB30_MP_GDSC] = &usb30_mp_gdsc, [USB30_PRIM_GDSC] = &usb30_prim_gdsc, [USB30_SEC_GDSC] = &usb30_sec_gdsc, + [EMAC_0_GDSC] = &emac_0_gdsc, + [EMAC_1_GDSC] = &emac_1_gdsc, }; static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { diff --git a/drivers/clk/qcom/gcc-sm6115.c b/drivers/clk/qcom/gcc-sm6115.c index 5b8222fea2f7..5f09aefa7fb9 100644 --- a/drivers/clk/qcom/gcc-sm6115.c +++ b/drivers/clk/qcom/gcc-sm6115.c @@ -694,7 +694,7 @@ static struct clk_rcg2 gcc_camss_axi_clk_src = { .parent_data = gcc_parents_7, .num_parents = ARRAY_SIZE(gcc_parents_7), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -715,7 +715,7 @@ static struct clk_rcg2 gcc_camss_cci_clk_src = { .parent_data = gcc_parents_9, .num_parents = ARRAY_SIZE(gcc_parents_9), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -738,7 +738,7 @@ static struct clk_rcg2 gcc_camss_csi0phytimer_clk_src = { .parent_data = gcc_parents_4, .num_parents = ARRAY_SIZE(gcc_parents_4), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -753,7 +753,7 @@ static struct clk_rcg2 gcc_camss_csi1phytimer_clk_src = { .parent_data = gcc_parents_4, .num_parents = ARRAY_SIZE(gcc_parents_4), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -768,7 +768,7 @@ static struct clk_rcg2 gcc_camss_csi2phytimer_clk_src = { .parent_data = gcc_parents_4, .num_parents = ARRAY_SIZE(gcc_parents_4), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -790,7 +790,7 @@ static struct clk_rcg2 gcc_camss_mclk0_clk_src = { .parent_data = gcc_parents_3, .num_parents = ARRAY_SIZE(gcc_parents_3), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -805,7 +805,7 @@ static struct clk_rcg2 gcc_camss_mclk1_clk_src = { .parent_data = gcc_parents_3, .num_parents = ARRAY_SIZE(gcc_parents_3), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -820,7 +820,7 @@ static struct clk_rcg2 gcc_camss_mclk2_clk_src = { .parent_data = gcc_parents_3, .num_parents = ARRAY_SIZE(gcc_parents_3), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -835,7 +835,7 @@ static struct clk_rcg2 gcc_camss_mclk3_clk_src = { .parent_data = gcc_parents_3, .num_parents = ARRAY_SIZE(gcc_parents_3), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -857,7 +857,7 @@ static struct clk_rcg2 gcc_camss_ope_ahb_clk_src = { .parent_data = gcc_parents_8, .num_parents = ARRAY_SIZE(gcc_parents_8), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -881,7 +881,7 @@ static struct clk_rcg2 gcc_camss_ope_clk_src = { .parent_data = gcc_parents_8, .num_parents = ARRAY_SIZE(gcc_parents_8), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -916,7 +916,7 @@ static struct clk_rcg2 gcc_camss_tfe_0_clk_src = { .parent_data = gcc_parents_5, .num_parents = ARRAY_SIZE(gcc_parents_5), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -941,7 +941,7 @@ static struct clk_rcg2 gcc_camss_tfe_0_csid_clk_src = { .parent_data = gcc_parents_6, .num_parents = ARRAY_SIZE(gcc_parents_6), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -956,7 +956,7 @@ static struct clk_rcg2 gcc_camss_tfe_1_clk_src = { .parent_data = gcc_parents_5, .num_parents = ARRAY_SIZE(gcc_parents_5), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -971,7 +971,7 @@ static struct clk_rcg2 gcc_camss_tfe_1_csid_clk_src = { .parent_data = gcc_parents_6, .num_parents = ARRAY_SIZE(gcc_parents_6), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -986,7 +986,7 @@ static struct clk_rcg2 gcc_camss_tfe_2_clk_src = { .parent_data = gcc_parents_5, .num_parents = ARRAY_SIZE(gcc_parents_5), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1001,7 +1001,7 @@ static struct clk_rcg2 gcc_camss_tfe_2_csid_clk_src = { .parent_data = gcc_parents_6, .num_parents = ARRAY_SIZE(gcc_parents_6), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1024,7 +1024,7 @@ static struct clk_rcg2 gcc_camss_tfe_cphy_rx_clk_src = { .parent_data = gcc_parents_10, .num_parents = ARRAY_SIZE(gcc_parents_10), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1046,7 +1046,7 @@ static struct clk_rcg2 gcc_camss_top_ahb_clk_src = { .parent_data = gcc_parents_7, .num_parents = ARRAY_SIZE(gcc_parents_7), .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1116,7 +1116,7 @@ static struct clk_rcg2 gcc_pdm2_clk_src = { .name = "gcc_pdm2_clk_src", .parent_data = gcc_parents_0, .num_parents = ARRAY_SIZE(gcc_parents_0), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1329,7 +1329,7 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { .name = "gcc_ufs_phy_axi_clk_src", .parent_data = gcc_parents_0, .num_parents = ARRAY_SIZE(gcc_parents_0), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1351,7 +1351,7 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { .name = "gcc_ufs_phy_ice_core_clk_src", .parent_data = gcc_parents_0, .num_parents = ARRAY_SIZE(gcc_parents_0), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1392,7 +1392,7 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { .name = "gcc_ufs_phy_unipro_core_clk_src", .parent_data = gcc_parents_0, .num_parents = ARRAY_SIZE(gcc_parents_0), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1414,7 +1414,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { .name = "gcc_usb30_prim_master_clk_src", .parent_data = gcc_parents_0, .num_parents = ARRAY_SIZE(gcc_parents_0), - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1483,7 +1483,7 @@ static struct clk_rcg2 gcc_video_venus_clk_src = { .parent_data = gcc_parents_13, .num_parents = ARRAY_SIZE(gcc_parents_13), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; diff --git a/drivers/clk/qcom/gcc-sm6375.c b/drivers/clk/qcom/gcc-sm6375.c index ad3c4833990d..417a0fd242ec 100644 --- a/drivers/clk/qcom/gcc-sm6375.c +++ b/drivers/clk/qcom/gcc-sm6375.c @@ -3534,7 +3534,8 @@ static struct gdsc usb30_prim_gdsc = { .pd = { .name = "usb30_prim_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + /* TODO: Change to OFF_ON when USB drivers get proper suspend support */ + .pwrsts = PWRSTS_RET_ON, }; static struct gdsc ufs_phy_gdsc = { diff --git a/drivers/clk/qcom/gcc-sm7150.c b/drivers/clk/qcom/gcc-sm7150.c new file mode 100644 index 000000000000..6b628178f62c --- /dev/null +++ b/drivers/clk/qcom/gcc-sm7150.c @@ -0,0 +1,3048 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Danila Tikhonov + * Copyright (c) 2023, David Wronek + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_EVEN, + P_GPLL0_OUT_MAIN, + P_GPLL6_OUT_MAIN, + P_GPLL7_OUT_MAIN, + P_SLEEP_CLK, +}; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_fabia_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0_out_even", + .parent_hws = (const struct clk_hw*[]){ + &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_fixed_factor gcc_pll0_main_div_cdiv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "gcc_pll0_main_div_cdiv", + .parent_hws = (const struct clk_hw*[]){ + &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_alpha_pll gpll6 = { + .offset = 0x13000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gpll6", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_fabia_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll7 = { + .offset = 0x27000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll7", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_fabia_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; +static const struct clk_parent_data gcc_parent_data_0_ao[] = { + { .index = DT_BI_TCXO_AO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct clk_parent_data gcc_parent_data_2_ao[] = { + { .index = DT_BI_TCXO_AO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL6_OUT_MAIN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll6.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL7_OUT_MAIN, 3 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll7.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpll0.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { + .cmd_rcgr = 0x48014, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_data = gcc_parent_data_0_ao, + .num_parents = ARRAY_SIZE(gcc_parent_data_0_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { + .cmd_rcgr = 0x4815c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk_src", + .parent_data = gcc_parent_data_2_ao, + .num_parents = ARRAY_SIZE(gcc_parent_data_2_ao), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x64004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x6b028, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_phy_refgen_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { + .cmd_rcgr = 0x6f014, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_phy_refgen_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_refgen_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x33010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + F(102400000, P_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GPLL0_OUT_EVEN, 2.5, 0, 0), + F(128000000, P_GPLL0_OUT_MAIN, 1, 16, 75), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x17034, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x17164, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x17294, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x173c4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x174f4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { + .name = "gcc_qupv3_wrap0_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x17624, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = { + .name = "gcc_qupv3_wrap0_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { + .cmd_rcgr = 0x17754, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = { + .name = "gcc_qupv3_wrap0_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x17884, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x18278, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x183a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x184d8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18608, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18738, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x18868, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, P_BI_TCXO, 16, 3, 25), + F(400000, P_BI_TCXO, 12, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(20000000, P_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GPLL0_OUT_EVEN, 6, 1, 2), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0), + F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x12028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x12010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(208000000, P_GPLL7_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x1400c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x1600c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_tsif_ref_clk_src[] = { + F(105495, P_BI_TCXO, 2, 1, 91), + { } +}; + +static struct clk_rcg2 gcc_tsif_ref_clk_src = { + .cmd_rcgr = 0x36010, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_tsif_ref_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ref_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(37500000, P_GPLL0_OUT_EVEN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x77098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(37500000, P_GPLL0_OUT_EVEN, 8, 0, 0), + F(75000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0xf01c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0), + F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0xf034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb3_prim_phy_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0xf060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_usb3_prim_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_vs_ctrl_clk_src = { + .cmd_rcgr = 0x7a030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_usb3_prim_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_vsensor_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(600000000, P_GPLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_vsensor_clk_src = { + .cmd_rcgr = 0x7a018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_vsensor_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_vsensor_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_tbu_clk = { + .halt_reg = 0x2800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2800c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_noc_pcie_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x82024, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x82024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x82024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x82024, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x82024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x82024, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_aggre_ufs_phy_axi_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch_simple_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x8201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_apc_vs_clk = { + .halt_reg = 0x7a050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apc_vs_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vsensor_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0xb020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0xb06c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb06c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_ahb_clk = { + .halt_reg = 0x4100c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4100c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_axi_clk = { + .halt_reg = 0x41008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_clk = { + .halt_reg = 0x41004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x502c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x502c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_ahb_clk = { + .halt_reg = 0x48000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_cpuss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_rbcpr_clk = { + .halt_reg = 0x48008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x48008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_cpuss_rbcpr_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x4452c, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x4452c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + + +static struct clk_branch gcc_disp_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(18), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(19), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pll0_main_div_cdiv.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0xb024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_sf_axi_clk = { + .halt_reg = 0xb070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb070, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_disp_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(16), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pll0_main_div_cdiv.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x7100c, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x7100c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_vs_clk = { + .halt_reg = 0x7a04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpu_vs_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vsensor_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_axi_clk = { + .halt_reg = 0x4d008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_cfg_ahb_clk = { + .halt_reg = 0x4d004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x4d004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4d004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_cfg_ahb_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(25), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_npu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "gcc_npu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pll0_main_div_cdiv.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_clkref_clk = { + .halt_reg = 0x8c008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x6b014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x6b020, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x6b010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0x6b00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_aux_clk = { + .halt_reg = 0x6f004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_phy_refgen_clk = { + .halt_reg = 0x6f02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6f02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_phy_refgen_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pcie_phy_refgen_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x33004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x34004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x17014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_clk = { + .halt_reg = 0x1700c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s0_clk = { + .halt_reg = 0x17030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s0_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s1_clk = { + .halt_reg = 0x17160, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s1_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s2_clk = { + .halt_reg = 0x17290, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s2_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s3_clk = { + .halt_reg = 0x173c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s3_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s4_clk = { + .halt_reg = 0x174f0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s4_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s5_clk = { + .halt_reg = 0x17620, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s5_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s6_clk = { + .halt_reg = 0x17750, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(16), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s6_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s7_clk = { + .halt_reg = 0x17880, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap0_s7_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap0_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(18), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x18008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(19), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x18014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x18144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(23), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x18274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(24), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x183a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(25), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x184d4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s5_clk = { + .halt_reg = 0x18604, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(27), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s5_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s6_clk = { + .halt_reg = 0x18734, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(28), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s6_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s7_clk = { + .halt_reg = 0x18864, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(29), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap1_s7_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_qupv3_wrap1_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_0_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { + .halt_reg = 0x17008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x17008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_0_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0x1800c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(20), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x18010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x18010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x5200c, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x12008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x1200c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1200c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_sdcc1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x12040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_sdcc1_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = { + .halt_reg = 0x4144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_cpuss_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_cpuss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_ahb_clk = { + .halt_reg = 0x36004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_inactivity_timers_clk = { + .halt_reg = 0x3600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_inactivity_timers_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_ref_clk = { + .halt_reg = 0x36008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x36008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_tsif_ref_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_tsif_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_mem_clkref_clk = { + .halt_reg = 0x8c000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_mem_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77014, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x77038, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x77038, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77038, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_axi_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch_simple_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x77090, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = { + .halt_reg = 0x77090, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77090, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_ice_core_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch_simple_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x77094, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77094, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { + .halt_reg = 0x77094, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x77094, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77094, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_phy_aux_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch_simple_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x7701c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x7701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x77018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x7708c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7708c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7708c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = { + .halt_reg = 0x7708c, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7708c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7708c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_ufs_phy_unipro_core_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch_simple_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0xf010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0xf018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0xf014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_clkref_clk = { + .halt_reg = 0x8c010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8c010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0xf050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0xf054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0xf058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_prim_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { + .halt_reg = 0x6a004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x6a004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_phy_cfg_ahb2phy_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vdda_vs_clk = { + .halt_reg = 0x7a00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vdda_vs_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vsensor_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vddcx_vs_clk = { + .halt_reg = 0x7a004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vddcx_vs_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vsensor_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vddmx_vs_clk = { + .halt_reg = 0x7a008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vddmx_vs_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vsensor_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + + +static struct clk_branch gcc_video_axi_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_video_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vs_ctrl_ahb_clk = { + .halt_reg = 0x7a014, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x7a014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7a014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vs_ctrl_clk = { + .halt_reg = 0x7a010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7a010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_vs_ctrl_clk", + .parent_hws = (const struct clk_hw*[]){ + &gcc_vs_ctrl_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc pcie_0_gdsc = { + .gdscr = 0x6b004, + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ufs_phy_gdsc = { + .gdscr = 0x77004, + .pd = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc = { + .gdscr = 0x7d030, + .pd = { + .name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc = { + .gdscr = 0x7d03c, + .pd = { + .name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_aggre_noc_mmu_tbu1_gdsc = { + .gdscr = 0x7d034, + .pd = { + .name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_aggre_noc_mmu_tbu2_gdsc = { + .gdscr = 0x7d038, + .pd = { + .name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { + .gdscr = 0x7d040, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { + .gdscr = 0x7d048, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { + .gdscr = 0x7d044, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct clk_hw *gcc_sm7150_hws[] = { + [GCC_GPLL0_MAIN_DIV_CDIV] = &gcc_pll0_main_div_cdiv.hw, +}; + +static struct clk_regmap *gcc_sm7150_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = + &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_APC_VS_CLK] = &gcc_apc_vs_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr, + [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr, + [GCC_CE1_CLK] = &gcc_ce1_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, + [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DISP_GPLL0_CLK_SRC] = &gcc_disp_gpll0_clk_src.clkr, + [GCC_DISP_GPLL0_DIV_CLK_SRC] = &gcc_disp_gpll0_div_clk_src.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_DISP_SF_AXI_CLK] = &gcc_disp_sf_axi_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, + [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_GPU_VS_CLK] = &gcc_gpu_vs_clk.clkr, + [GCC_NPU_AXI_CLK] = &gcc_npu_axi_clk.clkr, + [GCC_NPU_CFG_AHB_CLK] = &gcc_npu_cfg_ahb_clk.clkr, + [GCC_NPU_GPLL0_CLK_SRC] = &gcc_npu_gpll0_clk_src.clkr, + [GCC_NPU_GPLL0_DIV_CLK_SRC] = &gcc_npu_gpll0_div_clk_src.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PCIE_PHY_AUX_CLK] = &gcc_pcie_phy_aux_clk.clkr, + [GCC_PCIE_PHY_REFGEN_CLK] = &gcc_pcie_phy_refgen_clk.clkr, + [GCC_PCIE_PHY_REFGEN_CLK_SRC] = &gcc_pcie_phy_refgen_clk_src.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr, + [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr, + [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr, + [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr, + [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr, + [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr, + [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr, + [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr, + [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr, + [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr, + [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr, + [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr, + [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr, + [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr, + [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr, + [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr, + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr, + [GCC_TSIF_AHB_CLK] = &gcc_tsif_ahb_clk.clkr, + [GCC_TSIF_INACTIVITY_TIMERS_CLK] = &gcc_tsif_inactivity_timers_clk.clkr, + [GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr, + [GCC_TSIF_REF_CLK_SRC] = &gcc_tsif_ref_clk_src.clkr, + [GCC_UFS_MEM_CLKREF_CLK] = &gcc_ufs_mem_clkref_clk.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = + &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = + &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr, + [GCC_VDDA_VS_CLK] = &gcc_vdda_vs_clk.clkr, + [GCC_VDDCX_VS_CLK] = &gcc_vddcx_vs_clk.clkr, + [GCC_VDDMX_VS_CLK] = &gcc_vddmx_vs_clk.clkr, + [GCC_VIDEO_AXI_CLK] = &gcc_video_axi_clk.clkr, + [GCC_VS_CTRL_AHB_CLK] = &gcc_vs_ctrl_ahb_clk.clkr, + [GCC_VS_CTRL_CLK] = &gcc_vs_ctrl_clk.clkr, + [GCC_VS_CTRL_CLK_SRC] = &gcc_vs_ctrl_clk_src.clkr, + [GCC_VSENSOR_CLK_SRC] = &gcc_vsensor_clk_src.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, + [GPLL6] = &gpll6.clkr, + [GPLL7] = &gpll7.clkr, +}; + +static const struct qcom_reset_map gcc_sm7150_resets[] = { + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x26000 }, + [GCC_VIDEO_AXI_CLK_BCR] = { 0xb01c, 2 }, +}; + +static const struct clk_rcg_dfs_data gcc_sm7150_dfs_desc[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), +}; + +static struct gdsc *gcc_sm7150_gdscs[] = { + [PCIE_0_GDSC] = &pcie_0_gdsc, + [UFS_PHY_GDSC] = &ufs_phy_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC] = + &hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc, + [HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_GDSC] = + &hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC] = + &hlos1_vote_aggre_noc_mmu_tbu1_gdsc, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC] = + &hlos1_vote_aggre_noc_mmu_tbu2_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = + &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, +}; + +static const struct regmap_config gcc_sm7150_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1820b0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sm7150_desc = { + .config = &gcc_sm7150_regmap_config, + .clk_hws = gcc_sm7150_hws, + .num_clk_hws = ARRAY_SIZE(gcc_sm7150_hws), + .clks = gcc_sm7150_clocks, + .num_clks = ARRAY_SIZE(gcc_sm7150_clocks), + .resets = gcc_sm7150_resets, + .num_resets = ARRAY_SIZE(gcc_sm7150_resets), + .gdscs = gcc_sm7150_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm7150_gdscs), +}; + +static const struct of_device_id gcc_sm7150_match_table[] = { + { .compatible = "qcom,sm7150-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sm7150_match_table); + +static int gcc_sm7150_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sm7150_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* + * Disable the GPLL0 active input to MM blocks, NPU + * and GPU via MISC registers. + */ + regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); + regmap_update_bits(regmap, 0x4d110, 0x3, 0x3); + regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + + /* + * Keep the critical clocks always-ON + * GCC_CPUSS_GNOC_CLK, GCC_VIDEO_AHB_CLK, GCC_CAMERA_AHB_CLK, + * GCC_DISP_AHB_CLK, GCC_CAMERA_XO_CLK, GCC_VIDEO_XO_CLK, + * GCC_DISP_XO_CLK, GCC_GPU_CFG_AHB_CLK + */ + regmap_update_bits(regmap, 0x48004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b008, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b00c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b02c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b028, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x0b030, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_sm7150_dfs_desc, + ARRAY_SIZE(gcc_sm7150_dfs_desc)); + if (ret) + return ret; + + return qcom_cc_really_probe(pdev, &gcc_sm7150_desc, regmap); +} + +static struct platform_driver gcc_sm7150_driver = { + .probe = gcc_sm7150_probe, + .driver = { + .name = "gcc-sm7150", + .of_match_table = gcc_sm7150_match_table, + }, +}; + +static int __init gcc_sm7150_init(void) +{ + return platform_driver_register(&gcc_sm7150_driver); +} +subsys_initcall(gcc_sm7150_init); + +static void __exit gcc_sm7150_exit(void) +{ + platform_driver_unregister(&gcc_sm7150_driver); +} +module_exit(gcc_sm7150_exit); + +MODULE_DESCRIPTION("Qualcomm SM7150 Global Clock Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-sm8350.c b/drivers/clk/qcom/gcc-sm8350.c index af4a1ea28421..1385a98eb3bb 100644 --- a/drivers/clk/qcom/gcc-sm8350.c +++ b/drivers/clk/qcom/gcc-sm8350.c @@ -17,6 +17,7 @@ #include "clk-regmap.h" #include "clk-regmap-divider.h" #include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" #include "gdsc.h" #include "reset.h" @@ -158,26 +159,6 @@ static const struct clk_parent_data gcc_parent_data_3[] = { { .fw_name = "bi_tcxo" }, }; -static const struct parent_map gcc_parent_map_4[] = { - { P_PCIE_0_PIPE_CLK, 0 }, - { P_BI_TCXO, 2 }, -}; - -static const struct clk_parent_data gcc_parent_data_4[] = { - { .fw_name = "pcie_0_pipe_clk", }, - { .fw_name = "bi_tcxo" }, -}; - -static const struct parent_map gcc_parent_map_5[] = { - { P_PCIE_1_PIPE_CLK, 0 }, - { P_BI_TCXO, 2 }, -}; - -static const struct clk_parent_data gcc_parent_data_5[] = { - { .fw_name = "pcie_1_pipe_clk" }, - { .fw_name = "bi_tcxo" }, -}; - static const struct parent_map gcc_parent_map_6[] = { { P_BI_TCXO, 0 }, { P_GCC_GPLL0_OUT_MAIN, 1 }, @@ -274,32 +255,30 @@ static const struct clk_parent_data gcc_parent_data_14[] = { { .fw_name = "bi_tcxo" }, }; -static struct clk_regmap_mux gcc_pcie_0_pipe_clk_src = { +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { .reg = 0x6b054, - .shift = 0, - .width = 2, - .parent_map = gcc_parent_map_4, .clkr = { .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_pipe_clk_src", - .parent_data = gcc_parent_data_4, - .num_parents = ARRAY_SIZE(gcc_parent_data_4), - .ops = &clk_regmap_mux_closest_ops, + .parent_data = &(const struct clk_parent_data){ + .fw_name = "pcie_0_pipe_clk", + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, }, }, }; -static struct clk_regmap_mux gcc_pcie_1_pipe_clk_src = { +static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = { .reg = 0x8d054, - .shift = 0, - .width = 2, - .parent_map = gcc_parent_map_5, .clkr = { .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_pipe_clk_src", - .parent_data = gcc_parent_data_5, - .num_parents = ARRAY_SIZE(gcc_parent_data_5), - .ops = &clk_regmap_mux_closest_ops, + .parent_data = &(const struct clk_parent_data){ + .fw_name = "pcie_1_pipe_clk", + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, }, }, }; diff --git a/drivers/clk/qcom/gpucc-sa8775p.c b/drivers/clk/qcom/gpucc-sa8775p.c new file mode 100644 index 000000000000..18d23be8d435 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sa8775p.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "reset.h" +#include "gdsc.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_BI_TCXO, + DT_GCC_GPU_GPLL0_CLK_SRC, + DT_GCC_GPU_GPLL0_DIV_CLK_SRC, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL1_OUT_MAIN, +}; + +static const struct clk_parent_data parent_data_tcxo = { .index = DT_BI_TCXO }; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +/* 810MHz configuration */ +static struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x2a, + .alpha = 0x3000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_data = &parent_data_tcxo, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +/* 1000MHz configuration */ +static struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x34, + .alpha = 0x1555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_data = &parent_data_tcxo, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, + { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, + { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, +}; + +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, + { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, +}; + +static const struct parent_map gpu_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_3[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_ff_clk_src = { + .cmd_rcgr = 0x9474, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_ff_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x9318, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = { + F(240000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_hub_clk_src = { + .cmd_rcgr = 0x93ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_2, + .freq_tbl = ftbl_gpu_cc_hub_clk_src, + .clkr.hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_hub_clk_src", + .parent_data = gpu_cc_parent_data_2, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_xo_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_xo_clk_src = { + .cmd_rcgr = 0x9010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_3, + .freq_tbl = ftbl_gpu_cc_xo_clk_src, + .clkr.hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_xo_clk_src", + .parent_data = gpu_cc_parent_data_3, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div gpu_cc_demet_div_clk_src = { + .reg = 0x9054, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_demet_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gpu_cc_hub_ahb_div_clk_src = { + .reg = 0x9430, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_ahb_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gpu_cc_hub_cx_int_div_clk_src = { + .reg = 0x942c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_cx_int_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x911c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x911c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_ahb_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cb_clk = { + .halt_reg = 0x93a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x93a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cb_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x9120, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9120, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_ahb_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_ff_clk = { + .halt_reg = 0x914c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x914c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_ff_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x913c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x913c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x9130, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9130, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x9004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x9144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_demet_clk = { + .halt_reg = 0x900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x900c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_demet_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_demet_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .halt_reg = 0x7000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_aon_clk = { + .halt_reg = 0x93e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x93e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_hub_aon_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_cx_int_clk = { + .halt_reg = 0x9148, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9148, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_hub_cx_int_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_cx_int_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .halt_reg = 0x9150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_memnoc_gfx_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x9134, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9134, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_sleep_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gpu_cc_sa8775p_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CB_CLK] = &gpu_cc_cb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr, + [GPU_CC_DEMET_DIV_CLK_SRC] = &gpu_cc_demet_div_clk_src.clkr, + [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, + [GPU_CC_HUB_AHB_DIV_CLK_SRC] = &gpu_cc_hub_ahb_div_clk_src.clkr, + [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr, + [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr, + [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr, + [GPU_CC_HUB_CX_INT_DIV_CLK_SRC] = &gpu_cc_hub_cx_int_div_clk_src.clkr, + [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, + [GPU_CC_XO_CLK_SRC] = &gpu_cc_xo_clk_src.clkr, +}; + +static struct gdsc cx_gdsc = { + .gdscr = 0x9108, + .gds_hw_ctrl = 0x953c, + .pd = { + .name = "cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE | ALWAYS_ON, +}; + +static struct gdsc gx_gdsc = { + .gdscr = 0x905c, + .pd = { + .name = "gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = AON_RESET | RETAIN_FF_ENABLE, +}; + +static struct gdsc *gpu_cc_sa8775p_gdscs[] = { + [GPU_CC_CX_GDSC] = &cx_gdsc, + [GPU_CC_GX_GDSC] = &gx_gdsc, +}; + +static const struct qcom_reset_map gpu_cc_sa8775p_resets[] = { + [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 }, + [GPUCC_GPU_CC_CB_BCR] = { 0x93a0 }, + [GPUCC_GPU_CC_CX_BCR] = { 0x9104 }, + [GPUCC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 }, + [GPUCC_GPU_CC_FF_BCR] = { 0x9470 }, + [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x9198 }, + [GPUCC_GPU_CC_GMU_BCR] = { 0x9314 }, + [GPUCC_GPU_CC_GX_BCR] = { 0x9058 }, + [GPUCC_GPU_CC_XO_BCR] = { 0x9000 }, +}; + +static const struct regmap_config gpu_cc_sa8775p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9988, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sa8775p_desc = { + .config = &gpu_cc_sa8775p_regmap_config, + .clks = gpu_cc_sa8775p_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sa8775p_clocks), + .resets = gpu_cc_sa8775p_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sa8775p_resets), + .gdscs = gpu_cc_sa8775p_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sa8775p_gdscs), +}; + +static const struct of_device_id gpu_cc_sa8775p_match_table[] = { + { .compatible = "qcom,sa8775p-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sa8775p_match_table); + +static int gpu_cc_sa8775p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sa8775p_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_evo_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_evo_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + return qcom_cc_really_probe(pdev, &gpu_cc_sa8775p_desc, regmap); +} + +static struct platform_driver gpu_cc_sa8775p_driver = { + .probe = gpu_cc_sa8775p_probe, + .driver = { + .name = "gpu_cc-sa8775p", + .of_match_table = gpu_cc_sa8775p_match_table, + }, +}; + +static int __init gpu_cc_sa8775p_init(void) +{ + return platform_driver_register(&gpu_cc_sa8775p_driver); +} +subsys_initcall(gpu_cc_sa8775p_init); + +static void __exit gpu_cc_sa8775p_exit(void) +{ + platform_driver_unregister(&gpu_cc_sa8775p_driver); +} +module_exit(gpu_cc_sa8775p_exit); + +MODULE_DESCRIPTION("SA8775P GPUCC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gpucc-sm6115.c b/drivers/clk/qcom/gpucc-sm6115.c new file mode 100644 index 000000000000..c84727e8352d --- /dev/null +++ b/drivers/clk/qcom/gpucc-sm6115.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GCC_GPU_GPLL0_CLK_SRC, + DT_GCC_GPU_GPLL0_DIV_CLK_SRC, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_AUX2, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL1_OUT_AUX, + P_GPU_CC_PLL1_OUT_MAIN, +}; + +static struct pll_vco default_vco[] = { + { 1000000000, 2000000000, 0 }, +}; + +static struct pll_vco pll1_vco[] = { + { 500000000, 1000000000, 2 }, +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x3e, + .alpha = 0, + .alpha_hi = 0x80, + .vco_val = 0x0 << 20, + .vco_mask = GENMASK(21, 20), + .alpha_en_mask = BIT(24), + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), + .aux2_output_mask = BIT(2), + .config_ctl_val = 0x4001055b, + .test_ctl_hi1_val = 0x1, +}; + +/* 1200MHz configuration */ +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = default_vco, + .num_vco = ARRAY_SIZE(default_vco), + .flags = SUPPORTS_DYNAMIC_UPDATE, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gpu_cc_pll0_out_aux2[] = { + { 0x0, 1 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_aux2 = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_gpu_cc_pll0_out_aux2, + .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll0_out_aux2), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_aux2", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ops, + }, +}; + +/* 640MHz configuration */ +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x21, + .alpha = 0x55555555, + .alpha_hi = 0x55, + .alpha_en_mask = BIT(24), + .vco_val = 0x2 << 20, + .vco_mask = GENMASK(21, 20), + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), + .config_ctl_val = 0x4001055b, + .test_ctl_hi1_val = 0x1, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .vco_table = pll1_vco, + .num_vco = ARRAY_SIZE(pll1_vco), + .flags = SUPPORTS_DYNAMIC_UPDATE, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gpu_cc_pll1_out_aux[] = { + { 0x0, 1 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll1_out_aux = { + .offset = 0x100, + .post_div_shift = 15, + .post_div_table = post_div_table_gpu_cc_pll1_out_aux, + .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll1_out_aux), + .width = 3, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1_out_aux", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_pll1.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_ops, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = P_BI_TCXO }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, + { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_AUX2, 2 }, + { P_GPU_CC_PLL1_OUT_AUX, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = P_BI_TCXO }, + { .hw = &gpu_cc_pll0_out_aux2.clkr.hw }, + { .hw = &gpu_cc_pll1_out_aux.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { + F(320000000, P_GPU_CC_PLL1_OUT_AUX, 2, 0, 0), + F(465000000, P_GPU_CC_PLL1_OUT_AUX, 2, 0, 0), + F(600000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(745000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(820000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(900000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(950000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(980000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpu_cc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_cxo_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_cxo_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpu_cc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x1090, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .halt_reg = 0x5000, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x5000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x100c, + .clamp_io_ctrl = 0x1508, + .resets = (unsigned int []){ GPU_GX_BCR }, + .reset_count = 1, + .pd = { + .name = "gpu_gx_gdsc", + }, + .parent = &gpu_cx_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | SW_RESET | VOTABLE, +}; + +static struct clk_regmap *gpu_cc_sm6115_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL0_OUT_AUX2] = &gpu_cc_pll0_out_aux2.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, + [GPU_CC_PLL1_OUT_AUX] = &gpu_cc_pll1_out_aux.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, +}; + +static const struct qcom_reset_map gpu_cc_sm6115_resets[] = { + [GPU_GX_BCR] = { 0x1008 }, +}; + +static struct gdsc *gpu_cc_sm6115_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sm6115_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sm6115_desc = { + .config = &gpu_cc_sm6115_regmap_config, + .clks = gpu_cc_sm6115_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sm6115_clocks), + .resets = gpu_cc_sm6115_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sm6115_resets), + .gdscs = gpu_cc_sm6115_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sm6115_gdscs), +}; + +static const struct of_device_id gpu_cc_sm6115_match_table[] = { + { .compatible = "qcom,sm6115-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sm6115_match_table); + +static int gpu_cc_sm6115_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sm6115_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_alpha_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_alpha_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* Set recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ + qcom_branch_set_wakeup(regmap, gpu_cc_cx_gmu_clk, 0xf); + qcom_branch_set_sleep(regmap, gpu_cc_cx_gmu_clk, 0xf); + + qcom_branch_set_force_mem_core(regmap, gpu_cc_gx_gfx3d_clk, true); + qcom_branch_set_force_periph_on(regmap, gpu_cc_gx_gfx3d_clk, true); + + return qcom_cc_really_probe(pdev, &gpu_cc_sm6115_desc, regmap); +} + +static struct platform_driver gpu_cc_sm6115_driver = { + .probe = gpu_cc_sm6115_probe, + .driver = { + .name = "sm6115-gpucc", + .of_match_table = gpu_cc_sm6115_match_table, + }, +}; +module_platform_driver(gpu_cc_sm6115_driver); + +MODULE_DESCRIPTION("QTI GPU_CC SM6115 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gpucc-sm6125.c b/drivers/clk/qcom/gpucc-sm6125.c new file mode 100644 index 000000000000..d4f1296a48ef --- /dev/null +++ b/drivers/clk/qcom/gpucc-sm6125.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GCC_GPU_GPLL0_CLK_SRC, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPU_CC_PLL0_2X_CLK, + P_GPU_CC_PLL0_OUT_AUX2, + P_GPU_CC_PLL1_OUT_AUX, + P_GPU_CC_PLL1_OUT_AUX2, +}; + +static struct pll_vco gpu_cc_pll_vco[] = { + { 1000000000, 2000000000, 0 }, + { 500000000, 1000000000, 2 }, +}; + +/* 1020MHz configuration */ +static const struct alpha_pll_config gpu_pll0_config = { + .l = 0x35, + .config_ctl_val = 0x4001055b, + .alpha_hi = 0x20, + .alpha = 0x00, + .alpha_en_mask = BIT(24), + .vco_val = 0x0 << 20, + .vco_mask = 0x3 << 20, + .aux2_output_mask = BIT(2), +}; + +/* 930MHz configuration */ +static const struct alpha_pll_config gpu_pll1_config = { + .l = 0x30, + .config_ctl_val = 0x4001055b, + .alpha_hi = 0x70, + .alpha = 0x00, + .alpha_en_mask = BIT(24), + .vco_val = 0x2 << 20, + .vco_mask = 0x3 << 20, + .aux2_output_mask = BIT(2), +}; + +static struct clk_alpha_pll gpu_cc_pll0_out_aux2 = { + .offset = 0x0, + .vco_table = gpu_cc_pll_vco, + .num_vco = ARRAY_SIZE(gpu_cc_pll_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_aux2", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll gpu_cc_pll1_out_aux2 = { + .offset = 0x100, + .vco_table = gpu_cc_pll_vco, + .num_vco = ARRAY_SIZE(gpu_cc_pll_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], + .flags = SUPPORTS_DYNAMIC_UPDATE, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1_out_aux2", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_AUX2, 2 }, + { P_GPU_CC_PLL1_OUT_AUX2, 4 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll0_out_aux2.clkr.hw }, + { .hw = &gpu_cc_pll1_out_aux2.clkr.hw }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { + F(320000000, P_GPU_CC_PLL1_OUT_AUX2, 2, 0, 0), + F(465000000, P_GPU_CC_PLL1_OUT_AUX2, 2, 0, 0), + F(600000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(745000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(820000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(900000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + F(950000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_gx_gfx3d_clk.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x1090, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .halt_reg = 0x5000, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x5000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x100c, + .pd = { + .name = "gpu_gx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct clk_regmap *gpu_cc_sm6125_clocks[] = { + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_PLL0_OUT_AUX2] = &gpu_cc_pll0_out_aux2.clkr, + [GPU_CC_PLL1_OUT_AUX2] = &gpu_cc_pll1_out_aux2.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, +}; + +static struct gdsc *gpucc_sm6125_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sm6125_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sm6125_desc = { + .config = &gpu_cc_sm6125_regmap_config, + .clks = gpu_cc_sm6125_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sm6125_clocks), + .gdscs = gpucc_sm6125_gdscs, + .num_gdscs = ARRAY_SIZE(gpucc_sm6125_gdscs), +}; + +static const struct of_device_id gpu_cc_sm6125_match_table[] = { + { .compatible = "qcom,sm6125-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sm6125_match_table); + +static int gpu_cc_sm6125_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sm6125_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_alpha_pll_configure(&gpu_cc_pll0_out_aux2, regmap, &gpu_pll0_config); + clk_alpha_pll_configure(&gpu_cc_pll1_out_aux2, regmap, &gpu_pll1_config); + + /* Set recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ + qcom_branch_set_wakeup(regmap, gpu_cc_cx_gmu_clk, 0xf); + qcom_branch_set_sleep(regmap, gpu_cc_cx_gmu_clk, 0xf); + + qcom_branch_set_force_mem_core(regmap, gpu_cc_gx_gfx3d_clk, true); + qcom_branch_set_force_periph_on(regmap, gpu_cc_gx_gfx3d_clk, true); + + return qcom_cc_really_probe(pdev, &gpu_cc_sm6125_desc, regmap); +} + +static struct platform_driver gpu_cc_sm6125_driver = { + .probe = gpu_cc_sm6125_probe, + .driver = { + .name = "gpucc-sm6125", + .of_match_table = gpu_cc_sm6125_match_table, + }, +}; +module_platform_driver(gpu_cc_sm6125_driver); + +MODULE_DESCRIPTION("QTI GPUCC SM6125 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gpucc-sm6375.c b/drivers/clk/qcom/gpucc-sm6375.c new file mode 100644 index 000000000000..d3620344a009 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sm6375.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GCC_GPU_GPLL0_CLK_SRC, + DT_GCC_GPU_GPLL0_DIV_CLK_SRC, + DT_GCC_GPU_SNOC_DVM_GFX_CLK, +}; + +enum { + P_BI_TCXO, + P_GCC_GPU_GPLL0_CLK_SRC, + P_GCC_GPU_GPLL0_DIV_CLK_SRC, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static struct pll_vco lucid_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +/* 532MHz Configuration */ +static const struct alpha_pll_config gpucc_pll0_config = { + .l = 0x1b, + .alpha = 0xb555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x329a299c, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll gpucc_pll0 = { + .offset = 0x0, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpucc_pll0", + .parent_data = &(const struct clk_parent_data){ + .index = P_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_ops, + }, + }, +}; + +/* 514MHz Configuration */ +static const struct alpha_pll_config gpucc_pll1_config = { + .l = 0x1a, + .alpha = 0xc555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x329a299c, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll gpucc_pll1 = { + .offset = 0x100, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpucc_pll1", + .parent_data = &(const struct clk_parent_data){ + .index = P_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_ops, + }, + }, +}; + +static const struct parent_map gpucc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, + { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 }, +}; + +static const struct clk_parent_data gpucc_parent_data_0[] = { + { .index = P_BI_TCXO }, + { .hw = &gpucc_pll0.clkr.hw }, + { .hw = &gpucc_pll1.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, + { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, +}; + +static const struct parent_map gpucc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, +}; + +static const struct clk_parent_data gpucc_parent_data_1[] = { + { .index = P_BI_TCXO }, + { .hw = &gpucc_pll0.clkr.hw }, + { .hw = &gpucc_pll0.clkr.hw }, + { .hw = &gpucc_pll1.clkr.hw }, + { .hw = &gpucc_pll1.clkr.hw }, + { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, +}; + +static const struct freq_tbl ftbl_gpucc_gmu_clk_src[] = { + F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpucc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpucc_parent_map_0, + .freq_tbl = ftbl_gpucc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpucc_gmu_clk_src", + .parent_data = gpucc_parent_data_0, + .num_parents = ARRAY_SIZE(gpucc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpucc_gx_gfx3d_clk_src[] = { + F(266000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(390000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(490000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(770000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(840000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(900000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpucc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpucc_parent_map_1, + .freq_tbl = ftbl_gpucc_gx_gfx3d_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpucc_gx_gfx3d_clk_src", + .parent_data = gpucc_parent_data_1, + .num_parents = ARRAY_SIZE(gpucc_parent_data_1), + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gpucc_ahb_clk = { + .halt_reg = 0x1078, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_ahb_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cx_gfx3d_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpucc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cx_gfx3d_slv_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpucc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpucc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cx_snoc_dvm_clk", + .parent_data = &(const struct clk_parent_data){ + .index = DT_GCC_GPU_SNOC_DVM_GFX_CLK, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_gx_cxo_clk = { + .halt_reg = 0x1060, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_gx_cxo_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_gx_gfx3d_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpucc_gx_gfx3d_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_gx_gmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gpucc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpucc_sleep_clk = { + .halt_reg = 0x1090, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x1090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpucc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .clk_dis_wait_val = 8, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x100c, + .clamp_io_ctrl = 0x1508, + .resets = (unsigned int []){ GPU_GX_BCR, GPU_ACD_BCR, GPU_GX_ACD_MISC_BCR }, + .reset_count = 3, + .pd = { + .name = "gpu_gx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | SW_RESET | AON_RESET, +}; + +static struct clk_regmap *gpucc_sm6375_clocks[] = { + [GPU_CC_AHB_CLK] = &gpucc_ahb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpucc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpucc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpucc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpucc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpucc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpucc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpucc_gmu_clk_src.clkr, + [GPU_CC_GX_CXO_CLK] = &gpucc_gx_cxo_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpucc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpucc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpucc_gx_gmu_clk.clkr, + [GPU_CC_PLL0] = &gpucc_pll0.clkr, + [GPU_CC_PLL1] = &gpucc_pll1.clkr, + [GPU_CC_SLEEP_CLK] = &gpucc_sleep_clk.clkr, +}; + +static const struct qcom_reset_map gpucc_sm6375_resets[] = { + [GPU_GX_BCR] = { 0x1008 }, + [GPU_ACD_BCR] = { 0x1160 }, + [GPU_GX_ACD_MISC_BCR] = { 0x8004 }, +}; + +static struct gdsc *gpucc_sm6375_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpucc_sm6375_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpucc_sm6375_desc = { + .config = &gpucc_sm6375_regmap_config, + .clks = gpucc_sm6375_clocks, + .num_clks = ARRAY_SIZE(gpucc_sm6375_clocks), + .resets = gpucc_sm6375_resets, + .num_resets = ARRAY_SIZE(gpucc_sm6375_resets), + .gdscs = gpucc_sm6375_gdscs, + .num_gdscs = ARRAY_SIZE(gpucc_sm6375_gdscs), +}; + +static const struct of_device_id gpucc_sm6375_match_table[] = { + { .compatible = "qcom,sm6375-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpucc_sm6375_match_table); + +static int gpucc_sm6375_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpucc_sm6375_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_pll_configure(&gpucc_pll0, regmap, &gpucc_pll0_config); + clk_lucid_pll_configure(&gpucc_pll1, regmap, &gpucc_pll1_config); + + return qcom_cc_really_probe(pdev, &gpucc_sm6375_desc, regmap); +} + +static struct platform_driver gpucc_sm6375_driver = { + .probe = gpucc_sm6375_probe, + .driver = { + .name = "gpucc-sm6375", + .of_match_table = gpucc_sm6375_match_table, + }, +}; +module_platform_driver(gpucc_sm6375_driver); + +MODULE_DESCRIPTION("QTI GPUCC SM6375 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/lpassaudiocc-sc7280.c b/drivers/clk/qcom/lpassaudiocc-sc7280.c index 1339f9211a14..134eb1529ede 100644 --- a/drivers/clk/qcom/lpassaudiocc-sc7280.c +++ b/drivers/clk/qcom/lpassaudiocc-sc7280.c @@ -696,6 +696,8 @@ static const struct qcom_cc_desc lpass_cc_sc7280_desc = { .config = &lpass_audio_cc_sc7280_regmap_config, .clks = lpass_cc_sc7280_clocks, .num_clks = ARRAY_SIZE(lpass_cc_sc7280_clocks), + .gdscs = lpass_aon_cc_sc7280_gdscs, + .num_gdscs = ARRAY_SIZE(lpass_aon_cc_sc7280_gdscs), }; static const struct qcom_cc_desc lpass_audio_cc_sc7280_desc = { diff --git a/drivers/clk/qcom/lpasscc-sc7280.c b/drivers/clk/qcom/lpasscc-sc7280.c index 48432010ce24..0df2b29e95e3 100644 --- a/drivers/clk/qcom/lpasscc-sc7280.c +++ b/drivers/clk/qcom/lpasscc-sc7280.c @@ -121,14 +121,18 @@ static int lpass_cc_sc7280_probe(struct platform_device *pdev) goto destroy_pm_clk; } - lpass_regmap_config.name = "qdsp6ss"; - desc = &lpass_qdsp6ss_sc7280_desc; + if (!of_property_read_bool(pdev->dev.of_node, "qcom,adsp-pil-mode")) { + lpass_regmap_config.name = "qdsp6ss"; + lpass_regmap_config.max_register = 0x3f; + desc = &lpass_qdsp6ss_sc7280_desc; - ret = qcom_cc_probe_by_index(pdev, 0, desc); - if (ret) - goto destroy_pm_clk; + ret = qcom_cc_probe_by_index(pdev, 0, desc); + if (ret) + goto destroy_pm_clk; + } lpass_regmap_config.name = "top_cc"; + lpass_regmap_config.max_register = 0x4; desc = &lpass_cc_top_sc7280_desc; ret = qcom_cc_probe_by_index(pdev, 1, desc); diff --git a/drivers/clk/renesas/r8a77970-cpg-mssr.c b/drivers/clk/renesas/r8a77970-cpg-mssr.c index 0f59c84229a8..7e90e94c4b68 100644 --- a/drivers/clk/renesas/r8a77970-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77970-cpg-mssr.c @@ -76,6 +76,7 @@ static const struct cpg_core_clk r8a77970_core_clks[] __initconst = { DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), /* Core Clock Outputs */ + DEF_FIXED("z2", R8A77970_CLK_Z2, CLK_PLL1_DIV4, 1, 1), DEF_FIXED("ztr", R8A77970_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A77970_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A77970_CLK_ZT, CLK_PLL1_DIV2, 4, 1), diff --git a/drivers/clk/renesas/r8a77980-cpg-mssr.c b/drivers/clk/renesas/r8a77980-cpg-mssr.c index 06f925aff407..aaa685ec35df 100644 --- a/drivers/clk/renesas/r8a77980-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77980-cpg-mssr.c @@ -72,6 +72,7 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = { DEF_RATE(".oco", CLK_OCO, 32768), /* Core Clock Outputs */ + DEF_FIXED("z2", R8A77980_CLK_Z2, CLK_PLL2, 4, 1), DEF_FIXED("ztr", R8A77980_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A77980_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), DEF_FIXED("zt", R8A77980_CLK_ZT, CLK_PLL1_DIV2, 4, 1), @@ -150,11 +151,27 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = { DEF_MOD("imp-ocv3", 529, R8A77980_CLK_S1D1), DEF_MOD("imp-ocv2", 531, R8A77980_CLK_S1D1), DEF_MOD("fcpvd0", 603, R8A77980_CLK_S3D1), + DEF_MOD("vin15", 604, R8A77980_CLK_S2D1), + DEF_MOD("vin14", 605, R8A77980_CLK_S2D1), + DEF_MOD("vin13", 608, R8A77980_CLK_S2D1), + DEF_MOD("vin12", 612, R8A77980_CLK_S2D1), + DEF_MOD("vin11", 618, R8A77980_CLK_S2D1), DEF_MOD("vspd0", 623, R8A77980_CLK_S3D1), + DEF_MOD("vin10", 625, R8A77980_CLK_S2D1), + DEF_MOD("vin9", 627, R8A77980_CLK_S2D1), + DEF_MOD("vin8", 628, R8A77980_CLK_S2D1), DEF_MOD("csi41", 715, R8A77980_CLK_CSI0), DEF_MOD("csi40", 716, R8A77980_CLK_CSI0), DEF_MOD("du0", 724, R8A77980_CLK_S2D1), DEF_MOD("lvds", 727, R8A77980_CLK_S2D1), + DEF_MOD("vin7", 804, R8A77980_CLK_S2D1), + DEF_MOD("vin6", 805, R8A77980_CLK_S2D1), + DEF_MOD("vin5", 806, R8A77980_CLK_S2D1), + DEF_MOD("vin4", 807, R8A77980_CLK_S2D1), + DEF_MOD("vin3", 808, R8A77980_CLK_S2D1), + DEF_MOD("vin2", 809, R8A77980_CLK_S2D1), + DEF_MOD("vin1", 810, R8A77980_CLK_S2D1), + DEF_MOD("vin0", 811, R8A77980_CLK_S2D1), DEF_MOD("etheravb", 812, R8A77980_CLK_S3D2), DEF_MOD("gether", 813, R8A77980_CLK_S3D2), DEF_MOD("imp3", 824, R8A77980_CLK_S1D1), @@ -173,6 +190,7 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = { DEF_MOD("gpio0", 912, R8A77980_CLK_CP), DEF_MOD("can-fd", 914, R8A77980_CLK_S3D2), DEF_MOD("rpc-if", 917, R8A77980_CLK_RPCD2), + DEF_MOD("i2c5", 919, R8A77980_CLK_S0D6), DEF_MOD("i2c4", 927, R8A77980_CLK_S0D6), DEF_MOD("i2c3", 928, R8A77980_CLK_S0D6), DEF_MOD("i2c2", 929, R8A77980_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index 24ba9093a72f..3a73f6f911dd 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -167,7 +167,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("du0", 724, R8A77995_CLK_S1D1), DEF_MOD("lvds", 727, R8A77995_CLK_S2D1), DEF_MOD("mlp", 802, R8A77995_CLK_S2D1), - DEF_MOD("vin4", 807, R8A77995_CLK_S1D2), + DEF_MOD("vin4", 807, R8A77995_CLK_S3D1), DEF_MOD("etheravb", 812, R8A77995_CLK_S3D2), DEF_MOD("imr0", 823, R8A77995_CLK_S1D2), DEF_MOD("gpio6", 906, R8A77995_CLK_S3D4), diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index 7fca11204f74..7cc580d67362 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -146,6 +146,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1), DEF_FIXED("vcbusd2", R8A779G0_CLK_VCBUSD2, CLK_VC, 2, 1), DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), + DEF_DIV6P1("csi", R8A779G0_CLK_CSI, CLK_PLL5_DIV4, 0x880), DEF_FIXED("dsiref", R8A779G0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1), DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884), @@ -165,6 +166,8 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("avb1", 212, R8A779G0_CLK_S0D4_HSC), DEF_MOD("avb2", 213, R8A779G0_CLK_S0D4_HSC), DEF_MOD("canfd0", 328, R8A779G0_CLK_SASYNCPERD2), + DEF_MOD("csi40", 331, R8A779G0_CLK_CSI), + DEF_MOD("csi41", 400, R8A779G0_CLK_CSI), DEF_MOD("dis0", 411, R8A779G0_CLK_VIOBUSD2), DEF_MOD("dsitxlink0", 415, R8A779G0_CLK_VIOBUSD2), DEF_MOD("dsitxlink1", 416, R8A779G0_CLK_VIOBUSD2), @@ -181,6 +184,8 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("i2c4", 522, R8A779G0_CLK_S0D6_PER), DEF_MOD("i2c5", 523, R8A779G0_CLK_S0D6_PER), DEF_MOD("irqc", 611, R8A779G0_CLK_CL16M), + DEF_MOD("ispcs0", 612, R8A779G0_CLK_S0D2_VIO), + DEF_MOD("ispcs1", 613, R8A779G0_CLK_S0D2_VIO), DEF_MOD("msi0", 618, R8A779G0_CLK_MSO), DEF_MOD("msi1", 619, R8A779G0_CLK_MSO), DEF_MOD("msi2", 620, R8A779G0_CLK_MSO), @@ -202,6 +207,22 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("tmu3", 716, R8A779G0_CLK_SASYNCPERD2), DEF_MOD("tmu4", 717, R8A779G0_CLK_SASYNCPERD2), DEF_MOD("tpu0", 718, R8A779G0_CLK_SASYNCPERD4), + DEF_MOD("vin00", 730, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin01", 731, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin02", 800, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin03", 801, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin04", 802, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin05", 803, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin06", 804, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin07", 805, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin10", 806, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin11", 807, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin12", 808, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin13", 809, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin14", 810, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin15", 811, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin16", 812, R8A779G0_CLK_S0D4_VIO), + DEF_MOD("vin17", 813, R8A779G0_CLK_S0D4_VIO), DEF_MOD("vspd0", 830, R8A779G0_CLK_VIOBUSD2), DEF_MOD("vspd1", 831, R8A779G0_CLK_VIOBUSD2), DEF_MOD("wdt1:wdt0", 907, R8A779G0_CLK_R), @@ -213,6 +234,9 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("pfc1", 916, R8A779G0_CLK_CL16M), DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M), DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M), + DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M), + DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER), + DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER), }; /* diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 087146f2ee06..40828616f723 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -29,69 +29,189 @@ #define R9A06G032_SYSCTRL_USB_H2MODE (1<<1) #define R9A06G032_SYSCTRL_DMAMUX 0xA0 -struct r9a06g032_gate { - u16 gate, reset, ready, midle, - scon, mirack, mistat; +/** + * struct regbit - describe one bit in a register + * @reg: offset of register relative to base address, + * expressed in units of 32-bit words (not bytes), + * @bit: which bit (0 to 31) in the register + * + * This structure is used to compactly encode the location + * of a single bit in a register. Five bits are needed to + * encode the bit number. With uint16_t data type, this + * leaves 11 bits to encode a register offset up to 2047. + * + * Since registers are aligned on 32-bit boundaries, the + * offset will be specified in 32-bit words rather than bytes. + * This allows encoding an offset up to 0x1FFC (8188) bytes. + * + * Helper macro RB() takes care of converting the register + * offset from bytes to 32-bit words. + */ +struct regbit { + u16 bit:5; + u16 reg:11; }; -/* This is used to describe a clock for instantiation */ +#define RB(_reg, _bit) ((struct regbit) { \ + .reg = (_reg) / 4, \ + .bit = (_bit) \ +}) + +/** + * struct r9a06g032_gate - clock-related control bits + * @gate: clock enable/disable + * @reset: clock module reset (active low) + * @ready: enables NoC forwarding of read/write requests to device, + * (eg. device is ready to handle read/write requests) + * @midle: request to idle the NoC interconnect + * + * Each of these fields describes a single bit in a register, + * which controls some aspect of clock gating. The @gate field + * is mandatory, this one enables/disables the clock. The + * other fields are optional, with zero indicating "not used". + * + * In most cases there is a @reset bit which needs to be + * de-asserted to bring the module out of reset. + * + * Modules may also need to signal when they are @ready to + * handle requests (read/writes) from the NoC interconnect. + * + * Similarly, the @midle bit is used to idle the master. + */ +struct r9a06g032_gate { + struct regbit gate, reset, ready, midle; + /* Unused fields omitted to save space */ + /* struct regbit scon, mirack, mistat */; +}; + +enum gate_type { + K_GATE = 0, /* gate which enable/disable */ + K_FFC, /* fixed factor clock */ + K_DIV, /* divisor */ + K_BITSEL, /* special for UARTs */ + K_DUALGATE /* special for UARTs */ +}; + +/** + * struct r9a06g032_clkdesc - describe a single clock + * @name: string describing this clock + * @managed: boolean indicating if this clock should be + * started/stopped as part of power management + * @type: see enum @gate_type + * @index: the ID of this clock element + * @source: the ID+1 of the parent clock element. + * Root clock uses ID of ~0 (PARENT_ID); + * @gate: clock enable/disable + * @div_min: smallest permitted clock divider + * @div_max: largest permitted clock divider + * @reg: clock divider register offset, in 32-bit words + * @div_table: optional list of fixed clock divider values; + * must be in ascending order, zero for unused + * @div: divisor for fixed-factor clock + * @mul: multiplier for fixed-factor clock + * @group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7 + * @sel: select either g1/r1 or g2/r2 as clock source + * @g1: 1st source gate (clock enable/disable) + * @r1: 1st source reset (module reset) + * @g2: 2nd source gate (clock enable/disable) + * @r2: 2nd source reset (module reset) + * + * Describes a single element in the clock tree hierarchy. + * As there are quite a large number of clock elements, this + * structure is packed tightly to conserve space. + */ struct r9a06g032_clkdesc { const char *name; - uint32_t managed: 1; - uint32_t type: 3; - uint32_t index: 8; - uint32_t source : 8; /* source index + 1 (0 == none) */ - /* these are used to populate the bitsel struct */ + uint32_t managed:1; + enum gate_type type:3; + uint32_t index:8; + uint32_t source:8; /* source index + 1 (0 == none) */ union { + /* type = K_GATE */ struct r9a06g032_gate gate; - /* for dividers */ + /* type = K_DIV */ struct { - unsigned int div_min : 10, div_max : 10, reg: 10; + unsigned int div_min:10, div_max:10, reg:10; u16 div_table[4]; }; - /* For fixed-factor ones */ + /* type = K_FFC */ struct { u16 div, mul; }; - /* for dual gate */ + /* type = K_DUALGATE */ struct { - uint16_t group : 1; - u16 sel, g1, r1, g2, r2; + uint16_t group:1; + struct regbit sel, g1, r1, g2, r2; } dual; }; }; -#define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \ - { .gate = _clk, .reset = _rst, \ - .ready = _rdy, .midle = _midle, \ - .scon = _scon, .mirack = _mirack, .mistat = _mistat } -#define D_GATE(_idx, _n, _src, ...) \ - { .type = K_GATE, .index = R9A06G032_##_idx, \ - .source = 1 + R9A06G032_##_src, .name = _n, \ - .gate = I_GATE(__VA_ARGS__) } -#define D_MODULE(_idx, _n, _src, ...) \ - { .type = K_GATE, .index = R9A06G032_##_idx, \ - .source = 1 + R9A06G032_##_src, .name = _n, \ - .managed = 1, .gate = I_GATE(__VA_ARGS__) } -#define D_ROOT(_idx, _n, _mul, _div) \ - { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \ - .div = _div, .mul = _mul } -#define D_FFC(_idx, _n, _src, _div) \ - { .type = K_FFC, .index = R9A06G032_##_idx, \ - .source = 1 + R9A06G032_##_src, .name = _n, \ - .div = _div, .mul = 1} -#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) \ - { .type = K_DIV, .index = R9A06G032_##_idx, \ - .source = 1 + R9A06G032_##_src, .name = _n, \ - .reg = _reg, .div_min = _min, .div_max = _max, \ - .div_table = { __VA_ARGS__ } } -#define D_UGATE(_idx, _n, _src, _g, _g1, _r1, _g2, _r2) \ - { .type = K_DUALGATE, .index = R9A06G032_##_idx, \ - .source = 1 + R9A06G032_##_src, .name = _n, \ - .dual = { .group = _g, \ - .g1 = _g1, .r1 = _r1, .g2 = _g2, .r2 = _r2 }, } - -enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE }; +/* + * The last three arguments are not currently used, + * but are kept in the r9a06g032_clocks table below. + */ +#define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) { \ + .gate = _clk, \ + .reset = _rst, \ + .ready = _rdy, \ + .midle = _midle, \ + /* .scon = _scon, */ \ + /* .mirack = _mirack, */ \ + /* .mistat = _mistat */ \ +} +#define D_GATE(_idx, _n, _src, ...) { \ + .type = K_GATE, \ + .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, \ + .name = _n, \ + .gate = I_GATE(__VA_ARGS__) \ +} +#define D_MODULE(_idx, _n, _src, ...) { \ + .type = K_GATE, \ + .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, \ + .name = _n, \ + .managed = 1, \ + .gate = I_GATE(__VA_ARGS__) \ +} +#define D_ROOT(_idx, _n, _mul, _div) { \ + .type = K_FFC, \ + .index = R9A06G032_##_idx, \ + .name = _n, \ + .div = _div, \ + .mul = _mul \ +} +#define D_FFC(_idx, _n, _src, _div) { \ + .type = K_FFC, \ + .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, \ + .name = _n, \ + .div = _div, \ + .mul = 1 \ +} +#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) { \ + .type = K_DIV, \ + .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, \ + .name = _n, \ + .reg = _reg, \ + .div_min = _min, \ + .div_max = _max, \ + .div_table = { __VA_ARGS__ } \ +} +#define D_UGATE(_idx, _n, _src, _g, _g1, _r1, _g2, _r2) { \ + .type = K_DUALGATE, \ + .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, \ + .name = _n, \ + .dual = { \ + .group = _g, \ + .g1 = _g1, \ + .r1 = _r1, \ + .g2 = _g2, \ + .r2 = _r2 \ + }, \ +} /* Internal clock IDs */ #define R9A06G032_CLKOUT 0 @@ -160,58 +280,160 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] = { D_DIV(DIV_SDIO1, "div_sdio1", CLKOUT, 75, 20, 128), D_DIV(DIV_SWITCH, "div_switch", CLKOUT, 37, 5, 40), D_DIV(DIV_UART, "div_uart", CLKOUT, 79, 12, 128), - D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, 0x749, 0x74a, 0x74b, 0, 0xae3, 0, 0), - D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, 0x74c, 0x74d, 0x74e, 0, 0xae4, 0, 0), - D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, 0x74f, 0x750, 0x751, 0, 0xae5, 0, 0), - D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, 0x752, 0x753, 0x754, 0, 0xae6, 0, 0), - D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, 0x755, 0x756, 0x757, 0, 0xae7, 0, 0), - D_GATE(CLK_ADC, "clk_adc", DIV_ADC, 0x1ea, 0x1eb, 0, 0, 0, 0, 0), - D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, 0x405, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, 0x483, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, 0x1e6, 0x1e7, 0, 0, 0, 0, 0), - D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, 0x1e8, 0x1e9, 0, 0, 0, 0, 0), - D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, 0x342, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_NAND, "clk_nand", DIV_NAND, 0x284, 0x285, 0, 0, 0, 0, 0), - D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, 0x774, 0x775, 0, 0, 0, 0, 0), - D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, 0x862, 0x863, 0, 0, 0, 0, 0), - D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, 0x864, 0x865, 0, 0, 0, 0, 0), - D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, 0x866, 0x867, 0, 0, 0, 0, 0), - D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, 0x824, 0x825, 0, 0, 0, 0, 0), - D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, 0x826, 0x827, 0, 0, 0, 0, 0), - D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, 0x8a0, 0x8a1, 0x8a2, 0, 0xb60, 0, 0), - D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0), - D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0), - D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0), - D_MODULE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, 0xe6, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0), - D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0), - D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, 0x341, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, 0x64, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, 0x644, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, 0x425, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, 0x860, 0x861, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, 0x7e0, 0x7e1, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, 0x7e2, 0x7e3, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, 0x7e4, 0x7e5, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, 0x7e6, 0x7e7, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, 0x820, 0x821, 0, 0, 0, 0, 0), - D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0), - D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0), + D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, RB(0xe8, 9), + RB(0xe8, 10), RB(0xe8, 11), RB(0x00, 0), + RB(0x15c, 3), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, RB(0xe8, 12), + RB(0xe8, 13), RB(0xe8, 14), RB(0x00, 0), + RB(0x15c, 4), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, RB(0xe8, 15), + RB(0xe8, 16), RB(0xe8, 17), RB(0x00, 0), + RB(0x15c, 5), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, RB(0xe8, 18), + RB(0xe8, 19), RB(0xe8, 20), RB(0x00, 0), + RB(0x15c, 6), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, RB(0xe8, 21), + RB(0xe8, 22), RB(0xe8, 23), RB(0x00, 0), + RB(0x15c, 7), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_ADC, "clk_adc", DIV_ADC, RB(0x3c, 10), + RB(0x3c, 11), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, RB(0x80, 5), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, RB(0x90, 3), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, RB(0x3c, 6), + RB(0x3c, 7), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, RB(0x3c, 8), + RB(0x3c, 9), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, RB(0x68, 2), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_NAND, "clk_nand", DIV_NAND, RB(0x50, 4), + RB(0x50, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, RB(0xec, 20), + RB(0xec, 21), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, RB(0x10c, 2), + RB(0x10c, 3), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, RB(0x10c, 4), + RB(0x10c, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, RB(0x10c, 6), + RB(0x10c, 7), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, RB(0x104, 4), + RB(0x104, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, RB(0x104, 6), + RB(0x104, 7), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, RB(0x114, 0), + RB(0x114, 1), RB(0x114, 2), RB(0x00, 0), + RB(0x16c, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, RB(0x114, 3), + RB(0x114, 4), RB(0x114, 5), RB(0x00, 0), + RB(0x16c, 1), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, RB(0x114, 6), + RB(0x114, 7), RB(0x114, 8), RB(0x00, 0), + RB(0x16c, 2), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, RB(0x114, 9), + RB(0x114, 10), RB(0x114, 11), RB(0x00, 0), + RB(0x16c, 3), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(CLK_PCI_USB, "clk_pci_usb", CLKOUT_D40, RB(0x1c, 6), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, RB(0x54, 4), + RB(0x54, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, RB(0x90, 4), + RB(0x90, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, RB(0x68, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, RB(0x68, 1), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, RB(0x0c, 4), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, RB(0xc8, 4), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, RB(0x84, 5), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, RB(0x10c, 0), + RB(0x10c, 1), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, RB(0xfc, 0), + RB(0xfc, 1), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, RB(0xfc, 2), + RB(0xfc, 3), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, RB(0xfc, 4), + RB(0xfc, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, RB(0xfc, 6), + RB(0xfc, 7), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, RB(0x104, 0), + RB(0x104, 1), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, RB(0x104, 2), + RB(0x104, 3), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, RB(0x130, 2), + RB(0x130, 3), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8), - D_MODULE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441), - D_MODULE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0), - D_MODULE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461), - D_MODULE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0), - D_MODULE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0), - D_MODULE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0), - D_MODULE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0), - D_MODULE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0), - D_MODULE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103), - D_MODULE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101), - D_MODULE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0), - D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05), - D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0), + D_MODULE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, RB(0x80, 0), + RB(0x80, 1), RB(0x00, 0), RB(0x80, 2), + RB(0x00, 0), RB(0x88, 0), RB(0x88, 1)), + D_MODULE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, RB(0xe8, 0), + RB(0xe8, 1), RB(0xe8, 2), RB(0x00, 0), + RB(0x15c, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, RB(0x84, 0), + RB(0x84, 2), RB(0x00, 0), RB(0x84, 1), + RB(0x00, 0), RB(0x8c, 0), RB(0x8c, 1)), + D_MODULE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, RB(0x118, 3), + RB(0x118, 4), RB(0x118, 5), RB(0x00, 0), + RB(0x168, 1), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, RB(0x118, 6), + RB(0x118, 7), RB(0x118, 8), RB(0x00, 0), + RB(0x168, 2), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, RB(0x118, 9), + RB(0x118, 10), RB(0x118, 11), RB(0x00, 0), + RB(0x168, 3), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, RB(0xe8, 3), + RB(0xe8, 4), RB(0xe8, 5), RB(0x00, 0), + RB(0x15c, 1), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, RB(0xe8, 6), + RB(0xe8, 7), RB(0xe8, 8), RB(0x00, 0), + RB(0x15c, 2), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, RB(0x1c, 3), + RB(0x00, 0), RB(0x00, 0), RB(0x1c, 4), + RB(0x00, 0), RB(0x20, 2), RB(0x20, 3)), + D_MODULE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, RB(0x1c, 0), + RB(0x1c, 1), RB(0x00, 0), RB(0x1c, 2), + RB(0x00, 0), RB(0x20, 0), RB(0x20, 1)), + D_MODULE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, RB(0x1c, 5), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, RB(0xf0, 12), + RB(0xf0, 13), RB(0x00, 0), RB(0xf0, 14), + RB(0x00, 0), RB(0x160, 4), RB(0x160, 5)), + D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, RB(0xf0, 9), + RB(0xf0, 10), RB(0xf0, 11), RB(0x00, 0), + RB(0x160, 3), RB(0x00, 0), RB(0x00, 0)), D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4), D_FFC(CLK_ECAT100_D4, "clk_ecat100_d4", CLK_ECAT100, 4), D_FFC(CLK_HSR100_D2, "clk_hsr100_d2", CLK_HSR100, 2), @@ -219,67 +441,187 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] = { D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8), D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2), D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4), - D_MODULE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0), - D_MODULE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0), - D_MODULE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0), - D_MODULE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0), - D_MODULE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0), - D_MODULE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0), - D_MODULE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0), + D_MODULE(HCLK_CAN0, "hclk_can0", CLK_48, RB(0xf0, 3), + RB(0xf0, 4), RB(0xf0, 5), RB(0x00, 0), + RB(0x160, 1), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_CAN1, "hclk_can1", CLK_48, RB(0xf0, 6), + RB(0xf0, 7), RB(0xf0, 8), RB(0x00, 0), + RB(0x160, 2), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, RB(0x3c, 15), + RB(0x3c, 16), RB(0x3c, 17), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, RB(0x3c, 12), + RB(0x3c, 13), RB(0x3c, 14), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_RSV, "hclk_rsv", CLK_48, RB(0xf0, 0), + RB(0xf0, 1), RB(0xf0, 2), RB(0x00, 0), + RB(0x160, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, RB(0x3c, 0), + RB(0x3c, 1), RB(0x3c, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, RB(0x3c, 3), + RB(0x3c, 4), RB(0x3c, 5), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640), - D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1), - D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0), - D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, 0x403, 0x404, 0, 0, 0, 0, 0), - D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0), - D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0), - D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0), - D_MODULE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0), - D_MODULE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0), - D_MODULE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0), - D_MODULE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141), - D_MODULE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1), - D_MODULE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2), - D_MODULE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5), - D_MODULE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2), - D_MODULE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2), - D_MODULE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0), - D_MODULE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0), - D_MODULE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0), - D_MODULE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1), - D_MODULE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0), - D_MODULE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0), - D_MODULE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0), - D_MODULE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0), - D_MODULE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182), - D_MODULE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2), - D_MODULE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25), - D_MODULE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0), - D_MODULE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0), - D_MODULE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0), - D_MODULE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0), - D_MODULE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302), - D_MODULE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2), - D_MODULE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0), - D_MODULE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0xa03, 0, 0xa02, 0, 0, 0), - D_MODULE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82), - D_MODULE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662), - D_MODULE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0), - D_MODULE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0), - D_MODULE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0), - D_MODULE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0), - D_MODULE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0), - D_MODULE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0), - D_MODULE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0), - D_MODULE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0), - D_MODULE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0), - D_MODULE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0), - D_MODULE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0), - D_MODULE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0), - D_MODULE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0), - D_MODULE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0), - D_MODULE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0), - D_MODULE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0), - D_MODULE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0), + D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, RB(0x174, 0), + RB(0x174, 1), RB(0x00, 0), RB(0x174, 2), + RB(0x00, 0), RB(0x178, 0), RB(0x178, 1)), + D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, RB(0x64, 3), + RB(0x64, 4), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, RB(0x80, 3), + RB(0x80, 4), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, RB(0x90, 4), + RB(0x90, 5), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, RB(0x18c, 0), + RB(0x18c, 1), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, RB(0x84, 4), + RB(0x84, 3), RB(0x00, 0), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, RB(0x34, 15), + RB(0x34, 16), RB(0x34, 17), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, RB(0x184, 0), + RB(0x184, 1), RB(0x184, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, RB(0x24, 3), + RB(0x24, 4), RB(0x24, 5), RB(0x00, 0), + RB(0x28, 2), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, RB(0x24, 0), + RB(0x24, 1), RB(0x00, 0), RB(0x24, 2), + RB(0x00, 0), RB(0x28, 0), RB(0x28, 1)), + D_MODULE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, RB(0x64, 0), + RB(0x64, 2), RB(0x00, 0), RB(0x64, 1), + RB(0x00, 0), RB(0x74, 0), RB(0x74, 1)), + D_MODULE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, RB(0x4c, 0), + RB(0x4c, 1), RB(0x4c, 2), RB(0x4c, 3), + RB(0x58, 0), RB(0x58, 1), RB(0x58, 2)), + D_MODULE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, RB(0x4c, 4), + RB(0x4c, 5), RB(0x4c, 6), RB(0x4c, 7), + RB(0x58, 3), RB(0x58, 4), RB(0x58, 5)), + D_MODULE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, RB(0x6c, 0), + RB(0x6c, 1), RB(0x6c, 2), RB(0x6c, 3), + RB(0x78, 0), RB(0x78, 1), RB(0x78, 2)), + D_MODULE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, RB(0x70, 0), + RB(0x70, 1), RB(0x70, 2), RB(0x70, 3), + RB(0x7c, 0), RB(0x7c, 1), RB(0x7c, 2)), + D_MODULE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, RB(0x40, 18), + RB(0x40, 19), RB(0x40, 20), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, RB(0x40, 21), + RB(0x40, 22), RB(0x40, 23), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, RB(0x44, 9), + RB(0x44, 10), RB(0x44, 11), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, RB(0x90, 0), + RB(0x90, 2), RB(0x00, 0), RB(0x90, 1), + RB(0x00, 0), RB(0x98, 0), RB(0x98, 1)), + D_MODULE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, RB(0x34, 9), + RB(0x34, 10), RB(0x34, 11), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, RB(0x34, 12), + RB(0x34, 13), RB(0x34, 14), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, RB(0xf4, 0), + RB(0xf4, 1), RB(0xf4, 2), RB(0x00, 0), + RB(0x164, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, RB(0x2c, 4), + RB(0x2c, 5), RB(0x2c, 6), RB(0x00, 0), + RB(0x30, 3), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, RB(0x2c, 0), + RB(0x2c, 1), RB(0x2c, 2), RB(0x2c, 3), + RB(0x30, 0), RB(0x30, 1), RB(0x30, 2)), + D_MODULE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, RB(0x50, 0), + RB(0x50, 1), RB(0x50, 2), RB(0x50, 3), + RB(0x5c, 0), RB(0x5c, 1), RB(0x5c, 2)), + D_MODULE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, RB(0xf4, 12), + RB(0xf4, 13), RB(0x00, 0), RB(0xf4, 14), + RB(0x00, 0), RB(0x164, 4), RB(0x164, 5)), + D_MODULE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, RB(0x44, 12), + RB(0x44, 13), RB(0x44, 14), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, RB(0x44, 15), + RB(0x44, 16), RB(0x44, 17), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, RB(0xf4, 6), + RB(0xf4, 7), RB(0xf4, 8), RB(0x00, 0), + RB(0x164, 2), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, RB(0xf4, 9), + RB(0xf4, 10), RB(0xf4, 11), RB(0x00, 0), + RB(0x164, 3), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, RB(0x54, 0), + RB(0x54, 1), RB(0x54, 2), RB(0x54, 3), + RB(0x60, 0), RB(0x60, 1), RB(0x60, 2)), + D_MODULE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, RB(0x90, 0), + RB(0x90, 1), RB(0x90, 2), RB(0x90, 3), + RB(0x98, 0), RB(0x98, 1), RB(0x98, 2)), + D_MODULE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, RB(0x154, 0), + RB(0x154, 1), RB(0x154, 2), RB(0x00, 0), + RB(0x170, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, RB(0x140, 0), + RB(0x140, 3), RB(0x00, 0), RB(0x140, 2), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, RB(0x0c, 0), + RB(0x0c, 1), RB(0x0c, 2), RB(0x0c, 3), + RB(0x10, 0), RB(0x10, 1), RB(0x10, 2)), + D_MODULE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, RB(0xc8, 0), + RB(0xc8, 1), RB(0xc8, 2), RB(0xc8, 3), + RB(0xcc, 0), RB(0xcc, 1), RB(0xcc, 2)), + D_MODULE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, RB(0xf4, 3), + RB(0xf4, 4), RB(0xf4, 5), RB(0x00, 0), + RB(0x164, 1), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, RB(0x40, 0), + RB(0x40, 1), RB(0x40, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, RB(0x40, 3), + RB(0x40, 4), RB(0x40, 5), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, RB(0x40, 6), + RB(0x40, 7), RB(0x40, 8), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, RB(0x40, 9), + RB(0x40, 10), RB(0x40, 11), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, RB(0x40, 12), + RB(0x40, 13), RB(0x40, 14), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, RB(0x40, 15), + RB(0x40, 16), RB(0x40, 17), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, RB(0x130, 0), + RB(0x00, 0), RB(0x130, 1), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, RB(0x188, 0), + RB(0x188, 1), RB(0x188, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, RB(0x34, 0), + RB(0x34, 1), RB(0x34, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, RB(0x34, 3), + RB(0x34, 4), RB(0x34, 5), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, RB(0x34, 6), + RB(0x34, 7), RB(0x34, 8), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, RB(0x40, 24), + RB(0x40, 25), RB(0x40, 26), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, RB(0x40, 27), + RB(0x40, 28), RB(0x40, 29), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, RB(0x44, 0), + RB(0x44, 1), RB(0x44, 2), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, RB(0x44, 3), + RB(0x44, 4), RB(0x44, 5), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), + D_MODULE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, RB(0x44, 6), + RB(0x44, 7), RB(0x44, 8), RB(0x00, 0), + RB(0x00, 0), RB(0x00, 0), RB(0x00, 0)), /* * These are not hardware clocks, but are needed to handle the special * case where we have a 'selector bit' that doesn't just change the @@ -291,7 +633,7 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] = { .type = K_BITSEL, .source = 1 + R9A06G032_DIV_UART, /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */ - .dual.sel = ((0x34 / 4) << 5) | 30, + .dual.sel = RB(0x34, 30), .dual.group = 0, }, { @@ -300,17 +642,25 @@ static const struct r9a06g032_clkdesc r9a06g032_clocks[] = { .type = K_BITSEL, .source = 1 + R9A06G032_DIV_P2_PG, /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */ - .dual.sel = ((0xec / 4) << 5) | 24, + .dual.sel = RB(0xec, 24), .dual.group = 1, }, - D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5), - D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, 0x1b6, 0x1b7, 0x1b8, 0x1b9), - D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, 0x1ba, 0x1bb, 0x1bc, 0x1bd), - D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, 0x760, 0x761, 0x762, 0x763), - D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, 0x764, 0x765, 0x766, 0x767), - D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, 0x768, 0x769, 0x76a, 0x76b), - D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, 0x76c, 0x76d, 0x76e, 0x76f), - D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, 0x770, 0x771, 0x772, 0x773), + D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, + RB(0x34, 18), RB(0x34, 19), RB(0x34, 20), RB(0x34, 21)), + D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, + RB(0x34, 22), RB(0x34, 23), RB(0x34, 24), RB(0x34, 25)), + D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, + RB(0x34, 26), RB(0x34, 27), RB(0x34, 28), RB(0x34, 29)), + D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, + RB(0xec, 0), RB(0xec, 1), RB(0xec, 2), RB(0xec, 3)), + D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, + RB(0xec, 4), RB(0xec, 5), RB(0xec, 6), RB(0xec, 7)), + D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, + RB(0xec, 8), RB(0xec, 9), RB(0xec, 10), RB(0xec, 11)), + D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, + RB(0xec, 12), RB(0xec, 13), RB(0xec, 14), RB(0xec, 15)), + D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, + RB(0xec, 16), RB(0xec, 17), RB(0xec, 18), RB(0xec, 19)), }; struct r9a06g032_priv { @@ -343,26 +693,26 @@ int r9a06g032_sysctrl_set_dmamux(u32 mask, u32 val) } EXPORT_SYMBOL_GPL(r9a06g032_sysctrl_set_dmamux); -/* register/bit pairs are encoded as an uint16_t */ -static void -clk_rdesc_set(struct r9a06g032_priv *clocks, - u16 one, unsigned int on) +static void clk_rdesc_set(struct r9a06g032_priv *clocks, + struct regbit rb, unsigned int on) { - u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); - u32 val = readl(reg); + u32 __iomem *reg = clocks->reg + (rb.reg * 4); + u32 val; - val = (val & ~(1U << (one & 0x1f))) | ((!!on) << (one & 0x1f)); + if (!rb.reg && !rb.bit) + return; + + val = readl(reg); + val = (val & ~BIT(rb.bit)) | ((!!on) << rb.bit); writel(val, reg); } -static int -clk_rdesc_get(struct r9a06g032_priv *clocks, - uint16_t one) +static int clk_rdesc_get(struct r9a06g032_priv *clocks, struct regbit rb) { - u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); + u32 __iomem *reg = clocks->reg + (rb.reg * 4); u32 val = readl(reg); - return !!(val & (1U << (one & 0x1f))); + return !!(val & BIT(rb.bit)); } /* @@ -464,13 +814,12 @@ r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks, { unsigned long flags; - WARN_ON(!g->gate); + WARN_ON(!g->gate.reg && !g->gate.bit); spin_lock_irqsave(&clocks->lock, flags); clk_rdesc_set(clocks, g->gate, on); /* De-assert reset */ - if (g->reset) - clk_rdesc_set(clocks, g->reset, 1); + clk_rdesc_set(clocks, g->reset, 1); spin_unlock_irqrestore(&clocks->lock, flags); /* Hardware manual recommends 5us delay after enabling clock & reset */ @@ -480,15 +829,12 @@ r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks, * associated SLVRDY bit in the System Controller that needs to be set * so that the FlexWAY bus fabric passes on the read/write requests. */ - if (g->ready || g->midle) { - spin_lock_irqsave(&clocks->lock, flags); - if (g->ready) - clk_rdesc_set(clocks, g->ready, on); - /* Clear 'Master Idle Request' bit */ - if (g->midle) - clk_rdesc_set(clocks, g->midle, !on); - spin_unlock_irqrestore(&clocks->lock, flags); - } + spin_lock_irqsave(&clocks->lock, flags); + clk_rdesc_set(clocks, g->ready, on); + /* Clear 'Master Idle Request' bit */ + clk_rdesc_set(clocks, g->midle, !on); + spin_unlock_irqrestore(&clocks->lock, flags); + /* Note: We don't wait for FlexWAY Socket Connection signal */ } @@ -512,7 +858,7 @@ static int r9a06g032_clk_gate_is_enabled(struct clk_hw *hw) struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); /* if clock is in reset, the gate might be on, and still not 'be' on */ - if (g->gate.reset && !clk_rdesc_get(g->clocks, g->gate.reset)) + if (g->gate.reset.reg && !clk_rdesc_get(g->clocks, g->gate.reset)) return 0; return clk_rdesc_get(g->clocks, g->gate.gate); @@ -751,7 +1097,7 @@ struct r9a06g032_clk_bitsel { struct clk_hw hw; struct r9a06g032_priv *clocks; u16 index; - u16 selector; /* selector register + bit */ + struct regbit selector; /* selector register + bit */ }; #define to_clk_bitselect(_hw) \ @@ -820,7 +1166,7 @@ struct r9a06g032_clk_dualgate { struct clk_hw hw; struct r9a06g032_priv *clocks; u16 index; - u16 selector; /* selector register + bit */ + struct regbit selector; /* selector register + bit */ struct r9a06g032_gate gate[2]; }; @@ -873,7 +1219,7 @@ static struct clk * r9a06g032_register_dualgate(struct r9a06g032_priv *clocks, const char *parent_name, const struct r9a06g032_clkdesc *desc, - uint16_t sel) + struct regbit sel) { struct r9a06g032_clk_dualgate *g; struct clk *clk; @@ -951,7 +1297,7 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev) struct clk **clks; struct clk *mclk; unsigned int i; - u16 uart_group_sel[2]; + struct regbit uart_group_sel[2]; int error; clocks = devm_kzalloc(dev, sizeof(*clocks), GFP_KERNEL); diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c index 684d8937965e..17c110978e33 100644 --- a/drivers/clk/renesas/rcar-usb2-clock-sel.c +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -125,15 +125,13 @@ static int rcar_usb2_clock_sel_resume(struct device *dev) return 0; } -static int rcar_usb2_clock_sel_remove(struct platform_device *pdev) +static void rcar_usb2_clock_sel_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; of_clk_del_provider(dev->of_node); pm_runtime_put(dev); pm_runtime_disable(dev); - - return 0; } static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) @@ -215,7 +213,7 @@ static struct platform_driver rcar_usb2_clock_sel_driver = { .pm = &rcar_usb2_clock_sel_pm_ops, }, .probe = rcar_usb2_clock_sel_probe, - .remove = rcar_usb2_clock_sel_remove, + .remove_new = rcar_usb2_clock_sel_remove, }; builtin_platform_driver(rcar_usb2_clock_sel_driver); diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index b9f210437ddf..e9c0e341380e 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -61,7 +61,7 @@ static const u16 mstpsr_for_gen4[] = { 0x2E00, 0x2E04, 0x2E08, 0x2E0C, 0x2E10, 0x2E14, 0x2E18, 0x2E1C, 0x2E20, 0x2E24, 0x2E28, 0x2E2C, 0x2E30, 0x2E34, 0x2E38, 0x2E3C, 0x2E40, 0x2E44, 0x2E48, 0x2E4C, 0x2E50, 0x2E54, 0x2E58, 0x2E5C, - 0x2E60, 0x2E64, 0x2E68, 0x2E6C, + 0x2E60, 0x2E64, 0x2E68, 0x2E6C, 0x2E70, 0x2E74, }; /* @@ -77,7 +77,7 @@ static const u16 mstpcr_for_gen4[] = { 0x2D00, 0x2D04, 0x2D08, 0x2D0C, 0x2D10, 0x2D14, 0x2D18, 0x2D1C, 0x2D20, 0x2D24, 0x2D28, 0x2D2C, 0x2D30, 0x2D34, 0x2D38, 0x2D3C, 0x2D40, 0x2D44, 0x2D48, 0x2D4C, 0x2D50, 0x2D54, 0x2D58, 0x2D5C, - 0x2D60, 0x2D64, 0x2D68, 0x2D6C, + 0x2D60, 0x2D64, 0x2D68, 0x2D6C, 0x2D70, 0x2D74, }; /* @@ -103,7 +103,7 @@ static const u16 srcr_for_gen4[] = { 0x2C00, 0x2C04, 0x2C08, 0x2C0C, 0x2C10, 0x2C14, 0x2C18, 0x2C1C, 0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38, 0x2C3C, 0x2C40, 0x2C44, 0x2C48, 0x2C4C, 0x2C50, 0x2C54, 0x2C58, 0x2C5C, - 0x2C60, 0x2C64, 0x2C68, 0x2C6C, + 0x2C60, 0x2C64, 0x2C68, 0x2C6C, 0x2C70, 0x2C74, }; /* @@ -119,7 +119,7 @@ static const u16 srstclr_for_gen4[] = { 0x2C80, 0x2C84, 0x2C88, 0x2C8C, 0x2C90, 0x2C94, 0x2C98, 0x2C9C, 0x2CA0, 0x2CA4, 0x2CA8, 0x2CAC, 0x2CB0, 0x2CB4, 0x2CB8, 0x2CBC, 0x2CC0, 0x2CC4, 0x2CC8, 0x2CCC, 0x2CD0, 0x2CD4, 0x2CD8, 0x2CDC, - 0x2CE0, 0x2CE4, 0x2CE8, 0x2CEC, + 0x2CE0, 0x2CE4, 0x2CE8, 0x2CEC, 0x2CF0, 0x2CF4, }; /** @@ -1127,4 +1127,3 @@ void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks, } MODULE_DESCRIPTION("Renesas CPG/MSSR Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 4bf40f6ccd1d..93b02cdc98c2 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1440,4 +1440,3 @@ static int __init rzg2l_cpg_init(void) subsys_initcall(rzg2l_cpg_init); MODULE_DESCRIPTION("Renesas RZ/G2L CPG Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 306910a3a0d3..9ebd6c451b3d 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1263,7 +1263,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, RK3399_CLKGATE_CON(10), 7, GFLAGS), - COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, 0, + COMPOSITE_NOGATE(SCLK_CIF_OUT, "clk_cifout", mux_clk_cif_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(56), 5, 1, MFLAGS, 0, 5, DFLAGS), /* gic */ diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c index b7ce3fbd6fa6..6994165e0395 100644 --- a/drivers/clk/rockchip/clk-rk3588.c +++ b/drivers/clk/rockchip/clk-rk3588.c @@ -13,15 +13,25 @@ #include "clk.h" /* - * GATE with additional linked clock. Downstream enables the linked clock - * (via runtime PM) whenever the gate is enabled. The downstream implementation - * does this via separate clock nodes for each of the linked gate clocks, - * which leaks parts of the clock tree into DT. It is unclear why this is - * actually needed and things work without it for simple use cases. Thus - * the linked clock is ignored for now. + * Recent Rockchip SoCs have a new hardware block called Native Interface + * Unit (NIU), which gates clocks to devices behind them. These effectively + * need two parent clocks. + * + * Downstream enables the linked clock via runtime PM whenever the gate is + * enabled. This implementation uses separate clock nodes for each of the + * linked gate clocks, which leaks parts of the clock tree into DT. + * + * The GATE_LINK macro instead takes the second parent via 'linkname', but + * ignores the information. Once the clock framework is ready to handle it, the + * information should be passed on here. But since these clocks are required to + * access multiple relevant IP blocks, such as PCIe or USB, we mark all linked + * clocks critical until a better solution is available. This will waste some + * power, but avoids leaking implementation details into DT or hanging the + * system. */ #define GATE_LINK(_id, cname, pname, linkname, f, o, b, gf) \ GATE(_id, cname, pname, f, o, b, gf) +#define RK3588_LINKED_CLK CLK_IS_CRITICAL #define RK3588_GRF_SOC_STATUS0 0x600 @@ -1446,7 +1456,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { COMPOSITE_NODIV(HCLK_NVM_ROOT, "hclk_nvm_root", mux_200m_100m_50m_24m_p, 0, RK3588_CLKSEL_CON(77), 0, 2, MFLAGS, RK3588_CLKGATE_CON(31), 0, GFLAGS), - COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, 0, + COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(77), 7, 1, MFLAGS, 2, 5, DFLAGS, RK3588_CLKGATE_CON(31), 1, GFLAGS), GATE(ACLK_EMMC, "aclk_emmc", "aclk_nvm_root", 0, @@ -1675,13 +1685,13 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { RK3588_CLKGATE_CON(42), 9, GFLAGS), /* vdpu */ - COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, 0, + COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(98), 5, 2, MFLAGS, 0, 5, DFLAGS, RK3588_CLKGATE_CON(44), 0, GFLAGS), COMPOSITE_NODIV(ACLK_VDPU_LOW_ROOT, "aclk_vdpu_low_root", mux_400m_200m_100m_24m_p, 0, RK3588_CLKSEL_CON(98), 7, 2, MFLAGS, RK3588_CLKGATE_CON(44), 1, GFLAGS), - COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, 0, + COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(98), 9, 2, MFLAGS, RK3588_CLKGATE_CON(44), 2, GFLAGS), COMPOSITE(ACLK_JPEG_DECODER_ROOT, "aclk_jpeg_decoder_root", gpll_cpll_aupll_spll_p, 0, @@ -1732,9 +1742,9 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { COMPOSITE(ACLK_RKVENC0_ROOT, "aclk_rkvenc0_root", gpll_cpll_npll_p, 0, RK3588_CLKSEL_CON(102), 7, 2, MFLAGS, 2, 5, DFLAGS, RK3588_CLKGATE_CON(47), 1, GFLAGS), - GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", 0, + GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", RK3588_LINKED_CLK, RK3588_CLKGATE_CON(47), 4, GFLAGS), - GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", 0, + GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", RK3588_LINKED_CLK, RK3588_CLKGATE_CON(47), 5, GFLAGS), COMPOSITE(CLK_RKVENC0_CORE, "clk_rkvenc0_core", gpll_cpll_aupll_npll_p, 0, RK3588_CLKSEL_CON(102), 14, 2, MFLAGS, 9, 5, DFLAGS, @@ -1744,10 +1754,10 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { RK3588_CLKGATE_CON(48), 6, GFLAGS), /* vi */ - COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, 0, + COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(106), 5, 3, MFLAGS, 0, 5, DFLAGS, RK3588_CLKGATE_CON(49), 0, GFLAGS), - COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, 0, + COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(106), 8, 2, MFLAGS, RK3588_CLKGATE_CON(49), 1, GFLAGS), COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_100m_50m_24m_p, 0, @@ -1919,10 +1929,10 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0, RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS, RK3588_CLKGATE_CON(52), 0, GFLAGS), - COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0, + COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(110), 8, 2, MFLAGS, RK3588_CLKGATE_CON(52), 1, GFLAGS), - COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, 0, + COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, RK3588_CLKSEL_CON(110), 10, 2, MFLAGS, RK3588_CLKGATE_CON(52), 2, GFLAGS), COMPOSITE_NODIV(PCLK_VOP_ROOT, "pclk_vop_root", mux_100m_50m_24m_p, 0, @@ -2425,7 +2435,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", "aclk_vi_root", 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", "hclk_vi_root", 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), - GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", "aclk_nvm_root", 0, RK3588_CLKGATE_CON(31), 2, GFLAGS), + GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", "aclk_nvm_root", RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), GATE_LINK(ACLK_USB, "aclk_usb", "aclk_usb_root", "aclk_vo1usb_top_root", 0, RK3588_CLKGATE_CON(42), 2, GFLAGS), GATE_LINK(HCLK_USB, "hclk_usb", "hclk_usb_root", "hclk_vo1usb_top_root", 0, RK3588_CLKGATE_CON(42), 3, GFLAGS), GATE_LINK(ACLK_JPEG_DECODER_PRE, "aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", "aclk_vdpu_root", 0, RK3588_CLKGATE_CON(44), 7, GFLAGS), diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index a8646794575a..4059d9365ae6 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -244,10 +244,8 @@ static struct clk *rockchip_clk_register_frac_branch( div->reg = base + muxdiv_offset; div->mshift = 16; div->mwidth = 16; - div->mmask = GENMASK(div->mwidth - 1, 0) << div->mshift; div->nshift = 0; div->nwidth = 16; - div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift; div->lock = lock; div->approximation = rockchip_fractional_approximation; div_ops = &clk_fractional_divider_ops; diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c index b921b9a1134a..7d8937caf22a 100644 --- a/drivers/clk/samsung/clk-exynos-arm64.c +++ b/drivers/clk/samsung/clk-exynos-arm64.c @@ -10,6 +10,9 @@ */ #include #include +#include +#include +#include #include "clk-exynos-arm64.h" @@ -21,6 +24,19 @@ #define GATE_OFF_START 0x2000 #define GATE_OFF_END 0x2fff +struct exynos_arm64_cmu_data { + struct samsung_clk_reg_dump *clk_save; + unsigned int nr_clk_save; + const struct samsung_clk_reg_dump *clk_suspend; + unsigned int nr_clk_suspend; + + struct clk *clk; + struct clk **pclks; + int nr_pclks; + + struct samsung_clk_provider *ctx; +}; + /** * exynos_arm64_init_clocks - Set clocks initial configuration * @np: CMU device tree node with "reg" property (CMU addr) @@ -56,6 +72,83 @@ static void __init exynos_arm64_init_clocks(struct device_node *np, iounmap(reg_base); } +/** + * exynos_arm64_enable_bus_clk - Enable parent clock of specified CMU + * + * @dev: Device object; may be NULL if this function is not being + * called from platform driver probe function + * @np: CMU device tree node + * @cmu: CMU data + * + * Keep CMU parent clock running (needed for CMU registers access). + * + * Return: 0 on success or a negative error code on failure. + */ +static int __init exynos_arm64_enable_bus_clk(struct device *dev, + struct device_node *np, const struct samsung_cmu_info *cmu) +{ + struct clk *parent_clk; + + if (!cmu->clk_name) + return 0; + + if (dev) { + struct exynos_arm64_cmu_data *data; + + parent_clk = clk_get(dev, cmu->clk_name); + data = dev_get_drvdata(dev); + if (data) + data->clk = parent_clk; + } else { + parent_clk = of_clk_get_by_name(np, cmu->clk_name); + } + + if (IS_ERR(parent_clk)) + return PTR_ERR(parent_clk); + + return clk_prepare_enable(parent_clk); +} + +static int __init exynos_arm64_cmu_prepare_pm(struct device *dev, + const struct samsung_cmu_info *cmu) +{ + struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); + int i; + + data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs, + cmu->nr_clk_regs); + if (!data->clk_save) + return -ENOMEM; + + data->nr_clk_save = cmu->nr_clk_regs; + data->clk_suspend = cmu->suspend_regs; + data->nr_clk_suspend = cmu->nr_suspend_regs; + data->nr_pclks = of_clk_get_parent_count(dev->of_node); + if (!data->nr_pclks) + return 0; + + data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks, + GFP_KERNEL); + if (!data->pclks) { + kfree(data->clk_save); + return -ENOMEM; + } + + for (i = 0; i < data->nr_pclks; i++) { + struct clk *clk = of_clk_get(dev->of_node, i); + + if (IS_ERR(clk)) { + kfree(data->clk_save); + while (--i >= 0) + clk_put(data->pclks[i]); + return PTR_ERR(clk); + } + data->pclks[i] = clk; + } + + return 0; +} + /** * exynos_arm64_register_cmu - Register specified Exynos CMU domain * @dev: Device object; may be NULL if this function is not being @@ -72,23 +165,127 @@ static void __init exynos_arm64_init_clocks(struct device_node *np, void __init exynos_arm64_register_cmu(struct device *dev, struct device_node *np, const struct samsung_cmu_info *cmu) { - /* Keep CMU parent clock running (needed for CMU registers access) */ - if (cmu->clk_name) { - struct clk *parent_clk; + int err; - if (dev) - parent_clk = clk_get(dev, cmu->clk_name); - else - parent_clk = of_clk_get_by_name(np, cmu->clk_name); - - if (IS_ERR(parent_clk)) { - pr_err("%s: could not find bus clock %s; err = %ld\n", - __func__, cmu->clk_name, PTR_ERR(parent_clk)); - } else { - clk_prepare_enable(parent_clk); - } - } + /* + * Try to boot even if the parent clock enablement fails, as it might be + * already enabled by bootloader. + */ + err = exynos_arm64_enable_bus_clk(dev, np, cmu); + if (err) + pr_err("%s: could not enable bus clock %s; err = %d\n", + __func__, cmu->clk_name, err); exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs); samsung_cmu_register_one(np, cmu); } + +/** + * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support + * + * @pdev: Platform device object + * @set_manual: If true, set gate clocks to manual mode + * + * It's a version of exynos_arm64_register_cmu() with PM support. Should be + * called from probe function of platform driver. + * + * Return: 0 on success, or negative error code on error. + */ +int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev, + bool set_manual) +{ + const struct samsung_cmu_info *cmu; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct exynos_arm64_cmu_data *data; + void __iomem *reg_base; + int ret; + + cmu = of_device_get_match_data(dev); + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + ret = exynos_arm64_cmu_prepare_pm(dev, cmu); + if (ret) + return ret; + + /* + * Try to boot even if the parent clock enablement fails, as it might be + * already enabled by bootloader. + */ + ret = exynos_arm64_enable_bus_clk(dev, NULL, cmu); + if (ret) + dev_err(dev, "%s: could not enable bus clock %s; err = %d\n", + __func__, cmu->clk_name, ret); + + if (set_manual) + exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs); + + reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + data->ctx = samsung_clk_init(dev, reg_base, cmu->nr_clk_ids); + + /* + * Enable runtime PM here to allow the clock core using runtime PM + * for the registered clocks. Additionally, we increase the runtime + * PM usage count before registering the clocks, to prevent the + * clock core from runtime suspending the device. + */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + samsung_cmu_register_clocks(data->ctx, cmu); + samsung_clk_of_add_provider(dev->of_node, data->ctx); + pm_runtime_put_sync(dev); + + return 0; +} + +int exynos_arm64_cmu_suspend(struct device *dev) +{ + struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); + int i; + + samsung_clk_save(data->ctx->reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + /* For suspend some registers have to be set to certain values */ + samsung_clk_restore(data->ctx->reg_base, data->clk_suspend, + data->nr_clk_suspend); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + clk_disable_unprepare(data->clk); + + return 0; +} + +int exynos_arm64_cmu_resume(struct device *dev) +{ + struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev); + int i; + + clk_prepare_enable(data->clk); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + samsung_clk_restore(data->ctx->reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + return 0; +} diff --git a/drivers/clk/samsung/clk-exynos-arm64.h b/drivers/clk/samsung/clk-exynos-arm64.h index 0dd174693935..969979e714bc 100644 --- a/drivers/clk/samsung/clk-exynos-arm64.h +++ b/drivers/clk/samsung/clk-exynos-arm64.h @@ -16,5 +16,8 @@ void exynos_arm64_register_cmu(struct device *dev, struct device_node *np, const struct samsung_cmu_info *cmu); +int exynos_arm64_register_cmu_pm(struct platform_device *pdev, bool set_manual); +int exynos_arm64_cmu_suspend(struct device *dev); +int exynos_arm64_cmu_resume(struct device *dev); #endif /* __CLK_EXYNOS_ARM64_H */ diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 9cc127a162ad..7626dff41f6f 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -268,7 +268,7 @@ unregister: return ret; } -static int exynos_audss_clk_remove(struct platform_device *pdev) +static void exynos_audss_clk_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); @@ -277,8 +277,6 @@ static int exynos_audss_clk_remove(struct platform_device *pdev) if (!IS_ERR(epll)) clk_disable_unprepare(epll); - - return 0; } static const struct dev_pm_ops exynos_audss_clk_pm_ops = { @@ -295,7 +293,7 @@ static struct platform_driver exynos_audss_clk_driver = { .pm = &exynos_audss_clk_pm_ops, }, .probe = exynos_audss_clk_probe, - .remove = exynos_audss_clk_remove, + .remove_new = exynos_audss_clk_remove, }; module_platform_driver(exynos_audss_clk_driver); diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index e6d6cbf8c4e6..0cff1c94c35e 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -196,15 +196,13 @@ clks_put: return ret; } -static int exynos_clkout_remove(struct platform_device *pdev) +static void exynos_clkout_remove(struct platform_device *pdev) { struct exynos_clkout *clkout = platform_get_drvdata(pdev); of_clk_del_provider(clkout->np); clk_hw_unregister(clkout->data.hws[0]); iounmap(clkout->reg); - - return 0; } static int __maybe_unused exynos_clkout_suspend(struct device *dev) @@ -235,7 +233,7 @@ static struct platform_driver exynos_clkout_driver = { .pm = &exynos_clkout_pm_ops, }, .probe = exynos_clkout_probe, - .remove = exynos_clkout_remove, + .remove_new = exynos_clkout_remove, }; module_platform_driver(exynos_clkout_driver); diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 22009cb53428..d7dbb3858347 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1251,7 +1251,7 @@ static void __init exynos4_clk_init(struct device_node *np, if (!reg_base) panic("%s: failed to map registers\n", __func__); - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = samsung_clk_init(NULL, reg_base, CLK_NR_CLKS); hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos4_fixed_rate_ext_clks, @@ -1276,7 +1276,7 @@ static void __init exynos4_clk_init(struct device_node *np, exynos4210_vpll_rates; samsung_clk_register_pll(ctx, exynos4210_plls, - ARRAY_SIZE(exynos4210_plls), reg_base); + ARRAY_SIZE(exynos4210_plls)); } else { if (clk_hw_get_rate(hws[CLK_FIN_PLL]) == 24000000) { exynos4x12_plls[apll].rate_table = @@ -1288,7 +1288,7 @@ static void __init exynos4_clk_init(struct device_node *np, } samsung_clk_register_pll(ctx, exynos4x12_plls, - ARRAY_SIZE(exynos4x12_plls), reg_base); + ARRAY_SIZE(exynos4x12_plls)); } samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_clks, diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index 471a6fb82670..1470c15e95da 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -121,8 +121,7 @@ static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev) if (!exynos4x12_save_isp) return -ENOMEM; - ctx = samsung_clk_init(np, reg_base, CLK_NR_ISP_CLKS); - ctx->dev = dev; + ctx = samsung_clk_init(dev, reg_base, CLK_NR_ISP_CLKS); platform_set_drvdata(pdev, ctx); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 113df773ee44..92fb09922f28 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -797,7 +797,7 @@ static void __init exynos5250_clk_init(struct device_node *np) panic("%s: unable to determine soc\n", __func__); } - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = samsung_clk_init(NULL, reg_base, CLK_NR_CLKS); hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos5250_fixed_rate_ext_clks, @@ -815,8 +815,7 @@ static void __init exynos5250_clk_init(struct device_node *np) exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl; samsung_clk_register_pll(ctx, exynos5250_plls, - ARRAY_SIZE(exynos5250_plls), - reg_base); + ARRAY_SIZE(exynos5250_plls)); samsung_clk_register_fixed_rate(ctx, exynos5250_fixed_rate_clks, ARRAY_SIZE(exynos5250_fixed_rate_clks)); samsung_clk_register_fixed_factor(ctx, exynos5250_fixed_factor_clks, diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index caad74dee297..1e0cbf762408 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -1587,7 +1587,7 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5x_soc = soc; - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); + ctx = samsung_clk_init(NULL, reg_base, CLK_NR_CLKS); hws = ctx->clk_data.hws; samsung_clk_of_register_fixed_ext(ctx, exynos5x_fixed_rate_ext_clks, @@ -1606,8 +1606,7 @@ static void __init exynos5x_clk_init(struct device_node *np, else exynos5x_plls[bpll].rate_table = exynos5422_bpll_rate_table; - samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls), - reg_base); + samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls)); samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks, ARRAY_SIZE(exynos5x_fixed_rate_clks)); samsung_clk_register_fixed_factor(ctx, exynos5x_fixed_factor_clks, diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f9daae20f393..ed43233649ae 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos-arm64.h" #include "clk-pll.h" /* @@ -5478,160 +5478,9 @@ static const struct samsung_cmu_info imem_cmu_info __initconst = { .clk_name = "aclk_imem_200", }; -struct exynos5433_cmu_data { - struct samsung_clk_reg_dump *clk_save; - unsigned int nr_clk_save; - const struct samsung_clk_reg_dump *clk_suspend; - unsigned int nr_clk_suspend; - - struct clk *clk; - struct clk **pclks; - int nr_pclks; - - /* must be the last entry */ - struct samsung_clk_provider ctx; -}; - -static int __maybe_unused exynos5433_cmu_suspend(struct device *dev) -{ - struct exynos5433_cmu_data *data = dev_get_drvdata(dev); - int i; - - samsung_clk_save(data->ctx.reg_base, data->clk_save, - data->nr_clk_save); - - for (i = 0; i < data->nr_pclks; i++) - clk_prepare_enable(data->pclks[i]); - - /* for suspend some registers have to be set to certain values */ - samsung_clk_restore(data->ctx.reg_base, data->clk_suspend, - data->nr_clk_suspend); - - for (i = 0; i < data->nr_pclks; i++) - clk_disable_unprepare(data->pclks[i]); - - clk_disable_unprepare(data->clk); - - return 0; -} - -static int __maybe_unused exynos5433_cmu_resume(struct device *dev) -{ - struct exynos5433_cmu_data *data = dev_get_drvdata(dev); - int i; - - clk_prepare_enable(data->clk); - - for (i = 0; i < data->nr_pclks; i++) - clk_prepare_enable(data->pclks[i]); - - samsung_clk_restore(data->ctx.reg_base, data->clk_save, - data->nr_clk_save); - - for (i = 0; i < data->nr_pclks; i++) - clk_disable_unprepare(data->pclks[i]); - - return 0; -} - static int __init exynos5433_cmu_probe(struct platform_device *pdev) { - const struct samsung_cmu_info *info; - struct exynos5433_cmu_data *data; - struct samsung_clk_provider *ctx; - struct device *dev = &pdev->dev; - void __iomem *reg_base; - int i; - - info = of_device_get_match_data(dev); - - data = devm_kzalloc(dev, - struct_size(data, ctx.clk_data.hws, info->nr_clk_ids), - GFP_KERNEL); - if (!data) - return -ENOMEM; - ctx = &data->ctx; - - reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(reg_base)) - return PTR_ERR(reg_base); - - for (i = 0; i < info->nr_clk_ids; ++i) - ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); - - ctx->clk_data.num = info->nr_clk_ids; - ctx->reg_base = reg_base; - ctx->dev = dev; - spin_lock_init(&ctx->lock); - - data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs, - info->nr_clk_regs); - if (!data->clk_save) - return -ENOMEM; - data->nr_clk_save = info->nr_clk_regs; - data->clk_suspend = info->suspend_regs; - data->nr_clk_suspend = info->nr_suspend_regs; - data->nr_pclks = of_clk_get_parent_count(dev->of_node); - - if (data->nr_pclks > 0) { - data->pclks = devm_kcalloc(dev, sizeof(struct clk *), - data->nr_pclks, GFP_KERNEL); - if (!data->pclks) { - kfree(data->clk_save); - return -ENOMEM; - } - for (i = 0; i < data->nr_pclks; i++) { - struct clk *clk = of_clk_get(dev->of_node, i); - - if (IS_ERR(clk)) { - kfree(data->clk_save); - while (--i >= 0) - clk_put(data->pclks[i]); - return PTR_ERR(clk); - } - data->pclks[i] = clk; - } - } - - if (info->clk_name) - data->clk = clk_get(dev, info->clk_name); - clk_prepare_enable(data->clk); - - platform_set_drvdata(pdev, data); - - /* - * Enable runtime PM here to allow the clock core using runtime PM - * for the registered clocks. Additionally, we increase the runtime - * PM usage count before registering the clocks, to prevent the - * clock core from runtime suspending the device. - */ - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - if (info->pll_clks) - samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks, - reg_base); - if (info->mux_clks) - samsung_clk_register_mux(ctx, info->mux_clks, - info->nr_mux_clks); - if (info->div_clks) - samsung_clk_register_div(ctx, info->div_clks, - info->nr_div_clks); - if (info->gate_clks) - samsung_clk_register_gate(ctx, info->gate_clks, - info->nr_gate_clks); - if (info->fixed_clks) - samsung_clk_register_fixed_rate(ctx, info->fixed_clks, - info->nr_fixed_clks); - if (info->fixed_factor_clks) - samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks, - info->nr_fixed_factor_clks); - - samsung_clk_of_add_provider(dev->of_node, ctx); - pm_runtime_put_sync(dev); - - return 0; + return exynos_arm64_register_cmu_pm(pdev, false); } static const struct of_device_id exynos5433_cmu_of_match[] = { @@ -5679,7 +5528,7 @@ static const struct of_device_id exynos5433_cmu_of_match[] = { }; static const struct dev_pm_ops exynos5433_cmu_pm_ops = { - SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume, + SET_RUNTIME_PM_OPS(exynos_arm64_cmu_suspend, exynos_arm64_cmu_resume, NULL) SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c index 541761e96aeb..98b23af7324d 100644 --- a/drivers/clk/samsung/clk-exynos850.c +++ b/drivers/clk/samsung/clk-exynos850.c @@ -36,6 +36,7 @@ #define CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD 0x101c #define CLK_CON_MUX_MUX_CLKCMU_CORE_SSS 0x1020 #define CLK_CON_MUX_MUX_CLKCMU_DPU 0x1034 +#define CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH 0x1038 #define CLK_CON_MUX_MUX_CLKCMU_HSI_BUS 0x103c #define CLK_CON_MUX_MUX_CLKCMU_HSI_MMC_CARD 0x1040 #define CLK_CON_MUX_MUX_CLKCMU_HSI_USB20DRD 0x1044 @@ -57,6 +58,7 @@ #define CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD 0x1828 #define CLK_CON_DIV_CLKCMU_CORE_SSS 0x182c #define CLK_CON_DIV_CLKCMU_DPU 0x1840 +#define CLK_CON_DIV_CLKCMU_G3D_SWITCH 0x1844 #define CLK_CON_DIV_CLKCMU_HSI_BUS 0x1848 #define CLK_CON_DIV_CLKCMU_HSI_MMC_CARD 0x184c #define CLK_CON_DIV_CLKCMU_HSI_USB20DRD 0x1850 @@ -84,6 +86,7 @@ #define CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD 0x2024 #define CLK_CON_GAT_GATE_CLKCMU_CORE_SSS 0x2028 #define CLK_CON_GAT_GATE_CLKCMU_DPU 0x203c +#define CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH 0x2040 #define CLK_CON_GAT_GATE_CLKCMU_HSI_BUS 0x2044 #define CLK_CON_GAT_GATE_CLKCMU_HSI_MMC_CARD 0x2048 #define CLK_CON_GAT_GATE_CLKCMU_HSI_USB20DRD 0x204c @@ -116,6 +119,7 @@ static const unsigned long top_clk_regs[] __initconst = { CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD, CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, CLK_CON_MUX_MUX_CLKCMU_DPU, + CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH, CLK_CON_MUX_MUX_CLKCMU_HSI_BUS, CLK_CON_MUX_MUX_CLKCMU_HSI_MMC_CARD, CLK_CON_MUX_MUX_CLKCMU_HSI_USB20DRD, @@ -137,6 +141,7 @@ static const unsigned long top_clk_regs[] __initconst = { CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD, CLK_CON_DIV_CLKCMU_CORE_SSS, CLK_CON_DIV_CLKCMU_DPU, + CLK_CON_DIV_CLKCMU_G3D_SWITCH, CLK_CON_DIV_CLKCMU_HSI_BUS, CLK_CON_DIV_CLKCMU_HSI_MMC_CARD, CLK_CON_DIV_CLKCMU_HSI_USB20DRD, @@ -164,6 +169,7 @@ static const unsigned long top_clk_regs[] __initconst = { CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD, CLK_CON_GAT_GATE_CLKCMU_CORE_SSS, CLK_CON_GAT_GATE_CLKCMU_DPU, + CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, CLK_CON_GAT_GATE_CLKCMU_HSI_BUS, CLK_CON_GAT_GATE_CLKCMU_HSI_MMC_CARD, CLK_CON_GAT_GATE_CLKCMU_HSI_USB20DRD, @@ -216,6 +222,9 @@ PNAME(mout_core_mmc_embd_p) = { "oscclk", "dout_shared0_div2", "oscclk", "oscclk" }; PNAME(mout_core_sss_p) = { "dout_shared0_div3", "dout_shared1_div3", "dout_shared0_div4", "dout_shared1_div4" }; +/* List of parent clocks for Muxes in CMU_TOP: for CMU_G3D */ +PNAME(mout_g3d_switch_p) = { "dout_shared0_div2", "dout_shared1_div2", + "dout_shared0_div3", "dout_shared1_div3" }; /* List of parent clocks for Muxes in CMU_TOP: for CMU_HSI */ PNAME(mout_hsi_bus_p) = { "dout_shared0_div2", "dout_shared1_div2" }; PNAME(mout_hsi_mmc_card_p) = { "oscclk", "dout_shared0_div2", @@ -283,6 +292,10 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { MUX(CLK_MOUT_DPU, "mout_dpu", mout_dpu_p, CLK_CON_MUX_MUX_CLKCMU_DPU, 0, 2), + /* G3D */ + MUX(CLK_MOUT_G3D_SWITCH, "mout_g3d_switch", mout_g3d_switch_p, + CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH, 0, 2), + /* HSI */ MUX(CLK_MOUT_HSI_BUS, "mout_hsi_bus", mout_hsi_bus_p, CLK_CON_MUX_MUX_CLKCMU_HSI_BUS, 0, 1), @@ -357,6 +370,10 @@ static const struct samsung_div_clock top_div_clks[] __initconst = { DIV(CLK_DOUT_DPU, "dout_dpu", "gout_dpu", CLK_CON_DIV_CLKCMU_DPU, 0, 4), + /* G3D */ + DIV(CLK_DOUT_G3D_SWITCH, "dout_g3d_switch", "gout_g3d_switch", + CLK_CON_DIV_CLKCMU_G3D_SWITCH, 0, 3), + /* HSI */ DIV(CLK_DOUT_HSI_BUS, "dout_hsi_bus", "gout_hsi_bus", CLK_CON_DIV_CLKCMU_HSI_BUS, 0, 4), @@ -417,6 +434,10 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { GATE(CLK_GOUT_DPU, "gout_dpu", "mout_dpu", CLK_CON_GAT_GATE_CLKCMU_DPU, 21, 0, 0), + /* G3D */ + GATE(CLK_GOUT_G3D_SWITCH, "gout_g3d_switch", "mout_g3d_switch", + CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, 21, 0, 0), + /* HSI */ GATE(CLK_GOUT_HSI_BUS, "gout_hsi_bus", "mout_hsi_bus", CLK_CON_GAT_GATE_CLKCMU_HSI_BUS, 21, 0, 0), @@ -591,7 +612,7 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = { CLK_CON_GAT_GOUT_APM_APBIF_GPIO_ALIVE_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CLK_GOUT_PMU_ALIVE_PCLK, "gout_pmu_alive_pclk", "dout_apm_bus", - CLK_CON_GAT_GOUT_APM_APBIF_PMU_ALIVE_PCLK, 21, 0, 0), + CLK_CON_GAT_GOUT_APM_APBIF_PMU_ALIVE_PCLK, 21, CLK_IS_CRITICAL, 0), GATE(CLK_GOUT_SYSREG_APM_PCLK, "gout_sysreg_apm_pclk", "dout_apm_bus", CLK_CON_GAT_GOUT_APM_SYSREG_APM_PCLK, 21, 0, 0), }; @@ -653,6 +674,7 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = { #define CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF4 0x2014 #define CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF5 0x2018 #define CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF6 0x201c +#define CLK_CON_GAT_CLK_AUD_CMU_AUD_PCLK 0x2020 #define CLK_CON_GAT_GOUT_AUD_ABOX_ACLK 0x2048 #define CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_SPDY 0x204c #define CLK_CON_GAT_GOUT_AUD_ABOX_CCLK_ASB 0x2050 @@ -708,6 +730,7 @@ static const unsigned long aud_clk_regs[] __initconst = { CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF4, CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF5, CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_UAIF6, + CLK_CON_GAT_CLK_AUD_CMU_AUD_PCLK, CLK_CON_GAT_GOUT_AUD_ABOX_ACLK, CLK_CON_GAT_GOUT_AUD_ABOX_BCLK_SPDY, CLK_CON_GAT_GOUT_AUD_ABOX_CCLK_ASB, @@ -827,6 +850,9 @@ static const struct samsung_div_clock aud_div_clks[] __initconst = { }; static const struct samsung_gate_clock aud_gate_clks[] __initconst = { + GATE(CLK_GOUT_AUD_CMU_AUD_PCLK, "gout_aud_cmu_aud_pclk", + "dout_aud_busd", + CLK_CON_GAT_CLK_AUD_CMU_AUD_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CLK_GOUT_AUD_CA32_CCLK, "gout_aud_ca32_cclk", "mout_aud_cpu_hch", CLK_CON_GAT_GOUT_AUD_ABOX_CCLK_CA32, 21, 0, 0), GATE(CLK_GOUT_AUD_ASB_CCLK, "gout_aud_asb_cclk", "dout_aud_cpu_aclk", @@ -992,6 +1018,102 @@ static const struct samsung_cmu_info cmgp_cmu_info __initconst = { .clk_name = "gout_clkcmu_cmgp_bus", }; +/* ---- CMU_G3D ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_G3D (0x11400000) */ +#define PLL_LOCKTIME_PLL_G3D 0x0000 +#define PLL_CON0_PLL_G3D 0x0100 +#define PLL_CON3_PLL_G3D 0x010c +#define PLL_CON0_MUX_CLKCMU_G3D_SWITCH_USER 0x0600 +#define CLK_CON_MUX_MUX_CLK_G3D_BUSD 0x1000 +#define CLK_CON_DIV_DIV_CLK_G3D_BUSP 0x1804 +#define CLK_CON_GAT_CLK_G3D_CMU_G3D_PCLK 0x2000 +#define CLK_CON_GAT_CLK_G3D_GPU_CLK 0x2004 +#define CLK_CON_GAT_GOUT_G3D_TZPC_PCLK 0x200c +#define CLK_CON_GAT_GOUT_G3D_GRAY2BIN_CLK 0x2010 +#define CLK_CON_GAT_GOUT_G3D_BUSD_CLK 0x2024 +#define CLK_CON_GAT_GOUT_G3D_BUSP_CLK 0x2028 +#define CLK_CON_GAT_GOUT_G3D_SYSREG_PCLK 0x202c + +static const unsigned long g3d_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_G3D, + PLL_CON0_PLL_G3D, + PLL_CON3_PLL_G3D, + PLL_CON0_MUX_CLKCMU_G3D_SWITCH_USER, + CLK_CON_MUX_MUX_CLK_G3D_BUSD, + CLK_CON_DIV_DIV_CLK_G3D_BUSP, + CLK_CON_GAT_CLK_G3D_CMU_G3D_PCLK, + CLK_CON_GAT_CLK_G3D_GPU_CLK, + CLK_CON_GAT_GOUT_G3D_TZPC_PCLK, + CLK_CON_GAT_GOUT_G3D_GRAY2BIN_CLK, + CLK_CON_GAT_GOUT_G3D_BUSD_CLK, + CLK_CON_GAT_GOUT_G3D_BUSP_CLK, + CLK_CON_GAT_GOUT_G3D_SYSREG_PCLK, +}; + +/* List of parent clocks for Muxes in CMU_G3D */ +PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll" }; +PNAME(mout_g3d_switch_user_p) = { "oscclk", "dout_g3d_switch" }; +PNAME(mout_g3d_busd_p) = { "mout_g3d_pll", "mout_g3d_switch_user" }; + +/* + * Do not provide PLL table to PLL_G3D, as MANUAL_PLL_CTRL bit is not set + * for that PLL by default, so set_rate operation would fail. + */ +static const struct samsung_pll_clock g3d_pll_clks[] __initconst = { + PLL(pll_0818x, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "oscclk", + PLL_LOCKTIME_PLL_G3D, PLL_CON3_PLL_G3D, NULL), +}; + +static const struct samsung_mux_clock g3d_mux_clks[] __initconst = { + MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p, + PLL_CON0_PLL_G3D, 4, 1), + MUX(CLK_MOUT_G3D_SWITCH_USER, "mout_g3d_switch_user", + mout_g3d_switch_user_p, + PLL_CON0_MUX_CLKCMU_G3D_SWITCH_USER, 4, 1), + MUX(CLK_MOUT_G3D_BUSD, "mout_g3d_busd", mout_g3d_busd_p, + CLK_CON_MUX_MUX_CLK_G3D_BUSD, 0, 1), +}; + +static const struct samsung_div_clock g3d_div_clks[] __initconst = { + DIV(CLK_DOUT_G3D_BUSP, "dout_g3d_busp", "mout_g3d_busd", + CLK_CON_DIV_DIV_CLK_G3D_BUSP, 0, 3), +}; + +static const struct samsung_gate_clock g3d_gate_clks[] __initconst = { + GATE(CLK_GOUT_G3D_CMU_G3D_PCLK, "gout_g3d_cmu_g3d_pclk", + "dout_g3d_busp", + CLK_CON_GAT_CLK_G3D_CMU_G3D_PCLK, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_G3D_GPU_CLK, "gout_g3d_gpu_clk", "mout_g3d_busd", + CLK_CON_GAT_CLK_G3D_GPU_CLK, 21, 0, 0), + GATE(CLK_GOUT_G3D_TZPC_PCLK, "gout_g3d_tzpc_pclk", "dout_g3d_busp", + CLK_CON_GAT_GOUT_G3D_TZPC_PCLK, 21, 0, 0), + GATE(CLK_GOUT_G3D_GRAY2BIN_CLK, "gout_g3d_gray2bin_clk", + "mout_g3d_busd", + CLK_CON_GAT_GOUT_G3D_GRAY2BIN_CLK, 21, 0, 0), + GATE(CLK_GOUT_G3D_BUSD_CLK, "gout_g3d_busd_clk", "mout_g3d_busd", + CLK_CON_GAT_GOUT_G3D_BUSD_CLK, 21, 0, 0), + GATE(CLK_GOUT_G3D_BUSP_CLK, "gout_g3d_busp_clk", "dout_g3d_busp", + CLK_CON_GAT_GOUT_G3D_BUSP_CLK, 21, 0, 0), + GATE(CLK_GOUT_G3D_SYSREG_PCLK, "gout_g3d_sysreg_pclk", "dout_g3d_busp", + CLK_CON_GAT_GOUT_G3D_SYSREG_PCLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info g3d_cmu_info __initconst = { + .pll_clks = g3d_pll_clks, + .nr_pll_clks = ARRAY_SIZE(g3d_pll_clks), + .mux_clks = g3d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g3d_mux_clks), + .div_clks = g3d_div_clks, + .nr_div_clks = ARRAY_SIZE(g3d_div_clks), + .gate_clks = g3d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g3d_gate_clks), + .nr_clk_ids = G3D_NR_CLK, + .clk_regs = g3d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), + .clk_name = "dout_g3d_switch", +}; + /* ---- CMU_HSI ------------------------------------------------------------- */ /* Register Offset definitions for CMU_HSI (0x13400000) */ @@ -999,12 +1121,15 @@ static const struct samsung_cmu_info cmgp_cmu_info __initconst = { #define PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER 0x0610 #define PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER 0x0620 #define CLK_CON_MUX_MUX_CLK_HSI_RTC 0x1000 +#define CLK_CON_GAT_CLK_HSI_CMU_HSI_PCLK 0x2000 #define CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV 0x2008 #define CLK_CON_GAT_HSI_USB20DRD_TOP_I_REF_CLK_50 0x200c #define CLK_CON_GAT_HSI_USB20DRD_TOP_I_PHY_REFCLK_26 0x2010 #define CLK_CON_GAT_GOUT_HSI_GPIO_HSI_PCLK 0x2018 #define CLK_CON_GAT_GOUT_HSI_MMC_CARD_I_ACLK 0x2024 #define CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN 0x2028 +#define CLK_CON_GAT_GOUT_HSI_PPMU_ACLK 0x202c +#define CLK_CON_GAT_GOUT_HSI_PPMU_PCLK 0x2030 #define CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK 0x2038 #define CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_ACLK_PHYCTRL_20 0x203c #define CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY 0x2040 @@ -1014,12 +1139,15 @@ static const unsigned long hsi_clk_regs[] __initconst = { PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER, PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER, CLK_CON_MUX_MUX_CLK_HSI_RTC, + CLK_CON_GAT_CLK_HSI_CMU_HSI_PCLK, CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV, CLK_CON_GAT_HSI_USB20DRD_TOP_I_REF_CLK_50, CLK_CON_GAT_HSI_USB20DRD_TOP_I_PHY_REFCLK_26, CLK_CON_GAT_GOUT_HSI_GPIO_HSI_PCLK, CLK_CON_GAT_GOUT_HSI_MMC_CARD_I_ACLK, CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN, + CLK_CON_GAT_GOUT_HSI_PPMU_ACLK, + CLK_CON_GAT_GOUT_HSI_PPMU_PCLK, CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK, CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_ACLK_PHYCTRL_20, CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY, @@ -1045,6 +1173,10 @@ static const struct samsung_mux_clock hsi_mux_clks[] __initconst = { }; static const struct samsung_gate_clock hsi_gate_clks[] __initconst = { + /* TODO: Should be enabled in corresponding driver */ + GATE(CLK_GOUT_HSI_CMU_HSI_PCLK, "gout_hsi_cmu_hsi_pclk", + "mout_hsi_bus_user", + CLK_CON_GAT_CLK_HSI_CMU_HSI_PCLK, 21, CLK_IGNORE_UNUSED, 0), GATE(CLK_GOUT_USB_RTC_CLK, "gout_usb_rtc", "mout_hsi_rtc", CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV, 21, 0, 0), GATE(CLK_GOUT_USB_REF_CLK, "gout_usb_ref", "mout_hsi_usb20drd_user", @@ -1059,6 +1191,10 @@ static const struct samsung_gate_clock hsi_gate_clks[] __initconst = { GATE(CLK_GOUT_MMC_CARD_SDCLKIN, "gout_mmc_card_sdclkin", "mout_hsi_mmc_card_user", CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_HSI_PPMU_ACLK, "gout_hsi_ppmu_aclk", "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_PPMU_ACLK, 21, 0, 0), + GATE(CLK_GOUT_HSI_PPMU_PCLK, "gout_hsi_ppmu_pclk", "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_PPMU_PCLK, 21, 0, 0), GATE(CLK_GOUT_SYSREG_HSI_PCLK, "gout_sysreg_hsi_pclk", "mout_hsi_bus_user", CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK, 21, 0, 0), @@ -1700,6 +1836,9 @@ static const struct of_device_id exynos850_cmu_of_match[] = { }, { .compatible = "samsung,exynos850-cmu-cmgp", .data = &cmgp_cmu_info, + }, { + .compatible = "samsung,exynos850-cmu-g3d", + .data = &g3d_cmu_info, }, { .compatible = "samsung,exynos850-cmu-hsi", .data = &hsi_cmu_info, diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index df7812371d70..74934c6182ce 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1259,8 +1259,7 @@ static const struct clk_ops samsung_pll2650xx_clk_min_ops = { }; static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, - const struct samsung_pll_clock *pll_clk, - void __iomem *base) + const struct samsung_pll_clock *pll_clk) { struct samsung_clk_pll *pll; struct clk_init_data init; @@ -1315,6 +1314,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, init.ops = &samsung_pll35xx_clk_ops; break; case pll_1417x: + case pll_0818x: case pll_0822x: pll->enable_offs = PLL0822X_ENABLE_SHIFT; pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT; @@ -1395,8 +1395,8 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, pll->hw.init = &init; pll->type = pll_clk->type; - pll->lock_reg = base + pll_clk->lock_offset; - pll->con_reg = base + pll_clk->con_offset; + pll->lock_reg = ctx->reg_base + pll_clk->lock_offset; + pll->con_reg = ctx->reg_base + pll_clk->con_offset; ret = clk_hw_register(ctx->dev, &pll->hw); if (ret) { @@ -1412,10 +1412,10 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_list, - unsigned int nr_pll, void __iomem *base) + unsigned int nr_pll) { int cnt; for (cnt = 0; cnt < nr_pll; cnt++) - _samsung_clk_register_pll(ctx, &pll_list[cnt], base); + _samsung_clk_register_pll(ctx, &pll_list[cnt]); } diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 5d5a58d40e7e..0725d485c6ee 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -34,6 +34,7 @@ enum samsung_pll_type { pll_1451x, pll_1452x, pll_1460x, + pll_0818x, pll_0822x, pll_0831x, pll_142xx, diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index d6b432a26d63..d27a1f73f077 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -405,7 +405,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, panic("%s: failed to map registers\n", __func__); } - ctx = samsung_clk_init(np, reg_base, NR_CLKS); + ctx = samsung_clk_init(NULL, reg_base, NR_CLKS); hws = ctx->clk_data.hws; /* Register external clocks. */ @@ -414,7 +414,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, /* Register PLLs. */ samsung_clk_register_pll(ctx, s3c64xx_pll_clks, - ARRAY_SIZE(s3c64xx_pll_clks), reg_base); + ARRAY_SIZE(s3c64xx_pll_clks)); /* Register common internal clocks. */ samsung_clk_register_fixed_rate(ctx, s3c64xx_fixed_rate_clks, diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c index 4425186bdcab..cd85342e4ddb 100644 --- a/drivers/clk/samsung/clk-s5pv210.c +++ b/drivers/clk/samsung/clk-s5pv210.c @@ -743,7 +743,7 @@ static void __init __s5pv210_clk_init(struct device_node *np, struct samsung_clk_provider *ctx; struct clk_hw **hws; - ctx = samsung_clk_init(np, reg_base, NR_CLKS); + ctx = samsung_clk_init(NULL, reg_base, NR_CLKS); hws = ctx->clk_data.hws; samsung_clk_register_mux(ctx, early_mux_clks, @@ -753,7 +753,7 @@ static void __init __s5pv210_clk_init(struct device_node *np, samsung_clk_register_fixed_rate(ctx, s5p6442_frate_clks, ARRAY_SIZE(s5p6442_frate_clks)); samsung_clk_register_pll(ctx, s5p6442_pll_clks, - ARRAY_SIZE(s5p6442_pll_clks), reg_base); + ARRAY_SIZE(s5p6442_pll_clks)); samsung_clk_register_mux(ctx, s5p6442_mux_clks, ARRAY_SIZE(s5p6442_mux_clks)); samsung_clk_register_div(ctx, s5p6442_div_clks, @@ -764,7 +764,7 @@ static void __init __s5pv210_clk_init(struct device_node *np, samsung_clk_register_fixed_rate(ctx, s5pv210_frate_clks, ARRAY_SIZE(s5pv210_frate_clks)); samsung_clk_register_pll(ctx, s5pv210_pll_clks, - ARRAY_SIZE(s5pv210_pll_clks), reg_base); + ARRAY_SIZE(s5pv210_pll_clks)); samsung_clk_register_mux(ctx, s5pv210_mux_clks, ARRAY_SIZE(s5pv210_mux_clks)); samsung_clk_register_div(ctx, s5pv210_div_clks, diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index bca4731b14ea..b6701905f254 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -53,8 +53,18 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( return rd; } -/* setup the essentials required to support clock lookup using ccf */ -struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np, +/** + * samsung_clk_init() - Create and initialize a clock provider object + * @dev: CMU device to enable runtime PM, or NULL if RPM is not needed + * @base: Start address (mapped) of CMU registers + * @nr_clks: Total clock count to allocate in clock provider object + * + * Setup the essentials required to support clock lookup using Common Clock + * Framework. + * + * Return: Allocated and initialized clock provider object. + */ +struct samsung_clk_provider * __init samsung_clk_init(struct device *dev, void __iomem *base, unsigned long nr_clks) { struct samsung_clk_provider *ctx; @@ -67,6 +77,7 @@ struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np, for (i = 0; i < nr_clks; ++i) ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); + ctx->dev = dev; ctx->reg_base = base; ctx->clk_data.num = nr_clks; spin_lock_init(&ctx->lock); @@ -324,6 +335,33 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base, } #endif +/** + * samsung_cmu_register_clocks() - Register all clocks provided in CMU object + * @ctx: Clock provider object + * @cmu: CMU object with clocks to register + */ +void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, + const struct samsung_cmu_info *cmu) +{ + if (cmu->pll_clks) + samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks); + if (cmu->mux_clks) + samsung_clk_register_mux(ctx, cmu->mux_clks, cmu->nr_mux_clks); + if (cmu->div_clks) + samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks); + if (cmu->gate_clks) + samsung_clk_register_gate(ctx, cmu->gate_clks, + cmu->nr_gate_clks); + if (cmu->fixed_clks) + samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks, + cmu->nr_fixed_clks); + if (cmu->fixed_factor_clks) + samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks, + cmu->nr_fixed_factor_clks); + if (cmu->cpu_clks) + samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks); +} + /* * Common function which registers plls, muxes, dividers and gates * for each CMU. It also add CMU register list to register cache. @@ -341,31 +379,13 @@ struct samsung_clk_provider * __init samsung_cmu_register_one( return NULL; } - ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids); + ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids); + samsung_cmu_register_clocks(ctx, cmu); - if (cmu->pll_clks) - samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks, - reg_base); - if (cmu->mux_clks) - samsung_clk_register_mux(ctx, cmu->mux_clks, - cmu->nr_mux_clks); - if (cmu->div_clks) - samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks); - if (cmu->gate_clks) - samsung_clk_register_gate(ctx, cmu->gate_clks, - cmu->nr_gate_clks); - if (cmu->fixed_clks) - samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks, - cmu->nr_fixed_clks); - if (cmu->fixed_factor_clks) - samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks, - cmu->nr_fixed_factor_clks); if (cmu->clk_regs) samsung_clk_extended_sleep_init(reg_base, cmu->clk_regs, cmu->nr_clk_regs, cmu->suspend_regs, cmu->nr_suspend_regs); - if (cmu->cpu_clks) - samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index b46e83a2581f..ab9c3d7a25b3 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -16,6 +16,7 @@ /** * struct samsung_clk_provider: information about clock provider * @reg_base: virtual address for the register base. + * @dev: clock provider device needed for runtime PM. * @lock: maintains exclusion between callbacks for a given clock-provider. * @clk_data: holds clock related data like clk_hw* and number of clocks. */ @@ -337,9 +338,8 @@ struct samsung_cmu_info { const char *clk_name; }; -struct samsung_clk_provider * samsung_clk_init( - struct device_node *np, void __iomem *base, - unsigned long nr_clks); +struct samsung_clk_provider *samsung_clk_init(struct device *dev, + void __iomem *base, unsigned long nr_clks); void samsung_clk_of_add_provider(struct device_node *np, struct samsung_clk_provider *ctx); void samsung_clk_of_register_fixed_ext( @@ -373,10 +373,12 @@ void samsung_clk_register_gate(struct samsung_clk_provider *ctx, unsigned int nr_clk); void samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_list, - unsigned int nr_clk, void __iomem *base); + unsigned int nr_clk); void samsung_clk_register_cpu(struct samsung_clk_provider *ctx, const struct samsung_cpu_clock *list, unsigned int nr_clk); +void samsung_cmu_register_clocks(struct samsung_clk_provider *ctx, + const struct samsung_cmu_info *cmu); struct samsung_clk_provider *samsung_cmu_register_one( struct device_node *, const struct samsung_cmu_info *); diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index b7fde0aadfcb..2322f634a910 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -2,8 +2,8 @@ menuconfig CLK_SIFIVE bool "SiFive SoC driver support" - depends on SOC_SIFIVE || COMPILE_TEST - default SOC_SIFIVE + depends on ARCH_SIFIVE || COMPILE_TEST + default ARCH_SIFIVE help SoC drivers for SiFive Linux-capable SoCs. @@ -11,7 +11,7 @@ if CLK_SIFIVE config CLK_SIFIVE_PRCI bool "PRCI driver for SiFive SoCs" - default SOC_SIFIVE + default ARCH_SIFIVE select RESET_CONTROLLER select RESET_SIMPLE select CLK_ANALOGBITS_WRPLL_CLN28HPC diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c index 7cdf2f07c79b..06f129c160bc 100644 --- a/drivers/clk/socfpga/clk-gate-a10.c +++ b/drivers/clk/socfpga/clk-gate-a10.c @@ -40,7 +40,7 @@ static struct clk_ops gateclk_ops = { }; static void __init __socfpga_gate_init(struct device_node *node, - const struct clk_ops *ops) + const struct clk_ops *ops) { u32 clk_gate[2]; u32 div_reg[3]; @@ -94,13 +94,25 @@ static void __init __socfpga_gate_init(struct device_node *node, socfpga_clk->hw.hw.init = &init; hw_clk = &socfpga_clk->hw.hw; - if (clk_hw_register(NULL, hw_clk)) { - kfree(socfpga_clk); - return; + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); - if (WARN_ON(rc)) - return; + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { + pr_err("Could not register clock provider for node:%s\n", + clk_name); + goto err_of_clk_add_hw_provider; + } + + return; + +err_of_clk_add_hw_provider: + clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(socfpga_clk); } void __init socfpga_a10_gate_init(struct device_node *node) diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 0c18c55edf8c..32ccda960f28 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -126,17 +126,14 @@ void __init socfpga_gate_init(struct device_node *node) struct clk_init_data init; struct clk_ops *ops; int rc; - int err; socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); if (WARN_ON(!socfpga_clk)) return; ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL); - if (WARN_ON(!ops)) { - kfree(socfpga_clk); - return; - } + if (WARN_ON(!ops)) + goto err_kmemdup; rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2); if (rc) @@ -182,13 +179,25 @@ void __init socfpga_gate_init(struct device_node *node) hw_clk = &socfpga_clk->hw.hw; - err = clk_hw_register(NULL, hw_clk); - if (err) { - kfree(ops); - kfree(socfpga_clk); - return; + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); - if (WARN_ON(rc)) - return; + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { + pr_err("Could not register clock provider for node:%s\n", + clk_name); + goto err_of_clk_add_hw_provider; + } + + return; + +err_of_clk_add_hw_provider: + clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(ops); +err_kmemdup: + kfree(socfpga_clk); } diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c index b9cdde4b8441..64cc70b970b7 100644 --- a/drivers/clk/socfpga/clk-periph-a10.c +++ b/drivers/clk/socfpga/clk-periph-a10.c @@ -57,8 +57,8 @@ static const struct clk_ops periclk_ops = { .get_parent = clk_periclk_get_parent, }; -static __init void __socfpga_periph_init(struct device_node *node, - const struct clk_ops *ops) +static void __init __socfpga_periph_init(struct device_node *node, + const struct clk_ops *ops) { u32 reg; struct clk_hw *hw_clk; @@ -106,21 +106,25 @@ static __init void __socfpga_periph_init(struct device_node *node, hw_clk = &periph_clk->hw.hw; - if (clk_hw_register(NULL, hw_clk)) { - kfree(periph_clk); - return; + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); - if (rc < 0) { + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { pr_err("Could not register clock provider for node:%s\n", clk_name); - goto err_clk; + goto err_of_clk_add_hw_provider; } return; -err_clk: +err_of_clk_add_hw_provider: clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(periph_clk); } void __init socfpga_a10_periph_init(struct device_node *node) diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c index 43707e2d7248..6a4075147b9c 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c @@ -47,8 +47,8 @@ static const struct clk_ops periclk_ops = { .get_parent = clk_periclk_get_parent, }; -static __init void __socfpga_periph_init(struct device_node *node, - const struct clk_ops *ops) +static void __init __socfpga_periph_init(struct device_node *node, + const struct clk_ops *ops) { u32 reg; struct clk_hw *hw_clk; @@ -96,11 +96,25 @@ static __init void __socfpga_periph_init(struct device_node *node, periph_clk->hw.hw.init = &init; hw_clk = &periph_clk->hw.hw; - if (clk_hw_register(NULL, hw_clk)) { - kfree(periph_clk); - return; + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { + pr_err("Could not register clock provider for node:%s\n", + clk_name); + goto err_of_clk_add_hw_provider; + } + + return; + +err_of_clk_add_hw_provider: + clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(periph_clk); } void __init socfpga_periph_init(struct device_node *node) diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index bee0f7da5b6e..b028f25c658a 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -63,8 +63,8 @@ static const struct clk_ops clk_pll_ops = { .get_parent = clk_pll_get_parent, }; -static struct clk_hw * __init __socfpga_pll_init(struct device_node *node, - const struct clk_ops *ops) +static void __init __socfpga_pll_init(struct device_node *node, + const struct clk_ops *ops) { u32 reg; struct clk_hw *hw_clk; @@ -73,13 +73,14 @@ static struct clk_hw * __init __socfpga_pll_init(struct device_node *node, const char *parent_name[SOCFGPA_MAX_PARENTS]; struct clk_init_data init; struct device_node *clkmgr_np; + int rc; int i = 0; of_property_read_u32(node, "reg", ®); pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); if (WARN_ON(!pll_clk)) - return NULL; + return; clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0); @@ -103,12 +104,25 @@ static struct clk_hw * __init __socfpga_pll_init(struct device_node *node, pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA; hw_clk = &pll_clk->hw.hw; - if (clk_hw_register(NULL, hw_clk)) { - kfree(pll_clk); - return NULL; + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); - return hw_clk; + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { + pr_err("Could not register clock provider for node:%s\n", + clk_name); + goto err_of_clk_add_hw_provider; + } + + return; + +err_of_clk_add_hw_provider: + clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(pll_clk); } void __init socfpga_a10_pll_init(struct device_node *node) diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index 127cc849c5ee..9dcc1b2d2cc0 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -70,8 +70,8 @@ static const struct clk_ops clk_pll_ops = { .get_parent = clk_pll_get_parent, }; -static __init struct clk_hw *__socfpga_pll_init(struct device_node *node, - const struct clk_ops *ops) +static void __init __socfpga_pll_init(struct device_node *node, + const struct clk_ops *ops) { u32 reg; struct clk_hw *hw_clk; @@ -80,13 +80,13 @@ static __init struct clk_hw *__socfpga_pll_init(struct device_node *node, const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; struct device_node *clkmgr_np; - int err; + int rc; of_property_read_u32(node, "reg", ®); pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); if (WARN_ON(!pll_clk)) - return NULL; + return; clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_base_addr = of_iomap(clkmgr_np, 0); @@ -108,13 +108,25 @@ static __init struct clk_hw *__socfpga_pll_init(struct device_node *node, hw_clk = &pll_clk->hw.hw; - err = clk_hw_register(NULL, hw_clk); - if (err) { - kfree(pll_clk); - return ERR_PTR(err); + rc = clk_hw_register(NULL, hw_clk); + if (rc) { + pr_err("Could not register clock:%s\n", clk_name); + goto err_clk_hw_register; } - of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); - return hw_clk; + + rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk); + if (rc) { + pr_err("Could not register clock provider for node:%s\n", + clk_name); + goto err_of_clk_add_hw_provider; + } + + return; + +err_of_clk_add_hw_provider: + clk_hw_unregister(hw_clk); +err_clk_hw_register: + kfree(pll_clk); } void __init socfpga_pll_init(struct device_node *node) diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c index 2bfbab8db94b..16142fbb7a47 100644 --- a/drivers/clk/sprd/common.c +++ b/drivers/clk/sprd/common.c @@ -45,7 +45,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev, struct resource *res; struct regmap_config reg_config = sprdclk_regmap_config; - if (of_find_property(node, "sprd,syscon", NULL)) { + if (of_property_present(node, "sprd,syscon")) { regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); if (IS_ERR(regmap)) { pr_err("%s: failed to get syscon regmap\n", __func__); diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig index 003bd2d56ce7..5d2333106f13 100644 --- a/drivers/clk/starfive/Kconfig +++ b/drivers/clk/starfive/Kconfig @@ -1,9 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 +config CLK_STARFIVE_JH71X0 + bool + config CLK_STARFIVE_JH7100 bool "StarFive JH7100 clock support" - depends on SOC_STARFIVE || COMPILE_TEST - default SOC_STARFIVE + depends on ARCH_STARFIVE || COMPILE_TEST + select CLK_STARFIVE_JH71X0 + default ARCH_STARFIVE help Say yes here to support the clock controller on the StarFive JH7100 SoC. @@ -11,7 +15,27 @@ config CLK_STARFIVE_JH7100 config CLK_STARFIVE_JH7100_AUDIO tristate "StarFive JH7100 audio clock support" depends on CLK_STARFIVE_JH7100 - default m if SOC_STARFIVE + select CLK_STARFIVE_JH71X0 + default m if ARCH_STARFIVE help Say Y or M here to support the audio clocks on the StarFive JH7100 SoC. + +config CLK_STARFIVE_JH7110_SYS + bool "StarFive JH7110 system clock support" + depends on ARCH_STARFIVE || COMPILE_TEST + select AUXILIARY_BUS + select CLK_STARFIVE_JH71X0 + select RESET_STARFIVE_JH7110 if RESET_CONTROLLER + default ARCH_STARFIVE + help + Say yes here to support the system clock controller on the + StarFive JH7110 SoC. + +config CLK_STARFIVE_JH7110_AON + tristate "StarFive JH7110 always-on clock support" + depends on CLK_STARFIVE_JH7110_SYS + default m if ARCH_STARFIVE + help + Say yes here to support the always-on clock controller on the + StarFive JH7110 SoC. diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile index 0fa8ecb9ec1c..f3df7d957b1e 100644 --- a/drivers/clk/starfive/Makefile +++ b/drivers/clk/starfive/Makefile @@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -# StarFive Clock +obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o + obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o + +obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o +obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c index 8473a65e219b..02aefb7264f8 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c +++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c @@ -16,7 +16,7 @@ #include -#include "clk-starfive-jh7100.h" +#include "clk-starfive-jh71x0.h" /* external clocks */ #define JH7100_AUDCLK_AUDIO_SRC (JH7100_AUDCLK_END + 0) @@ -28,66 +28,66 @@ #define JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD (JH7100_AUDCLK_END + 6) #define JH7100_AUDCLK_VAD_INTMEM (JH7100_AUDCLK_END + 7) -static const struct jh7100_clk_data jh7100_audclk_data[] = { - JH7100__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2, +static const struct jh71x0_clk_data jh7100_audclk_data[] = { + JH71X0__GMD(JH7100_AUDCLK_ADC_MCLK, "adc_mclk", 0, 15, 2, JH7100_AUDCLK_AUDIO_SRC, JH7100_AUDCLK_AUDIO_12288), - JH7100__GMD(JH7100_AUDCLK_I2S1_MCLK, "i2s1_mclk", 0, 15, 2, + JH71X0__GMD(JH7100_AUDCLK_I2S1_MCLK, "i2s1_mclk", 0, 15, 2, JH7100_AUDCLK_AUDIO_SRC, JH7100_AUDCLK_AUDIO_12288), - JH7100_GATE(JH7100_AUDCLK_I2SADC_APB, "i2sadc_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100_MDIV(JH7100_AUDCLK_I2SADC_BCLK, "i2sadc_bclk", 31, 2, + JH71X0_GATE(JH7100_AUDCLK_I2SADC_APB, "i2sadc_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2SADC_BCLK, "i2sadc_bclk", 31, 2, JH7100_AUDCLK_ADC_MCLK, JH7100_AUDCLK_I2SADC_BCLK_IOPAD), - JH7100__INV(JH7100_AUDCLK_I2SADC_BCLK_N, "i2sadc_bclk_n", JH7100_AUDCLK_I2SADC_BCLK), - JH7100_MDIV(JH7100_AUDCLK_I2SADC_LRCLK, "i2sadc_lrclk", 63, 3, + JH71X0__INV(JH7100_AUDCLK_I2SADC_BCLK_N, "i2sadc_bclk_n", JH7100_AUDCLK_I2SADC_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2SADC_LRCLK, "i2sadc_lrclk", 63, 3, JH7100_AUDCLK_I2SADC_BCLK_N, JH7100_AUDCLK_I2SADC_LRCLK_IOPAD, JH7100_AUDCLK_I2SADC_BCLK), - JH7100_GATE(JH7100_AUDCLK_PDM_APB, "pdm_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100__GMD(JH7100_AUDCLK_PDM_MCLK, "pdm_mclk", 0, 15, 2, + JH71X0_GATE(JH7100_AUDCLK_PDM_APB, "pdm_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_PDM_MCLK, "pdm_mclk", 0, 15, 2, JH7100_AUDCLK_AUDIO_SRC, JH7100_AUDCLK_AUDIO_12288), - JH7100_GATE(JH7100_AUDCLK_I2SVAD_APB, "i2svad_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100__GMD(JH7100_AUDCLK_SPDIF, "spdif", 0, 15, 2, + JH71X0_GATE(JH7100_AUDCLK_I2SVAD_APB, "i2svad_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_SPDIF, "spdif", 0, 15, 2, JH7100_AUDCLK_AUDIO_SRC, JH7100_AUDCLK_AUDIO_12288), - JH7100_GATE(JH7100_AUDCLK_SPDIF_APB, "spdif_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100_GATE(JH7100_AUDCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100__GMD(JH7100_AUDCLK_DAC_MCLK, "dac_mclk", 0, 15, 2, + JH71X0_GATE(JH7100_AUDCLK_SPDIF_APB, "spdif_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_GATE(JH7100_AUDCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__GMD(JH7100_AUDCLK_DAC_MCLK, "dac_mclk", 0, 15, 2, JH7100_AUDCLK_AUDIO_SRC, JH7100_AUDCLK_AUDIO_12288), - JH7100_GATE(JH7100_AUDCLK_I2SDAC_APB, "i2sdac_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100_MDIV(JH7100_AUDCLK_I2SDAC_BCLK, "i2sdac_bclk", 31, 2, + JH71X0_GATE(JH7100_AUDCLK_I2SDAC_APB, "i2sdac_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_BCLK, "i2sdac_bclk", 31, 2, JH7100_AUDCLK_DAC_MCLK, JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), - JH7100__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK), - JH7100_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2, + JH71X0__INV(JH7100_AUDCLK_I2SDAC_BCLK_N, "i2sdac_bclk_n", JH7100_AUDCLK_I2SDAC_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2SDAC_LRCLK, "i2sdac_lrclk", 31, 2, JH7100_AUDCLK_I2S1_MCLK, JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), - JH7100_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2, + JH71X0_GATE(JH7100_AUDCLK_I2S1_APB, "i2s1_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0_MDIV(JH7100_AUDCLK_I2S1_BCLK, "i2s1_bclk", 31, 2, JH7100_AUDCLK_I2S1_MCLK, JH7100_AUDCLK_I2SDAC_BCLK_IOPAD), - JH7100__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK), - JH7100_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3, + JH71X0__INV(JH7100_AUDCLK_I2S1_BCLK_N, "i2s1_bclk_n", JH7100_AUDCLK_I2S1_BCLK), + JH71X0_MDIV(JH7100_AUDCLK_I2S1_LRCLK, "i2s1_lrclk", 63, 3, JH7100_AUDCLK_I2S1_BCLK_N, JH7100_AUDCLK_I2SDAC_LRCLK_IOPAD), - JH7100_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS), - JH7100__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS), - JH7100_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS), - JH7100_GATE(JH7100_AUDCLK_USB_APB, "usb_apb", CLK_IGNORE_UNUSED, JH7100_AUDCLK_APB_EN), - JH7100_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), - JH7100_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), - JH7100__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), - JH7100__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, + JH71X0_GATE(JH7100_AUDCLK_I2SDAC16K_APB, "i2s1dac16k_apb", 0, JH7100_AUDCLK_APB0_BUS), + JH71X0__DIV(JH7100_AUDCLK_APB0_BUS, "apb0_bus", 8, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0_GATE(JH7100_AUDCLK_DMA1P_AHB, "dma1p_ahb", 0, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0_GATE(JH7100_AUDCLK_USB_APB, "usb_apb", CLK_IGNORE_UNUSED, JH7100_AUDCLK_APB_EN), + JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), + JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), + JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), + JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, JH7100_AUDCLK_VAD_INTMEM, JH7100_AUDCLK_AUDIO_12288), }; static struct clk_hw *jh7100_audclk_get(struct of_phandle_args *clkspec, void *data) { - struct jh7100_clk_priv *priv = data; + struct jh71x0_clk_priv *priv = data; unsigned int idx = clkspec->args[0]; if (idx < JH7100_AUDCLK_END) @@ -98,7 +98,7 @@ static struct clk_hw *jh7100_audclk_get(struct of_phandle_args *clkspec, void *d static int jh7100_audclk_probe(struct platform_device *pdev) { - struct jh7100_clk_priv *priv; + struct jh71x0_clk_priv *priv; unsigned int idx; int ret; @@ -117,12 +117,12 @@ static int jh7100_audclk_probe(struct platform_device *pdev) struct clk_parent_data parents[4] = {}; struct clk_init_data init = { .name = jh7100_audclk_data[idx].name, - .ops = starfive_jh7100_clk_ops(max), + .ops = starfive_jh71x0_clk_ops(max), .parent_data = parents, - .num_parents = ((max & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT) + 1, + .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, .flags = jh7100_audclk_data[idx].flags, }; - struct jh7100_clk *clk = &priv->reg[idx]; + struct jh71x0_clk *clk = &priv->reg[idx]; unsigned int i; for (i = 0; i < init.num_parents; i++) { @@ -140,7 +140,7 @@ static int jh7100_audclk_probe(struct platform_device *pdev) clk->hw.init = &init; clk->idx = idx; - clk->max_div = max & JH7100_CLK_DIV_MASK; + clk->max_div = max & JH71X0_CLK_DIV_MASK; ret = devm_clk_hw_register(priv->dev, &clk->hw); if (ret) diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c index 691aeebc7092..69cc11ea7e33 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100.c +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -7,20 +7,15 @@ * Copyright (C) 2021 Emil Renner Berthing */ -#include #include -#include #include #include -#include -#include #include -#include #include #include -#include "clk-starfive-jh7100.h" +#include "clk-starfive-jh71x0.h" /* external clocks */ #define JH7100_CLK_OSC_SYS (JH7100_CLK_END + 0) @@ -28,570 +23,253 @@ #define JH7100_CLK_GMAC_RMII_REF (JH7100_CLK_END + 2) #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) -static const struct jh7100_clk_data jh7100_clk_data[] __initconst = { - JH7100__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, +static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { + JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, + JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, + JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, + JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, + JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT), - JH7100__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, + JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, + JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, + JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, JH7100_CLK_OSC_AUD, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), - JH7100_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), - JH7100__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, + JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), + JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH7100__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, + JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT), - JH7100__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, + JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, JH7100_CLK_OSC_AUD, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), - JH7100__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), - JH7100__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), - JH7100__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), - JH7100__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), - JH7100_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), - JH7100_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), - JH7100__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, + JH71X0__DIV(JH7100_CLK_CPUNBUS_ROOT_DIV, "cpunbus_root_div", 2, JH7100_CLK_CPUNDBUS_ROOT), + JH71X0__DIV(JH7100_CLK_DSP_ROOT_DIV, "dsp_root_div", 4, JH7100_CLK_DSP_ROOT), + JH71X0__DIV(JH7100_CLK_PERH0_SRC, "perh0_src", 4, JH7100_CLK_PERH0_ROOT), + JH71X0__DIV(JH7100_CLK_PERH1_SRC, "perh1_src", 4, JH7100_CLK_PERH1_ROOT), + JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), + JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), + JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, JH7100_CLK_OSC_SYS, JH7100_CLK_OSC_AUD), - JH7100__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), - JH7100__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), - JH7100__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), - JH7100_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), - JH7100_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), - JH7100_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), - JH7100_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), - JH7100_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), - JH7100_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), - JH7100_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), - JH7100_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), - JH7100_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), - JH7100__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), - JH7100_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), - JH7100__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), - JH7100__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), - JH7100_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), - JH7100_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), - JH7100_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), - JH7100_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), - JH7100_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), - JH7100_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), - JH7100_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), - JH7100_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), - JH7100__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), - JH7100_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), - JH7100_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), - JH7100_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), - JH7100_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), - JH7100_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), - JH7100_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV2), - JH7100_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, JH7100_CLK_DDRPLL_DIV4), - JH7100_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), - JH7100_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, + JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_CPU_AXI, "cpu_axi", 8, JH7100_CLK_CPU_CORE), + JH71X0__DIV(JH7100_CLK_AHB_BUS, "ahb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_APB1_BUS, "apb1_bus", 8, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_APB2_BUS, "apb2_bus", 8, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_DOM3AHB_BUS, "dom3ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_DOM7AHB_BUS, "dom7ahb_bus", CLK_IS_CRITICAL, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_U74_CORE0, "u74_core0", CLK_IS_CRITICAL, JH7100_CLK_CPU_CORE), + JH71X0_GDIV(JH7100_CLK_U74_CORE1, "u74_core1", CLK_IS_CRITICAL, 8, JH7100_CLK_CPU_CORE), + JH71X0_GATE(JH7100_CLK_U74_AXI, "u74_axi", CLK_IS_CRITICAL, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_U74RTC_TOGGLE, "u74rtc_toggle", CLK_IS_CRITICAL, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_SGDMA2P_AXI, "sgdma2p_axi", 0, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI), + JH71X0_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT), + JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS), + JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS), + JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT), + JH71X0_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC), + JH71X0__DIV(JH7100_CLK_VCDECBUS_SRC, "vcdecbus_src", 4, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0__DIV(JH7100_CLK_VDEC_BUS, "vdec_bus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_VDEC_AXI, "vdec_axi", 0, JH7100_CLK_VDEC_BUS), + JH71X0_GATE(JH7100_CLK_VDECBRG_MAIN, "vdecbrg_mainclk", 0, JH7100_CLK_VDEC_BUS), + JH71X0_GDIV(JH7100_CLK_VDEC_BCLK, "vdec_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GDIV(JH7100_CLK_VDEC_CCLK, "vdec_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), + JH71X0_GATE(JH7100_CLK_VDEC_APB, "vdec_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_JPEG_AXI, "jpeg_axi", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_JPEG_CCLK, "jpeg_cclk", 0, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_JPEG_APB, "jpeg_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_GC300_2X, "gc300_2x", 0, 8, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0_GATE(JH7100_CLK_GC300_AHB, "gc300_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_JPCGC300_AXIBUS, "jpcgc300_axibus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_GC300_AXI, "gc300_axi", 0, JH7100_CLK_JPCGC300_AXIBUS), + JH71X0_GATE(JH7100_CLK_JPCGC300_MAIN, "jpcgc300_mainclk", 0, JH7100_CLK_JPCGC300_AXIBUS), + JH71X0__DIV(JH7100_CLK_VENC_BUS, "venc_bus", 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GATE(JH7100_CLK_VENC_AXI, "venc_axi", 0, JH7100_CLK_VENC_BUS), + JH71X0_GATE(JH7100_CLK_VENCBRG_MAIN, "vencbrg_mainclk", 0, JH7100_CLK_VENC_BUS), + JH71X0_GDIV(JH7100_CLK_VENC_BCLK, "venc_bclk", 0, 8, JH7100_CLK_VCDECBUS_SRC), + JH71X0_GDIV(JH7100_CLK_VENC_CCLK, "venc_cclk", 0, 8, JH7100_CLK_CDEC_ROOT), + JH71X0_GATE(JH7100_CLK_VENC_APB, "venc_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV2, "ddrpll_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_PLL1_OUT), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV4, "ddrpll_div4", CLK_IS_CRITICAL, 2, + JH7100_CLK_DDRPLL_DIV2), + JH71X0_GDIV(JH7100_CLK_DDRPLL_DIV8, "ddrpll_div8", CLK_IS_CRITICAL, 2, + JH7100_CLK_DDRPLL_DIV4), + JH71X0_GDIV(JH7100_CLK_DDROSC_DIV2, "ddrosc_div2", CLK_IS_CRITICAL, 2, JH7100_CLK_OSC_SYS), + JH71X0_GMUX(JH7100_CLK_DDRC0, "ddrc0", CLK_IS_CRITICAL, 4, JH7100_CLK_DDROSC_DIV2, JH7100_CLK_DDRPLL_DIV2, JH7100_CLK_DDRPLL_DIV4, JH7100_CLK_DDRPLL_DIV8), - JH7100_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, + JH71X0_GMUX(JH7100_CLK_DDRC1, "ddrc1", CLK_IS_CRITICAL, 4, JH7100_CLK_DDROSC_DIV2, JH7100_CLK_DDRPLL_DIV2, JH7100_CLK_DDRPLL_DIV4, JH7100_CLK_DDRPLL_DIV8), - JH7100_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), - JH7100__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), - JH7100_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), - JH7100__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, + JH71X0_GATE(JH7100_CLK_DDRPHY_APB, "ddrphy_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0__DIV(JH7100_CLK_NOC_ROB, "noc_rob", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), + JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), + JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, JH7100_CLK_CPU_AXI, JH7100_CLK_NNEBUS_SRC1), - JH7100_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), - JH7100_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), - JH7100_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), - JH7100_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), - JH7100__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), - JH7100__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), - JH7100_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), - JH7100__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), - JH7100_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), - JH7100_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), - JH7100__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), - JH7100_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), - JH7100_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), - JH7100_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), - JH7100_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), - JH7100__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), - JH7100_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), - JH7100_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, JH7100_CLK_USBPHY_ROOTDIV), - JH7100__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, + JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_NNENOC_AXI, "nnenoc_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_DLASLV_AXI, "dlaslv_axi", 0, JH7100_CLK_NNE_BUS), + JH71X0_GATE(JH7100_CLK_DSPX2C_AXI, "dspx2c_axi", CLK_IS_CRITICAL, JH7100_CLK_NNE_BUS), + JH71X0__DIV(JH7100_CLK_HIFI4_SRC, "hifi4_src", 4, JH7100_CLK_CDECHIFI4_ROOT), + JH71X0__DIV(JH7100_CLK_HIFI4_COREFREE, "hifi4_corefree", 8, JH7100_CLK_HIFI4_SRC), + JH71X0_GATE(JH7100_CLK_HIFI4_CORE, "hifi4_core", 0, JH7100_CLK_HIFI4_COREFREE), + JH71X0__DIV(JH7100_CLK_HIFI4_BUS, "hifi4_bus", 8, JH7100_CLK_HIFI4_COREFREE), + JH71X0_GATE(JH7100_CLK_HIFI4_AXI, "hifi4_axi", 0, JH7100_CLK_HIFI4_BUS), + JH71X0_GATE(JH7100_CLK_HIFI4NOC_AXI, "hifi4noc_axi", 0, JH7100_CLK_HIFI4_BUS), + JH71X0__DIV(JH7100_CLK_SGDMA1P_BUS, "sgdma1p_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_SGDMA1P_AXI, "sgdma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), + JH71X0_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS), + JH71X0_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS), + JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS), + JH71X0__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT), + JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), + JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, + JH7100_CLK_USBPHY_ROOTDIV), + JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, JH7100_CLK_OSC_SYS, JH7100_CLK_USBPHY_PLLDIV25M), - JH7100_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), - JH7100_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), - JH7100_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), - JH7100_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), - JH7100__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), - JH7100_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), - JH7100_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), - JH7100_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), - JH7100__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), - JH7100_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), - JH7100_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), - JH7100__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), - JH7100_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), - JH7100_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), - JH7100_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), - JH7100__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), - JH7100__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), - JH7100_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), - JH7100_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), - JH7100_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), - JH7100__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), - JH7100_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), - JH7100__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), - JH7100_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), - JH7100_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), - JH7100_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), - JH7100_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), - JH7100_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), - JH7100__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, + JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), + JH71X0_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV), + JH71X0_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD), + JH71X0_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT), + JH71X0__DIV(JH7100_CLK_ISP0_BUS, "isp0_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_ISP0_AXI, "isp0_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0_GATE(JH7100_CLK_ISP0NOC_AXI, "isp0noc_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0_GATE(JH7100_CLK_ISPSLV_AXI, "ispslv_axi", 0, JH7100_CLK_ISP0_BUS), + JH71X0__DIV(JH7100_CLK_ISP1_BUS, "isp1_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_ISP1_AXI, "isp1_axi", 0, JH7100_CLK_ISP1_BUS), + JH71X0_GATE(JH7100_CLK_ISP1NOC_AXI, "isp1noc_axi", 0, JH7100_CLK_ISP1_BUS), + JH71X0__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC), + JH71X0_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS), + JH71X0_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS), + JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT), + JH71X0__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT), + JH71X0__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC), + JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS), + JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS), + JH71X0_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC), + JH71X0__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT), + JH71X0_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC), + JH71X0__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT), + JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT), + JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), + JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, JH7100_CLK_GMAC_GTX, JH7100_CLK_GMAC_TX_INV, JH7100_CLK_GMAC_RMII_TX), - JH7100__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), - JH7100__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, + JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), + JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, JH7100_CLK_GMAC_GR_MII_RX, JH7100_CLK_GMAC_RMII_RX), - JH7100__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), - JH7100_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), - JH7100_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), - JH7100_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), - JH7100_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), - JH7100_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), - JH7100_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), - JH7100_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), - JH7100_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), - JH7100_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), - JH7100_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), - JH7100_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), - JH7100_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), - JH7100_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), + JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF), + JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV), + JH71X0_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_E24_AHB, "e24_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_E24RTC_TOGGLE, "e24rtc_toggle", 0, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_QSPI_AHB, "qspi_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_QSPI_APB, "qspi_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_QSPI_REF, "qspi_refclk", 0, 31, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SEC_AHB, "sec_ahb", 0, JH7100_CLK_AHB_BUS), + JH71X0_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB), + JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_UART1_APB, "uart1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_UART1_CORE, "uart1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_SPI0_APB, "spi0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_SPI0_CORE, "spi0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_SPI1_APB, "spi1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_SPI1_CORE, "spi1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_I2C0_APB, "i2c0_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_I2C0_CORE, "i2c0_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_I2C1_APB, "i2c1_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GDIV(JH7100_CLK_I2C1_CORE, "i2c1_core", 0, 63, JH7100_CLK_PERH1_SRC), + JH71X0_GATE(JH7100_CLK_GPIO_APB, "gpio_apb", 0, JH7100_CLK_APB1_BUS), + JH71X0_GATE(JH7100_CLK_UART2_APB, "uart2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_UART2_CORE, "uart2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_UART3_APB, "uart3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_UART3_CORE, "uart3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SPI2_APB, "spi2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_SPI2_CORE, "spi2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_SPI3_APB, "spi3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_SPI3_CORE, "spi3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_I2C2_APB, "i2c2_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_I2C2_CORE, "i2c2_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_I2C3_APB, "i2c3_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_I2C3_CORE, "i2c3_core", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_WDTIMER_APB, "wdtimer_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_WDT_CORE, "wdt_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER0_CORE, "timer0_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER1_CORE, "timer1_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER2_CORE, "timer2_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER3_CORE, "timer3_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER4_CORE, "timer4_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER5_CORE, "timer5_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GDIV(JH7100_CLK_TIMER6_CORE, "timer6_coreclk", 0, 63, JH7100_CLK_PERH0_SRC), + JH71X0_GATE(JH7100_CLK_VP6INTC_APB, "vp6intc_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_PWM_APB, "pwm_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_MSI_APB, "msi_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GATE(JH7100_CLK_TEMP_APB, "temp_apb", 0, JH7100_CLK_APB2_BUS), + JH71X0_GDIV(JH7100_CLK_TEMP_SENSE, "temp_sense", 0, 31, JH7100_CLK_OSC_SYS), + JH71X0_GATE(JH7100_CLK_SYSERR_APB, "syserr_apb", 0, JH7100_CLK_APB2_BUS), }; -static struct jh7100_clk *jh7100_clk_from(struct clk_hw *hw) -{ - return container_of(hw, struct jh7100_clk, hw); -} - -static struct jh7100_clk_priv *jh7100_priv_from(struct jh7100_clk *clk) -{ - return container_of(clk, struct jh7100_clk_priv, reg[clk->idx]); -} - -static u32 jh7100_clk_reg_get(struct jh7100_clk *clk) -{ - struct jh7100_clk_priv *priv = jh7100_priv_from(clk); - void __iomem *reg = priv->base + 4 * clk->idx; - - return readl_relaxed(reg); -} - -static void jh7100_clk_reg_rmw(struct jh7100_clk *clk, u32 mask, u32 value) -{ - struct jh7100_clk_priv *priv = jh7100_priv_from(clk); - void __iomem *reg = priv->base + 4 * clk->idx; - unsigned long flags; - - spin_lock_irqsave(&priv->rmw_lock, flags); - value |= readl_relaxed(reg) & ~mask; - writel_relaxed(value, reg); - spin_unlock_irqrestore(&priv->rmw_lock, flags); -} - -static int jh7100_clk_enable(struct clk_hw *hw) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - - jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, JH7100_CLK_ENABLE); - return 0; -} - -static void jh7100_clk_disable(struct clk_hw *hw) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - - jh7100_clk_reg_rmw(clk, JH7100_CLK_ENABLE, 0); -} - -static int jh7100_clk_is_enabled(struct clk_hw *hw) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - - return !!(jh7100_clk_reg_get(clk) & JH7100_CLK_ENABLE); -} - -static unsigned long jh7100_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 div = jh7100_clk_reg_get(clk) & JH7100_CLK_DIV_MASK; - - return div ? parent_rate / div : 0; -} - -static int jh7100_clk_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - unsigned long parent = req->best_parent_rate; - unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); - unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); - unsigned long result = parent / div; - - /* - * we want the result clamped by min_rate and max_rate if possible: - * case 1: div hits the max divider value, which means it's less than - * parent / rate, so the result is greater than rate and min_rate in - * particular. we can't do anything about result > max_rate because the - * divider doesn't go any further. - * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is - * always lower or equal to rate and max_rate. however the result may - * turn out lower than min_rate, but then the next higher rate is fine: - * div - 1 = ceil(parent / rate) - 1 < parent / rate - * and thus - * min_rate <= rate < parent / (div - 1) - */ - if (result < req->min_rate && div > 1) - result = parent / (div - 1); - - req->rate = result; - return 0; -} - -static int jh7100_clk_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), - 1UL, (unsigned long)clk->max_div); - - jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, div); - return 0; -} - -static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 reg = jh7100_clk_reg_get(clk); - unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) + - ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT); - - return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; -} - -static int jh7100_clk_frac_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - unsigned long parent100 = 100 * req->best_parent_rate; - unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); - unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), - JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); - unsigned long result = parent100 / div100; - - /* clamp the result as in jh7100_clk_determine_rate() above */ - if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX) - result = parent100 / (div100 + 1); - if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN) - result = parent100 / (div100 - 1); - - req->rate = result; - return 0; -} - -static int jh7100_clk_frac_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), - JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX); - u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100); - - jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value); - return 0; -} - -static u8 jh7100_clk_get_parent(struct clk_hw *hw) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 value = jh7100_clk_reg_get(clk); - - return (value & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT; -} - -static int jh7100_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 value = (u32)index << JH7100_CLK_MUX_SHIFT; - - jh7100_clk_reg_rmw(clk, JH7100_CLK_MUX_MASK, value); - return 0; -} - -static int jh7100_clk_mux_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - return clk_mux_determine_rate_flags(hw, req, 0); -} - -static int jh7100_clk_get_phase(struct clk_hw *hw) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 value = jh7100_clk_reg_get(clk); - - return (value & JH7100_CLK_INVERT) ? 180 : 0; -} - -static int jh7100_clk_set_phase(struct clk_hw *hw, int degrees) -{ - struct jh7100_clk *clk = jh7100_clk_from(hw); - u32 value; - - if (degrees == 0) - value = 0; - else if (degrees == 180) - value = JH7100_CLK_INVERT; - else - return -EINVAL; - - jh7100_clk_reg_rmw(clk, JH7100_CLK_INVERT, value); - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static void jh7100_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) -{ - static const struct debugfs_reg32 jh7100_clk_reg = { - .name = "CTRL", - .offset = 0, - }; - struct jh7100_clk *clk = jh7100_clk_from(hw); - struct jh7100_clk_priv *priv = jh7100_priv_from(clk); - struct debugfs_regset32 *regset; - - regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); - if (!regset) - return; - - regset->regs = &jh7100_clk_reg; - regset->nregs = 1; - regset->base = priv->base + 4 * clk->idx; - - debugfs_create_regset32("registers", 0400, dentry, regset); -} -#else -#define jh7100_clk_debug_init NULL -#endif - -static const struct clk_ops jh7100_clk_gate_ops = { - .enable = jh7100_clk_enable, - .disable = jh7100_clk_disable, - .is_enabled = jh7100_clk_is_enabled, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_div_ops = { - .recalc_rate = jh7100_clk_recalc_rate, - .determine_rate = jh7100_clk_determine_rate, - .set_rate = jh7100_clk_set_rate, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_fdiv_ops = { - .recalc_rate = jh7100_clk_frac_recalc_rate, - .determine_rate = jh7100_clk_frac_determine_rate, - .set_rate = jh7100_clk_frac_set_rate, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_gdiv_ops = { - .enable = jh7100_clk_enable, - .disable = jh7100_clk_disable, - .is_enabled = jh7100_clk_is_enabled, - .recalc_rate = jh7100_clk_recalc_rate, - .determine_rate = jh7100_clk_determine_rate, - .set_rate = jh7100_clk_set_rate, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_mux_ops = { - .determine_rate = jh7100_clk_mux_determine_rate, - .set_parent = jh7100_clk_set_parent, - .get_parent = jh7100_clk_get_parent, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_gmux_ops = { - .enable = jh7100_clk_enable, - .disable = jh7100_clk_disable, - .is_enabled = jh7100_clk_is_enabled, - .determine_rate = jh7100_clk_mux_determine_rate, - .set_parent = jh7100_clk_set_parent, - .get_parent = jh7100_clk_get_parent, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_mdiv_ops = { - .recalc_rate = jh7100_clk_recalc_rate, - .determine_rate = jh7100_clk_determine_rate, - .get_parent = jh7100_clk_get_parent, - .set_parent = jh7100_clk_set_parent, - .set_rate = jh7100_clk_set_rate, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_gmd_ops = { - .enable = jh7100_clk_enable, - .disable = jh7100_clk_disable, - .is_enabled = jh7100_clk_is_enabled, - .recalc_rate = jh7100_clk_recalc_rate, - .determine_rate = jh7100_clk_determine_rate, - .get_parent = jh7100_clk_get_parent, - .set_parent = jh7100_clk_set_parent, - .set_rate = jh7100_clk_set_rate, - .debug_init = jh7100_clk_debug_init, -}; - -static const struct clk_ops jh7100_clk_inv_ops = { - .get_phase = jh7100_clk_get_phase, - .set_phase = jh7100_clk_set_phase, - .debug_init = jh7100_clk_debug_init, -}; - -const struct clk_ops *starfive_jh7100_clk_ops(u32 max) -{ - if (max & JH7100_CLK_DIV_MASK) { - if (max & JH7100_CLK_MUX_MASK) { - if (max & JH7100_CLK_ENABLE) - return &jh7100_clk_gmd_ops; - return &jh7100_clk_mdiv_ops; - } - if (max & JH7100_CLK_ENABLE) - return &jh7100_clk_gdiv_ops; - if (max == JH7100_CLK_FRAC_MAX) - return &jh7100_clk_fdiv_ops; - return &jh7100_clk_div_ops; - } - - if (max & JH7100_CLK_MUX_MASK) { - if (max & JH7100_CLK_ENABLE) - return &jh7100_clk_gmux_ops; - return &jh7100_clk_mux_ops; - } - - if (max & JH7100_CLK_ENABLE) - return &jh7100_clk_gate_ops; - - return &jh7100_clk_inv_ops; -} -EXPORT_SYMBOL_GPL(starfive_jh7100_clk_ops); - static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data) { - struct jh7100_clk_priv *priv = data; + struct jh71x0_clk_priv *priv = data; unsigned int idx = clkspec->args[0]; if (idx < JH7100_CLK_PLL0_OUT) @@ -605,7 +283,7 @@ static struct clk_hw *jh7100_clk_get(struct of_phandle_args *clkspec, void *data static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) { - struct jh7100_clk_priv *priv; + struct jh71x0_clk_priv *priv; unsigned int idx; int ret; @@ -639,12 +317,12 @@ static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) struct clk_parent_data parents[4] = {}; struct clk_init_data init = { .name = jh7100_clk_data[idx].name, - .ops = starfive_jh7100_clk_ops(max), + .ops = starfive_jh71x0_clk_ops(max), .parent_data = parents, - .num_parents = ((max & JH7100_CLK_MUX_MASK) >> JH7100_CLK_MUX_SHIFT) + 1, + .num_parents = ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, .flags = jh7100_clk_data[idx].flags, }; - struct jh7100_clk *clk = &priv->reg[idx]; + struct jh71x0_clk *clk = &priv->reg[idx]; unsigned int i; for (i = 0; i < init.num_parents; i++) { @@ -666,7 +344,7 @@ static int __init clk_starfive_jh7100_probe(struct platform_device *pdev) clk->hw.init = &init; clk->idx = idx; - clk->max_div = max & JH7100_CLK_DIV_MASK; + clk->max_div = max & JH71X0_CLK_DIV_MASK; ret = devm_clk_hw_register(priv->dev, &clk->hw); if (ret) diff --git a/drivers/clk/starfive/clk-starfive-jh7100.h b/drivers/clk/starfive/clk-starfive-jh7100.h deleted file mode 100644 index f116be5740a5..000000000000 --- a/drivers/clk/starfive/clk-starfive-jh7100.h +++ /dev/null @@ -1,112 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __CLK_STARFIVE_JH7100_H -#define __CLK_STARFIVE_JH7100_H - -#include -#include - -/* register fields */ -#define JH7100_CLK_ENABLE BIT(31) -#define JH7100_CLK_INVERT BIT(30) -#define JH7100_CLK_MUX_MASK GENMASK(27, 24) -#define JH7100_CLK_MUX_SHIFT 24 -#define JH7100_CLK_DIV_MASK GENMASK(23, 0) -#define JH7100_CLK_FRAC_MASK GENMASK(15, 8) -#define JH7100_CLK_FRAC_SHIFT 8 -#define JH7100_CLK_INT_MASK GENMASK(7, 0) - -/* fractional divider min/max */ -#define JH7100_CLK_FRAC_MIN 100UL -#define JH7100_CLK_FRAC_MAX 25599UL - -/* clock data */ -struct jh7100_clk_data { - const char *name; - unsigned long flags; - u32 max; - u8 parents[4]; -}; - -#define JH7100_GATE(_idx, _name, _flags, _parent) [_idx] = { \ - .name = _name, \ - .flags = CLK_SET_RATE_PARENT | (_flags), \ - .max = JH7100_CLK_ENABLE, \ - .parents = { [0] = _parent }, \ -} - -#define JH7100__DIV(_idx, _name, _max, _parent) [_idx] = { \ - .name = _name, \ - .flags = 0, \ - .max = _max, \ - .parents = { [0] = _parent }, \ -} - -#define JH7100_GDIV(_idx, _name, _flags, _max, _parent) [_idx] = { \ - .name = _name, \ - .flags = _flags, \ - .max = JH7100_CLK_ENABLE | (_max), \ - .parents = { [0] = _parent }, \ -} - -#define JH7100_FDIV(_idx, _name, _parent) [_idx] = { \ - .name = _name, \ - .flags = 0, \ - .max = JH7100_CLK_FRAC_MAX, \ - .parents = { [0] = _parent }, \ -} - -#define JH7100__MUX(_idx, _name, _nparents, ...) [_idx] = { \ - .name = _name, \ - .flags = 0, \ - .max = ((_nparents) - 1) << JH7100_CLK_MUX_SHIFT, \ - .parents = { __VA_ARGS__ }, \ -} - -#define JH7100_GMUX(_idx, _name, _flags, _nparents, ...) [_idx] = { \ - .name = _name, \ - .flags = _flags, \ - .max = JH7100_CLK_ENABLE | \ - (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT), \ - .parents = { __VA_ARGS__ }, \ -} - -#define JH7100_MDIV(_idx, _name, _max, _nparents, ...) [_idx] = { \ - .name = _name, \ - .flags = 0, \ - .max = (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ - .parents = { __VA_ARGS__ }, \ -} - -#define JH7100__GMD(_idx, _name, _flags, _max, _nparents, ...) [_idx] = { \ - .name = _name, \ - .flags = _flags, \ - .max = JH7100_CLK_ENABLE | \ - (((_nparents) - 1) << JH7100_CLK_MUX_SHIFT) | (_max), \ - .parents = { __VA_ARGS__ }, \ -} - -#define JH7100__INV(_idx, _name, _parent) [_idx] = { \ - .name = _name, \ - .flags = CLK_SET_RATE_PARENT, \ - .max = JH7100_CLK_INVERT, \ - .parents = { [0] = _parent }, \ -} - -struct jh7100_clk { - struct clk_hw hw; - unsigned int idx; - unsigned int max_div; -}; - -struct jh7100_clk_priv { - /* protect clk enable and set rate/parent from happening at the same time */ - spinlock_t rmw_lock; - struct device *dev; - void __iomem *base; - struct clk_hw *pll[3]; - struct jh7100_clk reg[]; -}; - -const struct clk_ops *starfive_jh7100_clk_ops(u32 max); - -#endif diff --git a/drivers/clk/starfive/clk-starfive-jh7110-aon.c b/drivers/clk/starfive/clk-starfive-jh7110-aon.c new file mode 100644 index 000000000000..62954eb7b50a --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 Always-On Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include +#include +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_AONCLK_OSC (JH7110_AONCLK_END + 0) +#define JH7110_AONCLK_GMAC0_RMII_REFIN (JH7110_AONCLK_END + 1) +#define JH7110_AONCLK_GMAC0_RGMII_RXIN (JH7110_AONCLK_END + 2) +#define JH7110_AONCLK_STG_AXIAHB (JH7110_AONCLK_END + 3) +#define JH7110_AONCLK_APB_BUS (JH7110_AONCLK_END + 4) +#define JH7110_AONCLK_GMAC0_GTXCLK (JH7110_AONCLK_END + 5) +#define JH7110_AONCLK_RTC_OSC (JH7110_AONCLK_END + 6) + +static const struct jh71x0_clk_data jh7110_aonclk_data[] = { + /* source */ + JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC), + JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2, + JH7110_AONCLK_OSC_DIV4, + JH7110_AONCLK_OSC), + /* gmac0 */ + JH71X0_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", 0, JH7110_AONCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", 0, JH7110_AONCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx", 30, + JH7110_AONCLK_GMAC0_RMII_REFIN), + JH71X0_GMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, + JH7110_AONCLK_GMAC0_GTXCLK, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX), + JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2, + JH7110_AONCLK_GMAC0_RGMII_RXIN, + JH7110_AONCLK_GMAC0_RMII_RTX), + JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX), + /* otpc */ + JH71X0_GATE(JH7110_AONCLK_OTPC_APB, "otpc_apb", 0, JH7110_AONCLK_APB_BUS), + /* rtc */ + JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS), + JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC), + JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2, + JH7110_AONCLK_RTC_OSC, + JH7110_AONCLK_RTC_INTERNAL), + JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC), +}; + +static struct clk_hw *jh7110_aonclk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_AONCLK_END) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} + +static int jh7110_aoncrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_AONCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + for (idx = 0; idx < JH7110_AONCLK_END; idx++) { + u32 max = jh7110_aonclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_aonclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_aonclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_aonclk_data[idx].parents[i]; + + if (pidx < JH7110_AONCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx == JH7110_AONCLK_OSC) + parents[i].fw_name = "osc"; + else if (pidx == JH7110_AONCLK_GMAC0_RMII_REFIN) + parents[i].fw_name = "gmac0_rmii_refin"; + else if (pidx == JH7110_AONCLK_GMAC0_RGMII_RXIN) + parents[i].fw_name = "gmac0_rgmii_rxin"; + else if (pidx == JH7110_AONCLK_STG_AXIAHB) + parents[i].fw_name = "stg_axiahb"; + else if (pidx == JH7110_AONCLK_APB_BUS) + parents[i].fw_name = "apb_bus"; + else if (pidx == JH7110_AONCLK_GMAC0_GTXCLK) + parents[i].fw_name = "gmac0_gtxclk"; + else if (pidx == JH7110_AONCLK_RTC_OSC) + parents[i].fw_name = "rtc_osc"; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_aonclk_get, priv); + if (ret) + return ret; + + return jh7110_reset_controller_register(priv, "rst-aon", 1); +} + +static const struct of_device_id jh7110_aoncrg_match[] = { + { .compatible = "starfive,jh7110-aoncrg" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_aoncrg_match); + +static struct platform_driver jh7110_aoncrg_driver = { + .probe = jh7110_aoncrg_probe, + .driver = { + .name = "clk-starfive-jh7110-aon", + .of_match_table = jh7110_aoncrg_match, + }, +}; +module_platform_driver(jh7110_aoncrg_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH7110 always-on clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c new file mode 100644 index 000000000000..e6031345ef05 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH7110 System Clock Driver + * + * Copyright (C) 2022 Emil Renner Berthing + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "clk-starfive-jh7110.h" + +/* external clocks */ +#define JH7110_SYSCLK_OSC (JH7110_SYSCLK_END + 0) +#define JH7110_SYSCLK_GMAC1_RMII_REFIN (JH7110_SYSCLK_END + 1) +#define JH7110_SYSCLK_GMAC1_RGMII_RXIN (JH7110_SYSCLK_END + 2) +#define JH7110_SYSCLK_I2STX_BCLK_EXT (JH7110_SYSCLK_END + 3) +#define JH7110_SYSCLK_I2STX_LRCK_EXT (JH7110_SYSCLK_END + 4) +#define JH7110_SYSCLK_I2SRX_BCLK_EXT (JH7110_SYSCLK_END + 5) +#define JH7110_SYSCLK_I2SRX_LRCK_EXT (JH7110_SYSCLK_END + 6) +#define JH7110_SYSCLK_TDM_EXT (JH7110_SYSCLK_END + 7) +#define JH7110_SYSCLK_MCLK_EXT (JH7110_SYSCLK_END + 8) +#define JH7110_SYSCLK_PLL0_OUT (JH7110_SYSCLK_END + 9) +#define JH7110_SYSCLK_PLL1_OUT (JH7110_SYSCLK_END + 10) +#define JH7110_SYSCLK_PLL2_OUT (JH7110_SYSCLK_END + 11) + +static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { + /* root */ + JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT), + JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE), + JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2, + JH7110_SYSCLK_PLL2_OUT, + JH7110_SYSCLK_PLL1_OUT), + JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2, + JH7110_SYSCLK_PLL0_OUT, + JH7110_SYSCLK_PLL2_OUT), + JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_AXI_CFG0, "axi_cfg0", 3, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_STG_AXIAHB, "stg_axiahb", 2, JH7110_SYSCLK_AXI_CFG0), + JH71X0_GATE(JH7110_SYSCLK_AHB0, "ahb0", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_SYSCLK_AHB1, "ahb1", CLK_IS_CRITICAL, JH7110_SYSCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_SYSCLK_APB_BUS, "apb_bus", 8, JH7110_SYSCLK_STG_AXIAHB), + JH71X0_GATE(JH7110_SYSCLK_APB0, "apb0", CLK_IS_CRITICAL, JH7110_SYSCLK_APB_BUS), + JH71X0__DIV(JH7110_SYSCLK_PLL0_DIV2, "pll0_div2", 2, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV2, "pll1_div2", 2, JH7110_SYSCLK_PLL1_OUT), + JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT), + JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2, + JH7110_SYSCLK_MCLK_INNER, + JH7110_SYSCLK_MCLK_EXT), + JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER), + JH71X0_MDIV(JH7110_SYSCLK_ISP_2X, "isp_2x", 8, 2, + JH7110_SYSCLK_PLL2_OUT, + JH7110_SYSCLK_PLL1_OUT), + JH71X0__DIV(JH7110_SYSCLK_ISP_AXI, "isp_axi", 4, JH7110_SYSCLK_ISP_2X), + JH71X0_GDIV(JH7110_SYSCLK_GCLK0, "gclk0", 0, 62, JH7110_SYSCLK_PLL0_DIV2), + JH71X0_GDIV(JH7110_SYSCLK_GCLK1, "gclk1", 0, 62, JH7110_SYSCLK_PLL1_DIV2), + JH71X0_GDIV(JH7110_SYSCLK_GCLK2, "gclk2", 0, 62, JH7110_SYSCLK_PLL2_DIV2), + /* cores */ + JH71X0_GATE(JH7110_SYSCLK_CORE, "core", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE1, "core1", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE2, "core2", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE3, "core3", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_CORE4, "core4", CLK_IS_CRITICAL, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_DEBUG, "debug", 0, JH7110_SYSCLK_CPU_BUS), + JH71X0__DIV(JH7110_SYSCLK_RTC_TOGGLE, "rtc_toggle", 6, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TRACE0, "trace0", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE1, "trace1", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE2, "trace2", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE3, "trace3", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE4, "trace4", 0, JH7110_SYSCLK_CPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_TRACE_COM, "trace_com", 0, JH7110_SYSCLK_CPU_BUS), + /* noc */ + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_CPU_AXI, "noc_bus_cpu_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_CPU_BUS), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_AXICFG0_AXI, "noc_bus_axicfg0_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_AXI_CFG0), + /* ddr */ + JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2), + JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4), + JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4, + JH7110_SYSCLK_OSC_DIV2, + JH7110_SYSCLK_PLL1_DIV2, + JH7110_SYSCLK_PLL1_DIV4, + JH7110_SYSCLK_PLL1_DIV8), + JH71X0_GATE(JH7110_SYSCLK_DDR_AXI, "ddr_axi", CLK_IS_CRITICAL, JH7110_SYSCLK_DDR_BUS), + /* gpu */ + JH71X0__DIV(JH7110_SYSCLK_GPU_CORE, "gpu_core", 7, JH7110_SYSCLK_GPU_ROOT), + JH71X0_GATE(JH7110_SYSCLK_GPU_CORE_CLK, "gpu_core_clk", 0, JH7110_SYSCLK_GPU_CORE), + JH71X0_GATE(JH7110_SYSCLK_GPU_SYS_CLK, "gpu_sys_clk", 0, JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_GPU_APB, "gpu_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_GPU_RTC_TOGGLE, "gpu_rtc_toggle", 0, 12, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_GPU_AXI, "noc_bus_gpu_axi", 0, JH7110_SYSCLK_GPU_CORE), + /* isp */ + JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_CORE, "isp_top_core", 0, JH7110_SYSCLK_ISP_2X), + JH71X0_GATE(JH7110_SYSCLK_ISP_TOP_AXI, "isp_top_axi", 0, JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_ISP_AXI, "noc_bus_isp_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_ISP_AXI), + /* hifi4 */ + JH71X0__DIV(JH7110_SYSCLK_HIFI4_CORE, "hifi4_core", 15, JH7110_SYSCLK_BUS_ROOT), + JH71X0__DIV(JH7110_SYSCLK_HIFI4_AXI, "hifi4_axi", 2, JH7110_SYSCLK_HIFI4_CORE), + /* axi_cfg1 */ + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_MAIN, "axi_cfg1_main", CLK_IS_CRITICAL, + JH7110_SYSCLK_ISP_AXI), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG1_AHB, "axi_cfg1_ahb", CLK_IS_CRITICAL, + JH7110_SYSCLK_AHB0), + /* vout */ + JH71X0_GATE(JH7110_SYSCLK_VOUT_SRC, "vout_src", 0, JH7110_SYSCLK_PLL2_OUT), + JH71X0__DIV(JH7110_SYSCLK_VOUT_AXI, "vout_axi", 7, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_DISP_AXI, "noc_bus_disp_axi", 0, JH7110_SYSCLK_VOUT_AXI), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AHB, "vout_top_ahb", 0, JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_AXI, "vout_top_axi", 0, JH7110_SYSCLK_VOUT_AXI), + JH71X0_GATE(JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK, "vout_top_hdmitx0_mclk", 0, + JH7110_SYSCLK_MCLK), + JH71X0__DIV(JH7110_SYSCLK_VOUT_TOP_MIPIPHY_REF, "vout_top_mipiphy_ref", 2, + JH7110_SYSCLK_OSC), + /* jpegc */ + JH71X0__DIV(JH7110_SYSCLK_JPEGC_AXI, "jpegc_axi", 16, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_CODAJ12_AXI, "codaj12_axi", 0, JH7110_SYSCLK_JPEGC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_CODAJ12_CORE, "codaj12_core", 0, 16, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_CODAJ12_APB, "codaj12_apb", 0, JH7110_SYSCLK_APB_BUS), + /* vdec */ + JH71X0__DIV(JH7110_SYSCLK_VDEC_AXI, "vdec_axi", 7, JH7110_SYSCLK_BUS_ROOT), + JH71X0_GATE(JH7110_SYSCLK_WAVE511_AXI, "wave511_axi", 0, JH7110_SYSCLK_VDEC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_WAVE511_BPU, "wave511_bpu", 0, 7, JH7110_SYSCLK_BUS_ROOT), + JH71X0_GDIV(JH7110_SYSCLK_WAVE511_VCE, "wave511_vce", 0, 7, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE511_APB, "wave511_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_VDEC_JPG, "vdec_jpg", 0, JH7110_SYSCLK_JPEGC_AXI), + JH71X0_GATE(JH7110_SYSCLK_VDEC_MAIN, "vdec_main", 0, JH7110_SYSCLK_VDEC_AXI), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VDEC_AXI, "noc_bus_vdec_axi", 0, JH7110_SYSCLK_VDEC_AXI), + /* venc */ + JH71X0__DIV(JH7110_SYSCLK_VENC_AXI, "venc_axi", 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE420L_AXI, "wave420l_axi", 0, JH7110_SYSCLK_VENC_AXI), + JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_BPU, "wave420l_bpu", 0, 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GDIV(JH7110_SYSCLK_WAVE420L_VCE, "wave420l_vce", 0, 15, JH7110_SYSCLK_PLL2_OUT), + JH71X0_GATE(JH7110_SYSCLK_WAVE420L_APB, "wave420l_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_VENC_AXI, "noc_bus_venc_axi", 0, JH7110_SYSCLK_VENC_AXI), + /* axi_cfg0 */ + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN_DIV, "axi_cfg0_main_div", CLK_IS_CRITICAL, + JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_MAIN, "axi_cfg0_main", CLK_IS_CRITICAL, + JH7110_SYSCLK_AXI_CFG0), + JH71X0_GATE(JH7110_SYSCLK_AXI_CFG0_HIFI4, "axi_cfg0_hifi4", CLK_IS_CRITICAL, + JH7110_SYSCLK_HIFI4_AXI), + /* intmem */ + JH71X0_GATE(JH7110_SYSCLK_AXIMEM2_AXI, "aximem2_axi", 0, JH7110_SYSCLK_AXI_CFG0), + /* qspi */ + JH71X0_GATE(JH7110_SYSCLK_QSPI_AHB, "qspi_ahb", 0, JH7110_SYSCLK_AHB1), + JH71X0_GATE(JH7110_SYSCLK_QSPI_APB, "qspi_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0__DIV(JH7110_SYSCLK_QSPI_REF_SRC, "qspi_ref_src", 16, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GMUX(JH7110_SYSCLK_QSPI_REF, "qspi_ref", 0, 2, + JH7110_SYSCLK_OSC, + JH7110_SYSCLK_QSPI_REF_SRC), + /* sdio */ + JH71X0_GATE(JH7110_SYSCLK_SDIO0_AHB, "sdio0_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_SDIO1_AHB, "sdio1_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GDIV(JH7110_SYSCLK_SDIO0_SDCARD, "sdio0_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), + JH71X0_GDIV(JH7110_SYSCLK_SDIO1_SDCARD, "sdio1_sdcard", 0, 15, JH7110_SYSCLK_AXI_CFG0), + /* stg */ + JH71X0__DIV(JH7110_SYSCLK_USB_125M, "usb_125m", 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GATE(JH7110_SYSCLK_NOC_BUS_STG_AXI, "noc_bus_stg_axi", CLK_IS_CRITICAL, + JH7110_SYSCLK_NOCSTG_BUS), + /* gmac1 */ + JH71X0_GATE(JH7110_SYSCLK_GMAC1_AHB, "gmac1_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_GMAC1_AXI, "gmac1_axi", 0, JH7110_SYSCLK_STG_AXIAHB), + JH71X0__DIV(JH7110_SYSCLK_GMAC_SRC, "gmac_src", 7, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_GMAC1_GTXCLK, "gmac1_gtxclk", 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30, + JH7110_SYSCLK_GMAC1_RMII_REFIN), + JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2, + JH7110_SYSCLK_GMAC1_RGMII_RXIN, + JH7110_SYSCLK_GMAC1_RMII_RTX), + JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX), + JH71X0_GMUX(JH7110_SYSCLK_GMAC1_TX, "gmac1_tx", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, + JH7110_SYSCLK_GMAC1_GTXCLK, + JH7110_SYSCLK_GMAC1_RMII_RTX), + JH71X0__INV(JH7110_SYSCLK_GMAC1_TX_INV, "gmac1_tx_inv", JH7110_SYSCLK_GMAC1_TX), + JH71X0_GATE(JH7110_SYSCLK_GMAC1_GTXC, "gmac1_gtxc", 0, JH7110_SYSCLK_GMAC1_GTXCLK), + /* gmac0 */ + JH71X0_GDIV(JH7110_SYSCLK_GMAC0_GTXCLK, "gmac0_gtxclk", 0, 15, JH7110_SYSCLK_PLL0_OUT), + JH71X0_GDIV(JH7110_SYSCLK_GMAC0_PTP, "gmac0_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0_GDIV(JH7110_SYSCLK_GMAC_PHY, "gmac_phy", 0, 31, JH7110_SYSCLK_GMAC_SRC), + JH71X0_GATE(JH7110_SYSCLK_GMAC0_GTXC, "gmac0_gtxc", 0, JH7110_SYSCLK_GMAC0_GTXCLK), + /* apb misc */ + JH71X0_GATE(JH7110_SYSCLK_IOMUX_APB, "iomux_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_MAILBOX_APB, "mailbox_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_INT_CTRL_APB, "int_ctrl_apb", 0, JH7110_SYSCLK_APB_BUS), + /* can0 */ + JH71X0_GATE(JH7110_SYSCLK_CAN0_APB, "can0_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_CAN0_TIMER, "can0_timer", 0, 24, JH7110_SYSCLK_OSC), + JH71X0_GDIV(JH7110_SYSCLK_CAN0_CAN, "can0_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), + /* can1 */ + JH71X0_GATE(JH7110_SYSCLK_CAN1_APB, "can1_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_CAN1_TIMER, "can1_timer", 0, 24, JH7110_SYSCLK_OSC), + JH71X0_GDIV(JH7110_SYSCLK_CAN1_CAN, "can1_can", 0, 63, JH7110_SYSCLK_PERH_ROOT), + /* pwm */ + JH71X0_GATE(JH7110_SYSCLK_PWM_APB, "pwm_apb", 0, JH7110_SYSCLK_APB_BUS), + /* wdt */ + JH71X0_GATE(JH7110_SYSCLK_WDT_APB, "wdt_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_WDT_CORE, "wdt_core", 0, JH7110_SYSCLK_OSC), + /* timer */ + JH71X0_GATE(JH7110_SYSCLK_TIMER_APB, "timer_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_TIMER0, "timer0", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER1, "timer1", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER2, "timer2", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_TIMER3, "timer3", 0, JH7110_SYSCLK_OSC), + /* temp sensor */ + JH71X0_GATE(JH7110_SYSCLK_TEMP_APB, "temp_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GDIV(JH7110_SYSCLK_TEMP_CORE, "temp_core", 0, 24, JH7110_SYSCLK_OSC), + /* spi */ + JH71X0_GATE(JH7110_SYSCLK_SPI0_APB, "spi0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI1_APB, "spi1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI2_APB, "spi2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPI3_APB, "spi3_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI4_APB, "spi4_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI5_APB, "spi5_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_SPI6_APB, "spi6_apb", 0, JH7110_SYSCLK_APB_BUS), + /* i2c */ + JH71X0_GATE(JH7110_SYSCLK_I2C0_APB, "i2c0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C1_APB, "i2c1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C2_APB, "i2c2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_I2C3_APB, "i2c3_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C4_APB, "i2c4_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C5_APB, "i2c5_apb", 0, JH7110_SYSCLK_APB_BUS), + JH71X0_GATE(JH7110_SYSCLK_I2C6_APB, "i2c6_apb", 0, JH7110_SYSCLK_APB_BUS), + /* uart */ + JH71X0_GATE(JH7110_SYSCLK_UART0_APB, "uart0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART0_CORE, "uart0_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART1_APB, "uart1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART1_CORE, "uart1_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART2_APB, "uart2_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_UART2_CORE, "uart2_core", 0, JH7110_SYSCLK_OSC), + JH71X0_GATE(JH7110_SYSCLK_UART3_APB, "uart3_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART3_CORE, "uart3_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + JH71X0_GATE(JH7110_SYSCLK_UART4_APB, "uart4_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART4_CORE, "uart4_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + JH71X0_GATE(JH7110_SYSCLK_UART5_APB, "uart5_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_UART5_CORE, "uart5_core", 0, 10, JH7110_SYSCLK_PERH_ROOT), + /* pwmdac */ + JH71X0_GATE(JH7110_SYSCLK_PWMDAC_APB, "pwmdac_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_PWMDAC_CORE, "pwmdac_core", 0, 256, JH7110_SYSCLK_AUDIO_ROOT), + /* spdif */ + JH71X0_GATE(JH7110_SYSCLK_SPDIF_APB, "spdif_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GATE(JH7110_SYSCLK_SPDIF_CORE, "spdif_core", 0, JH7110_SYSCLK_MCLK), + /* i2stx0 */ + JH71X0_GATE(JH7110_SYSCLK_I2STX0_APB, "i2stx0_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2STX0_BCLK_MST, "i2stx0_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_MST_INV, "i2stx0_bclk_mst_inv", + JH7110_SYSCLK_I2STX0_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX0_BCLK_MST_INV, + JH7110_SYSCLK_I2STX0_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2, + JH7110_SYSCLK_I2STX0_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2, + JH7110_SYSCLK_I2STX0_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2stx1 */ + JH71X0_GATE(JH7110_SYSCLK_I2STX1_APB, "i2stx1_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2STX1_BCLK_MST, "i2stx1_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_MST_INV, "i2stx1_bclk_mst_inv", + JH7110_SYSCLK_I2STX1_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2, + JH7110_SYSCLK_I2STX1_BCLK_MST_INV, + JH7110_SYSCLK_I2STX1_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2, + JH7110_SYSCLK_I2STX1_BCLK_MST, + JH7110_SYSCLK_I2STX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2, + JH7110_SYSCLK_I2STX1_LRCK_MST, + JH7110_SYSCLK_I2STX_LRCK_EXT), + /* i2srx */ + JH71X0_GATE(JH7110_SYSCLK_I2SRX_APB, "i2srx_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_I2SRX_BCLK_MST, "i2srx_bclk_mst", 0, 32, JH7110_SYSCLK_MCLK), + JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_MST_INV, "i2srx_bclk_mst_inv", + JH7110_SYSCLK_I2SRX_BCLK_MST), + JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2, + JH7110_SYSCLK_I2SRX_BCLK_MST_INV, + JH7110_SYSCLK_I2SRX_BCLK_MST), + JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2, + JH7110_SYSCLK_I2SRX_BCLK_MST, + JH7110_SYSCLK_I2SRX_BCLK_EXT), + JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK), + JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2, + JH7110_SYSCLK_I2SRX_LRCK_MST, + JH7110_SYSCLK_I2SRX_LRCK_EXT), + /* pdm */ + JH71X0_GDIV(JH7110_SYSCLK_PDM_DMIC, "pdm_dmic", 0, 64, JH7110_SYSCLK_MCLK), + JH71X0_GATE(JH7110_SYSCLK_PDM_APB, "pdm_apb", 0, JH7110_SYSCLK_APB0), + /* tdm */ + JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0), + JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0), + JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK), + JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2, + JH7110_SYSCLK_TDM_INTERNAL, + JH7110_SYSCLK_TDM_EXT), + JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM), + /* jtag */ + JH71X0__DIV(JH7110_SYSCLK_JTAG_CERTIFICATION_TRNG, "jtag_certification_trng", 4, + JH7110_SYSCLK_OSC), +}; + +static struct clk_hw *jh7110_sysclk_get(struct of_phandle_args *clkspec, void *data) +{ + struct jh71x0_clk_priv *priv = data; + unsigned int idx = clkspec->args[0]; + + if (idx < JH7110_SYSCLK_END) + return &priv->reg[idx].hw; + + return ERR_PTR(-EINVAL); +} + +static void jh7110_reset_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static void jh7110_reset_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct jh71x0_reset_adev *rdev = to_jh71x0_reset_adev(adev); + + kfree(rdev); +} + +int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id) +{ + struct jh71x0_reset_adev *rdev; + struct auxiliary_device *adev; + int ret; + + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) + return -ENOMEM; + + rdev->base = priv->base; + + adev = &rdev->adev; + adev->name = adev_name; + adev->dev.parent = priv->dev; + adev->dev.release = jh7110_reset_adev_release; + adev->id = adev_id; + + ret = auxiliary_device_init(adev); + if (ret) + return ret; + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(priv->dev, + jh7110_reset_unregister_adev, adev); +} +EXPORT_SYMBOL_GPL(jh7110_reset_controller_register); + +static int __init jh7110_syscrg_probe(struct platform_device *pdev) +{ + struct jh71x0_clk_priv *priv; + unsigned int idx; + int ret; + + priv = devm_kzalloc(&pdev->dev, + struct_size(priv, reg, JH7110_SYSCLK_END), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + priv->dev = &pdev->dev; + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + /* + * These PLL clocks are not actually fixed factor clocks and can be + * controlled by the syscon registers of JH7110. They will be dropped + * and registered in the PLL clock driver instead. + */ + /* 24MHz -> 1000.0MHz */ + priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out", + "osc", 0, 125, 3); + if (IS_ERR(priv->pll[0])) + return PTR_ERR(priv->pll[0]); + + /* 24MHz -> 1066.0MHz */ + priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out", + "osc", 0, 533, 12); + if (IS_ERR(priv->pll[1])) + return PTR_ERR(priv->pll[1]); + + /* 24MHz -> 1188.0MHz */ + priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out", + "osc", 0, 99, 2); + if (IS_ERR(priv->pll[2])) + return PTR_ERR(priv->pll[2]); + + for (idx = 0; idx < JH7110_SYSCLK_END; idx++) { + u32 max = jh7110_sysclk_data[idx].max; + struct clk_parent_data parents[4] = {}; + struct clk_init_data init = { + .name = jh7110_sysclk_data[idx].name, + .ops = starfive_jh71x0_clk_ops(max), + .parent_data = parents, + .num_parents = + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1, + .flags = jh7110_sysclk_data[idx].flags, + }; + struct jh71x0_clk *clk = &priv->reg[idx]; + unsigned int i; + + for (i = 0; i < init.num_parents; i++) { + unsigned int pidx = jh7110_sysclk_data[idx].parents[i]; + + if (pidx < JH7110_SYSCLK_END) + parents[i].hw = &priv->reg[pidx].hw; + else if (pidx == JH7110_SYSCLK_OSC) + parents[i].fw_name = "osc"; + else if (pidx == JH7110_SYSCLK_GMAC1_RMII_REFIN) + parents[i].fw_name = "gmac1_rmii_refin"; + else if (pidx == JH7110_SYSCLK_GMAC1_RGMII_RXIN) + parents[i].fw_name = "gmac1_rgmii_rxin"; + else if (pidx == JH7110_SYSCLK_I2STX_BCLK_EXT) + parents[i].fw_name = "i2stx_bclk_ext"; + else if (pidx == JH7110_SYSCLK_I2STX_LRCK_EXT) + parents[i].fw_name = "i2stx_lrck_ext"; + else if (pidx == JH7110_SYSCLK_I2SRX_BCLK_EXT) + parents[i].fw_name = "i2srx_bclk_ext"; + else if (pidx == JH7110_SYSCLK_I2SRX_LRCK_EXT) + parents[i].fw_name = "i2srx_lrck_ext"; + else if (pidx == JH7110_SYSCLK_TDM_EXT) + parents[i].fw_name = "tdm_ext"; + else if (pidx == JH7110_SYSCLK_MCLK_EXT) + parents[i].fw_name = "mclk_ext"; + else + parents[i].hw = priv->pll[pidx - JH7110_SYSCLK_PLL0_OUT]; + } + + clk->hw.init = &init; + clk->idx = idx; + clk->max_div = max & JH71X0_CLK_DIV_MASK; + + ret = devm_clk_hw_register(&pdev->dev, &clk->hw); + if (ret) + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_sysclk_get, priv); + if (ret) + return ret; + + return jh7110_reset_controller_register(priv, "rst-sys", 0); +} + +static const struct of_device_id jh7110_syscrg_match[] = { + { .compatible = "starfive,jh7110-syscrg" }, + { /* sentinel */ } +}; + +static struct platform_driver jh7110_syscrg_driver = { + .driver = { + .name = "clk-starfive-jh7110-sys", + .of_match_table = jh7110_syscrg_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(jh7110_syscrg_driver, jh7110_syscrg_probe); diff --git a/drivers/clk/starfive/clk-starfive-jh7110.h b/drivers/clk/starfive/clk-starfive-jh7110.h new file mode 100644 index 000000000000..f29682b8d400 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh7110.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __CLK_STARFIVE_JH7110_H +#define __CLK_STARFIVE_JH7110_H + +#include "clk-starfive-jh71x0.h" + +int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, + const char *adev_name, + u32 adev_id); + +#endif diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.c b/drivers/clk/starfive/clk-starfive-jh71x0.c new file mode 100644 index 000000000000..b372083d11c3 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh71x0.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH71X0 Clock Generator Driver + * + * Copyright (C) 2021-2022 Emil Renner Berthing + */ + +#include +#include +#include +#include + +#include "clk-starfive-jh71x0.h" + +static struct jh71x0_clk *jh71x0_clk_from(struct clk_hw *hw) +{ + return container_of(hw, struct jh71x0_clk, hw); +} + +static struct jh71x0_clk_priv *jh71x0_priv_from(struct jh71x0_clk *clk) +{ + return container_of(clk, struct jh71x0_clk_priv, reg[clk->idx]); +} + +static u32 jh71x0_clk_reg_get(struct jh71x0_clk *clk) +{ + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + + return readl_relaxed(reg); +} + +static void jh71x0_clk_reg_rmw(struct jh71x0_clk *clk, u32 mask, u32 value) +{ + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + void __iomem *reg = priv->base + 4 * clk->idx; + unsigned long flags; + + spin_lock_irqsave(&priv->rmw_lock, flags); + value |= readl_relaxed(reg) & ~mask; + writel_relaxed(value, reg); + spin_unlock_irqrestore(&priv->rmw_lock, flags); +} + +static int jh71x0_clk_enable(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, JH71X0_CLK_ENABLE); + return 0; +} + +static void jh71x0_clk_disable(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, 0); +} + +static int jh71x0_clk_is_enabled(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + + return !!(jh71x0_clk_reg_get(clk) & JH71X0_CLK_ENABLE); +} + +static unsigned long jh71x0_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 div = jh71x0_clk_reg_get(clk) & JH71X0_CLK_DIV_MASK; + + return div ? parent_rate / div : 0; +} + +static int jh71x0_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long parent = req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div = min_t(unsigned long, DIV_ROUND_UP(parent, rate), clk->max_div); + unsigned long result = parent / div; + + /* + * we want the result clamped by min_rate and max_rate if possible: + * case 1: div hits the max divider value, which means it's less than + * parent / rate, so the result is greater than rate and min_rate in + * particular. we can't do anything about result > max_rate because the + * divider doesn't go any further. + * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is + * always lower or equal to rate and max_rate. however the result may + * turn out lower than min_rate, but then the next higher rate is fine: + * div - 1 = ceil(parent / rate) - 1 < parent / rate + * and thus + * min_rate <= rate < parent / (div - 1) + */ + if (result < req->min_rate && div > 1) + result = parent / (div - 1); + + req->rate = result; + return 0; +} + +static int jh71x0_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate), + 1UL, (unsigned long)clk->max_div); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, div); + return 0; +} + +static unsigned long jh71x0_clk_frac_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 reg = jh71x0_clk_reg_get(clk); + unsigned long div100 = 100 * (reg & JH71X0_CLK_INT_MASK) + + ((reg & JH71X0_CLK_FRAC_MASK) >> JH71X0_CLK_FRAC_SHIFT); + + return (div100 >= JH71X0_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0; +} + +static int jh71x0_clk_frac_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long parent100 = 100 * req->best_parent_rate; + unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate), + JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); + unsigned long result = parent100 / div100; + + /* clamp the result as in jh71x0_clk_determine_rate() above */ + if (result > req->max_rate && div100 < JH71X0_CLK_FRAC_MAX) + result = parent100 / (div100 + 1); + if (result < req->min_rate && div100 > JH71X0_CLK_FRAC_MIN) + result = parent100 / (div100 - 1); + + req->rate = result; + return 0; +} + +static int jh71x0_clk_frac_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate), + JH71X0_CLK_FRAC_MIN, JH71X0_CLK_FRAC_MAX); + u32 value = ((div100 % 100) << JH71X0_CLK_FRAC_SHIFT) | (div100 / 100); + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, value); + return 0; +} + +static u8 jh71x0_clk_get_parent(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = jh71x0_clk_reg_get(clk); + + return (value & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT; +} + +static int jh71x0_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = (u32)index << JH71X0_CLK_MUX_SHIFT; + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_MUX_MASK, value); + return 0; +} + +static int jh71x0_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return clk_mux_determine_rate_flags(hw, req, 0); +} + +static int jh71x0_clk_get_phase(struct clk_hw *hw) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value = jh71x0_clk_reg_get(clk); + + return (value & JH71X0_CLK_INVERT) ? 180 : 0; +} + +static int jh71x0_clk_set_phase(struct clk_hw *hw, int degrees) +{ + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + u32 value; + + if (degrees == 0) + value = 0; + else if (degrees == 180) + value = JH71X0_CLK_INVERT; + else + return -EINVAL; + + jh71x0_clk_reg_rmw(clk, JH71X0_CLK_INVERT, value); + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void jh71x0_clk_debug_init(struct clk_hw *hw, struct dentry *dentry) +{ + static const struct debugfs_reg32 jh71x0_clk_reg = { + .name = "CTRL", + .offset = 0, + }; + struct jh71x0_clk *clk = jh71x0_clk_from(hw); + struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk); + struct debugfs_regset32 *regset; + + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return; + + regset->regs = &jh71x0_clk_reg; + regset->nregs = 1; + regset->base = priv->base + 4 * clk->idx; + + debugfs_create_regset32("registers", 0400, dentry, regset); +} +#else +#define jh71x0_clk_debug_init NULL +#endif + +static const struct clk_ops jh71x0_clk_gate_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_div_ops = { + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_fdiv_ops = { + .recalc_rate = jh71x0_clk_frac_recalc_rate, + .determine_rate = jh71x0_clk_frac_determine_rate, + .set_rate = jh71x0_clk_frac_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gdiv_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_mux_ops = { + .determine_rate = jh71x0_clk_mux_determine_rate, + .set_parent = jh71x0_clk_set_parent, + .get_parent = jh71x0_clk_get_parent, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gmux_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .determine_rate = jh71x0_clk_mux_determine_rate, + .set_parent = jh71x0_clk_set_parent, + .get_parent = jh71x0_clk_get_parent, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_mdiv_ops = { + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .get_parent = jh71x0_clk_get_parent, + .set_parent = jh71x0_clk_set_parent, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_gmd_ops = { + .enable = jh71x0_clk_enable, + .disable = jh71x0_clk_disable, + .is_enabled = jh71x0_clk_is_enabled, + .recalc_rate = jh71x0_clk_recalc_rate, + .determine_rate = jh71x0_clk_determine_rate, + .get_parent = jh71x0_clk_get_parent, + .set_parent = jh71x0_clk_set_parent, + .set_rate = jh71x0_clk_set_rate, + .debug_init = jh71x0_clk_debug_init, +}; + +static const struct clk_ops jh71x0_clk_inv_ops = { + .get_phase = jh71x0_clk_get_phase, + .set_phase = jh71x0_clk_set_phase, + .debug_init = jh71x0_clk_debug_init, +}; + +const struct clk_ops *starfive_jh71x0_clk_ops(u32 max) +{ + if (max & JH71X0_CLK_DIV_MASK) { + if (max & JH71X0_CLK_MUX_MASK) { + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gmd_ops; + return &jh71x0_clk_mdiv_ops; + } + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gdiv_ops; + if (max == JH71X0_CLK_FRAC_MAX) + return &jh71x0_clk_fdiv_ops; + return &jh71x0_clk_div_ops; + } + + if (max & JH71X0_CLK_MUX_MASK) { + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gmux_ops; + return &jh71x0_clk_mux_ops; + } + + if (max & JH71X0_CLK_ENABLE) + return &jh71x0_clk_gate_ops; + + return &jh71x0_clk_inv_ops; +} +EXPORT_SYMBOL_GPL(starfive_jh71x0_clk_ops); diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.h b/drivers/clk/starfive/clk-starfive-jh71x0.h new file mode 100644 index 000000000000..34bb11c72eb7 --- /dev/null +++ b/drivers/clk/starfive/clk-starfive-jh71x0.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __CLK_STARFIVE_JH71X0_H +#define __CLK_STARFIVE_JH71X0_H + +#include +#include +#include +#include + +/* register fields */ +#define JH71X0_CLK_ENABLE BIT(31) +#define JH71X0_CLK_INVERT BIT(30) +#define JH71X0_CLK_MUX_MASK GENMASK(27, 24) +#define JH71X0_CLK_MUX_SHIFT 24 +#define JH71X0_CLK_DIV_MASK GENMASK(23, 0) +#define JH71X0_CLK_FRAC_MASK GENMASK(15, 8) +#define JH71X0_CLK_FRAC_SHIFT 8 +#define JH71X0_CLK_INT_MASK GENMASK(7, 0) + +/* fractional divider min/max */ +#define JH71X0_CLK_FRAC_MIN 100UL +#define JH71X0_CLK_FRAC_MAX 25599UL + +/* clock data */ +struct jh71x0_clk_data { + const char *name; + unsigned long flags; + u32 max; + u8 parents[4]; +}; + +#define JH71X0_GATE(_idx, _name, _flags, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT | (_flags), \ + .max = JH71X0_CLK_ENABLE, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0__DIV(_idx, _name, _max, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = _max, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0_GDIV(_idx, _name, _flags, _max, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | (_max), \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0_FDIV(_idx, _name, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = JH71X0_CLK_FRAC_MAX, \ + .parents = { [0] = _parent }, \ +} + +#define JH71X0__MUX(_idx, _name, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0_GMUX(_idx, _name, _flags, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | \ + (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0_MDIV(_idx, _name, _max, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = 0, \ + .max = (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0__GMD(_idx, _name, _flags, _max, _nparents, ...) \ +[_idx] = { \ + .name = _name, \ + .flags = _flags, \ + .max = JH71X0_CLK_ENABLE | \ + (((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT) | (_max), \ + .parents = { __VA_ARGS__ }, \ +} + +#define JH71X0__INV(_idx, _name, _parent) \ +[_idx] = { \ + .name = _name, \ + .flags = CLK_SET_RATE_PARENT, \ + .max = JH71X0_CLK_INVERT, \ + .parents = { [0] = _parent }, \ +} + +struct jh71x0_clk { + struct clk_hw hw; + unsigned int idx; + unsigned int max_div; +}; + +struct jh71x0_clk_priv { + /* protect clk enable and set rate/parent from happening at the same time */ + spinlock_t rmw_lock; + struct device *dev; + void __iomem *base; + struct clk_hw *pll[3]; + struct jh71x0_clk reg[]; +}; + +const struct clk_ops *starfive_jh71x0_clk_ops(u32 max); + +#endif diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c index 1192eee8abe4..c4a737482fe5 100644 --- a/drivers/clk/stm32/clk-stm32mp13.c +++ b/drivers/clk/stm32/clk-stm32mp13.c @@ -1593,15 +1593,13 @@ static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) return ret; } -static int stm32mp1_rcc_clocks_remove(struct platform_device *pdev) +static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child, *np = dev_of_node(dev); for_each_available_child_of_node(np, child) of_clk_del_provider(child); - - return 0; } static struct platform_driver stm32mp13_rcc_clocks_driver = { @@ -1610,7 +1608,7 @@ static struct platform_driver stm32mp13_rcc_clocks_driver = { .of_match_table = stm32mp13_match_data, }, .probe = stm32mp1_rcc_clocks_probe, - .remove = stm32mp1_rcc_clocks_remove, + .remove_new = stm32mp1_rcc_clocks_remove, }; static int __init stm32mp13_clocks_init(void) diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 41433927b55c..58fa5a59e0c7 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -2081,7 +2081,10 @@ struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev) { struct tegra_dfll *td = platform_get_drvdata(pdev); - /* Try to prevent removal while the DFLL is active */ + /* + * Note that exiting early here doesn't prevent unbinding the driver. + * Exiting early here only leaks some resources. + */ if (td->mode != DFLL_DISABLED) { dev_err(&pdev->dev, "must disable DFLL before removing driver\n"); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 5e339ad0a97c..2a164e565c86 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -612,20 +612,19 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return 0; } -static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) +static void tegra124_dfll_fcpu_remove(struct platform_device *pdev) { struct tegra_dfll_soc_data *soc; + /* + * Note that exiting early here is dangerous as after this function + * returns *soc is freed. + */ soc = tegra_dfll_unregister(pdev); - if (IS_ERR(soc)) { - dev_err(&pdev->dev, "failed to unregister DFLL: %ld\n", - PTR_ERR(soc)); - return PTR_ERR(soc); - } + if (IS_ERR(soc)) + return; tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); - - return 0; } static const struct dev_pm_ops tegra124_dfll_pm_ops = { @@ -636,7 +635,7 @@ static const struct dev_pm_ops tegra124_dfll_pm_ops = { static struct platform_driver tegra124_dfll_fcpu_driver = { .probe = tegra124_dfll_fcpu_probe, - .remove = tegra124_dfll_fcpu_remove, + .remove_new = tegra124_dfll_fcpu_remove, .driver = { .name = "tegra124-dfll", .of_match_table = tegra124_dfll_fcpu_of_match, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 422d78247553..dcacc5064d33 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -21,24 +21,24 @@ #define MISC_CLK_ENB 0x48 #define OSC_CTRL 0x50 -#define OSC_CTRL_OSC_FREQ_MASK (3<<30) -#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) -#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) -#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) -#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) +#define OSC_CTRL_OSC_FREQ_MASK (3u<<30) +#define OSC_CTRL_OSC_FREQ_13MHZ (0u<<30) +#define OSC_CTRL_OSC_FREQ_19_2MHZ (1u<<30) +#define OSC_CTRL_OSC_FREQ_12MHZ (2u<<30) +#define OSC_CTRL_OSC_FREQ_26MHZ (3u<<30) +#define OSC_CTRL_MASK (0x3f2u | OSC_CTRL_OSC_FREQ_MASK) -#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28) -#define OSC_CTRL_PLL_REF_DIV_1 (0<<28) -#define OSC_CTRL_PLL_REF_DIV_2 (1<<28) -#define OSC_CTRL_PLL_REF_DIV_4 (2<<28) +#define OSC_CTRL_PLL_REF_DIV_MASK (3u<<28) +#define OSC_CTRL_PLL_REF_DIV_1 (0u<<28) +#define OSC_CTRL_PLL_REF_DIV_2 (1u<<28) +#define OSC_CTRL_PLL_REF_DIV_4 (2u<<28) #define OSC_FREQ_DET 0x58 -#define OSC_FREQ_DET_TRIG (1<<31) +#define OSC_FREQ_DET_TRIG (1u<<31) #define OSC_FREQ_DET_STATUS 0x5c -#define OSC_FREQ_DET_BUSY (1<<31) -#define OSC_FREQ_DET_CNT_MASK 0xFFFF +#define OSC_FREQ_DET_BUSYu (1<<31) +#define OSC_FREQ_DET_CNT_MASK 0xFFFFu #define TEGRA20_CLK_PERIPH_BANKS 3 diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index f5e7e2049241..6ecbba4342c5 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -931,13 +931,11 @@ free: return err; } -static int ti_adpll_remove(struct platform_device *pdev) +static void ti_adpll_remove(struct platform_device *pdev) { struct ti_adpll_data *d = dev_get_drvdata(&pdev->dev); ti_adpll_free_resources(d); - - return 0; } static struct platform_driver ti_adpll_driver = { @@ -946,7 +944,7 @@ static struct platform_driver ti_adpll_driver = { .of_match_table = ti_adpll_match, }, .probe = ti_adpll_probe, - .remove = ti_adpll_remove, + .remove_new = ti_adpll_remove, }; static int __init ti_adpll_init(void) diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index f73f402ff7de..b6fce916967c 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -512,16 +512,16 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) struct clk_hw_omap *hw; struct clk *clk; struct omap_clkctrl_clk *clkctrl_clk = NULL; - const __be32 *addrp; bool legacy_naming; const char *clkctrl_name; u32 addr; int ret; char *c; u16 soc_mask = 0; + struct resource res; - addrp = of_get_address(node, 0, NULL, NULL); - addr = (u32)of_translate_address(node, addrp); + of_address_to_resource(node, 0, &res); + addr = (u32)res.start; #ifdef CONFIG_ARCH_OMAP4 if (of_machine_is_compatible("ti,omap4")) diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 46c66fac48e6..a61213311d6c 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -87,15 +87,8 @@ static int uniphier_clk_probe(struct platform_device *pdev) hw_data->hws[p->idx] = hw; } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - hw_data); -} - -static int uniphier_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - - return 0; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + hw_data); } static const struct of_device_id uniphier_clk_match[] = { @@ -220,7 +213,6 @@ static const struct of_device_id uniphier_clk_match[] = { static struct platform_driver uniphier_clk_driver = { .probe = uniphier_clk_probe, - .remove = uniphier_clk_remove, .driver = { .name = "uniphier-clk", .of_match_table = uniphier_clk_match, diff --git a/drivers/clk/visconti/pll.h b/drivers/clk/visconti/pll.h index 16dae35ab370..01d07f1bf01b 100644 --- a/drivers/clk/visconti/pll.h +++ b/drivers/clk/visconti/pll.h @@ -15,7 +15,6 @@ struct visconti_pll_provider { void __iomem *reg_base; - struct regmap *regmap; struct clk_hw_onecell_data clk_data; struct device_node *node; }; diff --git a/drivers/clk/x86/clk-fch.c b/drivers/clk/x86/clk-fch.c index fdc060e75839..aed7d22fae63 100644 --- a/drivers/clk/x86/clk-fch.c +++ b/drivers/clk/x86/clk-fch.c @@ -92,14 +92,14 @@ static int fch_clk_probe(struct platform_device *pdev) return 0; } -static int fch_clk_remove(struct platform_device *pdev) +static void fch_clk_remove(struct platform_device *pdev) { int i, clks; struct pci_dev *rdev; rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); if (!rdev) - return -ENODEV; + return; clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS; @@ -107,7 +107,6 @@ static int fch_clk_remove(struct platform_device *pdev) clk_hw_unregister(hws[i]); pci_dev_put(rdev); - return 0; } static struct platform_driver fch_clk_driver = { @@ -116,6 +115,6 @@ static struct platform_driver fch_clk_driver = { .suppress_bind_attrs = true, }, .probe = fch_clk_probe, - .remove = fch_clk_remove, + .remove_new = fch_clk_remove, }; builtin_platform_driver(fch_clk_driver); diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c index e746e3f8d05a..2974dd0ec6f4 100644 --- a/drivers/clk/x86/clk-pmc-atom.c +++ b/drivers/clk/x86/clk-pmc-atom.c @@ -367,7 +367,7 @@ err_unreg_clk_plt: return err; } -static int plt_clk_remove(struct platform_device *pdev) +static void plt_clk_remove(struct platform_device *pdev) { struct clk_plt_data *data; @@ -377,7 +377,6 @@ static int plt_clk_remove(struct platform_device *pdev) clkdev_drop(data->mclk_lookup); plt_clk_unregister_loop(data, PMC_CLK_NUM); plt_clk_unregister_parents(data); - return 0; } static struct platform_driver plt_clk_driver = { @@ -385,6 +384,6 @@ static struct platform_driver plt_clk_driver = { .name = "clk-pmc-atom", }, .probe = plt_clk_probe, - .remove = plt_clk_remove, + .remove_new = plt_clk_remove, }; builtin_platform_driver(plt_clk_driver); diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index eb1dfe7ecc1b..e83f104fad02 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -8,12 +8,14 @@ * */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ #define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_FRAC_SHIFT 8 #define WZRD_CLKOUT_FRAC_MASK 0x3ff +#define WZRD_CLKOUT0_FRAC_MASK GENMASK(17, 8) #define WZRD_DR_MAX_INT_DIV_VALUE 255 #define WZRD_DR_STATUS_REG_OFFSET 0x04 @@ -49,6 +52,22 @@ #define WZRD_USEC_POLL 10 #define WZRD_TIMEOUT_POLL 1000 + +/* Divider limits, from UG572 Table 3-4 for Ultrascale+ */ +#define DIV_O 0x01 +#define DIV_ALL 0x03 + +#define WZRD_M_MIN 2 +#define WZRD_M_MAX 128 +#define WZRD_D_MIN 1 +#define WZRD_D_MAX 106 +#define WZRD_VCO_MIN 800000000 +#define WZRD_VCO_MAX 1600000000 +#define WZRD_O_MIN 1 +#define WZRD_O_MAX 128 +#define WZRD_MIN_ERR 20000 +#define WZRD_FRAC_POINTS 1000 + /* Get the mask from width */ #define div_mask(width) ((1 << (width)) - 1) @@ -97,6 +116,9 @@ struct clk_wzrd { * @width: width of the divider bit field * @flags: clk_wzrd divider flags * @table: array of value/divider pairs, last entry should have div = 0 + * @m: value of the multiplier + * @d: value of the common divider + * @o: value of the leaf divider * @lock: register lock */ struct clk_wzrd_divider { @@ -107,6 +129,9 @@ struct clk_wzrd_divider { u8 width; u8 flags; const struct clk_div_table *table; + u32 m; + u32 d; + u32 o; spinlock_t *lock; /* divider lock */ }; @@ -198,12 +223,155 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, return *prate / div; } +static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long vco_freq, freq, diff; + u32 m, d, o; + + for (m = WZRD_M_MIN; m <= WZRD_M_MAX; m++) { + for (d = WZRD_D_MIN; d <= WZRD_D_MAX; d++) { + vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); + if (vco_freq >= WZRD_VCO_MIN && vco_freq <= WZRD_VCO_MAX) { + for (o = WZRD_O_MIN; o <= WZRD_O_MAX; o++) { + freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); + diff = abs(freq - rate); + + if (diff < WZRD_MIN_ERR) { + divider->m = m; + divider->d = d; + divider->o = o; + return 0; + } + } + } + } + } + return -EBUSY; +} + +static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long vco_freq, rate_div, clockout0_div; + u32 reg, pre, value, f; + int err; + + err = clk_wzrd_get_divisors(hw, rate, parent_rate); + if (err) + return err; + + vco_freq = DIV_ROUND_CLOSEST(parent_rate * divider->m, divider->d); + rate_div = DIV_ROUND_CLOSEST_ULL((vco_freq * WZRD_FRAC_POINTS), rate); + + clockout0_div = div_u64(rate_div, WZRD_FRAC_POINTS); + + pre = DIV_ROUND_CLOSEST_ULL(vco_freq * WZRD_FRAC_POINTS, rate); + f = (pre - (clockout0_div * WZRD_FRAC_POINTS)); + f &= WZRD_CLKOUT_FRAC_MASK; + + reg = FIELD_PREP(WZRD_CLKOUT_DIVIDE_MASK, clockout0_div) | + FIELD_PREP(WZRD_CLKOUT0_FRAC_MASK, f); + + writel(reg, divider->base + WZRD_CLK_CFG_REG(2)); + /* Set divisor and clear phase offset */ + reg = FIELD_PREP(WZRD_CLKFBOUT_MULT_MASK, divider->m) | + FIELD_PREP(WZRD_DIVCLK_DIVIDE_MASK, divider->d); + writel(reg, divider->base + WZRD_CLK_CFG_REG(0)); + writel(divider->o, divider->base + WZRD_CLK_CFG_REG(2)); + writel(0, divider->base + WZRD_CLK_CFG_REG(3)); + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + return -ETIMEDOUT; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_REG_OFFSET); + + /* Check status register */ + return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +} + +static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(divider->lock, flags); + + ret = clk_wzrd_dynamic_all_nolock(hw, rate, parent_rate); + + spin_unlock_irqrestore(divider->lock, flags); + + return ret; +} + +static unsigned long clk_wzrd_recalc_rate_all(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + u32 m, d, o, div, reg, f; + + reg = readl(divider->base + WZRD_CLK_CFG_REG(0)); + d = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); + m = FIELD_GET(WZRD_CLKFBOUT_MULT_MASK, reg); + reg = readl(divider->base + WZRD_CLK_CFG_REG(2)); + o = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); + f = FIELD_GET(WZRD_CLKOUT0_FRAC_MASK, reg); + + div = DIV_ROUND_CLOSEST(d * (WZRD_FRAC_POINTS * o + f), WZRD_FRAC_POINTS); + return divider_recalc_rate(hw, parent_rate * m, div, divider->table, + divider->flags, divider->width); +} + +static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long int_freq; + u32 m, d, o, div, f; + int err; + + err = clk_wzrd_get_divisors(hw, rate, *prate); + if (err) + return err; + + m = divider->m; + d = divider->d; + o = divider->o; + + div = d * o; + int_freq = divider_recalc_rate(hw, *prate * m, div, divider->table, + divider->flags, divider->width); + + if (rate > int_freq) { + f = DIV_ROUND_CLOSEST_ULL(rate * WZRD_FRAC_POINTS, int_freq); + rate = DIV_ROUND_CLOSEST(int_freq * f, WZRD_FRAC_POINTS); + } + return rate; +} + static const struct clk_ops clk_wzrd_clk_divider_ops = { .round_rate = clk_wzrd_round_rate, .set_rate = clk_wzrd_dynamic_reconfig, .recalc_rate = clk_wzrd_recalc_rate, }; +static const struct clk_ops clk_wzrd_clk_div_all_ops = { + .round_rate = clk_wzrd_round_rate_all, + .set_rate = clk_wzrd_dynamic_all, + .recalc_rate = clk_wzrd_recalc_rate_all, +}; + static unsigned long clk_wzrd_recalc_ratef(struct clk_hw *hw, unsigned long parent_rate) { @@ -280,7 +448,7 @@ static struct clk *clk_wzrd_register_divf(struct device *dev, void __iomem *base, u16 offset, u8 shift, u8 width, u8 clk_divider_flags, - const struct clk_div_table *table, + u32 div_type, spinlock_t *lock) { struct clk_wzrd_divider *div; @@ -307,7 +475,6 @@ static struct clk *clk_wzrd_register_divf(struct device *dev, div->flags = clk_divider_flags; div->lock = lock; div->hw.init = &init; - div->table = table; hw = &div->hw; ret = devm_clk_hw_register(dev, hw); @@ -324,7 +491,7 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, void __iomem *base, u16 offset, u8 shift, u8 width, u8 clk_divider_flags, - const struct clk_div_table *table, + u32 div_type, spinlock_t *lock) { struct clk_wzrd_divider *div; @@ -337,7 +504,12 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, return ERR_PTR(-ENOMEM); init.name = name; - init.ops = &clk_wzrd_clk_divider_ops; + if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) + init.ops = &clk_divider_ro_ops; + else if (div_type == DIV_O) + init.ops = &clk_wzrd_clk_divider_ops; + else + init.ops = &clk_wzrd_clk_div_all_ops; init.flags = flags; init.parent_names = &parent_name; init.num_parents = 1; @@ -349,7 +521,6 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, div->flags = clk_divider_flags; div->lock = lock; div->hw.init = &init; - div->table = table; hw = &div->hw; ret = devm_clk_hw_register(dev, hw); @@ -425,6 +596,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) const char *clk_name; void __iomem *ctrl_reg; struct clk_wzrd *clk_wzrd; + const char *clkout_name; struct device_node *np = pdev->dev.of_node; int nr_outputs; unsigned long flags = 0; @@ -469,6 +641,26 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } + ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); + if (ret || nr_outputs > WZRD_NUM_OUTPUTS) { + ret = -EINVAL; + goto err_disable_clk; + } + + clkout_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_out0", dev_name(&pdev->dev)); + if (nr_outputs == 1) { + clk_wzrd->clkout[0] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, + __clk_get_name(clk_wzrd->clk_in1), 0, + clk_wzrd->base, WZRD_CLK_CFG_REG(3), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_ALL, &clkwzrd_lock); + + goto out; + } + reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; @@ -476,20 +668,11 @@ static int clk_wzrd_probe(struct platform_device *pdev) reg = reg & WZRD_CLKFBOUT_MULT_MASK; reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; mult = (reg * 1000) + reg_f; - clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); + clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; goto err_disable_clk; } - - ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); - if (ret || nr_outputs > WZRD_NUM_OUTPUTS) { - ret = -EINVAL; - goto err_disable_clk; - } - if (nr_outputs == 1) - flags = CLK_SET_RATE_PARENT; - clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), @@ -500,7 +683,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } - clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev)); + clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; goto err_rm_int_clk; @@ -521,9 +704,8 @@ static int clk_wzrd_probe(struct platform_device *pdev) /* register div per output */ for (i = nr_outputs - 1; i >= 0 ; i--) { - const char *clkout_name; - - clkout_name = kasprintf(GFP_KERNEL, "%s_out%d", dev_name(&pdev->dev), i); + clkout_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%s_out%d", dev_name(&pdev->dev), i); if (!clkout_name) { ret = -ENOMEM; goto err_rm_int_clk; @@ -537,7 +719,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - NULL, &clkwzrd_lock); + DIV_O, &clkwzrd_lock); else clk_wzrd->clkout[i] = clk_wzrd_register_divider (&pdev->dev, clkout_name, @@ -546,7 +728,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - NULL, &clkwzrd_lock); + DIV_O, &clkwzrd_lock); if (IS_ERR(clk_wzrd->clkout[i])) { int j; @@ -559,8 +741,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) } } - kfree(clk_name); - +out: clk_wzrd->clk_data.clks = clk_wzrd->clkout; clk_wzrd->clk_data.clk_num = ARRAY_SIZE(clk_wzrd->clkout); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_wzrd->clk_data); @@ -585,7 +766,6 @@ static int clk_wzrd_probe(struct platform_device *pdev) err_rm_int_clks: clk_unregister(clk_wzrd->clks_internal[1]); err_rm_int_clk: - kfree(clk_name); clk_unregister(clk_wzrd->clks_internal[0]); err_disable_clk: clk_disable_unprepare(clk_wzrd->axi_clk); @@ -593,7 +773,7 @@ err_disable_clk: return ret; } -static int clk_wzrd_remove(struct platform_device *pdev) +static void clk_wzrd_remove(struct platform_device *pdev) { int i; struct clk_wzrd *clk_wzrd = platform_get_drvdata(pdev); @@ -611,8 +791,6 @@ static int clk_wzrd_remove(struct platform_device *pdev) } clk_disable_unprepare(clk_wzrd->axi_clk); - - return 0; } static const struct of_device_id clk_wzrd_ids[] = { @@ -630,7 +808,7 @@ static struct platform_driver clk_wzrd_driver = { .pm = &clk_wzrd_dev_pm_ops, }, .probe = clk_wzrd_probe, - .remove = clk_wzrd_remove, + .remove_new = clk_wzrd_remove, }; module_platform_driver(clk_wzrd_driver); diff --git a/drivers/clk/xilinx/xlnx_vcu.c b/drivers/clk/xilinx/xlnx_vcu.c index d66b1315114e..0786f15ebbe8 100644 --- a/drivers/clk/xilinx/xlnx_vcu.c +++ b/drivers/clk/xilinx/xlnx_vcu.c @@ -702,13 +702,11 @@ error_clk_provider: * Return: Returns 0 on success * Negative error code otherwise */ -static int xvcu_remove(struct platform_device *pdev) +static void xvcu_remove(struct platform_device *pdev) { struct xvcu_device *xvcu; xvcu = platform_get_drvdata(pdev); - if (!xvcu) - return -ENODEV; xvcu_unregister_clock_provider(xvcu); @@ -716,8 +714,6 @@ static int xvcu_remove(struct platform_device *pdev) regmap_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0); clk_disable_unprepare(xvcu->aclk); - - return 0; } static const struct of_device_id xvcu_of_id_table[] = { @@ -733,7 +729,7 @@ static struct platform_driver xvcu_driver = { .of_match_table = xvcu_of_id_table, }, .probe = xvcu_probe, - .remove = xvcu_remove, + .remove_new = xvcu_remove, }; module_platform_driver(xvcu_driver); diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c index 0d3e1377b092..7411a7fd50ac 100644 --- a/drivers/clk/zynqmp/pll.c +++ b/drivers/clk/zynqmp/pll.c @@ -341,7 +341,5 @@ struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id, return ERR_PTR(ret); } - clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX); - return hw; } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5fc8f0e7fb38..526382dc7482 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -479,6 +479,15 @@ config MTK_TIMER help Support for Mediatek timer driver. +config MTK_CPUX_TIMER + bool "MediaTek CPUX timer driver" if COMPILE_TEST + depends on HAS_IOMEM + default ARCH_MEDIATEK + select TIMER_OF + select CLKSRC_MMIO + help + Support for MediaTek CPUXGPT timer driver. + config SPRD_TIMER bool "Spreadtrum timer driver" if EXPERT depends on HAS_IOMEM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 64ab547de97b..f12d3987a960 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += timer-fsl-ftm.o obj-$(CONFIG_VF_PIT_TIMER) += timer-vf-pit.o obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o +obj-$(CONFIG_MTK_CPUX_TIMER) += timer-mediatek-cpux.o obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index c04b47bd4868..ca8d29ab70da 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -363,4 +363,3 @@ module_exit(em_sti_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index bfd60093ee1c..ef8cb1b71be4 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -682,7 +682,7 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type) * processor cannot use the global comparator. */ if (frc_shared) - return ret; + return 0; return exynos4_clockevent_init(); } diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index c0cef92b12b8..bcd9042a0c9f 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -49,7 +49,7 @@ static bool direct_mode_enabled; static int stimer0_irq = -1; static int stimer0_message_sint; -static DEFINE_PER_CPU(long, stimer0_evt); +static __maybe_unused DEFINE_PER_CPU(long, stimer0_evt); /* * Common code for stimer0 interrupts coming via Direct Mode or @@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(hv_stimer0_isr); * stimer0 interrupt handler for architectures that support * per-cpu interrupts, which also implies Direct Mode. */ -static irqreturn_t hv_stimer0_percpu_isr(int irq, void *dev_id) +static irqreturn_t __maybe_unused hv_stimer0_percpu_isr(int irq, void *dev_id) { hv_stimer0_isr(); return IRQ_HANDLED; @@ -196,6 +196,7 @@ void __weak hv_remove_stimer0_handler(void) { }; +#ifdef CONFIG_ACPI /* Called only on architectures with per-cpu IRQs (i.e., not x86/x64) */ static int hv_setup_stimer0_irq(void) { @@ -230,6 +231,16 @@ static void hv_remove_stimer0_irq(void) stimer0_irq = -1; } } +#else +static int hv_setup_stimer0_irq(void) +{ + return 0; +} + +static void hv_remove_stimer0_irq(void) +{ +} +#endif /* hv_stimer_alloc - Global initialization of the clockevent and stimer0 */ int hv_stimer_alloc(bool have_percpu_irqs) @@ -506,9 +517,6 @@ static bool __init hv_init_tsc_clocksource(void) { union hv_reference_tsc_msr tsc_msr; - if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) - return false; - /* * If Hyper-V offers TSC_INVARIANT, then the virtualized TSC correctly * handles frequency and offset changes due to live migration, @@ -525,6 +533,9 @@ static bool __init hv_init_tsc_clocksource(void) hyperv_cs_msr.rating = 250; } + if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) + return false; + hv_read_reference_counter = read_hv_clock_tsc; /* diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 8b2e079d9df2..e81c588d9afe 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -1174,4 +1174,3 @@ module_exit(sh_cmt_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("SuperH CMT Timer Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 169a1fccc497..34872df5458a 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -484,11 +484,6 @@ static int sh_mtu2_probe(struct platform_device *pdev) return 0; } -static int sh_mtu2_remove(struct platform_device *pdev) -{ - return -EBUSY; /* cannot unregister clockevent */ -} - static const struct platform_device_id sh_mtu2_id_table[] = { { "sh-mtu2", 0 }, { }, @@ -503,10 +498,10 @@ MODULE_DEVICE_TABLE(of, sh_mtu2_of_table); static struct platform_driver sh_mtu2_device_driver = { .probe = sh_mtu2_probe, - .remove = sh_mtu2_remove, .driver = { .name = "sh_mtu2", .of_match_table = of_match_ptr(sh_mtu2_of_table), + .suppress_bind_attrs = true, }, .id_table = sh_mtu2_id_table, }; @@ -530,4 +525,3 @@ module_exit(sh_mtu2_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("SuperH MTU2 Timer Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 932f31a7c5be..beffff81c00f 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -674,4 +674,3 @@ module_exit(sh_tmu_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("SuperH TMU Timer Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c index 9996c0542520..b1c248498be4 100644 --- a/drivers/clocksource/timer-davinci.c +++ b/drivers/clocksource/timer-davinci.c @@ -257,21 +257,25 @@ int __init davinci_timer_register(struct clk *clk, resource_size(&timer_cfg->reg), "davinci-timer")) { pr_err("Unable to request memory region\n"); - return -EBUSY; + rv = -EBUSY; + goto exit_clk_disable; } base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg)); if (!base) { pr_err("Unable to map the register range\n"); - return -ENOMEM; + rv = -ENOMEM; + goto exit_mem_region; } davinci_timer_init(base); tick_rate = clk_get_rate(clk); clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL); - if (!clockevent) - return -ENOMEM; + if (!clockevent) { + rv = -ENOMEM; + goto exit_iounmap_base; + } clockevent->dev.name = "tim12"; clockevent->dev.features = CLOCK_EVT_FEAT_ONESHOT; @@ -296,7 +300,7 @@ int __init davinci_timer_register(struct clk *clk, "clockevent/tim12", clockevent); if (rv) { pr_err("Unable to request the clockevent interrupt\n"); - return rv; + goto exit_free_clockevent; } davinci_clocksource.dev.rating = 300; @@ -323,13 +327,27 @@ int __init davinci_timer_register(struct clk *clk, rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate); if (rv) { pr_err("Unable to register clocksource\n"); - return rv; + goto exit_free_irq; } sched_clock_register(davinci_timer_read_sched_clock, DAVINCI_TIMER_CLKSRC_BITS, tick_rate); return 0; + +exit_free_irq: + free_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, + clockevent); +exit_free_clockevent: + kfree(clockevent); +exit_iounmap_base: + iounmap(base); +exit_mem_region: + release_mem_region(timer_cfg->reg.start, + resource_size(&timer_cfg->reg)); +exit_clk_disable: + clk_disable_unprepare(clk); + return rv; } static int __init of_davinci_timer_register(struct device_node *np) diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 7b2c70f2f353..ca3e4cbc80c6 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -420,25 +420,6 @@ static int __init _mxc_timer_init(struct imx_timer *imxtm) return mxc_clockevent_init(imxtm); } -void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type) -{ - struct imx_timer *imxtm; - - imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); - BUG_ON(!imxtm); - - imxtm->clk_per = clk_get_sys("imx-gpt.0", "per"); - imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg"); - - imxtm->base = ioremap(pbase, SZ_4K); - BUG_ON(!imxtm->base); - - imxtm->type = type; - imxtm->irq = irq; - - _mxc_timer_init(imxtm); -} - static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type) { struct imx_timer *imxtm; diff --git a/drivers/clocksource/timer-mediatek-cpux.c b/drivers/clocksource/timer-mediatek-cpux.c new file mode 100644 index 000000000000..a8e3df4c09fd --- /dev/null +++ b/drivers/clocksource/timer-mediatek-cpux.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MediaTek SoCs CPUX General Purpose Timer handling + * + * Based on timer-mediatek.c: + * Copyright (C) 2014 Matthias Brugger + * + * Copyright (C) 2022 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "timer-of.h" + +#define TIMER_SYNC_TICKS 3 + +/* cpux mcusys wrapper */ +#define CPUX_CON_REG 0x0 +#define CPUX_IDX_REG 0x4 + +/* cpux */ +#define CPUX_IDX_GLOBAL_CTRL 0x0 + #define CPUX_ENABLE BIT(0) + #define CPUX_CLK_DIV_MASK GENMASK(10, 8) + #define CPUX_CLK_DIV1 BIT(8) + #define CPUX_CLK_DIV2 BIT(9) + #define CPUX_CLK_DIV4 BIT(10) +#define CPUX_IDX_GLOBAL_IRQ 0x30 + +static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to) +{ + writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); + return readl(timer_of_base(to) + CPUX_CON_REG); +} + +static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to) +{ + writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); + writel(val, timer_of_base(to) + CPUX_CON_REG); +} + +static void mtk_cpux_set_irq(struct timer_of *to, bool enable) +{ + const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask); + u32 val; + + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to); + + if (enable) + val |= *irq_mask; + else + val &= ~(*irq_mask); + + mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to); +} + +static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt) +{ + /* Clear any irq */ + mtk_cpux_set_irq(to_timer_of(clkevt), false); + + /* + * Disabling CPUXGPT timer will crash the platform, especially + * if Trusted Firmware is using it (usually, for sleep states), + * so we only mask the IRQ and call it a day. + */ + return 0; +} + +static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt) +{ + mtk_cpux_set_irq(to_timer_of(clkevt), true); + return 0; +} + +static struct timer_of to = { + /* + * There are per-cpu interrupts for the CPUX General Purpose Timer + * but since this timer feeds the AArch64 System Timer we can rely + * on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ. + */ + .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, + + .clkevt = { + .name = "mtk-cpuxgpt", + .cpumask = cpu_possible_mask, + .rating = 10, + .set_state_shutdown = mtk_cpux_clkevt_shutdown, + .tick_resume = mtk_cpux_clkevt_resume, + }, +}; + +static int __init mtk_cpux_init(struct device_node *node) +{ + u32 freq, val; + int ret; + + /* If this fails, bad things are about to happen... */ + ret = timer_of_init(node, &to); + if (ret) { + WARN(1, "Cannot start CPUX timers.\n"); + return ret; + } + + /* + * Check if we're given a clock with the right frequency for this + * timer, otherwise warn but keep going with the setup anyway, as + * that makes it possible to still boot the kernel, even though + * it may not work correctly (random lockups, etc). + * The reason behind this is that having an early UART may not be + * possible for everyone and this gives a chance to retrieve kmsg + * for eventual debugging even on consumer devices. + */ + freq = timer_of_rate(&to); + if (freq > 13000000) + WARN(1, "Requested unsupported timer frequency %u\n", freq); + + /* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */ + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to); + val &= ~CPUX_CLK_DIV_MASK; + val |= CPUX_CLK_DIV2; + mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to); + + /* Enable all CPUXGPT timers */ + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to); + mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to); + + clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), + TIMER_SYNC_TICKS, 0xffffffff); + + return 0; +} +TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init); diff --git a/drivers/clocksource/timer-mediatek.c b/drivers/clocksource/timer-mediatek.c index d5b29fd03ca2..7bcb4a3f26fb 100644 --- a/drivers/clocksource/timer-mediatek.c +++ b/drivers/clocksource/timer-mediatek.c @@ -22,19 +22,6 @@ #define TIMER_SYNC_TICKS (3) -/* cpux mcusys wrapper */ -#define CPUX_CON_REG 0x0 -#define CPUX_IDX_REG 0x4 - -/* cpux */ -#define CPUX_IDX_GLOBAL_CTRL 0x0 - #define CPUX_ENABLE BIT(0) - #define CPUX_CLK_DIV_MASK GENMASK(10, 8) - #define CPUX_CLK_DIV1 BIT(8) - #define CPUX_CLK_DIV2 BIT(9) - #define CPUX_CLK_DIV4 BIT(10) -#define CPUX_IDX_GLOBAL_IRQ 0x30 - /* gpt */ #define GPT_IRQ_EN_REG 0x00 #define GPT_IRQ_ENABLE(val) BIT((val) - 1) @@ -85,52 +72,6 @@ static void __iomem *gpt_sched_reg __read_mostly; -static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to) -{ - writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); - return readl(timer_of_base(to) + CPUX_CON_REG); -} - -static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to) -{ - writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); - writel(val, timer_of_base(to) + CPUX_CON_REG); -} - -static void mtk_cpux_set_irq(struct timer_of *to, bool enable) -{ - const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask); - u32 val; - - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to); - - if (enable) - val |= *irq_mask; - else - val &= ~(*irq_mask); - - mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to); -} - -static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt) -{ - /* Clear any irq */ - mtk_cpux_set_irq(to_timer_of(clkevt), false); - - /* - * Disabling CPUXGPT timer will crash the platform, especially - * if Trusted Firmware is using it (usually, for sleep states), - * so we only mask the IRQ and call it a day. - */ - return 0; -} - -static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt) -{ - mtk_cpux_set_irq(to_timer_of(clkevt), true); - return 0; -} - static void mtk_syst_ack_irq(struct timer_of *to) { /* Clear and disable interrupt */ @@ -340,60 +281,6 @@ static struct timer_of to = { }, }; -static int __init mtk_cpux_init(struct device_node *node) -{ - static struct timer_of to_cpux; - u32 freq, val; - int ret; - - /* - * There are per-cpu interrupts for the CPUX General Purpose Timer - * but since this timer feeds the AArch64 System Timer we can rely - * on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ. - */ - to_cpux.flags = TIMER_OF_BASE | TIMER_OF_CLOCK; - to_cpux.clkevt.name = "mtk-cpuxgpt"; - to_cpux.clkevt.rating = 10; - to_cpux.clkevt.cpumask = cpu_possible_mask; - to_cpux.clkevt.set_state_shutdown = mtk_cpux_clkevt_shutdown; - to_cpux.clkevt.tick_resume = mtk_cpux_clkevt_resume; - - /* If this fails, bad things are about to happen... */ - ret = timer_of_init(node, &to_cpux); - if (ret) { - WARN(1, "Cannot start CPUX timers.\n"); - return ret; - } - - /* - * Check if we're given a clock with the right frequency for this - * timer, otherwise warn but keep going with the setup anyway, as - * that makes it possible to still boot the kernel, even though - * it may not work correctly (random lockups, etc). - * The reason behind this is that having an early UART may not be - * possible for everyone and this gives a chance to retrieve kmsg - * for eventual debugging even on consumer devices. - */ - freq = timer_of_rate(&to_cpux); - if (freq > 13000000) - WARN(1, "Requested unsupported timer frequency %u\n", freq); - - /* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */ - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux); - val &= ~CPUX_CLK_DIV_MASK; - val |= CPUX_CLK_DIV2; - mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to_cpux); - - /* Enable all CPUXGPT timers */ - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux); - mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to_cpux); - - clockevents_config_and_register(&to_cpux.clkevt, timer_of_rate(&to_cpux), - TIMER_SYNC_TICKS, 0xffffffff); - - return 0; -} - static int __init mtk_syst_init(struct device_node *node) { int ret; @@ -452,4 +339,3 @@ static int __init mtk_gpt_init(struct device_node *node) } TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init); TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init); -TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init); diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c index db2841d0beb8..a4c95161cb22 100644 --- a/drivers/clocksource/timer-stm32-lp.c +++ b/drivers/clocksource/timer-stm32-lp.c @@ -195,11 +195,6 @@ out_clk_disable: return ret; } -static int stm32_clkevent_lp_remove(struct platform_device *pdev) -{ - return -EBUSY; /* cannot unregister clockevent */ -} - static const struct of_device_id stm32_clkevent_lp_of_match[] = { { .compatible = "st,stm32-lptimer-timer", }, {}, @@ -207,15 +202,14 @@ static const struct of_device_id stm32_clkevent_lp_of_match[] = { MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match); static struct platform_driver stm32_clkevent_lp_driver = { - .probe = stm32_clkevent_lp_probe, - .remove = stm32_clkevent_lp_remove, + .probe = stm32_clkevent_lp_probe, .driver = { .name = "stm32-lptimer-timer", - .of_match_table = of_match_ptr(stm32_clkevent_lp_of_match), + .of_match_table = stm32_clkevent_lp_of_match, + .suppress_bind_attrs = true, }, }; module_platform_driver(stm32_clkevent_lp_driver); MODULE_ALIAS("platform:stm32-lptimer-timer"); MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c index ea742889ee06..83d08591ea0a 100644 --- a/drivers/clocksource/timer-tegra186.c +++ b/drivers/clocksource/timer-tegra186.c @@ -447,15 +447,13 @@ unregister_tsc: return err; } -static int tegra186_timer_remove(struct platform_device *pdev) +static void tegra186_timer_remove(struct platform_device *pdev) { struct tegra186_timer *tegra = platform_get_drvdata(pdev); clocksource_unregister(&tegra->usec); clocksource_unregister(&tegra->osc); clocksource_unregister(&tegra->tsc); - - return 0; } static int __maybe_unused tegra186_timer_suspend(struct device *dev) @@ -505,10 +503,9 @@ static struct platform_driver tegra186_wdt_driver = { .of_match_table = tegra186_timer_of_match, }, .probe = tegra186_timer_probe, - .remove = tegra186_timer_remove, + .remove_new = tegra186_timer_remove, }; module_platform_driver(tegra186_wdt_driver); MODULE_AUTHOR("Thierry Reding "); MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index 632523c1232f..c2dcd8d68e45 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -251,24 +251,24 @@ static void __init dmtimer_systimer_assign_alwon(void) counter_32k = -ENODEV; for_each_matching_node(np, dmtimer_match_table) { + struct resource res; if (!dmtimer_is_preferred(np)) continue; - if (of_property_read_bool(np, "ti,timer-alwon")) { - const __be32 *addr; + if (!of_property_read_bool(np, "ti,timer-alwon")) + continue; - addr = of_get_address(np, 0, NULL, NULL); - pa = of_translate_address(np, addr); - if (pa) { - /* Quirky omap3 boards must use dmtimer12 */ - if (quirk_unreliable_oscillator && - pa == 0x48318000) - continue; + if (of_address_to_resource(np, 0, &res)) + continue; - of_node_put(np); - break; - } - } + pa = res.start; + + /* Quirky omap3 boards must use dmtimer12 */ + if (quirk_unreliable_oscillator && pa == 0x48318000) + continue; + + of_node_put(np); + break; } /* Usually no need for dmtimer clocksource if we have counter32 */ @@ -285,24 +285,22 @@ static void __init dmtimer_systimer_assign_alwon(void) static u32 __init dmtimer_systimer_find_first_available(void) { struct device_node *np; - const __be32 *addr; u32 pa = 0; for_each_matching_node(np, dmtimer_match_table) { + struct resource res; if (!dmtimer_is_preferred(np)) continue; - addr = of_get_address(np, 0, NULL, NULL); - pa = of_translate_address(np, addr); - if (pa) { - if (pa == clocksource || pa == clockevent) { - pa = 0; - continue; - } + if (of_address_to_resource(np, 0, &res)) + continue; - of_node_put(np); - break; - } + if (res.start == clocksource || res.start == clockevent) + continue; + + pa = res.start; + of_node_put(np); + break; } return pa; @@ -586,7 +584,7 @@ static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); pr_info("TI gptimer %s: %s%lu Hz at %pOF\n", - name, of_find_property(np, "ti,timer-alwon", NULL) ? + name, of_property_read_bool(np, "ti,timer-alwon") ? "always-on " : "", t->rate, np->parent); return 0; @@ -787,7 +785,7 @@ static int __init dmtimer_clocksource_init(struct device_node *np) t->base + t->ctrl); pr_info("TI gptimer clocksource: %s%pOF\n", - of_find_property(np, "ti,timer-alwon", NULL) ? + of_property_read_bool(np, "ti,timer-alwon") ? "always-on " : "", np->parent); if (!dmtimer_sched_clock_counter) { @@ -812,7 +810,7 @@ err_out_free: */ static int __init dmtimer_systimer_init(struct device_node *np) { - const __be32 *addr; + struct resource res; u32 pa; /* One time init for the preferred timer configuration */ @@ -826,8 +824,9 @@ static int __init dmtimer_systimer_init(struct device_node *np) return -EINVAL; } - addr = of_get_address(np, 0, NULL, NULL); - pa = of_translate_address(np, addr); + + of_address_to_resource(np, 0, &res); + pa = (u32)res.start; if (!pa) return -EINVAL; diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index b24b903a8822..349236a7ba5f 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -1104,13 +1104,13 @@ static int omap_dm_timer_probe(struct platform_device *pdev) platform_set_drvdata(pdev, timer); if (dev->of_node) { - if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) + if (of_property_read_bool(dev->of_node, "ti,timer-alwon")) timer->capability |= OMAP_TIMER_ALWON; - if (of_find_property(dev->of_node, "ti,timer-dsp", NULL)) + if (of_property_read_bool(dev->of_node, "ti,timer-dsp")) timer->capability |= OMAP_TIMER_HAS_DSP_IRQ; - if (of_find_property(dev->of_node, "ti,timer-pwm", NULL)) + if (of_property_read_bool(dev->of_node, "ti,timer-pwm")) timer->capability |= OMAP_TIMER_HAS_PWM; - if (of_find_property(dev->of_node, "ti,timer-secure", NULL)) + if (of_property_read_bool(dev->of_node, "ti,timer-secure")) timer->capability |= OMAP_TIMER_SECURE; } else { timer->id = pdev->id; @@ -1177,7 +1177,7 @@ err_disable: * In addition to freeing platform resources it also deletes the timer * entry from the local list. */ -static int omap_dm_timer_remove(struct platform_device *pdev) +static void omap_dm_timer_remove(struct platform_device *pdev) { struct dmtimer *timer; unsigned long flags; @@ -1197,7 +1197,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - return ret; + if (ret) + dev_err(&pdev->dev, "Unable to determine timer entry in list of drivers on remove\n"); } static const struct omap_dm_timer_ops dmtimer_ops = { @@ -1272,7 +1273,7 @@ MODULE_DEVICE_TABLE(of, omap_timer_match); static struct platform_driver omap_dm_timer_driver = { .probe = omap_dm_timer_probe, - .remove = omap_dm_timer_remove, + .remove_new = omap_dm_timer_remove, .driver = { .name = "omap_timer", .of_match_table = omap_timer_match, @@ -1283,5 +1284,4 @@ static struct platform_driver omap_dm_timer_driver = { module_platform_driver(omap_dm_timer_driver); MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index b982903aaa46..8e43918d38c4 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -3383,7 +3383,7 @@ static int __init comedi_init(void) if (retval) goto out_unregister_chrdev_region; - comedi_class = class_create(THIS_MODULE, "comedi"); + comedi_class = class_create("comedi"); if (IS_ERR(comedi_class)) { retval = PTR_ERR(comedi_class); pr_err("failed to create class\n"); diff --git a/drivers/comedi/drivers/comedi_test.c b/drivers/comedi/drivers/comedi_test.c index 0b5c0af1cebf..c02dc19a679b 100644 --- a/drivers/comedi/drivers/comedi_test.c +++ b/drivers/comedi/drivers/comedi_test.c @@ -795,7 +795,7 @@ static int __init comedi_test_init(void) } if (!config_mode) { - ctcls = class_create(THIS_MODULE, CLASS_NAME); + ctcls = class_create(CLASS_NAME); if (IS_ERR(ctcls)) { pr_warn("comedi_test: unable to create class\n"); goto clean3; diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index b5ba8fb02cf7..4228be917038 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -73,6 +73,17 @@ config MICROCHIP_TCB_CAPTURE To compile this driver as a module, choose M here: the module will be called microchip-tcb-capture. +config RZ_MTU3_CNT + tristate "Renesas RZ/G2L MTU3a counter driver" + depends on RZ_MTU3 || COMPILE_TEST + help + Enable support for MTU3a counter driver found on Renesas RZ/G2L alike + SoCs. This IP supports both 16-bit and 32-bit phase counting mode + support. + + To compile this driver as a module, choose M here: the + module will be called rz-mtu3-cnt. + config STM32_LPTIMER_CNT tristate "STM32 LP Timer encoder counter driver" depends on MFD_STM32_LPTIMER || COMPILE_TEST diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index b9a369e0d4fc..933fdd50b3e4 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o counter-chrdev.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o +obj-$(CONFIG_RZ_MTU3_CNT) += rz-mtu3-cnt.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o obj-$(CONFIG_TI_EQEP) += ti-eqep.o diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c new file mode 100644 index 000000000000..48c83933aa2f --- /dev/null +++ b/drivers/counter/rz-mtu3-cnt.c @@ -0,0 +1,906 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L MTU3a Counter driver + * + * Copyright (C) 2022 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Register descriptions + * TSR: Timer Status Register + * TMDR1: Timer Mode Register 1 + * TMDR3: Timer Mode Register 3 + * TIOR: Timer I/O Control Register + * TCR: Timer Control Register + * TCNT: Timer Counter + * TGRA: Timer general register A + * TCNTLW: Timer Longword Counter + * TGRALW: Timer longword general register A + */ + +#define RZ_MTU3_TSR_TCFD BIT(7) /* Count Direction Flag */ + +#define RZ_MTU3_TMDR1_PH_CNT_MODE_1 (4) /* Phase counting mode 1 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_2 (5) /* Phase counting mode 2 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_3 (6) /* Phase counting mode 3 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_4 (7) /* Phase counting mode 4 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_5 (9) /* Phase counting mode 5 */ +#define RZ_MTU3_TMDR1_PH_CNT_MODE_MASK (0xf) + +/* + * LWA: MTU1/MTU2 Combination Longword Access Control + * 0: 16-bit, 1: 32-bit + */ +#define RZ_MTU3_TMDR3_LWA (0) + +/* + * PHCKSEL: External Input Phase Clock Select + * 0: MTCLKA and MTCLKB, 1: MTCLKC and MTCLKD + */ +#define RZ_MTU3_TMDR3_PHCKSEL (1) + +#define RZ_MTU3_16_BIT_MTU1_CH (0) +#define RZ_MTU3_16_BIT_MTU2_CH (1) +#define RZ_MTU3_32_BIT_CH (2) + +#define RZ_MTU3_TIOR_NO_OUTPUT (0) /* Output prohibited */ +#define RZ_MTU3_TIOR_IC_BOTH (10) /* Input capture at both edges */ + +#define SIGNAL_A_ID (0) +#define SIGNAL_B_ID (1) +#define SIGNAL_C_ID (2) +#define SIGNAL_D_ID (3) + +#define RZ_MTU3_MAX_HW_CNTR_CHANNELS (2) +#define RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS (3) + +/** + * struct rz_mtu3_cnt - MTU3 counter private data + * + * @clk: MTU3 module clock + * @lock: Lock to prevent concurrent access for ceiling and count + * @ch: HW channels for the counters + * @count_is_enabled: Enabled state of Counter value channel + * @mtu_16bit_max: Cache for 16-bit counters + * @mtu_32bit_max: Cache for 32-bit counters + */ +struct rz_mtu3_cnt { + struct clk *clk; + struct mutex lock; + struct rz_mtu3_channel *ch; + bool count_is_enabled[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS]; + union { + u16 mtu_16bit_max[RZ_MTU3_MAX_HW_CNTR_CHANNELS]; + u32 mtu_32bit_max; + }; +}; + +static const enum counter_function rz_mtu3_count_functions[] = { + COUNTER_FUNCTION_QUADRATURE_X4, + COUNTER_FUNCTION_PULSE_DIRECTION, + COUNTER_FUNCTION_QUADRATURE_X2_B, +}; + +static inline size_t rz_mtu3_get_hw_ch(const size_t id) +{ + return (id == RZ_MTU3_32_BIT_CH) ? 0 : id; +} + +static inline struct rz_mtu3_channel *rz_mtu3_get_ch(struct counter_device *counter, int id) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(id); + + return &priv->ch[ch_id]; +} + +static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + + if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) + return false; + + if (id != RZ_MTU3_32_BIT_CH && !test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) + return false; + + return true; +} + +static int rz_mtu3_lock_if_counter_is_valid(struct counter_device *counter, + struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + int id) +{ + mutex_lock(&priv->lock); + + if (ch->is_busy && !priv->count_is_enabled[id]) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + if (rz_mtu3_is_counter_invalid(counter, id)) { + mutex_unlock(&priv->lock); + return -EBUSY; + } + + return 0; +} + +static int rz_mtu3_lock_if_count_is_enabled(struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + int id) +{ + mutex_lock(&priv->lock); + + if (ch->is_busy && !priv->count_is_enabled[id]) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + return 0; +} + +static int rz_mtu3_count_read(struct counter_device *counter, + struct counter_count *count, u64 *val) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + *val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW); + else + *val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_write(struct counter_device *counter, + struct counter_count *count, const u64 val) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val); + else + rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch, + struct rz_mtu3_cnt *const priv, + enum counter_function *function) +{ + u8 timer_mode; + + pm_runtime_get_sync(ch->dev); + timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1); + pm_runtime_put(ch->dev); + + switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) { + case RZ_MTU3_TMDR1_PH_CNT_MODE_1: + *function = COUNTER_FUNCTION_QUADRATURE_X4; + return 0; + case RZ_MTU3_TMDR1_PH_CNT_MODE_2: + *function = COUNTER_FUNCTION_PULSE_DIRECTION; + return 0; + case RZ_MTU3_TMDR1_PH_CNT_MODE_4: + *function = COUNTER_FUNCTION_QUADRATURE_X2_B; + return 0; + default: + /* + * TODO: + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 + */ + return -EINVAL; + } +} + +static int rz_mtu3_count_function_read(struct counter_device *counter, + struct counter_count *count, + enum counter_function *function) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + ret = rz_mtu3_count_function_read_helper(ch, priv, function); + mutex_unlock(&priv->lock); + + return ret; +} + +static int rz_mtu3_count_function_write(struct counter_device *counter, + struct counter_count *count, + enum counter_function function) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + u8 timer_mode; + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + switch (function) { + case COUNTER_FUNCTION_QUADRATURE_X4: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_1; + break; + case COUNTER_FUNCTION_PULSE_DIRECTION: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_2; + break; + case COUNTER_FUNCTION_QUADRATURE_X2_B: + timer_mode = RZ_MTU3_TMDR1_PH_CNT_MODE_4; + break; + default: + /* + * TODO: + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_3 + * - need to add RZ_MTU3_TMDR1_PH_CNT_MODE_5 + */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + pm_runtime_get_sync(ch->dev); + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_direction_read(struct counter_device *counter, + struct counter_count *count, + enum counter_count_direction *direction) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + u8 tsr; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + pm_runtime_get_sync(ch->dev); + tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR); + pm_runtime_put(ch->dev); + + *direction = (tsr & RZ_MTU3_TSR_TCFD) ? + COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD; + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_ceiling_read(struct counter_device *counter, + struct counter_count *count, + u64 *ceiling) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(count->id); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + switch (count->id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + *ceiling = priv->mtu_16bit_max[ch_id]; + break; + case RZ_MTU3_32_BIT_CH: + *ceiling = priv->mtu_32bit_max; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + mutex_unlock(&priv->lock); + return 0; +} + +static int rz_mtu3_count_ceiling_write(struct counter_device *counter, + struct counter_count *count, + u64 ceiling) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + const size_t ch_id = rz_mtu3_get_hw_ch(count->id); + int ret; + + ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id); + if (ret) + return ret; + + switch (count->id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + if (ceiling > U16_MAX) { + mutex_unlock(&priv->lock); + return -ERANGE; + } + priv->mtu_16bit_max[ch_id] = ceiling; + break; + case RZ_MTU3_32_BIT_CH: + if (ceiling > U32_MAX) { + mutex_unlock(&priv->lock); + return -ERANGE; + } + priv->mtu_32bit_max = ceiling; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + pm_runtime_get_sync(ch->dev); + if (count->id == RZ_MTU3_32_BIT_CH) + rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling); + else + rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling); + + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + pm_runtime_put(ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static void rz_mtu3_32bit_cnt_setting(struct counter_device *counter) +{ + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + /* Phase counting mode 1 is used as default in initialization. */ + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); + + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + rz_mtu3_8bit_ch_write(ch1, RZ_MTU3_TIOR, RZ_MTU3_TIOR_IC_BOTH); + + rz_mtu3_enable(ch1); + rz_mtu3_enable(ch2); +} + +static void rz_mtu3_16bit_cnt_setting(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + + /* Phase counting mode 1 is used as default in initialization. */ + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, RZ_MTU3_TMDR1_PH_CNT_MODE_1); + + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); + rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TIOR, RZ_MTU3_TIOR_NO_OUTPUT); + rz_mtu3_enable(ch); +} + +static int rz_mtu3_initialize_counter(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + switch (id) { + case RZ_MTU3_16_BIT_MTU1_CH: + case RZ_MTU3_16_BIT_MTU2_CH: + if (!rz_mtu3_request_channel(ch)) + return -EBUSY; + + rz_mtu3_16bit_cnt_setting(counter, id); + return 0; + case RZ_MTU3_32_BIT_CH: + /* + * 32-bit phase counting need MTU1 and MTU2 to create 32-bit + * cascade counter. + */ + if (!rz_mtu3_request_channel(ch1)) + return -EBUSY; + + if (!rz_mtu3_request_channel(ch2)) { + rz_mtu3_release_channel(ch1); + return -EBUSY; + } + + rz_mtu3_32bit_cnt_setting(counter); + return 0; + default: + /* should never reach this path */ + return -EINVAL; + } +} + +static void rz_mtu3_terminate_counter(struct counter_device *counter, int id) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + + if (id == RZ_MTU3_32_BIT_CH) { + rz_mtu3_release_channel(ch2); + rz_mtu3_release_channel(ch1); + rz_mtu3_disable(ch2); + rz_mtu3_disable(ch1); + } else { + rz_mtu3_release_channel(ch); + rz_mtu3_disable(ch); + } +} + +static int rz_mtu3_count_enable_read(struct counter_device *counter, + struct counter_count *count, u8 *enable) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_channel *const ch1 = rz_mtu3_get_ch(counter, 0); + struct rz_mtu3_channel *const ch2 = rz_mtu3_get_ch(counter, 1); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + if (count->id == RZ_MTU3_32_BIT_CH) + *enable = rz_mtu3_is_enabled(ch1) && rz_mtu3_is_enabled(ch2); + else + *enable = rz_mtu3_is_enabled(ch); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_count_enable_write(struct counter_device *counter, + struct counter_count *count, u8 enable) +{ + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret = 0; + + if (enable) { + pm_runtime_get_sync(ch->dev); + mutex_lock(&priv->lock); + ret = rz_mtu3_initialize_counter(counter, count->id); + if (ret == 0) + priv->count_is_enabled[count->id] = true; + mutex_unlock(&priv->lock); + } else { + mutex_lock(&priv->lock); + rz_mtu3_terminate_counter(counter, count->id); + priv->count_is_enabled[count->id] = false; + mutex_unlock(&priv->lock); + pm_runtime_put(ch->dev); + } + + return ret; +} + +static int rz_mtu3_lock_if_ch0_is_enabled(struct rz_mtu3_cnt *const priv) +{ + mutex_lock(&priv->lock); + if (priv->ch->is_busy && !(priv->count_is_enabled[RZ_MTU3_16_BIT_MTU1_CH] || + priv->count_is_enabled[RZ_MTU3_32_BIT_CH])) { + mutex_unlock(&priv->lock); + return -EINVAL; + } + + return 0; +} + +static int rz_mtu3_cascade_counts_enable_get(struct counter_device *counter, + u8 *cascade_enable) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + *cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_cascade_counts_enable_set(struct counter_device *counter, + u8 cascade_enable) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, + RZ_MTU3_TMDR3_LWA, cascade_enable); + pm_runtime_put(priv->ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_ext_input_phase_clock_select_get(struct counter_device *counter, + u32 *ext_input_phase_clock_select) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + pm_runtime_put(priv->ch->dev); + *ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); + mutex_unlock(&priv->lock); + + return 0; +} + +static int rz_mtu3_ext_input_phase_clock_select_set(struct counter_device *counter, + u32 ext_input_phase_clock_select) +{ + struct rz_mtu3_cnt *const priv = counter_priv(counter); + int ret; + + ret = rz_mtu3_lock_if_ch0_is_enabled(priv); + if (ret) + return ret; + + pm_runtime_get_sync(priv->ch->dev); + rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, + RZ_MTU3_TMDR3_PHCKSEL, + ext_input_phase_clock_select); + pm_runtime_put(priv->ch->dev); + mutex_unlock(&priv->lock); + + return 0; +} + +static struct counter_comp rz_mtu3_count_ext[] = { + COUNTER_COMP_DIRECTION(rz_mtu3_count_direction_read), + COUNTER_COMP_ENABLE(rz_mtu3_count_enable_read, + rz_mtu3_count_enable_write), + COUNTER_COMP_CEILING(rz_mtu3_count_ceiling_read, + rz_mtu3_count_ceiling_write), +}; + +static const enum counter_synapse_action rz_mtu3_synapse_actions[] = { + COUNTER_SYNAPSE_ACTION_BOTH_EDGES, + COUNTER_SYNAPSE_ACTION_RISING_EDGE, + COUNTER_SYNAPSE_ACTION_NONE, +}; + +static int rz_mtu3_action_read(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, + enum counter_synapse_action *action) +{ + const bool is_signal_ab = (synapse->signal->id == SIGNAL_A_ID) || + (synapse->signal->id == SIGNAL_B_ID); + struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); + struct rz_mtu3_cnt *const priv = counter_priv(counter); + enum counter_function function; + bool mtclkc_mtclkd; + unsigned long tmdr; + int ret; + + ret = rz_mtu3_lock_if_count_is_enabled(ch, priv, count->id); + if (ret) + return ret; + + ret = rz_mtu3_count_function_read_helper(ch, priv, &function); + if (ret) { + mutex_unlock(&priv->lock); + return ret; + } + + /* Default action mode */ + *action = COUNTER_SYNAPSE_ACTION_NONE; + + if (count->id != RZ_MTU3_16_BIT_MTU1_CH) { + tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); + mtclkc_mtclkd = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); + if ((mtclkc_mtclkd && is_signal_ab) || + (!mtclkc_mtclkd && !is_signal_ab)) { + mutex_unlock(&priv->lock); + return 0; + } + } + + switch (function) { + case COUNTER_FUNCTION_PULSE_DIRECTION: + /* + * Rising edges on signal A (signal C) updates the respective + * count. The input level of signal B (signal D) determines + * direction. + */ + if (synapse->signal->id == SIGNAL_A_ID || + synapse->signal->id == SIGNAL_C_ID) + *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; + break; + case COUNTER_FUNCTION_QUADRATURE_X2_B: + /* + * Any state transition on quadrature pair signal B (signal D) + * updates the respective count. + */ + if (synapse->signal->id == SIGNAL_B_ID || + synapse->signal->id == SIGNAL_D_ID) + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + break; + case COUNTER_FUNCTION_QUADRATURE_X4: + /* counts up/down on both edges of A (C) and B (D) signal */ + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + break; + default: + /* should never reach this path */ + mutex_unlock(&priv->lock); + return -EINVAL; + } + + mutex_unlock(&priv->lock); + + return 0; +} + +static const struct counter_ops rz_mtu3_cnt_ops = { + .count_read = rz_mtu3_count_read, + .count_write = rz_mtu3_count_write, + .function_read = rz_mtu3_count_function_read, + .function_write = rz_mtu3_count_function_write, + .action_read = rz_mtu3_action_read, +}; + +#define RZ_MTU3_PHASE_SIGNAL(_id, _name) { \ + .id = (_id), \ + .name = (_name), \ +} + +static struct counter_signal rz_mtu3_signals[] = { + RZ_MTU3_PHASE_SIGNAL(SIGNAL_A_ID, "MTU1 MTCLKA"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_B_ID, "MTU1 MTCLKB"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_C_ID, "MTU2 MTCLKC"), + RZ_MTU3_PHASE_SIGNAL(SIGNAL_D_ID, "MTU2 MTCLKD"), +}; + +static struct counter_synapse rz_mtu3_mtu1_count_synapses[] = { + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 1, + } +}; + +static struct counter_synapse rz_mtu3_mtu2_count_synapses[] = { + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 1, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 2, + }, + { + .actions_list = rz_mtu3_synapse_actions, + .num_actions = ARRAY_SIZE(rz_mtu3_synapse_actions), + .signal = rz_mtu3_signals + 3, + } +}; + +static struct counter_count rz_mtu3_counts[] = { + { + .id = RZ_MTU3_16_BIT_MTU1_CH, + .name = "Channel 1 Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu1_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu1_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + }, + { + .id = RZ_MTU3_16_BIT_MTU2_CH, + .name = "Channel 2 Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu2_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + }, + { + .id = RZ_MTU3_32_BIT_CH, + .name = "Channel 1 and 2 (cascaded) Count", + .functions_list = rz_mtu3_count_functions, + .num_functions = ARRAY_SIZE(rz_mtu3_count_functions), + .synapses = rz_mtu3_mtu2_count_synapses, + .num_synapses = ARRAY_SIZE(rz_mtu3_mtu2_count_synapses), + .ext = rz_mtu3_count_ext, + .num_ext = ARRAY_SIZE(rz_mtu3_count_ext), + } +}; + +static const char *const rz_mtu3_ext_input_phase_clock_select[] = { + "MTCLKA-MTCLKB", + "MTCLKC-MTCLKD", +}; + +static DEFINE_COUNTER_ENUM(rz_mtu3_ext_input_phase_clock_select_enum, + rz_mtu3_ext_input_phase_clock_select); + +static struct counter_comp rz_mtu3_device_ext[] = { + COUNTER_COMP_DEVICE_BOOL("cascade_counts_enable", + rz_mtu3_cascade_counts_enable_get, + rz_mtu3_cascade_counts_enable_set), + COUNTER_COMP_DEVICE_ENUM("external_input_phase_clock_select", + rz_mtu3_ext_input_phase_clock_select_get, + rz_mtu3_ext_input_phase_clock_select_set, + rz_mtu3_ext_input_phase_clock_select_enum), +}; + +static int rz_mtu3_cnt_pm_runtime_suspend(struct device *dev) +{ + struct clk *const clk = dev_get_drvdata(dev); + + clk_disable_unprepare(clk); + + return 0; +} + +static int rz_mtu3_cnt_pm_runtime_resume(struct device *dev) +{ + struct clk *const clk = dev_get_drvdata(dev); + + clk_prepare_enable(clk); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(rz_mtu3_cnt_pm_ops, + rz_mtu3_cnt_pm_runtime_suspend, + rz_mtu3_cnt_pm_runtime_resume, NULL); + +static void rz_mtu3_cnt_pm_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); +} + +static int rz_mtu3_cnt_probe(struct platform_device *pdev) +{ + struct rz_mtu3 *ddata = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct counter_device *counter; + struct rz_mtu3_channel *ch; + struct rz_mtu3_cnt *priv; + unsigned int i; + int ret; + + counter = devm_counter_alloc(dev, sizeof(*priv)); + if (!counter) + return -ENOMEM; + + priv = counter_priv(counter); + priv->clk = ddata->clk; + priv->mtu_32bit_max = U32_MAX; + priv->ch = &ddata->channels[RZ_MTU3_CHAN_1]; + ch = &priv->ch[0]; + for (i = 0; i < RZ_MTU3_MAX_HW_CNTR_CHANNELS; i++) { + ch->dev = dev; + priv->mtu_16bit_max[i] = U16_MAX; + ch++; + } + + mutex_init(&priv->lock); + platform_set_drvdata(pdev, priv->clk); + clk_prepare_enable(priv->clk); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_cnt_pm_disable, dev); + if (ret < 0) + goto disable_clock; + + counter->name = dev_name(dev); + counter->parent = dev; + counter->ops = &rz_mtu3_cnt_ops; + counter->counts = rz_mtu3_counts; + counter->num_counts = ARRAY_SIZE(rz_mtu3_counts); + counter->signals = rz_mtu3_signals; + counter->num_signals = ARRAY_SIZE(rz_mtu3_signals); + counter->ext = rz_mtu3_device_ext; + counter->num_ext = ARRAY_SIZE(rz_mtu3_device_ext); + + /* Register Counter device */ + ret = devm_counter_add(dev, counter); + if (ret < 0) { + dev_err_probe(dev, ret, "Failed to add counter\n"); + goto disable_clock; + } + + return 0; + +disable_clock: + clk_disable_unprepare(priv->clk); + + return ret; +} + +static struct platform_driver rz_mtu3_cnt_driver = { + .probe = rz_mtu3_cnt_probe, + .driver = { + .name = "rz-mtu3-counter", + .pm = pm_ptr(&rz_mtu3_cnt_pm_ops), + }, +}; +module_platform_driver(rz_mtu3_cnt_driver); + +MODULE_AUTHOR("Biju Das "); +MODULE_ALIAS("platform:rz-mtu3-counter"); +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a counter driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(COUNTER); diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 29904395e95f..b2f05d27167e 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -975,7 +975,7 @@ static int __init acpi_cpufreq_probe(struct platform_device *pdev) /* don't keep reloading if cpufreq_driver exists */ if (cpufreq_get_current_driver()) - return -EEXIST; + return -ENODEV; pr_debug("%s\n", __func__); diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index fcb54a6f6598..ddd346a239e0 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -63,7 +63,6 @@ static struct cpufreq_driver *current_pstate_driver; static struct cpufreq_driver amd_pstate_driver; static struct cpufreq_driver amd_pstate_epp_driver; static int cppc_state = AMD_PSTATE_DISABLE; -struct kobject *amd_pstate_kobj; /* * AMD Energy Preference Performance (EPP) @@ -445,9 +444,8 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy) return 0; } -static int amd_pstate_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static int amd_pstate_update_freq(struct cpufreq_policy *policy, + unsigned int target_freq, bool fast_switch) { struct cpufreq_freqs freqs; struct amd_cpudata *cpudata = policy->driver_data; @@ -466,26 +464,51 @@ static int amd_pstate_target(struct cpufreq_policy *policy, des_perf = DIV_ROUND_CLOSEST(target_freq * cap_perf, cpudata->max_freq); - cpufreq_freq_transition_begin(policy, &freqs); + WARN_ON(fast_switch && !policy->fast_switch_enabled); + /* + * If fast_switch is desired, then there aren't any registered + * transition notifiers. See comment for + * cpufreq_enable_fast_switch(). + */ + if (!fast_switch) + cpufreq_freq_transition_begin(policy, &freqs); + amd_pstate_update(cpudata, min_perf, des_perf, - max_perf, false, policy->governor->flags); - cpufreq_freq_transition_end(policy, &freqs, false); + max_perf, fast_switch, policy->governor->flags); + + if (!fast_switch) + cpufreq_freq_transition_end(policy, &freqs, false); return 0; } +static int amd_pstate_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + return amd_pstate_update_freq(policy, target_freq, false); +} + +static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + return amd_pstate_update_freq(policy, target_freq, true); +} + static void amd_pstate_adjust_perf(unsigned int cpu, unsigned long _min_perf, unsigned long target_perf, unsigned long capacity) { unsigned long max_perf, min_perf, des_perf, - cap_perf, lowest_nonlinear_perf; + cap_perf, lowest_nonlinear_perf, max_freq; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); struct amd_cpudata *cpudata = policy->driver_data; + unsigned int target_freq; cap_perf = READ_ONCE(cpudata->highest_perf); lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); + max_freq = READ_ONCE(cpudata->max_freq); des_perf = cap_perf; if (target_perf < capacity) @@ -502,6 +525,10 @@ static void amd_pstate_adjust_perf(unsigned int cpu, if (max_perf < min_perf) max_perf = min_perf; + des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf); + target_freq = div_u64(des_perf * max_freq, max_perf); + policy->cur = target_freq; + amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true, policy->governor->flags); cpufreq_cpu_put(policy); @@ -716,6 +743,7 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy) freq_qos_remove_request(&cpudata->req[1]); freq_qos_remove_request(&cpudata->req[0]); + policy->fast_switch_possible = false; kfree(cpudata); return 0; @@ -1013,6 +1041,7 @@ static struct attribute *pstate_global_attributes[] = { }; static const struct attribute_group amd_pstate_global_attr_group = { + .name = "amd_pstate", .attrs = pstate_global_attributes, }; @@ -1079,7 +1108,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) policy->policy = CPUFREQ_POLICY_POWERSAVE; if (boot_cpu_has(X86_FEATURE_CPPC)) { - policy->fast_switch_possible = true; ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &value); if (ret) return ret; @@ -1102,7 +1130,6 @@ free_cpudata1: static int amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy) { pr_debug("CPU %d exiting\n", policy->cpu); - policy->fast_switch_possible = false; return 0; } @@ -1309,6 +1336,7 @@ static struct cpufreq_driver amd_pstate_driver = { .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS, .verify = amd_pstate_verify, .target = amd_pstate_target, + .fast_switch = amd_pstate_fast_switch, .init = amd_pstate_cpu_init, .exit = amd_pstate_cpu_exit, .suspend = amd_pstate_cpu_suspend, @@ -1334,6 +1362,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = { static int __init amd_pstate_init(void) { + struct device *dev_root; int ret; if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) @@ -1380,24 +1409,19 @@ static int __init amd_pstate_init(void) if (ret) pr_err("failed to register with return %d\n", ret); - amd_pstate_kobj = kobject_create_and_add("amd_pstate", &cpu_subsys.dev_root->kobj); - if (!amd_pstate_kobj) { - ret = -EINVAL; - pr_err("global sysfs registration failed.\n"); - goto kobject_free; - } - - ret = sysfs_create_group(amd_pstate_kobj, &amd_pstate_global_attr_group); - if (ret) { - pr_err("sysfs attribute export failed with error %d.\n", ret); - goto global_attr_free; + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + ret = sysfs_create_group(&dev_root->kobj, &amd_pstate_global_attr_group); + put_device(dev_root); + if (ret) { + pr_err("sysfs attribute export failed with error %d.\n", ret); + goto global_attr_free; + } } return ret; global_attr_free: - kobject_put(amd_pstate_kobj); -kobject_free: cpufreq_unregister_driver(current_pstate_driver); return ret; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2ac905c637dd..6b52ebe5a890 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2937,11 +2937,16 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); static int __init cpufreq_core_init(void) { struct cpufreq_governor *gov = cpufreq_default_governor(); + struct device *dev_root; if (cpufreq_disabled()) return -ENODEV; - cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { + cpufreq_global_kobject = kobject_create_and_add("cpufreq", &dev_root->kobj); + put_device(dev_root); + } BUG_ON(!cpufreq_global_kobject); if (!strlen(default_governor)) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 2a1a6779d82d..2548ec92faa2 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1473,10 +1473,13 @@ static struct kobject *intel_pstate_kobject; static void __init intel_pstate_sysfs_expose_params(void) { + struct device *dev_root = bus_get_dev_root(&cpu_subsys); int rc; - intel_pstate_kobject = kobject_create_and_add("intel_pstate", - &cpu_subsys.dev_root->kobj); + if (dev_root) { + intel_pstate_kobject = kobject_create_and_add("intel_pstate", &dev_root->kobj); + put_device(dev_root); + } if (WARN_ON(!intel_pstate_kobject)) return; diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 1d2cfea9858a..73efbcf5513b 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -583,7 +583,7 @@ static int __init pcc_cpufreq_probe(struct platform_device *pdev) /* Skip initialization if another cpufreq driver is there. */ if (cpufreq_get_current_driver()) - return -EEXIST; + return -ENODEV; if (acpi_disabled) return -ENODEV; diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index 1bad4d2b7be3..a7d33f3ee01e 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -33,16 +33,16 @@ static struct cpuidle_state *cpuidle_state_table __read_mostly; static u64 snooze_timeout __read_mostly; static bool snooze_timeout_en __read_mostly; -static int snooze_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static __cpuidle +int snooze_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, + int index) { u64 snooze_exit_time; set_thread_flag(TIF_POLLING_NRFLAG); pseries_idle_prolog(); - local_irq_enable(); + raw_local_irq_enable(); snooze_exit_time = get_tb() + snooze_timeout; dev->poll_time_limit = false; @@ -65,14 +65,14 @@ static int snooze_loop(struct cpuidle_device *dev, HMT_medium(); clear_thread_flag(TIF_POLLING_NRFLAG); - local_irq_disable(); + raw_local_irq_disable(); pseries_idle_epilog(); return index; } -static void check_and_cede_processor(void) +static __cpuidle void check_and_cede_processor(void) { /* * Ensure our interrupt state is properly tracked, @@ -216,9 +216,9 @@ static int __init parse_cede_parameters(void) #define NR_DEDICATED_STATES 2 /* snooze, CEDE */ static u8 cede_latency_hint[NR_DEDICATED_STATES]; -static int dedicated_cede_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static __cpuidle +int dedicated_cede_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, + int index) { u8 old_latency_hint; @@ -230,7 +230,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, HMT_medium(); check_and_cede_processor(); - local_irq_disable(); + raw_local_irq_disable(); get_lppaca()->donate_dedicated_cpu = 0; get_lppaca()->cede_latency_hint = old_latency_hint; @@ -239,9 +239,9 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, return index; } -static int shared_cede_loop(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static __cpuidle +int shared_cede_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, + int index) { pseries_idle_prolog(); @@ -255,7 +255,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, */ check_and_cede_processor(); - local_irq_disable(); + raw_local_irq_disable(); pseries_idle_epilog(); return index; diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c index f2ccda2c3871..e8094fc92491 100644 --- a/drivers/cpuidle/cpuidle-riscv-sbi.c +++ b/drivers/cpuidle/cpuidle-riscv-sbi.c @@ -613,7 +613,7 @@ static int __init sbi_cpuidle_init(void) * 2) SBI HSM extension is available */ if ((sbi_spec_version < sbi_mk_version(0, 3)) || - sbi_probe_extension(SBI_EXT_HSM) <= 0) { + !sbi_probe_extension(SBI_EXT_HSM)) { pr_info("HSM suspend not available\n"); return 0; } diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0b00f21cefe3..8e929f6602ce 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -808,7 +808,7 @@ static int __init cpuidle_init(void) if (cpuidle_disabled()) return -ENODEV; - return cpuidle_add_interface(cpu_subsys.dev_root); + return cpuidle_add_interface(); } module_param(off, int, 0444); diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 9f336af17fa6..52701d9588f1 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -30,7 +30,7 @@ extern int cpuidle_switch_governor(struct cpuidle_governor *gov); struct device; -extern int cpuidle_add_interface(struct device *dev); +extern int cpuidle_add_interface(void); extern void cpuidle_remove_interface(struct device *dev); extern int cpuidle_add_device_sysfs(struct cpuidle_device *device); extern void cpuidle_remove_device_sysfs(struct cpuidle_device *device); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 48948b171749..d6f5da61cb7d 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -119,11 +119,18 @@ static struct attribute_group cpuidle_attr_group = { /** * cpuidle_add_interface - add CPU global sysfs attributes - * @dev: the target device */ -int cpuidle_add_interface(struct device *dev) +int cpuidle_add_interface(void) { - return sysfs_create_group(&dev->kobj, &cpuidle_attr_group); + struct device *dev_root = bus_get_dev_root(&cpu_subsys); + int retval; + + if (!dev_root) + return -EINVAL; + + retval = sysfs_create_group(&dev_root->kobj, &cpuidle_attr_group); + put_device(dev_root); + return retval; } /** diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index 83c6dfad77e1..16966cc94e24 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -151,7 +151,7 @@ static int sun8i_ss_setup_ivs(struct skcipher_request *areq) } rctx->p_iv[i] = a; /* we need to setup all others IVs only in the decrypt way */ - if (rctx->op_dir & SS_ENCRYPTION) + if (rctx->op_dir == SS_ENCRYPTION) return 0; todo = min(len, sg_dma_len(sg)); len -= todo; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index b1f3327f65e0..f97166fba9d9 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -892,7 +892,7 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp) /* * The length of the ID shouldn't be assumed by software since * it may change in the future. The allocation size is limited - * to 1 << (PAGE_SHIFT + MAX_ORDER - 1) by the page allocator. + * to 1 << (PAGE_SHIFT + MAX_ORDER) by the page allocator. * If the allocation fails, simply return ENOMEM rather than * warning in the kernel log. */ diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 8b563ab47484..ad0c042b5e66 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -3690,7 +3690,7 @@ static ssize_t qm_get_qos_value(struct hisi_qm *qm, const char *buf, unsigned long *val, unsigned int *fun_index) { - struct bus_type *bus_type = qm->pdev->dev.bus; + const struct bus_type *bus_type = qm->pdev->dev.bus; char tbuf_bdf[QM_DBG_READ_LEN] = {0}; char val_buf[QM_DBG_READ_LEN] = {0}; struct pci_dev *pdev; diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c index 09586a837b1e..3df7a256e919 100644 --- a/drivers/crypto/hisilicon/sgl.c +++ b/drivers/crypto/hisilicon/sgl.c @@ -70,11 +70,11 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, HISI_ACC_SGL_ALIGN_SIZE); /* - * the pool may allocate a block of memory of size PAGE_SIZE * 2^(MAX_ORDER - 1), + * the pool may allocate a block of memory of size PAGE_SIZE * 2^MAX_ORDER, * block size may exceed 2^31 on ia64, so the max of block size is 2^31 */ - block_size = 1 << (PAGE_SHIFT + MAX_ORDER <= 32 ? - PAGE_SHIFT + MAX_ORDER - 1 : 31); + block_size = 1 << (PAGE_SHIFT + MAX_ORDER < 32 ? + PAGE_SHIFT + MAX_ORDER : 31); sgl_num_per_block = block_size / sgl_size; block_num = count / sgl_num_per_block; remain_sgl = count % sgl_num_per_block; diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c index 88c41d6fbb7c..29c4422f243c 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c @@ -57,7 +57,7 @@ static int adf_chr_drv_create(void) return -EFAULT; } - adf_ctl_drv.drv_class = class_create(THIS_MODULE, DEVICE_NAME); + adf_ctl_drv.drv_class = class_create(DEVICE_NAME); if (IS_ERR(adf_ctl_drv.drv_class)) { pr_err("QAT: class_create failed for adf_ctl\n"); goto err_chrdev_unreg; diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index cde475e13216..27f0968449de 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -25,7 +25,12 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); #define CXL_DAX_REGION_TYPE(x) (&cxl_dax_region_type) int cxl_region_init(void); void cxl_region_exit(void); +int cxl_get_poison_by_endpoint(struct cxl_port *port); #else +static inline int cxl_get_poison_by_endpoint(struct cxl_port *port) +{ + return 0; +} static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled) { } @@ -64,4 +69,10 @@ int cxl_memdev_init(void); void cxl_memdev_exit(void); void cxl_mbox_init(void); +enum cxl_poison_trace_type { + CXL_POISON_TRACE_LIST, + CXL_POISON_TRACE_INJECT, + CXL_POISON_TRACE_CLEAR, +}; + #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 02cc2c38b44b..7889ff203a34 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ -#include #include #include #include @@ -93,8 +92,9 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb, cxl_probe_component_regs(&port->dev, crb, &map.component_map); if (!map.component_map.hdm_decoder.valid) { - dev_err(&port->dev, "HDM decoder registers invalid\n"); - return -ENXIO; + dev_dbg(&port->dev, "HDM decoder registers not implemented\n"); + /* unique error code to indicate no HDM decoder capability */ + return -ENODEV; } return cxl_map_component_regs(&port->dev, regs, &map, @@ -130,6 +130,14 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) */ for (i = 0; i < cxlhdm->decoder_count; i++) { ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); + dev_dbg(&info->port->dev, + "decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n", + info->port->id, i, + FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl), + readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)), + readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)), + readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)), + readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i))); if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) return false; } @@ -269,8 +277,11 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, lockdep_assert_held_write(&cxl_dpa_rwsem); - if (!len) - goto success; + if (!len) { + dev_warn(dev, "decoder%d.%d: empty reservation attempted\n", + port->id, cxled->cxld.id); + return -EINVAL; + } if (cxled->dpa_res) { dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n", @@ -323,7 +334,6 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, cxled->mode = CXL_DECODER_MIXED; } -success: port->hdm_end++; get_device(&cxled->cxld.dev); return 0; @@ -783,8 +793,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, int *target_map, void __iomem *hdm, int which, u64 *dpa_base, struct cxl_endpoint_dvsec_info *info) { + u64 size, base, skip, dpa_size, lo, hi; struct cxl_endpoint_decoder *cxled; - u64 size, base, skip, dpa_size; bool committed; u32 remainder; int i, rc; @@ -799,8 +809,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, which, info); 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)); + lo = readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which)); + hi = readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(which)); + base = (hi << 32) + lo; + lo = readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which)); + hi = readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(which)); + size = (hi << 32) + lo; committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED); cxld->commit = cxl_decoder_commit; cxld->reset = cxl_decoder_reset; @@ -833,6 +847,13 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, port->id, cxld->id); return -ENXIO; } + + if (size == 0) { + dev_warn(&port->dev, + "decoder%d.%d: Committed with zero size\n", + port->id, cxld->id); + return -ENXIO; + } port->commit_end = cxld->id; } else { /* unless / until type-2 drivers arrive, assume type-3 */ @@ -855,9 +876,14 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, if (rc) return rc; + dev_dbg(&port->dev, "decoder%d.%d: range: %#llx-%#llx iw: %d ig: %d\n", + port->id, cxld->id, cxld->hpa_range.start, cxld->hpa_range.end, + cxld->interleave_ways, cxld->interleave_granularity); + if (!info) { - target_list.value = - ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); + lo = readl(hdm + CXL_HDM_DECODER0_TL_LOW(which)); + hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which)); + target_list.value = (hi << 32) + lo; for (i = 0; i < cxld->interleave_ways; i++) target_map[i] = target_list.target_id[i]; @@ -874,7 +900,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, port->id, cxld->id, size, cxld->interleave_ways); return -ENXIO; } - skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which)); + lo = readl(hdm + CXL_HDM_DECODER0_SKIP_LOW(which)); + hi = readl(hdm + CXL_HDM_DECODER0_SKIP_HIGH(which)); + skip = (hi << 32) + lo; cxled = to_cxl_endpoint_decoder(&cxld->dev); rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip); if (rc) { diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index f2addb457172..bea9cf31a12d 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ -#include #include #include #include #include +#include +#include #include #include @@ -61,12 +62,7 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = { CXL_CMD(SET_ALERT_CONFIG, 0xc, 0, 0), CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0), CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0), - CXL_CMD(GET_POISON, 0x10, CXL_VARIABLE_PAYLOAD, 0), - CXL_CMD(INJECT_POISON, 0x8, 0, 0), - CXL_CMD(CLEAR_POISON, 0x48, 0, 0), CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0), - CXL_CMD(SCAN_MEDIA, 0x11, 0, 0), - CXL_CMD(GET_SCAN_MEDIA, 0, CXL_VARIABLE_PAYLOAD, 0), }; /* @@ -87,6 +83,9 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = { * * CXL_MBOX_OP_[GET_]SCAN_MEDIA: The kernel provides a native error list that * is kept up to date with patrol notifications and error management. + * + * CXL_MBOX_OP_[GET_,INJECT_,CLEAR_]POISON: These commands require kernel + * driver orchestration for safety. */ static u16 cxl_disabled_raw_commands[] = { CXL_MBOX_OP_ACTIVATE_FW, @@ -95,6 +94,9 @@ static u16 cxl_disabled_raw_commands[] = { CXL_MBOX_OP_SET_SHUTDOWN_STATE, CXL_MBOX_OP_SCAN_MEDIA, CXL_MBOX_OP_GET_SCAN_MEDIA, + CXL_MBOX_OP_GET_POISON, + CXL_MBOX_OP_INJECT_POISON, + CXL_MBOX_OP_CLEAR_POISON, }; /* @@ -119,6 +121,43 @@ static bool cxl_is_security_command(u16 opcode) return false; } +static bool cxl_is_poison_command(u16 opcode) +{ +#define CXL_MBOX_OP_POISON_CMDS 0x43 + + if ((opcode >> 8) == CXL_MBOX_OP_POISON_CMDS) + return true; + + return false; +} + +static void cxl_set_poison_cmd_enabled(struct cxl_poison_state *poison, + u16 opcode) +{ + switch (opcode) { + case CXL_MBOX_OP_GET_POISON: + set_bit(CXL_POISON_ENABLED_LIST, poison->enabled_cmds); + break; + case CXL_MBOX_OP_INJECT_POISON: + set_bit(CXL_POISON_ENABLED_INJECT, poison->enabled_cmds); + break; + case CXL_MBOX_OP_CLEAR_POISON: + set_bit(CXL_POISON_ENABLED_CLEAR, poison->enabled_cmds); + break; + case CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS: + set_bit(CXL_POISON_ENABLED_SCAN_CAPS, poison->enabled_cmds); + break; + case CXL_MBOX_OP_SCAN_MEDIA: + set_bit(CXL_POISON_ENABLED_SCAN_MEDIA, poison->enabled_cmds); + break; + case CXL_MBOX_OP_GET_SCAN_MEDIA: + set_bit(CXL_POISON_ENABLED_SCAN_RESULTS, poison->enabled_cmds); + break; + default: + break; + } +} + static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) { struct cxl_mem_command *c; @@ -634,13 +673,18 @@ static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel) u16 opcode = le16_to_cpu(cel_entry[i].opcode); struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); - if (!cmd) { + if (!cmd && !cxl_is_poison_command(opcode)) { dev_dbg(cxlds->dev, "Opcode 0x%04x unsupported by driver\n", opcode); continue; } - set_bit(cmd->info.id, cxlds->enabled_cmds); + if (cmd) + set_bit(cmd->info.id, cxlds->enabled_cmds); + + if (cxl_is_poison_command(opcode)) + cxl_set_poison_cmd_enabled(&cxlds->poison, opcode); + dev_dbg(cxlds->dev, "Opcode 0x%04x enabled\n", opcode); } } @@ -984,7 +1028,7 @@ static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds) * cxl_dev_state_identify() - Send the IDENTIFY command to the device. * @cxlds: The device data for the operation * - * Return: 0 if identify was executed successfully. + * Return: 0 if identify was executed successfully or media not ready. * * This will dispatch the identify command to the device and on success populate * structures to be exported to sysfs. @@ -994,8 +1038,12 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds) /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ struct cxl_mbox_identify id; struct cxl_mbox_cmd mbox_cmd; + u32 val; int rc; + if (!cxlds->media_ready) + return 0; + mbox_cmd = (struct cxl_mbox_cmd) { .opcode = CXL_MBOX_OP_IDENTIFY, .size_out = sizeof(id), @@ -1017,6 +1065,11 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds) cxlds->lsa_size = le32_to_cpu(id.lsa_size); memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision)); + if (test_bit(CXL_POISON_ENABLED_LIST, cxlds->poison.enabled_cmds)) { + val = get_unaligned_le24(id.poison_list_max_mer); + cxlds->poison.max_errors = min_t(u32, val, CXL_POISON_LIST_MAX); + } + return 0; } EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); @@ -1052,6 +1105,13 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) struct device *dev = cxlds->dev; int rc; + if (!cxlds->media_ready) { + cxlds->dpa_res = DEFINE_RES_MEM(0, 0); + cxlds->ram_res = DEFINE_RES_MEM(0, 0); + cxlds->pmem_res = DEFINE_RES_MEM(0, 0); + return 0; + } + cxlds->dpa_res = (struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes); @@ -1107,6 +1167,91 @@ int cxl_set_timestamp(struct cxl_dev_state *cxlds) } EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL); +int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, + struct cxl_region *cxlr) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_mbox_poison_out *po; + struct cxl_mbox_poison_in pi; + struct cxl_mbox_cmd mbox_cmd; + int nr_records = 0; + int rc; + + rc = mutex_lock_interruptible(&cxlds->poison.lock); + if (rc) + return rc; + + po = cxlds->poison.list_out; + pi.offset = cpu_to_le64(offset); + pi.length = cpu_to_le64(len / CXL_POISON_LEN_MULT); + + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_POISON, + .size_in = sizeof(pi), + .payload_in = &pi, + .size_out = cxlds->payload_size, + .payload_out = po, + .min_out = struct_size(po, record, 0), + }; + + do { + rc = cxl_internal_send_cmd(cxlds, &mbox_cmd); + if (rc) + break; + + for (int i = 0; i < le16_to_cpu(po->count); i++) + trace_cxl_poison(cxlmd, cxlr, &po->record[i], + po->flags, po->overflow_ts, + CXL_POISON_TRACE_LIST); + + /* Protect against an uncleared _FLAG_MORE */ + nr_records = nr_records + le16_to_cpu(po->count); + if (nr_records >= cxlds->poison.max_errors) { + dev_dbg(&cxlmd->dev, "Max Error Records reached: %d\n", + nr_records); + break; + } + } while (po->flags & CXL_POISON_FLAG_MORE); + + mutex_unlock(&cxlds->poison.lock); + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_mem_get_poison, CXL); + +static void free_poison_buf(void *buf) +{ + kvfree(buf); +} + +/* Get Poison List output buffer is protected by cxlds->poison.lock */ +static int cxl_poison_alloc_buf(struct cxl_dev_state *cxlds) +{ + cxlds->poison.list_out = kvmalloc(cxlds->payload_size, GFP_KERNEL); + if (!cxlds->poison.list_out) + return -ENOMEM; + + return devm_add_action_or_reset(cxlds->dev, free_poison_buf, + cxlds->poison.list_out); +} + +int cxl_poison_state_init(struct cxl_dev_state *cxlds) +{ + int rc; + + if (!test_bit(CXL_POISON_ENABLED_LIST, cxlds->poison.enabled_cmds)) + return 0; + + rc = cxl_poison_alloc_buf(cxlds); + if (rc) { + clear_bit(CXL_POISON_ENABLED_LIST, cxlds->poison.enabled_cmds); + return rc; + } + + mutex_init(&cxlds->poison.lock); + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, CXL); + struct cxl_dev_state *cxl_dev_state_create(struct device *dev) { struct cxl_dev_state *cxlds; diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 28a05f2fe32d..057a43267290 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -6,6 +6,7 @@ #include #include #include +#include "trace.h" #include "core.h" static DECLARE_RWSEM(cxl_memdev_rwsem); @@ -106,6 +107,232 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(numa_node); +static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + u64 offset, length; + int rc = 0; + + /* CXL 3.0 Spec 8.2.9.8.4.1 Separate pmem and ram poison requests */ + if (resource_size(&cxlds->pmem_res)) { + offset = cxlds->pmem_res.start; + length = resource_size(&cxlds->pmem_res); + rc = cxl_mem_get_poison(cxlmd, offset, length, NULL); + if (rc) + return rc; + } + if (resource_size(&cxlds->ram_res)) { + offset = cxlds->ram_res.start; + length = resource_size(&cxlds->ram_res); + rc = cxl_mem_get_poison(cxlmd, offset, length, NULL); + /* + * Invalid Physical Address is not an error for + * volatile addresses. Device support is optional. + */ + if (rc == -EFAULT) + rc = 0; + } + return rc; +} + +int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) +{ + struct cxl_port *port; + int rc; + + port = dev_get_drvdata(&cxlmd->dev); + if (!port || !is_cxl_endpoint(port)) + return -EINVAL; + + rc = down_read_interruptible(&cxl_dpa_rwsem); + if (rc) + return rc; + + if (port->commit_end == -1) { + /* No regions mapped to this memdev */ + rc = cxl_get_poison_by_memdev(cxlmd); + } else { + /* Regions mapped, collect poison by endpoint */ + rc = cxl_get_poison_by_endpoint(port); + } + up_read(&cxl_dpa_rwsem); + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, CXL); + +struct cxl_dpa_to_region_context { + struct cxl_region *cxlr; + u64 dpa; +}; + +static int __cxl_dpa_to_region(struct device *dev, void *arg) +{ + struct cxl_dpa_to_region_context *ctx = arg; + struct cxl_endpoint_decoder *cxled; + u64 dpa = ctx->dpa; + + if (!is_endpoint_decoder(dev)) + return 0; + + cxled = to_cxl_endpoint_decoder(dev); + if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) + return 0; + + if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) + return 0; + + dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, + dev_name(&cxled->cxld.region->dev)); + + ctx->cxlr = cxled->cxld.region; + + return 1; +} + +static struct cxl_region *cxl_dpa_to_region(struct cxl_memdev *cxlmd, u64 dpa) +{ + struct cxl_dpa_to_region_context ctx; + struct cxl_port *port; + + ctx = (struct cxl_dpa_to_region_context) { + .dpa = dpa, + }; + port = dev_get_drvdata(&cxlmd->dev); + if (port && is_cxl_endpoint(port) && port->commit_end != -1) + device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); + + return ctx.cxlr; +} + +static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + + if (!resource_size(&cxlds->dpa_res)) { + dev_dbg(cxlds->dev, "device has no dpa resource\n"); + return -EINVAL; + } + if (dpa < cxlds->dpa_res.start || dpa > cxlds->dpa_res.end) { + dev_dbg(cxlds->dev, "dpa:0x%llx not in resource:%pR\n", + dpa, &cxlds->dpa_res); + return -EINVAL; + } + if (!IS_ALIGNED(dpa, 64)) { + dev_dbg(cxlds->dev, "dpa:0x%llx is not 64-byte aligned\n", dpa); + return -EINVAL; + } + + return 0; +} + +int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_mbox_inject_poison inject; + struct cxl_poison_record record; + struct cxl_mbox_cmd mbox_cmd; + struct cxl_region *cxlr; + int rc; + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + + rc = down_read_interruptible(&cxl_dpa_rwsem); + if (rc) + return rc; + + rc = cxl_validate_poison_dpa(cxlmd, dpa); + if (rc) + goto out; + + inject.address = cpu_to_le64(dpa); + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_INJECT_POISON, + .size_in = sizeof(inject), + .payload_in = &inject, + }; + rc = cxl_internal_send_cmd(cxlds, &mbox_cmd); + if (rc) + goto out; + + cxlr = cxl_dpa_to_region(cxlmd, dpa); + if (cxlr) + dev_warn_once(cxlds->dev, + "poison inject dpa:%#llx region: %s\n", dpa, + dev_name(&cxlr->dev)); + + record = (struct cxl_poison_record) { + .address = cpu_to_le64(dpa), + .length = cpu_to_le32(1), + }; + trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_INJECT); +out: + up_read(&cxl_dpa_rwsem); + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, CXL); + +int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_mbox_clear_poison clear; + struct cxl_poison_record record; + struct cxl_mbox_cmd mbox_cmd; + struct cxl_region *cxlr; + int rc; + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + + rc = down_read_interruptible(&cxl_dpa_rwsem); + if (rc) + return rc; + + rc = cxl_validate_poison_dpa(cxlmd, dpa); + if (rc) + goto out; + + /* + * In CXL 3.0 Spec 8.2.9.8.4.3, the Clear Poison mailbox command + * is defined to accept 64 bytes of write-data, along with the + * address to clear. This driver uses zeroes as write-data. + */ + clear = (struct cxl_mbox_clear_poison) { + .address = cpu_to_le64(dpa) + }; + + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_CLEAR_POISON, + .size_in = sizeof(clear), + .payload_in = &clear, + }; + + rc = cxl_internal_send_cmd(cxlds, &mbox_cmd); + if (rc) + goto out; + + cxlr = cxl_dpa_to_region(cxlmd, dpa); + if (cxlr) + dev_warn_once(cxlds->dev, "poison clear dpa:%#llx region: %s\n", + dpa, dev_name(&cxlr->dev)); + + record = (struct cxl_poison_record) { + .address = cpu_to_le64(dpa), + .length = cpu_to_le32(1), + }; + trace_cxl_poison(cxlmd, cxlr, &record, 0, 0, CXL_POISON_TRACE_CLEAR); +out: + up_read(&cxl_dpa_rwsem); + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_clear_poison, CXL); + static struct attribute *cxl_memdev_attributes[] = { &dev_attr_serial.attr, &dev_attr_firmware_version.attr, diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 523d5b9fd7fc..67f4ab6daa34 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -101,23 +101,57 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port) } EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL); -/* - * Wait up to @media_ready_timeout for the device to report memory - * active. - */ -int cxl_await_media_ready(struct cxl_dev_state *cxlds) +static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id) +{ + struct pci_dev *pdev = to_pci_dev(cxlds->dev); + int d = cxlds->cxl_dvsec; + bool valid = false; + int rc, i; + u32 temp; + + if (id > CXL_DVSEC_RANGE_MAX) + return -EINVAL; + + /* Check MEM INFO VALID bit first, give up after 1s */ + i = 1; + do { + rc = pci_read_config_dword(pdev, + d + CXL_DVSEC_RANGE_SIZE_LOW(id), + &temp); + if (rc) + return rc; + + valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp); + if (valid) + break; + msleep(1000); + } while (i--); + + if (!valid) { + dev_err(&pdev->dev, + "Timeout awaiting memory range %d valid after 1s.\n", + id); + return -ETIMEDOUT; + } + + return 0; +} + +static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id) { struct pci_dev *pdev = to_pci_dev(cxlds->dev); int d = cxlds->cxl_dvsec; bool active = false; - u64 md_status; int rc, i; + u32 temp; + if (id > CXL_DVSEC_RANGE_MAX) + return -EINVAL; + + /* Check MEM ACTIVE bit, up to 60s timeout by default */ for (i = media_ready_timeout; i; i--) { - u32 temp; - rc = pci_read_config_dword( - pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp); + pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp); if (rc) return rc; @@ -134,6 +168,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds) return -ETIMEDOUT; } + return 0; +} + +/* + * Wait up to @media_ready_timeout for the device to report memory + * active. + */ +int cxl_await_media_ready(struct cxl_dev_state *cxlds) +{ + struct pci_dev *pdev = to_pci_dev(cxlds->dev); + int d = cxlds->cxl_dvsec; + int rc, i, hdm_count; + u64 md_status; + u16 cap; + + rc = pci_read_config_word(pdev, + d + CXL_DVSEC_CAP_OFFSET, &cap); + if (rc) + return rc; + + hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap); + for (i = 0; i < hdm_count; i++) { + rc = cxl_dvsec_mem_range_valid(cxlds, i); + if (rc) + return rc; + } + + for (i = 0; i < hdm_count; i++) { + rc = cxl_dvsec_mem_range_active(cxlds, i); + if (rc) + return rc; + } + md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET); if (!CXLMDEV_READY(md_status)) return -EIO; @@ -241,17 +308,36 @@ static void disable_hdm(void *_cxlhdm) hdm + CXL_HDM_DECODER_CTRL_OFFSET); } -static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm) +int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm) { - void __iomem *hdm = cxlhdm->regs.hdm_decoder; + void __iomem *hdm; u32 global_ctrl; + /* + * If the hdm capability was not mapped there is nothing to enable and + * the caller is responsible for what happens next. For example, + * emulate a passthrough decoder. + */ + if (IS_ERR(cxlhdm)) + return 0; + + hdm = cxlhdm->regs.hdm_decoder; global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET); + + /* + * If the HDM decoder capability was enabled on entry, skip + * registering disable_hdm() since this decode capability may be + * owned by platform firmware. + */ + if (global_ctrl & CXL_HDM_DECODER_ENABLE) + return 0; + writel(global_ctrl | CXL_HDM_DECODER_ENABLE, hdm + CXL_HDM_DECODER_CTRL_OFFSET); - return devm_add_action_or_reset(host, disable_hdm, cxlhdm); + return devm_add_action_or_reset(&port->dev, disable_hdm, cxlhdm); } +EXPORT_SYMBOL_NS_GPL(devm_cxl_enable_hdm, CXL); int cxl_dvsec_rr_decode(struct device *dev, int d, struct cxl_endpoint_dvsec_info *info) @@ -425,7 +511,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, if (info->mem_enabled) return 0; - rc = devm_cxl_enable_hdm(&port->dev, cxlhdm); + rc = devm_cxl_enable_hdm(port, cxlhdm); if (rc) return rc; @@ -441,27 +527,6 @@ EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL); #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) cpu_to_le32 \ (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE, \ CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) | \ @@ -469,51 +534,26 @@ static struct pci_doe_mb *find_cdat_doe(struct device *uport) 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 { - __le32 request_pl; - __le32 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); + __le32 request = CDAT_DOE_REQ(0); + __le32 response[2]; int rc; - rc = pci_doe_submit_task(cdat_doe, &t.task); + rc = pci_doe(cdat_doe, PCI_DVSEC_VENDOR_ID_CXL, + CXL_DOE_PROTOCOL_TABLE_ACCESS, + &request, sizeof(request), + &response, sizeof(response)); if (rc < 0) { - dev_err(dev, "DOE submit failed: %d", rc); + dev_err(dev, "DOE failed: %d", rc); return rc; } - wait_for_completion(&t.c); - if (t.task.rv < 2 * sizeof(__le32)) + if (rc < sizeof(response)) return -EIO; - *length = le32_to_cpu(t.response_pl[1]); + *length = le32_to_cpu(response[1]); dev_dbg(dev, "CDAT length %zu\n", *length); return 0; @@ -521,51 +561,55 @@ static int cxl_cdat_get_length(struct device *dev, static int cxl_cdat_read_table(struct device *dev, struct pci_doe_mb *cdat_doe, - struct cxl_cdat *cdat) + void *cdat_table, size_t *cdat_length) { - size_t length = cdat->length; - __le32 *data = cdat->table; + size_t length = *cdat_length + sizeof(__le32); + __le32 *data = cdat_table; int entry_handle = 0; + __le32 saved_dw = 0; do { - DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t); + __le32 request = CDAT_DOE_REQ(entry_handle); struct cdat_entry_header *entry; size_t entry_dw; int rc; - rc = pci_doe_submit_task(cdat_doe, &t.task); + rc = pci_doe(cdat_doe, PCI_DVSEC_VENDOR_ID_CXL, + CXL_DOE_PROTOCOL_TABLE_ACCESS, + &request, sizeof(request), + data, length); if (rc < 0) { - dev_err(dev, "DOE submit failed: %d", rc); + dev_err(dev, "DOE failed: %d", rc); return rc; } - wait_for_completion(&t.c); /* 1 DW Table Access Response Header + CDAT entry */ - entry = (struct cdat_entry_header *)(t.response_pl + 1); + entry = (struct cdat_entry_header *)(data + 1); if ((entry_handle == 0 && - t.task.rv != sizeof(__le32) + sizeof(struct cdat_header)) || + rc != sizeof(__le32) + sizeof(struct cdat_header)) || (entry_handle > 0 && - (t.task.rv < sizeof(__le32) + sizeof(*entry) || - t.task.rv != sizeof(__le32) + le16_to_cpu(entry->length)))) + (rc < sizeof(__le32) + sizeof(*entry) || + rc != sizeof(__le32) + le16_to_cpu(entry->length)))) return -EIO; /* Get the CXL table access header entry handle */ entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, - le32_to_cpu(t.response_pl[0])); - entry_dw = t.task.rv / sizeof(__le32); + le32_to_cpu(data[0])); + entry_dw = rc / sizeof(__le32); /* Skip Header */ entry_dw -= 1; - entry_dw = min(length / sizeof(__le32), entry_dw); - /* Prevent length < 1 DW from causing a buffer overflow */ - if (entry_dw) { - memcpy(data, entry, entry_dw * sizeof(__le32)); - length -= entry_dw * sizeof(__le32); - data += entry_dw; - } + /* + * Table Access Response Header overwrote the last DW of + * previous entry, so restore that DW + */ + *data = saved_dw; + length -= entry_dw * sizeof(__le32); + data += entry_dw; + saved_dw = *data; } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY); /* Length in CDAT header may exceed concatenation of CDAT entries */ - cdat->length -= length; + *cdat_length -= length - sizeof(__le32); return 0; } @@ -578,13 +622,19 @@ static int cxl_cdat_read_table(struct device *dev, */ void read_cdat_data(struct cxl_port *port) { - struct pci_doe_mb *cdat_doe; + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); + struct device *host = cxlmd->dev.parent; struct device *dev = &port->dev; - struct device *uport = port->uport; + struct pci_doe_mb *cdat_doe; size_t cdat_length; + void *cdat_table; int rc; - cdat_doe = find_cdat_doe(uport); + if (!dev_is_pci(host)) + return; + cdat_doe = pci_find_doe_mailbox(to_pci_dev(host), + PCI_DVSEC_VENDOR_ID_CXL, + CXL_DOE_PROTOCOL_TABLE_ACCESS); if (!cdat_doe) { dev_dbg(dev, "No CDAT mailbox\n"); return; @@ -597,19 +647,21 @@ void read_cdat_data(struct cxl_port *port) return; } - port->cdat.table = devm_kzalloc(dev, cdat_length, GFP_KERNEL); - if (!port->cdat.table) + cdat_table = devm_kzalloc(dev, cdat_length + sizeof(__le32), + GFP_KERNEL); + if (!cdat_table) return; - port->cdat.length = cdat_length; - rc = cxl_cdat_read_table(dev, cdat_doe, &port->cdat); + rc = cxl_cdat_read_table(dev, cdat_doe, cdat_table, &cdat_length); if (rc) { /* Don't leave table data allocated on error */ - devm_kfree(dev, port->cdat.table); - port->cdat.table = NULL; - port->cdat.length = 0; + devm_kfree(dev, cdat_table); dev_err(dev, "CDAT data read error\n"); + return; } + + port->cdat.table = cdat_table + sizeof(__le32); + port->cdat.length = cdat_length; } EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 4d1f9c5b5029..e7c284c890bc 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ -#include #include #include #include @@ -751,11 +750,10 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, parent_port = parent_dport ? parent_dport->port : NULL; if (IS_ERR(port)) { - dev_dbg(uport, "Failed to add %s%s%s%s: %ld\n", - dev_name(&port->dev), - parent_port ? " to " : "", + dev_dbg(uport, "Failed to add%s%s%s: %ld\n", + parent_port ? " port to " : "", parent_port ? dev_name(&parent_port->dev) : "", - parent_port ? "" : " (root port)", + parent_port ? "" : " root port", PTR_ERR(port)); } else { dev_dbg(uport, "%s added%s%s%s\n", @@ -1903,7 +1901,7 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL); /* for user tooling to ensure port disable work has completed */ -static ssize_t flush_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t flush_store(const struct bus_type *bus, const char *buf, size_t count) { if (sysfs_streq(buf, "1")) { flush_workqueue(cxl_bus_wq); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index b2fd67fcebfb..f822de44bee0 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2238,6 +2238,130 @@ struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev) } EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL); +struct cxl_poison_context { + struct cxl_port *port; + enum cxl_decoder_mode mode; + u64 offset; +}; + +static int cxl_get_poison_unmapped(struct cxl_memdev *cxlmd, + struct cxl_poison_context *ctx) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + u64 offset, length; + int rc = 0; + + /* + * Collect poison for the remaining unmapped resources + * after poison is collected by committed endpoints. + * + * Knowing that PMEM must always follow RAM, get poison + * for unmapped resources based on the last decoder's mode: + * ram: scan remains of ram range, then any pmem range + * pmem: scan remains of pmem range + */ + + if (ctx->mode == CXL_DECODER_RAM) { + offset = ctx->offset; + length = resource_size(&cxlds->ram_res) - offset; + rc = cxl_mem_get_poison(cxlmd, offset, length, NULL); + if (rc == -EFAULT) + rc = 0; + if (rc) + return rc; + } + if (ctx->mode == CXL_DECODER_PMEM) { + offset = ctx->offset; + length = resource_size(&cxlds->dpa_res) - offset; + if (!length) + return 0; + } else if (resource_size(&cxlds->pmem_res)) { + offset = cxlds->pmem_res.start; + length = resource_size(&cxlds->pmem_res); + } else { + return 0; + } + + return cxl_mem_get_poison(cxlmd, offset, length, NULL); +} + +static int poison_by_decoder(struct device *dev, void *arg) +{ + struct cxl_poison_context *ctx = arg; + struct cxl_endpoint_decoder *cxled; + struct cxl_memdev *cxlmd; + u64 offset, length; + int rc = 0; + + if (!is_endpoint_decoder(dev)) + return rc; + + cxled = to_cxl_endpoint_decoder(dev); + if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) + return rc; + + /* + * Regions are only created with single mode decoders: pmem or ram. + * Linux does not support mixed mode decoders. This means that + * reading poison per endpoint decoder adheres to the requirement + * that poison reads of pmem and ram must be separated. + * CXL 3.0 Spec 8.2.9.8.4.1 + */ + if (cxled->mode == CXL_DECODER_MIXED) { + dev_dbg(dev, "poison list read unsupported in mixed mode\n"); + return rc; + } + + cxlmd = cxled_to_memdev(cxled); + if (cxled->skip) { + offset = cxled->dpa_res->start - cxled->skip; + length = cxled->skip; + rc = cxl_mem_get_poison(cxlmd, offset, length, NULL); + if (rc == -EFAULT && cxled->mode == CXL_DECODER_RAM) + rc = 0; + if (rc) + return rc; + } + + offset = cxled->dpa_res->start; + length = cxled->dpa_res->end - offset + 1; + rc = cxl_mem_get_poison(cxlmd, offset, length, cxled->cxld.region); + if (rc == -EFAULT && cxled->mode == CXL_DECODER_RAM) + rc = 0; + if (rc) + return rc; + + /* Iterate until commit_end is reached */ + if (cxled->cxld.id == ctx->port->commit_end) { + ctx->offset = cxled->dpa_res->end + 1; + ctx->mode = cxled->mode; + return 1; + } + + return 0; +} + +int cxl_get_poison_by_endpoint(struct cxl_port *port) +{ + struct cxl_poison_context ctx; + int rc = 0; + + rc = down_read_interruptible(&cxl_region_rwsem); + if (rc) + return rc; + + ctx = (struct cxl_poison_context) { + .port = port + }; + + rc = device_for_each_child(&port->dev, &ctx, poison_by_decoder); + if (rc == 1) + rc = cxl_get_poison_unmapped(to_cxl_memdev(port->uport), &ctx); + + up_read(&cxl_region_rwsem); + return rc; +} + static struct lock_class_key cxl_pmem_region_key; static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) diff --git a/drivers/cxl/core/trace.c b/drivers/cxl/core/trace.c index 29ae7ce81dc5..d0403dc3c8ab 100644 --- a/drivers/cxl/core/trace.c +++ b/drivers/cxl/core/trace.c @@ -1,5 +1,99 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ +#include +#include "core.h" + #define CREATE_TRACE_POINTS #include "trace.h" + +static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos) +{ + struct cxl_region_params *p = &cxlr->params; + int gran = p->interleave_granularity; + int ways = p->interleave_ways; + u64 offset; + + /* Is the hpa within this region at all */ + if (hpa < p->res->start || hpa > p->res->end) { + dev_dbg(&cxlr->dev, + "Addr trans fail: hpa 0x%llx not in region\n", hpa); + return false; + } + + /* Is the hpa in an expected chunk for its pos(-ition) */ + offset = hpa - p->res->start; + offset = do_div(offset, gran * ways); + if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) + return true; + + dev_dbg(&cxlr->dev, + "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); + + return false; +} + +static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, + struct cxl_endpoint_decoder *cxled) +{ + u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; + struct cxl_region_params *p = &cxlr->params; + int pos = cxled->pos; + u16 eig = 0; + u8 eiw = 0; + + ways_to_eiw(p->interleave_ways, &eiw); + granularity_to_eig(p->interleave_granularity, &eig); + + /* + * The device position in the region interleave set was removed + * from the offset at HPA->DPA translation. To reconstruct the + * HPA, place the 'pos' in the offset. + * + * The placement of 'pos' in the HPA is determined by interleave + * ways and granularity and is defined in the CXL Spec 3.0 Section + * 8.2.4.19.13 Implementation Note: Device Decode Logic + */ + + /* Remove the dpa base */ + dpa_offset = dpa - cxl_dpa_resource_start(cxled); + + mask_upper = GENMASK_ULL(51, eig + 8); + + if (eiw < 8) { + hpa_offset = (dpa_offset & mask_upper) << eiw; + hpa_offset |= pos << (eig + 8); + } else { + bits_upper = (dpa_offset & mask_upper) >> (eig + 8); + bits_upper = bits_upper * 3; + hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); + } + + /* The lower bits remain unchanged */ + hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); + + /* Apply the hpa_offset to the region base address */ + hpa = hpa_offset + p->res->start; + + if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos)) + return ULLONG_MAX; + + return hpa; +} + +u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *cxlmd, + u64 dpa) +{ + struct cxl_region_params *p = &cxlr->params; + struct cxl_endpoint_decoder *cxled = NULL; + + for (int i = 0; i < p->nr_targets; i++) { + cxled = p->targets[i]; + if (cxlmd == cxled_to_memdev(cxled)) + break; + } + if (!cxled || cxlmd != cxled_to_memdev(cxled)) + return ULLONG_MAX; + + return cxl_dpa_to_hpa(dpa, cxlr, cxled); +} diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index 9b8d3d997834..a0b5819bc70b 100644 --- a/drivers/cxl/core/trace.h +++ b/drivers/cxl/core/trace.h @@ -7,10 +7,12 @@ #define _CXL_EVENTS_H #include +#include #include #include #include +#include "core.h" #define CXL_RAS_UC_CACHE_DATA_PARITY BIT(0) #define CXL_RAS_UC_CACHE_ADDR_PARITY BIT(1) @@ -600,6 +602,107 @@ TRACE_EVENT(cxl_memory_module, ) ); +#define show_poison_trace_type(type) \ + __print_symbolic(type, \ + { CXL_POISON_TRACE_LIST, "List" }, \ + { CXL_POISON_TRACE_INJECT, "Inject" }, \ + { CXL_POISON_TRACE_CLEAR, "Clear" }) + +#define __show_poison_source(source) \ + __print_symbolic(source, \ + { CXL_POISON_SOURCE_UNKNOWN, "Unknown" }, \ + { CXL_POISON_SOURCE_EXTERNAL, "External" }, \ + { CXL_POISON_SOURCE_INTERNAL, "Internal" }, \ + { CXL_POISON_SOURCE_INJECTED, "Injected" }, \ + { CXL_POISON_SOURCE_VENDOR, "Vendor" }) + +#define show_poison_source(source) \ + (((source > CXL_POISON_SOURCE_INJECTED) && \ + (source != CXL_POISON_SOURCE_VENDOR)) ? "Reserved" \ + : __show_poison_source(source)) + +#define show_poison_flags(flags) \ + __print_flags(flags, "|", \ + { CXL_POISON_FLAG_MORE, "More" }, \ + { CXL_POISON_FLAG_OVERFLOW, "Overflow" }, \ + { CXL_POISON_FLAG_SCANNING, "Scanning" }) + +#define __cxl_poison_addr(record) \ + (le64_to_cpu(record->address)) +#define cxl_poison_record_dpa(record) \ + (__cxl_poison_addr(record) & CXL_POISON_START_MASK) +#define cxl_poison_record_source(record) \ + (__cxl_poison_addr(record) & CXL_POISON_SOURCE_MASK) +#define cxl_poison_record_dpa_length(record) \ + (le32_to_cpu(record->length) * CXL_POISON_LEN_MULT) +#define cxl_poison_overflow(flags, time) \ + (flags & CXL_POISON_FLAG_OVERFLOW ? le64_to_cpu(time) : 0) + +u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *memdev, u64 dpa); + +TRACE_EVENT(cxl_poison, + + TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *region, + const struct cxl_poison_record *record, u8 flags, + __le64 overflow_ts, enum cxl_poison_trace_type trace_type), + + TP_ARGS(cxlmd, region, record, flags, overflow_ts, trace_type), + + TP_STRUCT__entry( + __string(memdev, dev_name(&cxlmd->dev)) + __string(host, dev_name(cxlmd->dev.parent)) + __field(u64, serial) + __field(u8, trace_type) + __string(region, region) + __field(u64, overflow_ts) + __field(u64, hpa) + __field(u64, dpa) + __field(u32, dpa_length) + __array(char, uuid, 16) + __field(u8, source) + __field(u8, flags) + ), + + TP_fast_assign( + __assign_str(memdev, dev_name(&cxlmd->dev)); + __assign_str(host, dev_name(cxlmd->dev.parent)); + __entry->serial = cxlmd->cxlds->serial; + __entry->overflow_ts = cxl_poison_overflow(flags, overflow_ts); + __entry->dpa = cxl_poison_record_dpa(record); + __entry->dpa_length = cxl_poison_record_dpa_length(record); + __entry->source = cxl_poison_record_source(record); + __entry->trace_type = trace_type; + __entry->flags = flags; + if (region) { + __assign_str(region, dev_name(®ion->dev)); + memcpy(__entry->uuid, ®ion->params.uuid, 16); + __entry->hpa = cxl_trace_hpa(region, cxlmd, + __entry->dpa); + } else { + __assign_str(region, ""); + memset(__entry->uuid, 0, 16); + __entry->hpa = ULLONG_MAX; + } + ), + + TP_printk("memdev=%s host=%s serial=%lld trace_type=%s region=%s " \ + "region_uuid=%pU hpa=0x%llx dpa=0x%llx dpa_length=0x%x " \ + "source=%s flags=%s overflow_time=%llu", + __get_str(memdev), + __get_str(host), + __entry->serial, + show_poison_trace_type(__entry->trace_type), + __get_str(region), + __entry->uuid, + __entry->hpa, + __entry->dpa, + __entry->dpa_length, + show_poison_source(__entry->source), + show_poison_flags(__entry->flags), + __entry->overflow_ts + ) +); + #endif /* _CXL_EVENTS_H */ #define TRACE_INCLUDE_FILE trace diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 044a92d9813e..f93a28538962 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -710,6 +710,7 @@ struct cxl_endpoint_dvsec_info { struct cxl_hdm; struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, struct cxl_endpoint_dvsec_info *info); +int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm); int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, struct cxl_endpoint_dvsec_info *info); int devm_cxl_add_passthrough_decoder(struct cxl_port *port); diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 090acebba4fa..a2845a7a69d8 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -127,7 +127,7 @@ struct cxl_mbox_cmd { }; /* - * Per CXL 2.0 Section 8.2.8.4.5.1 + * Per CXL 3.0 Section 8.2.8.4.5.1 */ #define CMD_CMD_RC_TABLE \ C(SUCCESS, 0, NULL), \ @@ -145,14 +145,22 @@ struct cxl_mbox_cmd { C(FWROLLBACK, -ENXIO, "rolled back to the previous active FW"), \ C(FWRESET, -ENXIO, "FW failed to activate, needs cold reset"), \ C(HANDLE, -ENXIO, "one or more Event Record Handles were invalid"), \ - C(PADDR, -ENXIO, "physical address specified is invalid"), \ + C(PADDR, -EFAULT, "physical address specified is invalid"), \ C(POISONLMT, -ENXIO, "poison injection limit has been reached"), \ C(MEDIAFAILURE, -ENXIO, "permanent issue with the media"), \ C(ABORT, -ENXIO, "background cmd was aborted by device"), \ C(SECURITY, -ENXIO, "not valid in the current security state"), \ C(PASSPHRASE, -ENXIO, "phrase doesn't match current set passphrase"), \ C(MBUNSUPPORTED, -ENXIO, "unsupported on the mailbox it was issued on"),\ - C(PAYLOADLEN, -ENXIO, "invalid payload length") + C(PAYLOADLEN, -ENXIO, "invalid payload length"), \ + C(LOG, -ENXIO, "invalid or unsupported log page"), \ + C(INTERRUPTED, -ENXIO, "asynchronous event occured"), \ + C(FEATUREVERSION, -ENXIO, "unsupported feature version"), \ + C(FEATURESELVALUE, -ENXIO, "unsupported feature selection value"), \ + C(FEATURETRANSFERIP, -ENXIO, "feature transfer in progress"), \ + C(FEATURETRANSFEROOO, -ENXIO, "feature transfer out of order"), \ + C(RESOURCEEXHAUSTED, -ENXIO, "resources are exhausted"), \ + C(EXTLIST, -ENXIO, "invalid Extent List"), \ #undef C #define C(a, b, c) CXL_MBOX_CMD_RC_##a @@ -215,6 +223,37 @@ struct cxl_event_state { struct mutex log_lock; }; +/* Device enabled poison commands */ +enum poison_cmd_enabled_bits { + CXL_POISON_ENABLED_LIST, + CXL_POISON_ENABLED_INJECT, + CXL_POISON_ENABLED_CLEAR, + CXL_POISON_ENABLED_SCAN_CAPS, + CXL_POISON_ENABLED_SCAN_MEDIA, + CXL_POISON_ENABLED_SCAN_RESULTS, + CXL_POISON_ENABLED_MAX +}; + +/** + * struct cxl_poison_state - Driver poison state info + * + * @max_errors: Maximum media error records held in device cache + * @enabled_cmds: All poison commands enabled in the CEL + * @list_out: The poison list payload returned by device + * @lock: Protect reads of the poison list + * + * Reads of the poison list are synchronized to ensure that a reader + * does not get an incomplete list because their request overlapped + * (was interrupted or preceded by) another read request of the same + * DPA range. CXL Spec 3.0 Section 8.2.9.8.4.1 + */ +struct cxl_poison_state { + u32 max_errors; + DECLARE_BITMAP(enabled_cmds, CXL_POISON_ENABLED_MAX); + struct cxl_mbox_poison_out *list_out; + struct mutex lock; /* Protect reads of poison list */ +}; + /** * struct cxl_dev_state - The driver device state * @@ -227,6 +266,7 @@ struct cxl_event_state { * @regs: Parsed register blocks * @cxl_dvsec: Offset to the PCIe device DVSEC * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH) + * @media_ready: Indicate whether the device media is usable * @payload_size: Size of space for payload * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register) * @lsa_size: Size of Label Storage Area @@ -249,8 +289,8 @@ struct cxl_event_state { * @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 * @event: event log driver state + * @poison: poison driver state info * @mbox_send: @dev specific transport for transmitting mailbox commands * * See section 8.2.9.5.2 Capacity Configuration and Label Storage for @@ -264,6 +304,7 @@ struct cxl_dev_state { int cxl_dvsec; bool rcd; + bool media_ready; size_t payload_size; size_t lsa_size; struct mutex mbox_mutex; /* Protects device mailbox and firmware */ @@ -287,9 +328,8 @@ struct cxl_dev_state { resource_size_t component_reg_phys; u64 serial; - struct xarray doe_mbs; - struct cxl_event_state event; + struct cxl_poison_state poison; int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd); }; @@ -538,6 +578,61 @@ struct cxl_mbox_set_timestamp_in { } __packed; +/* Get Poison List CXL 3.0 Spec 8.2.9.8.4.1 */ +struct cxl_mbox_poison_in { + __le64 offset; + __le64 length; +} __packed; + +struct cxl_mbox_poison_out { + u8 flags; + u8 rsvd1; + __le64 overflow_ts; + __le16 count; + u8 rsvd2[20]; + struct cxl_poison_record { + __le64 address; + __le32 length; + __le32 rsvd; + } __packed record[]; +} __packed; + +/* + * Get Poison List address field encodes the starting + * address of poison, and the source of the poison. + */ +#define CXL_POISON_START_MASK GENMASK_ULL(63, 6) +#define CXL_POISON_SOURCE_MASK GENMASK(2, 0) + +/* Get Poison List record length is in units of 64 bytes */ +#define CXL_POISON_LEN_MULT 64 + +/* Kernel defined maximum for a list of poison errors */ +#define CXL_POISON_LIST_MAX 1024 + +/* Get Poison List: Payload out flags */ +#define CXL_POISON_FLAG_MORE BIT(0) +#define CXL_POISON_FLAG_OVERFLOW BIT(1) +#define CXL_POISON_FLAG_SCANNING BIT(2) + +/* Get Poison List: Poison Source */ +#define CXL_POISON_SOURCE_UNKNOWN 0 +#define CXL_POISON_SOURCE_EXTERNAL 1 +#define CXL_POISON_SOURCE_INTERNAL 2 +#define CXL_POISON_SOURCE_INJECTED 3 +#define CXL_POISON_SOURCE_VENDOR 7 + +/* Inject & Clear Poison CXL 3.0 Spec 8.2.9.8.4.2/3 */ +struct cxl_mbox_inject_poison { + __le64 address; +}; + +/* Clear Poison CXL 3.0 Spec 8.2.9.8.4.3 */ +struct cxl_mbox_clear_poison { + __le64 address; + u8 write_data[CXL_POISON_LEN_MULT]; +} __packed; + /** * struct cxl_mem_command - Driver representation of a memory device command * @info: Command information as it exists for the UAPI @@ -608,6 +703,12 @@ void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds); void cxl_mem_get_event_records(struct cxl_dev_state *cxlds, u32 status); int cxl_set_timestamp(struct cxl_dev_state *cxlds); +int cxl_poison_state_init(struct cxl_dev_state *cxlds); +int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, + struct cxl_region *cxlr); +int cxl_trigger_poison_list(struct cxl_memdev *cxlmd); +int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa); +int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa); #ifdef CONFIG_CXL_SUSPEND void cxl_mem_active_inc(void); diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index 0465ef963cd6..7c02e55b8042 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -31,6 +31,8 @@ #define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10)) #define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28) +#define CXL_DVSEC_RANGE_MAX 2 + /* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */ #define CXL_DVSEC_FUNCTION_MAP 2 diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 39c4b54f0715..519edd0eb196 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -94,6 +94,26 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd, return 0; } +static int cxl_debugfs_poison_inject(void *data, u64 dpa) +{ + struct cxl_memdev *cxlmd = data; + + return cxl_inject_poison(cxlmd, dpa); +} + +DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_inject_fops, NULL, + cxl_debugfs_poison_inject, "%llx\n"); + +static int cxl_debugfs_poison_clear(void *data, u64 dpa) +{ + struct cxl_memdev *cxlmd = data; + + return cxl_clear_poison(cxlmd, dpa); +} + +DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_clear_fops, NULL, + cxl_debugfs_poison_clear, "%llx\n"); + static int cxl_mem_probe(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); @@ -104,6 +124,9 @@ static int cxl_mem_probe(struct device *dev) struct dentry *dentry; int rc; + if (!cxlds->media_ready) + return -EBUSY; + /* * Someone is trying to reattach this device after it lost its port * connection (an endpoint port previously registered by this memdev was @@ -117,6 +140,14 @@ static int cxl_mem_probe(struct device *dev) dentry = cxl_debugfs_create_dir(dev_name(dev)); debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show); + + if (test_bit(CXL_POISON_ENABLED_INJECT, cxlds->poison.enabled_cmds)) + debugfs_create_file("inject_poison", 0200, dentry, cxlmd, + &cxl_poison_inject_fops); + if (test_bit(CXL_POISON_ENABLED_CLEAR, cxlds->poison.enabled_cmds)) + debugfs_create_file("clear_poison", 0200, dentry, cxlmd, + &cxl_poison_clear_fops); + rc = devm_add_action_or_reset(dev, remove_debugfs, dentry); if (rc) return rc; @@ -176,10 +207,53 @@ unlock: return devm_add_action_or_reset(dev, enable_suspend, NULL); } +static ssize_t trigger_poison_list_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + bool trigger; + int rc; + + if (kstrtobool(buf, &trigger) || !trigger) + return -EINVAL; + + rc = cxl_trigger_poison_list(to_cxl_memdev(dev)); + + return rc ? rc : len; +} +static DEVICE_ATTR_WO(trigger_poison_list); + +static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n) +{ + if (a == &dev_attr_trigger_poison_list.attr) { + struct device *dev = kobj_to_dev(kobj); + + if (!test_bit(CXL_POISON_ENABLED_LIST, + to_cxl_memdev(dev)->cxlds->poison.enabled_cmds)) + return 0; + } + return a->mode; +} + +static struct attribute *cxl_mem_attrs[] = { + &dev_attr_trigger_poison_list.attr, + NULL +}; + +static struct attribute_group cxl_mem_group = { + .attrs = cxl_mem_attrs, + .is_visible = cxl_mem_visible, +}; + +__ATTRIBUTE_GROUPS(cxl_mem); + static struct cxl_driver cxl_mem_driver = { .name = "cxl_mem", .probe = cxl_mem_probe, .id = CXL_DEVICE_MEMORY_EXPANDER, + .drv = { + .dev_groups = cxl_mem_groups, + }, }; module_cxl_driver(cxl_mem_driver); diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 60b23624d167..0872f2233ed0 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include "cxlmem.h" @@ -357,52 +356,6 @@ static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, 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 (!pci_request_config_region_exclusive(pdev, off, - PCI_DOE_CAP_SIZEOF, - dev_name(dev))) - pci_err(pdev, "Failed to exclude DOE registers\n"); - - 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); - } -} - /* * Assume that any RCIEP that emits the CXL memory expander class code * is an RCD @@ -750,13 +703,17 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) cxlds->component_reg_phys = map.resource; - devm_cxl_pci_create_doe(cxlds); - rc = cxl_map_component_regs(&pdev->dev, &cxlds->regs.component, &map, BIT(CXL_CM_CAP_CAP_ID_RAS)); if (rc) dev_dbg(&pdev->dev, "Failed to map RAS capability.\n"); + rc = cxl_await_media_ready(cxlds); + if (rc == 0) + cxlds->media_ready = true; + else + dev_warn(&pdev->dev, "Media not active (%d)\n", rc); + rc = cxl_pci_setup_mailbox(cxlds); if (rc) return rc; @@ -769,6 +726,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; + rc = cxl_poison_state_init(cxlds); + if (rc) + return rc; + rc = cxl_dev_state_identify(cxlds); if (rc) return rc; diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 22a7ab2bae7c..c23b6164e1c0 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -60,20 +60,32 @@ static int discover_region(struct device *dev, void *root) static int cxl_switch_port_probe(struct cxl_port *port) { struct cxl_hdm *cxlhdm; - int rc; + int rc, nr_dports; - rc = devm_cxl_port_enumerate_dports(port); - if (rc < 0) - return rc; - - if (rc == 1) - return devm_cxl_add_passthrough_decoder(port); + nr_dports = devm_cxl_port_enumerate_dports(port); + if (nr_dports < 0) + return nr_dports; cxlhdm = devm_cxl_setup_hdm(port, NULL); - if (IS_ERR(cxlhdm)) - return PTR_ERR(cxlhdm); + rc = devm_cxl_enable_hdm(port, cxlhdm); + if (rc) + return rc; - return devm_cxl_enumerate_decoders(cxlhdm, NULL); + if (!IS_ERR(cxlhdm)) + return devm_cxl_enumerate_decoders(cxlhdm, NULL); + + if (PTR_ERR(cxlhdm) != -ENODEV) { + dev_err(&port->dev, "Failed to map HDM decoder capability\n"); + return PTR_ERR(cxlhdm); + } + + if (nr_dports == 1) { + dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); + return devm_cxl_add_passthrough_decoder(port); + } + + dev_err(&port->dev, "HDM decoder capability not found\n"); + return -ENXIO; } static int cxl_endpoint_port_probe(struct cxl_port *port) @@ -105,12 +117,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) if (rc) return rc; - rc = cxl_await_media_ready(cxlds); - if (rc) { - dev_err(&port->dev, "Media not active (%d)\n", rc); - return rc; - } - rc = devm_cxl_enumerate_decoders(cxlhdm, &info); if (rc) return rc; diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index c40c2ebfdae9..ed3dac546dd6 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -294,9 +294,7 @@ EXPORT_SYMBOL_GPL(dca3_get_tag); */ u8 dca_get_tag(int cpu) { - struct device *dev = NULL; - - return dca_common_get_tag(dev, cpu); + return dca_common_get_tag(NULL, cpu); } EXPORT_SYMBOL_GPL(dca_get_tag); diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c index 21ebd0af268b..fcc83ede0909 100644 --- a/drivers/dca/dca-sysfs.c +++ b/drivers/dca/dca-sysfs.c @@ -74,7 +74,7 @@ int __init dca_sysfs_init(void) idr_init(&dca_idr); spin_lock_init(&dca_idr_lock); - dca_class = class_create(THIS_MODULE, "dca"); + dca_class = class_create("dca"); if (IS_ERR(dca_class)) { idr_destroy(&dca_idr); return PTR_ERR(dca_class); diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c index f041edccd107..3ebac2496679 100644 --- a/drivers/devfreq/devfreq-event.c +++ b/drivers/devfreq/devfreq-event.c @@ -469,7 +469,7 @@ ATTRIBUTE_GROUPS(devfreq_event); static int __init devfreq_event_init(void) { - devfreq_event_class = class_create(THIS_MODULE, "devfreq-event"); + devfreq_event_class = class_create("devfreq-event"); if (IS_ERR(devfreq_event_class)) { pr_err("%s: couldn't create class\n", __FILE__); return PTR_ERR(devfreq_event_class); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 817c71da391a..e36cbb920ec8 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1988,7 +1988,7 @@ DEFINE_SHOW_ATTRIBUTE(devfreq_summary); static int __init devfreq_init(void) { - devfreq_class = class_create(THIS_MODULE, "devfreq"); + devfreq_class = class_create("devfreq"); if (IS_ERR(devfreq_class)) { pr_err("%s: couldn't create class\n", __FILE__); return PTR_ERR(devfreq_class); diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c index c9e41e8a9e27..84ae708fafe7 100644 --- a/drivers/dma-buf/dma-heap.c +++ b/drivers/dma-buf/dma-heap.c @@ -314,7 +314,7 @@ static int dma_heap_init(void) if (ret) return ret; - dma_heap_class = class_create(THIS_MODULE, DEVNAME); + dma_heap_class = class_create(DEVNAME); if (IS_ERR(dma_heap_class)) { unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); return PTR_ERR(dma_heap_class); diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 1131fb943992..a7f048048864 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -407,4 +407,3 @@ static int add_default_cma_heap(void) } module_init(add_default_cma_heap); MODULE_DESCRIPTION("DMA-BUF CMA Heap"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index e8bd10e60998..ee7059399e9c 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -41,12 +41,11 @@ struct dma_heap_attachment { bool mapped; }; -#define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO | __GFP_COMP) -#define MID_ORDER_GFP (LOW_ORDER_GFP | __GFP_NOWARN) +#define LOW_ORDER_GFP (GFP_HIGHUSER | __GFP_ZERO) #define HIGH_ORDER_GFP (((GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN \ | __GFP_NORETRY) & ~__GFP_RECLAIM) \ | __GFP_COMP) -static gfp_t order_flags[] = {HIGH_ORDER_GFP, MID_ORDER_GFP, LOW_ORDER_GFP}; +static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP}; /* * The selection of the orders used for allocation (1MB, 64K, 4K) is designed * to match with the sizes often found in IOMMUs. Using order 4 pages instead @@ -440,4 +439,3 @@ static int system_heap_create(void) return 0; } module_init(system_heap_create); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 740d6e426ee9..01f2e86f3f7c 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -430,4 +430,3 @@ module_init(udmabuf_dev_init) module_exit(udmabuf_dev_exit) MODULE_AUTHOR("Gerd Hoffmann "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index fb7073fc034f..f5f422f9b850 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -623,6 +623,7 @@ config TEGRA186_GPC_DMA depends on (ARCH_TEGRA || COMPILE_TEST) && ARCH_DMA_ADDR_T_64BIT depends on IOMMU_API select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS help Support for the NVIDIA Tegra General Purpose Central DMA controller. The DMA controller has multiple DMA channels which can be configured diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 8858470246e1..ee3a219e3a89 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -132,7 +132,7 @@ #define ATC_DST_PIP BIT(12) /* Destination Picture-in-Picture enabled */ #define ATC_SRC_DSCR_DIS BIT(16) /* Src Descriptor fetch disable */ #define ATC_DST_DSCR_DIS BIT(20) /* Dst Descriptor fetch disable */ -#define ATC_FC GENMASK(22, 21) /* Choose Flow Controller */ +#define ATC_FC GENMASK(23, 21) /* Choose Flow Controller */ #define ATC_FC_MEM2MEM 0x0 /* Mem-to-Mem (DMA) */ #define ATC_FC_MEM2PER 0x1 /* Mem-to-Periph (DMA) */ #define ATC_FC_PER2MEM 0x2 /* Periph-to-Mem (DMA) */ @@ -153,8 +153,6 @@ #define ATC_AUTO BIT(31) /* Auto multiple buffer tx enable */ /* Bitfields in CFG */ -#define ATC_PER_MSB(h) ((0x30U & (h)) >> 4) /* Extract most significant bits of a handshaking identifier */ - #define ATC_SRC_PER GENMASK(3, 0) /* Channel src rq associated with periph handshaking ifc h */ #define ATC_DST_PER GENMASK(7, 4) /* Channel dst rq associated with periph handshaking ifc h */ #define ATC_SRC_REP BIT(8) /* Source Replay Mod */ @@ -181,10 +179,15 @@ #define ATC_DPIP_HOLE GENMASK(15, 0) #define ATC_DPIP_BOUNDARY GENMASK(25, 16) -#define ATC_SRC_PER_ID(id) (FIELD_PREP(ATC_SRC_PER_MSB, (id)) | \ - FIELD_PREP(ATC_SRC_PER, (id))) -#define ATC_DST_PER_ID(id) (FIELD_PREP(ATC_DST_PER_MSB, (id)) | \ - FIELD_PREP(ATC_DST_PER, (id))) +#define ATC_PER_MSB GENMASK(5, 4) /* Extract MSBs of a handshaking identifier */ +#define ATC_SRC_PER_ID(id) \ + ({ typeof(id) _id = (id); \ + FIELD_PREP(ATC_SRC_PER_MSB, FIELD_GET(ATC_PER_MSB, _id)) | \ + FIELD_PREP(ATC_SRC_PER, _id); }) +#define ATC_DST_PER_ID(id) \ + ({ typeof(id) _id = (id); \ + FIELD_PREP(ATC_DST_PER_MSB, FIELD_GET(ATC_PER_MSB, _id)) | \ + FIELD_PREP(ATC_DST_PER, _id); }) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 1f0fab180f8f..c3b37168b21f 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -187,6 +187,7 @@ enum atc_status { AT_XDMAC_CHAN_IS_CYCLIC = 0, AT_XDMAC_CHAN_IS_PAUSED, + AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, }; struct at_xdmac_layout { @@ -245,6 +246,7 @@ struct at_xdmac { int irq; struct clk *clk; u32 save_gim; + u32 save_gs; struct dma_pool *at_xdmac_desc_pool; const struct at_xdmac_layout *layout; struct at_xdmac_chan chan[]; @@ -347,6 +349,11 @@ static inline int at_xdmac_chan_is_paused(struct at_xdmac_chan *atchan) return test_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status); } +static inline int at_xdmac_chan_is_paused_internal(struct at_xdmac_chan *atchan) +{ + return test_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status); +} + static inline bool at_xdmac_chan_is_peripheral_xfer(u32 cfg) { return cfg & AT_XDMAC_CC_TYPE_PER_TRAN; @@ -412,7 +419,7 @@ static bool at_xdmac_chan_is_enabled(struct at_xdmac_chan *atchan) return ret; } -static void at_xdmac_off(struct at_xdmac *atxdmac) +static void at_xdmac_off(struct at_xdmac *atxdmac, bool suspend_descriptors) { struct dma_chan *chan, *_chan; struct at_xdmac_chan *atchan; @@ -431,7 +438,7 @@ static void at_xdmac_off(struct at_xdmac *atxdmac) at_xdmac_write(atxdmac, AT_XDMAC_GID, -1L); /* Decrement runtime PM ref counter for each active descriptor. */ - if (!list_empty(&atxdmac->dma.channels)) { + if (!list_empty(&atxdmac->dma.channels) && suspend_descriptors) { list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { atchan = to_at_xdmac_chan(chan); @@ -1095,6 +1102,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, NULL, src_addr, dst_addr, xt, xt->sgl); + if (!first) + return NULL; /* Length of the block is (BLEN+1) microblocks. */ for (i = 0; i < xt->numf - 1; i++) @@ -1125,8 +1134,9 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, src_addr, dst_addr, xt, chunk); if (!desc) { - list_splice_tail_init(&first->descs_list, - &atchan->free_descs_list); + if (first) + list_splice_tail_init(&first->descs_list, + &atchan->free_descs_list); return NULL; } @@ -1898,6 +1908,26 @@ static int at_xdmac_device_config(struct dma_chan *chan, return ret; } +static void at_xdmac_device_pause_set(struct at_xdmac *atxdmac, + struct at_xdmac_chan *atchan) +{ + at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask); + while (at_xdmac_chan_read(atchan, AT_XDMAC_CC) & + (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP)) + cpu_relax(); +} + +static void at_xdmac_device_pause_internal(struct at_xdmac_chan *atchan) +{ + struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); + unsigned long flags; + + spin_lock_irqsave(&atchan->lock, flags); + set_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status); + at_xdmac_device_pause_set(atxdmac, atchan); + spin_unlock_irqrestore(&atchan->lock, flags); +} + static int at_xdmac_device_pause(struct dma_chan *chan) { struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); @@ -1915,11 +1945,8 @@ static int at_xdmac_device_pause(struct dma_chan *chan) return ret; spin_lock_irqsave(&atchan->lock, flags); - at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask); - while (at_xdmac_chan_read(atchan, AT_XDMAC_CC) - & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP)) - cpu_relax(); + at_xdmac_device_pause_set(atxdmac, atchan); /* Decrement runtime PM ref counter for each active descriptor. */ at_xdmac_runtime_suspend_descriptors(atchan); @@ -1931,6 +1958,17 @@ static int at_xdmac_device_pause(struct dma_chan *chan) return 0; } +static void at_xdmac_device_resume_internal(struct at_xdmac_chan *atchan) +{ + struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); + unsigned long flags; + + spin_lock_irqsave(&atchan->lock, flags); + at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask); + clear_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status); + spin_unlock_irqrestore(&atchan->lock, flags); +} + static int at_xdmac_device_resume(struct dma_chan *chan) { struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); @@ -2118,19 +2156,26 @@ static int __maybe_unused atmel_xdmac_suspend(struct device *dev) atchan->save_cc = at_xdmac_chan_read(atchan, AT_XDMAC_CC); if (at_xdmac_chan_is_cyclic(atchan)) { - if (!at_xdmac_chan_is_paused(atchan)) - at_xdmac_device_pause(chan); + if (!at_xdmac_chan_is_paused(atchan)) { + dev_warn(chan2dev(chan), "%s: channel %d not paused\n", + __func__, chan->chan_id); + at_xdmac_device_pause_internal(atchan); + at_xdmac_runtime_suspend_descriptors(atchan); + } atchan->save_cim = at_xdmac_chan_read(atchan, AT_XDMAC_CIM); atchan->save_cnda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA); atchan->save_cndc = at_xdmac_chan_read(atchan, AT_XDMAC_CNDC); } - - at_xdmac_runtime_suspend_descriptors(atchan); } atxdmac->save_gim = at_xdmac_read(atxdmac, AT_XDMAC_GIM); + atxdmac->save_gs = at_xdmac_read(atxdmac, AT_XDMAC_GS); - at_xdmac_off(atxdmac); - return pm_runtime_force_suspend(atxdmac->dev); + at_xdmac_off(atxdmac, false); + pm_runtime_mark_last_busy(atxdmac->dev); + pm_runtime_put_noidle(atxdmac->dev); + clk_disable_unprepare(atxdmac->clk); + + return 0; } static int __maybe_unused atmel_xdmac_resume(struct device *dev) @@ -2139,13 +2184,14 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev) struct at_xdmac_chan *atchan; struct dma_chan *chan, *_chan; struct platform_device *pdev = container_of(dev, struct platform_device, dev); - int i; - int ret; + int i, ret; - ret = pm_runtime_force_resume(atxdmac->dev); - if (ret < 0) + ret = clk_prepare_enable(atxdmac->clk); + if (ret) return ret; + pm_runtime_get_noresume(atxdmac->dev); + at_xdmac_axi_config(pdev); /* Clear pending interrupts. */ @@ -2159,19 +2205,33 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev) list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { atchan = to_at_xdmac_chan(chan); - ret = at_xdmac_runtime_resume_descriptors(atchan); - if (ret < 0) - return ret; - at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc); if (at_xdmac_chan_is_cyclic(atchan)) { - if (at_xdmac_chan_is_paused(atchan)) - at_xdmac_device_resume(chan); + /* + * Resume only channels not explicitly paused by + * consumers. + */ + if (at_xdmac_chan_is_paused_internal(atchan)) { + ret = at_xdmac_runtime_resume_descriptors(atchan); + if (ret < 0) + return ret; + at_xdmac_device_resume_internal(atchan); + } + + /* + * We may resume from a deep sleep state where power + * to DMA controller is cut-off. Thus, restore the + * suspend state of channels set though dmaengine API. + */ + else if (at_xdmac_chan_is_paused(atchan)) + at_xdmac_device_pause_set(atxdmac, atchan); + at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda); at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc); at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim); wmb(); - at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask); + if (atxdmac->save_gs & atchan->mask) + at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask); } } @@ -2312,7 +2372,7 @@ static int at_xdmac_probe(struct platform_device *pdev) INIT_LIST_HEAD(&atxdmac->dma.channels); /* Disable all chans and interrupts. */ - at_xdmac_off(atxdmac); + at_xdmac_off(atxdmac, true); for (i = 0; i < nr_channels; i++) { struct at_xdmac_chan *atchan = &atxdmac->chan[i]; @@ -2376,7 +2436,7 @@ static int at_xdmac_remove(struct platform_device *pdev) struct at_xdmac *atxdmac = (struct at_xdmac *)platform_get_drvdata(pdev); int i; - at_xdmac_off(atxdmac); + at_xdmac_off(atxdmac, true); of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&atxdmac->dma); pm_runtime_disable(atxdmac->dev); diff --git a/drivers/dma/bestcomm/sram.c b/drivers/dma/bestcomm/sram.c index c465758e7193..0553956f7456 100644 --- a/drivers/dma/bestcomm/sram.c +++ b/drivers/dma/bestcomm/sram.c @@ -38,7 +38,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner) { int rv; const u32 *regaddr_p; - u64 regaddr64, size64; + struct resource res; unsigned int psize; /* Create our state struct */ @@ -56,21 +56,18 @@ int bcom_sram_init(struct device_node *sram_node, char *owner) } /* Get address and size of the sram */ - regaddr_p = of_get_address(sram_node, 0, &size64, NULL); - if (!regaddr_p) { + rv = of_address_to_resource(sram_node, 0, &res); + if (rv) { printk(KERN_ERR "%s: bcom_sram_init: " "Invalid device node !\n", owner); - rv = -EINVAL; goto error_free; } - regaddr64 = of_translate_address(sram_node, regaddr_p); - - bcom_sram->base_phys = (phys_addr_t) regaddr64; - bcom_sram->size = (unsigned int) size64; + bcom_sram->base_phys = res.start; + bcom_sram->size = resource_size(&res); /* Request region */ - if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) { + if (!request_mem_region(res.start, resource_size(&res), owner)) { printk(KERN_ERR "%s: bcom_sram_init: " "Couldn't request region !\n", owner); rv = -EBUSY; @@ -79,7 +76,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner) /* Map SRAM */ /* sram is not really __iomem */ - bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size); + bcom_sram->base_virt = (void *)ioremap(res.start, resource_size(&res)); if (!bcom_sram->base_virt) { printk(KERN_ERR "%s: bcom_sram_init: " @@ -120,7 +117,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner) return 0; error_release: - release_mem_region(bcom_sram->base_phys, bcom_sram->size); + release_mem_region(res.start, resource_size(&res)); error_free: kfree(bcom_sram); bcom_sram = NULL; diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 4169e1d7d5ca..6937cc0c0b65 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -21,10 +21,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -46,6 +48,10 @@ DMA_SLAVE_BUSWIDTH_32_BYTES | \ DMA_SLAVE_BUSWIDTH_64_BYTES) +#define AXI_DMA_FLAG_HAS_APB_REGS BIT(0) +#define AXI_DMA_FLAG_HAS_RESETS BIT(1) +#define AXI_DMA_FLAG_USE_CFG2 BIT(2) + static inline void axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val) { @@ -86,7 +92,8 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan, cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS | config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS); - if (chan->chip->dw->hdata->reg_map_8_channels) { + if (chan->chip->dw->hdata->reg_map_8_channels && + !chan->chip->dw->hdata->use_cfg2) { cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS | config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS | config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS | @@ -1140,7 +1147,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan) axi_chan_disable(chan); ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val, - !(val & chan_active), 1000, 10000); + !(val & chan_active), 1000, 50000); if (ret == -ETIMEDOUT) dev_warn(dchan2dev(dchan), "%s failed to stop\n", axi_chan_name(chan)); @@ -1367,10 +1374,11 @@ static int parse_device_properties(struct axi_dma_chip *chip) static int dw_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct axi_dma_chip *chip; struct dw_axi_dma *dw; struct dw_axi_dma_hcfg *hdata; + struct reset_control *resets; + unsigned int flags; u32 i; int ret; @@ -1398,12 +1406,25 @@ static int dw_probe(struct platform_device *pdev) if (IS_ERR(chip->regs)) return PTR_ERR(chip->regs); - if (of_device_is_compatible(node, "intel,kmb-axi-dma")) { + flags = (uintptr_t)of_device_get_match_data(&pdev->dev); + if (flags & AXI_DMA_FLAG_HAS_APB_REGS) { chip->apb_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(chip->apb_regs)) return PTR_ERR(chip->apb_regs); } + if (flags & AXI_DMA_FLAG_HAS_RESETS) { + resets = devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(resets)) + return PTR_ERR(resets); + + ret = reset_control_deassert(resets); + if (ret) + return ret; + } + + chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2); + chip->core_clk = devm_clk_get(chip->dev, "core-clk"); if (IS_ERR(chip->core_clk)) return PTR_ERR(chip->core_clk); @@ -1554,8 +1575,15 @@ static const struct dev_pm_ops dw_axi_dma_pm_ops = { }; static const struct of_device_id dw_dma_of_id_table[] = { - { .compatible = "snps,axi-dma-1.01a" }, - { .compatible = "intel,kmb-axi-dma" }, + { + .compatible = "snps,axi-dma-1.01a" + }, { + .compatible = "intel,kmb-axi-dma", + .data = (void *)AXI_DMA_FLAG_HAS_APB_REGS, + }, { + .compatible = "starfive,jh7110-axi-dma", + .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), + }, {} }; MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index e9d5eb0fd594..eb267cb24f67 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -33,6 +33,7 @@ struct dw_axi_dma_hcfg { /* Register map for DMAX_NUM_CHANNELS <= 8 */ bool reg_map_8_channels; bool restrict_axi_burst_len; + bool use_cfg2; }; struct axi_dma_chan { diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index 1906a836f0aa..7d2b73ef0872 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -181,7 +181,7 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc) dw_edma_free_desc(vd2dw_edma_desc(vdesc)); } -static void dw_edma_start_transfer(struct dw_edma_chan *chan) +static int dw_edma_start_transfer(struct dw_edma_chan *chan) { struct dw_edma_chunk *child; struct dw_edma_desc *desc; @@ -189,16 +189,16 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan) vd = vchan_next_desc(&chan->vc); if (!vd) - return; + return 0; desc = vd2dw_edma_desc(vd); if (!desc) - return; + return 0; child = list_first_entry_or_null(&desc->chunk->list, struct dw_edma_chunk, list); if (!child) - return; + return 0; dw_edma_v0_core_start(child, !desc->xfer_sz); desc->xfer_sz += child->ll_region.sz; @@ -206,6 +206,8 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan) list_del(&child->list); kfree(child); desc->chunks_alloc--; + + return 1; } static void dw_edma_device_caps(struct dma_chan *dchan, @@ -306,9 +308,12 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan) struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan); unsigned long flags; + if (!chan->configured) + return; + spin_lock_irqsave(&chan->vc.lock, flags); - if (chan->configured && chan->request == EDMA_REQ_NONE && - chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) { + if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE && + chan->status == EDMA_ST_IDLE) { chan->status = EDMA_ST_BUSY; dw_edma_start_transfer(chan); } @@ -602,14 +607,14 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan) switch (chan->request) { case EDMA_REQ_NONE: desc = vd2dw_edma_desc(vd); - if (desc->chunks_alloc) { - chan->status = EDMA_ST_BUSY; - dw_edma_start_transfer(chan); - } else { + if (!desc->chunks_alloc) { list_del(&vd->node); vchan_cookie_complete(vd); - chan->status = EDMA_ST_IDLE; } + + /* Continue transferring if there are remaining chunks or issued requests. + */ + chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE; break; case EDMA_REQ_STOP: diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c index 72e79a0c0a4e..32f834a3848a 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.c +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c @@ -159,62 +159,6 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch, #define GET_CH_32(dw, dir, ch, name) \ readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name)) -static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch, - u64 value, void __iomem *addr) -{ - if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) { - u32 viewport_sel; - unsigned long flags; - - raw_spin_lock_irqsave(&dw->lock, flags); - - viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch); - if (dir == EDMA_DIR_READ) - viewport_sel |= BIT(31); - - writel(viewport_sel, - &(__dw_regs(dw)->type.legacy.viewport_sel)); - writeq(value, addr); - - raw_spin_unlock_irqrestore(&dw->lock, flags); - } else { - writeq(value, addr); - } -} - -static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch, - const void __iomem *addr) -{ - u64 value; - - if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) { - u32 viewport_sel; - unsigned long flags; - - raw_spin_lock_irqsave(&dw->lock, flags); - - viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch); - if (dir == EDMA_DIR_READ) - viewport_sel |= BIT(31); - - writel(viewport_sel, - &(__dw_regs(dw)->type.legacy.viewport_sel)); - value = readq(addr); - - raw_spin_unlock_irqrestore(&dw->lock, flags); - } else { - value = readq(addr); - } - - return value; -} - -#define SET_CH_64(dw, dir, ch, name, value) \ - writeq_ch(dw, dir, ch, value, &(__dw_ch_regs(dw, dir, ch)->name)) - -#define GET_CH_64(dw, dir, ch, name) \ - readq_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name)) - /* eDMA management callbacks */ void dw_edma_v0_core_off(struct dw_edma *dw) { diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index d19ea885c63e..5338a94f1a69 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -1431,4 +1431,3 @@ subsys_initcall(ep93xx_dma_module_init); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("EP93xx DMA driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile index a1e9f2b3a37c..dc096839ac63 100644 --- a/drivers/dma/idxd/Makefile +++ b/drivers/dma/idxd/Makefile @@ -1,7 +1,7 @@ ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=IDXD obj-$(CONFIG_INTEL_IDXD) += idxd.o -idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o +idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o debugfs.o idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index 674bfefca088..d32deb9b4e3d 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include "registers.h" #include "idxd.h" @@ -21,6 +23,13 @@ struct idxd_cdev_context { struct ida minor_ida; }; +/* + * Since user file names are global in DSA devices, define their ida's as + * global to avoid conflict file names. + */ +static DEFINE_IDA(file_ida); +static DEFINE_MUTEX(ida_lock); + /* * ictx is an array based off of accelerator types. enum idxd_type * is used as index @@ -34,8 +43,119 @@ struct idxd_user_context { struct idxd_wq *wq; struct task_struct *task; unsigned int pasid; + struct mm_struct *mm; unsigned int flags; struct iommu_sva *sva; + struct idxd_dev idxd_dev; + u64 counters[COUNTER_MAX]; + int id; + pid_t pid; +}; + +static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid); +static void idxd_xa_pasid_remove(struct idxd_user_context *ctx); + +static inline struct idxd_user_context *dev_to_uctx(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_user_context, idxd_dev); +} + +static ssize_t cr_faults_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct idxd_user_context *ctx = dev_to_uctx(dev); + + return sysfs_emit(buf, "%llu\n", ctx->counters[COUNTER_FAULTS]); +} +static DEVICE_ATTR_RO(cr_faults); + +static ssize_t cr_fault_failures_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct idxd_user_context *ctx = dev_to_uctx(dev); + + return sysfs_emit(buf, "%llu\n", ctx->counters[COUNTER_FAULT_FAILS]); +} +static DEVICE_ATTR_RO(cr_fault_failures); + +static ssize_t pid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct idxd_user_context *ctx = dev_to_uctx(dev); + + return sysfs_emit(buf, "%u\n", ctx->pid); +} +static DEVICE_ATTR_RO(pid); + +static struct attribute *cdev_file_attributes[] = { + &dev_attr_cr_faults.attr, + &dev_attr_cr_fault_failures.attr, + &dev_attr_pid.attr, + NULL +}; + +static umode_t cdev_file_attr_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, typeof(*dev), kobj); + struct idxd_user_context *ctx = dev_to_uctx(dev); + struct idxd_wq *wq = ctx->wq; + + if (!wq_pasid_enabled(wq)) + return 0; + + return a->mode; +} + +static const struct attribute_group cdev_file_attribute_group = { + .attrs = cdev_file_attributes, + .is_visible = cdev_file_attr_visible, +}; + +static const struct attribute_group *cdev_file_attribute_groups[] = { + &cdev_file_attribute_group, + NULL +}; + +static void idxd_file_dev_release(struct device *dev) +{ + struct idxd_user_context *ctx = dev_to_uctx(dev); + struct idxd_wq *wq = ctx->wq; + struct idxd_device *idxd = wq->idxd; + int rc; + + mutex_lock(&ida_lock); + ida_free(&file_ida, ctx->id); + mutex_unlock(&ida_lock); + + /* Wait for in-flight operations to complete. */ + if (wq_shared(wq)) { + idxd_device_drain_pasid(idxd, ctx->pasid); + } else { + if (device_user_pasid_enabled(idxd)) { + /* The wq disable in the disable pasid function will drain the wq */ + rc = idxd_wq_disable_pasid(wq); + if (rc < 0) + dev_err(dev, "wq disable pasid failed.\n"); + } else { + idxd_wq_drain(wq); + } + } + + if (ctx->sva) { + idxd_cdev_evl_drain_pasid(wq, ctx->pasid); + iommu_sva_unbind_device(ctx->sva); + idxd_xa_pasid_remove(ctx); + } + kfree(ctx); + mutex_lock(&wq->wq_lock); + idxd_wq_put(wq); + mutex_unlock(&wq->wq_lock); +} + +static struct device_type idxd_cdev_file_type = { + .name = "idxd_file", + .release = idxd_file_dev_release, + .groups = cdev_file_attribute_groups, }; static void idxd_cdev_dev_release(struct device *dev) @@ -68,15 +188,46 @@ static inline struct idxd_wq *inode_wq(struct inode *inode) return idxd_cdev->wq; } +static void idxd_xa_pasid_remove(struct idxd_user_context *ctx) +{ + struct idxd_wq *wq = ctx->wq; + void *ptr; + + mutex_lock(&wq->uc_lock); + ptr = xa_cmpxchg(&wq->upasid_xa, ctx->pasid, ctx, NULL, GFP_KERNEL); + if (ptr != (void *)ctx) + dev_warn(&wq->idxd->pdev->dev, "xarray cmpxchg failed for pasid %u\n", + ctx->pasid); + mutex_unlock(&wq->uc_lock); +} + +void idxd_user_counter_increment(struct idxd_wq *wq, u32 pasid, int index) +{ + struct idxd_user_context *ctx; + + if (index >= COUNTER_MAX) + return; + + mutex_lock(&wq->uc_lock); + ctx = xa_load(&wq->upasid_xa, pasid); + if (!ctx) { + mutex_unlock(&wq->uc_lock); + return; + } + ctx->counters[index]++; + mutex_unlock(&wq->uc_lock); +} + static int idxd_cdev_open(struct inode *inode, struct file *filp) { struct idxd_user_context *ctx; struct idxd_device *idxd; struct idxd_wq *wq; - struct device *dev; + struct device *dev, *fdev; int rc = 0; struct iommu_sva *sva; unsigned int pasid; + struct idxd_cdev *idxd_cdev; wq = inode_wq(inode); idxd = wq->idxd; @@ -97,6 +248,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) ctx->wq = wq; filp->private_data = ctx; + ctx->pid = current->pid; if (device_user_pasid_enabled(idxd)) { sva = iommu_sva_bind_device(dev, current->mm); @@ -108,65 +260,117 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) pasid = iommu_sva_get_pasid(sva); if (pasid == IOMMU_PASID_INVALID) { - iommu_sva_unbind_device(sva); rc = -EINVAL; - goto failed; + goto failed_get_pasid; } ctx->sva = sva; ctx->pasid = pasid; + ctx->mm = current->mm; + + mutex_lock(&wq->uc_lock); + rc = xa_insert(&wq->upasid_xa, pasid, ctx, GFP_KERNEL); + mutex_unlock(&wq->uc_lock); + if (rc < 0) + dev_warn(dev, "PASID entry already exist in xarray.\n"); if (wq_dedicated(wq)) { rc = idxd_wq_set_pasid(wq, pasid); if (rc < 0) { - iommu_sva_unbind_device(sva); dev_err(dev, "wq set pasid failed: %d\n", rc); - goto failed; + goto failed_set_pasid; } } } + idxd_cdev = wq->idxd_cdev; + mutex_lock(&ida_lock); + ctx->id = ida_alloc(&file_ida, GFP_KERNEL); + mutex_unlock(&ida_lock); + if (ctx->id < 0) { + dev_warn(dev, "ida alloc failure\n"); + goto failed_ida; + } + ctx->idxd_dev.type = IDXD_DEV_CDEV_FILE; + fdev = user_ctx_dev(ctx); + device_initialize(fdev); + fdev->parent = cdev_dev(idxd_cdev); + fdev->bus = &dsa_bus_type; + fdev->type = &idxd_cdev_file_type; + + rc = dev_set_name(fdev, "file%d", ctx->id); + if (rc < 0) { + dev_warn(dev, "set name failure\n"); + goto failed_dev_name; + } + + rc = device_add(fdev); + if (rc < 0) { + dev_warn(dev, "file device add failure\n"); + goto failed_dev_add; + } + idxd_wq_get(wq); mutex_unlock(&wq->wq_lock); return 0; - failed: +failed_dev_add: +failed_dev_name: + put_device(fdev); +failed_ida: +failed_set_pasid: + if (device_user_pasid_enabled(idxd)) + idxd_xa_pasid_remove(ctx); +failed_get_pasid: + if (device_user_pasid_enabled(idxd)) + iommu_sva_unbind_device(sva); +failed: mutex_unlock(&wq->wq_lock); kfree(ctx); return rc; } +static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid) +{ + struct idxd_device *idxd = wq->idxd; + struct idxd_evl *evl = idxd->evl; + union evl_status_reg status; + u16 h, t, size; + int ent_size = evl_ent_size(idxd); + struct __evl_entry *entry_head; + + if (!evl) + return; + + spin_lock(&evl->lock); + status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = status.tail; + h = evl->head; + size = evl->size; + + while (h != t) { + entry_head = (struct __evl_entry *)(evl->log + (h * ent_size)); + if (entry_head->pasid == pasid && entry_head->wq_idx == wq->id) + set_bit(h, evl->bmap); + h = (h + 1) % size; + } + spin_unlock(&evl->lock); + + drain_workqueue(wq->wq); +} + static int idxd_cdev_release(struct inode *node, struct file *filep) { struct idxd_user_context *ctx = filep->private_data; struct idxd_wq *wq = ctx->wq; struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; - int rc; dev_dbg(dev, "%s called\n", __func__); filep->private_data = NULL; - /* Wait for in-flight operations to complete. */ - if (wq_shared(wq)) { - idxd_device_drain_pasid(idxd, ctx->pasid); - } else { - if (device_user_pasid_enabled(idxd)) { - /* The wq disable in the disable pasid function will drain the wq */ - rc = idxd_wq_disable_pasid(wq); - if (rc < 0) - dev_err(dev, "wq disable pasid failed.\n"); - } else { - idxd_wq_drain(wq); - } - } + device_unregister(user_ctx_dev(ctx)); - if (ctx->sva) - iommu_sva_unbind_device(ctx->sva); - kfree(ctx); - mutex_lock(&wq->wq_lock); - idxd_wq_put(wq); - mutex_unlock(&wq->wq_lock); return 0; } @@ -297,6 +501,7 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) struct idxd_cdev *idxd_cdev; idxd_cdev = wq->idxd_cdev; + ida_destroy(&file_ida); wq->idxd_cdev = NULL; cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev)); put_device(cdev_dev(idxd_cdev)); @@ -330,6 +535,13 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) } mutex_lock(&wq->wq_lock); + + wq->wq = create_workqueue(dev_name(wq_confdev(wq))); + if (!wq->wq) { + rc = -ENOMEM; + goto wq_err; + } + wq->type = IDXD_WQT_USER; rc = drv_enable_wq(wq); if (rc < 0) @@ -348,7 +560,9 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) err_cdev: drv_disable_wq(wq); err: + destroy_workqueue(wq->wq); wq->type = IDXD_WQT_NONE; +wq_err: mutex_unlock(&wq->wq_lock); return rc; } @@ -361,6 +575,8 @@ static void idxd_user_drv_remove(struct idxd_dev *idxd_dev) idxd_wq_del_cdev(wq); drv_disable_wq(wq); wq->type = IDXD_WQT_NONE; + destroy_workqueue(wq->wq); + wq->wq = NULL; mutex_unlock(&wq->wq_lock); } @@ -407,3 +623,70 @@ void idxd_cdev_remove(void) ida_destroy(&ictx[i].minor_ida); } } + +/** + * idxd_copy_cr - copy completion record to user address space found by wq and + * PASID + * @wq: work queue + * @pasid: PASID + * @addr: user fault address to write + * @cr: completion record + * @len: number of bytes to copy + * + * This is called by a work that handles completion record fault. + * + * Return: number of bytes copied. + */ +int idxd_copy_cr(struct idxd_wq *wq, ioasid_t pasid, unsigned long addr, + void *cr, int len) +{ + struct device *dev = &wq->idxd->pdev->dev; + int left = len, status_size = 1; + struct idxd_user_context *ctx; + struct mm_struct *mm; + + mutex_lock(&wq->uc_lock); + + ctx = xa_load(&wq->upasid_xa, pasid); + if (!ctx) { + dev_warn(dev, "No user context\n"); + goto out; + } + + mm = ctx->mm; + /* + * The completion record fault handling work is running in kernel + * thread context. It temporarily switches to the mm to copy cr + * to addr in the mm. + */ + kthread_use_mm(mm); + left = copy_to_user((void __user *)addr + status_size, cr + status_size, + len - status_size); + /* + * Copy status only after the rest of completion record is copied + * successfully so that the user gets the complete completion record + * when a non-zero status is polled. + */ + if (!left) { + u8 status; + + /* + * Ensure that the completion record's status field is written + * after the rest of the completion record has been written. + * This ensures that the user receives the correct completion + * record information once polling for a non-zero status. + */ + wmb(); + status = *(u8 *)cr; + if (put_user(status, (u8 __user *)addr)) + left += status_size; + } else { + left += status_size; + } + kthread_unuse_mm(mm); + +out: + mutex_unlock(&wq->uc_lock); + + return len - left; +} diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index 3df21615f888..5fd38d1b9d28 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -16,7 +16,7 @@ extern void device_driver_detach(struct device *dev); static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = drv->bus; + const struct bus_type *bus = drv->bus; struct device *dev; int rc = -ENODEV; @@ -32,7 +32,7 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = drv->bus; + const struct bus_type *bus = drv->bus; struct device *dev; struct device_driver *alt_drv = NULL; int rc = -ENODEV; diff --git a/drivers/dma/idxd/debugfs.c b/drivers/dma/idxd/debugfs.c new file mode 100644 index 000000000000..9cfbd9b14c4c --- /dev/null +++ b/drivers/dma/idxd/debugfs.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ +#include +#include +#include +#include +#include +#include +#include +#include "idxd.h" +#include "registers.h" + +static struct dentry *idxd_debugfs_dir; + +static void dump_event_entry(struct idxd_device *idxd, struct seq_file *s, + u16 index, int *count, bool processed) +{ + struct idxd_evl *evl = idxd->evl; + struct dsa_evl_entry *entry; + struct dsa_completion_record *cr; + u64 *raw; + int i; + int evl_strides = evl_ent_size(idxd) / sizeof(u64); + + entry = (struct dsa_evl_entry *)evl->log + index; + + if (!entry->e.desc_valid) + return; + + seq_printf(s, "Event Log entry %d (real index %u) processed: %u\n", + *count, index, processed); + + seq_printf(s, "desc valid %u wq idx valid %u\n" + "batch %u fault rw %u priv %u error 0x%x\n" + "wq idx %u op %#x pasid %u batch idx %u\n" + "fault addr %#llx\n", + entry->e.desc_valid, entry->e.wq_idx_valid, + entry->e.batch, entry->e.fault_rw, entry->e.priv, + entry->e.error, entry->e.wq_idx, entry->e.operation, + entry->e.pasid, entry->e.batch_idx, entry->e.fault_addr); + + cr = &entry->cr; + seq_printf(s, "status %#x result %#x fault_info %#x bytes_completed %u\n" + "fault addr %#llx inv flags %#x\n\n", + cr->status, cr->result, cr->fault_info, cr->bytes_completed, + cr->fault_addr, cr->invalid_flags); + + raw = (u64 *)entry; + + for (i = 0; i < evl_strides; i++) + seq_printf(s, "entry[%d] = %#llx\n", i, raw[i]); + + seq_puts(s, "\n"); + *count += 1; +} + +static int debugfs_evl_show(struct seq_file *s, void *d) +{ + struct idxd_device *idxd = s->private; + struct idxd_evl *evl = idxd->evl; + union evl_status_reg evl_status; + u16 h, t, evl_size, i; + int count = 0; + bool processed = true; + + if (!evl || !evl->log) + return 0; + + spin_lock(&evl->lock); + + h = evl->head; + evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = evl_status.tail; + evl_size = evl->size; + + seq_printf(s, "Event Log head %u tail %u interrupt pending %u\n\n", + evl_status.head, evl_status.tail, evl_status.int_pending); + + i = t; + while (1) { + i = (i + 1) % evl_size; + if (i == t) + break; + + if (processed && i == h) + processed = false; + dump_event_entry(idxd, s, i, &count, processed); + } + + spin_unlock(&evl->lock); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(debugfs_evl); + +int idxd_device_init_debugfs(struct idxd_device *idxd) +{ + if (IS_ERR_OR_NULL(idxd_debugfs_dir)) + return 0; + + idxd->dbgfs_dir = debugfs_create_dir(dev_name(idxd_confdev(idxd)), idxd_debugfs_dir); + if (IS_ERR(idxd->dbgfs_dir)) + return PTR_ERR(idxd->dbgfs_dir); + + if (idxd->evl) { + idxd->dbgfs_evl_file = debugfs_create_file("event_log", 0400, + idxd->dbgfs_dir, idxd, + &debugfs_evl_fops); + if (IS_ERR(idxd->dbgfs_evl_file)) { + debugfs_remove_recursive(idxd->dbgfs_dir); + idxd->dbgfs_dir = NULL; + return PTR_ERR(idxd->dbgfs_evl_file); + } + } + + return 0; +} + +void idxd_device_remove_debugfs(struct idxd_device *idxd) +{ + debugfs_remove_recursive(idxd->dbgfs_dir); +} + +int idxd_init_debugfs(void) +{ + if (!debugfs_initialized()) + return 0; + + idxd_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(idxd_debugfs_dir)) + return PTR_ERR(idxd_debugfs_dir); + return 0; +} + +void idxd_remove_debugfs(void) +{ + debugfs_remove_recursive(idxd_debugfs_dir); +} diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5f321f3b4242..5abbcc61c528 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -752,6 +752,101 @@ void idxd_device_clear_state(struct idxd_device *idxd) spin_unlock(&idxd->dev_lock); } +static int idxd_device_evl_setup(struct idxd_device *idxd) +{ + union gencfg_reg gencfg; + union evlcfg_reg evlcfg; + union genctrl_reg genctrl; + struct device *dev = &idxd->pdev->dev; + void *addr; + dma_addr_t dma_addr; + int size; + struct idxd_evl *evl = idxd->evl; + unsigned long *bmap; + int rc; + + if (!evl) + return 0; + + size = evl_size(idxd); + + bmap = bitmap_zalloc(size, GFP_KERNEL); + if (!bmap) { + rc = -ENOMEM; + goto err_bmap; + } + + /* + * Address needs to be page aligned. However, dma_alloc_coherent() provides + * at minimal page size aligned address. No manual alignment required. + */ + addr = dma_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL); + if (!addr) { + rc = -ENOMEM; + goto err_alloc; + } + + memset(addr, 0, size); + + spin_lock(&evl->lock); + evl->log = addr; + evl->dma = dma_addr; + evl->log_size = size; + evl->bmap = bmap; + + memset(&evlcfg, 0, sizeof(evlcfg)); + evlcfg.bits[0] = dma_addr & GENMASK(63, 12); + evlcfg.size = evl->size; + + iowrite64(evlcfg.bits[0], idxd->reg_base + IDXD_EVLCFG_OFFSET); + iowrite64(evlcfg.bits[1], idxd->reg_base + IDXD_EVLCFG_OFFSET + 8); + + genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET); + genctrl.evl_int_en = 1; + iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET); + + gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); + gencfg.evl_en = 1; + iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); + + spin_unlock(&evl->lock); + return 0; + +err_alloc: + bitmap_free(bmap); +err_bmap: + return rc; +} + +static void idxd_device_evl_free(struct idxd_device *idxd) +{ + union gencfg_reg gencfg; + union genctrl_reg genctrl; + struct device *dev = &idxd->pdev->dev; + struct idxd_evl *evl = idxd->evl; + + gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); + if (!gencfg.evl_en) + return; + + spin_lock(&evl->lock); + gencfg.evl_en = 0; + iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); + + genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET); + genctrl.evl_int_en = 0; + iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET); + + iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET); + iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8); + + dma_free_coherent(dev, evl->log_size, evl->log, evl->dma); + bitmap_free(evl->bmap); + evl->log = NULL; + evl->size = IDXD_EVL_SIZE_MIN; + spin_unlock(&evl->lock); +} + static void idxd_group_config_write(struct idxd_group *group) { struct idxd_device *idxd = group->idxd; @@ -872,12 +967,16 @@ static int idxd_wq_config_write(struct idxd_wq *wq) wq->wqcfg->priority = wq->priority; if (idxd->hw.gen_cap.block_on_fault && - test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags)) + test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags) && + !test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags)) wq->wqcfg->bof = 1; if (idxd->hw.wq_cap.wq_ats_support) wq->wqcfg->wq_ats_disable = test_bit(WQ_FLAG_ATS_DISABLE, &wq->flags); + if (idxd->hw.wq_cap.wq_prs_support) + wq->wqcfg->wq_prs_disable = test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags); + /* bytes 12-15 */ wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes); idxd_wqcfg_set_max_batch_shift(idxd->data->type, wq->wqcfg, ilog2(wq->max_batch_size)); @@ -1194,7 +1293,7 @@ static void idxd_device_set_perm_entry(struct idxd_device *idxd, { union msix_perm mperm; - if (ie->pasid == INVALID_IOASID) + if (ie->pasid == IOMMU_PASID_INVALID) return; mperm.bits = 0; @@ -1224,7 +1323,7 @@ void idxd_wq_free_irq(struct idxd_wq *wq) idxd_device_clear_perm_entry(idxd, ie); ie->vector = -1; ie->int_handle = INVALID_INT_HANDLE; - ie->pasid = INVALID_IOASID; + ie->pasid = IOMMU_PASID_INVALID; } int idxd_wq_request_irq(struct idxd_wq *wq) @@ -1240,7 +1339,7 @@ int idxd_wq_request_irq(struct idxd_wq *wq) ie = &wq->ie; ie->vector = pci_irq_vector(pdev, ie->id); - ie->pasid = device_pasid_enabled(idxd) ? idxd->pasid : INVALID_IOASID; + ie->pasid = device_pasid_enabled(idxd) ? idxd->pasid : IOMMU_PASID_INVALID; idxd_device_set_perm_entry(idxd, ie); rc = request_threaded_irq(ie->vector, NULL, idxd_wq_thread, 0, "idxd-portal", ie); @@ -1265,7 +1364,7 @@ err_int_handle: free_irq(ie->vector, ie); err_irq: idxd_device_clear_perm_entry(idxd, ie); - ie->pasid = INVALID_IOASID; + ie->pasid = IOMMU_PASID_INVALID; return rc; } @@ -1451,15 +1550,24 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) if (rc < 0) return -ENXIO; + rc = idxd_device_evl_setup(idxd); + if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_DEV_EVL_ERR; + return rc; + } + /* Start device */ rc = idxd_device_enable(idxd); - if (rc < 0) + if (rc < 0) { + idxd_device_evl_free(idxd); return rc; + } /* Setup DMA device without channels */ rc = idxd_register_dma_device(idxd); if (rc < 0) { idxd_device_disable(idxd); + idxd_device_evl_free(idxd); idxd->cmd_status = IDXD_SCMD_DEV_DMA_ERR; return rc; } @@ -1488,6 +1596,7 @@ void idxd_device_drv_remove(struct idxd_dev *idxd_dev) idxd_device_disable(idxd); if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) idxd_device_reset(idxd); + idxd_device_evl_free(idxd); } static enum idxd_dev_type dev_types[] = { diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 7ced8d283d98..5428a2e1b1ec 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -10,9 +10,9 @@ #include #include #include -#include #include #include +#include #include #include "registers.h" @@ -32,6 +32,7 @@ enum idxd_dev_type { IDXD_DEV_GROUP, IDXD_DEV_ENGINE, IDXD_DEV_CDEV, + IDXD_DEV_CDEV_FILE, IDXD_DEV_MAX_TYPE, }; @@ -127,6 +128,12 @@ struct idxd_pmu { #define IDXD_MAX_PRIORITY 0xf +enum { + COUNTER_FAULTS = 0, + COUNTER_FAULT_FAILS, + COUNTER_MAX +}; + enum idxd_wq_state { IDXD_WQ_DISABLED = 0, IDXD_WQ_ENABLED, @@ -136,6 +143,7 @@ enum idxd_wq_flag { WQ_FLAG_DEDICATED = 0, WQ_FLAG_BLOCK_ON_FAULT, WQ_FLAG_ATS_DISABLE, + WQ_FLAG_PRS_DISABLE, }; enum idxd_wq_type { @@ -185,6 +193,7 @@ struct idxd_wq { struct idxd_dev idxd_dev; struct idxd_cdev *idxd_cdev; struct wait_queue_head err_queue; + struct workqueue_struct *wq; struct idxd_device *idxd; int id; struct idxd_irq_entry ie; @@ -214,6 +223,10 @@ struct idxd_wq { char name[WQ_NAME_SIZE + 1]; u64 max_xfer_bytes; u32 max_batch_size; + + /* Lock to protect upasid_xa access. */ + struct mutex uc_lock; + struct xarray upasid_xa; }; struct idxd_engine { @@ -232,6 +245,7 @@ struct idxd_hw { union engine_cap_reg engine_cap; struct opcap opcap; u32 cmd_cap; + union iaa_cap_reg iaa_cap; }; enum idxd_device_state { @@ -258,6 +272,32 @@ struct idxd_driver_data { struct device_type *dev_type; int compl_size; int align; + int evl_cr_off; + int cr_status_off; + int cr_result_off; +}; + +struct idxd_evl { + /* Lock to protect event log access. */ + spinlock_t lock; + void *log; + dma_addr_t dma; + /* Total size of event log = number of entries * entry size. */ + unsigned int log_size; + /* The number of entries in the event log. */ + u16 size; + u16 head; + unsigned long *bmap; + bool batch_fail[IDXD_MAX_BATCH_IDENT]; +}; + +struct idxd_evl_fault { + struct work_struct work; + struct idxd_wq *wq; + u8 status; + + /* make this last member always */ + struct __evl_entry entry[]; }; struct idxd_device { @@ -316,8 +356,24 @@ struct idxd_device { struct idxd_pmu *idxd_pmu; unsigned long *opcap_bmap; + struct idxd_evl *evl; + struct kmem_cache *evl_cache; + + struct dentry *dbgfs_dir; + struct dentry *dbgfs_evl_file; }; +static inline unsigned int evl_ent_size(struct idxd_device *idxd) +{ + return idxd->hw.gen_cap.evl_support ? + (32 * (1 << idxd->hw.gen_cap.evl_support)) : 0; +} + +static inline unsigned int evl_size(struct idxd_device *idxd) +{ + return idxd->evl->size * evl_ent_size(idxd); +} + /* IDXD software descriptor */ struct idxd_desc { union { @@ -351,6 +407,7 @@ enum idxd_completion_status { #define engine_confdev(engine) &engine->idxd_dev.conf_dev #define group_confdev(group) &group->idxd_dev.conf_dev #define cdev_dev(cdev) &cdev->idxd_dev.conf_dev +#define user_ctx_dev(ctx) (&(ctx)->idxd_dev.conf_dev) #define confdev_to_idxd_dev(dev) container_of(dev, struct idxd_dev, conf_dev) #define idxd_dev_to_idxd(idxd_dev) container_of(idxd_dev, struct idxd_device, idxd_dev) @@ -598,6 +655,7 @@ int idxd_register_driver(void); void idxd_unregister_driver(void); void idxd_wqs_quiesce(struct idxd_device *idxd); bool idxd_queue_int_handle_resubmit(struct idxd_desc *desc); +void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count); /* device interrupt control */ irqreturn_t idxd_misc_thread(int vec, void *data); @@ -662,6 +720,9 @@ void idxd_cdev_remove(void); int idxd_cdev_get_major(struct idxd_device *idxd); int idxd_wq_add_cdev(struct idxd_wq *wq); void idxd_wq_del_cdev(struct idxd_wq *wq); +int idxd_copy_cr(struct idxd_wq *wq, ioasid_t pasid, unsigned long addr, + void *buf, int len); +void idxd_user_counter_increment(struct idxd_wq *wq, u32 pasid, int index); /* perfmon */ #if IS_ENABLED(CONFIG_INTEL_IDXD_PERFMON) @@ -678,4 +739,10 @@ static inline void perfmon_init(void) {} static inline void perfmon_exit(void) {} #endif +/* debugfs */ +int idxd_device_init_debugfs(struct idxd_device *idxd); +void idxd_device_remove_debugfs(struct idxd_device *idxd); +int idxd_init_debugfs(void); +void idxd_remove_debugfs(void); + #endif diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 640d3048368e..1aa823974cda 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,9 @@ static struct idxd_driver_data idxd_driver_data[] = { .compl_size = sizeof(struct dsa_completion_record), .align = 32, .dev_type = &dsa_device_type, + .evl_cr_off = offsetof(struct dsa_evl_entry, cr), + .cr_status_off = offsetof(struct dsa_completion_record, status), + .cr_result_off = offsetof(struct dsa_completion_record, result), }, [IDXD_TYPE_IAX] = { .name_prefix = "iax", @@ -54,6 +56,9 @@ static struct idxd_driver_data idxd_driver_data[] = { .compl_size = sizeof(struct iax_completion_record), .align = 64, .dev_type = &iax_device_type, + .evl_cr_off = offsetof(struct iax_evl_entry, cr), + .cr_status_off = offsetof(struct iax_completion_record, status), + .cr_result_off = offsetof(struct iax_completion_record, error_code), }, }; @@ -105,7 +110,7 @@ static int idxd_setup_interrupts(struct idxd_device *idxd) ie = idxd_get_ie(idxd, msix_idx); ie->id = msix_idx; ie->int_handle = INVALID_INT_HANDLE; - ie->pasid = INVALID_IOASID; + ie->pasid = IOMMU_PASID_INVALID; spin_lock_init(&ie->list_lock); init_llist_head(&ie->pending_llist); @@ -200,6 +205,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) } bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); } + mutex_init(&wq->uc_lock); + xa_init(&wq->upasid_xa); idxd->wqs[i] = wq; } @@ -332,6 +339,33 @@ static void idxd_cleanup_internals(struct idxd_device *idxd) destroy_workqueue(idxd->wq); } +static int idxd_init_evl(struct idxd_device *idxd) +{ + struct device *dev = &idxd->pdev->dev; + struct idxd_evl *evl; + + if (idxd->hw.gen_cap.evl_support == 0) + return 0; + + evl = kzalloc_node(sizeof(*evl), GFP_KERNEL, dev_to_node(dev)); + if (!evl) + return -ENOMEM; + + spin_lock_init(&evl->lock); + evl->size = IDXD_EVL_SIZE_MIN; + + idxd->evl_cache = kmem_cache_create(dev_name(idxd_confdev(idxd)), + sizeof(struct idxd_evl_fault) + evl_ent_size(idxd), + 0, 0, NULL); + if (!idxd->evl_cache) { + kfree(evl); + return -ENOMEM; + } + + idxd->evl = evl; + return 0; +} + static int idxd_setup_internals(struct idxd_device *idxd) { struct device *dev = &idxd->pdev->dev; @@ -357,8 +391,14 @@ static int idxd_setup_internals(struct idxd_device *idxd) goto err_wkq_create; } + rc = idxd_init_evl(idxd); + if (rc < 0) + goto err_evl; + return 0; + err_evl: + destroy_workqueue(idxd->wq); err_wkq_create: for (i = 0; i < idxd->max_groups; i++) put_device(group_confdev(idxd->groups[i])); @@ -389,7 +429,7 @@ static void idxd_read_table_offsets(struct idxd_device *idxd) dev_dbg(dev, "IDXD Perfmon Offset: %#x\n", idxd->perfmon_offset); } -static void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count) +void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count) { int i, j, nr; @@ -461,6 +501,10 @@ static void idxd_read_caps(struct idxd_device *idxd) dev_dbg(dev, "opcap[%d]: %#llx\n", i, idxd->hw.opcap.bits[i]); } multi_u64_to_bmap(idxd->opcap_bmap, &idxd->hw.opcap.bits[0], 4); + + /* read iaa cap */ + if (idxd->data->type == IDXD_TYPE_IAX && idxd->hw.version >= DEVICE_VERSION_2) + idxd->hw.iaa_cap.bits = ioread64(idxd->reg_base + IDXD_IAACAP_OFFSET); } static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data) @@ -516,6 +560,27 @@ static void idxd_disable_system_pasid(struct idxd_device *idxd) idxd->sva = NULL; } +static int idxd_enable_sva(struct pci_dev *pdev) +{ + int ret; + + ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); + if (ret) + return ret; + + ret = iommu_dev_enable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); + if (ret) + iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); + + return ret; +} + +static void idxd_disable_sva(struct pci_dev *pdev) +{ + iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); + iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); +} + static int idxd_probe(struct idxd_device *idxd) { struct pci_dev *pdev = idxd->pdev; @@ -530,7 +595,7 @@ static int idxd_probe(struct idxd_device *idxd) dev_dbg(dev, "IDXD reset complete\n"); if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) { - if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA)) { + if (idxd_enable_sva(pdev)) { dev_warn(dev, "Unable to turn on user SVA feature.\n"); } else { set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags); @@ -578,21 +643,19 @@ static int idxd_probe(struct idxd_device *idxd) if (device_pasid_enabled(idxd)) idxd_disable_system_pasid(idxd); if (device_user_pasid_enabled(idxd)) - iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA); + idxd_disable_sva(pdev); return rc; } static void idxd_cleanup(struct idxd_device *idxd) { - struct device *dev = &idxd->pdev->dev; - perfmon_pmu_remove(idxd); idxd_cleanup_interrupts(idxd); idxd_cleanup_internals(idxd); if (device_pasid_enabled(idxd)) idxd_disable_system_pasid(idxd); if (device_user_pasid_enabled(idxd)) - iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA); + idxd_disable_sva(idxd->pdev); } static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -642,6 +705,10 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_dev_register; } + rc = idxd_device_init_debugfs(idxd); + if (rc) + dev_warn(dev, "IDXD debugfs failed to setup\n"); + dev_info(&pdev->dev, "Intel(R) Accelerator Device (v%x)\n", idxd->hw.version); @@ -704,13 +771,14 @@ static void idxd_remove(struct pci_dev *pdev) idxd_shutdown(pdev); if (device_pasid_enabled(idxd)) idxd_disable_system_pasid(idxd); + idxd_device_remove_debugfs(idxd); irq_entry = idxd_get_ie(idxd, 0); free_irq(irq_entry->vector, irq_entry); pci_free_irq_vectors(pdev); pci_iounmap(pdev, idxd->reg_base); if (device_user_pasid_enabled(idxd)) - iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); + idxd_disable_sva(pdev); pci_disable_device(pdev); destroy_workqueue(idxd->wq); perfmon_pmu_remove(idxd); @@ -761,6 +829,10 @@ static int __init idxd_init_module(void) if (err) goto err_cdev_register; + err = idxd_init_debugfs(); + if (err) + goto err_debugfs; + err = pci_register_driver(&idxd_pci_driver); if (err) goto err_pci_register; @@ -768,6 +840,8 @@ static int __init idxd_init_module(void) return 0; err_pci_register: + idxd_remove_debugfs(); +err_debugfs: idxd_cdev_remove(); err_cdev_register: idxd_driver_unregister(&idxd_user_drv); @@ -788,5 +862,6 @@ static void __exit idxd_exit_module(void) pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); perfmon_exit(); + idxd_remove_debugfs(); } module_exit(idxd_exit_module); diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index aa314ebec587..b501320a9c7a 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include "../dmaengine.h" #include "idxd.h" @@ -80,7 +82,7 @@ static void idxd_int_handle_revoke_drain(struct idxd_irq_entry *ie) desc.opcode = DSA_OPCODE_DRAIN; desc.priv = 1; - if (ie->pasid != INVALID_IOASID) + if (ie->pasid != IOMMU_PASID_INVALID) desc.pasid = ie->pasid; desc.int_handle = ie->int_handle; portal = idxd_wq_portal_addr(wq); @@ -217,13 +219,187 @@ static void idxd_int_handle_revoke(struct work_struct *work) kfree(revoke); } -static int process_misc_interrupts(struct idxd_device *idxd, u32 cause) +static void idxd_evl_fault_work(struct work_struct *work) { + struct idxd_evl_fault *fault = container_of(work, struct idxd_evl_fault, work); + struct idxd_wq *wq = fault->wq; + struct idxd_device *idxd = wq->idxd; + struct device *dev = &idxd->pdev->dev; + struct idxd_evl *evl = idxd->evl; + struct __evl_entry *entry_head = fault->entry; + void *cr = (void *)entry_head + idxd->data->evl_cr_off; + int cr_size = idxd->data->compl_size; + u8 *status = (u8 *)cr + idxd->data->cr_status_off; + u8 *result = (u8 *)cr + idxd->data->cr_result_off; + int copied, copy_size; + bool *bf; + + switch (fault->status) { + case DSA_COMP_CRA_XLAT: + if (entry_head->batch && entry_head->first_err_in_batch) + evl->batch_fail[entry_head->batch_id] = false; + + copy_size = cr_size; + idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULTS); + break; + case DSA_COMP_BATCH_EVL_ERR: + bf = &evl->batch_fail[entry_head->batch_id]; + + copy_size = entry_head->rcr || *bf ? cr_size : 0; + if (*bf) { + if (*status == DSA_COMP_SUCCESS) + *status = DSA_COMP_BATCH_FAIL; + *result = 1; + *bf = false; + } + idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULTS); + break; + case DSA_COMP_DRAIN_EVL: + copy_size = cr_size; + break; + default: + copy_size = 0; + dev_dbg_ratelimited(dev, "Unrecognized error code: %#x\n", fault->status); + break; + } + + if (copy_size == 0) + return; + + /* + * Copy completion record to fault_addr in user address space + * that is found by wq and PASID. + */ + copied = idxd_copy_cr(wq, entry_head->pasid, entry_head->fault_addr, + cr, copy_size); + /* + * The task that triggered the page fault is unknown currently + * because multiple threads may share the user address + * space or the task exits already before this fault. + * So if the copy fails, SIGSEGV can not be sent to the task. + * Just print an error for the failure. The user application + * waiting for the completion record will time out on this + * failure. + */ + switch (fault->status) { + case DSA_COMP_CRA_XLAT: + if (copied != copy_size) { + idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULT_FAILS); + dev_dbg_ratelimited(dev, "Failed to write to completion record: (%d:%d)\n", + copy_size, copied); + if (entry_head->batch) + evl->batch_fail[entry_head->batch_id] = true; + } + break; + case DSA_COMP_BATCH_EVL_ERR: + if (copied != copy_size) { + idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULT_FAILS); + dev_dbg_ratelimited(dev, "Failed to write to batch completion record: (%d:%d)\n", + copy_size, copied); + } + break; + case DSA_COMP_DRAIN_EVL: + if (copied != copy_size) + dev_dbg_ratelimited(dev, "Failed to write to drain completion record: (%d:%d)\n", + copy_size, copied); + break; + } + + kmem_cache_free(idxd->evl_cache, fault); +} + +static void process_evl_entry(struct idxd_device *idxd, + struct __evl_entry *entry_head, unsigned int index) +{ + struct device *dev = &idxd->pdev->dev; + struct idxd_evl *evl = idxd->evl; + u8 status; + + if (test_bit(index, evl->bmap)) { + clear_bit(index, evl->bmap); + } else { + status = DSA_COMP_STATUS(entry_head->error); + + if (status == DSA_COMP_CRA_XLAT || status == DSA_COMP_DRAIN_EVL || + status == DSA_COMP_BATCH_EVL_ERR) { + struct idxd_evl_fault *fault; + int ent_size = evl_ent_size(idxd); + + if (entry_head->rci) + dev_dbg(dev, "Completion Int Req set, ignoring!\n"); + + if (!entry_head->rcr && status == DSA_COMP_DRAIN_EVL) + return; + + fault = kmem_cache_alloc(idxd->evl_cache, GFP_ATOMIC); + if (fault) { + struct idxd_wq *wq = idxd->wqs[entry_head->wq_idx]; + + fault->wq = wq; + fault->status = status; + memcpy(&fault->entry, entry_head, ent_size); + INIT_WORK(&fault->work, idxd_evl_fault_work); + queue_work(wq->wq, &fault->work); + } else { + dev_warn(dev, "Failed to service fault work.\n"); + } + } else { + dev_warn_ratelimited(dev, "Device error %#x operation: %#x fault addr: %#llx\n", + status, entry_head->operation, + entry_head->fault_addr); + } + } +} + +static void process_evl_entries(struct idxd_device *idxd) +{ + union evl_status_reg evl_status; + unsigned int h, t; + struct idxd_evl *evl = idxd->evl; + struct __evl_entry *entry_head; + unsigned int ent_size = evl_ent_size(idxd); + u32 size; + + evl_status.bits = 0; + evl_status.int_pending = 1; + + spin_lock(&evl->lock); + /* Clear interrupt pending bit */ + iowrite32(evl_status.bits_upper32, + idxd->reg_base + IDXD_EVLSTATUS_OFFSET + sizeof(u32)); + h = evl->head; + evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + t = evl_status.tail; + size = idxd->evl->size; + + while (h != t) { + entry_head = (struct __evl_entry *)(evl->log + (h * ent_size)); + process_evl_entry(idxd, entry_head, h); + h = (h + 1) % size; + } + + evl->head = h; + evl_status.head = h; + iowrite32(evl_status.bits_lower32, idxd->reg_base + IDXD_EVLSTATUS_OFFSET); + spin_unlock(&evl->lock); +} + +irqreturn_t idxd_misc_thread(int vec, void *data) +{ + struct idxd_irq_entry *irq_entry = data; + struct idxd_device *idxd = ie_to_idxd(irq_entry); struct device *dev = &idxd->pdev->dev; union gensts_reg gensts; u32 val = 0; int i; bool err = false; + u32 cause; + + cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET); + if (!cause) + return IRQ_NONE; + + iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET); if (cause & IDXD_INTC_HALT_STATE) goto halt; @@ -295,13 +471,18 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause) perfmon_counter_overflow(idxd); } + if (cause & IDXD_INTC_EVL) { + val |= IDXD_INTC_EVL; + process_evl_entries(idxd); + } + val ^= cause; if (val) dev_warn_once(dev, "Unexpected interrupt cause bits set: %#x\n", val); if (!err) - return 0; + goto out; halt: gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET); @@ -324,33 +505,10 @@ halt: "idxd halted, need %s.\n", gensts.reset_type == IDXD_DEVICE_RESET_FLR ? "FLR" : "system reset"); - return -ENXIO; } } - return 0; -} - -irqreturn_t idxd_misc_thread(int vec, void *data) -{ - struct idxd_irq_entry *irq_entry = data; - struct idxd_device *idxd = ie_to_idxd(irq_entry); - int rc; - u32 cause; - - cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET); - if (cause) - iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET); - - while (cause) { - rc = process_misc_interrupts(idxd, cause); - if (rc < 0) - break; - cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET); - if (cause) - iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET); - } - +out: return IRQ_HANDLED; } diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index fe3b8d04f9db..7b54a3939ea1 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -3,6 +3,8 @@ #ifndef _IDXD_REGISTERS_H_ #define _IDXD_REGISTERS_H_ +#include + /* PCI Config */ #define PCI_DEVICE_ID_INTEL_DSA_SPR0 0x0b25 #define PCI_DEVICE_ID_INTEL_IAX_SPR0 0x0cfe @@ -31,7 +33,9 @@ union gen_cap_reg { u64 rsvd:3; u64 dest_readback:1; u64 drain_readback:1; - u64 rsvd2:6; + u64 rsvd2:3; + u64 evl_support:2; + u64 batch_continuation:1; u64 max_xfer_shift:5; u64 max_batch_shift:4; u64 max_ims_mult:6; @@ -55,7 +59,8 @@ union wq_cap_reg { u64 occupancy:1; u64 occupancy_int:1; u64 op_config:1; - u64 rsvd3:9; + u64 wq_prs_support:1; + u64 rsvd4:8; }; u64 bits; } __packed; @@ -117,7 +122,8 @@ union gencfg_reg { u32 rdbuf_limit:8; u32 rsvd:4; u32 user_int_en:1; - u32 rsvd2:19; + u32 evl_en:1; + u32 rsvd2:18; }; u32 bits; } __packed; @@ -127,7 +133,8 @@ union genctrl_reg { struct { u32 softerr_int_en:1; u32 halt_int_en:1; - u32 rsvd:30; + u32 evl_int_en:1; + u32 rsvd:29; }; u32 bits; } __packed; @@ -162,6 +169,7 @@ enum idxd_device_reset_type { #define IDXD_INTC_OCCUPY 0x04 #define IDXD_INTC_PERFMON_OVFL 0x08 #define IDXD_INTC_HALT_STATE 0x10 +#define IDXD_INTC_EVL 0x20 #define IDXD_INTC_INT_HANDLE_REVOKED 0x80000000 #define IDXD_CMD_OFFSET 0xa0 @@ -276,6 +284,45 @@ union sw_err_reg { u64 bits[4]; } __packed; +union iaa_cap_reg { + struct { + u64 dec_aecs_format_ver:1; + u64 drop_init_bits:1; + u64 chaining:1; + u64 force_array_output_mod:1; + u64 load_part_aecs:1; + u64 comp_early_abort:1; + u64 nested_comp:1; + u64 diction_comp:1; + u64 header_gen:1; + u64 crypto_gcm:1; + u64 crypto_cfb:1; + u64 crypto_xts:1; + u64 rsvd:52; + }; + u64 bits; +} __packed; + +#define IDXD_IAACAP_OFFSET 0x180 + +#define IDXD_EVLCFG_OFFSET 0xe0 +union evlcfg_reg { + struct { + u64 pasid_en:1; + u64 priv:1; + u64 rsvd:10; + u64 base_addr:52; + + u64 size:16; + u64 pasid:20; + u64 rsvd2:28; + }; + u64 bits[2]; +} __packed; + +#define IDXD_EVL_SIZE_MIN 0x0040 +#define IDXD_EVL_SIZE_MAX 0xffff + union msix_perm { struct { u32 rsvd:2; @@ -325,7 +372,7 @@ union wqcfg { u32 mode:1; /* shared or dedicated */ u32 bof:1; /* block on fault */ u32 wq_ats_disable:1; - u32 rsvd2:1; + u32 wq_prs_disable:1; u32 priority:4; u32 pasid:20; u32 pasid_en:1; @@ -513,4 +560,73 @@ union filter_cfg { u64 val; } __packed; +#define IDXD_EVLSTATUS_OFFSET 0xf0 + +union evl_status_reg { + struct { + u32 head:16; + u32 rsvd:16; + u32 tail:16; + u32 rsvd2:14; + u32 int_pending:1; + u32 rsvd3:1; + }; + struct { + u32 bits_lower32; + u32 bits_upper32; + }; + u64 bits; +} __packed; + +#define IDXD_MAX_BATCH_IDENT 256 + +struct __evl_entry { + u64 rsvd:2; + u64 desc_valid:1; + u64 wq_idx_valid:1; + u64 batch:1; + u64 fault_rw:1; + u64 priv:1; + u64 err_info_valid:1; + u64 error:8; + u64 wq_idx:8; + u64 batch_id:8; + u64 operation:8; + u64 pasid:20; + u64 rsvd2:4; + + u16 batch_idx; + u16 rsvd3; + union { + /* Invalid Flags 0x11 */ + u32 invalid_flags; + /* Invalid Int Handle 0x19 */ + /* Page fault 0x1a */ + /* Page fault 0x06, 0x1f, only operand_id */ + /* Page fault before drain or in batch, 0x26, 0x27 */ + struct { + u16 int_handle; + u16 rci:1; + u16 ims:1; + u16 rcr:1; + u16 first_err_in_batch:1; + u16 rsvd4_2:9; + u16 operand_id:3; + }; + }; + u64 fault_addr; + u64 rsvd5; +} __packed; + +struct dsa_evl_entry { + struct __evl_entry e; + struct dsa_completion_record cr; +} __packed; + +struct iax_evl_entry { + struct __evl_entry e; + u64 rsvd[4]; + struct iax_completion_record cr; +} __packed; + #endif diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 18cd8151dee0..293739ac5596 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -822,10 +822,14 @@ static ssize_t wq_block_on_fault_store(struct device *dev, if (rc < 0) return rc; - if (bof) + if (bof) { + if (test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags)) + return -EOPNOTSUPP; + set_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); - else + } else { clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); + } return count; } @@ -1109,6 +1113,44 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute static struct device_attribute dev_attr_wq_ats_disable = __ATTR(ats_disable, 0644, wq_ats_disable_show, wq_ats_disable_store); +static ssize_t wq_prs_disable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct idxd_wq *wq = confdev_to_wq(dev); + + return sysfs_emit(buf, "%u\n", test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags)); +} + +static ssize_t wq_prs_disable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_wq *wq = confdev_to_wq(dev); + struct idxd_device *idxd = wq->idxd; + bool prs_dis; + int rc; + + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + + if (!idxd->hw.wq_cap.wq_prs_support) + return -EOPNOTSUPP; + + rc = kstrtobool(buf, &prs_dis); + if (rc < 0) + return rc; + + if (prs_dis) { + set_bit(WQ_FLAG_PRS_DISABLE, &wq->flags); + /* when PRS is disabled, BOF needs to be off as well */ + clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); + } else { + clear_bit(WQ_FLAG_PRS_DISABLE, &wq->flags); + } + return count; +} + +static struct device_attribute dev_attr_wq_prs_disable = + __ATTR(prs_disable, 0644, wq_prs_disable_show, wq_prs_disable_store); + static ssize_t wq_occupancy_show(struct device *dev, struct device_attribute *attr, char *buf) { struct idxd_wq *wq = confdev_to_wq(dev); @@ -1239,6 +1281,7 @@ static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_max_transfer_size.attr, &dev_attr_wq_max_batch_size.attr, &dev_attr_wq_ats_disable.attr, + &dev_attr_wq_prs_disable.attr, &dev_attr_wq_occupancy.attr, &dev_attr_wq_enqcmds_retries.attr, &dev_attr_wq_op_config.attr, @@ -1260,6 +1303,13 @@ static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr, idxd->data->type == IDXD_TYPE_IAX; } +static bool idxd_wq_attr_wq_prs_disable_invisible(struct attribute *attr, + struct idxd_device *idxd) +{ + return attr == &dev_attr_wq_prs_disable.attr && + !idxd->hw.wq_cap.wq_prs_support; +} + static umode_t idxd_wq_attr_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -1273,6 +1323,9 @@ static umode_t idxd_wq_attr_visible(struct kobject *kobj, if (idxd_wq_attr_max_batch_size_invisible(attr, idxd)) return 0; + if (idxd_wq_attr_wq_prs_disable_invisible(attr, idxd)) + return 0; + return attr->mode; } @@ -1292,6 +1345,7 @@ static void idxd_conf_wq_release(struct device *dev) bitmap_free(wq->opcap_bmap); kfree(wq->wqcfg); + xa_destroy(&wq->upasid_xa); kfree(wq); } @@ -1452,15 +1506,13 @@ static ssize_t errors_show(struct device *dev, struct device_attribute *attr, char *buf) { struct idxd_device *idxd = confdev_to_idxd(dev); - int i, out = 0; + DECLARE_BITMAP(swerr_bmap, 256); + bitmap_zero(swerr_bmap, 256); spin_lock(&idxd->dev_lock); - for (i = 0; i < 4; i++) - out += sysfs_emit_at(buf, out, "%#018llx ", idxd->sw_err.bits[i]); + multi_u64_to_bmap(swerr_bmap, &idxd->sw_err.bits[0], 4); spin_unlock(&idxd->dev_lock); - out--; - out += sysfs_emit_at(buf, out, "\n"); - return out; + return sysfs_emit(buf, "%*pb\n", 256, swerr_bmap); } static DEVICE_ATTR_RO(errors); @@ -1563,6 +1615,59 @@ static ssize_t cmd_status_store(struct device *dev, struct device_attribute *att } static DEVICE_ATTR_RW(cmd_status); +static ssize_t iaa_cap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct idxd_device *idxd = confdev_to_idxd(dev); + + if (idxd->hw.version < DEVICE_VERSION_2) + return -EOPNOTSUPP; + + return sysfs_emit(buf, "%#llx\n", idxd->hw.iaa_cap.bits); +} +static DEVICE_ATTR_RO(iaa_cap); + +static ssize_t event_log_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct idxd_device *idxd = confdev_to_idxd(dev); + + if (!idxd->evl) + return -EOPNOTSUPP; + + return sysfs_emit(buf, "%u\n", idxd->evl->size); +} + +static ssize_t event_log_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_device *idxd = confdev_to_idxd(dev); + unsigned long val; + int rc; + + if (!idxd->evl) + return -EOPNOTSUPP; + + rc = kstrtoul(buf, 10, &val); + if (rc < 0) + return -EINVAL; + + if (idxd->state == IDXD_DEV_ENABLED) + return -EPERM; + + if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + return -EPERM; + + if (val < IDXD_EVL_SIZE_MIN || val > IDXD_EVL_SIZE_MAX || + (val * evl_ent_size(idxd) > ULONG_MAX - idxd->evl->dma)) + return -EINVAL; + + idxd->evl->size = val; + return count; +} +static DEVICE_ATTR_RW(event_log_size); + static bool idxd_device_attr_max_batch_size_invisible(struct attribute *attr, struct idxd_device *idxd) { @@ -1585,6 +1690,21 @@ static bool idxd_device_attr_read_buffers_invisible(struct attribute *attr, idxd->data->type == IDXD_TYPE_IAX; } +static bool idxd_device_attr_iaa_cap_invisible(struct attribute *attr, + struct idxd_device *idxd) +{ + return attr == &dev_attr_iaa_cap.attr && + (idxd->data->type != IDXD_TYPE_IAX || + idxd->hw.version < DEVICE_VERSION_2); +} + +static bool idxd_device_attr_event_log_size_invisible(struct attribute *attr, + struct idxd_device *idxd) +{ + return (attr == &dev_attr_event_log_size.attr && + !idxd->hw.gen_cap.evl_support); +} + static umode_t idxd_device_attr_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -1597,6 +1717,12 @@ static umode_t idxd_device_attr_visible(struct kobject *kobj, if (idxd_device_attr_read_buffers_invisible(attr, idxd)) return 0; + if (idxd_device_attr_iaa_cap_invisible(attr, idxd)) + return 0; + + if (idxd_device_attr_event_log_size_invisible(attr, idxd)) + return 0; + return attr->mode; } @@ -1622,6 +1748,8 @@ static struct attribute *idxd_device_attributes[] = { &dev_attr_read_buffer_limit.attr, &dev_attr_cdev_major.attr, &dev_attr_cmd_status.attr, + &dev_attr_iaa_cap.attr, + &dev_attr_event_log_size.attr, NULL, }; @@ -1643,6 +1771,8 @@ static void idxd_conf_device_release(struct device *dev) bitmap_free(idxd->wq_enable_map); kfree(idxd->wqs); kfree(idxd->engines); + kfree(idxd->evl); + kmem_cache_destroy(idxd->evl_cache); ida_free(&idxd_ida, idxd->id); bitmap_free(idxd->opcap_bmap); kfree(idxd); diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 80086977973f..f040751690af 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -750,7 +750,6 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan) desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) break; - memset(&desc->desc, 0, sizeof(struct dma_async_tx_descriptor)); dma_async_tx_descriptor_init(&desc->desc, chan); desc->desc.tx_submit = imxdma_tx_submit; /* txd.flags will be overwritten in prep funcs */ diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 5d707ff63554..c4602bfc9c74 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "dma.h" #include "registers.h" @@ -1191,13 +1190,13 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) ioat_dma->dca = ioat_dca_init(pdev, ioat_dma->reg_base); /* disable relaxed ordering */ - err = pcie_capability_read_word(pdev, IOAT_DEVCTRL_OFFSET, &val16); + err = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &val16); if (err) return pcibios_err_to_errno(err); /* clear relaxed ordering enable */ - val16 &= ~IOAT_DEVCTRL_ROE; - err = pcie_capability_write_word(pdev, IOAT_DEVCTRL_OFFSET, val16); + val16 &= ~PCI_EXP_DEVCTL_RELAX_EN; + err = pcie_capability_write_word(pdev, PCI_EXP_DEVCTL, val16); if (err) return pcibios_err_to_errno(err); @@ -1380,15 +1379,11 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (is_skx_ioat(pdev)) device->version = IOAT_VER_3_2; err = ioat3_dma_probe(device, ioat_dca_enabled); - - if (device->version >= IOAT_VER_3_3) - pci_enable_pcie_error_reporting(pdev); } else return -ENODEV; if (err) { dev_err(dev, "Intel(R) I/OAT DMA Engine init failed\n"); - pci_disable_pcie_error_reporting(pdev); return -ENODEV; } @@ -1411,7 +1406,6 @@ static void ioat_remove(struct pci_dev *pdev) device->dca = NULL; } - pci_disable_pcie_error_reporting(pdev); ioat_dma_remove(device); } diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h index f55a5f92f185..54cf0ad39887 100644 --- a/drivers/dma/ioat/registers.h +++ b/drivers/dma/ioat/registers.h @@ -14,13 +14,6 @@ #define IOAT_PCI_CHANERR_INT_OFFSET 0x180 #define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184 -/* PCIe config registers */ - -/* EXPCAPID + N */ -#define IOAT_DEVCTRL_OFFSET 0x8 -/* relaxed ordering enable */ -#define IOAT_DEVCTRL_ROE 0x10 - /* MMIO Device Registers */ #define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */ diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index baab1ca9f621..d799b99c18bd 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1797,6 +1797,5 @@ static int __init ipu_init(void) subsys_initcall(ipu_init); MODULE_DESCRIPTION("IPU core driver"); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Guennadi Liakhovetski "); MODULE_ALIAS("platform:ipu-core"); diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index 89790beba305..0e1e9ca1c005 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -739,32 +739,18 @@ static int mv_xor_v2_probe(struct platform_device *pdev) if (ret) return ret; - xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg"); - if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) { - if (!IS_ERR(xor_dev->reg_clk)) { - ret = clk_prepare_enable(xor_dev->reg_clk); - if (ret) - return ret; - } else { - return PTR_ERR(xor_dev->reg_clk); - } - } + xor_dev->reg_clk = devm_clk_get_optional_enabled(&pdev->dev, "reg"); + if (IS_ERR(xor_dev->reg_clk)) + return PTR_ERR(xor_dev->reg_clk); - xor_dev->clk = devm_clk_get(&pdev->dev, NULL); - if (PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) { - ret = EPROBE_DEFER; - goto disable_reg_clk; - } - if (!IS_ERR(xor_dev->clk)) { - ret = clk_prepare_enable(xor_dev->clk); - if (ret) - goto disable_reg_clk; - } + xor_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(xor_dev->clk)) + return PTR_ERR(xor_dev->clk); ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1, mv_xor_v2_set_msi_msg); if (ret) - goto disable_clk; + return ret; xor_dev->irq = msi_get_virq(&pdev->dev, 0); @@ -866,10 +852,6 @@ free_hw_desq: xor_dev->hw_desq_virt, xor_dev->hw_desq); free_msi_irqs: platform_msi_domain_free_irqs(&pdev->dev); -disable_clk: - clk_disable_unprepare(xor_dev->clk); -disable_reg_clk: - clk_disable_unprepare(xor_dev->reg_clk); return ret; } @@ -889,9 +871,6 @@ static int mv_xor_v2_remove(struct platform_device *pdev) tasklet_kill(&xor_dev->irq_tasklet); - clk_disable_unprepare(xor_dev->clk); - clk_disable_unprepare(xor_dev->reg_clk); - return 0; } @@ -917,4 +896,3 @@ static struct platform_driver mv_xor_v2_driver = { module_platform_driver(mv_xor_v2_driver); MODULE_DESCRIPTION("DMA engine driver for Marvell's Version 2 of XOR engine"); -MODULE_LICENSE("GPL"); diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index ac61ecda2926..775a7f408b9a 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -264,7 +264,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, } /* Silently fail if there is not even the "dmas" property */ - if (!of_find_property(np, "dmas", NULL)) + if (!of_property_present(np, "dmas")) return ERR_PTR(-ENODEV); count = of_property_count_strings(np, "dma-names"); diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 0d9257fbdfb0..b4731fe6bbc1 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1050,7 +1050,7 @@ static bool _trigger(struct pl330_thread *thrd) return true; } -static bool _start(struct pl330_thread *thrd) +static bool pl330_start_thread(struct pl330_thread *thrd) { switch (_state(thrd)) { case PL330_STATE_FAULT_COMPLETING: @@ -1702,7 +1702,7 @@ static int pl330_update(struct pl330_dmac *pl330) thrd->req_running = -1; /* Get going again ASAP */ - _start(thrd); + pl330_start_thread(thrd); /* For now, just make a list of callbacks to be done */ list_add_tail(&descdone->rqd, &pl330->req_done); @@ -2089,7 +2089,7 @@ static void pl330_tasklet(struct tasklet_struct *t) } else { /* Make sure the PL330 Channel thread is active */ spin_lock(&pch->thread->dmac->lock); - _start(pch->thread); + pl330_start_thread(pch->thread); spin_unlock(&pch->thread->dmac->lock); } @@ -2107,7 +2107,7 @@ static void pl330_tasklet(struct tasklet_struct *t) if (power_down) { pch->active = true; spin_lock(&pch->thread->dmac->lock); - _start(pch->thread); + pl330_start_thread(pch->thread); spin_unlock(&pch->thread->dmac->lock); power_down = false; } diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 59a36cbf9b5f..932628b319c8 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1966,7 +1966,6 @@ error_alloc_ev_ring: error_config_int: gpi_free_ring(&gpii->ev_ring, gpii); exit_gpi_init: - mutex_unlock(&gpii->ctrl_lock); return ret; } diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 62026607f3f8..05e96b31d871 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 476847a4916b..9479f29692d3 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -66,8 +67,6 @@ struct rz_dmac_chan { struct rz_dmac_desc *desc; int descs_allocated; - enum dma_slave_buswidth src_word_size; - enum dma_slave_buswidth dst_word_size; dma_addr_t src_per_address; dma_addr_t dst_per_address; @@ -92,6 +91,7 @@ struct rz_dmac_chan { struct rz_dmac { struct dma_device engine; struct device *dev; + struct reset_control *rstc; void __iomem *base; void __iomem *ext_base; @@ -601,9 +601,7 @@ static int rz_dmac_config(struct dma_chan *chan, u32 val; channel->src_per_address = config->src_addr; - channel->src_word_size = config->src_addr_width; channel->dst_per_address = config->dst_addr; - channel->dst_word_size = config->dst_addr_width; val = rz_dmac_ds_to_val_mapping(config->dst_addr_width); if (val == CHCFG_DS_INVALID) @@ -889,6 +887,11 @@ static int rz_dmac_probe(struct platform_device *pdev) /* Initialize the channels. */ INIT_LIST_HEAD(&dmac->engine.channels); + dmac->rstc = devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(dmac->rstc)) + return dev_err_probe(&pdev->dev, PTR_ERR(dmac->rstc), + "failed to get resets\n"); + pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) { @@ -896,6 +899,10 @@ static int rz_dmac_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = reset_control_deassert(dmac->rstc); + if (ret) + goto err_pm_runtime_put; + for (i = 0; i < dmac->n_channels; i++) { ret = rz_dmac_chan_probe(dmac, &dmac->channels[i], i); if (ret < 0) @@ -940,6 +947,7 @@ static int rz_dmac_probe(struct platform_device *pdev) dma_register_err: of_dma_controller_free(pdev->dev.of_node); err: + reset_control_assert(dmac->rstc); channel_num = i ? i - 1 : 0; for (i = 0; i < channel_num; i++) { struct rz_dmac_chan *channel = &dmac->channels[i]; @@ -950,6 +958,7 @@ err: channel->lmdesc.base_dma); } +err_pm_runtime_put: pm_runtime_put(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -972,6 +981,7 @@ static int rz_dmac_remove(struct platform_device *pdev) } of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&dmac->engine); + reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 158e5e7defae..588c5f409a80 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -1047,6 +1047,5 @@ static void __exit shdma_exit(void) } module_exit(shdma_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("SH-DMA driver base library"); MODULE_AUTHOR("Guennadi Liakhovetski "); diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index 46b884d46188..e415bd9f4f2b 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -398,4 +398,3 @@ arch_initcall(stm32_dmamux_init); MODULE_DESCRIPTION("DMA Router driver for STM32 DMA MUX"); MODULE_AUTHOR("M'boumba Cedric Madianga "); MODULE_AUTHOR("Pierre-Yves Mordret "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 84e7f4f4a800..1d0e9dd72ab3 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1814,4 +1814,3 @@ subsys_initcall(stm32_mdma_init); MODULE_DESCRIPTION("Driver for STM32 MDMA controller"); MODULE_AUTHOR("M'boumba Cedric Madianga "); MODULE_AUTHOR("Pierre-Yves Mordret "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index eaafcbe4ca94..cc6b91f48979 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -233,11 +233,6 @@ static inline void tdma_write(struct tegra_dma *tdma, u32 reg, u32 val) writel(val, tdma->base_addr + reg); } -static inline u32 tdma_read(struct tegra_dma *tdma, u32 reg) -{ - return readl(tdma->base_addr + reg); -} - static inline void tdc_write(struct tegra_dma_channel *tdc, u32 reg, u32 val) { diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile index bd1e07fda559..acc950bf609c 100644 --- a/drivers/dma/ti/Makefile +++ b/drivers/dma/ti/Makefile @@ -11,6 +11,7 @@ k3-psil-lib-objs := k3-psil.o \ k3-psil-am64.o \ k3-psil-j721s2.o \ k3-psil-am62.o \ - k3-psil-am62a.o + k3-psil-am62a.o \ + k3-psil-j784s4.o obj-$(CONFIG_TI_K3_PSIL) += k3-psil-lib.o obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index fa06d7e6d8e3..9ea91c640c32 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -318,14 +318,6 @@ static inline void edma_modify(struct edma_cc *ecc, int offset, unsigned and, edma_write(ecc, offset, val); } -static inline void edma_and(struct edma_cc *ecc, int offset, unsigned and) -{ - unsigned val = edma_read(ecc, offset); - - val &= and; - edma_write(ecc, offset, val); -} - static inline void edma_or(struct edma_cc *ecc, int offset, unsigned or) { unsigned val = edma_read(ecc, offset); diff --git a/drivers/dma/ti/k3-psil-j784s4.c b/drivers/dma/ti/k3-psil-j784s4.c new file mode 100644 index 000000000000..12bfa2478f92 --- /dev/null +++ b/drivers/dma/ti/k3-psil-j784s4.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com + */ + +#include + +#include "k3-psil-priv.h" + +#define PSIL_PDMA_XY_TR(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + }, \ + } + +#define PSIL_PDMA_XY_PKT(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .pkt_mode = 1, \ + }, \ + } + +#define PSIL_PDMA_MCASP(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_PDMA_XY, \ + .pdma_acc32 = 1, \ + .pdma_burst = 1, \ + }, \ + } + +#define PSIL_ETHERNET(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 16, \ + }, \ + } + +#define PSIL_SA2UL(x, tx) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + .pkt_mode = 1, \ + .needs_epib = 1, \ + .psd_size = 64, \ + .notdpkt = tx, \ + }, \ + } + +#define PSIL_CSI2RX(x) \ + { \ + .thread_id = x, \ + .ep_config = { \ + .ep_type = PSIL_EP_NATIVE, \ + }, \ + } + +/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */ +static struct psil_ep j784s4_src_ep_map[] = { + /* PDMA_MCASP - McASP0-4 */ + PSIL_PDMA_MCASP(0x4400), + PSIL_PDMA_MCASP(0x4401), + PSIL_PDMA_MCASP(0x4402), + PSIL_PDMA_MCASP(0x4403), + PSIL_PDMA_MCASP(0x4404), + /* PDMA_SPI_G0 - SPI0-3 */ + PSIL_PDMA_XY_PKT(0x4600), + PSIL_PDMA_XY_PKT(0x4601), + PSIL_PDMA_XY_PKT(0x4602), + PSIL_PDMA_XY_PKT(0x4603), + PSIL_PDMA_XY_PKT(0x4604), + PSIL_PDMA_XY_PKT(0x4605), + PSIL_PDMA_XY_PKT(0x4606), + PSIL_PDMA_XY_PKT(0x4607), + PSIL_PDMA_XY_PKT(0x4608), + PSIL_PDMA_XY_PKT(0x4609), + PSIL_PDMA_XY_PKT(0x460a), + PSIL_PDMA_XY_PKT(0x460b), + PSIL_PDMA_XY_PKT(0x460c), + PSIL_PDMA_XY_PKT(0x460d), + PSIL_PDMA_XY_PKT(0x460e), + PSIL_PDMA_XY_PKT(0x460f), + /* PDMA_SPI_G1 - SPI4-7 */ + PSIL_PDMA_XY_PKT(0x4620), + PSIL_PDMA_XY_PKT(0x4621), + PSIL_PDMA_XY_PKT(0x4622), + PSIL_PDMA_XY_PKT(0x4623), + PSIL_PDMA_XY_PKT(0x4624), + PSIL_PDMA_XY_PKT(0x4625), + PSIL_PDMA_XY_PKT(0x4626), + PSIL_PDMA_XY_PKT(0x4627), + PSIL_PDMA_XY_PKT(0x4628), + PSIL_PDMA_XY_PKT(0x4629), + PSIL_PDMA_XY_PKT(0x462a), + PSIL_PDMA_XY_PKT(0x462b), + PSIL_PDMA_XY_PKT(0x462c), + PSIL_PDMA_XY_PKT(0x462d), + PSIL_PDMA_XY_PKT(0x462e), + PSIL_PDMA_XY_PKT(0x462f), + /* MAIN_CPSW2G */ + PSIL_ETHERNET(0x4640), + /* PDMA_USART_G0 - UART0-1 */ + PSIL_PDMA_XY_PKT(0x4700), + PSIL_PDMA_XY_PKT(0x4701), + /* PDMA_USART_G1 - UART2-3 */ + PSIL_PDMA_XY_PKT(0x4702), + PSIL_PDMA_XY_PKT(0x4703), + /* PDMA_USART_G2 - UART4-9 */ + PSIL_PDMA_XY_PKT(0x4704), + PSIL_PDMA_XY_PKT(0x4705), + PSIL_PDMA_XY_PKT(0x4706), + PSIL_PDMA_XY_PKT(0x4707), + PSIL_PDMA_XY_PKT(0x4708), + PSIL_PDMA_XY_PKT(0x4709), + /* CSI2RX */ + PSIL_CSI2RX(0x4900), + PSIL_CSI2RX(0x4901), + PSIL_CSI2RX(0x4902), + PSIL_CSI2RX(0x4903), + PSIL_CSI2RX(0x4940), + PSIL_CSI2RX(0x4941), + PSIL_CSI2RX(0x4942), + PSIL_CSI2RX(0x4943), + PSIL_CSI2RX(0x4944), + PSIL_CSI2RX(0x4945), + PSIL_CSI2RX(0x4946), + PSIL_CSI2RX(0x4947), + PSIL_CSI2RX(0x4948), + PSIL_CSI2RX(0x4949), + PSIL_CSI2RX(0x494a), + PSIL_CSI2RX(0x494b), + PSIL_CSI2RX(0x494c), + PSIL_CSI2RX(0x494d), + PSIL_CSI2RX(0x494e), + PSIL_CSI2RX(0x494f), + PSIL_CSI2RX(0x4950), + PSIL_CSI2RX(0x4951), + PSIL_CSI2RX(0x4952), + PSIL_CSI2RX(0x4953), + PSIL_CSI2RX(0x4954), + PSIL_CSI2RX(0x4955), + PSIL_CSI2RX(0x4956), + PSIL_CSI2RX(0x4957), + PSIL_CSI2RX(0x4958), + PSIL_CSI2RX(0x4959), + PSIL_CSI2RX(0x495a), + PSIL_CSI2RX(0x495b), + PSIL_CSI2RX(0x495c), + PSIL_CSI2RX(0x495d), + PSIL_CSI2RX(0x495e), + PSIL_CSI2RX(0x495f), + PSIL_CSI2RX(0x4960), + PSIL_CSI2RX(0x4961), + PSIL_CSI2RX(0x4962), + PSIL_CSI2RX(0x4963), + PSIL_CSI2RX(0x4964), + PSIL_CSI2RX(0x4965), + PSIL_CSI2RX(0x4966), + PSIL_CSI2RX(0x4967), + PSIL_CSI2RX(0x4968), + PSIL_CSI2RX(0x4969), + PSIL_CSI2RX(0x496a), + PSIL_CSI2RX(0x496b), + PSIL_CSI2RX(0x496c), + PSIL_CSI2RX(0x496d), + PSIL_CSI2RX(0x496e), + PSIL_CSI2RX(0x496f), + PSIL_CSI2RX(0x4970), + PSIL_CSI2RX(0x4971), + PSIL_CSI2RX(0x4972), + PSIL_CSI2RX(0x4973), + PSIL_CSI2RX(0x4974), + PSIL_CSI2RX(0x4975), + PSIL_CSI2RX(0x4976), + PSIL_CSI2RX(0x4977), + PSIL_CSI2RX(0x4978), + PSIL_CSI2RX(0x4979), + PSIL_CSI2RX(0x497a), + PSIL_CSI2RX(0x497b), + PSIL_CSI2RX(0x497c), + PSIL_CSI2RX(0x497d), + PSIL_CSI2RX(0x497e), + PSIL_CSI2RX(0x497f), + PSIL_CSI2RX(0x4980), + PSIL_CSI2RX(0x4981), + PSIL_CSI2RX(0x4982), + PSIL_CSI2RX(0x4983), + PSIL_CSI2RX(0x4984), + PSIL_CSI2RX(0x4985), + PSIL_CSI2RX(0x4986), + PSIL_CSI2RX(0x4987), + PSIL_CSI2RX(0x4988), + PSIL_CSI2RX(0x4989), + PSIL_CSI2RX(0x498a), + PSIL_CSI2RX(0x498b), + PSIL_CSI2RX(0x498c), + PSIL_CSI2RX(0x498d), + PSIL_CSI2RX(0x498e), + PSIL_CSI2RX(0x498f), + PSIL_CSI2RX(0x4990), + PSIL_CSI2RX(0x4991), + PSIL_CSI2RX(0x4992), + PSIL_CSI2RX(0x4993), + PSIL_CSI2RX(0x4994), + PSIL_CSI2RX(0x4995), + PSIL_CSI2RX(0x4996), + PSIL_CSI2RX(0x4997), + PSIL_CSI2RX(0x4998), + PSIL_CSI2RX(0x4999), + PSIL_CSI2RX(0x499a), + PSIL_CSI2RX(0x499b), + PSIL_CSI2RX(0x499c), + PSIL_CSI2RX(0x499d), + PSIL_CSI2RX(0x499e), + PSIL_CSI2RX(0x499f), + /* MAIN_CPSW9G */ + PSIL_ETHERNET(0x4a00), + /* MAIN-SA2UL */ + PSIL_SA2UL(0x4a40, 0), + PSIL_SA2UL(0x4a41, 0), + PSIL_SA2UL(0x4a42, 0), + PSIL_SA2UL(0x4a43, 0), + /* MCU_CPSW0 */ + PSIL_ETHERNET(0x7000), + /* MCU_PDMA0 (MCU_PDMA_MISC_G0) - SPI0 */ + PSIL_PDMA_XY_PKT(0x7100), + PSIL_PDMA_XY_PKT(0x7101), + PSIL_PDMA_XY_PKT(0x7102), + PSIL_PDMA_XY_PKT(0x7103), + /* MCU_PDMA1 (MCU_PDMA_MISC_G1) - SPI1-2 */ + PSIL_PDMA_XY_PKT(0x7200), + PSIL_PDMA_XY_PKT(0x7201), + PSIL_PDMA_XY_PKT(0x7202), + PSIL_PDMA_XY_PKT(0x7203), + PSIL_PDMA_XY_PKT(0x7204), + PSIL_PDMA_XY_PKT(0x7205), + PSIL_PDMA_XY_PKT(0x7206), + PSIL_PDMA_XY_PKT(0x7207), + /* MCU_PDMA2 (MCU_PDMA_MISC_G2) - UART0 */ + PSIL_PDMA_XY_PKT(0x7300), + /* MCU_PDMA_ADC - ADC0-1 */ + PSIL_PDMA_XY_TR(0x7400), + PSIL_PDMA_XY_TR(0x7401), + PSIL_PDMA_XY_TR(0x7402), + PSIL_PDMA_XY_TR(0x7403), + /* MCU_SA2UL */ + PSIL_SA2UL(0x7500, 0), + PSIL_SA2UL(0x7501, 0), + PSIL_SA2UL(0x7502, 0), + PSIL_SA2UL(0x7503, 0), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep j784s4_dst_ep_map[] = { + /* MAIN_CPSW2G */ + PSIL_ETHERNET(0xc640), + PSIL_ETHERNET(0xc641), + PSIL_ETHERNET(0xc642), + PSIL_ETHERNET(0xc643), + PSIL_ETHERNET(0xc644), + PSIL_ETHERNET(0xc645), + PSIL_ETHERNET(0xc646), + PSIL_ETHERNET(0xc647), + /* MAIN_CPSW9G */ + PSIL_ETHERNET(0xca00), + PSIL_ETHERNET(0xca01), + PSIL_ETHERNET(0xca02), + PSIL_ETHERNET(0xca03), + PSIL_ETHERNET(0xca04), + PSIL_ETHERNET(0xca05), + PSIL_ETHERNET(0xca06), + PSIL_ETHERNET(0xca07), + /* MAIN-SA2UL */ + PSIL_SA2UL(0xca40, 1), + PSIL_SA2UL(0xca41, 1), + /* PDMA_SPI_G0 - SPI0-3 */ + PSIL_PDMA_XY_PKT(0xc600), + PSIL_PDMA_XY_PKT(0xc601), + PSIL_PDMA_XY_PKT(0xc602), + PSIL_PDMA_XY_PKT(0xc603), + PSIL_PDMA_XY_PKT(0xc604), + PSIL_PDMA_XY_PKT(0xc605), + PSIL_PDMA_XY_PKT(0xc606), + PSIL_PDMA_XY_PKT(0xc607), + PSIL_PDMA_XY_PKT(0xc608), + PSIL_PDMA_XY_PKT(0xc609), + PSIL_PDMA_XY_PKT(0xc60a), + PSIL_PDMA_XY_PKT(0xc60b), + PSIL_PDMA_XY_PKT(0xc60c), + PSIL_PDMA_XY_PKT(0xc60d), + PSIL_PDMA_XY_PKT(0xc60e), + PSIL_PDMA_XY_PKT(0xc60f), + /* PDMA_SPI_G1 - SPI4-7 */ + PSIL_PDMA_XY_PKT(0xc620), + PSIL_PDMA_XY_PKT(0xc621), + PSIL_PDMA_XY_PKT(0xc622), + PSIL_PDMA_XY_PKT(0xc623), + PSIL_PDMA_XY_PKT(0xc624), + PSIL_PDMA_XY_PKT(0xc625), + PSIL_PDMA_XY_PKT(0xc626), + PSIL_PDMA_XY_PKT(0xc627), + PSIL_PDMA_XY_PKT(0xc628), + PSIL_PDMA_XY_PKT(0xc629), + PSIL_PDMA_XY_PKT(0xc62a), + PSIL_PDMA_XY_PKT(0xc62b), + PSIL_PDMA_XY_PKT(0xc62c), + PSIL_PDMA_XY_PKT(0xc62d), + PSIL_PDMA_XY_PKT(0xc62e), + PSIL_PDMA_XY_PKT(0xc62f), + /* MCU_CPSW0 */ + PSIL_ETHERNET(0xf000), + PSIL_ETHERNET(0xf001), + PSIL_ETHERNET(0xf002), + PSIL_ETHERNET(0xf003), + PSIL_ETHERNET(0xf004), + PSIL_ETHERNET(0xf005), + PSIL_ETHERNET(0xf006), + PSIL_ETHERNET(0xf007), + /* MCU_PDMA_MISC_G0 - SPI0 */ + PSIL_PDMA_XY_PKT(0xf100), + PSIL_PDMA_XY_PKT(0xf101), + PSIL_PDMA_XY_PKT(0xf102), + PSIL_PDMA_XY_PKT(0xf103), + /* MCU_PDMA_MISC_G1 - SPI1-2 */ + PSIL_PDMA_XY_PKT(0xf200), + PSIL_PDMA_XY_PKT(0xf201), + PSIL_PDMA_XY_PKT(0xf202), + PSIL_PDMA_XY_PKT(0xf203), + PSIL_PDMA_XY_PKT(0xf204), + PSIL_PDMA_XY_PKT(0xf205), + PSIL_PDMA_XY_PKT(0xf206), + PSIL_PDMA_XY_PKT(0xf207), + /* MCU_SA2UL */ + PSIL_SA2UL(0xf500, 1), + PSIL_SA2UL(0xf501, 1), +}; + +struct psil_ep_map j784s4_ep_map = { + .name = "j784s4", + .src = j784s4_src_ep_map, + .src_count = ARRAY_SIZE(j784s4_src_ep_map), + .dst = j784s4_dst_ep_map, + .dst_count = ARRAY_SIZE(j784s4_dst_ep_map), +}; diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h index abd650bb7600..c383723d1c8f 100644 --- a/drivers/dma/ti/k3-psil-priv.h +++ b/drivers/dma/ti/k3-psil-priv.h @@ -44,5 +44,6 @@ extern struct psil_ep_map am64_ep_map; extern struct psil_ep_map j721s2_ep_map; extern struct psil_ep_map am62_ep_map; extern struct psil_ep_map am62a_ep_map; +extern struct psil_ep_map j784s4_ep_map; #endif /* K3_PSIL_PRIV_H_ */ diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c index 2da6988a0e7b..c11389d67a3f 100644 --- a/drivers/dma/ti/k3-psil.c +++ b/drivers/dma/ti/k3-psil.c @@ -25,6 +25,7 @@ static const struct soc_device_attribute k3_soc_devices[] = { { .family = "J721S2", .data = &j721s2_ep_map }, { .family = "AM62X", .data = &am62_ep_map }, { .family = "AM62AX", .data = &am62a_ep_map }, + { .family = "J784S4", .data = &j784s4_ep_map }, { /* sentinel */ } }; diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 7e23a6fdef95..b8329a23728d 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -305,6 +305,8 @@ struct udma_chan { /* Channel configuration parameters */ struct udma_chan_config config; + /* Channel configuration parameters (backup) */ + struct udma_chan_config backup_config; /* dmapool for packet mode descriptors */ bool use_dma_pool; @@ -2964,6 +2966,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, struct scatterlist *sgent; struct cppi5_tr_type15_t *tr_req = NULL; enum dma_slave_buswidth dev_width; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; u16 tr_cnt0, tr_cnt1; dma_addr_t dev_addr; struct udma_desc *d; @@ -3034,6 +3037,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, if (uc->ud->match_data->type == DMA_TYPE_UDMA) { asel = 0; + csf |= CPPI5_TR_CSF_EOL_ICNT0; } else { asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; dev_addr |= asel; @@ -3057,7 +3061,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); cppi5_tr_set_trigger(&tr_req[tr_idx].flags, uc->config.tr_trigger_type, CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0); @@ -3103,8 +3107,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); cppi5_tr_set_trigger(&tr_req[tr_idx].flags, uc->config.tr_trigger_type, CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, @@ -3148,8 +3151,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, d->residue += sg_len; } - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); return d; } @@ -3678,6 +3680,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, int num_tr; size_t tr_size = sizeof(struct cppi5_tr_type15_t); u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; if (uc->config.dir != DMA_MEM_TO_MEM) { dev_err(chan->device->dev, @@ -3708,13 +3711,15 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (uc->ud->match_data->type != DMA_TYPE_UDMA) { src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; + } else { + csf |= CPPI5_TR_CSF_EOL_ICNT0; } tr_req = d->hwdesc[0].tr_req_base; cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[0].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[0].flags, csf); tr_req[0].addr = src; tr_req[0].icnt0 = tr0_cnt0; @@ -3733,7 +3738,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (num_tr == 2) { cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[1].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[1].flags, csf); tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0; tr_req[1].icnt0 = tr1_cnt0; @@ -3748,8 +3753,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, tr_req[1].dicnt3 = 1; } - cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); + cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP); if (uc->config.metadata_size) d->vd.tx.metadata_ops = &metadata_ops; @@ -4412,6 +4416,7 @@ static const struct soc_device_attribute k3_soc_devices[] = { { .family = "J721S2", .data = &j721e_soc_data}, { .family = "AM62X", .data = &am64_soc_data }, { .family = "AM62AX", .data = &am64_soc_data }, + { .family = "J784S4", .data = &j721e_soc_data }, { /* sentinel */ } }; @@ -5522,11 +5527,63 @@ static int udma_probe(struct platform_device *pdev) return ret; } +static int __maybe_unused udma_pm_suspend(struct device *dev) +{ + struct udma_dev *ud = dev_get_drvdata(dev); + struct dma_device *dma_dev = &ud->ddev; + struct dma_chan *chan; + struct udma_chan *uc; + + list_for_each_entry(chan, &dma_dev->channels, device_node) { + if (chan->client_count) { + uc = to_udma_chan(chan); + /* backup the channel configuration */ + memcpy(&uc->backup_config, &uc->config, + sizeof(struct udma_chan_config)); + dev_dbg(dev, "Suspending channel %s\n", + dma_chan_name(chan)); + ud->ddev.device_free_chan_resources(chan); + } + } + + return 0; +} + +static int __maybe_unused udma_pm_resume(struct device *dev) +{ + struct udma_dev *ud = dev_get_drvdata(dev); + struct dma_device *dma_dev = &ud->ddev; + struct dma_chan *chan; + struct udma_chan *uc; + int ret; + + list_for_each_entry(chan, &dma_dev->channels, device_node) { + if (chan->client_count) { + uc = to_udma_chan(chan); + /* restore the channel configuration */ + memcpy(&uc->config, &uc->backup_config, + sizeof(struct udma_chan_config)); + dev_dbg(dev, "Resuming channel %s\n", + dma_chan_name(chan)); + ret = ud->ddev.device_alloc_chan_resources(chan); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct dev_pm_ops udma_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume) +}; + static struct platform_driver udma_driver = { .driver = { .name = "ti-udma", .of_match_table = udma_of_match, .suppress_bind_attrs = true, + .pm = &udma_pm_ops, }, .probe = udma_probe, }; diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index ce359058c638..9360f43b8e0f 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -1060,7 +1060,11 @@ static int zynqmp_dma_probe(struct platform_device *pdev) zdev->dev = &pdev->dev; INIT_LIST_HEAD(&zdev->common.channels); - dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44)); + if (ret) { + dev_err(&pdev->dev, "DMA not available for address range\n"); + return ret; + } dma_cap_set(DMA_MEMCPY, zdev->common.cap_mask); p = &zdev->common; diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index ac678b4a21fc..010c26be5846 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -228,8 +228,9 @@ static struct kobj_type ktype_device_ctrl = { */ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) { + struct device *dev_root; struct bus_type *edac_subsys; - int err; + int err = -ENODEV; edac_dbg(1, "\n"); @@ -247,15 +248,16 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) */ edac_dev->owner = THIS_MODULE; - if (!try_module_get(edac_dev->owner)) { - err = -ENODEV; + if (!try_module_get(edac_dev->owner)) goto err_out; - } /* register */ - err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl, - &edac_subsys->dev_root->kobj, - "%s", edac_dev->name); + dev_root = bus_get_dev_root(edac_subsys); + if (dev_root) { + err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl, + &dev_root->kobj, "%s", edac_dev->name); + put_device(dev_root); + } if (err) { edac_dbg(1, "Failed to register '.../edac/%s'\n", edac_dev->name); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 888d5728ecef..287cc51dbc86 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -337,8 +337,9 @@ static struct kobj_type ktype_edac_pci_main_kobj = { */ static int edac_pci_main_kobj_setup(void) { - int err; + int err = -ENODEV; struct bus_type *edac_subsys; + struct device *dev_root; edac_dbg(0, "\n"); @@ -357,7 +358,6 @@ static int edac_pci_main_kobj_setup(void) */ if (!try_module_get(THIS_MODULE)) { edac_dbg(1, "try_module_get() failed\n"); - err = -ENODEV; goto decrement_count_fail; } @@ -369,9 +369,13 @@ static int edac_pci_main_kobj_setup(void) } /* Instanstiate the pci object */ - err = kobject_init_and_add(edac_pci_top_main_kobj, - &ktype_edac_pci_main_kobj, - &edac_subsys->dev_root->kobj, "pci"); + dev_root = bus_get_dev_root(edac_subsys); + if (dev_root) { + err = kobject_init_and_add(edac_pci_top_main_kobj, + &ktype_edac_pci_main_kobj, + &dev_root->kobj, "pci"); + put_device(dev_root); + } if (err) { edac_dbg(1, "Failed to register '.../edac/pci'\n"); goto kobject_init_and_add_fail; diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index e1c71359b605..d43ba8e7260d 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1013,7 +1013,7 @@ ATTRIBUTE_GROUPS(extcon); static int create_extcon_class(void) { if (!extcon_class) { - extcon_class = class_create(THIS_MODULE, "extcon"); + extcon_class = class_create("extcon"); if (IS_ERR(extcon_class)) return PTR_ERR(extcon_class); extcon_class->dev_groups = extcon_groups; diff --git a/drivers/firewire/init_ohci1394_dma.c b/drivers/firewire/init_ohci1394_dma.c index 659256927b42..48b879e9e831 100644 --- a/drivers/firewire/init_ohci1394_dma.c +++ b/drivers/firewire/init_ohci1394_dma.c @@ -251,7 +251,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func) } /** - * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them + * init_ohci1394_dma_on_all_controllers - scan for OHCI1394 controllers and init DMA on them * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them */ void __init init_ohci1394_dma_on_all_controllers(void) @@ -283,7 +283,7 @@ void __init init_ohci1394_dma_on_all_controllers(void) } /** - * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization + * setup_ohci1394_dma - enables early OHCI1394 DMA initialization */ static int __init setup_ohci1394_dma(char *opt) { diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index af22be84034b..538bd677c254 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -706,21 +706,22 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, int rcode; if (destination == IEEE1394_ALL_NODES) { - kfree(r); - - return; - } - - if (offset != dev->handler.offset) + // Although the response to the broadcast packet is not necessarily required, the + // fw_send_response() function should still be called to maintain the reference + // counting of the object. In the case, the call of function just releases the + // object as a result to decrease the reference counting. + rcode = RCODE_COMPLETE; + } else if (offset != dev->handler.offset) { rcode = RCODE_ADDRESS_ERROR; - else if (tcode != TCODE_WRITE_BLOCK_REQUEST) + } else if (tcode != TCODE_WRITE_BLOCK_REQUEST) { rcode = RCODE_TYPE_ERROR; - else if (fwnet_incoming_packet(dev, payload, length, - source, generation, false) != 0) { + } else if (fwnet_incoming_packet(dev, payload, length, + source, generation, false) != 0) { dev_err(&dev->netdev->dev, "incoming packet failure\n"); rcode = RCODE_CONFLICT_ERROR; - } else + } else { rcode = RCODE_COMPLETE; + } fw_send_response(card, r, rcode); } diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index f29d77ecf72d..2b8bfcd010f5 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -15,6 +15,8 @@ #include "common.h" +static DEFINE_IDA(ffa_bus_id); + static int ffa_device_match(struct device *dev, struct device_driver *drv) { const struct ffa_device_id *id_table; @@ -53,7 +55,8 @@ static void ffa_device_remove(struct device *dev) { struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); - ffa_drv->remove(to_ffa_dev(dev)); + if (ffa_drv->remove) + ffa_drv->remove(to_ffa_dev(dev)); } static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env) @@ -130,6 +133,7 @@ static void ffa_release_device(struct device *dev) { struct ffa_device *ffa_dev = to_ffa_dev(dev); + ida_free(&ffa_bus_id, ffa_dev->id); kfree(ffa_dev); } @@ -170,18 +174,24 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, const struct ffa_ops *ops) { - int ret; + int id, ret; struct device *dev; struct ffa_device *ffa_dev; - ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); - if (!ffa_dev) + id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL); + if (id < 0) return NULL; + ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL); + if (!ffa_dev) { + ida_free(&ffa_bus_id, id); + return NULL; + } + dev = &ffa_dev->dev; dev->bus = &ffa_bus_type; dev->release = ffa_release_device; - dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id); + dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); ffa_dev->vm_id = vm_id; ffa_dev->ops = ops; @@ -217,4 +227,5 @@ void arm_ffa_bus_exit(void) { ffa_devices_unregister(); bus_unregister(&ffa_bus_type); + ida_destroy(&ffa_bus_id); } diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index fa85c64d3ded..e23409138667 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -193,7 +193,8 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, int idx, count, flags = 0, sz, buf_sz; ffa_value_t partition_info; - if (!buffer || !num_partitions) /* Just get the count for now */ + if (drv_info->version > FFA_VERSION_1_0 && + (!buffer || !num_partitions)) /* Just get the count for now */ flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY; mutex_lock(&drv_info->rx_lock); @@ -420,12 +421,17 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, ep_mem_access->receiver = args->attrs[idx].receiver; ep_mem_access->attrs = args->attrs[idx].attrs; ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs); + ep_mem_access->flag = 0; + ep_mem_access->reserved = 0; } + mem_region->reserved_0 = 0; + mem_region->reserved_1 = 0; mem_region->ep_count = args->nattrs; composite = buffer + COMPOSITE_OFFSET(args->nattrs); composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); composite->addr_range_cnt = num_entries; + composite->reserved = 0; length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries); frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0); @@ -460,6 +466,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, constituents->address = sg_phys(args->sg); constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE; + constituents->reserved = 0; constituents++; frag_len += sizeof(struct ffa_mem_region_addr_range); } while ((args->sg = sg_next(args->sg))); diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index d40df099fd51..6971dcf72fb9 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -1066,7 +1066,7 @@ static int scmi_xfer_raw_worker_init(struct scmi_raw_mode_info *raw) raw->wait_wq = alloc_workqueue("scmi-raw-wait-wq-%d", WQ_UNBOUND | WQ_FREEZABLE | - WQ_HIGHPRI, WQ_SYSFS, raw->id); + WQ_HIGHPRI | WQ_SYSFS, 0, raw->id); if (!raw->wait_wq) return -ENOMEM; diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c index 5f47dbf4889a..0ea5206be4c9 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c @@ -255,4 +255,3 @@ char *bcm47xx_nvram_get_contents(size_t *nvram_size) } EXPORT_SYMBOL(bcm47xx_nvram_get_contents); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c index ed5aff0a4204..03708ab64e56 100644 --- a/drivers/firmware/dmi-sysfs.c +++ b/drivers/firmware/dmi-sysfs.c @@ -304,7 +304,7 @@ static struct attribute *dmi_sysfs_sel_attrs[] = { }; ATTRIBUTE_GROUPS(dmi_sysfs_sel); -static struct kobj_type dmi_system_event_log_ktype = { +static const struct kobj_type dmi_system_event_log_ktype = { .release = dmi_entry_free, .sysfs_ops = &dmi_sysfs_specialize_attr_ops, .default_groups = dmi_sysfs_sel_groups, @@ -563,7 +563,7 @@ static void dmi_sysfs_entry_release(struct kobject *kobj) kfree(entry); } -static struct kobj_type dmi_sysfs_entry_ktype = { +static const struct kobj_type dmi_sysfs_entry_ktype = { .release = dmi_sysfs_entry_release, .sysfs_ops = &dmi_sysfs_attr_ops, .default_groups = dmi_sysfs_entry_groups, diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 5cc238916551..55dec4eb2c00 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -608,7 +608,7 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type edd_ktype = { +static const struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, }; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 80d85a5169fb..3abb2b357482 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -23,8 +23,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly # disable the stackleak plugin cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ - -fno-unwind-tables -fno-asynchronous-unwind-tables \ - $(call cc-option,-mbranch-protection=none) + -fno-unwind-tables -fno-asynchronous-unwind-tables cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ -DEFI_HAVE_STRCMP -fno-builtin -fpic \ diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot index ccdd6a130d98..2c489627a807 100644 --- a/drivers/firmware/efi/libstub/Makefile.zboot +++ b/drivers/firmware/efi/libstub/Makefile.zboot @@ -1,7 +1,16 @@ # SPDX-License-Identifier: GPL-2.0 # to be include'd by arch/$(ARCH)/boot/Makefile after setting -# EFI_ZBOOT_PAYLOAD, EFI_ZBOOT_BFD_TARGET and EFI_ZBOOT_MACH_TYPE +# EFI_ZBOOT_PAYLOAD, EFI_ZBOOT_BFD_TARGET, EFI_ZBOOT_MACH_TYPE and +# EFI_ZBOOT_FORWARD_CFI + +quiet_cmd_copy_and_pad = PAD $@ + cmd_copy_and_pad = cp $< $@ && \ + truncate -s $(shell hexdump -s16 -n4 -e '"%u"' $<) $@ + +# Pad the file to the size of the uncompressed image in memory, including BSS +$(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE + $(call if_changed,copy_and_pad) comp-type-$(CONFIG_KERNEL_GZIP) := gzip comp-type-$(CONFIG_KERNEL_LZ4) := lz4 @@ -10,26 +19,33 @@ comp-type-$(CONFIG_KERNEL_LZO) := lzo comp-type-$(CONFIG_KERNEL_XZ) := xzkern comp-type-$(CONFIG_KERNEL_ZSTD) := zstd22 -# Copy the SizeOfHeaders, SizeOfCode and SizeOfImage fields from the payload to -# the end of the compressed image. Note that this presupposes a PE header -# offset of 64 bytes, which is what arm64, RISC-V and LoongArch use. -quiet_cmd_compwithsize = $(quiet_cmd_$(comp-type-y)) - cmd_compwithsize = $(cmd_$(comp-type-y)) && ( \ - dd status=none if=$< bs=4 count=1 skip=37 ; \ - dd status=none if=$< bs=4 count=1 skip=23 ; \ - dd status=none if=$< bs=4 count=1 skip=36 ) >> $@ +# in GZIP, the appended le32 carrying the uncompressed size is part of the +# format, but in other cases, we just append it at the end for convenience, +# causing the original tools to complain when checking image integrity. +# So disregard it when calculating the payload size in the zimage header. +zboot-method-y := $(comp-type-y)_with_size +zboot-size-len-y := 4 -$(obj)/vmlinuz: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE - $(call if_changed,compwithsize) +zboot-method-$(CONFIG_KERNEL_GZIP) := gzip +zboot-size-len-$(CONFIG_KERNEL_GZIP) := 0 -OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \ +$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE + $(call if_changed,$(zboot-method-y)) + +# avoid eager evaluation to prevent references to non-existent build artifacts +OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \ --rename-section .data=.gzdata,load,alloc,readonly,contents $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE $(call if_changed,objcopy) +aflags-zboot-header-$(EFI_ZBOOT_FORWARD_CFI) := \ + -DPE_DLL_CHAR_EX=IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT + AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \ -DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \ - -DCOMP_TYPE="\"$(comp-type-y)\"" + -DZBOOT_SIZE_LEN=$(zboot-size-len-y) \ + -DCOMP_TYPE="\"$(comp-type-y)\"" \ + $(aflags-zboot-header-y) $(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE $(call if_changed_rule,as_o_S) @@ -44,4 +60,4 @@ OBJCOPYFLAGS_vmlinuz.efi := -O binary $(obj)/vmlinuz.efi: $(obj)/vmlinuz.efi.elf FORCE $(call if_changed,objcopy) -targets += zboot-header.o vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi +targets += zboot-header.o vmlinux.bin vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c index 8aad8c49d43f..446e35eaf3d9 100644 --- a/drivers/firmware/efi/libstub/arm64.c +++ b/drivers/firmware/efi/libstub/arm64.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -88,9 +89,10 @@ efi_status_t check_platform_features(void) #define DCTYPE "cvau" #endif +u32 __weak code_size; + void efi_cache_sync_image(unsigned long image_base, - unsigned long alloc_size, - unsigned long code_size) + unsigned long alloc_size) { u32 ctr = read_cpuid_effective_cachetype(); u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr, @@ -98,16 +100,21 @@ void efi_cache_sync_image(unsigned long image_base, /* only perform the cache maintenance if needed for I/D coherency */ if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) { + unsigned long base = image_base; + unsigned long size = code_size; + do { - asm("dc " DCTYPE ", %0" :: "r"(image_base)); - image_base += lsize; - code_size -= lsize; - } while (code_size >= lsize); + asm("dc " DCTYPE ", %0" :: "r"(base)); + base += lsize; + size -= lsize; + } while (size >= lsize); } asm("ic ialluis"); dsb(ish); isb(); + + efi_remap_image(image_base, alloc_size, code_size); } unsigned long __weak primary_entry_offset(void) diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 148013bcb5f8..54a2822cae77 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1066,8 +1066,7 @@ struct screen_info *__alloc_screen_info(void); void free_screen_info(struct screen_info *si); void efi_cache_sync_image(unsigned long image_base, - unsigned long alloc_size, - unsigned long code_size); + unsigned long alloc_size); struct efi_smbios_record { u8 type; @@ -1134,4 +1133,7 @@ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record, void efi_remap_image(unsigned long image_base, unsigned alloc_size, unsigned long code_size); +asmlinkage efi_status_t __efiapi +efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab); + #endif diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c index eee7ed43cdfb..72c71ae201f0 100644 --- a/drivers/firmware/efi/libstub/loongarch-stub.c +++ b/drivers/firmware/efi/libstub/loongarch-stub.c @@ -21,27 +21,17 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, efi_loaded_image_t *image, efi_handle_t image_handle) { - int nr_pages = round_up(kernel_asize, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; - efi_physical_addr_t kernel_addr = EFI_KIMG_PREFERRED_ADDRESS; efi_status_t status; + unsigned long kernel_addr = 0; - /* - * Allocate space for the kernel image at the preferred offset. This is - * the only location in memory from where we can execute the image, so - * no point in falling back to another allocation. - */ - status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, - EFI_LOADER_DATA, nr_pages, &kernel_addr); - if (status != EFI_SUCCESS) - return status; + kernel_addr = (unsigned long)&kernel_offset - kernel_offset; - *image_addr = EFI_KIMG_PREFERRED_ADDRESS; + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize, + EFI_KIMG_PREFERRED_ADDRESS, efi_get_kimg_min_align(), 0x0); + + *image_addr = kernel_addr; *image_size = kernel_asize; - memcpy((void *)EFI_KIMG_PREFERRED_ADDRESS, - (void *)&kernel_offset - kernel_offset, - kernel_fsize); - return status; } diff --git a/drivers/firmware/efi/libstub/zboot-header.S b/drivers/firmware/efi/libstub/zboot-header.S index 445cb646eaaa..fb676ded47fa 100644 --- a/drivers/firmware/efi/libstub/zboot-header.S +++ b/drivers/firmware/efi/libstub/zboot-header.S @@ -17,7 +17,7 @@ __efistub_efi_zboot_header: .long MZ_MAGIC .ascii "zimg" // image type .long __efistub__gzdata_start - .Ldoshdr // payload offset - .long __efistub__gzdata_size - 12 // payload size + .long __efistub__gzdata_size - ZBOOT_SIZE_LEN // payload size .long 0, 0 // reserved .asciz COMP_TYPE // compression type .org .Ldoshdr + 0x38 @@ -78,9 +78,36 @@ __efistub_efi_zboot_header: .quad 0 // ExceptionTable .quad 0 // CertificationTable .quad 0 // BaseRelocationTable -#ifdef CONFIG_DEBUG_EFI +#if defined(PE_DLL_CHAR_EX) || defined(CONFIG_DEBUG_EFI) .long .Lefi_debug_table - .Ldoshdr // DebugTable .long .Lefi_debug_table_size + + .section ".rodata", "a" + .p2align 2 +.Lefi_debug_table: + // EFI_IMAGE_DEBUG_DIRECTORY_ENTRY[] +#ifdef PE_DLL_CHAR_EX + .long 0 // Characteristics + .long 0 // TimeDateStamp + .short 0 // MajorVersion + .short 0 // MinorVersion + .long IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS // Type + .long 4 // SizeOfData + .long 0 // RVA + .long .Lefi_dll_characteristics_ex - .Ldoshdr // FileOffset +#endif +#ifdef CONFIG_DEBUG_EFI + .long 0 // Characteristics + .long 0 // TimeDateStamp + .short 0 // MajorVersion + .short 0 // MinorVersion + .long IMAGE_DEBUG_TYPE_CODEVIEW // Type + .long .Lefi_debug_entry_size // SizeOfData + .long 0 // RVA + .long .Lefi_debug_entry - .Ldoshdr // FileOffset +#endif + .set .Lefi_debug_table_size, . - .Lefi_debug_table + .previous #endif .Lsection_table: @@ -110,23 +137,11 @@ __efistub_efi_zboot_header: .set .Lsection_count, (. - .Lsection_table) / 40 +#ifdef PE_DLL_CHAR_EX +.Lefi_dll_characteristics_ex: + .long PE_DLL_CHAR_EX +#endif #ifdef CONFIG_DEBUG_EFI - .section ".rodata", "a" - .align 2 -.Lefi_debug_table: - // EFI_IMAGE_DEBUG_DIRECTORY_ENTRY - .long 0 // Characteristics - .long 0 // TimeDateStamp - .short 0 // MajorVersion - .short 0 // MinorVersion - .long IMAGE_DEBUG_TYPE_CODEVIEW // Type - .long .Lefi_debug_entry_size // SizeOfData - .long 0 // RVA - .long .Lefi_debug_entry - .Ldoshdr // FileOffset - - .set .Lefi_debug_table_size, . - .Lefi_debug_table - .previous - .Lefi_debug_entry: // EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY .ascii "NB10" // Signature diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index 6105e5e2eda4..e5d7fa1f1d8f 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -50,8 +50,7 @@ static unsigned long alloc_preferred_address(unsigned long alloc_size) } void __weak efi_cache_sync_image(unsigned long image_base, - unsigned long alloc_size, - unsigned long code_size) + unsigned long alloc_size) { // Provided by the arch to perform the cache maintenance necessary for // executable code loaded into memory to be safe for execution. @@ -66,7 +65,7 @@ asmlinkage efi_status_t __efiapi efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) { unsigned long compressed_size = _gzdata_end - _gzdata_start; - unsigned long image_base, alloc_size, code_size; + unsigned long image_base, alloc_size; efi_loaded_image_t *image; efi_status_t status; char *cmdline_ptr; @@ -94,10 +93,6 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4), EFI_ALLOC_ALIGN); - // SizeOfHeaders and SizeOfCode from the compressee's PE/COFF header - code_size = get_unaligned_le32(_gzdata_end - 8) + - get_unaligned_le32(_gzdata_end - 12); - // If the architecture has a preferred address for the image, // try that first. image_base = alloc_preferred_address(alloc_size); @@ -140,9 +135,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) goto free_image; } - efi_cache_sync_image(image_base, alloc_size, code_size); - - efi_remap_image(image_base, alloc_size, code_size); + efi_cache_sync_image(image_base, alloc_size); status = efi_stub_common(handle, image, image_base, cmdline_ptr); diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds index 93d33f68333b..ac8c0ef85158 100644 --- a/drivers/firmware/efi/libstub/zboot.lds +++ b/drivers/firmware/efi/libstub/zboot.lds @@ -2,6 +2,8 @@ ENTRY(__efistub_efi_zboot_header); +PROVIDE(zboot_code_size = ABSOLUTE(0)); + SECTIONS { .head : ALIGN(4096) { @@ -17,6 +19,11 @@ SECTIONS *(.gzdata) __efistub__gzdata_end = .; *(.rodata* .init.rodata* .srodata*) + + . = ALIGN(4); + __efistub_code_size = .; + LONG(zboot_code_size); + _etext = ALIGN(4096); . = _etext; } diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 1fba4e09cdcf..a400c4312c82 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -158,7 +158,7 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call) * none of the remaining functions are actually ever called at runtime. * So let's just use a single lock to serialize all Runtime Services calls. */ -static DEFINE_SEMAPHORE(efi_runtime_lock); +static DEFINE_SEMAPHORE(efi_runtime_lock, 1); /* * Expose the EFI runtime lock to the UV platform diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index bd75b87f5fc1..bfc5fa6aa47b 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -21,7 +21,7 @@ /* Private pointer to registered efivars */ static struct efivars *__efivars; -static DEFINE_SEMAPHORE(efivars_lock); +static DEFINE_SEMAPHORE(efivars_lock, 1); static efi_status_t check_var_size(bool nonblocking, u32 attributes, unsigned long size) diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index bde1f543f529..80f4e2d14e04 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -1133,8 +1133,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) return ret; genpool = svc_create_memory_pool(pdev, sh_memory); - if (!genpool) - return -ENOMEM; + if (IS_ERR(genpool)) + return PTR_ERR(genpool); /* allocate service controller and supporting channel */ controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL); diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c index 82c64cb9f531..74363ed7501f 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -51,7 +51,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si, * * It's not easily possible to fix this in struct screen_info, * as this could break UAPI. The best solution is to compute - * bits_per_pixel here and ignore lfb_depth. In the loop below, + * bits_per_pixel from the color bits, reserved bits and + * reported lfb_depth, whichever is highest. In the loop below, * ignore simplefb formats with alpha bits, as EFI and VESA * don't specify alpha channels. */ @@ -60,6 +61,7 @@ __init bool sysfb_parse_mode(const struct screen_info *si, si->green_size + si->green_pos, si->blue_size + si->blue_pos), si->rsvd_size + si->rsvd_pos); + bits_per_pixel = max_t(u32, bits_per_pixel, si->lfb_depth); } else { bits_per_pixel = si->lfb_depth; } diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index ce86a1850305..a736db4a5825 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -971,6 +971,39 @@ int zynqmp_pm_fpga_get_status(u32 *value) } EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status); +/** + * zynqmp_pm_fpga_get_config_status - Get the FPGA configuration status. + * @value: Buffer to store FPGA configuration status. + * + * This function provides access to the pmufw to get the FPGA configuration + * status + * + * Return: 0 on success, a negative value on error + */ +int zynqmp_pm_fpga_get_config_status(u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 buf, lower_addr, upper_addr; + int ret; + + if (!value) + return -EINVAL; + + lower_addr = lower_32_bits((u64)&buf); + upper_addr = upper_32_bits((u64)&buf); + + ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, + XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, + lower_addr, upper_addr, + XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG, + ret_payload); + + *value = ret_payload[1]; + + return ret; +} +EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_config_status); + /** * zynqmp_pm_pinctrl_request - Request Pin from firmware * @pin: Pin number to request diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 0953e6e4db04..a6c25dee9cc1 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -115,7 +115,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data) /** * fpga_bridge_get - get an exclusive reference to an fpga bridge * @dev: parent device that fpga bridge was registered with - * @info: fpga manager info + * @info: fpga image specific information * * Given a device, get an exclusive reference to an fpga bridge. * @@ -417,7 +417,7 @@ static void fpga_bridge_dev_release(struct device *dev) static int __init fpga_bridge_dev_init(void) { - fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge"); + fpga_bridge_class = class_create("fpga_bridge"); if (IS_ERR(fpga_bridge_class)) return PTR_ERR(fpga_bridge_class); diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 8efa67620e21..eb583f86a0b9 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -971,7 +971,7 @@ static int __init fpga_mgr_class_init(void) { pr_info("FPGA manager framework\n"); - fpga_mgr_class = class_create(THIS_MODULE, "fpga_manager"); + fpga_mgr_class = class_create("fpga_manager"); if (IS_ERR(fpga_mgr_class)) return PTR_ERR(fpga_mgr_class); diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index 27ff9dea04ae..ccf6fdab1360 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -293,7 +293,7 @@ static void fpga_region_dev_release(struct device *dev) */ static int __init fpga_region_init(void) { - fpga_region_class = class_create(THIS_MODULE, "fpga_region"); + fpga_region_class = class_create("fpga_region"); if (IS_ERR(fpga_region_class)) return PTR_ERR(fpga_region_class); diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c index c60f20949c47..f3434e2c487b 100644 --- a/drivers/fpga/zynqmp-fpga.c +++ b/drivers/fpga/zynqmp-fpga.c @@ -77,6 +77,26 @@ static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr) return FPGA_MGR_STATE_UNKNOWN; } +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 status; + int ret; + + ret = zynqmp_pm_fpga_get_config_status(&status); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%x\n", status); +} +static DEVICE_ATTR_RO(status); + +static struct attribute *zynqmp_fpga_attrs[] = { + &dev_attr_status.attr, + NULL, +}; +ATTRIBUTE_GROUPS(zynqmp_fpga); + static const struct fpga_manager_ops zynqmp_fpga_ops = { .state = zynqmp_fpga_ops_state, .write_init = zynqmp_fpga_ops_write_init, @@ -113,6 +133,7 @@ static struct platform_driver zynqmp_fpga_driver = { .driver = { .name = "zynqmp_fpga_manager", .of_match_table = of_match_ptr(zynqmp_fpga_of_match), + .dev_groups = zynqmp_fpga_groups, }, }; diff --git a/drivers/gnss/core.c b/drivers/gnss/core.c index 77a4b280c552..48f2ee0f78c4 100644 --- a/drivers/gnss/core.c +++ b/drivers/gnss/core.c @@ -387,7 +387,7 @@ static int __init gnss_module_init(void) return ret; } - gnss_class = class_create(THIS_MODULE, "gnss"); + gnss_class = class_create("gnss"); if (IS_ERR(gnss_class)) { ret = PTR_ERR(gnss_class); pr_err("failed to create class: %d\n", ret); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b81393072715..f45c6a36551c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -897,7 +897,7 @@ config GPIO_F7188X help This option enables support for GPIOs found on Fintek Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866. - As well as Nuvoton Super-I/O chip NCT6116D. + As well as Nuvoton Super-I/O chip NCT6126D. To compile this driver as a module, choose M here: the module will be called f7188x-gpio. @@ -1292,6 +1292,18 @@ config GPIO_KEMPLD This driver can also be built as a module. If so, the module will be called gpio-kempld. +config GPIO_LJCA + tristate "INTEL La Jolla Cove Adapter GPIO support" + depends on MFD_LJCA + select GPIOLIB_IRQCHIP + default MFD_LJCA + help + Select this option to enable GPIO driver for the INTEL + La Jolla Cove Adapter (LJCA) board. + + This driver can also be built as a module. If so, the module + will be called gpio-ljca. + config GPIO_LP3943 tristate "TI/National Semiconductor LP3943 GPIO expander" depends on MFD_LP3943 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 8309b4ff128b..20036af3acb1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o +obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 9effa7769bef..f54ca5a1775e 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -48,7 +48,7 @@ /* * Nuvoton devices. */ -#define SIO_NCT6116D_ID 0xD283 /* NCT6116D chipset ID */ +#define SIO_NCT6126D_ID 0xD283 /* NCT6126D chipset ID */ #define SIO_LD_GPIO_NUVOTON 0x07 /* GPIO logical device */ @@ -62,7 +62,7 @@ enum chips { f81866, f81804, f81865, - nct6116d, + nct6126d, }; static const char * const f7188x_names[] = { @@ -74,7 +74,7 @@ static const char * const f7188x_names[] = { "f81866", "f81804", "f81865", - "nct6116d", + "nct6126d", }; struct f7188x_sio { @@ -187,8 +187,8 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset, /* Output mode register (0:open drain 1:push-pull). */ #define f7188x_gpio_out_mode(base) ((base) + 3) -#define f7188x_gpio_dir_invert(type) ((type) == nct6116d) -#define f7188x_gpio_data_single(type) ((type) == nct6116d) +#define f7188x_gpio_dir_invert(type) ((type) == nct6126d) +#define f7188x_gpio_data_single(type) ((type) == nct6126d) static struct f7188x_gpio_bank f71869_gpio_bank[] = { F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"), @@ -274,7 +274,7 @@ static struct f7188x_gpio_bank f81865_gpio_bank[] = { F7188X_GPIO_BANK(60, 5, 0x90, DRVNAME "-6"), }; -static struct f7188x_gpio_bank nct6116d_gpio_bank[] = { +static struct f7188x_gpio_bank nct6126d_gpio_bank[] = { F7188X_GPIO_BANK(0, 8, 0xE0, DRVNAME "-0"), F7188X_GPIO_BANK(10, 8, 0xE4, DRVNAME "-1"), F7188X_GPIO_BANK(20, 8, 0xE8, DRVNAME "-2"), @@ -282,7 +282,7 @@ static struct f7188x_gpio_bank nct6116d_gpio_bank[] = { F7188X_GPIO_BANK(40, 8, 0xF0, DRVNAME "-4"), F7188X_GPIO_BANK(50, 8, 0xF4, DRVNAME "-5"), F7188X_GPIO_BANK(60, 8, 0xF8, DRVNAME "-6"), - F7188X_GPIO_BANK(70, 1, 0xFC, DRVNAME "-7"), + F7188X_GPIO_BANK(70, 8, 0xFC, DRVNAME "-7"), }; static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -490,9 +490,9 @@ static int f7188x_gpio_probe(struct platform_device *pdev) data->nr_bank = ARRAY_SIZE(f81865_gpio_bank); data->bank = f81865_gpio_bank; break; - case nct6116d: - data->nr_bank = ARRAY_SIZE(nct6116d_gpio_bank); - data->bank = nct6116d_gpio_bank; + case nct6126d: + data->nr_bank = ARRAY_SIZE(nct6126d_gpio_bank); + data->bank = nct6126d_gpio_bank; break; default: return -ENODEV; @@ -559,9 +559,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F81865_ID: sio->type = f81865; break; - case SIO_NCT6116D_ID: + case SIO_NCT6126D_ID: sio->device = SIO_LD_GPIO_NUVOTON; - sio->type = nct6116d; + sio->type = nct6126d; break; default: pr_info("Unsupported Fintek device 0x%04x\n", devid); @@ -569,7 +569,7 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) } /* double check manufacturer where possible */ - if (sio->type != nct6116d) { + if (sio->type != nct6126d) { manid = superio_inw(addr, SIO_FINTEK_MANID); if (manid != SIO_FINTEK_ID) { pr_debug("Not a Fintek device at 0x%08x\n", addr); @@ -581,7 +581,7 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) err = 0; pr_info("Found %s at %#x\n", f7188x_names[sio->type], (unsigned int)addr); - if (sio->type != nct6116d) + if (sio->type != nct6126d) pr_info(" revision %d\n", superio_inb(addr, SIO_FINTEK_DEVREV)); err: diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c new file mode 100644 index 000000000000..87863f0230f5 --- /dev/null +++ b/drivers/gpio/gpio-ljca.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel La Jolla Cove Adapter USB-GPIO driver + * + * Copyright (c) 2023, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* GPIO commands */ +#define LJCA_GPIO_CONFIG 1 +#define LJCA_GPIO_READ 2 +#define LJCA_GPIO_WRITE 3 +#define LJCA_GPIO_INT_EVENT 4 +#define LJCA_GPIO_INT_MASK 5 +#define LJCA_GPIO_INT_UNMASK 6 + +#define LJCA_GPIO_CONF_DISABLE BIT(0) +#define LJCA_GPIO_CONF_INPUT BIT(1) +#define LJCA_GPIO_CONF_OUTPUT BIT(2) +#define LJCA_GPIO_CONF_PULLUP BIT(3) +#define LJCA_GPIO_CONF_PULLDOWN BIT(4) +#define LJCA_GPIO_CONF_DEFAULT BIT(5) +#define LJCA_GPIO_CONF_INTERRUPT BIT(6) +#define LJCA_GPIO_INT_TYPE BIT(7) + +#define LJCA_GPIO_CONF_EDGE FIELD_PREP(LJCA_GPIO_INT_TYPE, 1) +#define LJCA_GPIO_CONF_LEVEL FIELD_PREP(LJCA_GPIO_INT_TYPE, 0) + +/* Intentional overlap with PULLUP / PULLDOWN */ +#define LJCA_GPIO_CONF_SET BIT(3) +#define LJCA_GPIO_CONF_CLR BIT(4) + +struct gpio_op { + u8 index; + u8 value; +} __packed; + +struct gpio_packet { + u8 num; + struct gpio_op item[]; +} __packed; + +#define LJCA_GPIO_BUF_SIZE 60 +struct ljca_gpio_dev { + struct platform_device *pdev; + struct gpio_chip gc; + struct ljca_gpio_info *gpio_info; + DECLARE_BITMAP(unmasked_irqs, LJCA_MAX_GPIO_NUM); + DECLARE_BITMAP(enabled_irqs, LJCA_MAX_GPIO_NUM); + DECLARE_BITMAP(reenable_irqs, LJCA_MAX_GPIO_NUM); + u8 *connect_mode; + /* mutex to protect irq bus */ + struct mutex irq_lock; + struct work_struct work; + /* lock to protect package transfer to Hardware */ + struct mutex trans_lock; + + u8 obuf[LJCA_GPIO_BUF_SIZE]; + u8 ibuf[LJCA_GPIO_BUF_SIZE]; +}; + +static int gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, u8 config) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->item[0].index = gpio_id; + packet->item[0].value = config | ljca_gpio->connect_mode[gpio_id]; + packet->num = 1; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_CONFIG, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static int ljca_gpio_read(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + struct gpio_packet *ack_packet = (struct gpio_packet *)ljca_gpio->ibuf; + unsigned int ibuf_len = LJCA_GPIO_BUF_SIZE; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_READ, packet, + struct_size(packet, item, packet->num), ljca_gpio->ibuf, &ibuf_len); + if (ret) + goto out_unlock; + + if (!ibuf_len || ack_packet->num != packet->num) { + dev_err(&ljca_gpio->pdev->dev, "failed gpio_id:%u %u", gpio_id, ack_packet->num); + ret = -EIO; + } + +out_unlock: + mutex_unlock(&ljca_gpio->trans_lock); + if (ret) + return ret; + return ack_packet->item[0].value > 0; +} + +static int ljca_gpio_write(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, + int value) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + packet->item[0].value = value & 1; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, LJCA_GPIO_WRITE, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static int ljca_gpio_get_value(struct gpio_chip *chip, unsigned int offset) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + return ljca_gpio_read(ljca_gpio, offset); +} + +static void ljca_gpio_set_value(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + int ret; + + ret = ljca_gpio_write(ljca_gpio, offset, val); + if (ret) + dev_err(chip->parent, "offset:%u val:%d set value failed %d\n", offset, val, ret); +} + +static int ljca_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + u8 config = LJCA_GPIO_CONF_INPUT | LJCA_GPIO_CONF_CLR; + + return gpio_config(ljca_gpio, offset, config); +} + +static int ljca_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int val) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + u8 config = LJCA_GPIO_CONF_OUTPUT | LJCA_GPIO_CONF_CLR; + int ret; + + ret = gpio_config(ljca_gpio, offset, config); + if (ret) + return ret; + + ljca_gpio_set_value(chip, offset, val); + return 0; +} + +static int ljca_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + ljca_gpio->connect_mode[offset] = 0; + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_UP: + ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLUP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ljca_gpio->connect_mode[offset] |= LJCA_GPIO_CONF_PULLDOWN; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_PERSIST_STATE: + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int ljca_gpio_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, + unsigned int ngpios) +{ + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(chip); + + WARN_ON_ONCE(ngpios != ljca_gpio->gpio_info->num); + bitmap_copy(valid_mask, ljca_gpio->gpio_info->valid_pin_map, ngpios); + + return 0; +} + +static void ljca_gpio_irq_init_valid_mask(struct gpio_chip *chip, unsigned long *valid_mask, + unsigned int ngpios) +{ + ljca_gpio_init_valid_mask(chip, valid_mask, ngpios); +} + +static int ljca_enable_irq(struct ljca_gpio_dev *ljca_gpio, int gpio_id, bool enable) +{ + struct gpio_packet *packet = (struct gpio_packet *)ljca_gpio->obuf; + int ret; + + mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; + packet->item[0].index = gpio_id; + packet->item[0].value = 0; + + ret = ljca_transfer(ljca_gpio->gpio_info->ljca, + enable ? LJCA_GPIO_INT_UNMASK : LJCA_GPIO_INT_MASK, packet, + struct_size(packet, item, packet->num), NULL, NULL); + mutex_unlock(&ljca_gpio->trans_lock); + return ret; +} + +static void ljca_gpio_async(struct work_struct *work) +{ + struct ljca_gpio_dev *ljca_gpio = container_of(work, struct ljca_gpio_dev, work); + int gpio_id; + int unmasked; + + for_each_set_bit(gpio_id, ljca_gpio->reenable_irqs, ljca_gpio->gc.ngpio) { + clear_bit(gpio_id, ljca_gpio->reenable_irqs); + unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); + if (unmasked) + ljca_enable_irq(ljca_gpio, gpio_id, true); + } +} + +static void ljca_gpio_event_cb(void *context, u8 cmd, const void *evt_data, int len) +{ + const struct gpio_packet *packet = evt_data; + struct ljca_gpio_dev *ljca_gpio = context; + int i; + int irq; + + if (cmd != LJCA_GPIO_INT_EVENT) + return; + + for (i = 0; i < packet->num; i++) { + irq = irq_find_mapping(ljca_gpio->gc.irq.domain, packet->item[i].index); + if (!irq) { + dev_err(ljca_gpio->gc.parent, "gpio_id %u does not mapped to IRQ yet\n", + packet->item[i].index); + return; + } + + generic_handle_domain_irq(ljca_gpio->gc.irq.domain, irq); + set_bit(packet->item[i].index, ljca_gpio->reenable_irqs); + } + + schedule_work(&ljca_gpio->work); +} + +static void ljca_irq_unmask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + gpiochip_enable_irq(gc, gpio_id); + set_bit(gpio_id, ljca_gpio->unmasked_irqs); +} + +static void ljca_irq_mask(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + clear_bit(gpio_id, ljca_gpio->unmasked_irqs); + gpiochip_disable_irq(gc, gpio_id); +} + +static int ljca_irq_set_type(struct irq_data *irqd, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + + ljca_gpio->connect_mode[gpio_id] = LJCA_GPIO_CONF_INTERRUPT; + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLUP); + break; + case IRQ_TYPE_LEVEL_LOW: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_LEVEL | LJCA_GPIO_CONF_PULLDOWN); + break; + case IRQ_TYPE_EDGE_BOTH: + break; + case IRQ_TYPE_EDGE_RISING: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLUP); + break; + case IRQ_TYPE_EDGE_FALLING: + ljca_gpio->connect_mode[gpio_id] |= (LJCA_GPIO_CONF_EDGE | LJCA_GPIO_CONF_PULLDOWN); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ljca_irq_bus_lock(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + + mutex_lock(&ljca_gpio->irq_lock); +} + +static void ljca_irq_bus_unlock(struct irq_data *irqd) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); + struct ljca_gpio_dev *ljca_gpio = gpiochip_get_data(gc); + int gpio_id = irqd_to_hwirq(irqd); + int enabled; + int unmasked; + + enabled = test_bit(gpio_id, ljca_gpio->enabled_irqs); + unmasked = test_bit(gpio_id, ljca_gpio->unmasked_irqs); + + if (enabled != unmasked) { + if (unmasked) { + gpio_config(ljca_gpio, gpio_id, 0); + ljca_enable_irq(ljca_gpio, gpio_id, true); + set_bit(gpio_id, ljca_gpio->enabled_irqs); + } else { + ljca_enable_irq(ljca_gpio, gpio_id, false); + clear_bit(gpio_id, ljca_gpio->enabled_irqs); + } + } + + mutex_unlock(&ljca_gpio->irq_lock); +} + +static const struct irq_chip ljca_gpio_irqchip = { + .name = "ljca-irq", + .irq_mask = ljca_irq_mask, + .irq_unmask = ljca_irq_unmask, + .irq_set_type = ljca_irq_set_type, + .irq_bus_lock = ljca_irq_bus_lock, + .irq_bus_sync_unlock = ljca_irq_bus_unlock, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int ljca_gpio_probe(struct platform_device *pdev) +{ + struct ljca_gpio_dev *ljca_gpio; + struct gpio_irq_chip *girq; + int ret; + + ljca_gpio = devm_kzalloc(&pdev->dev, sizeof(*ljca_gpio), GFP_KERNEL); + if (!ljca_gpio) + return -ENOMEM; + + ljca_gpio->gpio_info = dev_get_platdata(&pdev->dev); + ljca_gpio->connect_mode = devm_kcalloc(&pdev->dev, ljca_gpio->gpio_info->num, + sizeof(*ljca_gpio->connect_mode), GFP_KERNEL); + if (!ljca_gpio->connect_mode) + return -ENOMEM; + + mutex_init(&ljca_gpio->irq_lock); + mutex_init(&ljca_gpio->trans_lock); + ljca_gpio->pdev = pdev; + ljca_gpio->gc.direction_input = ljca_gpio_direction_input; + ljca_gpio->gc.direction_output = ljca_gpio_direction_output; + ljca_gpio->gc.get = ljca_gpio_get_value; + ljca_gpio->gc.set = ljca_gpio_set_value; + ljca_gpio->gc.set_config = ljca_gpio_set_config; + ljca_gpio->gc.init_valid_mask = ljca_gpio_init_valid_mask; + ljca_gpio->gc.can_sleep = true; + ljca_gpio->gc.parent = &pdev->dev; + + ljca_gpio->gc.base = -1; + ljca_gpio->gc.ngpio = ljca_gpio->gpio_info->num; + ljca_gpio->gc.label = ACPI_COMPANION(&pdev->dev) ? + acpi_dev_name(ACPI_COMPANION(&pdev->dev)) : + dev_name(&pdev->dev); + ljca_gpio->gc.owner = THIS_MODULE; + + platform_set_drvdata(pdev, ljca_gpio); + ljca_register_event_cb(ljca_gpio->gpio_info->ljca, ljca_gpio_event_cb, ljca_gpio); + + girq = &ljca_gpio->gc.irq; + gpio_irq_chip_set_chip(girq, &ljca_gpio_irqchip); + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->init_valid_mask = ljca_gpio_irq_init_valid_mask; + + INIT_WORK(&ljca_gpio->work, ljca_gpio_async); + ret = gpiochip_add_data(&ljca_gpio->gc, ljca_gpio); + if (ret) { + ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); + mutex_destroy(&ljca_gpio->irq_lock); + mutex_destroy(&ljca_gpio->trans_lock); + } + + return ret; +} + +static int ljca_gpio_remove(struct platform_device *pdev) +{ + struct ljca_gpio_dev *ljca_gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&ljca_gpio->gc); + ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca); + mutex_destroy(&ljca_gpio->irq_lock); + mutex_destroy(&ljca_gpio->trans_lock); + return 0; +} + +#define LJCA_GPIO_DRV_NAME "ljca-gpio" +static const struct platform_device_id ljca_gpio_id[] = { + { LJCA_GPIO_DRV_NAME, 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, ljca_gpio_id); + +static struct platform_driver ljca_gpio_driver = { + .driver.name = LJCA_GPIO_DRV_NAME, + .probe = ljca_gpio_probe, + .remove = ljca_gpio_remove, +}; +module_platform_driver(ljca_gpio_driver); + +MODULE_AUTHOR("Ye Xiang "); +MODULE_AUTHOR("Wang Zhifeng "); +MODULE_AUTHOR("Zhang Lixu "); +MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-GPIO driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(LJCA); diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index e6a7049bef64..b32063ac845a 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -369,7 +369,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev, priv->offset = i; priv->desc = gpiochip_get_desc(gc, i); - debugfs_create_file(name, 0200, chip->dbg_dir, priv, + debugfs_create_file(name, 0600, chip->dbg_dir, priv, &gpio_mockup_debugfs_ops); } } diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 14c872b6ad05..b904de0b1784 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -1134,6 +1134,7 @@ static const struct tegra_gpio_soc tegra234_aon_soc = { .name = "tegra234-gpio-aon", .instance = 1, .num_irqs_per_bank = 8, + .has_gte = true, }; #define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index c1cbf71329f0..530dfd19d7b5 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -437,8 +437,8 @@ ATTRIBUTE_GROUPS(gpiochip); * /sys/class/gpio/unexport ... write-only * integer N ... number of GPIO to unexport */ -static ssize_t export_store(struct class *class, - struct class_attribute *attr, +static ssize_t export_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t len) { long gpio; @@ -489,8 +489,8 @@ done: } static CLASS_ATTR_WO(export); -static ssize_t unexport_store(struct class *class, - struct class_attribute *attr, +static ssize_t unexport_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t len) { long gpio; @@ -534,8 +534,6 @@ ATTRIBUTE_GROUPS(gpio_class); static struct class gpio_class = { .name = "gpio", - .owner = THIS_MODULE, - .class_groups = gpio_class_groups, }; @@ -567,7 +565,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) int offset; /* can't export until sysfs is available ... */ - if (!gpio_class.p) { + if (!class_is_registered(&gpio_class)) { pr_debug("%s: called too early!\n", __func__); return -ENOENT; } @@ -741,7 +739,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) * register later, in gpiolib_sysfs_init() ... here we just * verify that _some_ field of gpio_class got initialized. */ - if (!gpio_class.p) + if (!class_is_registered(&gpio_class)) return 0; /* diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 04fb05df805b..a7220e04a93e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -209,6 +209,8 @@ static int gpiochip_find_base(int ngpio) break; /* nope, check the space right after the chip */ base = gdev->base + gdev->ngpio; + if (base < GPIO_DYNAMIC_BASE) + base = GPIO_DYNAMIC_BASE; } if (gpio_is_valid(base)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 08eced097bd8..2eb2c66843a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1276,7 +1276,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, r = drm_sched_job_add_dependency(&leader->base, fence); if (r) { dma_fence_put(fence); - goto error_cleanup; + return r; } } @@ -1303,7 +1303,8 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } if (r) { r = -EAGAIN; - goto error_unlock; + mutex_unlock(&p->adev->notifier_lock); + return r; } p->fence = dma_fence_get(&leader->base.s_fence->finished); @@ -1350,14 +1351,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, mutex_unlock(&p->adev->notifier_lock); mutex_unlock(&p->bo_list->bo_list_mutex); return 0; - -error_unlock: - mutex_unlock(&p->adev->notifier_lock); - -error_cleanup: - for (i = 0; i < p->gang_size; ++i) - drm_sched_job_cleanup(&p->jobs[i]->base); - return r; } /* Cleanup the parser structure */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a2292acf06d0..5c7d40873ee2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2539,8 +2539,6 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) amdgpu_fru_get_product_info(adev); init_failed: - if (amdgpu_sriov_vf(adev)) - amdgpu_virt_release_full_gpu(adev, true); return r; } @@ -3580,6 +3578,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, int r, i; bool px = false; u32 max_MBps; + int tmp; adev->shutdown = false; adev->flags = flags; @@ -3758,6 +3757,12 @@ int amdgpu_device_init(struct amdgpu_device *adev, adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *) adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags == (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64); + /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a + * internal path natively support atomics, set have_atomics_support to true. + */ + else if ((adev->flags & AMD_IS_APU) && + (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0))) + adev->have_atomics_support = true; else adev->have_atomics_support = !pci_enable_atomic_ops_to_root(adev->pdev, @@ -3801,7 +3806,13 @@ int amdgpu_device_init(struct amdgpu_device *adev, } } } else { + tmp = amdgpu_reset_method; + /* It should do a default reset when loading or reloading the driver, + * regardless of the module parameter reset_method. + */ + amdgpu_reset_method = AMD_RESET_METHOD_NONE; r = amdgpu_asic_reset(adev); + amdgpu_reset_method = tmp; if (r) { dev_err(adev->dev, "asic reset on init failed\n"); goto failed; @@ -3859,18 +3870,6 @@ fence_driver_init: r = amdgpu_device_ip_init(adev); if (r) { - /* failed in exclusive mode due to timeout */ - if (amdgpu_sriov_vf(adev) && - !amdgpu_sriov_runtime(adev) && - amdgpu_virt_mmio_blocked(adev) && - !amdgpu_virt_wait_reset(adev)) { - dev_err(adev->dev, "VF exclusive mode timeout\n"); - /* Don't send request since VF is inactive. */ - adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; - adev->virt.ops = NULL; - r = -EAGAIN; - goto release_ras_con; - } dev_err(adev->dev, "amdgpu_device_ip_init failed\n"); amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0); goto release_ras_con; @@ -3939,8 +3938,10 @@ fence_driver_init: msecs_to_jiffies(AMDGPU_RESUME_MS)); } - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_release_full_gpu(adev, true); flush_delayed_work(&adev->delayed_init_work); + } r = sysfs_create_files(&adev->dev->kobj, amdgpu_dev_attributes); if (r) @@ -3980,6 +3981,20 @@ fence_driver_init: return 0; release_ras_con: + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_release_full_gpu(adev, true); + + /* failed in exclusive mode due to timeout */ + if (amdgpu_sriov_vf(adev) && + !amdgpu_sriov_runtime(adev) && + amdgpu_virt_mmio_blocked(adev) && + !amdgpu_virt_wait_reset(adev)) { + dev_err(adev->dev, "VF exclusive mode timeout\n"); + /* Don't send request since VF is inactive. */ + adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; + adev->virt.ops = NULL; + r = -EAGAIN; + } amdgpu_release_ras_context(adev); failed: @@ -4497,7 +4512,11 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) dev_info(adev->dev, "recover vram bo from shadow start\n"); mutex_lock(&adev->shadow_list_lock); list_for_each_entry(vmbo, &adev->shadow_list, shadow_list) { - shadow = &vmbo->bo; + /* If vm is compute context or adev is APU, shadow will be NULL */ + if (!vmbo->shadow) + continue; + shadow = vmbo->shadow; + /* No need to recover an evicted BO */ if (shadow->tbo.resource->mem_type != TTM_PL_TT || shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET || diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index f52d0ba91a77..a7d250809da9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -582,7 +582,8 @@ void amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev) if (r) amdgpu_fence_driver_force_completion(ring); - if (ring->fence_drv.irq_src) + if (!drm_dev_is_unplugged(adev_to_drm(adev)) && + ring->fence_drv.irq_src) amdgpu_irq_put(adev, ring->fence_drv.irq_src, ring->fence_drv.irq_type); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 9d3a0542c996..f3f541ba0aca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -687,9 +687,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r if (r) return r; - r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); - if (r) - goto late_fini; + if (adev->gfx.cp_ecc_error_irq.funcs) { + r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (r) + goto late_fini; + } } else { amdgpu_ras_feature_enable_on_boot(adev, ras_block, 0); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 4e2531758866..95b0f984acbf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -593,6 +593,8 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) case IP_VERSION(9, 3, 0): /* GC 10.3.7 */ case IP_VERSION(10, 3, 7): + /* GC 11.0.1 */ + case IP_VERSION(11, 0, 1): if (amdgpu_tmz == 0) { adev->gmc.tmz_enabled = false; dev_info(adev->dev, @@ -616,7 +618,6 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) case IP_VERSION(10, 3, 1): /* YELLOW_CARP*/ case IP_VERSION(10, 3, 3): - case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 4): /* Don't enable it by default yet. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c index b07c000fc8ba..4fa019c8aefc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -241,6 +241,31 @@ int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev, return 0; } +int amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r, i; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + r = amdgpu_irq_get(adev, &adev->jpeg.inst[i].ras_poison_irq, 0); + if (r) + goto late_fini; + } + } + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + return r; +} + int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev) { int err; @@ -262,7 +287,7 @@ int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev) adev->jpeg.ras_if = &ras->ras_block.ras_comm; if (!ras->ras_block.ras_late_init) - ras->ras_block.ras_late_init = amdgpu_ras_block_late_init; + ras->ras_block.ras_late_init = amdgpu_jpeg_ras_late_init; return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h index 0ca76f0f23e9..1471a1ebb034 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h @@ -38,6 +38,7 @@ struct amdgpu_jpeg_reg{ struct amdgpu_jpeg_inst { struct amdgpu_ring ring_dec; struct amdgpu_irq_src irq; + struct amdgpu_irq_src ras_poison_irq; struct amdgpu_jpeg_reg external; }; @@ -72,6 +73,8 @@ int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); +int amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev, + struct ras_common_if *ras_block); int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev); #endif /*__AMDGPU_JPEG_H__*/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index e9b45089a28a..863b2a34b2d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -38,6 +38,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, { struct fd f = fdget(fd); struct amdgpu_fpriv *fpriv; + struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; uint32_t id; int r; @@ -51,8 +52,11 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, return r; } - idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) + mgr = &fpriv->ctx_mgr; + mutex_lock(&mgr->lock); + idr_for_each_entry(&mgr->ctx_handles, ctx, id) amdgpu_ctx_priority_override(ctx, priority); + mutex_unlock(&mgr->lock); fdput(f); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index e63fcc58e8e0..2d94f1b63bd6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -1181,6 +1181,31 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, return 0; } +int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) +{ + int r, i; + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) + return r; + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { + if (adev->vcn.harvest_config & (1 << i)) + continue; + + r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0); + if (r) + goto late_fini; + } + } + return 0; + +late_fini: + amdgpu_ras_block_late_fini(adev, ras_block); + return r; +} + int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev) { int err; @@ -1202,7 +1227,7 @@ int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev) adev->vcn.ras_if = &ras->ras_block.ras_comm; if (!ras->ras_block.ras_late_init) - ras->ras_block.ras_late_init = amdgpu_ras_block_late_init; + ras->ras_block.ras_late_init = amdgpu_vcn_ras_late_init; return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index c730949ece7d..f1397ef66fd7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -234,6 +234,7 @@ struct amdgpu_vcn_inst { struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS]; atomic_t sched_score; struct amdgpu_irq_src irq; + struct amdgpu_irq_src ras_poison_irq; struct amdgpu_vcn_reg external; struct amdgpu_bo *dpg_sram_bo; struct dpg_pause_state pause_state; @@ -400,6 +401,8 @@ void amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev, int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); +int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, + struct ras_common_if *ras_block); int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index f5b5ce1051a2..ab44c1391d52 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -6892,8 +6892,10 @@ static int gfx_v10_0_kiq_resume(struct amdgpu_device *adev) return r; r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr); - if (unlikely(r != 0)) + if (unlikely(r != 0)) { + amdgpu_bo_unreserve(ring->mqd_obj); return r; + } gfx_v10_0_kiq_init_queue(ring); amdgpu_bo_kunmap(ring->mqd_obj); @@ -8152,8 +8154,14 @@ static int gfx_v10_0_set_powergating_state(void *handle, case IP_VERSION(10, 3, 3): case IP_VERSION(10, 3, 6): case IP_VERSION(10, 3, 7): + if (!enable) + amdgpu_gfx_off_ctrl(adev, false); + gfx_v10_cntl_pg(adev, enable); - amdgpu_gfx_off_ctrl(adev, enable); + + if (enable) + amdgpu_gfx_off_ctrl(adev, true); + break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index a9da0486467a..c4940b6ea1c4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -1315,13 +1315,6 @@ static int gfx_v11_0_sw_init(void *handle) if (r) return r; - /* ECC error */ - r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, - GFX_11_0_0__SRCID__CP_ECC_ERROR, - &adev->gfx.cp_ecc_error_irq); - if (r) - return r; - /* FED error */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX, GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT, @@ -4444,7 +4437,6 @@ static int gfx_v11_0_hw_fini(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4675,24 +4667,27 @@ static uint64_t gfx_v11_0_get_gpu_clock_counter(struct amdgpu_device *adev) uint64_t clock; uint64_t clock_counter_lo, clock_counter_hi_pre, clock_counter_hi_after; - amdgpu_gfx_off_ctrl(adev, false); - mutex_lock(&adev->gfx.gpu_clock_mutex); if (amdgpu_sriov_vf(adev)) { + amdgpu_gfx_off_ctrl(adev, false); + mutex_lock(&adev->gfx.gpu_clock_mutex); clock_counter_hi_pre = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_HI); clock_counter_lo = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_LO); clock_counter_hi_after = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_HI); if (clock_counter_hi_pre != clock_counter_hi_after) clock_counter_lo = (uint64_t)RREG32_SOC15(GC, 0, regCP_MES_MTIME_LO); + mutex_unlock(&adev->gfx.gpu_clock_mutex); + amdgpu_gfx_off_ctrl(adev, true); } else { + preempt_disable(); clock_counter_hi_pre = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); clock_counter_hi_after = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_UPPER); if (clock_counter_hi_pre != clock_counter_hi_after) clock_counter_lo = (uint64_t)RREG32_SOC15(SMUIO, 0, regGOLDEN_TSC_COUNT_LOWER); + preempt_enable(); } clock = clock_counter_lo | (clock_counter_hi_after << 32ULL); - mutex_unlock(&adev->gfx.gpu_clock_mutex); - amdgpu_gfx_off_ctrl(adev, true); + return clock; } @@ -5158,8 +5153,14 @@ static int gfx_v11_0_set_powergating_state(void *handle, break; case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 4): + if (!enable) + amdgpu_gfx_off_ctrl(adev, false); + gfx_v11_cntl_pg(adev, enable); - amdgpu_gfx_off_ctrl(adev, enable); + + if (enable) + amdgpu_gfx_off_ctrl(adev, true); + break; default: break; @@ -5897,36 +5898,6 @@ static void gfx_v11_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev } } -#define CP_ME1_PIPE_INST_ADDR_INTERVAL 0x1 -#define SET_ECC_ME_PIPE_STATE(reg_addr, state) \ - do { \ - uint32_t tmp = RREG32_SOC15_IP(GC, reg_addr); \ - tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, state); \ - WREG32_SOC15_IP(GC, reg_addr, tmp); \ - } while (0) - -static int gfx_v11_0_set_cp_ecc_error_state(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - unsigned type, - enum amdgpu_interrupt_state state) -{ - uint32_t ecc_irq_state = 0; - uint32_t pipe0_int_cntl_addr = 0; - int i = 0; - - ecc_irq_state = (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0; - - pipe0_int_cntl_addr = SOC15_REG_OFFSET(GC, 0, regCP_ME1_PIPE0_INT_CNTL); - - WREG32_FIELD15_PREREG(GC, 0, CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, ecc_irq_state); - - for (i = 0; i < adev->gfx.mec.num_pipe_per_mec; i++) - SET_ECC_ME_PIPE_STATE(pipe0_int_cntl_addr + i * CP_ME1_PIPE_INST_ADDR_INTERVAL, - ecc_irq_state); - - return 0; -} - static int gfx_v11_0_set_eop_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, @@ -6341,11 +6312,6 @@ static const struct amdgpu_irq_src_funcs gfx_v11_0_priv_inst_irq_funcs = { .process = gfx_v11_0_priv_inst_irq, }; -static const struct amdgpu_irq_src_funcs gfx_v11_0_cp_ecc_error_irq_funcs = { - .set = gfx_v11_0_set_cp_ecc_error_state, - .process = amdgpu_gfx_cp_ecc_error_irq, -}; - static const struct amdgpu_irq_src_funcs gfx_v11_0_rlc_gc_fed_irq_funcs = { .process = gfx_v11_0_rlc_gc_fed_irq, }; @@ -6361,9 +6327,6 @@ static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.priv_inst_irq.num_types = 1; adev->gfx.priv_inst_irq.funcs = &gfx_v11_0_priv_inst_irq_funcs; - adev->gfx.cp_ecc_error_irq.num_types = 1; /* CP ECC error */ - adev->gfx.cp_ecc_error_irq.funcs = &gfx_v11_0_cp_ecc_error_irq_funcs; - adev->gfx.rlc_gc_fed_irq.num_types = 1; /* 0x80 FED error */ adev->gfx.rlc_gc_fed_irq.funcs = &gfx_v11_0_rlc_gc_fed_irq_funcs; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index adbcd8127c82..ce22f7b30416 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3617,8 +3617,10 @@ static int gfx_v9_0_kiq_resume(struct amdgpu_device *adev) return r; r = amdgpu_bo_kmap(ring->mqd_obj, (void **)&ring->mqd_ptr); - if (unlikely(r != 0)) + if (unlikely(r != 0)) { + amdgpu_bo_unreserve(ring->mqd_obj); return r; + } gfx_v9_0_kiq_init_queue(ring); amdgpu_bo_kunmap(ring->mqd_obj); @@ -3764,7 +3766,8 @@ static int gfx_v9_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) + amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4002,30 +4005,25 @@ static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev) clock = clock_lo | (clock_hi << 32ULL); break; case IP_VERSION(9, 1, 0): - preempt_disable(); - clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); - clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); - hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); - /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over - * roughly every 42 seconds. - */ - if (hi_check != clock_hi) { - clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); - clock_hi = hi_check; - } - preempt_enable(); - clock = clock_lo | (clock_hi << 32ULL); - break; case IP_VERSION(9, 2, 2): preempt_disable(); - clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); - clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2); - hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); - /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over - * roughly every 42 seconds. - */ - if (hi_check != clock_hi) { + if (adev->rev_id >= 0x8) { + clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2); + hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2); + } else { + clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); + hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven); + } + /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over + * roughly every 42 seconds. + */ + if (hi_check != clock_hi) { + if (adev->rev_id >= 0x8) + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2); + else + clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven); clock_hi = hi_check; } preempt_enable(); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 7d6f4a68f416..b213dcf8ca06 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -1143,7 +1143,6 @@ static int gmc_v10_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index d809f2ed5600..4116c112e8a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -31,6 +31,8 @@ #include "umc_v8_10.h" #include "athub/athub_3_0_0_sh_mask.h" #include "athub/athub_3_0_0_offset.h" +#include "dcn/dcn_3_2_0_offset.h" +#include "dcn/dcn_3_2_0_sh_mask.h" #include "oss/osssys_6_0_0_offset.h" #include "ivsrcid/vmc/irqsrcs_vmc_1_0.h" #include "navi10_enum.h" @@ -546,7 +548,24 @@ static void gmc_v11_0_get_vm_pte(struct amdgpu_device *adev, static unsigned gmc_v11_0_get_vbios_fb_size(struct amdgpu_device *adev) { - return 0; + u32 d1vga_control = RREG32_SOC15(DCE, 0, regD1VGA_CONTROL); + unsigned size; + + if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { + size = AMDGPU_VBIOS_VGA_ALLOCATION; + } else { + u32 viewport; + u32 pitch; + + viewport = RREG32_SOC15(DCE, 0, regHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); + pitch = RREG32_SOC15(DCE, 0, regHUBPREQ0_DCSURF_SURFACE_PITCH); + size = (REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * + REG_GET_FIELD(pitch, HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH) * + 4); + } + + return size; } static const struct amdgpu_gmc_funcs gmc_v11_0_gmc_funcs = { @@ -951,7 +970,6 @@ static int gmc_v11_0_hw_fini(void *handle) return 0; } - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v11_0_gart_disable(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 64ab1a306dfe..2fe21cefd772 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1999,7 +1999,6 @@ static int gmc_v9_0_hw_fini(void *handle) if (adev->mmhub.funcs->update_power_gating) adev->mmhub.funcs->update_power_gating(adev, false); - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index b040f51d9aa9..73e0dc5a10cd 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -102,13 +102,13 @@ static int jpeg_v2_5_sw_init(void *handle) /* JPEG DJPEG POISON EVENT */ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_jpeg[i], - VCN_2_6__SRCID_DJPEG0_POISON, &adev->jpeg.inst[i].irq); + VCN_2_6__SRCID_DJPEG0_POISON, &adev->jpeg.inst[i].ras_poison_irq); if (r) return r; /* JPEG EJPEG POISON EVENT */ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_jpeg[i], - VCN_2_6__SRCID_EJPEG0_POISON, &adev->jpeg.inst[i].irq); + VCN_2_6__SRCID_EJPEG0_POISON, &adev->jpeg.inst[i].ras_poison_irq); if (r) return r; } @@ -221,6 +221,9 @@ static int jpeg_v2_5_hw_fini(void *handle) if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(JPEG, i, mmUVD_JRBC_STATUS)) jpeg_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE); + + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG)) + amdgpu_irq_put(adev, &adev->jpeg.inst[i].ras_poison_irq, 0); } return 0; @@ -569,6 +572,14 @@ static int jpeg_v2_5_set_interrupt_state(struct amdgpu_device *adev, return 0; } +static int jpeg_v2_6_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -593,10 +604,6 @@ static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev, case VCN_2_0__SRCID__JPEG_DECODE: amdgpu_fence_process(&adev->jpeg.inst[ip_instance].ring_dec); break; - case VCN_2_6__SRCID_DJPEG0_POISON: - case VCN_2_6__SRCID_EJPEG0_POISON: - amdgpu_jpeg_process_poison_irq(adev, source, entry); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -725,6 +732,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v2_5_irq_funcs = { .process = jpeg_v2_5_process_interrupt, }; +static const struct amdgpu_irq_src_funcs jpeg_v2_6_ras_irq_funcs = { + .set = jpeg_v2_6_set_ras_interrupt_state, + .process = amdgpu_jpeg_process_poison_irq, +}; + static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev) { int i; @@ -735,6 +747,9 @@ static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev) adev->jpeg.inst[i].irq.num_types = 1; adev->jpeg.inst[i].irq.funcs = &jpeg_v2_5_irq_funcs; + + adev->jpeg.inst[i].ras_poison_irq.num_types = 1; + adev->jpeg.inst[i].ras_poison_irq.funcs = &jpeg_v2_6_ras_irq_funcs; } } @@ -800,6 +815,7 @@ const struct amdgpu_ras_block_hw_ops jpeg_v2_6_ras_hw_ops = { static struct amdgpu_jpeg_ras jpeg_v2_6_ras = { .ras_block = { .hw_ops = &jpeg_v2_6_ras_hw_ops, + .ras_late_init = amdgpu_jpeg_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index c55e09432e26..1c2292cc5f2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -54,6 +54,7 @@ static int jpeg_v3_0_early_init(void *handle) switch (adev->ip_versions[UVD_HWIP][0]) { case IP_VERSION(3, 1, 1): + case IP_VERSION(3, 1, 2): break; default: harvest = RREG32_SOC15(JPEG, 0, mmCC_UVD_HARVESTING); diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c index a6ad678fd507..a3d83c9f2c9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c @@ -87,13 +87,13 @@ static int jpeg_v4_0_sw_init(void *handle) /* JPEG DJPEG POISON EVENT */ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, - VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->irq); + VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); if (r) return r; /* JPEG EJPEG POISON EVENT */ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, - VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->irq); + VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq); if (r) return r; @@ -202,7 +202,8 @@ static int jpeg_v4_0_hw_fini(void *handle) RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS)) jpeg_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE); } - amdgpu_irq_put(adev, &adev->jpeg.inst->irq, 0); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG)) + amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0); return 0; } @@ -430,7 +431,7 @@ static int jpeg_v4_0_start_sriov(struct amdgpu_device *adev) MMSCH_COMMAND__END; header.version = MMSCH_VERSION; - header.total_size = sizeof(struct mmsch_v4_0_init_header) >> 2; + header.total_size = RREG32_SOC15(VCN, 0, regMMSCH_VF_CTX_SIZE); header.jpegdec.init_status = 0; header.jpegdec.table_offset = 0; @@ -670,6 +671,14 @@ static int jpeg_v4_0_set_interrupt_state(struct amdgpu_device *adev, return 0; } +static int jpeg_v4_0_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -680,10 +689,6 @@ static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev, case VCN_4_0__SRCID__JPEG_DECODE: amdgpu_fence_process(&adev->jpeg.inst->ring_dec); break; - case VCN_4_0__SRCID_DJPEG0_POISON: - case VCN_4_0__SRCID_EJPEG0_POISON: - amdgpu_jpeg_process_poison_irq(adev, source, entry); - break; default: DRM_DEV_ERROR(adev->dev, "Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -753,10 +758,18 @@ static const struct amdgpu_irq_src_funcs jpeg_v4_0_irq_funcs = { .process = jpeg_v4_0_process_interrupt, }; +static const struct amdgpu_irq_src_funcs jpeg_v4_0_ras_irq_funcs = { + .set = jpeg_v4_0_set_ras_interrupt_state, + .process = amdgpu_jpeg_process_poison_irq, +}; + static void jpeg_v4_0_set_irq_funcs(struct amdgpu_device *adev) { adev->jpeg.inst->irq.num_types = 1; adev->jpeg.inst->irq.funcs = &jpeg_v4_0_irq_funcs; + + adev->jpeg.inst->ras_poison_irq.num_types = 1; + adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v4_0_ras_irq_funcs; } const struct amdgpu_ip_block_version jpeg_v4_0_ip_block = { @@ -811,6 +824,7 @@ const struct amdgpu_ras_block_hw_ops jpeg_v4_0_ras_hw_ops = { static struct amdgpu_jpeg_ras jpeg_v4_0_ras = { .ras_block = { .hw_ops = &jpeg_v4_0_ras_hw_ops, + .ras_late_init = amdgpu_jpeg_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 47420b403871..0fb6013441f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -98,6 +98,16 @@ static const struct amdgpu_video_codecs nv_video_codecs_decode = }; /* Sienna Cichlid */ +static const struct amdgpu_video_codec_info sc_video_codecs_encode_array[] = { + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2160, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 7680, 4352, 0)}, +}; + +static const struct amdgpu_video_codecs sc_video_codecs_encode = { + .codec_count = ARRAY_SIZE(sc_video_codecs_encode_array), + .codec_array = sc_video_codecs_encode_array, +}; + static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn0[] = { {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)}, @@ -136,8 +146,8 @@ static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn1 = /* SRIOV Sienna Cichlid, not const since data is controlled by host */ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] = { - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)}, - {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2160, 0)}, + {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 7680, 4352, 0)}, }; static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] = @@ -237,12 +247,12 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, } else { if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) { if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn1; } else { if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn0; } @@ -251,14 +261,14 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode, case IP_VERSION(3, 0, 16): case IP_VERSION(3, 0, 2): if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &sc_video_codecs_decode_vcn0; return 0; case IP_VERSION(3, 1, 1): case IP_VERSION(3, 1, 2): if (encode) - *codecs = &nv_video_codecs_encode; + *codecs = &sc_video_codecs_encode; else *codecs = &yc_video_codecs_decode; return 0; @@ -531,13 +541,6 @@ static void nv_program_aspm(struct amdgpu_device *adev) } -static void nv_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version nv_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -999,6 +1002,11 @@ static int nv_common_late_init(void *handle) } } + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -1038,7 +1046,7 @@ static int nv_common_hw_init(void *handle) if (adev->nbio.funcs->remap_hdp_registers && !amdgpu_sriov_vf(adev)) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - nv_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); return 0; } @@ -1047,8 +1055,13 @@ static int nv_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - nv_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because nv_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index e1b7fca09666..5f10883da6a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -57,7 +57,13 @@ static int psp_v10_0_init_microcode(struct psp_context *psp) if (err) return err; - return psp_init_ta_microcode(psp, ucode_prefix); + err = psp_init_ta_microcode(psp, ucode_prefix); + if ((adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 1, 0)) && + (adev->pdev->revision == 0xa1) && + (psp->securedisplay_context.context.bin_desc.fw_version >= 0x27000008)) { + adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0; + } + return err; } static int psp_v10_0_ring_create(struct psp_context *psp, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index b3cc04dd8653..9295ac7edd56 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1917,9 +1917,11 @@ static int sdma_v4_0_hw_fini(void *handle) return 0; } - for (i = 0; i < adev->sdma.num_instances; i++) { - amdgpu_irq_put(adev, &adev->sdma.ecc_irq, - AMDGPU_SDMA_IRQ_INSTANCE0 + i); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + amdgpu_irq_put(adev, &adev->sdma.ecc_irq, + AMDGPU_SDMA_IRQ_INSTANCE0 + i); + } } sdma_v4_0_ctx_switch_enable(adev, false); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index eb722830531f..3d9a80511a45 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -510,10 +510,7 @@ static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); - if (amdgpu_sriov_vf(adev)) - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 1); - else - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 0); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, WPTR_POLL_ENABLE, 0); rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, F32_WPTR_POLL_ENABLE, 1); WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_BASE), ring->gpu_addr >> 8); diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c index 81a6d5b94987..8b8086d5c864 100644 --- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +++ b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c @@ -40,7 +40,7 @@ static bool sienna_cichlid_is_mode2_default(struct amdgpu_reset_control *reset_c adev->pm.fw_version >= 0x3a5500 && !amdgpu_sriov_vf(adev)) return true; #endif - return false; + return amdgpu_reset_method == AMD_RESET_METHOD_MODE2; } static struct amdgpu_reset_handler * diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index bc5dd80f10c1..6d15d5cd9e07 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -619,13 +619,6 @@ static void soc15_program_aspm(struct amdgpu_device *adev) adev->nbio.funcs->program_aspm(adev); } -static void soc15_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version vega10_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -1125,6 +1118,11 @@ static int soc15_common_late_init(void *handle) if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_get_irq(adev); + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -1182,7 +1180,8 @@ static int soc15_common_hw_init(void *handle) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - soc15_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); + /* HW doorbell routing policy: doorbell writing not * in SDMA/IH/MM/ACV range will be routed to CP. So * we need to init SDMA doorbell range prior @@ -1198,8 +1197,14 @@ static int soc15_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - soc15_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because soc15_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); + if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_put_irq(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 514bfc705d5a..d77162536514 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -450,13 +450,6 @@ static void soc21_program_aspm(struct amdgpu_device *adev) adev->nbio.funcs->program_aspm(adev); } -static void soc21_enable_doorbell_aperture(struct amdgpu_device *adev, - bool enable) -{ - adev->nbio.funcs->enable_doorbell_aperture(adev, enable); - adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, enable); -} - const struct amdgpu_ip_block_version soc21_common_ip_block = { .type = AMD_IP_BLOCK_TYPE_COMMON, @@ -718,7 +711,7 @@ static int soc21_common_early_init(void *handle) AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_JPEG; - adev->external_rev_id = adev->rev_id + 0x1; + adev->external_rev_id = adev->rev_id + 0x80; break; default: @@ -764,6 +757,11 @@ static int soc21_common_late_init(void *handle) amdgpu_irq_get(adev, &adev->nbio.ras_err_event_athub_irq, 0); } + /* Enable selfring doorbell aperture late because doorbell BAR + * aperture will change if resize BAR successfully in gmc sw_init. + */ + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, true); + return 0; } @@ -797,7 +795,7 @@ static int soc21_common_hw_init(void *handle) if (adev->nbio.funcs->remap_hdp_registers) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ - soc21_enable_doorbell_aperture(adev, true); + adev->nbio.funcs->enable_doorbell_aperture(adev, true); return 0; } @@ -806,8 +804,13 @@ static int soc21_common_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - /* disable the doorbell aperture */ - soc21_enable_doorbell_aperture(adev, false); + /* Disable the doorbell aperture and selfring doorbell aperture + * separately in hw_fini because soc21_enable_doorbell_aperture + * has been removed and there is no need to delay disabling + * selfring doorbell. + */ + adev->nbio.funcs->enable_doorbell_aperture(adev, false); + adev->nbio.funcs->enable_doorbell_selfring_aperture(adev, false); if (amdgpu_sriov_vf(adev)) { xgpu_nv_mailbox_put_irq(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index ab0b45d0ead1..515681c88dcb 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -143,7 +143,7 @@ static int vcn_v2_5_sw_init(void *handle) /* VCN POISON TRAP */ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j], - VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].irq); + VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq); if (r) return r; } @@ -354,6 +354,9 @@ static int vcn_v2_5_hw_fini(void *handle) (adev->vcn.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(VCN, i, mmUVD_STATUS))) vcn_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE); + + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) + amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0); } return 0; @@ -1807,6 +1810,14 @@ static int vcn_v2_5_set_interrupt_state(struct amdgpu_device *adev, return 0; } +static int vcn_v2_6_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + static int vcn_v2_5_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -1837,9 +1848,6 @@ static int vcn_v2_5_process_interrupt(struct amdgpu_device *adev, case VCN_2_0__SRCID__UVD_ENC_LOW_LATENCY: amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[1]); break; - case VCN_2_6__SRCID_UVD_POISON: - amdgpu_vcn_process_poison_irq(adev, source, entry); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -1854,6 +1862,11 @@ static const struct amdgpu_irq_src_funcs vcn_v2_5_irq_funcs = { .process = vcn_v2_5_process_interrupt, }; +static const struct amdgpu_irq_src_funcs vcn_v2_6_ras_irq_funcs = { + .set = vcn_v2_6_set_ras_interrupt_state, + .process = amdgpu_vcn_process_poison_irq, +}; + static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev) { int i; @@ -1863,6 +1876,9 @@ static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev) continue; adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1; adev->vcn.inst[i].irq.funcs = &vcn_v2_5_irq_funcs; + + adev->vcn.inst[i].ras_poison_irq.num_types = adev->vcn.num_enc_rings + 1; + adev->vcn.inst[i].ras_poison_irq.funcs = &vcn_v2_6_ras_irq_funcs; } } @@ -1965,6 +1981,7 @@ const struct amdgpu_ras_block_hw_ops vcn_v2_6_ras_hw_ops = { static struct amdgpu_vcn_ras vcn_v2_6_ras = { .ras_block = { .hw_ops = &vcn_v2_6_ras_hw_ops, + .ras_late_init = amdgpu_vcn_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index bf0674039598..e5fd1e00914d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -139,7 +139,7 @@ static int vcn_v4_0_sw_init(void *handle) /* VCN POISON TRAP */ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i], - VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].irq); + VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].ras_poison_irq); if (r) return r; @@ -305,8 +305,8 @@ static int vcn_v4_0_hw_fini(void *handle) vcn_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE); } } - - amdgpu_irq_put(adev, &adev->vcn.inst[i].irq, 0); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) + amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0); } return 0; @@ -1975,6 +1975,24 @@ static int vcn_v4_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgp return 0; } +/** + * vcn_v4_0_set_ras_interrupt_state - set VCN block RAS interrupt state + * + * @adev: amdgpu_device pointer + * @source: interrupt sources + * @type: interrupt types + * @state: interrupt states + * + * Set VCN block RAS interrupt state + */ +static int vcn_v4_0_set_ras_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + /** * vcn_v4_0_process_interrupt - process VCN block interrupt * @@ -2007,9 +2025,6 @@ static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_ case VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE: amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[0]); break; - case VCN_4_0__SRCID_UVD_POISON: - amdgpu_vcn_process_poison_irq(adev, source, entry); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -2024,6 +2039,11 @@ static const struct amdgpu_irq_src_funcs vcn_v4_0_irq_funcs = { .process = vcn_v4_0_process_interrupt, }; +static const struct amdgpu_irq_src_funcs vcn_v4_0_ras_irq_funcs = { + .set = vcn_v4_0_set_ras_interrupt_state, + .process = amdgpu_vcn_process_poison_irq, +}; + /** * vcn_v4_0_set_irq_funcs - set VCN block interrupt irq functions * @@ -2041,6 +2061,9 @@ static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev) adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1; adev->vcn.inst[i].irq.funcs = &vcn_v4_0_irq_funcs; + + adev->vcn.inst[i].ras_poison_irq.num_types = adev->vcn.num_enc_rings + 1; + adev->vcn.inst[i].ras_poison_irq.funcs = &vcn_v4_0_ras_irq_funcs; } } @@ -2114,6 +2137,7 @@ const struct amdgpu_ras_block_hw_ops vcn_v4_0_ras_hw_ops = { static struct amdgpu_vcn_ras vcn_v4_0_ras = { .ras_block = { .hw_ops = &vcn_v4_0_ras_hw_ops, + .ras_late_init = amdgpu_vcn_ras_late_init, }, }; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 81d07ecf666d..1b54a9aaae70 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -93,7 +93,7 @@ int kfd_chardev_init(void) if (err < 0) goto err_register_chrdev; - kfd_class = class_create(THIS_MODULE, kfd_dev_name); + kfd_class = class_create(kfd_dev_name); err = PTR_ERR(kfd_class); if (IS_ERR(kfd_class)) goto err_class_create; diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 06b438217c61..2d8e55e29637 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -8,7 +8,7 @@ config DRM_AMD_DC depends on BROKEN || !CC_IS_CLANG || X86_64 || SPARC64 || ARM64 select SND_HDA_COMPONENT if SND_HDA_CORE # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752 - select DRM_AMD_DC_FP if (X86 || PPC64 || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) + select DRM_AMD_DC_FP if (X86 || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c4aa87086a4e..d5cec03eaa8d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2479,20 +2479,25 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, if (acrtc && state->stream_status[i].plane_count != 0) { irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst; rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; - DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n", - acrtc->crtc_id, enable ? "en" : "dis", rc); if (rc) DRM_WARN("Failed to %s pflip interrupts\n", enable ? "enable" : "disable"); if (enable) { - rc = amdgpu_dm_crtc_enable_vblank(&acrtc->base); - if (rc) - DRM_WARN("Failed to enable vblank interrupts\n"); - } else { - amdgpu_dm_crtc_disable_vblank(&acrtc->base); - } + if (amdgpu_dm_crtc_vrr_active(to_dm_crtc_state(acrtc->base.state))) + rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true); + } else + rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, false); + if (rc) + DRM_WARN("Failed to %sable vupdate interrupt\n", enable ? "en" : "dis"); + + irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + /* During gpu-reset we disable and then enable vblank irq, so + * don't use amdgpu_irq_get/put() to avoid refcount change. + */ + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + DRM_WARN("Failed to %sable vblank interrupt\n", enable ? "en" : "dis"); } } @@ -2852,7 +2857,7 @@ static int dm_resume(void *handle) * this is the case when traversing through already created * MST connectors, should be skipped */ - if (aconnector->dc_link->type == dc_connection_mst_branch) + if (aconnector && aconnector->mst_root) continue; mutex_lock(&aconnector->hpd_lock); @@ -3128,9 +3133,12 @@ void amdgpu_dm_update_connector_after_detect( aconnector->edid); } - aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL); - if (!aconnector->timing_requested) - dm_error("%s: failed to create aconnector->requested_timing\n", __func__); + if (!aconnector->timing_requested) { + aconnector->timing_requested = + kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL); + if (!aconnector->timing_requested) + dm_error("failed to create aconnector->requested_timing\n"); + } drm_connector_update_edid_property(connector, aconnector->edid); amdgpu_dm_update_freesync_caps(connector, aconnector->edid); @@ -6734,7 +6742,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, int clock, bpp = 0; bool is_y420 = false; - if (!aconnector->mst_output_port || !aconnector->dc_sink) + if (!aconnector->mst_output_port) return 0; mst_port = aconnector->mst_output_port; @@ -7894,6 +7902,13 @@ static void amdgpu_dm_commit_cursors(struct drm_atomic_state *state) amdgpu_dm_plane_handle_cursor_update(plane, old_plane_state); } +static inline uint32_t get_mem_type(struct drm_framebuffer *fb) +{ + struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]); + + return abo->tbo.resource ? abo->tbo.resource->mem_type : 0; +} + static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dc_state *dc_state, struct drm_device *dev, @@ -7968,6 +7983,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, continue; dc_plane = dm_new_plane_state->dc_state; + if (!dc_plane) + continue; bundle->surface_updates[planes_count].surface = dc_plane; if (new_pcrtc_state->color_mgmt_changed) { @@ -8034,11 +8051,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, /* * Only allow immediate flips for fast updates that don't - * change FB pitch, DCC state, rotation or mirroing. + * change memory domain, FB pitch, DCC state, rotation or + * mirroring. */ bundle->flip_addrs[planes_count].flip_immediate = crtc->state->async_flip && - acrtc_state->update_type == UPDATE_TYPE_FAST; + acrtc_state->update_type == UPDATE_TYPE_FAST && + get_mem_type(old_plane_state->fb) == get_mem_type(fb); timestamp_ns = ktime_get_ns(); bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); @@ -8550,6 +8569,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i); if (!connector) @@ -8598,6 +8620,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (!adev->dm.hdcp_workqueue) + continue; + new_crtc_state = NULL; old_crtc_state = NULL; @@ -9616,8 +9641,9 @@ static int dm_update_plane_state(struct dc *dc, return -EINVAL; } + if (dm_old_plane_state->dc_state) + dc_plane_state_release(dm_old_plane_state->dc_state); - dc_plane_state_release(dm_old_plane_state->dc_state); dm_new_plane_state->dc_state = NULL; *lock_and_validation_needed = true; @@ -10154,6 +10180,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars); if (ret) { DRM_DEBUG_DRIVER("compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto fail; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index e3762e806617..440fc0869a34 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -146,7 +146,6 @@ static void vblank_control_worker(struct work_struct *work) static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) { - enum dc_irq_source irq_source; struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); @@ -169,18 +168,9 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) if (rc) return rc; - if (amdgpu_in_reset(adev)) { - irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; - /* During gpu-reset we disable and then enable vblank irq, so - * don't use amdgpu_irq_get/put() to avoid refcount change. - */ - if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) - rc = -EBUSY; - } else { - rc = (enable) - ? amdgpu_irq_get(adev, &adev->crtc_irq, acrtc->crtc_id) - : amdgpu_irq_put(adev, &adev->crtc_irq, acrtc->crtc_id); - } + rc = (enable) + ? amdgpu_irq_get(adev, &adev->crtc_irq, acrtc->crtc_id) + : amdgpu_irq_put(adev, &adev->crtc_irq, acrtc->crtc_id); if (rc) return rc; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 330ab036c830..c6ce2b7123b7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -687,7 +687,6 @@ static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux) return; data[0] |= (1 << 1); // set bit 1 to 1 - return; if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data)) return; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 994ba426ca66..810ab682f424 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -379,13 +379,17 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (aconnector->dc_sink && connector->state) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); - struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; - struct hdcp_workqueue *hdcp_w = &hdcp_work[aconnector->dc_link->link_index]; - connector->state->hdcp_content_type = - hdcp_w->hdcp_content_type[connector->index]; - connector->state->content_protection = - hdcp_w->content_protection[connector->index]; + if (adev->dm.hdcp_workqueue) { + struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; + struct hdcp_workqueue *hdcp_w = + &hdcp_work[aconnector->dc_link->link_index]; + + connector->state->hdcp_content_type = + hdcp_w->hdcp_content_type[connector->index]; + connector->state->content_protection = + hdcp_w->content_protection[connector->index]; + } } if (aconnector->dc_sink) { @@ -1406,6 +1410,7 @@ int pre_validate_dsc(struct drm_atomic_state *state, ret = pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars); if (ret != 0) { DRM_INFO_ONCE("pre_compute_mst_dsc_configs_for_state() failed\n"); + ret = -EINVAL; goto clean_exit; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 1743ca0a3641..c42aa947c969 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -89,6 +89,7 @@ void dc_fpu_begin(const char *function_name, const int line) if (*pcpu == 1) { #if defined(CONFIG_X86) + migrate_disable(); kernel_fpu_begin(); #elif defined(CONFIG_PPC64) if (cpu_has_feature(CPU_FTR_VSX_COMP)) { @@ -129,6 +130,7 @@ void dc_fpu_end(const char *function_name, const int line) if (*pcpu <= 0) { #if defined(CONFIG_X86) kernel_fpu_end(); + migrate_enable(); #elif defined(CONFIG_PPC64) if (cpu_has_feature(CPU_FTR_VSX_COMP)) { disable_kernel_vsx(); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index ea753f8fa175..8d9444db092a 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -878,6 +878,8 @@ void dcn32_clk_mgr_construct( struct pp_smu_funcs *pp_smu, struct dccg *dccg) { + struct clk_log_info log_info = {0}; + clk_mgr->base.ctx = ctx; clk_mgr->base.funcs = &dcn32_funcs; if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) { @@ -911,6 +913,7 @@ void dcn32_clk_mgr_construct( clk_mgr->base.clks.ref_dtbclk_khz = 268750; } + /* integer part is now VCO frequency in kHz */ clk_mgr->base.dentist_vco_freq_khz = dcn32_get_vco_frequency_from_reg(clk_mgr); @@ -918,6 +921,8 @@ void dcn32_clk_mgr_construct( if (clk_mgr->base.dentist_vco_freq_khz == 0) clk_mgr->base.dentist_vco_freq_khz = 4300000; /* Updated as per HW docs */ + dcn32_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); + if (ctx->dc->debug.disable_dtb_ref_clk_switch && clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) { clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 85d54bfb595c..117d80cb36fb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1707,6 +1707,9 @@ bool dc_remove_plane_from_context( struct dc_stream_status *stream_status = NULL; struct resource_pool *pool = dc->res_pool; + if (!plane_state) + return true; + for (i = 0; i < context->stream_count; i++) if (context->streams[i] == stream) { stream_status = &context->stream_status[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 23ee63b98dcd..30f0ba05a6e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1454,6 +1454,7 @@ struct dc_link { struct ddc_service *ddc; + enum dp_panel_mode panel_mode; bool aux_mode; /* Private to DC core */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 181a3408cc61..25284006019c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -144,7 +144,7 @@ struct test_pattern { unsigned int cust_pattern_size; }; -#define SUBVP_DRR_MARGIN_US 600 // 600us for DRR margin (SubVP + DRR) +#define SUBVP_DRR_MARGIN_US 100 // 100us for DRR margin (SubVP + DRR) enum mall_stream_type { SUBVP_NONE, // subvp not in use diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 9fe0ce91db00..8d2460d06bce 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -3031,10 +3031,12 @@ void dce110_enable_dp_link_output( const struct link_hwss *link_hwss = get_link_hwss(link, link_res); unsigned int i; - + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ if (link->connector_signal == SIGNAL_TYPE_EDP) { - if (!link->dc->config.edp_no_power_sequencing) - link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); } @@ -3096,11 +3098,12 @@ void dce110_disable_link_output(struct dc_link *link, link_hwss->disable_link_output(link, link_res, signal); link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control) - link->dc->hwss.edp_power_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) dmcu->funcs->unlock_phy(dmcu); dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 0e071fbc9154..32121db2851e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -983,7 +983,7 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc, } void dcn30_prepare_bandwidth(struct dc *dc, - struct dc_state *context) + struct dc_state *context) { if (dc->clk_mgr->dc_mode_softmax_enabled) if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 965f5ceb33f7..67a34cda3774 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -701,7 +701,9 @@ static const struct dc_plane_cap plane_cap = { .argb8888 = 167, .nv12 = 167, .fp16 = 167 - } + }, + 16, + 16 }; static const struct dc_debug_options debug_defaults_drv = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 7ac6e69cff37..62ce36c75c4d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -295,6 +295,10 @@ void dcn31_init_hw(struct dc *dc) if (dc->res_pool->hubbub->funcs->init_crb) dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); #endif + + // Get DMCUB capabilities + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; } void dcn31_dsc_pg_control( diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c index 6f879265ad9c..de7bfba2c179 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c @@ -274,7 +274,7 @@ static void dccg314_set_dpstreamclk( } } -void dccg314_init(struct dccg *dccg) +static void dccg314_init(struct dccg *dccg) { int otg_inst; diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c index 40c488b26901..cc3fe9cac5b5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c @@ -423,3 +423,68 @@ void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool PERF_TRACE(); } +static void apply_symclk_on_tx_off_wa(struct dc_link *link) +{ + /* There are use cases where SYMCLK is referenced by OTG. For instance + * for TMDS signal, OTG relies SYMCLK even if TX video output is off. + * However current link interface will power off PHY when disabling link + * output. This will turn off SYMCLK generated by PHY. The workaround is + * to identify such case where SYMCLK is still in use by OTG when we + * power off PHY. When this is detected, we will temporarily power PHY + * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling + * program_pix_clk interface. When OTG is disabled, we will then power + * off PHY by calling disable link output again. + * + * In future dcn generations, we plan to rework transmitter control + * interface so that we could have an option to set SYMCLK ON TX OFF + * state in one step without this workaround + */ + + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + if (link->phy_state.symclk_ref_cnts.otg > 0) { + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format( + &pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + break; + } + } + } +} + +void dcn314_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + + apply_symclk_on_tx_off_wa(link); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h index c786d5e6a428..6d0b62503caa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h @@ -45,4 +45,6 @@ void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); +void dcn314_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); + #endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 5267e901a35c..a588f46b166f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -105,7 +105,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .enable_lvds_link_output = dce110_enable_lvds_link_output, .enable_tmds_link_output = dce110_enable_tmds_link_output, .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, + .disable_link_output = dcn314_disable_link_output, .z10_restore = dcn31_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 24806acc8438..abeeede38fb3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -885,7 +885,7 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = false, .enable_z9_disable_interface = true, - .minimum_z8_residency_time = 3080, + .minimum_z8_residency_time = 2000, .psr_skip_crtc_disable = true, .disable_dmcu = true, .force_abm_enable = false, diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index db0974fe58ab..1f5ee5cde6e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -948,6 +948,7 @@ void dcn32_init_hw(struct dc *dc) if (dc->ctx->dmub_srv) { dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index e30d1f60695d..22dd1ebea618 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -324,7 +324,6 @@ static const struct dcn10_link_enc_shift le_shift = { static const struct dcn10_link_enc_mask le_mask = { LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - //DPCS_DCN31_MASK_SH_LIST(_MASK) }; @@ -2024,7 +2023,7 @@ int dcn32_populate_dml_pipes_from_context( // In general cases we want to keep the dram clock change requirement // (prefer configs that support MCLK switch). Only override to false // for SubVP - if (subvp_in_use) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use) context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false; else context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; @@ -2080,6 +2079,14 @@ static struct resource_funcs dcn32_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN32 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn32_resource_construct( uint8_t num_virtual_links, @@ -2093,27 +2100,28 @@ static bool dcn32_resource_construct( uint32_t pipe_fuses = 0; uint32_t num_pipes = 4; - #undef REG_STRUCT - #define REG_STRUCT bios_regs - bios_regs_init(); +#undef REG_STRUCT +#define REG_STRUCT bios_regs + bios_regs_init(); - #undef REG_STRUCT - #define REG_STRUCT clk_src_regs - clk_src_regs_init(0, A), - clk_src_regs_init(1, B), - clk_src_regs_init(2, C), - clk_src_regs_init(3, D), - clk_src_regs_init(4, E); - #undef REG_STRUCT - #define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); +#undef REG_STRUCT +#define REG_STRUCT clk_src_regs + clk_src_regs_init(0, A), + clk_src_regs_init(1, B), + clk_src_regs_init(2, C), + clk_src_regs_init(3, D), + clk_src_regs_init(4, E); - #undef REG_STRUCT - #define REG_STRUCT dccg_regs - dccg_regs_init(); +#undef REG_STRUCT +#define REG_STRUCT abm_regs + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); + +#undef REG_STRUCT +#define REG_STRUCT dccg_regs + dccg_regs_init(); DC_FP_START(); @@ -2122,7 +2130,7 @@ static bool dcn32_resource_construct( pool->base.res_cap = &res_cap_dcn32; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index e5ab7f3077c4..a60ddb343d13 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -1632,6 +1632,14 @@ static struct resource_funcs dcn321_res_pool_funcs = { .restore_mall_state = dcn32_restore_mall_state, }; +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN321 support max 4 pipes */ + value = value & 0xf; + return value; +} + static bool dcn321_resource_construct( uint8_t num_virtual_links, @@ -1674,7 +1682,7 @@ static bool dcn321_resource_construct( pool->base.res_cap = &res_cap_dcn321; /* max number of pipes for ASIC before checking for pipe fuses */ num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = REG_READ(CC_DC_PIPE_DIS); + pipe_fuses = read_pipe_fuses(ctx); for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) if (pipe_fuses & 1 << i) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 38d1f2be8cf3..f1c1a4b5fcac 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -917,19 +917,19 @@ void dcn20_populate_dml_writeback_from_context(struct dc *dc, } void dcn20_fpu_set_wb_arb_params(struct mcif_arb_params *wb_arb_params, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, int i) + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, int i) { - int k; + int k; - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) { - wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; - wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; - } - wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */ + for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) { + wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + } + wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */ } static bool is_dtbclk_required(struct dc *dc, struct dc_state *context) @@ -1037,11 +1037,11 @@ static void dcn20_adjust_freesync_v_startup( *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start); } -void dcn20_calculate_dlg_params( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) +void dcn20_calculate_dlg_params(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) { int i, pipe_idx; @@ -1083,6 +1083,7 @@ void dcn20_calculate_dlg_params( pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); + if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { // Phantom pipe requires that DET_SIZE = 0 and no unbounded requests context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0; @@ -1091,6 +1092,7 @@ void dcn20_calculate_dlg_params( context->res_ctx.pipe_ctx[i].det_buffer_size_kb = context->bw_ctx.dml.ip.det_buffer_size_kbytes; context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode; } + if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = @@ -1118,6 +1120,7 @@ void dcn20_calculate_dlg_params( if (!context->res_ctx.pipe_ctx[i].stream) continue; + /* cstate disabled on 201 */ if (dc->ctx->dce_version == DCN_VERSION_2_01) cstate_en = false; @@ -1201,11 +1204,10 @@ static void swizzle_to_dml_params( } } -int dcn20_populate_dml_pipes_from_context( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) +int dcn20_populate_dml_pipes_from_context(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) { int pipe_cnt, i; bool synchronized_vblank = true; @@ -1257,6 +1259,8 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0; + pipes[pipe_cnt].pipe.dest.use_maximum_vstartup = dc->ctx->dce_version == DCN_VERSION_2_01; + pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC; /* todo: rotation?*/ pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h; @@ -1296,8 +1300,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.dest.pixel_rate_mhz *= 2; pipes[pipe_cnt].pipe.dest.otg_inst = res_ctx->pipe_ctx[i].stream_res.tg->inst; pipes[pipe_cnt].dout.dp_lanes = 4; - if (res_ctx->pipe_ctx[i].stream->link) - pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_na; + pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_na; pipes[pipe_cnt].dout.is_virtual = 0; pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min; pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max; @@ -1357,7 +1360,6 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].dout.is_virtual = 1; pipes[pipe_cnt].dout.output_type = dm_dp; pipes[pipe_cnt].dout.dp_lanes = 4; - pipes[pipe_cnt].dout.dp_rate = dm_dp_rate_hbr2; } switch (res_ctx->pipe_ctx[i].stream->timing.display_color_depth) { @@ -1507,6 +1509,7 @@ int dcn20_populate_dml_pipes_from_context( default: break; } + pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y; pipes[pipe_cnt].pipe.src.viewport_x_y = scl->viewport.x; @@ -1615,13 +1618,12 @@ int dcn20_populate_dml_pipes_from_context( return pipe_cnt; } -void dcn20_calculate_wm( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *out_pipe_cnt, - int *pipe_split_from, - int vlevel, - bool fast_validate) +void dcn20_calculate_wm(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *out_pipe_cnt, + int *pipe_split_from, + int vlevel, + bool fast_validate) { int pipe_cnt, i, pipe_idx; @@ -1733,8 +1735,11 @@ void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; } -void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb, - struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states) +void dcn20_update_bounding_box(struct dc *dc, + struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table *max_clocks, + unsigned int *uclk_states, + unsigned int num_states) { int num_calculated_states = 0; int min_dcfclk = 0; @@ -1796,9 +1801,8 @@ void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s bb->clock_limits[num_calculated_states].state = bb->num_states; } -void dcn20_cap_soc_clocks( - struct _vcs_dpi_soc_bounding_box_st *bb, - struct pp_smu_nv_clock_table max_clocks) +void dcn20_cap_soc_clocks(struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table max_clocks) { int i; @@ -1954,80 +1958,80 @@ validate_out: } bool dcn20_validate_bandwidth_fp(struct dc *dc, - struct dc_state *context, - bool fast_validate) + struct dc_state *context, + bool fast_validate) { - bool voltage_supported = false; - bool full_pstate_supported = false; - bool dummy_pstate_supported = false; - double p_state_latency_us; + bool voltage_supported = false; + bool full_pstate_supported = false; + bool dummy_pstate_supported = false; + double p_state_latency_us; - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; - context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support = - dc->debug.disable_dram_clock_change_vactive_support; - context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive = - dc->debug.enable_dram_clock_change_one_display_vactive; + p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; + context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support = + dc->debug.disable_dram_clock_change_vactive_support; + context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive = + dc->debug.enable_dram_clock_change_one_display_vactive; - /*Unsafe due to current pipe merge and split logic*/ - ASSERT(context != dc->current_state); + /*Unsafe due to current pipe merge and split logic*/ + ASSERT(context != dc->current_state); - if (fast_validate) { - return dcn20_validate_bandwidth_internal(dc, context, true); - } + if (fast_validate) { + return dcn20_validate_bandwidth_internal(dc, context, true); + } - // Best case, we support full UCLK switch latency - voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); - full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + // Best case, we support full UCLK switch latency + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; - if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || - (voltage_supported && full_pstate_supported)) { - context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported; - goto restore_dml_state; - } + if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || + (voltage_supported && full_pstate_supported)) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported; + goto restore_dml_state; + } - // Fallback: Try to only support G6 temperature read latency - context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; + // Fallback: Try to only support G6 temperature read latency + context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; - voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); - dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; - if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { - context->bw_ctx.bw.dcn.clk.p_state_change_support = false; - goto restore_dml_state; - } + if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + goto restore_dml_state; + } - // ERROR: fallback is supposed to always work. - ASSERT(false); + // ERROR: fallback is supposed to always work. + ASSERT(false); restore_dml_state: - context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; - return voltage_supported; + context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; + return voltage_supported; } void dcn20_fpu_set_wm_ranges(int i, - struct pp_smu_wm_range_sets *ranges, - struct _vcs_dpi_soc_bounding_box_st *loaded_bb) + struct pp_smu_wm_range_sets *ranges, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb) { - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; - ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; + ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; } void dcn20_fpu_adjust_dppclk(struct vba_vars_st *v, - int vlevel, - int max_mpc_comb, - int pipe_idx, - bool is_validating_bw) + int vlevel, + int max_mpc_comb, + int pipe_idx, + bool is_validating_bw) { - dc_assert_fp_enabled(); + dc_assert_fp_enabled(); - if (is_validating_bw) - v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] *= 2; - else - v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2; + if (is_validating_bw) + v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] *= 2; + else + v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2; } int dcn21_populate_dml_pipes_from_context(struct dc *dc, @@ -2329,7 +2333,7 @@ void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params k++; } - memcpy(dcn2_1_soc.clock_limits, s, sizeof(dcn2_1_soc.clock_limits)); + memcpy(&dcn2_1_soc.clock_limits, s, sizeof(dcn2_1_soc.clock_limits)); if (clk_table->num_entries) { dcn2_1_soc.num_states = clk_table->num_entries + 1; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index 80972ee5e55b..a352c703e258 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -368,7 +368,9 @@ void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) dc_assert_fp_enabled(); if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) { - context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || + context->bw_ctx.dml.soc.dram_clock_change_latency_us == 0) + context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us; context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us; context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us; } @@ -563,6 +565,20 @@ void dcn30_fpu_calculate_wm_and_dlg( pipe_idx++; } + // WA: restrict FPO to use first non-strobe mode (NV24 BW issue) + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching && + dc->dml.soc.num_chans <= 4 && + context->bw_ctx.dml.vba.DRAMSpeed <= 1700 && + context->bw_ctx.dml.vba.DRAMSpeed >= 1500) { + + for (i = 0; i < dc->dml.soc.num_states; i++) { + if (dc->dml.soc.clock_limits[i].dram_speed_mts > 1700) { + context->bw_ctx.dml.vba.DRAMSpeed = dc->dml.soc.clock_limits[i].dram_speed_mts; + break; + } + } + } + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); if (!pstate_en) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c index 44082f65de1f..9e54e3d0eb78 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c @@ -149,8 +149,8 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = { .num_states = 5, .sr_exit_time_us = 16.5, .sr_enter_plus_exit_time_us = 18.5, - .sr_exit_z8_time_us = 210.0, - .sr_enter_plus_exit_z8_time_us = 310.0, + .sr_exit_z8_time_us = 268.0, + .sr_enter_plus_exit_z8_time_us = 393.0, .writeback_latency_us = 12.0, .dram_channel_width_bytes = 4, .round_trip_ping_latency_dcfclk_cycles = 106, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 4548320217fc..47beb4ea779d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -109,7 +109,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { { .state = 0, .dcfclk_mhz = 1564.0, - .fabricclk_mhz = 400.0, + .fabricclk_mhz = 2500.0, .dispclk_mhz = 2150.0, .dppclk_mhz = 2150.0, .phyclk_mhz = 810.0, @@ -117,7 +117,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { .phyclk_d32_mhz = 625.0, .socclk_mhz = 1200.0, .dscclk_mhz = 716.667, - .dram_speed_mts = 16000.0, + .dram_speed_mts = 18000.0, .dtbclk_mhz = 1564.0, }, }, @@ -148,7 +148,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = { .max_avg_fabric_bw_use_normal_percent = 60.0, .max_avg_dram_bw_use_normal_strobe_percent = 50.0, .max_avg_dram_bw_use_normal_percent = 15.0, - .num_chans = 8, + .num_chans = 24, .dram_channel_width_bytes = 2, .fabric_datapath_to_dcn_data_return_bytes = 64, .return_bus_width_bytes = 64, @@ -1331,6 +1331,11 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != dm_dram_clock_change_unsupported; + /* Pstate change might not be supported by hardware, but it might be + * possible with firmware driven vertical blank stretching. + */ + context->bw_ctx.bw.dcn.clk.p_state_change_support |= context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching; + context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context); context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = context->bw_ctx.dml.vba.DTBCLKPerState[vlevel] * 1000; @@ -2871,3 +2876,9 @@ bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, uint } return vactive_found; } + +void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb) +{ + dc_assert_fp_enabled(); + dcn3_2_soc.clock_limits[0].dcfclk_mhz = 1200.0; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h index 9a0806a0e2ef..dcf512cd3072 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h @@ -80,4 +80,6 @@ void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *co bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, uint32_t vactive_margin_req); +void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 13c7e7394b1c..d75248b6cae9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -810,7 +810,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman v->SwathHeightY[k], v->SwathHeightC[k], TWait, - v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ || + v->DCFCLKPerState[mode_lib->vba.VoltageLevel] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ &v->DSTXAfterScaler[k], @@ -3310,7 +3311,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->swath_width_chroma_ub_this_state[k], v->SwathHeightYThisState[k], v->SwathHeightCThisState[k], v->TWait, - v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ ? + (v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKState[i][j] <= MIN_DCFCLK_FREQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, /* Output */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h index 500b3dd6052d..d98e36a9a09c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h @@ -53,6 +53,7 @@ #define BPP_BLENDED_PIPE 0xffffffff #define MEM_STROBE_FREQ_MHZ 1600 +#define MIN_DCFCLK_FREQ_MHZ 200 #define MEM_STROBE_MAX_DELIVERY_TIME_US 60.0 struct display_mode_lib; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index 57b9bd896678..342a1bcb4927 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -106,16 +106,16 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .clock_limits = { { .state = 0, - .dcfclk_mhz = 1564.0, - .fabricclk_mhz = 400.0, - .dispclk_mhz = 2150.0, - .dppclk_mhz = 2150.0, + .dcfclk_mhz = 1434.0, + .fabricclk_mhz = 2250.0, + .dispclk_mhz = 1720.0, + .dppclk_mhz = 1720.0, .phyclk_mhz = 810.0, .phyclk_d18_mhz = 667.0, - .phyclk_d32_mhz = 625.0, + .phyclk_d32_mhz = 313.0, .socclk_mhz = 1200.0, - .dscclk_mhz = 716.667, - .dram_speed_mts = 1600.0, + .dscclk_mhz = 573.333, + .dram_speed_mts = 16000.0, .dtbclk_mhz = 1564.0, }, }, @@ -125,14 +125,14 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { .sr_exit_z8_time_us = 285.0, .sr_enter_plus_exit_z8_time_us = 320, .writeback_latency_us = 12.0, - .round_trip_ping_latency_dcfclk_cycles = 263, + .round_trip_ping_latency_dcfclk_cycles = 207, .urgent_latency_pixel_data_only_us = 4, .urgent_latency_pixel_mixed_with_vm_data_us = 4, .urgent_latency_vm_data_only_us = 4, - .fclk_change_latency_us = 20, - .usr_retraining_latency_us = 2, - .smn_latency_us = 2, - .mall_allocated_for_dcn_mbytes = 64, + .fclk_change_latency_us = 7, + .usr_retraining_latency_us = 0, + .smn_latency_us = 0, + .mall_allocated_for_dcn_mbytes = 32, .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 027ad1f0144d..2267fb097830 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -1927,6 +1927,11 @@ static void disable_link_dp(struct dc_link *link, dp_disable_link_phy(link, link_res, signal); + if (link->connector_signal == SIGNAL_TYPE_EDP) { + if (!link->dc->config.edp_no_power_sequencing) + link->dc->hwss.edp_power_control(link, false); + } + if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) /* set the sink to SST mode after disabling the link */ enable_mst_on_sink(link, false); diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index d4b7da526f0a..e8b2fc4002a5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -359,5 +359,8 @@ bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const un link[i] = stream[i].link; bw_needed[i] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing); } + + ret = dpia_validate_usb4_bw(link, bw_needed, num_streams); + return ret; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index 170f33835930..579fa222810d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -1596,7 +1596,10 @@ bool perform_link_training_with_retries( * Report and continue with eDP panel mode to * perform eDP link training with right settings */ - cp_psp->funcs.enable_assr(cp_psp->handle, link); + bool result; + result = cp_psp->funcs.enable_assr(cp_psp->handle, link); + if (!result && link->panel_mode != DP_PANEL_MODE_EDP) + panel_mode = DP_PANEL_MODE_DEFAULT; } } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index d895046787bc..8d1df863659c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -83,6 +83,7 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) ASSERT(result == DC_OK); } } + link->panel_mode = panel_mode; DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c index a76da0131add..9c20516be066 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn32.c @@ -130,12 +130,13 @@ void dmub_dcn32_reset(struct dmub_srv *dmub) REG_WRITE(DMCUB_INBOX1_WPTR, 0); REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_WPTR, 0); REG_WRITE(DMCUB_SCRATCH0, 0); } void dmub_dcn32_reset_release(struct dmub_srv *dmub) { - REG_WRITE(DMCUB_GPINT_DATAIN1, 0); REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0); REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h index beed70179bb5..23a308c3eccb 100644 --- a/drivers/gpu/drm/amd/display/include/signal_types.h +++ b/drivers/gpu/drm/amd/display/include/signal_types.h @@ -104,6 +104,7 @@ static inline bool dc_is_audio_capable_signal(enum signal_type signal) { return (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + signal == SIGNAL_TYPE_VIRTUAL || dc_is_hdmi_signal(signal)); } diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 300e156b924f..078aaaa53162 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -36,6 +36,8 @@ #define amdgpu_dpm_enable_bapm(adev, e) \ ((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e))) +#define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev)) + int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1460,15 +1462,24 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev, int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev) { - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - struct smu_context *smu = adev->powerplay.pp_handle; + if (is_support_sw_smu(adev)) { + struct smu_context *smu = adev->powerplay.pp_handle; - if ((is_support_sw_smu(adev) && smu->od_enabled) || - (is_support_sw_smu(adev) && smu->is_apu) || - (!is_support_sw_smu(adev) && hwmgr->od_enabled)) - return true; + return (smu->od_enabled || smu->is_apu); + } else { + struct pp_hwmgr *hwmgr; - return false; + /* + * dpm on some legacy asics don't carry od_enabled member + * as its pp_handle is casted directly from adev. + */ + if (amdgpu_dpm_is_legacy_dpm(adev)) + return false; + + hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle; + + return hwmgr->od_enabled; + } } int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 58c2246918fd..f4f40459f22b 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -871,13 +871,11 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, } if (ret == -ENOENT) { size = amdgpu_dpm_print_clock_levels(adev, OD_SCLK, buf); - if (size > 0) { - size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_VDDC_CURVE, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_VDDGFX_OFFSET, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf + size); - size += amdgpu_dpm_print_clock_levels(adev, OD_CCLK, buf + size); - } + size += amdgpu_dpm_print_clock_levels(adev, OD_MCLK, buf + size); + size += amdgpu_dpm_print_clock_levels(adev, OD_VDDC_CURVE, buf + size); + size += amdgpu_dpm_print_clock_levels(adev, OD_VDDGFX_OFFSET, buf + size); + size += amdgpu_dpm_print_clock_levels(adev, OD_RANGE, buf + size); + size += amdgpu_dpm_print_clock_levels(adev, OD_CCLK, buf + size); } if (size == 0) diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c index d6d9e3b1b2c0..02e69ccff3ba 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -6925,23 +6925,6 @@ static int si_dpm_enable(struct amdgpu_device *adev) return 0; } -static int si_set_temperature_range(struct amdgpu_device *adev) -{ - int ret; - - ret = si_thermal_enable_alert(adev, false); - if (ret) - return ret; - ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - ret = si_thermal_enable_alert(adev, true); - if (ret) - return ret; - - return ret; -} - static void si_dpm_disable(struct amdgpu_device *adev) { struct rv7xx_power_info *pi = rv770_get_pi(adev); @@ -7626,18 +7609,6 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev, static int si_dpm_late_init(void *handle) { - int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->pm.dpm_enabled) - return 0; - - ret = si_set_temperature_range(adev); - if (ret) - return ret; -#if 0 //TODO ? - si_dpm_powergate_uvd(adev, true); -#endif return 0; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 5633c5797e85..2ddf5198e5c4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -733,6 +733,24 @@ static int smu_late_init(void *handle) return ret; } + /* + * Explicitly notify PMFW the power mode the system in. Since + * the PMFW may boot the ASIC with a different mode. + * For those supporting ACDC switch via gpio, PMFW will + * handle the switch automatically. Driver involvement + * is unnecessary. + */ + if (!smu->dc_controlled_by_gpio) { + ret = smu_set_power_source(smu, + adev->pm.ac_power ? SMU_POWER_SOURCE_AC : + SMU_POWER_SOURCE_DC); + if (ret) { + dev_err(adev->dev, "Failed to switch to %s mode!\n", + adev->pm.ac_power ? "AC" : "DC"); + return ret; + } + } + if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 1)) || (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 3))) return 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 7944ce80e5c3..df3baaab0037 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -62,8 +62,8 @@ #define CTF_OFFSET_HOTSPOT 5 #define CTF_OFFSET_MEM 5 -static const int pmfw_decoded_link_speed[5] = {1, 2, 3, 4, 5}; -static const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; +extern const int pmfw_decoded_link_speed[5]; +extern const int pmfw_decoded_link_width[7]; #define DECODE_GEN_SPEED(gen_speed_idx) (pmfw_decoded_link_speed[gen_speed_idx]) #define DECODE_LANE_WIDTH(lane_width_idx) (pmfw_decoded_link_width[lane_width_idx]) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index c4000518dc56..275f708db636 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3413,26 +3413,8 @@ static int navi10_post_smu_init(struct smu_context *smu) return 0; ret = navi10_run_umc_cdr_workaround(smu); - if (ret) { + if (ret) dev_err(adev->dev, "Failed to apply umc cdr workaround!\n"); - return ret; - } - - if (!smu->dc_controlled_by_gpio) { - /* - * For Navi1X, manually switch it to AC mode as PMFW - * may boot it with DC mode. - */ - ret = smu_v11_0_set_power_source(smu, - adev->pm.ac_power ? - SMU_POWER_SOURCE_AC : - SMU_POWER_SOURCE_DC); - if (ret) { - dev_err(adev->dev, "Failed to switch to %s mode!\n", - adev->pm.ac_power ? "AC" : "DC"); - return ret; - } - } return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 7433dcaa16e0..067b4e0b026c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -582,7 +582,7 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu, DpmClocks_t *clk_table = smu->smu_table.clocks_table; SmuMetrics_legacy_t metrics; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; bool cur_value_match_level = false; @@ -656,7 +656,8 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu, case SMU_MCLK: case SMU_FCLK: for (i = 0; i < count; i++) { - ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value); + idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = vangogh_get_dpm_clk_limited(smu, clk_type, idx, &value); if (ret) return ret; if (!value) @@ -683,7 +684,7 @@ static int vangogh_print_clk_levels(struct smu_context *smu, DpmClocks_t *clk_table = smu->smu_table.clocks_table; SmuMetrics_t metrics; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; bool cur_value_match_level = false; uint32_t min, max; @@ -765,7 +766,8 @@ static int vangogh_print_clk_levels(struct smu_context *smu, case SMU_MCLK: case SMU_FCLK: for (i = 0; i < count; i++) { - ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value); + idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = vangogh_get_dpm_clk_limited(smu, clk_type, idx, &value); if (ret) return ret; if (!value) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 5cdc07165480..8a8ba25c9ad7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -494,7 +494,7 @@ static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu) static int renoir_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0; SmuMetrics_t metrics; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); @@ -594,7 +594,8 @@ static int renoir_print_clk_levels(struct smu_context *smu, case SMU_VCLK: case SMU_DCLK: for (i = 0; i < count; i++) { - ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value); + idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = renoir_get_dpm_clk_limited(smu, clk_type, idx, &value); if (ret) return ret; if (!value) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 73175c993da9..393c6a7b9609 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -85,6 +85,9 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_10.bin"); static const int link_width[] = {0, 1, 2, 4, 8, 12, 16}; static const int link_speed[] = {25, 50, 80, 160}; +const int pmfw_decoded_link_speed[5] = {1, 2, 3, 4, 5}; +const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; + int smu_v13_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 8fa9a36c38b6..6d9760eac16d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -478,7 +478,7 @@ static int smu_v13_0_4_get_dpm_level_count(struct smu_context *smu, static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; @@ -512,7 +512,8 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu, break; for (i = 0; i < count; i++) { - ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, i, &value); + idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) break; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index 66445964efbd..0081fa607e02 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -866,7 +866,7 @@ out: static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min = 0, max = 0; @@ -898,7 +898,8 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu, goto print_clk_out; for (i = 0; i < count; i++) { - ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, i, &value); + idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) goto print_clk_out; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 3d9ff46706fb..bba621615abf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -125,6 +125,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), + MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), }; static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = { @@ -1770,6 +1771,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost, .get_power_limit = smu_v13_0_7_get_power_limit, .set_power_limit = smu_v13_0_set_power_limit, + .set_power_source = smu_v13_0_set_power_source, .get_power_profile_mode = smu_v13_0_7_get_power_profile_mode, .set_power_profile_mode = smu_v13_0_7_set_power_profile_mode, .set_tool_table_location = smu_v13_0_set_tool_table_location, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 04e56b0b3033..798f36cfcebd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1000,7 +1000,7 @@ out: static int yellow_carp_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { - int i, size = 0, ret = 0; + int i, idx, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; @@ -1033,7 +1033,8 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu, goto print_clk_out; for (i = 0; i < count; i++) { - ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, i, &value); + idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i; + ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) goto print_clk_out; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 794ffd4a29c5..f32ce29edba7 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -425,11 +425,12 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, return ERR_PTR(-EIO); /* - * If we don't have IO space at all, use MMIO now and - * assume the chip has MMIO enabled by default (rev 0x20 - * and higher). + * After AST2500, MMIO is enabled by default, and it should be adopted + * to be compatible with Arm. */ - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { + if (pdev->revision >= 0x40) { + ast->ioregs = ast->regs + AST_IO_MM_OFFSET; + } else if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { drm_info(dev, "platform has no IO space, trying MMIO\n"); ast->ioregs = ast->regs + AST_IO_MM_OFFSET; } diff --git a/drivers/gpu/drm/display/drm_dp_aux_dev.c b/drivers/gpu/drm/display/drm_dp_aux_dev.c index 098e482e65a2..29555b9f03c8 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/display/drm_dp_aux_dev.c @@ -330,7 +330,7 @@ int drm_dp_aux_dev_init(void) { int res; - drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev"); + drm_dp_aux_dev_class = class_create("drm_dp_aux_dev"); if (IS_ERR(drm_dp_aux_dev_class)) { return PTR_ERR(drm_dp_aux_dev_class); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 64458982be40..6bb1b8b27d7a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -641,19 +641,27 @@ static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, size_t len, struct drm_rect *clip) { + u32 line_length = info->fix.line_length; + u32 fb_height = info->var.yres; off_t end = off + len; u32 x1 = 0; - u32 y1 = off / info->fix.line_length; + u32 y1 = off / line_length; u32 x2 = info->var.xres; - u32 y2 = DIV_ROUND_UP(end, info->fix.line_length); + u32 y2 = DIV_ROUND_UP(end, line_length); + + /* Don't allow any of them beyond the bottom bound of display area */ + if (y1 > fb_height) + y1 = fb_height; + if (y2 > fb_height) + y2 = fb_height; if ((y2 - y1) == 1) { /* * We've only written to a single scanline. Try to reduce * the number of horizontal pixels that need an update. */ - off_t bit_off = (off % info->fix.line_length) * 8; - off_t bit_end = (end % info->fix.line_length) * 8; + off_t bit_off = (off % line_length) * 8; + off_t bit_end = (end % line_length) * 8; x1 = bit_off / info->var.bits_per_pixel; x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel); diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c index 4cf214de50c4..c21c3f623033 100644 --- a/drivers/gpu/drm/drm_managed.c +++ b/drivers/gpu/drm/drm_managed.c @@ -264,28 +264,10 @@ void drmm_kfree(struct drm_device *dev, void *data) } EXPORT_SYMBOL(drmm_kfree); -static void drmm_mutex_release(struct drm_device *dev, void *res) +void __drmm_mutex_release(struct drm_device *dev, void *res) { struct mutex *lock = res; mutex_destroy(lock); } - -/** - * drmm_mutex_init - &drm_device-managed mutex_init() - * @dev: DRM device - * @lock: lock to be initialized - * - * Returns: - * 0 on success, or a negative errno code otherwise. - * - * This is a &drm_device-managed version of mutex_init(). The initialized - * lock is automatically destroyed on the final drm_dev_put(). - */ -int drmm_mutex_init(struct drm_device *dev, struct mutex *lock) -{ - mutex_init(lock); - - return drmm_add_action_or_reset(dev, drmm_mutex_release, lock); -} -EXPORT_SYMBOL(drmm_mutex_init); +EXPORT_SYMBOL(__drmm_mutex_release); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 7900a4707d7c..3fd6c733ff4e 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -160,7 +160,7 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg; - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + if (of_alias_from_compatible(node, info.type, sizeof(info.type)) < 0) { drm_err(host, "modalias failure on %pOF\n", node); return ERR_PTR(-EINVAL); } @@ -221,7 +221,7 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host, return dsi; } - dsi->dev.of_node = info->node; + device_set_node(&dsi->dev, of_fwnode_handle(info->node)); dsi->channel = info->channel; strlcpy(dsi->name, info->type, sizeof(dsi->name)); diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index b1a38e6ce2f8..0cb646cb04ee 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -179,7 +179,7 @@ static const struct dmi_system_id orientation_data[] = { }, { /* AYA NEO AIR */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO"), - DMI_MATCH(DMI_BOARD_NAME, "AIR"), + DMI_MATCH(DMI_PRODUCT_NAME, "AIR"), }, .driver_data = (void *)&lcd1080x1920_leftside_up, }, { /* AYA NEO NEXT */ diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 183130355997..3c22a803201d 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -112,7 +112,7 @@ int drm_sysfs_init(void) { int err; - drm_class = class_create(THIS_MODULE, "drm"); + drm_class = class_create("drm"); if (IS_ERR(drm_class)) return PTR_ERR(drm_class); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h index 74ea3c26dead..1a5ae781b56c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.h +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h @@ -34,11 +34,11 @@ static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, return -ENODEV; } -int g2d_open(struct drm_device *drm_dev, struct drm_file *file) +static inline int g2d_open(struct drm_device *drm_dev, struct drm_file *file) { return 0; } -void g2d_close(struct drm_device *drm_dev, struct drm_file *file) +static inline void g2d_close(struct drm_device *drm_dev, struct drm_file *file) { } #endif diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 06a0ca157e89..e4f4d2e3fdfe 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -62,10 +62,11 @@ config DRM_I915_FORCE_PROBE This is the default value for the i915.force_probe module parameter. Using the module parameter overrides this option. - Force probe the i915 for Intel graphics devices that are - recognized but not properly supported by this kernel version. It is - recommended to upgrade to a kernel version with proper support as soon - as it is available. + Force probe the i915 driver for Intel graphics devices that are + recognized but not properly supported by this kernel version. Force + probing an unsupported device taints the kernel. It is recommended to + upgrade to a kernel version with proper support as soon as it is + available. It can also be used to block the probe of recognized and fully supported devices. @@ -75,7 +76,8 @@ config DRM_I915_FORCE_PROBE Use "[,,...]" to force probe the i915 for listed devices. For example, "4500" or "4500,4571". - Use "*" to force probe the driver for all known devices. + Use "*" to force probe the driver for all known devices. Not + recommended. Use "!" right before the ID to block the probe of the device. For example, "4500,!4571" forces the probe of 4500 and blocks the probe of diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index ad78148e0788..c9aeba0ecf91 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1140,7 +1140,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) /* panel power on related mipi dsi vbt sequences */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); - intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); + msleep(intel_dsi->panel_on_delay); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 40de9f0f171b..f33164b10292 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -1028,7 +1028,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, int ret; if (old_obj) { - const struct intel_crtc_state *crtc_state = + const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, to_intel_crtc(old_plane_state->hw.crtc)); @@ -1043,7 +1043,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, * This should only fail upon a hung GPU, in which case we * can safely continue. */ - if (intel_crtc_needs_modeset(crtc_state)) { + if (new_crtc_state && intel_crtc_needs_modeset(new_crtc_state)) { ret = i915_sw_fence_await_reservation(&state->commit_ready, old_obj->base.resv, false, 0, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3c29792137a5..0aae9a1eb3d5 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1851,9 +1851,17 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, intel_disable_shared_dpll(old_crtc_state); - intel_encoders_post_pll_disable(state, crtc); + if (!intel_crtc_is_bigjoiner_slave(old_crtc_state)) { + struct intel_crtc *slave_crtc; - intel_dmc_disable_pipe(i915, crtc->pipe); + intel_encoders_post_pll_disable(state, crtc); + + intel_dmc_disable_pipe(i915, crtc->pipe); + + for_each_intel_crtc_in_pipe_mask(&i915->drm, slave_crtc, + intel_crtc_bigjoiner_slave_pipes(old_crtc_state)) + intel_dmc_disable_pipe(i915, slave_crtc->pipe); + } } static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index f0bace9d98a1..529ee22be872 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1601,6 +1601,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->dsc.slice_count = drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, true); + if (!pipe_config->dsc.slice_count) { + drm_dbg_kms(&dev_priv->drm, "Unsupported Slice Count %d\n", + pipe_config->dsc.slice_count); + return -EINVAL; + } } else { u16 dsc_max_output_bpp = 0; u8 dsc_dp_slice_count; diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 695b0d69a4cb..c7935ea498c4 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -763,17 +763,6 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 0); } -void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) -{ - struct intel_connector *connector = intel_dsi->attached_connector; - - /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ - if (is_vid_mode(intel_dsi) && connector->panel.vbt.dsi.seq_version >= 3) - return; - - msleep(msec); -} - void intel_dsi_log_params(struct intel_dsi *intel_dsi) { struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h index dc642c1fe7ef..468d873fab1a 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h @@ -16,7 +16,6 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on); void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi); void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, enum mipi_seq seq_id); -void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec); void intel_dsi_log_params(struct intel_dsi *intel_dsi); #endif /* __INTEL_DSI_VBT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 650232c4892b..b183efab04a1 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -204,8 +204,6 @@ bool intel_hdcp2_capable(struct intel_connector *connector) struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; - struct intel_gt *gt = dev_priv->media_gt; - struct intel_gsc_uc *gsc = >->uc.gsc; bool capable = false; /* I915 support for HDCP2.2 */ @@ -213,9 +211,13 @@ bool intel_hdcp2_capable(struct intel_connector *connector) return false; /* If MTL+ make sure gsc is loaded and proxy is setup */ - if (intel_hdcp_gsc_cs_required(dev_priv)) - if (!intel_uc_fw_is_running(&gsc->fw)) + if (intel_hdcp_gsc_cs_required(dev_priv)) { + struct intel_gt *gt = dev_priv->media_gt; + struct intel_gsc_uc *gsc = gt ? >->uc.gsc : NULL; + + if (!gsc || !intel_uc_fw_is_running(&gsc->fw)) return false; + } /* MEI/GSC interface is solid depending on which is used */ mutex_lock(&dev_priv->display.hdcp.comp_mutex); diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index 473d53610b92..0e7e014fcc71 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -111,6 +111,8 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); int min_src_w, min_src_h, min_dst_w, min_dst_h; int max_src_w, max_src_h, max_dst_w, max_dst_h; @@ -207,6 +209,21 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, return -EINVAL; } + /* + * The pipe scaler does not use all the bits of PIPESRC, at least + * on the earlier platforms. So even when we're scaling a plane + * the *pipe* source size must not be too large. For simplicity + * we assume the limits match the scaler source size limits. Might + * not be 100% accurate on all platforms, but good enough for now. + */ + if (pipe_src_w > max_src_w || pipe_src_h > max_src_h) { + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: pipe src size %ux%u " + "is out of scaler range\n", + crtc->pipe, scaler_user, pipe_src_w, pipe_src_h); + return -EINVAL; + } + /* mark this plane as a scaler user in crtc_state */ scaler_state->scaler_users |= (1 << scaler_user); drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 028965ab442d..61d008d4e5f1 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -737,7 +737,6 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, { struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); - struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum port port; @@ -779,21 +778,10 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, if (!IS_GEMINILAKE(dev_priv)) intel_dsi_prepare(encoder, pipe_config); + /* Give the panel time to power-on and then deassert its reset */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); - - /* - * Give the panel time to power-on and then deassert its reset. - * Depending on the VBT MIPI sequences version the deassert-seq - * may contain the necessary delay, intel_dsi_msleep() will skip - * the delay in that case. If there is no deassert-seq, then an - * unconditional msleep is used to give the panel time to power-on. - */ - if (connector->panel.vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) { - intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); - intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); - } else { - msleep(intel_dsi->panel_on_delay); - } + msleep(intel_dsi->panel_on_delay); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); if (IS_GEMINILAKE(dev_priv)) { glk_cold_boot = glk_dsi_enable_io(encoder); @@ -827,7 +815,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, msleep(20); /* XXX */ for_each_dsi_port(port, intel_dsi->ports) dpi_send_cmd(intel_dsi, TURN_ON, false, port); - intel_dsi_msleep(intel_dsi, 100); + msleep(100); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); @@ -949,7 +937,7 @@ static void intel_dsi_post_disable(struct intel_atomic_state *state, /* Assert reset */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET); - intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay); + msleep(intel_dsi->panel_off_delay); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); intel_dsi->panel_power_off_time = ktime_get_boottime(); diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index defece0bcb81..99f39a5feca1 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -115,7 +115,7 @@ static int get_huge_pages(struct drm_i915_gem_object *obj) do { struct page *page; - GEM_BUG_ON(order >= MAX_ORDER); + GEM_BUG_ON(order > MAX_ORDER); page = alloc_pages(GFP | __GFP_ZERO, order); if (!page) goto err; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index cf49188db6a6..e0e793167d61 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -31,12 +31,14 @@ { FORCEWAKE_MT, 0, 0, "FORCEWAKE" } #define COMMON_GEN9BASE_GLOBAL \ - { GEN8_FAULT_TLB_DATA0, 0, 0, "GEN8_FAULT_TLB_DATA0" }, \ - { GEN8_FAULT_TLB_DATA1, 0, 0, "GEN8_FAULT_TLB_DATA1" }, \ { ERROR_GEN6, 0, 0, "ERROR_GEN6" }, \ { DONE_REG, 0, 0, "DONE_REG" }, \ { HSW_GTT_CACHE_EN, 0, 0, "HSW_GTT_CACHE_EN" } +#define GEN9_GLOBAL \ + { GEN8_FAULT_TLB_DATA0, 0, 0, "GEN8_FAULT_TLB_DATA0" }, \ + { GEN8_FAULT_TLB_DATA1, 0, 0, "GEN8_FAULT_TLB_DATA1" } + #define COMMON_GEN12BASE_GLOBAL \ { GEN12_FAULT_TLB_DATA0, 0, 0, "GEN12_FAULT_TLB_DATA0" }, \ { GEN12_FAULT_TLB_DATA1, 0, 0, "GEN12_FAULT_TLB_DATA1" }, \ @@ -142,6 +144,7 @@ static const struct __guc_mmio_reg_descr xe_lpd_gsc_inst_regs[] = { static const struct __guc_mmio_reg_descr default_global_regs[] = { COMMON_BASE_GLOBAL, COMMON_GEN9BASE_GLOBAL, + GEN9_GLOBAL, }; static const struct __guc_mmio_reg_descr default_rc_class_regs[] = { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index aefdaa62da99..04724ff56ded 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -190,7 +190,7 @@ static int gsc_notifier(struct notifier_block *nb, unsigned long action, void *d return 0; } -void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +void intel_huc_register_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { int ret; @@ -206,7 +206,7 @@ void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus } } -void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus) { if (!huc->delayed_load.nb.notifier_call) return; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index db555b3c1f56..0789184d81a2 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -52,8 +52,8 @@ int intel_huc_check_status(struct intel_huc *huc); void intel_huc_update_auth_status(struct intel_huc *huc); bool intel_huc_is_authenticated(struct intel_huc *huc); -void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); -void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); +void intel_huc_register_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus); +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, const struct bus_type *bus); static inline bool intel_huc_is_supported(struct intel_huc *huc) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 24765c30a0e1..c36e68e23a14 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -635,9 +635,10 @@ static bool is_ver_8bit(struct intel_uc_fw_ver *ver) return ver->major < 0xFF && ver->minor < 0xFF && ver->patch < 0xFF; } -static bool guc_check_version_range(struct intel_uc_fw *uc_fw) +static int guc_check_version_range(struct intel_uc_fw *uc_fw) { struct intel_guc *guc = container_of(uc_fw, struct intel_guc, fw); + struct intel_gt *gt = __uc_fw_to_gt(uc_fw); /* * GuC version number components are defined as being 8-bits. @@ -646,24 +647,24 @@ static bool guc_check_version_range(struct intel_uc_fw *uc_fw) */ if (!is_ver_8bit(&uc_fw->file_selected.ver)) { - gt_warn(__uc_fw_to_gt(uc_fw), "%s firmware: invalid file version: 0x%02X:%02X:%02X\n", + gt_warn(gt, "%s firmware: invalid file version: 0x%02X:%02X:%02X\n", intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.ver.major, uc_fw->file_selected.ver.minor, uc_fw->file_selected.ver.patch); - return false; + return -EINVAL; } if (!is_ver_8bit(&guc->submission_version)) { - gt_warn(__uc_fw_to_gt(uc_fw), "%s firmware: invalid submit version: 0x%02X:%02X:%02X\n", + gt_warn(gt, "%s firmware: invalid submit version: 0x%02X:%02X:%02X\n", intel_uc_fw_type_repr(uc_fw->type), guc->submission_version.major, guc->submission_version.minor, guc->submission_version.patch); - return false; + return -EINVAL; } - return true; + return i915_inject_probe_error(gt->i915, -EINVAL); } static int check_fw_header(struct intel_gt *gt, @@ -772,8 +773,11 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) if (err) goto fail; - if (uc_fw->type == INTEL_UC_FW_TYPE_GUC && !guc_check_version_range(uc_fw)) - goto fail; + if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) { + err = guc_check_version_range(uc_fw); + if (err) + goto fail; + } if (uc_fw->file_wanted.ver.major && uc_fw->file_selected.ver.major) { /* Check the file's major version was as it claimed */ diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index cddb6e197972..edcfb5fe20b2 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1134,6 +1134,8 @@ static const struct intel_gt_definition xelpmp_extra_gt[] = { static const struct intel_device_info mtl_info = { XE_HP_FEATURES, XE_LPDP_FEATURES, + .__runtime.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D), /* * Real graphics IP version will be obtained from hardware GMD_ID * register. Value provided here is just for sanity checking. @@ -1342,6 +1344,12 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENODEV; } + if (intel_info->require_force_probe) { + dev_info(&pdev->dev, "Force probing unsupported Device ID %04x, tainting kernel\n", + pdev->device); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } + /* Only bind to function 0 of the device. Early generations * used function 1 as a placeholder for multi-head. This causes * us confusion instead, especially on the systems where both diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 050b8ae7b8e7..3035cba2c6a2 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -877,12 +877,17 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, stream->oa_buffer.last_ctx_id = ctx_id; } - /* - * Clear out the report id and timestamp as a means to detect unlanded - * reports. - */ - oa_report_id_clear(stream, report32); - oa_timestamp_clear(stream, report32); + if (is_power_of_2(report_size)) { + /* + * Clear out the report id and timestamp as a means + * to detect unlanded reports. + */ + oa_report_id_clear(stream, report32); + oa_timestamp_clear(stream, report32); + } else { + /* Zero out the entire report */ + memset(report32, 0, report_size); + } } if (start_offset != *offset) { diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0f2dd26755df..af3ce5a6a636 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -642,6 +642,11 @@ void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_ if (funcs->pixpllc_atomic_update) funcs->pixpllc_atomic_update(crtc, old_state); + if (crtc_state->gamma_lut) + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, format); + mgag200_enable_display(mdev); if (funcs->enable_vidrst) diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index 2b3ae84057df..bdcd554fc8a8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -98,17 +98,17 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { static const struct dpu_lm_cfg msm8998_lm[] = { LM_BLK("lm_0", LM_0, 0x44000, MIXER_MSM8998_MASK, - &msm8998_lm_sblk, PINGPONG_0, LM_2, DSPP_0), + &msm8998_lm_sblk, PINGPONG_0, LM_1, DSPP_0), LM_BLK("lm_1", LM_1, 0x45000, MIXER_MSM8998_MASK, - &msm8998_lm_sblk, PINGPONG_1, LM_5, DSPP_1), + &msm8998_lm_sblk, PINGPONG_1, LM_0, DSPP_1), LM_BLK("lm_2", LM_2, 0x46000, MIXER_MSM8998_MASK, - &msm8998_lm_sblk, PINGPONG_2, LM_0, 0), + &msm8998_lm_sblk, PINGPONG_2, LM_5, 0), LM_BLK("lm_3", LM_3, 0x47000, MIXER_MSM8998_MASK, &msm8998_lm_sblk, PINGPONG_MAX, 0, 0), LM_BLK("lm_4", LM_4, 0x48000, MIXER_MSM8998_MASK, &msm8998_lm_sblk, PINGPONG_MAX, 0, 0), LM_BLK("lm_5", LM_5, 0x49000, MIXER_MSM8998_MASK, - &msm8998_lm_sblk, PINGPONG_3, LM_1, 0), + &msm8998_lm_sblk, PINGPONG_3, LM_2, 0), }; static const struct dpu_pingpong_cfg msm8998_pp[] = { @@ -134,10 +134,10 @@ static const struct dpu_dspp_cfg msm8998_dspp[] = { }; static const struct dpu_intf_cfg msm8998_intf[] = { - INTF_BLK("intf_0", INTF_0, 0x6a000, 0x280, INTF_DP, 0, 25, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 24, 25), - INTF_BLK("intf_1", INTF_1, 0x6a800, 0x280, INTF_DSI, 0, 25, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 26, 27), - INTF_BLK("intf_2", INTF_2, 0x6b000, 0x280, INTF_DSI, 1, 25, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 28, 29), - INTF_BLK("intf_3", INTF_3, 0x6b800, 0x280, INTF_HDMI, 0, 25, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 30, 31), + INTF_BLK("intf_0", INTF_0, 0x6a000, 0x280, INTF_DP, 0, 21, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_1", INTF_1, 0x6a800, 0x280, INTF_DSI, 0, 21, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 26, 27), + INTF_BLK("intf_2", INTF_2, 0x6b000, 0x280, INTF_DSI, 1, 21, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 28, 29), + INTF_BLK("intf_3", INTF_3, 0x6b800, 0x280, INTF_HDMI, 0, 21, INTF_SDM845_MASK, MDP_SSPP_TOP0_INTR, 30, 31), }; static const struct dpu_perf_cfg msm8998_perf_data = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index 282d410269ff..42b0e58624d0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -128,10 +128,10 @@ static const struct dpu_dspp_cfg sm8150_dspp[] = { }; static const struct dpu_pingpong_cfg sm8150_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), PP_BLK("pingpong_2", PINGPONG_2, 0x71000, MERGE_3D_1, sdm845_pp_sblk, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index c57400265f28..e3bdfe7b30f1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -116,10 +116,10 @@ static const struct dpu_lm_cfg sc8180x_lm[] = { }; static const struct dpu_pingpong_cfg sc8180x_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), PP_BLK("pingpong_2", PINGPONG_2, 0x71000, MERGE_3D_1, sdm845_pp_sblk, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 2c40229ea515..ed130582873c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -129,10 +129,10 @@ static const struct dpu_dspp_cfg sm8250_dspp[] = { }; static const struct dpu_pingpong_cfg sm8250_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK("pingpong_1", PINGPONG_1, 0x70800, MERGE_3D_0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), PP_BLK("pingpong_2", PINGPONG_2, 0x71000, MERGE_3D_1, sdm845_pp_sblk, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index 8799ed757119..a46b11730a4d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -80,8 +80,8 @@ static const struct dpu_dspp_cfg sc7180_dspp[] = { }; static const struct dpu_pingpong_cfg sc7180_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk_te, -1, -1), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, 0, sdm845_pp_sblk_te, -1, -1), + PP_BLK("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk, -1, -1), + PP_BLK("pingpong_1", PINGPONG_1, 0x70800, 0, sdm845_pp_sblk, -1, -1), }; static const struct dpu_intf_cfg sc7180_intf[] = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 6f04d8f85c92..988d820f7ef2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -122,7 +122,6 @@ const struct dpu_mdss_cfg dpu_sm6115_cfg = { .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ BIT(MDP_SSPP_TOP0_INTR2) | \ BIT(MDP_SSPP_TOP0_HIST_INTR) | \ - BIT(MDP_INTF0_INTR) | \ BIT(MDP_INTF1_INTR), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h index 303492d62a5c..c9003dcc1a59 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h @@ -112,7 +112,6 @@ const struct dpu_mdss_cfg dpu_qcm2290_cfg = { .mdss_irqs = BIT(MDP_SSPP_TOP0_INTR) | \ BIT(MDP_SSPP_TOP0_INTR2) | \ BIT(MDP_SSPP_TOP0_HIST_INTR) | \ - BIT(MDP_INTF0_INTR) | \ BIT(MDP_INTF1_INTR), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index ca107ca8de46..4f6a965bcd90 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -127,22 +127,22 @@ static const struct dpu_dspp_cfg sm8350_dspp[] = { }; static const struct dpu_pingpong_cfg sm8350_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK_DITHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK_DITHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), - PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)), - PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)), - PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), - PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 5957de185984..6b2c7eae71d9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -87,10 +87,10 @@ static const struct dpu_dspp_cfg sc7280_dspp[] = { }; static const struct dpu_pingpong_cfg sc7280_pp[] = { - PP_BLK("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK_DITHER("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK_DITHER("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK_DITHER("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK_DITHER("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), }; static const struct dpu_intf_cfg sc7280_intf[] = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 9aab110b8c44..706d0f13b598 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -121,18 +121,18 @@ static const struct dpu_dspp_cfg sc8280xp_dspp[] = { }; static const struct dpu_pingpong_cfg sc8280xp_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), -1), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), -1), - PP_BLK_TE("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), -1), - PP_BLK_TE("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), -1), - PP_BLK_TE("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), - PP_BLK_TE("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk_te, - DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), + PP_BLK_DITHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), -1), + PP_BLK_DITHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), -1), + PP_BLK_DITHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), -1), + PP_BLK_DITHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), -1), + PP_BLK_DITHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), + PP_BLK_DITHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, + DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), }; static const struct dpu_merge_3d_cfg sc8280xp_merge_3d[] = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 02a259b6b426..4ecb3df5cbc0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -128,28 +128,28 @@ static const struct dpu_dspp_cfg sm8450_dspp[] = { }; /* FIXME: interrupts */ static const struct dpu_pingpong_cfg sm8450_pp[] = { - PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK_DITHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)), - PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te, + PP_BLK_DITHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)), - PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)), - PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)), - PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), - PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), - PP_BLK("pingpong_6", PINGPONG_6, 0x65800, MERGE_3D_3, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_6", PINGPONG_6, 0x65800, MERGE_3D_3, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_7", PINGPONG_7, 0x65c00, MERGE_3D_3, sdm845_pp_sblk, + PP_BLK_DITHER("pingpong_7", PINGPONG_7, 0x65c00, MERGE_3D_3, sc7280_pp_sblk, -1, -1), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 9e403034093f..d0ab351b6a8b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -132,28 +132,28 @@ static const struct dpu_dspp_cfg sm8550_dspp[] = { &sm8150_dspp_sblk), }; static const struct dpu_pingpong_cfg sm8550_pp[] = { - PP_BLK_DIPHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), -1), - PP_BLK_DIPHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), -1), - PP_BLK_DIPHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), -1), - PP_BLK_DIPHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), -1), - PP_BLK_DIPHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1), - PP_BLK_DIPHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1), - PP_BLK_DIPHER("pingpong_6", PINGPONG_6, 0x66000, MERGE_3D_3, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_6", PINGPONG_6, 0x66000, MERGE_3D_3, sc7280_pp_sblk, -1, -1), - PP_BLK_DIPHER("pingpong_7", PINGPONG_7, 0x66400, MERGE_3D_3, sc7280_pp_sblk, + PP_BLK_DITHER("pingpong_7", PINGPONG_7, 0x66400, MERGE_3D_3, sc7280_pp_sblk, -1, -1), }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 03f162af1a50..5d994bce696f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -491,7 +491,7 @@ static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = { .len = 0x20, .version = 0x20000}, }; -#define PP_BLK_DIPHER(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \ +#define PP_BLK_DITHER(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \ {\ .name = _name, .id = _id, \ .base = _base, .len = 0, \ @@ -587,12 +587,12 @@ static const u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { { - .pps = 1088 * 1920 * 30, + .pps = 1920 * 1080 * 30, .ot_limit = 2, }, { - .pps = 1088 * 1920 * 60, - .ot_limit = 6, + .pps = 1920 * 1080 * 60, + .ot_limit = 4, }, { .pps = 3840 * 2160 * 30, @@ -705,10 +705,7 @@ static const struct dpu_qos_lut_entry msm8998_qos_linear[] = { {.fl = 10, .lut = 0x1555b}, {.fl = 11, .lut = 0x5555b}, {.fl = 12, .lut = 0x15555b}, - {.fl = 13, .lut = 0x55555b}, - {.fl = 14, .lut = 0}, - {.fl = 1, .lut = 0x1b}, - {.fl = 0, .lut = 0} + {.fl = 0, .lut = 0x55555b} }; static const struct dpu_qos_lut_entry sdm845_qos_linear[] = { @@ -730,9 +727,7 @@ static const struct dpu_qos_lut_entry msm8998_qos_macrotile[] = { {.fl = 10, .lut = 0x1aaff}, {.fl = 11, .lut = 0x5aaff}, {.fl = 12, .lut = 0x15aaff}, - {.fl = 13, .lut = 0x55aaff}, - {.fl = 1, .lut = 0x1aaff}, - {.fl = 0, .lut = 0}, + {.fl = 0, .lut = 0x55aaff}, }; static const struct dpu_qos_lut_entry sc7180_qos_linear[] = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 53326f25e40e..17f3e7e4f194 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -15,7 +15,7 @@ /* * Register offsets in MDSS register file for the interrupt registers - * w.r.t. to the MDP base + * w.r.t. the MDP base */ #define MDP_SSPP_TOP0_OFF 0x0 #define MDP_INTF_0_OFF 0x6A000 @@ -24,20 +24,23 @@ #define MDP_INTF_3_OFF 0x6B800 #define MDP_INTF_4_OFF 0x6C000 #define MDP_INTF_5_OFF 0x6C800 +#define INTF_INTR_EN 0x1c0 +#define INTF_INTR_STATUS 0x1c4 +#define INTF_INTR_CLEAR 0x1c8 #define MDP_AD4_0_OFF 0x7C000 #define MDP_AD4_1_OFF 0x7D000 #define MDP_AD4_INTR_EN_OFF 0x41c #define MDP_AD4_INTR_CLEAR_OFF 0x424 #define MDP_AD4_INTR_STATUS_OFF 0x420 -#define MDP_INTF_0_OFF_REV_7xxx 0x34000 -#define MDP_INTF_1_OFF_REV_7xxx 0x35000 -#define MDP_INTF_2_OFF_REV_7xxx 0x36000 -#define MDP_INTF_3_OFF_REV_7xxx 0x37000 -#define MDP_INTF_4_OFF_REV_7xxx 0x38000 -#define MDP_INTF_5_OFF_REV_7xxx 0x39000 -#define MDP_INTF_6_OFF_REV_7xxx 0x3a000 -#define MDP_INTF_7_OFF_REV_7xxx 0x3b000 -#define MDP_INTF_8_OFF_REV_7xxx 0x3c000 +#define MDP_INTF_0_OFF_REV_7xxx 0x34000 +#define MDP_INTF_1_OFF_REV_7xxx 0x35000 +#define MDP_INTF_2_OFF_REV_7xxx 0x36000 +#define MDP_INTF_3_OFF_REV_7xxx 0x37000 +#define MDP_INTF_4_OFF_REV_7xxx 0x38000 +#define MDP_INTF_5_OFF_REV_7xxx 0x39000 +#define MDP_INTF_6_OFF_REV_7xxx 0x3a000 +#define MDP_INTF_7_OFF_REV_7xxx 0x3b000 +#define MDP_INTF_8_OFF_REV_7xxx 0x3c000 /** * struct dpu_intr_reg - array of DPU register sets diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index 84ee2efa9c66..b9dddf576c02 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -56,11 +56,6 @@ #define INTF_TPG_RGB_MAPPING 0x11C #define INTF_PROG_FETCH_START 0x170 #define INTF_PROG_ROT_START 0x174 - -#define INTF_FRAME_LINE_COUNT_EN 0x0A8 -#define INTF_FRAME_COUNT 0x0AC -#define INTF_LINE_COUNT 0x0B0 - #define INTF_MUX 0x25C #define INTF_STATUS 0x26C diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c index 2d28afdf860e..a3e413d27717 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c @@ -61,6 +61,7 @@ static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb, for (i = 0; i < m->wb_count; i++) { if (wb == m->wb[i].id) { b->blk_addr = addr + m->wb[i].base; + b->log_mask = DPU_DBG_MASK_WB; return &m->wb[i]; } } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h index feb9a729844a..5acd5683d25a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h @@ -21,9 +21,6 @@ #define HIST_INTR_EN 0x01c #define HIST_INTR_STATUS 0x020 #define HIST_INTR_CLEAR 0x024 -#define INTF_INTR_EN 0x1C0 -#define INTF_INTR_STATUS 0x1C4 -#define INTF_INTR_CLEAR 0x1C8 #define SPLIT_DISPLAY_EN 0x2F4 #define SPLIT_DISPLAY_UPPER_PIPE_CTRL 0x2F8 #define DSPP_IGC_COLOR0_RAM_LUTN 0x300 diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c index 6666783e1468..1245c7aa49df 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -593,6 +593,18 @@ static struct hdmi_codec_pdata codec_data = { .i2s = 1, }; +void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio) +{ + struct dp_audio_private *audio_priv; + + audio_priv = container_of(dp_audio, struct dp_audio_private, dp_audio); + + if (audio_priv->audio_pdev) { + platform_device_unregister(audio_priv->audio_pdev); + audio_priv->audio_pdev = NULL; + } +} + int dp_register_audio_driver(struct device *dev, struct dp_audio *dp_audio) { diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h index 84e5f4a5d26b..4ab78880af82 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.h +++ b/drivers/gpu/drm/msm/dp/dp_audio.h @@ -53,6 +53,8 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev, int dp_register_audio_driver(struct device *dev, struct dp_audio *dp_audio); +void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio); + /** * dp_audio_put() * diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 3e13acdfa7e5..99a38dbe51c0 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -326,6 +326,7 @@ static void dp_display_unbind(struct device *dev, struct device *master, kthread_stop(dp->ev_tsk); dp_power_client_deinit(dp->power); + dp_unregister_audio_driver(dev, dp->audio); dp_aux_unregister(dp->aux); dp->drm_dev = NULL; dp->aux->drm_dev = NULL; diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index d77fa9793c54..9c45d641b521 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -155,6 +155,8 @@ static bool can_do_async(struct drm_atomic_state *state, for_each_new_crtc_in_state(state, crtc, crtc_state, i) { if (drm_atomic_crtc_needs_modeset(crtc_state)) return false; + if (!crtc_state->active) + return false; if (++num_crtcs > 1) return false; *async_crtc = crtc; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index db6c4e281d75..cd39b9d8abdb 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -219,7 +219,8 @@ static void put_pages(struct drm_gem_object *obj) } } -static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) +static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj, + unsigned madv) { struct msm_drm_private *priv = obj->dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); @@ -227,7 +228,9 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) msm_gem_assert_locked(obj); - if (GEM_WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { + if (GEM_WARN_ON(msm_obj->madv > madv)) { + DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n", + msm_obj->madv, madv); return ERR_PTR(-EBUSY); } @@ -248,7 +251,7 @@ struct page **msm_gem_pin_pages(struct drm_gem_object *obj) struct page **p; msm_gem_lock(obj); - p = msm_gem_pin_pages_locked(obj); + p = msm_gem_pin_pages_locked(obj, MSM_MADV_WILLNEED); msm_gem_unlock(obj); return p; @@ -473,10 +476,7 @@ int msm_gem_pin_vma_locked(struct drm_gem_object *obj, struct msm_gem_vma *vma) msm_gem_assert_locked(obj); - if (GEM_WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) - return -EBUSY; - - pages = msm_gem_pin_pages_locked(obj); + pages = msm_gem_pin_pages_locked(obj, MSM_MADV_WILLNEED); if (IS_ERR(pages)) return PTR_ERR(pages); @@ -699,13 +699,7 @@ static void *get_vaddr(struct drm_gem_object *obj, unsigned madv) if (obj->import_attach) return ERR_PTR(-ENODEV); - if (GEM_WARN_ON(msm_obj->madv > madv)) { - DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n", - msm_obj->madv, madv); - return ERR_PTR(-EBUSY); - } - - pages = msm_gem_pin_pages_locked(obj); + pages = msm_gem_pin_pages_locked(obj, madv); if (IS_ERR(pages)) return ERR_CAST(pages); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index aff18c2f600a..9f5933c75e3d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -722,7 +722,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_drm_private *priv = dev->dev_private; struct drm_msm_gem_submit *args = data; struct msm_file_private *ctx = file->driver_priv; - struct msm_gem_submit *submit; + struct msm_gem_submit *submit = NULL; struct msm_gpu *gpu = priv->gpu; struct msm_gpu_submitqueue *queue; struct msm_ringbuffer *ring; @@ -769,13 +769,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out_fence_fd = get_unused_fd_flags(O_CLOEXEC); if (out_fence_fd < 0) { ret = out_fence_fd; - return ret; + goto out_post_unlock; } } submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds); - if (IS_ERR(submit)) - return PTR_ERR(submit); + if (IS_ERR(submit)) { + ret = PTR_ERR(submit); + goto out_post_unlock; + } trace_msm_gpu_submit(pid_nr(submit->pid), ring->id, submit->ident, args->nr_bos, args->nr_cmds); @@ -962,11 +964,20 @@ out: if (has_ww_ticket) ww_acquire_fini(&submit->ticket); out_unlock: - if (ret && (out_fence_fd >= 0)) - put_unused_fd(out_fence_fd); mutex_unlock(&queue->lock); out_post_unlock: - msm_gem_submit_put(submit); + if (ret && (out_fence_fd >= 0)) + put_unused_fd(out_fence_fd); + + if (!IS_ERR_OR_NULL(submit)) { + msm_gem_submit_put(submit); + } else { + /* + * If the submit hasn't yet taken ownership of the queue + * then we need to drop the reference ourself: + */ + msm_submitqueue_put(queue); + } if (!IS_ERR_OR_NULL(post_deps)) { for (i = 0; i < args->nr_out_syncobjs; ++i) { kfree(post_deps[i].chain); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 418e1e06cdde..5cc8d358cc97 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -234,7 +234,12 @@ struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent) /* Get the pagetable configuration from the domain */ if (adreno_smmu->cookie) ttbr1_cfg = adreno_smmu->get_ttbr1_cfg(adreno_smmu->cookie); - if (!ttbr1_cfg) + + /* + * If you hit this WARN_ONCE() you are probably missing an entry in + * qcom_smmu_impl_of_match[] in arm-smmu-qcom.c + */ + if (WARN_ONCE(!ttbr1_cfg, "No per-process page tables")) return ERR_PTR(-ENODEV); pagetable = kzalloc(sizeof(*pagetable), GFP_KERNEL); @@ -410,7 +415,7 @@ struct msm_mmu *msm_iommu_gpu_new(struct device *dev, struct msm_gpu *gpu, unsig struct msm_mmu *mmu; mmu = msm_iommu_new(dev, quirks); - if (IS_ERR(mmu)) + if (IS_ERR_OR_NULL(mmu)) return mmu; iommu = to_msm_iommu(mmu); diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index eb99d84eb844..16d4ad5023a3 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -2,6 +2,8 @@ #ifndef __NVIF_IF0012_H__ #define __NVIF_IF0012_H__ +#include + union nvif_outp_args { struct nvif_outp_v0 { __u8 version; @@ -63,7 +65,7 @@ union nvif_outp_acquire_args { __u8 hda; __u8 mst; __u8 pad04[4]; - __u8 dpcd[16]; + __u8 dpcd[DP_RECEIVER_CAP_SIZE]; } dp; }; } v0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index b7631c1ab242..4e7f873f66e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -3,6 +3,7 @@ #define __NVKM_DISP_OUTP_H__ #include "priv.h" +#include #include #include #include @@ -42,7 +43,7 @@ struct nvkm_outp { bool aux_pwr_pu; u8 lttpr[6]; u8 lttprs; - u8 dpcd[16]; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; struct { int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 4f0ca709c85a..fc283a4a1522 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -146,7 +146,7 @@ nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc) } static int -nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[16], +nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 link_nr, u8 link_bw, bool hda, bool mst) { int ret; diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 6afdf260a4e2..b9fe926a49e8 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -53,7 +53,7 @@ pl111_mode_valid(struct drm_simple_display_pipe *pipe, { struct drm_device *drm = pipe->crtc.dev; struct pl111_drm_dev_private *priv = drm->dev_private; - u32 cpp = priv->variant->fb_bpp / 8; + u32 cpp = DIV_ROUND_UP(priv->variant->fb_depth, 8); u64 bw; /* diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index 2a46b5bd8576..d1fe756444ee 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h @@ -114,7 +114,7 @@ struct drm_minor; * extensions to the control register * @formats: array of supported pixel formats on this variant * @nformats: the length of the array of supported pixel formats - * @fb_bpp: desired bits per pixel on the default framebuffer + * @fb_depth: desired depth per pixel on the default framebuffer */ struct pl111_variant_data { const char *name; @@ -126,7 +126,7 @@ struct pl111_variant_data { bool st_bitmux_control; const u32 *formats; unsigned int nformats; - unsigned int fb_bpp; + unsigned int fb_depth; }; struct pl111_drm_dev_private { diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 4b2a9e9753f6..43049c8028b2 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -308,7 +308,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, if (ret < 0) goto dev_put; - drm_fbdev_dma_setup(drm, priv->variant->fb_bpp); + drm_fbdev_dma_setup(drm, priv->variant->fb_depth); return 0; @@ -351,7 +351,7 @@ static const struct pl111_variant_data pl110_variant = { .is_pl110 = true, .formats = pl110_pixel_formats, .nformats = ARRAY_SIZE(pl110_pixel_formats), - .fb_bpp = 16, + .fb_depth = 16, }; /* RealView, Versatile Express etc use this modern variant */ @@ -376,7 +376,7 @@ static const struct pl111_variant_data pl111_variant = { .name = "PL111", .formats = pl111_pixel_formats, .nformats = ARRAY_SIZE(pl111_pixel_formats), - .fb_bpp = 32, + .fb_depth = 32, }; static const u32 pl110_nomadik_pixel_formats[] = { @@ -405,7 +405,7 @@ static const struct pl111_variant_data pl110_nomadik_variant = { .is_lcdc = true, .st_bitmux_control = true, .broken_vblank = true, - .fb_bpp = 16, + .fb_depth = 16, }; static const struct amba_id pl111_id_table[] = { diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index 1b436b75fd39..00c3ebd32359 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c @@ -316,7 +316,7 @@ static const struct pl111_variant_data pl110_integrator = { .broken_vblank = true, .formats = pl110_integrator_pixel_formats, .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats), - .fb_bpp = 16, + .fb_depth = 16, }; /* @@ -330,7 +330,7 @@ static const struct pl111_variant_data pl110_impd1 = { .broken_vblank = true, .formats = pl110_integrator_pixel_formats, .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats), - .fb_bpp = 16, + .fb_depth = 15, }; /* @@ -343,7 +343,7 @@ static const struct pl111_variant_data pl110_versatile = { .external_bgr = true, .formats = pl110_versatile_pixel_formats, .nformats = ARRAY_SIZE(pl110_versatile_pixel_formats), - .fb_bpp = 16, + .fb_depth = 16, }; /* @@ -355,7 +355,7 @@ static const struct pl111_variant_data pl111_realview = { .name = "PL111 RealView", .formats = pl111_realview_pixel_formats, .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), - .fb_bpp = 16, + .fb_depth = 16, }; /* @@ -367,7 +367,7 @@ static const struct pl111_variant_data pl111_vexpress = { .name = "PL111 Versatile Express", .formats = pl111_realview_pixel_formats, .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), - .fb_bpp = 16, + .fb_depth = 16, .broken_clockdivider = true, }; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 3377fbc71f65..c4dda908666c 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -99,6 +99,16 @@ static void radeon_hotplug_work_func(struct work_struct *work) static void radeon_dp_work_func(struct work_struct *work) { + struct radeon_device *rdev = container_of(work, struct radeon_device, + dp_work); + struct drm_device *dev = rdev->ddev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + + mutex_lock(&mode_config->mutex); + list_for_each_entry(connector, &mode_config->connector_list, head) + radeon_connector_hotplug(connector); + mutex_unlock(&mode_config->mutex); } /** diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index fcd5bd7e5e8e..aea5a90ff98b 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -309,7 +309,7 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched) */ void drm_sched_fault(struct drm_gpu_scheduler *sched) { - if (sched->ready) + if (sched->timeout_wq) mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0); } EXPORT_SYMBOL(drm_sched_fault); @@ -1141,9 +1141,6 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched) for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { struct drm_sched_rq *rq = &sched->sched_rq[i]; - if (!rq) - continue; - spin_lock(&rq->lock); list_for_each_entry(s_entity, &rq->entities, list) /* diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 4bca6b54520a..4212b8c91dd4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -261,7 +261,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, * encryption bits. This is because the exact location of the * data may not be known at mmap() time and may also change * at arbitrary times while the data is mmap'ed. - * See vmf_insert_mixed_prot() for a discussion. + * See vmf_insert_pfn_prot() for a discussion. */ ret = vmf_insert_pfn_prot(vma, address, pfn, prot); diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index dfce896c4bae..4db3982057be 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -65,11 +65,11 @@ module_param(page_pool_size, ulong, 0644); static atomic_long_t allocated_pages; -static struct ttm_pool_type global_write_combined[MAX_ORDER]; -static struct ttm_pool_type global_uncached[MAX_ORDER]; +static struct ttm_pool_type global_write_combined[MAX_ORDER + 1]; +static struct ttm_pool_type global_uncached[MAX_ORDER + 1]; -static struct ttm_pool_type global_dma32_write_combined[MAX_ORDER]; -static struct ttm_pool_type global_dma32_uncached[MAX_ORDER]; +static struct ttm_pool_type global_dma32_write_combined[MAX_ORDER + 1]; +static struct ttm_pool_type global_dma32_uncached[MAX_ORDER + 1]; static spinlock_t shrinker_lock; static struct list_head shrinker_list; @@ -444,7 +444,7 @@ int ttm_pool_alloc(struct ttm_pool *pool, struct ttm_tt *tt, else gfp_flags |= GFP_HIGHUSER; - for (order = min_t(unsigned int, MAX_ORDER - 1, __fls(num_pages)); + for (order = min_t(unsigned int, MAX_ORDER, __fls(num_pages)); num_pages; order = min_t(unsigned int, order, __fls(num_pages))) { struct ttm_pool_type *pt; @@ -563,7 +563,7 @@ void ttm_pool_init(struct ttm_pool *pool, struct device *dev, if (use_dma_alloc) { for (i = 0; i < TTM_NUM_CACHING_TYPES; ++i) - for (j = 0; j < MAX_ORDER; ++j) + for (j = 0; j <= MAX_ORDER; ++j) ttm_pool_type_init(&pool->caching[i].orders[j], pool, i, j); } @@ -583,7 +583,7 @@ void ttm_pool_fini(struct ttm_pool *pool) if (pool->use_dma_alloc) { for (i = 0; i < TTM_NUM_CACHING_TYPES; ++i) - for (j = 0; j < MAX_ORDER; ++j) + for (j = 0; j <= MAX_ORDER; ++j) ttm_pool_type_fini(&pool->caching[i].orders[j]); } @@ -637,7 +637,7 @@ static void ttm_pool_debugfs_header(struct seq_file *m) unsigned int i; seq_puts(m, "\t "); - for (i = 0; i < MAX_ORDER; ++i) + for (i = 0; i <= MAX_ORDER; ++i) seq_printf(m, " ---%2u---", i); seq_puts(m, "\n"); } @@ -648,7 +648,7 @@ static void ttm_pool_debugfs_orders(struct ttm_pool_type *pt, { unsigned int i; - for (i = 0; i < MAX_ORDER; ++i) + for (i = 0; i <= MAX_ORDER; ++i) seq_printf(m, " %8u", ttm_pool_type_count(&pt[i])); seq_puts(m, "\n"); } @@ -757,7 +757,7 @@ int ttm_pool_mgr_init(unsigned long num_pages) spin_lock_init(&shrinker_lock); INIT_LIST_HEAD(&shrinker_list); - for (i = 0; i < MAX_ORDER; ++i) { + for (i = 0; i <= MAX_ORDER; ++i) { ttm_pool_type_init(&global_write_combined[i], NULL, ttm_write_combined, i); ttm_pool_type_init(&global_uncached[i], NULL, ttm_uncached, i); @@ -790,7 +790,7 @@ void ttm_pool_mgr_fini(void) { unsigned int i; - for (i = 0; i < MAX_ORDER; ++i) { + for (i = 0; i <= MAX_ORDER; ++i) { ttm_pool_type_fini(&global_write_combined[i]); ttm_pool_type_fini(&global_uncached[i]); diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index cc535d2d6e8c..d7b932925730 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -58,7 +58,7 @@ static unsigned int swap_opt_cmd; module_param(swap_opt_cmd, uint, 0644); MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") keys. " "(For people who want to keep Windows PC keyboard muscle memory. " - "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)"); + "[0] = as-is, Mac layout. 1 = swapped, Windows layout., 2 = swapped, Swap only left side)"); static unsigned int swap_ctrl_cmd; module_param(swap_ctrl_cmd, uint, 0644); @@ -319,6 +319,12 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = { { } }; +static const struct apple_key_translation swapped_option_cmd_left_keys[] = { + { KEY_LEFTALT, KEY_LEFTMETA }, + { KEY_LEFTMETA, KEY_LEFTALT }, + { } +}; + static const struct apple_key_translation swapped_ctrl_cmd_keys[] = { { KEY_LEFTCTRL, KEY_LEFTMETA }, { KEY_LEFTMETA, KEY_LEFTCTRL }, @@ -416,7 +422,10 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (swap_opt_cmd) { - trans = apple_find_translation(swapped_option_cmd_keys, code); + if (swap_opt_cmd == 2) + trans = apple_find_translation(swapped_option_cmd_left_keys, code); + else + trans = apple_find_translation(swapped_option_cmd_keys, code); if (trans) code = trans->to; diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c index d94ee0539421..ea6b79b3aeeb 100644 --- a/drivers/hid/hid-roccat-arvo.c +++ b/drivers/hid/hid-roccat-arvo.c @@ -433,7 +433,7 @@ static int __init arvo_init(void) { int retval; - arvo_class = class_create(THIS_MODULE, "arvo"); + arvo_class = class_create("arvo"); if (IS_ERR(arvo_class)) return PTR_ERR(arvo_class); arvo_class->dev_groups = arvo_groups; diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index e95d59cd8d07..3903a2cea00c 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c @@ -435,7 +435,7 @@ static struct hid_driver isku_driver = { static int __init isku_init(void) { int retval; - isku_class = class_create(THIS_MODULE, "isku"); + isku_class = class_create("isku"); if (IS_ERR(isku_class)) return PTR_ERR(isku_class); isku_class->dev_groups = isku_groups; diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 76da04801ca9..945ae236fb45 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -890,7 +890,7 @@ static int __init kone_init(void) int retval; /* class name has to be same as driver name */ - kone_class = class_create(THIS_MODULE, "kone"); + kone_class = class_create("kone"); if (IS_ERR(kone_class)) return PTR_ERR(kone_class); kone_class->dev_groups = kone_groups; diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 1896c69ea512..97b83b6f53dd 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -549,7 +549,7 @@ static int __init koneplus_init(void) int retval; /* class name has to be same as driver name */ - koneplus_class = class_create(THIS_MODULE, "koneplus"); + koneplus_class = class_create("koneplus"); if (IS_ERR(koneplus_class)) return PTR_ERR(koneplus_class); koneplus_class->dev_groups = koneplus_groups; diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c index cf8eeb33a125..a297756f2410 100644 --- a/drivers/hid/hid-roccat-konepure.c +++ b/drivers/hid/hid-roccat-konepure.c @@ -207,7 +207,7 @@ static int __init konepure_init(void) { int retval; - konepure_class = class_create(THIS_MODULE, "konepure"); + konepure_class = class_create("konepure"); if (IS_ERR(konepure_class)) return PTR_ERR(konepure_class); konepure_class->dev_groups = konepure_groups; diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 6fb9b9563769..1a1d96e11683 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -638,7 +638,7 @@ static int __init kovaplus_init(void) { int retval; - kovaplus_class = class_create(THIS_MODULE, "kovaplus"); + kovaplus_class = class_create("kovaplus"); if (IS_ERR(kovaplus_class)) return PTR_ERR(kovaplus_class); kovaplus_class->dev_groups = kovaplus_groups; diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 4fcc8e7d276f..15528c3b013c 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -585,7 +585,7 @@ static int __init pyra_init(void) int retval; /* class name has to be same as driver name */ - pyra_class = class_create(THIS_MODULE, "pyra"); + pyra_class = class_create("pyra"); if (IS_ERR(pyra_class)) return PTR_ERR(pyra_class); pyra_class->dev_groups = pyra_groups; diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c index 5bf1971a2b14..0eb17a3b925d 100644 --- a/drivers/hid/hid-roccat-ryos.c +++ b/drivers/hid/hid-roccat-ryos.c @@ -216,7 +216,7 @@ static int __init ryos_init(void) { int retval; - ryos_class = class_create(THIS_MODULE, "ryos"); + ryos_class = class_create("ryos"); if (IS_ERR(ryos_class)) return PTR_ERR(ryos_class); ryos_class->dev_groups = ryos_groups; diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c index a784bb4ee651..93be7acef673 100644 --- a/drivers/hid/hid-roccat-savu.c +++ b/drivers/hid/hid-roccat-savu.c @@ -204,7 +204,7 @@ static int __init savu_init(void) { int retval; - savu_class = class_create(THIS_MODULE, "savu"); + savu_class = class_create("savu"); if (IS_ERR(savu_class)) return PTR_ERR(savu_class); savu_class->dev_groups = savu_groups; diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index b617aada50b0..e63c56a0d57f 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -623,7 +623,7 @@ int __init hidraw_init(void) hidraw_major = MAJOR(dev_id); - hidraw_class = class_create(THIS_MODULE, "hidraw"); + hidraw_class = class_create("hidraw"); if (IS_ERR(hidraw_class)) { result = PTR_ERR(hidraw_class); goto error_cdev; diff --git a/drivers/hsi/hsi_core.c b/drivers/hsi/hsi_core.c index 8fda8f1d064d..acbf82f755a8 100644 --- a/drivers/hsi/hsi_core.c +++ b/drivers/hsi/hsi_core.c @@ -207,7 +207,7 @@ static void hsi_add_client_from_dt(struct hsi_port *port, if (!cl) return; - err = of_modalias_node(client, name, sizeof(name)); + err = of_alias_from_compatible(client, name, sizeof(name)); if (err) goto err; diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c index 358d4a10c6a1..ba37a5efbf82 100644 --- a/drivers/hte/hte-tegra194-test.c +++ b/drivers/hte/hte-tegra194-test.c @@ -16,7 +16,7 @@ #include /* - * This sample HTE GPIO test driver demonstrates HTE API usage by enabling + * This sample HTE test driver demonstrates HTE API usage by enabling * hardware timestamp on gpio_in and specified LIC IRQ lines. * * Note: gpio_out and gpio_in need to be shorted externally in order for this diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c index 49a27af22742..06ef349a2265 100644 --- a/drivers/hte/hte-tegra194.c +++ b/drivers/hte/hte-tegra194.c @@ -62,6 +62,10 @@ #define NV_AON_HTE_SLICE2_IRQ_GPIO_25 25 #define NV_AON_HTE_SLICE2_IRQ_GPIO_26 26 #define NV_AON_HTE_SLICE2_IRQ_GPIO_27 27 +#define NV_AON_HTE_SLICE2_IRQ_GPIO_28 28 +#define NV_AON_HTE_SLICE2_IRQ_GPIO_29 29 +#define NV_AON_HTE_SLICE2_IRQ_GPIO_30 30 +#define NV_AON_HTE_SLICE2_IRQ_GPIO_31 31 #define HTE_TECTRL 0x0 #define HTE_TETSCH 0x4 @@ -114,6 +118,7 @@ struct tegra_hte_line_data { struct tegra_hte_data { enum tegra_hte_type type; + u32 slices; u32 map_sz; u32 sec_map_sz; const struct tegra_hte_line_mapped *map; @@ -220,18 +225,129 @@ static const struct tegra_hte_line_mapped tegra194_aon_gpio_sec_map[] = { [39] = {NV_AON_SLICE_INVALID, 0}, }; -static const struct tegra_hte_data aon_hte = { +static const struct tegra_hte_line_mapped tegra234_aon_gpio_map[] = { + /* gpio, slice, bit_index */ + /* AA port */ + [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11}, + [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10}, + [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9}, + [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8}, + [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7}, + [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6}, + [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5}, + [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4}, + /* BB port */ + [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3}, + [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2}, + [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1}, + [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0}, + /* CC port */ + [12] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22}, + [13] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21}, + [14] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20}, + [15] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19}, + [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18}, + [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17}, + [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16}, + [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15}, + /* DD port */ + [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14}, + [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13}, + [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12}, + /* EE port */ + [23] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_31}, + [24] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_30}, + [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_29}, + [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_28}, + [27] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27}, + [28] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26}, + [29] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25}, + [30] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24}, + /* GG port */ + [31] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23}, +}; + +static const struct tegra_hte_line_mapped tegra234_aon_gpio_sec_map[] = { + /* gpio, slice, bit_index */ + /* AA port */ + [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11}, + [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10}, + [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9}, + [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8}, + [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7}, + [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6}, + [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5}, + [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4}, + /* BB port */ + [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3}, + [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2}, + [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1}, + [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0}, + [12] = {NV_AON_SLICE_INVALID, 0}, + [13] = {NV_AON_SLICE_INVALID, 0}, + [14] = {NV_AON_SLICE_INVALID, 0}, + [15] = {NV_AON_SLICE_INVALID, 0}, + /* CC port */ + [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22}, + [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21}, + [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20}, + [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19}, + [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18}, + [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17}, + [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16}, + [23] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15}, + /* DD port */ + [24] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14}, + [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13}, + [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12}, + [27] = {NV_AON_SLICE_INVALID, 0}, + [28] = {NV_AON_SLICE_INVALID, 0}, + [29] = {NV_AON_SLICE_INVALID, 0}, + [30] = {NV_AON_SLICE_INVALID, 0}, + [31] = {NV_AON_SLICE_INVALID, 0}, + /* EE port */ + [32] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_31}, + [33] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_30}, + [34] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_29}, + [35] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_28}, + [36] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27}, + [37] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26}, + [38] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25}, + [39] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24}, + /* GG port */ + [40] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23}, +}; + +static const struct tegra_hte_data t194_aon_hte = { .map_sz = ARRAY_SIZE(tegra194_aon_gpio_map), .map = tegra194_aon_gpio_map, .sec_map_sz = ARRAY_SIZE(tegra194_aon_gpio_sec_map), .sec_map = tegra194_aon_gpio_sec_map, .type = HTE_TEGRA_TYPE_GPIO, + .slices = 3, }; -static const struct tegra_hte_data lic_hte = { +static const struct tegra_hte_data t234_aon_hte = { + .map_sz = ARRAY_SIZE(tegra234_aon_gpio_map), + .map = tegra234_aon_gpio_map, + .sec_map_sz = ARRAY_SIZE(tegra234_aon_gpio_sec_map), + .sec_map = tegra234_aon_gpio_sec_map, + .type = HTE_TEGRA_TYPE_GPIO, + .slices = 3, +}; + +static const struct tegra_hte_data t194_lic_hte = { .map_sz = 0, .map = NULL, .type = HTE_TEGRA_TYPE_LIC, + .slices = 11, +}; + +static const struct tegra_hte_data t234_lic_hte = { + .map_sz = 0, + .map = NULL, + .type = HTE_TEGRA_TYPE_LIC, + .slices = 17, }; static inline u32 tegra_hte_readl(struct tegra_hte_soc *hte, u32 reg) @@ -251,7 +367,7 @@ static int tegra_hte_map_to_line_id(u32 eid, { if (m) { - if (eid > map_sz) + if (eid >= map_sz) return -EINVAL; if (m[eid].slice == NV_AON_SLICE_INVALID) return -EINVAL; @@ -534,8 +650,10 @@ static bool tegra_hte_match_from_linedata(const struct hte_chip *chip, } static const struct of_device_id tegra_hte_of_match[] = { - { .compatible = "nvidia,tegra194-gte-lic", .data = &lic_hte}, - { .compatible = "nvidia,tegra194-gte-aon", .data = &aon_hte}, + { .compatible = "nvidia,tegra194-gte-lic", .data = &t194_lic_hte}, + { .compatible = "nvidia,tegra194-gte-aon", .data = &t194_aon_hte}, + { .compatible = "nvidia,tegra234-gte-lic", .data = &t234_lic_hte}, + { .compatible = "nvidia,tegra234-gte-aon", .data = &t234_aon_hte}, { } }; MODULE_DEVICE_TABLE(of, tegra_hte_of_match); @@ -561,6 +679,11 @@ static int tegra_get_gpiochip_from_name(struct gpio_chip *chip, void *data) return !strcmp(chip->label, data); } +static int tegra_gpiochip_match(struct gpio_chip *chip, void *data) +{ + return chip->fwnode == of_node_to_fwnode(data); +} + static int tegra_hte_probe(struct platform_device *pdev) { int ret; @@ -569,16 +692,10 @@ static int tegra_hte_probe(struct platform_device *pdev) struct device *dev; struct tegra_hte_soc *hte_dev; struct hte_chip *gc; + struct device_node *gpio_ctrl; dev = &pdev->dev; - ret = of_property_read_u32(dev->of_node, "nvidia,slices", &slices); - if (ret != 0) { - dev_err(dev, "Could not read slices\n"); - return -EINVAL; - } - nlines = slices << 5; - hte_dev = devm_kzalloc(dev, sizeof(*hte_dev), GFP_KERNEL); if (!hte_dev) return -ENOMEM; @@ -590,6 +707,13 @@ static int tegra_hte_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, hte_dev); hte_dev->prov_data = of_device_get_match_data(&pdev->dev); + ret = of_property_read_u32(dev->of_node, "nvidia,slices", &slices); + if (ret != 0) + slices = hte_dev->prov_data->slices; + + dev_dbg(dev, "slices:%d\n", slices); + nlines = slices << 5; + hte_dev->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hte_dev->regs)) return PTR_ERR(hte_dev->regs); @@ -635,8 +759,25 @@ static int tegra_hte_probe(struct platform_device *pdev) gc->match_from_linedata = tegra_hte_match_from_linedata; - hte_dev->c = gpiochip_find("tegra194-gpio-aon", - tegra_get_gpiochip_from_name); + if (of_device_is_compatible(dev->of_node, + "nvidia,tegra194-gte-aon")) { + hte_dev->c = gpiochip_find("tegra194-gpio-aon", + tegra_get_gpiochip_from_name); + } else { + gpio_ctrl = of_parse_phandle(dev->of_node, + "nvidia,gpio-controller", + 0); + if (!gpio_ctrl) { + dev_err(dev, + "gpio controller node not found\n"); + return -ENODEV; + } + + hte_dev->c = gpiochip_find(gpio_ctrl, + tegra_gpiochip_match); + of_node_put(gpio_ctrl); + } + if (!hte_dev->c) return dev_err_probe(dev, -EPROBE_DEFER, "wait for gpio controller\n"); diff --git a/drivers/hte/hte.c b/drivers/hte/hte.c index 9f3221462e75..67c15724ee78 100644 --- a/drivers/hte/hte.c +++ b/drivers/hte/hte.c @@ -444,7 +444,7 @@ static struct hte_device *of_node_to_htedevice(struct device_node *np) list_for_each_entry(gdev, &hte_devices, list) if (gdev->chip && gdev->chip->dev && - gdev->chip->dev->of_node == np) { + device_match_of_node(gdev->chip->dev, np)) { spin_unlock(&hte_lock); return gdev; } diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 0747a8f1fcee..00242107d62e 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -4,15 +4,39 @@ menu "Microsoft Hyper-V guest support" config HYPERV tristate "Microsoft Hyper-V client drivers" - depends on ACPI && ((X86 && X86_LOCAL_APIC && HYPERVISOR_GUEST) \ - || (ARM64 && !CPU_BIG_ENDIAN)) + depends on (X86 && X86_LOCAL_APIC && HYPERVISOR_GUEST) \ + || (ACPI && ARM64 && !CPU_BIG_ENDIAN) select PARAVIRT select X86_HV_CALLBACK_VECTOR if X86 - select VMAP_PFN + select OF_EARLY_FLATTREE if OF help Select this option to run Linux as a Hyper-V client operating system. +config HYPERV_VTL_MODE + bool "Enable Linux to boot in VTL context" + depends on X86_64 && HYPERV + default n + help + Virtual Secure Mode (VSM) is a set of hypervisor capabilities and + enlightenments offered to host and guest partitions which enables + the creation and management of new security boundaries within + operating system software. + + VSM achieves and maintains isolation through Virtual Trust Levels + (VTLs). Virtual Trust Levels are hierarchical, with higher levels + being more privileged than lower levels. VTL0 is the least privileged + level, and currently only other level supported is VTL2. + + Select this option to build a Linux kernel to run at a VTL other than + the normal VTL0, which currently is only VTL2. This option + initializes the x86 platform for VTL2, and adds the ability to boot + secondary CPUs directly into 64-bit context as required for VTLs other + than 0. A kernel built with this option must run at VTL2, and will + not run as a normal guest. + + If unsure, say N + config HYPERV_TIMER def_bool HYPERV && X86 diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index cc23b90cae02..007f26d5f1a4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -67,7 +67,7 @@ const struct vmbus_device vmbus_devs[] = { { .dev_type = HV_PCIE, HV_PCIE_GUID, .perf_device = false, - .allowed_in_isolated = false, + .allowed_in_isolated = true, }, /* Synthetic Frame Buffer */ diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index da51b50787df..5978e9dbc286 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -104,8 +104,14 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; } - msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0]; - msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1]; + /* + * shared_gpa_boundary is zero in non-SNP VMs, so it's safe to always + * bitwise OR it + */ + msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]) | + ms_hyperv.shared_gpa_boundary; + msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]) | + ms_hyperv.shared_gpa_boundary; msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU); @@ -219,72 +225,27 @@ int vmbus_connect(void) * Setup the monitor notification facility. The 1st page for * parent->child and the 2nd page for child->parent */ - vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page(); - vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page(); + vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_page(); + vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_page(); if ((vmbus_connection.monitor_pages[0] == NULL) || (vmbus_connection.monitor_pages[1] == NULL)) { ret = -ENOMEM; goto cleanup; } - vmbus_connection.monitor_pages_original[0] - = vmbus_connection.monitor_pages[0]; - vmbus_connection.monitor_pages_original[1] - = vmbus_connection.monitor_pages[1]; - vmbus_connection.monitor_pages_pa[0] - = virt_to_phys(vmbus_connection.monitor_pages[0]); - vmbus_connection.monitor_pages_pa[1] - = virt_to_phys(vmbus_connection.monitor_pages[1]); + ret = set_memory_decrypted((unsigned long) + vmbus_connection.monitor_pages[0], 1); + ret |= set_memory_decrypted((unsigned long) + vmbus_connection.monitor_pages[1], 1); + if (ret) + goto cleanup; - if (hv_is_isolation_supported()) { - ret = set_memory_decrypted((unsigned long) - vmbus_connection.monitor_pages[0], - 1); - ret |= set_memory_decrypted((unsigned long) - vmbus_connection.monitor_pages[1], - 1); - if (ret) - goto cleanup; - - /* - * Isolation VM with AMD SNP needs to access monitor page via - * address space above shared gpa boundary. - */ - if (hv_isolation_type_snp()) { - vmbus_connection.monitor_pages_pa[0] += - ms_hyperv.shared_gpa_boundary; - vmbus_connection.monitor_pages_pa[1] += - ms_hyperv.shared_gpa_boundary; - - vmbus_connection.monitor_pages[0] - = memremap(vmbus_connection.monitor_pages_pa[0], - HV_HYP_PAGE_SIZE, - MEMREMAP_WB); - if (!vmbus_connection.monitor_pages[0]) { - ret = -ENOMEM; - goto cleanup; - } - - vmbus_connection.monitor_pages[1] - = memremap(vmbus_connection.monitor_pages_pa[1], - HV_HYP_PAGE_SIZE, - MEMREMAP_WB); - if (!vmbus_connection.monitor_pages[1]) { - ret = -ENOMEM; - goto cleanup; - } - } - - /* - * Set memory host visibility hvcall smears memory - * and so zero monitor pages here. - */ - memset(vmbus_connection.monitor_pages[0], 0x00, - HV_HYP_PAGE_SIZE); - memset(vmbus_connection.monitor_pages[1], 0x00, - HV_HYP_PAGE_SIZE); - - } + /* + * Set_memory_decrypted() will change the memory contents if + * decryption occurs, so zero monitor pages here. + */ + memset(vmbus_connection.monitor_pages[0], 0x00, HV_HYP_PAGE_SIZE); + memset(vmbus_connection.monitor_pages[1], 0x00, HV_HYP_PAGE_SIZE); msginfo = kzalloc(sizeof(*msginfo) + sizeof(struct vmbus_channel_initiate_contact), @@ -376,31 +337,13 @@ void vmbus_disconnect(void) vmbus_connection.int_page = NULL; } - if (hv_is_isolation_supported()) { - /* - * memunmap() checks input address is ioremap address or not - * inside. It doesn't unmap any thing in the non-SNP CVM and - * so not check CVM type here. - */ - memunmap(vmbus_connection.monitor_pages[0]); - memunmap(vmbus_connection.monitor_pages[1]); + set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[0], 1); + set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[1], 1); - set_memory_encrypted((unsigned long) - vmbus_connection.monitor_pages_original[0], - 1); - set_memory_encrypted((unsigned long) - vmbus_connection.monitor_pages_original[1], - 1); - } - - hv_free_hyperv_page((unsigned long) - vmbus_connection.monitor_pages_original[0]); - hv_free_hyperv_page((unsigned long) - vmbus_connection.monitor_pages_original[1]); - vmbus_connection.monitor_pages_original[0] = - vmbus_connection.monitor_pages[0] = NULL; - vmbus_connection.monitor_pages_original[1] = - vmbus_connection.monitor_pages[1] = NULL; + hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]); + hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]); + vmbus_connection.monitor_pages[0] = NULL; + vmbus_connection.monitor_pages[1] = NULL; } /* diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 8b0dd8e5244d..de6708dbe0df 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -38,42 +38,6 @@ int hv_init(void) return 0; } -/* - * Functions for allocating and freeing memory with size and - * alignment HV_HYP_PAGE_SIZE. These functions are needed because - * the guest page size may not be the same as the Hyper-V page - * size. We depend upon kmalloc() aligning power-of-two size - * allocations to the allocation size boundary, so that the - * allocated memory appears to Hyper-V as a page of the size - * it expects. - */ - -void *hv_alloc_hyperv_page(void) -{ - BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); - - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - return (void *)__get_free_page(GFP_KERNEL); - else - return kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); -} - -void *hv_alloc_hyperv_zeroed_page(void) -{ - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); - else - return kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); -} - -void hv_free_hyperv_page(unsigned long addr) -{ - if (PAGE_SIZE == HV_HYP_PAGE_SIZE) - free_page(addr); - else - kfree((void *)addr); -} - /* * hv_post_message - Post a message using the hypervisor message IPC. * @@ -84,14 +48,15 @@ int hv_post_message(union hv_connection_id connection_id, void *payload, size_t payload_size) { struct hv_input_post_message *aligned_msg; - struct hv_per_cpu_context *hv_cpu; + unsigned long flags; u64 status; if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) return -EMSGSIZE; - hv_cpu = get_cpu_ptr(hv_context.cpu_context); - aligned_msg = hv_cpu->post_msg_page; + local_irq_save(flags); + + aligned_msg = *this_cpu_ptr(hyperv_pcpu_input_arg); aligned_msg->connectionid = connection_id; aligned_msg->reserved = 0; aligned_msg->message_type = message_type; @@ -106,11 +71,7 @@ int hv_post_message(union hv_connection_id connection_id, status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); - /* Preemption must remain disabled until after the hypercall - * so some other thread can't get scheduled onto this cpu and - * corrupt the per-cpu post_msg_page - */ - put_cpu_ptr(hv_cpu); + local_irq_restore(flags); return hv_result(status); } @@ -162,12 +123,6 @@ int hv_synic_alloc(void) goto err; } } - - hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); - if (hv_cpu->post_msg_page == NULL) { - pr_err("Unable to allocate post msg page\n"); - goto err; - } } return 0; @@ -190,7 +145,6 @@ void hv_synic_free(void) free_page((unsigned long)hv_cpu->synic_event_page); free_page((unsigned long)hv_cpu->synic_message_page); - free_page((unsigned long)hv_cpu->post_msg_page); } kfree(hv_context.hv_numa_map); @@ -217,11 +171,13 @@ void hv_synic_enable_regs(unsigned int cpu) simp.simp_enabled = 1; if (hv_isolation_type_snp() || hv_root_partition) { + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + u64 base = (simp.base_simp_gpa << HV_HYP_PAGE_SHIFT) & + ~ms_hyperv.shared_gpa_boundary; hv_cpu->synic_message_page - = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT, - HV_HYP_PAGE_SIZE, MEMREMAP_WB); + = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); if (!hv_cpu->synic_message_page) - pr_err("Fail to map syinc message page.\n"); + pr_err("Fail to map synic message page.\n"); } else { simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) >> HV_HYP_PAGE_SHIFT; @@ -234,12 +190,13 @@ void hv_synic_enable_regs(unsigned int cpu) siefp.siefp_enabled = 1; if (hv_isolation_type_snp() || hv_root_partition) { - hv_cpu->synic_event_page = - memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT, - HV_HYP_PAGE_SIZE, MEMREMAP_WB); - + /* Mask out vTOM bit. ioremap_cache() maps decrypted */ + u64 base = (siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT) & + ~ms_hyperv.shared_gpa_boundary; + hv_cpu->synic_event_page + = (void *)ioremap_cache(base, HV_HYP_PAGE_SIZE); if (!hv_cpu->synic_event_page) - pr_err("Fail to map syinc event page.\n"); + pr_err("Fail to map synic event page.\n"); } else { siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) >> HV_HYP_PAGE_SHIFT; @@ -316,7 +273,7 @@ void hv_synic_disable_regs(unsigned int cpu) */ simp.simp_enabled = 0; if (hv_isolation_type_snp() || hv_root_partition) { - memunmap(hv_cpu->synic_message_page); + iounmap(hv_cpu->synic_message_page); hv_cpu->synic_message_page = NULL; } else { simp.base_simp_gpa = 0; @@ -328,7 +285,7 @@ void hv_synic_disable_regs(unsigned int cpu) siefp.siefp_enabled = 0; if (hv_isolation_type_snp() || hv_root_partition) { - memunmap(hv_cpu->synic_event_page); + iounmap(hv_cpu->synic_event_page); hv_cpu->synic_event_page = NULL; } else { siefp.base_siefp_gpa = 0; diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 52a6f89ccdbd..64f9ceca887b 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -17,8 +17,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -54,6 +57,10 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg); void * __percpu *hyperv_pcpu_output_arg; EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); +static void hv_kmsg_dump_unregister(void); + +static struct ctl_table_header *hv_ctl_table_hdr; + /* * Hyper-V specific initialization and shutdown code that is * common across all architectures. Called from architecture @@ -62,6 +69,12 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); void __init hv_common_free(void) { + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; + + if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) + hv_kmsg_dump_unregister(); + kfree(hv_vp_index); hv_vp_index = NULL; @@ -72,10 +85,203 @@ void __init hv_common_free(void) hyperv_pcpu_input_arg = NULL; } +/* + * Functions for allocating and freeing memory with size and + * alignment HV_HYP_PAGE_SIZE. These functions are needed because + * the guest page size may not be the same as the Hyper-V page + * size. We depend upon kmalloc() aligning power-of-two size + * allocations to the allocation size boundary, so that the + * allocated memory appears to Hyper-V as a page of the size + * it expects. + */ + +void *hv_alloc_hyperv_page(void) +{ + BUILD_BUG_ON(PAGE_SIZE < HV_HYP_PAGE_SIZE); + + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL); + else + return kmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page); + +void *hv_alloc_hyperv_zeroed_page(void) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + else + return kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page); + +void hv_free_hyperv_page(unsigned long addr) +{ + if (PAGE_SIZE == HV_HYP_PAGE_SIZE) + free_page(addr); + else + kfree((void *)addr); +} +EXPORT_SYMBOL_GPL(hv_free_hyperv_page); + +static void *hv_panic_page; + +/* + * Boolean to control whether to report panic messages over Hyper-V. + * + * It can be set via /proc/sys/kernel/hyperv_record_panic_msg + */ +static int sysctl_record_panic_msg = 1; + +/* + * sysctl option to allow the user to control whether kmsg data should be + * reported to Hyper-V on panic. + */ +static struct ctl_table hv_ctl_table[] = { + { + .procname = "hyperv_record_panic_msg", + .data = &sysctl_record_panic_msg, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE + }, + {} +}; + +static int hv_die_panic_notify_crash(struct notifier_block *self, + unsigned long val, void *args); + +static struct notifier_block hyperv_die_report_block = { + .notifier_call = hv_die_panic_notify_crash, +}; + +static struct notifier_block hyperv_panic_report_block = { + .notifier_call = hv_die_panic_notify_crash, +}; + +/* + * The following callback works both as die and panic notifier; its + * goal is to provide panic information to the hypervisor unless the + * kmsg dumper is used [see hv_kmsg_dump()], which provides more + * information but isn't always available. + * + * Notice that both the panic/die report notifiers are registered only + * if we have the capability HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE set. + */ +static int hv_die_panic_notify_crash(struct notifier_block *self, + unsigned long val, void *args) +{ + struct pt_regs *regs; + bool is_die; + + /* Don't notify Hyper-V unless we have a die oops event or panic. */ + if (self == &hyperv_panic_report_block) { + is_die = false; + regs = current_pt_regs(); + } else { /* die event */ + if (val != DIE_OOPS) + return NOTIFY_DONE; + + is_die = true; + regs = ((struct die_args *)args)->regs; + } + + /* + * Hyper-V should be notified only once about a panic/die. If we will + * be calling hv_kmsg_dump() later with kmsg data, don't do the + * notification here. + */ + if (!sysctl_record_panic_msg || !hv_panic_page) + hyperv_report_panic(regs, val, is_die); + + return NOTIFY_DONE; +} + +/* + * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg + * buffer and call into Hyper-V to transfer the data. + */ +static void hv_kmsg_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) +{ + struct kmsg_dump_iter iter; + size_t bytes_written; + + /* We are only interested in panics. */ + if (reason != KMSG_DUMP_PANIC || !sysctl_record_panic_msg) + return; + + /* + * Write dump contents to the page. No need to synchronize; panic should + * be single-threaded. + */ + kmsg_dump_rewind(&iter); + kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, + &bytes_written); + if (!bytes_written) + return; + /* + * P3 to contain the physical address of the panic page & P4 to + * contain the size of the panic data in that page. Rest of the + * registers are no-op when the NOTIFY_MSG flag is set. + */ + hv_set_register(HV_REGISTER_CRASH_P0, 0); + hv_set_register(HV_REGISTER_CRASH_P1, 0); + hv_set_register(HV_REGISTER_CRASH_P2, 0); + hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page)); + hv_set_register(HV_REGISTER_CRASH_P4, bytes_written); + + /* + * Let Hyper-V know there is crash data available along with + * the panic message. + */ + hv_set_register(HV_REGISTER_CRASH_CTL, + (HV_CRASH_CTL_CRASH_NOTIFY | + HV_CRASH_CTL_CRASH_NOTIFY_MSG)); +} + +static struct kmsg_dumper hv_kmsg_dumper = { + .dump = hv_kmsg_dump, +}; + +static void hv_kmsg_dump_unregister(void) +{ + kmsg_dump_unregister(&hv_kmsg_dumper); + unregister_die_notifier(&hyperv_die_report_block); + atomic_notifier_chain_unregister(&panic_notifier_list, + &hyperv_panic_report_block); + + hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_panic_page = NULL; +} + +static void hv_kmsg_dump_register(void) +{ + int ret; + + hv_panic_page = hv_alloc_hyperv_zeroed_page(); + if (!hv_panic_page) { + pr_err("Hyper-V: panic message page memory allocation failed\n"); + return; + } + + ret = kmsg_dump_register(&hv_kmsg_dumper); + if (ret) { + pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); + hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_panic_page = NULL; + } +} + int __init hv_common_init(void) { int i; + if (hv_is_isolation_supported()) + sysctl_record_panic_msg = 0; + /* * Hyper-V expects to get crash register data or kmsg when * crash enlightment is available and system crashes. Set @@ -84,8 +290,33 @@ int __init hv_common_init(void) * kernel. */ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + u64 hyperv_crash_ctl; + crash_kexec_post_notifiers = true; pr_info("Hyper-V: enabling crash_kexec_post_notifiers\n"); + + /* + * Panic message recording (sysctl_record_panic_msg) + * is enabled by default in non-isolated guests and + * disabled by default in isolated guests; the panic + * message recording won't be available in isolated + * guests should the following registration fail. + */ + hv_ctl_table_hdr = register_sysctl("kernel", hv_ctl_table); + if (!hv_ctl_table_hdr) + pr_err("Hyper-V: sysctl table register error"); + + /* + * Register for panic kmsg callback only if the right + * capability is supported by the hypervisor. + */ + hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL); + if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) + hv_kmsg_dump_register(); + + register_die_notifier(&hyperv_die_report_block); + atomic_notifier_chain_register(&panic_notifier_list, + &hyperv_panic_report_block); } /* @@ -311,14 +542,3 @@ u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_s return HV_STATUS_INVALID_PARAMETER; } EXPORT_SYMBOL_GPL(hv_ghcb_hypercall); - -void __weak *hv_map_memory(void *addr, unsigned long size) -{ - return NULL; -} -EXPORT_SYMBOL_GPL(hv_map_memory); - -void __weak hv_unmap_memory(void *addr) -{ -} -EXPORT_SYMBOL_GPL(hv_unmap_memory); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index dc673edf053c..55f2086841ae 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -122,10 +122,6 @@ enum { struct hv_per_cpu_context { void *synic_message_page; void *synic_event_page; - /* - * buffer to post messages to the host. - */ - void *post_msg_page; /* * Starting with win8, we can take channel interrupts on any CPU; @@ -241,8 +237,6 @@ struct vmbus_connection { * is child->parent notification */ struct hv_monitor_page *monitor_pages[2]; - void *monitor_pages_original[2]; - phys_addr_t monitor_pages_pa[2]; struct list_head chn_msg_list; spinlock_t channelmsg_lock; diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 2111e97c3b63..3c9b02471760 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -186,8 +186,6 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, struct page *pages, u32 page_cnt, u32 max_pkt_size) { struct page **pages_wraparound; - unsigned long *pfns_wraparound; - u64 pfn; int i; BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); @@ -196,50 +194,30 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, * First page holds struct hv_ring_buffer, do wraparound mapping for * the rest. */ - if (hv_isolation_type_snp()) { - pfn = page_to_pfn(pages) + - PFN_DOWN(ms_hyperv.shared_gpa_boundary); + pages_wraparound = kcalloc(page_cnt * 2 - 1, + sizeof(struct page *), + GFP_KERNEL); + if (!pages_wraparound) + return -ENOMEM; - pfns_wraparound = kcalloc(page_cnt * 2 - 1, - sizeof(unsigned long), GFP_KERNEL); - if (!pfns_wraparound) - return -ENOMEM; + pages_wraparound[0] = pages; + for (i = 0; i < 2 * (page_cnt - 1); i++) + pages_wraparound[i + 1] = + &pages[i % (page_cnt - 1) + 1]; - pfns_wraparound[0] = pfn; - for (i = 0; i < 2 * (page_cnt - 1); i++) - pfns_wraparound[i + 1] = pfn + i % (page_cnt - 1) + 1; + ring_info->ring_buffer = (struct hv_ring_buffer *) + vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, + pgprot_decrypted(PAGE_KERNEL)); - ring_info->ring_buffer = (struct hv_ring_buffer *) - vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, - pgprot_decrypted(PAGE_KERNEL)); - kfree(pfns_wraparound); - - if (!ring_info->ring_buffer) - return -ENOMEM; - - /* Zero ring buffer after setting memory host visibility. */ - memset(ring_info->ring_buffer, 0x00, PAGE_SIZE * page_cnt); - } else { - pages_wraparound = kcalloc(page_cnt * 2 - 1, - sizeof(struct page *), - GFP_KERNEL); - if (!pages_wraparound) - return -ENOMEM; - - pages_wraparound[0] = pages; - for (i = 0; i < 2 * (page_cnt - 1); i++) - pages_wraparound[i + 1] = - &pages[i % (page_cnt - 1) + 1]; - - ring_info->ring_buffer = (struct hv_ring_buffer *) - vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, - PAGE_KERNEL); - - kfree(pages_wraparound); - if (!ring_info->ring_buffer) - return -ENOMEM; - } + kfree(pages_wraparound); + if (!ring_info->ring_buffer) + return -ENOMEM; + /* + * Ensure the header page is zero'ed since + * encryption status may have changed. + */ + memset(ring_info->ring_buffer, 0, HV_HYP_PAGE_SIZE); ring_info->ring_buffer->read_index = ring_info->ring_buffer->write_index = 0; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index e9e1c4139e0d..1c65a6dfb9fa 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -44,30 +45,16 @@ struct vmbus_dynid { struct hv_vmbus_device_id id; }; -static struct acpi_device *hv_acpi_dev; +static struct device *hv_dev; static int hyperv_cpuhp_online; -static void *hv_panic_page; - static long __percpu *vmbus_evt; /* Values parsed from ACPI DSDT */ int vmbus_irq; int vmbus_interrupt; -/* - * Boolean to control whether to report panic messages over Hyper-V. - * - * It can be set via /proc/sys/kernel/hyperv_record_panic_msg - */ -static int sysctl_record_panic_msg = 1; - -static int hyperv_report_reg(void) -{ - return !sysctl_record_panic_msg || !hv_panic_page; -} - /* * The panic notifier below is responsible solely for unloading the * vmbus connection, which is necessary in a panic event. @@ -88,54 +75,6 @@ static struct notifier_block hyperv_panic_vmbus_unload_block = { .priority = INT_MIN + 1, /* almost the latest one to execute */ }; -static int hv_die_panic_notify_crash(struct notifier_block *self, - unsigned long val, void *args); - -static struct notifier_block hyperv_die_report_block = { - .notifier_call = hv_die_panic_notify_crash, -}; -static struct notifier_block hyperv_panic_report_block = { - .notifier_call = hv_die_panic_notify_crash, -}; - -/* - * The following callback works both as die and panic notifier; its - * goal is to provide panic information to the hypervisor unless the - * kmsg dumper is used [see hv_kmsg_dump()], which provides more - * information but isn't always available. - * - * Notice that both the panic/die report notifiers are registered only - * if we have the capability HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE set. - */ -static int hv_die_panic_notify_crash(struct notifier_block *self, - unsigned long val, void *args) -{ - struct pt_regs *regs; - bool is_die; - - /* Don't notify Hyper-V unless we have a die oops event or panic. */ - if (self == &hyperv_panic_report_block) { - is_die = false; - regs = current_pt_regs(); - } else { /* die event */ - if (val != DIE_OOPS) - return NOTIFY_DONE; - - is_die = true; - regs = ((struct die_args *)args)->regs; - } - - /* - * Hyper-V should be notified only once about a panic/die. If we will - * be calling hv_kmsg_dump() later with kmsg data, don't do the - * notification here. - */ - if (hyperv_report_reg()) - hyperv_report_panic(regs, val, is_die); - - return NOTIFY_DONE; -} - static const char *fb_mmio_name = "fb_range"; static struct resource *fb_mmio; static struct resource *hyperv_mmio; @@ -143,7 +82,7 @@ static DEFINE_MUTEX(hyperv_mmio_lock); static int vmbus_exists(void) { - if (hv_acpi_dev == NULL) + if (hv_dev == NULL) return -ENODEV; return 0; @@ -684,7 +623,7 @@ static const struct attribute_group vmbus_dev_group = { __ATTRIBUTE_GROUPS(vmbus_dev); /* Set up the attribute for /sys/bus/vmbus/hibernation */ -static ssize_t hibernation_show(struct bus_type *bus, char *buf) +static ssize_t hibernation_show(const struct bus_type *bus, char *buf) { return sprintf(buf, "%d\n", !!hv_is_hibernation_supported()); } @@ -932,7 +871,7 @@ static int vmbus_dma_configure(struct device *child_device) * On x86/x64 coherence is assumed and these calls have no effect. */ hv_setup_dma_ops(child_device, - device_get_dma_attr(&hv_acpi_dev->dev) == DEV_DMA_COHERENT); + device_get_dma_attr(hv_dev) == DEV_DMA_COHERENT); return 0; } @@ -1377,98 +1316,6 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg - * buffer and call into Hyper-V to transfer the data. - */ -static void hv_kmsg_dump(struct kmsg_dumper *dumper, - enum kmsg_dump_reason reason) -{ - struct kmsg_dump_iter iter; - size_t bytes_written; - - /* We are only interested in panics. */ - if ((reason != KMSG_DUMP_PANIC) || (!sysctl_record_panic_msg)) - return; - - /* - * Write dump contents to the page. No need to synchronize; panic should - * be single-threaded. - */ - kmsg_dump_rewind(&iter); - kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, - &bytes_written); - if (!bytes_written) - return; - /* - * P3 to contain the physical address of the panic page & P4 to - * contain the size of the panic data in that page. Rest of the - * registers are no-op when the NOTIFY_MSG flag is set. - */ - hv_set_register(HV_REGISTER_CRASH_P0, 0); - hv_set_register(HV_REGISTER_CRASH_P1, 0); - hv_set_register(HV_REGISTER_CRASH_P2, 0); - hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page)); - hv_set_register(HV_REGISTER_CRASH_P4, bytes_written); - - /* - * Let Hyper-V know there is crash data available along with - * the panic message. - */ - hv_set_register(HV_REGISTER_CRASH_CTL, - (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG)); -} - -static struct kmsg_dumper hv_kmsg_dumper = { - .dump = hv_kmsg_dump, -}; - -static void hv_kmsg_dump_register(void) -{ - int ret; - - hv_panic_page = hv_alloc_hyperv_zeroed_page(); - if (!hv_panic_page) { - pr_err("Hyper-V: panic message page memory allocation failed\n"); - return; - } - - ret = kmsg_dump_register(&hv_kmsg_dumper); - if (ret) { - pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); - hv_free_hyperv_page((unsigned long)hv_panic_page); - hv_panic_page = NULL; - } -} - -static struct ctl_table_header *hv_ctl_table_hdr; - -/* - * sysctl option to allow the user to control whether kmsg data should be - * reported to Hyper-V on panic. - */ -static struct ctl_table hv_ctl_table[] = { - { - .procname = "hyperv_record_panic_msg", - .data = &sysctl_record_panic_msg, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE - }, - {} -}; - -static struct ctl_table hv_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = hv_ctl_table - }, - {} -}; - /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -1532,38 +1379,6 @@ static int vmbus_bus_init(void) if (ret) goto err_connect; - if (hv_is_isolation_supported()) - sysctl_record_panic_msg = 0; - - /* - * Only register if the crash MSRs are available - */ - if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { - u64 hyperv_crash_ctl; - /* - * Panic message recording (sysctl_record_panic_msg) - * is enabled by default in non-isolated guests and - * disabled by default in isolated guests; the panic - * message recording won't be available in isolated - * guests should the following registration fail. - */ - hv_ctl_table_hdr = register_sysctl_table(hv_root_table); - if (!hv_ctl_table_hdr) - pr_err("Hyper-V: sysctl table register error"); - - /* - * Register for panic kmsg callback only if the right - * capability is supported by the hypervisor. - */ - hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL); - if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) - hv_kmsg_dump_register(); - - register_die_notifier(&hyperv_die_report_block); - atomic_notifier_chain_register(&panic_notifier_list, - &hyperv_panic_report_block); - } - /* * Always register the vmbus unload panic notifier because we * need to shut the VMbus channel connection on panic. @@ -1588,8 +1403,6 @@ err_alloc: } err_setup: bus_unregister(&hv_bus); - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; return ret; } @@ -2090,7 +1903,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) &child_device_obj->channel->offermsg.offer.if_instance); child_device_obj->device.bus = &hv_bus; - child_device_obj->device.parent = &hv_acpi_dev->dev; + child_device_obj->device.parent = hv_dev; child_device_obj->device.release = vmbus_device_release; child_device_obj->device.dma_parms = &child_device_obj->dma_parms; @@ -2151,7 +1964,7 @@ void vmbus_device_unregister(struct hv_device *device_obj) device_unregister(&device_obj->device); } - +#ifdef CONFIG_ACPI /* * VMBUS is an acpi enumerated device. Get the information we * need from DSDT. @@ -2260,8 +2073,9 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) return AE_OK; } +#endif -static void vmbus_acpi_remove(struct acpi_device *device) +static void vmbus_mmio_remove(void) { struct resource *cur_res; struct resource *next_res; @@ -2280,7 +2094,7 @@ static void vmbus_acpi_remove(struct acpi_device *device) } } -static void vmbus_reserve_fb(void) +static void __maybe_unused vmbus_reserve_fb(void) { resource_size_t start = 0, size; struct pci_dev *pdev; @@ -2440,13 +2254,15 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) } EXPORT_SYMBOL_GPL(vmbus_free_mmio); -static int vmbus_acpi_add(struct acpi_device *device) +#ifdef CONFIG_ACPI +static int vmbus_acpi_add(struct platform_device *pdev) { acpi_status result; int ret_val = -ENODEV; struct acpi_device *ancestor; + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); - hv_acpi_dev = device; + hv_dev = &device->dev; /* * Older versions of Hyper-V for ARM64 fail to include the _CCA @@ -2488,9 +2304,64 @@ static int vmbus_acpi_add(struct acpi_device *device) acpi_walk_err: if (ret_val) - vmbus_acpi_remove(device); + vmbus_mmio_remove(); return ret_val; } +#else +static int vmbus_acpi_add(struct platform_device *pdev) +{ + return 0; +} +#endif + +static int vmbus_device_add(struct platform_device *pdev) +{ + struct resource **cur_res = &hyperv_mmio; + struct of_range range; + struct of_range_parser parser; + struct device_node *np = pdev->dev.of_node; + int ret; + + hv_dev = &pdev->dev; + + ret = of_range_parser_init(&parser, np); + if (ret) + return ret; + + for_each_of_range(&parser, &range) { + struct resource *res; + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) { + vmbus_mmio_remove(); + return -ENOMEM; + } + + res->name = "hyperv mmio"; + res->flags = range.flags; + res->start = range.cpu_addr; + res->end = range.cpu_addr + range.size; + + *cur_res = res; + cur_res = &res->sibling; + } + + return ret; +} + +static int vmbus_platform_driver_probe(struct platform_device *pdev) +{ + if (acpi_disabled) + return vmbus_device_add(pdev); + else + return vmbus_acpi_add(pdev); +} + +static int vmbus_platform_driver_remove(struct platform_device *pdev) +{ + vmbus_mmio_remove(); + return 0; +} #ifdef CONFIG_PM_SLEEP static int vmbus_bus_suspend(struct device *dev) @@ -2629,7 +2500,17 @@ static int vmbus_bus_resume(struct device *dev) #define vmbus_bus_resume NULL #endif /* CONFIG_PM_SLEEP */ -static const struct acpi_device_id vmbus_acpi_device_ids[] = { +static const __maybe_unused struct of_device_id vmbus_of_match[] = { + { + .compatible = "microsoft,vmbus", + }, + { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, vmbus_of_match); + +static const __maybe_unused struct acpi_device_id vmbus_acpi_device_ids[] = { {"VMBUS", 0}, {"VMBus", 0}, {"", 0}, @@ -2657,15 +2538,16 @@ static const struct dev_pm_ops vmbus_bus_pm = { .restore_noirq = vmbus_bus_resume }; -static struct acpi_driver vmbus_acpi_driver = { - .name = "vmbus", - .ids = vmbus_acpi_device_ids, - .ops = { - .add = vmbus_acpi_add, - .remove = vmbus_acpi_remove, - }, - .drv.pm = &vmbus_bus_pm, - .drv.probe_type = PROBE_FORCE_SYNCHRONOUS, +static struct platform_driver vmbus_platform_driver = { + .probe = vmbus_platform_driver_probe, + .remove = vmbus_platform_driver_remove, + .driver = { + .name = "vmbus", + .acpi_match_table = ACPI_PTR(vmbus_acpi_device_ids), + .of_match_table = of_match_ptr(vmbus_of_match), + .pm = &vmbus_bus_pm, + .probe_type = PROBE_FORCE_SYNCHRONOUS, + } }; static void hv_kexec_handler(void) @@ -2749,12 +2631,11 @@ static int __init hv_acpi_init(void) /* * Get ACPI resources first. */ - ret = acpi_bus_register_driver(&vmbus_acpi_driver); - + ret = platform_driver_register(&vmbus_platform_driver); if (ret) return ret; - if (!hv_acpi_dev) { + if (!hv_dev) { ret = -ENODEV; goto cleanup; } @@ -2784,8 +2665,8 @@ static int __init hv_acpi_init(void) return 0; cleanup: - acpi_bus_unregister_driver(&vmbus_acpi_driver); - hv_acpi_dev = NULL; + platform_driver_unregister(&vmbus_platform_driver); + hv_dev = NULL; return ret; } @@ -2817,13 +2698,6 @@ static void __exit vmbus_exit(void) vmbus_free_channels(); kfree(vmbus_connection.channels); - if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { - kmsg_dump_unregister(&hv_kmsg_dumper); - unregister_die_notifier(&hyperv_die_report_block); - atomic_notifier_chain_unregister(&panic_notifier_list, - &hyperv_panic_report_block); - } - /* * The vmbus panic notifier is always registered, hence we should * also unconditionally unregister it here as well. @@ -2831,14 +2705,11 @@ static void __exit vmbus_exit(void) atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_vmbus_unload_block); - free_page((unsigned long)hv_panic_page); - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; bus_unregister(&hv_bus); cpuhp_remove_state(hyperv_cpuhp_online); hv_synic_free(); - acpi_bus_unregister_driver(&vmbus_acpi_driver); + platform_driver_unregister(&vmbus_platform_driver); } diff --git a/drivers/hwmon/drivetemp.c b/drivers/hwmon/drivetemp.c index e73b7bfc6af3..6bdd21aa005a 100644 --- a/drivers/hwmon/drivetemp.c +++ b/drivers/hwmon/drivetemp.c @@ -550,7 +550,7 @@ static const struct hwmon_chip_info drivetemp_chip_info = { * The device argument points to sdev->sdev_dev. Its parent is * sdev->sdev_gendev, which we can use to get the scsi_device pointer. */ -static int drivetemp_add(struct device *dev, struct class_interface *intf) +static int drivetemp_add(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev->parent); struct drivetemp_data *st; @@ -585,7 +585,7 @@ abort: return err; } -static void drivetemp_remove(struct device *dev, struct class_interface *intf) +static void drivetemp_remove(struct device *dev) { struct drivetemp_data *st, *tmp; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 508cb768c267..573b83b6c08c 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -138,7 +138,6 @@ static void hwmon_dev_release(struct device *dev) static struct class hwmon_class = { .name = "hwmon", - .owner = THIS_MODULE, .dev_groups = hwmon_dev_attr_groups, .dev_release = hwmon_dev_release, }; diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index ba2f6a4f8c16..7b177b9fbb09 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -507,6 +507,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M50H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, {} }; diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 22b8f2a70b3b..ada694ba9f95 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -949,6 +949,5 @@ struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev, } EXPORT_SYMBOL_GPL(devm_hwspin_lock_request_specific); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Hardware spinlock interface"); MODULE_AUTHOR("Ohad Ben-Cohen "); diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index a48c97da8165..89e8ed214ea4 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -402,6 +402,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, trace_id = coresight_trace_id_get_cpu_id(cpu); if (!IS_VALID_CS_TRACE_ID(trace_id)) { cpumask_clear_cpu(cpu, mask); + coresight_release_path(path); continue; } @@ -901,6 +902,7 @@ int __init etm_perf_init(void) etm_pmu.addr_filters_sync = etm_addr_filters_sync; etm_pmu.addr_filters_validate = etm_addr_filters_validate; etm_pmu.nr_addr_filters = ETM_ADDR_CMP_MAX; + etm_pmu.module = THIS_MODULE; ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1); if (ret == 0) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 918d461fcf4a..eaa296ced167 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -942,7 +942,7 @@ tmc_etr_buf_insert_barrier_packet(struct etr_buf *etr_buf, u64 offset) len = tmc_etr_buf_get_data(etr_buf, offset, CORESIGHT_BARRIER_PKT_SIZE, &bufp); - if (WARN_ON(len < CORESIGHT_BARRIER_PKT_SIZE)) + if (WARN_ON(len < 0 || len < CORESIGHT_BARRIER_PKT_SIZE)) return -EINVAL; coresight_insert_barrier_packet(bufp); return offset + CORESIGHT_BARRIER_PKT_SIZE; diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index d4b55d989a26..8ea3fb5e4c7f 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -353,7 +353,6 @@ static void gxp_i2c_chk_data_ack(struct gxp_i2c_drvdata *drvdata) writew(value, drvdata->base + GXP_I2CMCMD); } -#if IS_ENABLED(CONFIG_I2C_SLAVE) static bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata) { u8 value; @@ -437,7 +436,6 @@ static bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata) return true; } -#endif static irqreturn_t gxp_i2c_irq_handler(int irq, void *_drvdata) { diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index a49b14d52a98..1af0a637d7f1 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -639,7 +639,7 @@ static int __maybe_unused lpi2c_runtime_suspend(struct device *dev) { struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); - clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks); + clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks); pinctrl_pm_select_sleep_state(dev); return 0; @@ -651,7 +651,7 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev) int ret; pinctrl_pm_select_default_state(dev); - ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks); + ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks); if (ret) { dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret); return ret; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2b4e2be51318..4199f57a6bf2 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1058,7 +1058,7 @@ omap_i2c_isr(int irq, void *dev_id) u16 stat; stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); - mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK; if (stat & mask) ret = IRQ_WAKE_THREAD; diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 2e74747eec9c..ec706a3aba26 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -284,7 +284,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap, */ /* First try proper modalias */ - if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) { + if (of_alias_from_compatible(node, tmp, sizeof(tmp)) >= 0) { snprintf(type, type_size, "MAC,%s", tmp); return true; } diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 6aab84c8d22b..157066f06a32 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -242,9 +242,10 @@ struct tegra_i2c_hw_feature { * @is_dvc: identifies the DVC I2C controller, has a different register layout * @is_vi: identifies the VI I2C controller, has a different register layout * @msg_complete: transfer completion notifier + * @msg_buf_remaining: size of unsent data in the message buffer + * @msg_len: length of message in current transfer * @msg_err: error code for completed message * @msg_buf: pointer to current message data - * @msg_buf_remaining: size of unsent data in the message buffer * @msg_read: indicates that the transfer is a read access * @timings: i2c timings information like bus frequency * @multimaster_mode: indicates that I2C controller is in multi-master mode @@ -277,6 +278,7 @@ struct tegra_i2c_dev { struct completion msg_complete; size_t msg_buf_remaining; + unsigned int msg_len; int msg_err; u8 *msg_buf; @@ -1169,7 +1171,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev, else i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); - packet_header = msg->len - 1; + packet_header = i2c_dev->msg_len - 1; if (i2c_dev->dma_mode && !i2c_dev->msg_read) *dma_buf++ = packet_header; @@ -1242,20 +1244,32 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, return err; i2c_dev->msg_buf = msg->buf; + i2c_dev->msg_len = msg->len; - /* The condition true implies smbus block read and len is already read */ - if (msg->flags & I2C_M_RECV_LEN && end_state != MSG_END_CONTINUE) - i2c_dev->msg_buf = msg->buf + 1; - - i2c_dev->msg_buf_remaining = msg->len; i2c_dev->msg_err = I2C_ERR_NONE; i2c_dev->msg_read = !!(msg->flags & I2C_M_RD); reinit_completion(&i2c_dev->msg_complete); + /* + * For SMBUS block read command, read only 1 byte in the first transfer. + * Adjust that 1 byte for the next transfer in the msg buffer and msg + * length. + */ + if (msg->flags & I2C_M_RECV_LEN) { + if (end_state == MSG_END_CONTINUE) { + i2c_dev->msg_len = 1; + } else { + i2c_dev->msg_buf += 1; + i2c_dev->msg_len -= 1; + } + } + + i2c_dev->msg_buf_remaining = i2c_dev->msg_len; + if (i2c_dev->msg_read) - xfer_size = msg->len; + xfer_size = i2c_dev->msg_len; else - xfer_size = msg->len + I2C_PACKET_HEADER_SIZE; + xfer_size = i2c_dev->msg_len + I2C_PACKET_HEADER_SIZE; xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD); @@ -1295,7 +1309,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, if (!i2c_dev->msg_read) { if (i2c_dev->dma_mode) { memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE, - msg->buf, msg->len); + msg->buf, i2c_dev->msg_len); dma_sync_single_for_device(i2c_dev->dma_dev, i2c_dev->dma_phys, @@ -1352,7 +1366,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, i2c_dev->dma_phys, xfer_size, DMA_FROM_DEVICE); - memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, msg->len); + memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len); } } @@ -1408,8 +1422,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE); if (ret) break; - /* Set the read byte as msg len */ - msgs[i].len = msgs[i].buf[0]; + /* Set the msg length from first byte */ + msgs[i].len += msgs[i].buf[0]; dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len); } ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type); diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 5c1376386897..a6c407d36800 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -27,7 +27,7 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node, memset(info, 0, sizeof(*info)); - if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) { + if (of_alias_from_compatible(node, info->type, sizeof(info->type)) < 0) { dev_err(dev, "of_i2c: modalias failure on %pOF\n", node); return -EINVAL; } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 95a0b63ac560..a01b59e3599b 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -751,7 +751,7 @@ static int __init i2c_dev_init(void) if (res) goto out; - i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); + i2c_dev_class = class_create("i2c-dev"); if (IS_ERR(i2c_dev_class)) { res = PTR_ERR(i2c_dev_class); goto out_unreg_chrdev; diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 54e4c34b4a22..08aeb69a7800 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -21,6 +21,7 @@ static DEFINE_IDR(i3c_bus_idr); static DEFINE_MUTEX(i3c_core_lock); +static int __i3c_first_dynamic_bus_num; /** * i3c_bus_maintenance_lock - Lock the bus for a maintenance operation @@ -419,9 +420,9 @@ static void i3c_bus_cleanup(struct i3c_bus *i3cbus) mutex_unlock(&i3c_core_lock); } -static int i3c_bus_init(struct i3c_bus *i3cbus) +static int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np) { - int ret; + int ret, start, end, id = -1; init_rwsem(&i3cbus->lock); INIT_LIST_HEAD(&i3cbus->devs.i2c); @@ -429,8 +430,19 @@ static int i3c_bus_init(struct i3c_bus *i3cbus) i3c_bus_init_addrslots(i3cbus); i3cbus->mode = I3C_BUS_MODE_PURE; + if (np) + id = of_alias_get_id(np, "i3c"); + mutex_lock(&i3c_core_lock); - ret = idr_alloc(&i3c_bus_idr, i3cbus, 0, 0, GFP_KERNEL); + if (id >= 0) { + start = id; + end = start + 1; + } else { + start = __i3c_first_dynamic_bus_num; + end = 0; + } + + ret = idr_alloc(&i3c_bus_idr, i3cbus, start, end, GFP_KERNEL); mutex_unlock(&i3c_core_lock); if (ret < 0) @@ -2606,7 +2618,7 @@ int i3c_master_register(struct i3c_master_controller *master, INIT_LIST_HEAD(&master->boardinfo.i2c); INIT_LIST_HEAD(&master->boardinfo.i3c); - ret = i3c_bus_init(i3cbus); + ret = i3c_bus_init(i3cbus, master->dev.of_node); if (ret) return ret; @@ -2695,17 +2707,13 @@ EXPORT_SYMBOL_GPL(i3c_master_register); * @master: master used to send frames on the bus * * Basically undo everything done in i3c_master_register(). - * - * Return: 0 in case of success, a negative error code otherwise. */ -int i3c_master_unregister(struct i3c_master_controller *master) +void i3c_master_unregister(struct i3c_master_controller *master) { i3c_master_i2c_adapter_cleanup(master); i3c_master_unregister_i3c_devs(master); i3c_master_bus_cleanup(master); device_unregister(&master->dev); - - return 0; } EXPORT_SYMBOL_GPL(i3c_master_unregister); @@ -2834,8 +2842,16 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev) static int __init i3c_init(void) { - int res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); + int res; + res = of_alias_get_highest_id("i3c"); + if (res >= 0) { + mutex_lock(&i3c_core_lock); + __i3c_first_dynamic_bus_num = res + 1; + mutex_unlock(&i3c_core_lock); + } + + res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res) return res; diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig index 3b8f95916f46..90dee3ec5520 100644 --- a/drivers/i3c/master/Kconfig +++ b/drivers/i3c/master/Kconfig @@ -22,6 +22,20 @@ config DW_I3C_MASTER This driver can also be built as a module. If so, the module will be called dw-i3c-master. +config AST2600_I3C_MASTER + tristate "ASPEED AST2600 I3C master driver" + depends on DW_I3C_MASTER + depends on ARCH_ASPEED || COMPILE_TEST + select MFD_SYSCON + help + Support for ASPEED AST2600 I3C Controller. + + This hardware is an instance of the DW I3C controller; this + driver adds platform- specific support for AST2600 hardware. + + This driver can also be built as a module. If so, the module + will be called ast2600-i3c-master. + config SVC_I3C_MASTER tristate "Silvaco I3C Dual-Role Master driver" depends on I3C diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile index b3fee0f690b2..3e97960160bc 100644 --- a/drivers/i3c/master/Makefile +++ b/drivers/i3c/master/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_CDNS_I3C_MASTER) += i3c-master-cdns.o obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o +obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/ diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c new file mode 100644 index 000000000000..09ed19d489e9 --- /dev/null +++ b/drivers/i3c/master/ast2600-i3c-master.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Code Construct + * + * Author: Jeremy Kerr + */ + +#include +#include +#include +#include +#include +#include + +#include "dw-i3c-master.h" + +/* AST2600-specific global register set */ +#define AST2600_I3CG_REG0(idx) (((idx) * 4 * 4) + 0x10) +#define AST2600_I3CG_REG1(idx) (((idx) * 4 * 4) + 0x14) + +#define AST2600_I3CG_REG0_SDA_PULLUP_EN_MASK GENMASK(29, 28) +#define AST2600_I3CG_REG0_SDA_PULLUP_EN_2K (0x0 << 28) +#define AST2600_I3CG_REG0_SDA_PULLUP_EN_750 (0x2 << 28) +#define AST2600_I3CG_REG0_SDA_PULLUP_EN_545 (0x3 << 28) + +#define AST2600_I3CG_REG1_I2C_MODE BIT(0) +#define AST2600_I3CG_REG1_TEST_MODE BIT(1) +#define AST2600_I3CG_REG1_ACT_MODE_MASK GENMASK(3, 2) +#define AST2600_I3CG_REG1_ACT_MODE(x) (((x) << 2) & AST2600_I3CG_REG1_ACT_MODE_MASK) +#define AST2600_I3CG_REG1_PENDING_INT_MASK GENMASK(7, 4) +#define AST2600_I3CG_REG1_PENDING_INT(x) (((x) << 4) & AST2600_I3CG_REG1_PENDING_INT_MASK) +#define AST2600_I3CG_REG1_SA_MASK GENMASK(14, 8) +#define AST2600_I3CG_REG1_SA(x) (((x) << 8) & AST2600_I3CG_REG1_SA_MASK) +#define AST2600_I3CG_REG1_SA_EN BIT(15) +#define AST2600_I3CG_REG1_INST_ID_MASK GENMASK(19, 16) +#define AST2600_I3CG_REG1_INST_ID(x) (((x) << 16) & AST2600_I3CG_REG1_INST_ID_MASK) + +#define AST2600_DEFAULT_SDA_PULLUP_OHMS 2000 + +#define DEV_ADDR_TABLE_IBI_PEC BIT(11) + +struct ast2600_i3c { + struct dw_i3c_master dw; + struct regmap *global_regs; + unsigned int global_idx; + unsigned int sda_pullup; +}; + +static struct ast2600_i3c *to_ast2600_i3c(struct dw_i3c_master *dw) +{ + return container_of(dw, struct ast2600_i3c, dw); +} + +static int ast2600_i3c_pullup_to_reg(unsigned int ohms, u32 *regp) +{ + u32 reg; + + switch (ohms) { + case 2000: + reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_2K; + break; + case 750: + reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_750; + break; + case 545: + reg = AST2600_I3CG_REG0_SDA_PULLUP_EN_545; + break; + default: + return -EINVAL; + } + + if (regp) + *regp = reg; + + return 0; +} + +static int ast2600_i3c_init(struct dw_i3c_master *dw) +{ + struct ast2600_i3c *i3c = to_ast2600_i3c(dw); + u32 reg = 0; + int rc; + + /* reg0: set SDA pullup values */ + rc = ast2600_i3c_pullup_to_reg(i3c->sda_pullup, ®); + if (rc) + return rc; + + rc = regmap_write(i3c->global_regs, + AST2600_I3CG_REG0(i3c->global_idx), reg); + if (rc) + return rc; + + /* reg1: set up the instance id, but leave everything else disabled, + * as it's all for client mode + */ + reg = AST2600_I3CG_REG1_INST_ID(i3c->global_idx); + rc = regmap_write(i3c->global_regs, + AST2600_I3CG_REG1(i3c->global_idx), reg); + + return rc; +} + +static void ast2600_i3c_set_dat_ibi(struct dw_i3c_master *i3c, + struct i3c_dev_desc *dev, + bool enable, u32 *dat) +{ + /* + * The ast2600 i3c controller will lock up on receiving 4n+1-byte IBIs + * if the PEC is disabled. We have no way to restrict the length of + * IBIs sent to the controller, so we need to unconditionally enable + * PEC checking, which means we drop a byte of payload data + */ + if (enable && dev->info.bcr & I3C_BCR_IBI_PAYLOAD) { + dev_warn_once(&i3c->base.dev, + "Enabling PEC workaround. IBI payloads will be truncated\n"); + *dat |= DEV_ADDR_TABLE_IBI_PEC; + } +} + +static const struct dw_i3c_platform_ops ast2600_i3c_ops = { + .init = ast2600_i3c_init, + .set_dat_ibi = ast2600_i3c_set_dat_ibi, +}; + +static int ast2600_i3c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct of_phandle_args gspec; + struct ast2600_i3c *i3c; + int rc; + + i3c = devm_kzalloc(&pdev->dev, sizeof(*i3c), GFP_KERNEL); + if (!i3c) + return -ENOMEM; + + rc = of_parse_phandle_with_fixed_args(np, "aspeed,global-regs", 1, 0, + &gspec); + if (rc) + return -ENODEV; + + i3c->global_regs = syscon_node_to_regmap(gspec.np); + of_node_put(gspec.np); + + if (IS_ERR(i3c->global_regs)) + return PTR_ERR(i3c->global_regs); + + i3c->global_idx = gspec.args[0]; + + rc = of_property_read_u32(np, "sda-pullup-ohms", &i3c->sda_pullup); + if (rc) + i3c->sda_pullup = AST2600_DEFAULT_SDA_PULLUP_OHMS; + + rc = ast2600_i3c_pullup_to_reg(i3c->sda_pullup, NULL); + if (rc) + dev_err(&pdev->dev, "invalid sda-pullup value %d\n", + i3c->sda_pullup); + + i3c->dw.platform_ops = &ast2600_i3c_ops; + i3c->dw.ibi_capable = true; + return dw_i3c_common_probe(&i3c->dw, pdev); +} + +static void ast2600_i3c_remove(struct platform_device *pdev) +{ + struct dw_i3c_master *dw_i3c = platform_get_drvdata(pdev); + + dw_i3c_common_remove(dw_i3c); +} + +static const struct of_device_id ast2600_i3c_master_of_match[] = { + { .compatible = "aspeed,ast2600-i3c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ast2600_i3c_master_of_match); + +static struct platform_driver ast2600_i3c_driver = { + .probe = ast2600_i3c_probe, + .remove_new = ast2600_i3c_remove, + .driver = { + .name = "ast2600-i3c-master", + .of_match_table = ast2600_i3c_master_of_match, + }, +}; +module_platform_driver(ast2600_i3c_driver); + +MODULE_AUTHOR("Jeremy Kerr "); +MODULE_DESCRIPTION("ASPEED AST2600 I3C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 48954d3e6571..9332ae5f6419 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -21,6 +21,8 @@ #include #include +#include "dw-i3c-master.h" + #define DEVICE_CTRL 0x0 #define DEV_CTRL_ENABLE BIT(31) #define DEV_CTRL_RESUME BIT(30) @@ -74,7 +76,22 @@ #define RX_TX_DATA_PORT 0x14 #define IBI_QUEUE_STATUS 0x18 +#define IBI_QUEUE_STATUS_IBI_ID(x) (((x) & GENMASK(15, 8)) >> 8) +#define IBI_QUEUE_STATUS_DATA_LEN(x) ((x) & GENMASK(7, 0)) +#define IBI_QUEUE_IBI_ADDR(x) (IBI_QUEUE_STATUS_IBI_ID(x) >> 1) +#define IBI_QUEUE_IBI_RNW(x) (IBI_QUEUE_STATUS_IBI_ID(x) & BIT(0)) +#define IBI_TYPE_MR(x) \ + ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) +#define IBI_TYPE_HJ(x) \ + ((IBI_QUEUE_IBI_ADDR(x) == I3C_HOT_JOIN_ADDR) && !IBI_QUEUE_IBI_RNW(x)) +#define IBI_TYPE_SIRQ(x) \ + ((IBI_QUEUE_IBI_ADDR(x) != I3C_HOT_JOIN_ADDR) && IBI_QUEUE_IBI_RNW(x)) + #define QUEUE_THLD_CTRL 0x1c +#define QUEUE_THLD_CTRL_IBI_STAT_MASK GENMASK(31, 24) +#define QUEUE_THLD_CTRL_IBI_STAT(x) (((x) - 1) << 24) +#define QUEUE_THLD_CTRL_IBI_DATA_MASK GENMASK(20, 16) +#define QUEUE_THLD_CTRL_IBI_DATA(x) ((x) << 16) #define QUEUE_THLD_CTRL_RESP_BUF_MASK GENMASK(15, 8) #define QUEUE_THLD_CTRL_RESP_BUF(x) (((x) - 1) << 8) @@ -184,13 +201,13 @@ #define EXTENDED_CAPABILITY 0xe8 #define SLAVE_CONFIG 0xec +#define DEV_ADDR_TABLE_IBI_MDB BIT(12) +#define DEV_ADDR_TABLE_SIR_REJECT BIT(13) #define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31) #define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16)) #define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0)) #define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2)) -#define MAX_DEVS 32 - #define I3C_BUS_SDR1_SCL_RATE 8000000 #define I3C_BUS_SDR2_SCL_RATE 6000000 #define I3C_BUS_SDR3_SCL_RATE 4000000 @@ -201,11 +218,6 @@ #define XFER_TIMEOUT (msecs_to_jiffies(1000)) -struct dw_i3c_master_caps { - u8 cmdfifodepth; - u8 datafifodepth; -}; - struct dw_i3c_cmd { u32 cmd_lo; u32 cmd_hi; @@ -224,27 +236,9 @@ struct dw_i3c_xfer { struct dw_i3c_cmd cmds[]; }; -struct dw_i3c_master { - struct i3c_master_controller base; - u16 maxdevs; - u16 datstartaddr; - u32 free_pos; - struct { - struct list_head list; - struct dw_i3c_xfer *cur; - spinlock_t lock; - } xferqueue; - struct dw_i3c_master_caps caps; - void __iomem *regs; - struct reset_control *core_rst; - struct clk *core_clk; - char version[5]; - char type[5]; - u8 addrs[MAX_DEVS]; -}; - struct dw_i3c_i2c_dev_data { u8 index; + struct i3c_generic_ibi_pool *ibi_pool; }; static u8 even_parity(u8 p) @@ -315,7 +309,7 @@ static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr) int pos; for (pos = 0; pos < master->maxdevs; pos++) { - if (addr == master->addrs[pos]) + if (addr == master->devs[pos].addr) return pos; } @@ -342,18 +336,30 @@ static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, } } -static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, - u8 *bytes, int nbytes) +static void dw_i3c_master_read_fifo(struct dw_i3c_master *master, + int reg, u8 *bytes, int nbytes) { - readsl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); + readsl(master->regs + reg, bytes, nbytes / 4); if (nbytes & 3) { u32 tmp; - readsl(master->regs + RX_TX_DATA_PORT, &tmp, 1); + readsl(master->regs + reg, &tmp, 1); memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); } } +static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, + u8 *bytes, int nbytes) +{ + return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes); +} + +static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master, + u8 *bytes, int nbytes) +{ + return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes); +} + static struct dw_i3c_xfer * dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds) { @@ -538,7 +544,11 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master) scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt); writel(scl_timing, master->regs + SCL_I3C_PP_TIMING); - if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT)) + /* + * In pure i3c mode, MST_FREE represents tCAS. In shared mode, this + * will be set up by dw_i2c_clk_cfg as tLOW. + */ + if (master->base.bus.mode == I3C_BUS_MODE_PURE) writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); lcnt = max_t(u8, @@ -598,6 +608,10 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) u32 thld_ctrl; int ret; + ret = master->platform_ops->init(master); + if (ret) + return ret; + switch (bus->mode) { case I3C_BUS_MODE_MIXED_FAST: case I3C_BUS_MODE_MIXED_LIMITED: @@ -615,7 +629,11 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m) } thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); - thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK; + thld_ctrl &= ~(QUEUE_THLD_CTRL_RESP_BUF_MASK | + QUEUE_THLD_CTRL_IBI_STAT_MASK | + QUEUE_THLD_CTRL_IBI_STAT_MASK); + thld_ctrl |= QUEUE_THLD_CTRL_IBI_STAT(1) | + QUEUE_THLD_CTRL_IBI_DATA(31); writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL); @@ -779,7 +797,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m) if (ret < 0) return -ENOSPC; - master->addrs[pos] = ret; + master->devs[pos].addr = ret; p = even_parity(ret); last_addr = ret; ret |= (p << 7); @@ -816,7 +834,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m) for (pos = 0; pos < master->maxdevs; pos++) { if (newdevs & BIT(pos)) - i3c_master_add_i3c_dev_locked(m, master->addrs[pos]); + i3c_master_add_i3c_dev_locked(m, master->devs[pos].addr); } dw_i3c_master_free_xfer(xfer); @@ -887,6 +905,13 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) dw_i3c_master_dequeue_xfer(master, xfer); + for (i = 0; i < i3c_nxfers; i++) { + struct dw_i3c_cmd *cmd = &xfer->cmds[i]; + + if (i3c_xfers[i].rnw) + i3c_xfers[i].len = cmd->rx_len; + } + ret = xfer->ret; dw_i3c_master_free_xfer(xfer); @@ -908,11 +933,11 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); - master->addrs[data->index] = 0; + master->devs[data->index].addr = 0; master->free_pos |= BIT(data->index); data->index = pos; - master->addrs[pos] = dev->info.dyn_addr; + master->devs[pos].addr = dev->info.dyn_addr; master->free_pos &= ~BIT(pos); } @@ -920,7 +945,7 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); - master->addrs[data->index] = dev->info.dyn_addr; + master->devs[data->index].addr = dev->info.dyn_addr; return 0; } @@ -941,11 +966,11 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) return -ENOMEM; data->index = pos; - master->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr; + master->devs[pos].addr = dev->info.dyn_addr ? : dev->info.static_addr; master->free_pos &= ~BIT(pos); i3c_dev_set_master_data(dev, data); - writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->addrs[pos]), + writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr), master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); @@ -963,7 +988,7 @@ static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); i3c_dev_set_master_data(dev, NULL); - master->addrs[data->index] = 0; + master->devs[data->index].addr = 0; master->free_pos |= BIT(data->index); kfree(data); } @@ -1049,7 +1074,7 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) return -ENOMEM; data->index = pos; - master->addrs[pos] = dev->addr; + master->devs[pos].addr = dev->addr; master->free_pos &= ~BIT(pos); i2c_dev_set_master_data(dev, data); @@ -1072,11 +1097,243 @@ static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); i2c_dev_set_master_data(dev, NULL); - master->addrs[data->index] = 0; + master->devs[data->index].addr = 0; master->free_pos |= BIT(data->index); kfree(data); } +static int dw_i3c_master_request_ibi(struct i3c_dev_desc *dev, + const struct i3c_ibi_setup *req) +{ + struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + unsigned long flags; + + data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req); + if (IS_ERR(data->ibi_pool)) + return PTR_ERR(data->ibi_pool); + + spin_lock_irqsave(&master->devs_lock, flags); + master->devs[data->index].ibi_dev = dev; + spin_unlock_irqrestore(&master->devs_lock, flags); + + return 0; +} + +static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev) +{ + struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + unsigned long flags; + + spin_lock_irqsave(&master->devs_lock, flags); + master->devs[data->index].ibi_dev = NULL; + spin_unlock_irqrestore(&master->devs_lock, flags); + + i3c_generic_ibi_free_pool(data->ibi_pool); + data->ibi_pool = NULL; +} + +static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, + struct i3c_dev_desc *dev, + u8 idx, bool enable) +{ + unsigned long flags; + u32 dat_entry, reg; + bool global; + + dat_entry = DEV_ADDR_TABLE_LOC(master->datstartaddr, idx); + + spin_lock_irqsave(&master->devs_lock, flags); + reg = readl(master->regs + dat_entry); + if (enable) { + reg &= ~DEV_ADDR_TABLE_SIR_REJECT; + if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) + reg |= DEV_ADDR_TABLE_IBI_MDB; + } else { + reg |= DEV_ADDR_TABLE_SIR_REJECT; + } + master->platform_ops->set_dat_ibi(master, dev, enable, ®); + writel(reg, master->regs + dat_entry); + + reg = readl(master->regs + IBI_SIR_REQ_REJECT); + if (enable) { + global = reg == 0xffffffff; + reg &= ~BIT(idx); + } else { + global = reg == 0; + reg |= BIT(idx); + } + writel(reg, master->regs + IBI_SIR_REQ_REJECT); + + if (global) { + reg = readl(master->regs + INTR_STATUS_EN); + reg &= ~INTR_IBI_THLD_STAT; + if (enable) + reg |= INTR_IBI_THLD_STAT; + writel(reg, master->regs + INTR_STATUS_EN); + + reg = readl(master->regs + INTR_SIGNAL_EN); + reg &= ~INTR_IBI_THLD_STAT; + if (enable) + reg |= INTR_IBI_THLD_STAT; + writel(reg, master->regs + INTR_SIGNAL_EN); + } + + spin_unlock_irqrestore(&master->devs_lock, flags); +} + +static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev) +{ + struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + int rc; + + dw_i3c_master_set_sir_enabled(master, dev, data->index, true); + + rc = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); + + if (rc) + dw_i3c_master_set_sir_enabled(master, dev, data->index, false); + + return rc; +} + +static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev) +{ + struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + int rc; + + rc = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); + if (rc) + return rc; + + dw_i3c_master_set_sir_enabled(master, dev, data->index, false); + + return 0; +} + +static void dw_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, + struct i3c_ibi_slot *slot) +{ + struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); + + i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); +} + +static void dw_i3c_master_drain_ibi_queue(struct dw_i3c_master *master, + int len) +{ + int i; + + for (i = 0; i < DIV_ROUND_UP(len, 4); i++) + readl(master->regs + IBI_QUEUE_STATUS); +} + +static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master, + u32 status) +{ + struct dw_i3c_i2c_dev_data *data; + struct i3c_ibi_slot *slot; + struct i3c_dev_desc *dev; + unsigned long flags; + u8 addr, len; + int idx; + + addr = IBI_QUEUE_IBI_ADDR(status); + len = IBI_QUEUE_STATUS_DATA_LEN(status); + + /* + * We be tempted to check the error status in bit 30; however, due + * to the PEC errata workaround on some platform implementations (see + * ast2600_i3c_set_dat_ibi()), those will almost always have a PEC + * error on IBI payload data, as well as losing the last byte of + * payload. + * + * If we implement error status checking on that bit, we may need + * a new platform op to validate it. + */ + + spin_lock_irqsave(&master->devs_lock, flags); + idx = dw_i3c_master_get_addr_pos(master, addr); + if (idx < 0) { + dev_dbg_ratelimited(&master->base.dev, + "IBI from unknown addr 0x%x\n", addr); + goto err_drain; + } + + dev = master->devs[idx].ibi_dev; + if (!dev || !dev->ibi) { + dev_dbg_ratelimited(&master->base.dev, + "IBI from non-requested dev idx %d\n", idx); + goto err_drain; + } + + data = i3c_dev_get_master_data(dev); + slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); + if (!slot) { + dev_dbg_ratelimited(&master->base.dev, + "No IBI slots available\n"); + goto err_drain; + } + + if (dev->ibi->max_payload_len < len) { + dev_dbg_ratelimited(&master->base.dev, + "IBI payload len %d greater than max %d\n", + len, dev->ibi->max_payload_len); + goto err_drain; + } + + if (len) { + dw_i3c_master_read_ibi_fifo(master, slot->data, len); + slot->len = len; + } + i3c_master_queue_ibi(dev, slot); + + spin_unlock_irqrestore(&master->devs_lock, flags); + + return; + +err_drain: + dw_i3c_master_drain_ibi_queue(master, len); + + spin_unlock_irqrestore(&master->devs_lock, flags); +} + +/* "ibis": referring to In-Band Interrupts, and not + * https://en.wikipedia.org/wiki/Australian_white_ibis. The latter should + * not be handled. + */ +static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master) +{ + unsigned int i, len, n_ibis; + u32 reg; + + reg = readl(master->regs + QUEUE_STATUS_LEVEL); + n_ibis = QUEUE_STATUS_IBI_STATUS_CNT(reg); + if (!n_ibis) + return; + + for (i = 0; i < n_ibis; i++) { + reg = readl(master->regs + IBI_QUEUE_STATUS); + + if (IBI_TYPE_SIRQ(reg)) { + dw_i3c_master_handle_ibi_sir(master, reg); + } else { + len = IBI_QUEUE_STATUS_DATA_LEN(reg); + dev_info(&master->base.dev, + "unsupported IBI type 0x%lx len %d\n", + IBI_QUEUE_STATUS_IBI_ID(reg), len); + dw_i3c_master_drain_ibi_queue(master, len); + } + } +} + static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) { struct dw_i3c_master *master = dev_id; @@ -1095,6 +1352,9 @@ static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id) writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS); spin_unlock(&master->xferqueue.lock); + if (status & INTR_IBI_THLD_STAT) + dw_i3c_master_irq_handle_ibis(master); + return IRQ_HANDLED; } @@ -1113,14 +1373,51 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = { .i2c_xfers = dw_i3c_master_i2c_xfers, }; -static int dw_i3c_probe(struct platform_device *pdev) +static const struct i3c_master_controller_ops dw_mipi_i3c_ibi_ops = { + .bus_init = dw_i3c_master_bus_init, + .bus_cleanup = dw_i3c_master_bus_cleanup, + .attach_i3c_dev = dw_i3c_master_attach_i3c_dev, + .reattach_i3c_dev = dw_i3c_master_reattach_i3c_dev, + .detach_i3c_dev = dw_i3c_master_detach_i3c_dev, + .do_daa = dw_i3c_master_daa, + .supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd, + .send_ccc_cmd = dw_i3c_master_send_ccc_cmd, + .priv_xfers = dw_i3c_master_priv_xfers, + .attach_i2c_dev = dw_i3c_master_attach_i2c_dev, + .detach_i2c_dev = dw_i3c_master_detach_i2c_dev, + .i2c_xfers = dw_i3c_master_i2c_xfers, + .request_ibi = dw_i3c_master_request_ibi, + .free_ibi = dw_i3c_master_free_ibi, + .enable_ibi = dw_i3c_master_enable_ibi, + .disable_ibi = dw_i3c_master_disable_ibi, + .recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot, +}; + +/* default platform ops implementations */ +static int dw_i3c_platform_init_nop(struct dw_i3c_master *i3c) { - struct dw_i3c_master *master; + return 0; +} + +static void dw_i3c_platform_set_dat_ibi_nop(struct dw_i3c_master *i3c, + struct i3c_dev_desc *dev, + bool enable, u32 *dat) +{ +} + +static const struct dw_i3c_platform_ops dw_i3c_platform_ops_default = { + .init = dw_i3c_platform_init_nop, + .set_dat_ibi = dw_i3c_platform_set_dat_ibi_nop, +}; + +int dw_i3c_common_probe(struct dw_i3c_master *master, + struct platform_device *pdev) +{ + const struct i3c_master_controller_ops *ops; int ret, irq; - master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); - if (!master) - return -ENOMEM; + if (!master->platform_ops) + master->platform_ops = &dw_i3c_platform_ops_default; master->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(master->regs)) @@ -1166,8 +1463,11 @@ static int dw_i3c_probe(struct platform_device *pdev) master->maxdevs = ret >> 16; master->free_pos = GENMASK(master->maxdevs - 1, 0); - ret = i3c_master_register(&master->base, &pdev->dev, - &dw_mipi_i3c_ops, false); + ops = &dw_mipi_i3c_ops; + if (master->ibi_capable) + ops = &dw_mipi_i3c_ibi_ops; + + ret = i3c_master_register(&master->base, &pdev->dev, ops, false); if (ret) goto err_assert_rst; @@ -1181,21 +1481,36 @@ err_disable_core_clk: return ret; } +EXPORT_SYMBOL_GPL(dw_i3c_common_probe); -static int dw_i3c_remove(struct platform_device *pdev) +void dw_i3c_common_remove(struct dw_i3c_master *master) { - struct dw_i3c_master *master = platform_get_drvdata(pdev); - int ret; - - ret = i3c_master_unregister(&master->base); - if (ret) - return ret; + i3c_master_unregister(&master->base); reset_control_assert(master->core_rst); clk_disable_unprepare(master->core_clk); +} +EXPORT_SYMBOL_GPL(dw_i3c_common_remove); - return 0; +/* base platform implementation */ + +static int dw_i3c_probe(struct platform_device *pdev) +{ + struct dw_i3c_master *master; + + master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); + if (!master) + return -ENOMEM; + + return dw_i3c_common_probe(master, pdev); +} + +static void dw_i3c_remove(struct platform_device *pdev) +{ + struct dw_i3c_master *master = platform_get_drvdata(pdev); + + dw_i3c_common_remove(master); } static const struct of_device_id dw_i3c_master_of_match[] = { @@ -1206,10 +1521,10 @@ MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match); static struct platform_driver dw_i3c_driver = { .probe = dw_i3c_probe, - .remove = dw_i3c_remove, + .remove_new = dw_i3c_remove, .driver = { .name = "dw-i3c-master", - .of_match_table = of_match_ptr(dw_i3c_master_of_match), + .of_match_table = dw_i3c_master_of_match, }, }; module_platform_driver(dw_i3c_driver); diff --git a/drivers/i3c/master/dw-i3c-master.h b/drivers/i3c/master/dw-i3c-master.h new file mode 100644 index 000000000000..ab862c5d15fe --- /dev/null +++ b/drivers/i3c/master/dw-i3c-master.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Code Construct + * + * Author: Jeremy Kerr + */ + +#include +#include +#include +#include + +#define DW_I3C_MAX_DEVS 32 + +struct dw_i3c_master_caps { + u8 cmdfifodepth; + u8 datafifodepth; +}; + +struct dw_i3c_dat_entry { + u8 addr; + struct i3c_dev_desc *ibi_dev; +}; + +struct dw_i3c_master { + struct i3c_master_controller base; + u16 maxdevs; + u16 datstartaddr; + u32 free_pos; + struct { + struct list_head list; + struct dw_i3c_xfer *cur; + spinlock_t lock; + } xferqueue; + struct dw_i3c_master_caps caps; + void __iomem *regs; + struct reset_control *core_rst; + struct clk *core_clk; + char version[5]; + char type[5]; + bool ibi_capable; + + /* + * Per-device hardware data, used to manage the device address table + * (DAT) + * + * Locking: the devs array may be referenced in IRQ context while + * processing an IBI. However, IBIs (for a specific device, which + * implies a specific DAT entry) can only happen while interrupts are + * requested for that device, which is serialised against other + * insertions/removals from the array by the global i3c infrastructure. + * So, devs_lock protects against concurrent updates to devs->ibi_dev + * between request_ibi/free_ibi and the IBI irq event. + */ + struct dw_i3c_dat_entry devs[DW_I3C_MAX_DEVS]; + spinlock_t devs_lock; + + /* platform-specific data */ + const struct dw_i3c_platform_ops *platform_ops; +}; + +struct dw_i3c_platform_ops { + /* + * Called on early bus init: the i3c has been set up, but before any + * transactions have taken place. Platform implementations may use to + * perform actual device enabling with the i3c core ready. + */ + int (*init)(struct dw_i3c_master *i3c); + + /* + * Initialise a DAT entry to enable/disable IBIs. Allows the platform + * to perform any device workarounds on the DAT entry before + * inserting into the hardware table. + * + * Called with the DAT lock held; must not sleep. + */ + void (*set_dat_ibi)(struct dw_i3c_master *i3c, + struct i3c_dev_desc *dev, bool enable, u32 *reg); +}; + +extern int dw_i3c_common_probe(struct dw_i3c_master *master, + struct platform_device *pdev); +extern void dw_i3c_common_remove(struct dw_i3c_master *master); + diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 5b37ffe5ad5b..01610fa5b0cc 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -1662,24 +1662,19 @@ err_disable_pclk: return ret; } -static int cdns_i3c_master_remove(struct platform_device *pdev) +static void cdns_i3c_master_remove(struct platform_device *pdev) { struct cdns_i3c_master *master = platform_get_drvdata(pdev); - int ret; - ret = i3c_master_unregister(&master->base); - if (ret) - return ret; + i3c_master_unregister(&master->base); clk_disable_unprepare(master->sysclk); clk_disable_unprepare(master->pclk); - - return 0; } static struct platform_driver cdns_i3c_master = { .probe = cdns_i3c_master_probe, - .remove = cdns_i3c_master_remove, + .remove_new = cdns_i3c_master_remove, .driver = { .name = "cdns-i3c-master", .of_match_table = cdns_i3c_master_of_ids, diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 6aef5ce43cc1..837af83c85f4 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -765,11 +765,11 @@ static int i3c_hci_probe(struct platform_device *pdev) return 0; } -static int i3c_hci_remove(struct platform_device *pdev) +static void i3c_hci_remove(struct platform_device *pdev) { struct i3c_hci *hci = platform_get_drvdata(pdev); - return i3c_master_unregister(&hci->master); + i3c_master_unregister(&hci->master); } static const __maybe_unused struct of_device_id i3c_hci_of_match[] = { @@ -780,7 +780,7 @@ MODULE_DEVICE_TABLE(of, i3c_hci_of_match); static struct platform_driver i3c_hci_driver = { .probe = i3c_hci_probe, - .remove = i3c_hci_remove, + .remove_new = i3c_hci_remove, .driver = { .name = "mipi-i3c-hci", .of_match_table = of_match_ptr(i3c_hci_of_match), diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index d6e9ed74cdcf..e3f454123805 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -1569,19 +1569,14 @@ err_disable_clks: return ret; } -static int svc_i3c_master_remove(struct platform_device *pdev) +static void svc_i3c_master_remove(struct platform_device *pdev) { struct svc_i3c_master *master = platform_get_drvdata(pdev); - int ret; - ret = i3c_master_unregister(&master->base); - if (ret) - return ret; + i3c_master_unregister(&master->base); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) @@ -1619,7 +1614,7 @@ MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); static struct platform_driver svc_i3c_master = { .probe = svc_i3c_master_probe, - .remove = svc_i3c_master_remove, + .remove_new = svc_i3c_master_remove, .driver = { .name = "silvaco-i3c-master", .of_match_table = svc_i3c_master_of_match_tbl, diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 938c17f25d94..aa2d19db2b1d 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -66,8 +66,9 @@ static struct cpuidle_driver intel_idle_driver = { }; /* intel_idle.max_cstate=0 disables driver */ static int max_cstate = CPUIDLE_STATE_MAX - 1; -static unsigned int disabled_states_mask; -static unsigned int preferred_states_mask; +static unsigned int disabled_states_mask __read_mostly; +static unsigned int preferred_states_mask __read_mostly; +static bool force_irq_on __read_mostly; static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; @@ -1838,9 +1839,6 @@ static bool __init intel_idle_verify_cstate(unsigned int mwait_hint) return true; } -static bool force_irq_on __read_mostly; -module_param(force_irq_on, bool, 0444); - static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) { int cstate; @@ -1871,6 +1869,7 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) } for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { + struct cpuidle_state *state; unsigned int mwait_hint; if (intel_idle_max_cstate_reached(cstate)) @@ -1893,29 +1892,39 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) /* Structure copy. */ drv->states[drv->state_count] = cpuidle_state_table[cstate]; + state = &drv->states[drv->state_count]; - if ((cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) || force_irq_on) { - printk("intel_idle: forced intel_idle_irq for state %d\n", cstate); - drv->states[drv->state_count].enter = intel_idle_irq; + if (state->flags & CPUIDLE_FLAG_INIT_XSTATE) { + /* + * Combining with XSTATE with IBRS or IRQ_ENABLE flags + * is not currently supported but this driver. + */ + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IBRS); + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE); + state->enter = intel_idle_xstate; + } else if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && + state->flags & CPUIDLE_FLAG_IBRS) { + /* + * IBRS mitigation requires that C-states are entered + * with interrupts disabled. + */ + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE); + state->enter = intel_idle_ibrs; + } else if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) { + state->enter = intel_idle_irq; + } else if (force_irq_on) { + pr_info("forced intel_idle_irq for state %d\n", cstate); + state->enter = intel_idle_irq; } - if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && - cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) { - WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE); - drv->states[drv->state_count].enter = intel_idle_ibrs; - } - - if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_INIT_XSTATE) - drv->states[drv->state_count].enter = intel_idle_xstate; - if ((disabled_states_mask & BIT(drv->state_count)) || ((icpu->use_acpi || force_use_acpi) && intel_idle_off_by_default(mwait_hint) && - !(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_ALWAYS_ENABLE))) - drv->states[drv->state_count].flags |= CPUIDLE_FLAG_OFF; + !(state->flags & CPUIDLE_FLAG_ALWAYS_ENABLE))) + state->flags |= CPUIDLE_FLAG_OFF; - if (intel_idle_state_needs_timer_stop(&drv->states[drv->state_count])) - drv->states[drv->state_count].flags |= CPUIDLE_FLAG_TIMER_STOP; + if (intel_idle_state_needs_timer_stop(state)) + state->flags |= CPUIDLE_FLAG_TIMER_STOP; drv->state_count++; } @@ -2146,3 +2155,9 @@ MODULE_PARM_DESC(states_off, "Mask of disabled idle states"); */ module_param_named(preferred_cstates, preferred_states_mask, uint, 0444); MODULE_PARM_DESC(preferred_cstates, "Mask of preferred idle states"); +/* + * Debugging option that forces the driver to enter all C-states with + * interrupts enabled. Does not apply to C-states with + * 'CPUIDLE_FLAG_INIT_XSTATE' and 'CPUIDLE_FLAG_IBRS' flags. + */ +module_param(force_irq_on, bool, 0444); diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index b190846c3dc2..52eb46ef84c1 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -30,6 +30,9 @@ config IIO_CONFIGFS (e.g. software triggers). For more info see Documentation/iio/iio_configfs.rst. +config IIO_GTS_HELPER + tristate + config IIO_TRIGGER bool "Enable triggered sampling support" help diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 3be08cdadd7e..9622347a1c1b 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -9,6 +9,7 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o +obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 623f37cbaf50..a68b845f5b4f 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -1688,7 +1688,7 @@ static irqreturn_t bma400_interrupt(int irq, void *private) if (FIELD_GET(BMA400_INT_DRDY_MSK, le16_to_cpu(data->status))) { mutex_unlock(&data->mutex); - iio_trigger_poll_chained(data->trig); + iio_trigger_poll_nested(data->trig); return IRQ_HANDLED; } diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 1c3a72380fb8..b8636fa8eaeb 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -162,7 +162,6 @@ struct kx022a_data { int inc_reg; int ien_reg; - unsigned int g_range; unsigned int state; unsigned int odr_ns; @@ -900,7 +899,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) mutex_lock(&data->mutex); if (data->trigger_enabled) { - iio_trigger_poll_chained(data->trig); + iio_trigger_poll_nested(data->trig); ret = IRQ_HANDLED; } @@ -1049,7 +1048,7 @@ int kx022a_probe_internal(struct device *dev) data->ien_reg = KX022A_REG_INC4; } else { irq = fwnode_irq_get_byname(fwnode, "INT2"); - if (irq <= 0) + if (irq < 0) return dev_err_probe(dev, irq, "No suitable IRQ\n"); data->inc_reg = KX022A_REG_INC5; diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index f97fb68e3a71..ea14e3aaa30a 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1067,7 +1067,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) return IRQ_NONE; if (src & MMA8452_INT_DRDY) { - iio_trigger_poll_chained(indio_dev->trig); + iio_trigger_poll_nested(indio_dev->trig); ret = IRQ_HANDLED; } diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index af94d3adf6d8..6690fa37da8f 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -951,7 +951,7 @@ static irqreturn_t msa311_irq_thread(int irq, void *p) } if (new_data_int_enabled) - iio_trigger_poll_chained(msa311->new_data_trig); + iio_trigger_poll_nested(msa311->new_data_trig); return IRQ_HANDLED; } diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 56ed0c776d4a..e7525615712b 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -39,6 +39,7 @@ #define LIS302DL_ACCEL_DEV_NAME "lis302dl" #define LSM303C_ACCEL_DEV_NAME "lsm303c_accel" #define SC7A20_ACCEL_DEV_NAME "sc7a20" +#define IIS328DQ_ACCEL_DEV_NAME "iis328dq" #ifdef CONFIG_IIO_BUFFER diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 6b8562f684d5..282e539157f8 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -517,6 +517,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = H3LIS331DL_ACCEL_DEV_NAME, + [1] = IIS328DQ_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { @@ -1290,12 +1291,12 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev) adev = ACPI_COMPANION(indio_dev->dev.parent); if (!adev) - return 0; + return -ENXIO; /* Read _ONT data, which should be a package of 6 integers. */ status = acpi_evaluate_object(adev->handle, "_ONT", NULL, &buffer); if (status == AE_NOT_FOUND) { - return 0; + return -ENXIO; } else if (ACPI_FAILURE(status)) { dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n", status); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 3f02fd5d5946..fb9e2d6f4210 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -119,6 +119,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "silan,sc7a20", .data = SC7A20_ACCEL_DEV_NAME, }, + { + .compatible = "st,iis328dq", + .data = IIS328DQ_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -157,6 +161,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, { SC7A20_ACCEL_DEV_NAME }, + { IIS328DQ_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 5740dc1820bd..f72a24f45322 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -100,6 +100,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm303c-accel", .data = LSM303C_ACCEL_DEV_NAME, }, + { + .compatible = "st,iis328dq", + .data = IIS328DQ_ACCEL_DEV_NAME, + }, {} }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -157,6 +161,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LIS3DE_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, { LSM303C_ACCEL_DEV_NAME }, + { IIS328DQ_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 45af2302be53..eb2b09ef5d5b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1229,6 +1229,16 @@ config TI_ADS7924 This driver can also be built as a module. If so, the module will be called ti-ads7924. +config TI_ADS1100 + tristate "Texas Instruments ADS1100 and ADS1000 ADC" + depends on I2C + help + If you say yes here you get support for Texas Instruments ADS1100 and + ADS1000 ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads1100. + config TI_ADS7950 tristate "Texas Instruments ADS7950 ADC driver" depends on SPI && GPIOLIB diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 36c18177322a..e07e4a3e6237 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -108,6 +108,7 @@ obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o +obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 38394341fd6e..5a5dd5e87ffc 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1817,6 +1817,11 @@ static const struct clk_ops ad4130_int_clk_ops = { .unprepare = ad4130_int_clk_unprepare, }; +static void ad4130_clk_del_provider(void *of_node) +{ + of_clk_del_provider(of_node); +} + static int ad4130_setup_int_clk(struct ad4130_state *st) { struct device *dev = &st->spi->dev; @@ -1824,6 +1829,7 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) struct clk_init_data init; const char *clk_name; struct clk *clk; + int ret; if (st->int_pin_sel == AD4130_INT_PIN_CLK || st->mclk_sel != AD4130_MCLK_76_8KHZ) @@ -1843,7 +1849,11 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) if (IS_ERR(clk)) return PTR_ERR(clk); - return of_clk_add_provider(of_node, of_clk_src_simple_get, clk); + ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node); } static int ad4130_setup(struct iio_dev *indio_dev) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 55a6ab591016..99bb604b78c8 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -897,10 +897,6 @@ static const struct iio_info ad7195_info = { __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \ BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) -#define AD719x_SHORTED_CHANNEL(_si, _channel1, _address) \ - __AD719x_CHANNEL(_si, _channel1, -1, _address, "shorted", IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) - #define AD719x_TEMP_CHANNEL(_si, _address) \ __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL) @@ -908,7 +904,7 @@ static const struct iio_chan_spec ad7192_channels[] = { AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), - AD719x_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M), + AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), @@ -922,7 +918,7 @@ static const struct iio_chan_spec ad7193_channels[] = { AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M), AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M), AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP), - AD719x_SHORTED_CHANNEL(5, 2, AD7193_CH_AIN2P_AIN2M), + AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M), AD719x_CHANNEL(6, 1, AD7193_CH_AIN1), AD719x_CHANNEL(7, 2, AD7193_CH_AIN2), AD719x_CHANNEL(8, 3, AD7193_CH_AIN3), diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index dd6b603f65ea..1928d9ae5bcf 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -477,7 +477,7 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) if (iio_buffer_enabled(indio_dev)) { gpiod_set_value(st->gpio_convst, 0); - iio_trigger_poll_chained(st->trig); + iio_trigger_poll_nested(st->trig); } else { complete(&st->completion); } diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index d8570f620785..7e2192870743 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -584,6 +584,10 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de init_completion(&sigma_delta->completion); sigma_delta->irq_dis = true; + + /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */ + irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY); + ret = devm_request_irq(dev, sigma_delta->spi->irq, ad_sd_data_rdy_trig_poll, sigma_delta->info->irq_flags | IRQF_NO_AUTOEN, diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 7258912fe17b..df67b63ccf69 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -1194,7 +1194,7 @@ static void at91_dma_buffer_done(void *data) { struct iio_dev *indio_dev = data; - iio_trigger_poll_chained(indio_dev->trig); + iio_trigger_poll_nested(indio_dev->trig); } static int at91_adc_dma_start(struct iio_dev *indio_dev) @@ -2400,12 +2400,8 @@ static int at91_adc_probe(struct platform_device *pdev) st->dma_st.phys_addr = res->start; st->irq = platform_get_irq(pdev, 0); - if (st->irq <= 0) { - if (!st->irq) - st->irq = -ENXIO; - + if (st->irq < 0) return st->irq; - } st->per_clk = devm_clk_get(&pdev->dev, "adc_clk"); if (IS_ERR(st->per_clk)) diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 53bf7d4899d2..75bda94dbce1 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -5,6 +5,7 @@ * Quentin Schulz */ +#include #include #include #include @@ -22,20 +23,20 @@ #include #define AXP20X_ADC_EN1_MASK GENMASK(7, 0) - #define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7)) + #define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0)) #define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0) #define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1) -#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0)) -#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1) #define AXP20X_ADC_RATE_MASK GENMASK(7, 6) +#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK) + +#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK) + #define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4) #define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK) -#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK) -#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK) #define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x) #define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK) #define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x)) @@ -234,7 +235,7 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { struct axp20x_adc_iio *info = iio_priv(indio_dev); - int size = 12; + int ret, size; /* * N.B.: Unlike the Chinese datasheets tell, the charging current is @@ -246,10 +247,11 @@ static int axp20x_adc_raw(struct iio_dev *indio_dev, else size = 12; - *val = axp20x_read_variable_width(info->regmap, chan->address, size); - if (*val < 0) - return *val; + ret = axp20x_read_variable_width(info->regmap, chan->address, size); + if (ret < 0) + return ret; + *val = ret; return IIO_VAL_INT; } @@ -257,11 +259,13 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { struct axp20x_adc_iio *info = iio_priv(indio_dev); + int ret; - *val = axp20x_read_variable_width(info->regmap, chan->address, 12); - if (*val < 0) - return *val; + ret = axp20x_read_variable_width(info->regmap, chan->address, 12); + if (ret < 0) + return ret; + *val = ret; return IIO_VAL_INT; } @@ -269,11 +273,13 @@ static int axp813_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { struct axp20x_adc_iio *info = iio_priv(indio_dev); + int ret; - *val = axp20x_read_variable_width(info->regmap, chan->address, 12); - if (*val < 0) - return *val; + ret = axp20x_read_variable_width(info->regmap, chan->address, 12); + if (ret < 0) + return ret; + *val = ret; return IIO_VAL_INT; } @@ -443,27 +449,27 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, int *val) { struct axp20x_adc_iio *info = iio_priv(indio_dev); + unsigned int regval; int ret; - ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val); + ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, ®val); if (ret < 0) return ret; switch (channel) { case AXP20X_GPIO0_V: - *val &= AXP20X_GPIO10_IN_RANGE_GPIO0; + regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO0, regval); break; case AXP20X_GPIO1_V: - *val &= AXP20X_GPIO10_IN_RANGE_GPIO1; + regval = FIELD_GET(AXP20X_GPIO10_IN_RANGE_GPIO1, regval); break; default: return -EINVAL; } - *val = *val ? 700000 : 0; - + *val = regval ? 700000 : 0; return IIO_VAL_INT; } @@ -548,7 +554,7 @@ static int axp20x_write_raw(struct iio_dev *indio_dev, long mask) { struct axp20x_adc_iio *info = iio_priv(indio_dev); - unsigned int reg, regval; + unsigned int regmask, regval; /* * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets @@ -560,25 +566,22 @@ static int axp20x_write_raw(struct iio_dev *indio_dev, if (val != 0 && val != 700000) return -EINVAL; - val = val ? 1 : 0; - switch (chan->channel) { case AXP20X_GPIO0_V: - reg = AXP20X_GPIO10_IN_RANGE_GPIO0; - regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val); + regmask = AXP20X_GPIO10_IN_RANGE_GPIO0; + regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO0, !!val); break; case AXP20X_GPIO1_V: - reg = AXP20X_GPIO10_IN_RANGE_GPIO1; - regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val); + regmask = AXP20X_GPIO10_IN_RANGE_GPIO1; + regval = FIELD_PREP(AXP20X_GPIO10_IN_RANGE_GPIO1, !!val); break; default: return -EINVAL; } - return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg, - regval); + return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval); } static const struct iio_info axp20x_adc_iio_info = { @@ -620,9 +623,9 @@ struct axp_data { int num_channels; struct iio_chan_spec const *channels; unsigned long adc_en1_mask; + unsigned long adc_en2_mask; int (*adc_rate)(struct axp20x_adc_iio *info, int rate); - bool adc_en2; struct iio_map *maps; }; @@ -631,8 +634,8 @@ static const struct axp_data axp20x_data = { .num_channels = ARRAY_SIZE(axp20x_adc_channels), .channels = axp20x_adc_channels, .adc_en1_mask = AXP20X_ADC_EN1_MASK, + .adc_en2_mask = AXP20X_ADC_EN2_MASK, .adc_rate = axp20x_adc_rate, - .adc_en2 = true, .maps = axp20x_maps, }; @@ -642,7 +645,6 @@ static const struct axp_data axp22x_data = { .channels = axp22x_adc_channels, .adc_en1_mask = AXP22X_ADC_EN1_MASK, .adc_rate = axp22x_adc_rate, - .adc_en2 = false, .maps = axp22x_maps, }; @@ -652,7 +654,6 @@ static const struct axp_data axp813_data = { .channels = axp813_adc_channels, .adc_en1_mask = AXP22X_ADC_EN1_MASK, .adc_rate = axp813_adc_rate, - .adc_en2 = false, .maps = axp22x_maps, }; @@ -710,10 +711,10 @@ static int axp20x_probe(struct platform_device *pdev) /* Enable the ADCs on IP */ regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask); - if (info->data->adc_en2) - /* Enable GPIO0/1 and internal temperature ADCs */ + if (info->data->adc_en2_mask) regmap_update_bits(info->regmap, AXP20X_ADC_EN2, - AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK); + info->data->adc_en2_mask, + info->data->adc_en2_mask); /* Configure ADCs rate */ info->data->adc_rate(info, 100); @@ -738,7 +739,7 @@ fail_register: fail_map: regmap_write(info->regmap, AXP20X_ADC_EN1, 0); - if (info->data->adc_en2) + if (info->data->adc_en2_mask) regmap_write(info->regmap, AXP20X_ADC_EN2, 0); return ret; @@ -754,7 +755,7 @@ static int axp20x_remove(struct platform_device *pdev) regmap_write(info->regmap, AXP20X_ADC_EN1, 0); - if (info->data->adc_en2) + if (info->data->adc_en2_mask) regmap_write(info->regmap, AXP20X_ADC_EN2, 0); return 0; diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index a775d2e40567..dce9ec91e4a7 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -236,8 +236,7 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev, { struct imx93_adc *adc = iio_priv(indio_dev); struct device *dev = adc->dev; - long ret; - u32 vref_uv; + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -253,10 +252,10 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = vref_uv = regulator_get_voltage(adc->vref); + ret = regulator_get_voltage(adc->vref); if (ret < 0) return ret; - *val = vref_uv / 1000; + *val = ret / 1000; *val2 = 12; return IIO_VAL_FRACTIONAL_LOG2; diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index f6895bc9fc4b..6af829349b4e 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -682,7 +682,7 @@ static irqreturn_t max11410_interrupt(int irq, void *dev_id) struct max11410_state *st = iio_priv(indio_dev); if (iio_buffer_enabled(indio_dev)) - iio_trigger_poll_chained(st->trig); + iio_trigger_poll_nested(st->trig); else complete(&st->completion); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 85b6826cc10c..18937a262af6 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -957,14 +957,18 @@ err_lock: return ret; } -static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) +static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); int ret; + /* + * If taking the lock fails we have to assume that BL30 is broken. The + * best we can do then is to release the resources anyhow. + */ ret = meson_sar_adc_lock(indio_dev); if (ret) - return ret; + dev_err(indio_dev->dev.parent, "Failed to lock ADC (%pE)\n", ERR_PTR(ret)); clk_disable_unprepare(priv->adc_clk); @@ -977,9 +981,8 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) regulator_disable(priv->vref); - meson_sar_adc_unlock(indio_dev); - - return 0; + if (!ret) + meson_sar_adc_unlock(indio_dev); } static irqreturn_t meson_sar_adc_irq(int irq, void *data) @@ -1283,14 +1286,18 @@ static int meson_sar_adc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); - return meson_sar_adc_hw_disable(indio_dev); + meson_sar_adc_hw_disable(indio_dev); + + return 0; } static int meson_sar_adc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - return meson_sar_adc_hw_disable(indio_dev); + meson_sar_adc_hw_disable(indio_dev); + + return 0; } static int meson_sar_adc_resume(struct device *dev) diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c index bc62e5a9d50d..0bc112135bca 100644 --- a/drivers/iio/adc/mt6370-adc.c +++ b/drivers/iio/adc/mt6370-adc.c @@ -19,6 +19,7 @@ #include +#define MT6370_REG_DEV_INFO 0x100 #define MT6370_REG_CHG_CTRL3 0x113 #define MT6370_REG_CHG_CTRL7 0x117 #define MT6370_REG_CHG_ADC 0x121 @@ -27,6 +28,7 @@ #define MT6370_ADC_START_MASK BIT(0) #define MT6370_ADC_IN_SEL_MASK GENMASK(7, 4) #define MT6370_AICR_ICHG_MASK GENMASK(7, 2) +#define MT6370_VENID_MASK GENMASK(7, 4) #define MT6370_AICR_100_mA 0x0 #define MT6370_AICR_150_mA 0x1 @@ -47,6 +49,10 @@ #define ADC_CONV_TIME_MS 35 #define ADC_CONV_POLLING_TIME_US 1000 +#define MT6370_VID_RT5081 0x8 +#define MT6370_VID_RT5081A 0xA +#define MT6370_VID_MT6370 0xE + struct mt6370_adc_data { struct device *dev; struct regmap *regmap; @@ -55,6 +61,7 @@ struct mt6370_adc_data { * from being read at the same time. */ struct mutex adc_lock; + unsigned int vid; }; static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan, @@ -98,6 +105,30 @@ adc_unlock: return ret; } +static int mt6370_adc_get_ibus_scale(struct mt6370_adc_data *priv) +{ + switch (priv->vid) { + case MT6370_VID_RT5081: + case MT6370_VID_RT5081A: + case MT6370_VID_MT6370: + return 3350; + default: + return 3875; + } +} + +static int mt6370_adc_get_ibat_scale(struct mt6370_adc_data *priv) +{ + switch (priv->vid) { + case MT6370_VID_RT5081: + case MT6370_VID_RT5081A: + case MT6370_VID_MT6370: + return 2680; + default: + return 3870; + } +} + static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, int chan, int *val1, int *val2) { @@ -123,7 +154,7 @@ static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, case MT6370_AICR_250_mA: case MT6370_AICR_300_mA: case MT6370_AICR_350_mA: - *val1 = 3350; + *val1 = mt6370_adc_get_ibus_scale(priv); break; default: *val1 = 5000; @@ -150,7 +181,7 @@ static int mt6370_adc_read_scale(struct mt6370_adc_data *priv, case MT6370_ICHG_600_mA: case MT6370_ICHG_700_mA: case MT6370_ICHG_800_mA: - *val1 = 2680; + *val1 = mt6370_adc_get_ibat_scale(priv); break; default: *val1 = 5000; @@ -251,6 +282,20 @@ static const struct iio_chan_spec mt6370_adc_channels[] = { MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)), }; +static int mt6370_get_vendor_info(struct mt6370_adc_data *priv) +{ + unsigned int dev_info; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info); + if (ret) + return ret; + + priv->vid = FIELD_GET(MT6370_VENID_MASK, dev_info); + + return 0; +} + static int mt6370_adc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -272,6 +317,10 @@ static int mt6370_adc_probe(struct platform_device *pdev) priv->regmap = regmap; mutex_init(&priv->adc_lock); + ret = mt6370_get_vendor_info(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to get vid\n"); + ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0); if (ret) return dev_err_probe(dev, ret, "Failed to reset ADC\n"); diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index bca79a93cbe4..a50f39143d3e 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -757,13 +757,13 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev) ret = mxs_lradc_adc_trigger_init(iio); if (ret) - goto err_trig; + return ret; ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, &mxs_lradc_adc_trigger_handler, &mxs_lradc_adc_buffer_ops); if (ret) - return ret; + goto err_trig; adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc]; @@ -801,9 +801,9 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev) err_dev: mxs_lradc_adc_hw_stop(adc); - mxs_lradc_adc_trigger_remove(iio); -err_trig: iio_triggered_buffer_cleanup(iio); +err_trig: + mxs_lradc_adc_trigger_remove(iio); return ret; } @@ -814,8 +814,8 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev) iio_device_unregister(iio); mxs_lradc_adc_hw_stop(adc); - mxs_lradc_adc_trigger_remove(iio); iio_triggered_buffer_cleanup(iio); + mxs_lradc_adc_trigger_remove(iio); return 0; } diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 849a697a467e..7dfc9c927a23 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,17 @@ static struct palmas_gpadc_info palmas_gpadc_info[] = { PALMAS_ADC_INFO(IN15, 0, 0, 0, 0, INVALID, INVALID, true), }; +struct palmas_adc_event { + bool enabled; + int channel; + enum iio_event_direction direction; +}; + +struct palmas_gpadc_thresholds { + int high; + int low; +}; + /* * struct palmas_gpadc - the palmas_gpadc structure * @ch0_current: channel 0 current source setting @@ -111,14 +123,33 @@ struct palmas_gpadc { int irq_auto_1; struct palmas_gpadc_info *adc_info; struct completion conv_completion; - struct palmas_adc_wakeup_property wakeup1_data; - struct palmas_adc_wakeup_property wakeup2_data; - bool wakeup1_enable; - bool wakeup2_enable; + struct palmas_adc_event event0; + struct palmas_adc_event event1; + struct palmas_gpadc_thresholds thresholds[PALMAS_ADC_CH_MAX]; int auto_conversion_period; struct mutex lock; }; +static struct palmas_adc_event *palmas_gpadc_get_event(struct palmas_gpadc *adc, + int adc_chan, + enum iio_event_direction dir) +{ + if (adc_chan == adc->event0.channel && dir == adc->event0.direction) + return &adc->event0; + + if (adc_chan == adc->event1.channel && dir == adc->event1.direction) + return &adc->event1; + + return NULL; +} + +static bool palmas_gpadc_channel_is_freerunning(struct palmas_gpadc *adc, + int adc_chan) +{ + return palmas_gpadc_get_event(adc, adc_chan, IIO_EV_DIR_RISING) || + palmas_gpadc_get_event(adc, adc_chan, IIO_EV_DIR_FALLING); +} + /* * GPADC lock issue in AUTO mode. * Impact: In AUTO mode, GPADC conversion can be locked after disabling AUTO @@ -188,11 +219,24 @@ static irqreturn_t palmas_gpadc_irq(int irq, void *data) static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data) { - struct palmas_gpadc *adc = data; + struct iio_dev *indio_dev = data; + struct palmas_gpadc *adc = iio_priv(indio_dev); + struct palmas_adc_event *ev; dev_dbg(adc->dev, "Threshold interrupt %d occurs\n", irq); palmas_disable_auto_conversion(adc); + ev = (irq == adc->irq_auto_0) ? &adc->event0 : &adc->event1; + if (ev->channel != -1) { + enum iio_event_direction dir; + u64 code; + + dir = ev->direction; + code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, ev->channel, + IIO_EV_TYPE_THRESH, dir); + iio_push_event(indio_dev, code, iio_get_time_ns(indio_dev)); + } + return IRQ_HANDLED; } @@ -280,6 +324,9 @@ static int palmas_gpadc_read_prepare(struct palmas_gpadc *adc, int adc_chan) { int ret; + if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) + return 0; /* ADC already running */ + ret = palmas_gpadc_enable(adc, adc_chan, true); if (ret < 0) return ret; @@ -339,28 +386,43 @@ static int palmas_gpadc_start_conversion(struct palmas_gpadc *adc, int adc_chan) unsigned int val; int ret; - init_completion(&adc->conv_completion); - ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_SELECT, - PALMAS_GPADC_SW_SELECT_SW_START_CONV0, - PALMAS_GPADC_SW_SELECT_SW_START_CONV0); - if (ret < 0) { - dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret); - return ret; - } + if (palmas_gpadc_channel_is_freerunning(adc, adc_chan)) { + int event = (adc_chan == adc->event0.channel) ? 0 : 1; + unsigned int reg = (event == 0) ? + PALMAS_GPADC_AUTO_CONV0_LSB : + PALMAS_GPADC_AUTO_CONV1_LSB; - ret = wait_for_completion_timeout(&adc->conv_completion, - PALMAS_ADC_CONVERSION_TIMEOUT); - if (ret == 0) { - dev_err(adc->dev, "conversion not completed\n"); - return -ETIMEDOUT; - } + ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, + reg, &val, 2); + if (ret < 0) { + dev_err(adc->dev, "AUTO_CONV%x_LSB read failed: %d\n", + event, ret); + return ret; + } + } else { + init_completion(&adc->conv_completion); + ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_SW_SELECT, + PALMAS_GPADC_SW_SELECT_SW_START_CONV0, + PALMAS_GPADC_SW_SELECT_SW_START_CONV0); + if (ret < 0) { + dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret); + return ret; + } - ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, - PALMAS_GPADC_SW_CONV0_LSB, &val, 2); - if (ret < 0) { - dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret); - return ret; + ret = wait_for_completion_timeout(&adc->conv_completion, + PALMAS_ADC_CONVERSION_TIMEOUT); + if (ret == 0) { + dev_err(adc->dev, "conversion not completed\n"); + return -ETIMEDOUT; + } + + ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE, + PALMAS_GPADC_SW_CONV0_LSB, &val, 2); + if (ret < 0) { + dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret); + return ret; + } } ret = val & 0xFFF; @@ -386,6 +448,98 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, return val; } +/* + * The high and low threshold values are calculated based on the advice given + * in TI Application Report SLIA087A, "Guide to Using the GPADC in PS65903x, + * TPS65917-Q1, TPS65919-Q1, and TPS65916 Devices". This document recommend + * taking ADC tolerances into account and is based on the device integral non- + * linearity (INL), offset error and gain error: + * + * raw high threshold = (ideal threshold + INL) * gain error + offset error + * + * The gain error include both gain error, as specified in the datasheet, and + * the gain error drift. These paramenters vary depending on device and whether + * the the channel is calibrated (trimmed) or not. + */ +static int palmas_gpadc_threshold_with_tolerance(int val, const int INL, + const int gain_error, + const int offset_error) +{ + val = ((val + INL) * (1000 + gain_error)) / 1000 + offset_error; + + return clamp(val, 0, 0xFFF); +} + +/* + * The values below are taken from the datasheet of TWL6035, TWL6037. + * todo: get max INL, gain error, and offset error from OF. + */ +static int palmas_gpadc_get_high_threshold_raw(struct palmas_gpadc *adc, + struct palmas_adc_event *ev) +{ + const int adc_chan = ev->channel; + int val = adc->thresholds[adc_chan].high; + /* integral nonlinearity, measured in LSB */ + const int max_INL = 2; + /* measured in LSB */ + int max_offset_error; + /* 0.2% when calibrated */ + int max_gain_error = 2; + + val = (val * 1000) / adc->adc_info[adc_chan].gain; + + if (adc->adc_info[adc_chan].is_uncalibrated) { + /* 2% worse */ + max_gain_error += 20; + max_offset_error = 36; + } else { + val = (val * adc->adc_info[adc_chan].gain_error + + adc->adc_info[adc_chan].offset) / + 1000; + max_offset_error = 2; + } + + return palmas_gpadc_threshold_with_tolerance(val, + max_INL, + max_gain_error, + max_offset_error); +} + +/* + * The values below are taken from the datasheet of TWL6035, TWL6037. + * todo: get min INL, gain error, and offset error from OF. + */ +static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc, + struct palmas_adc_event *ev) +{ + const int adc_chan = ev->channel; + int val = adc->thresholds[adc_chan].low; + /* integral nonlinearity, measured in LSB */ + const int min_INL = -2; + /* measured in LSB */ + int min_offset_error; + /* -0.6% when calibrated */ + int min_gain_error = -6; + + val = (val * 1000) / adc->adc_info[adc_chan].gain; + + if (adc->adc_info[adc_chan].is_uncalibrated) { + /* 2% worse */ + min_gain_error -= 20; + min_offset_error = -36; + } else { + val = (val * adc->adc_info[adc_chan].gain_error - + adc->adc_info[adc_chan].offset) / + 1000; + min_offset_error = -2; + } + + return palmas_gpadc_threshold_with_tolerance(val, + min_INL, + min_gain_error, + min_offset_error); +} + static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -393,7 +547,7 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev, int adc_chan = chan->channel; int ret = 0; - if (adc_chan > PALMAS_ADC_CH_MAX) + if (adc_chan >= PALMAS_ADC_CH_MAX) return -EINVAL; mutex_lock(&adc->lock); @@ -432,8 +586,217 @@ out: return ret; } +static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + if (palmas_gpadc_get_event(adc, adc_chan, dir)) + ret = 1; + + mutex_unlock(&adc->lock); + + return ret; +} + +static int palmas_adc_configure_events(struct palmas_gpadc *adc); +static int palmas_adc_reset_events(struct palmas_gpadc *adc); + +static int palmas_gpadc_reconfigure_event_channels(struct palmas_gpadc *adc) +{ + return (adc->event0.enabled || adc->event1.enabled) ? + palmas_adc_configure_events(adc) : + palmas_adc_reset_events(adc); +} + +static int palmas_gpadc_enable_event_config(struct palmas_gpadc *adc, + const struct iio_chan_spec *chan, + enum iio_event_direction dir) +{ + struct palmas_adc_event *ev; + int adc_chan = chan->channel; + + if (palmas_gpadc_get_event(adc, adc_chan, dir)) + /* already enabled */ + return 0; + + if (adc->event0.channel == -1) { + ev = &adc->event0; + } else if (adc->event1.channel == -1) { + /* event0 has to be the lowest channel */ + if (adc_chan < adc->event0.channel) { + adc->event1 = adc->event0; + ev = &adc->event0; + } else { + ev = &adc->event1; + } + } else { /* both AUTO channels already in use */ + dev_warn(adc->dev, "event0 - %d, event1 - %d\n", + adc->event0.channel, adc->event1.channel); + return -EBUSY; + } + + ev->enabled = true; + ev->channel = adc_chan; + ev->direction = dir; + + return palmas_gpadc_reconfigure_event_channels(adc); +} + +static int palmas_gpadc_disable_event_config(struct palmas_gpadc *adc, + const struct iio_chan_spec *chan, + enum iio_event_direction dir) +{ + int adc_chan = chan->channel; + struct palmas_adc_event *ev = palmas_gpadc_get_event(adc, adc_chan, dir); + + if (!ev) + return 0; + + if (ev == &adc->event0) { + adc->event0 = adc->event1; + ev = &adc->event1; + } + + ev->enabled = false; + ev->channel = -1; + ev->direction = IIO_EV_DIR_NONE; + + return palmas_gpadc_reconfigure_event_channels(adc); +} + +static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret; + + if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + if (state) + ret = palmas_gpadc_enable_event_config(adc, chan, dir); + else + ret = palmas_gpadc_disable_event_config(adc, chan, dir); + + mutex_unlock(&adc->lock); + + return ret; +} + +static int palmas_gpadc_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int ret; + + if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + + switch (info) { + case IIO_EV_INFO_VALUE: + *val = (dir == IIO_EV_DIR_RISING) ? + adc->thresholds[adc_chan].high : + adc->thresholds[adc_chan].low; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static int palmas_gpadc_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct palmas_gpadc *adc = iio_priv(indio_dev); + int adc_chan = chan->channel; + int old; + int ret; + + if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + mutex_lock(&adc->lock); + switch (info) { + case IIO_EV_INFO_VALUE: + if (val < 0 || val > 0xFFF) { + ret = -EINVAL; + goto out_unlock; + } + if (dir == IIO_EV_DIR_RISING) { + old = adc->thresholds[adc_chan].high; + adc->thresholds[adc_chan].high = val; + } else { + old = adc->thresholds[adc_chan].low; + adc->thresholds[adc_chan].low = val; + } + ret = 0; + break; + default: + ret = -EINVAL; + goto out_unlock; + } + + if (val != old && palmas_gpadc_get_event(adc, adc_chan, dir)) + ret = palmas_gpadc_reconfigure_event_channels(adc); + +out_unlock: + mutex_unlock(&adc->lock); + + return ret; +} + static const struct iio_info palmas_gpadc_iio_info = { .read_raw = palmas_gpadc_read_raw, + .read_event_config = palmas_gpadc_read_event_config, + .write_event_config = palmas_gpadc_write_event_config, + .read_event_value = palmas_gpadc_read_event_value, + .write_event_value = palmas_gpadc_write_event_value, +}; + +static const struct iio_event_spec palmas_gpadc_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, }; #define PALMAS_ADC_CHAN_IIO(chan, _type, chan_info) \ @@ -444,6 +807,8 @@ static const struct iio_info palmas_gpadc_iio_info = { BIT(chan_info), \ .indexed = 1, \ .channel = PALMAS_ADC_CH_##chan, \ + .event_spec = palmas_gpadc_events, \ + .num_event_specs = ARRAY_SIZE(palmas_gpadc_events) \ } static const struct iio_chan_spec palmas_gpadc_iio_channel[] = { @@ -493,6 +858,13 @@ static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev, return 0; } +static void palmas_gpadc_reset(void *data) +{ + struct palmas_gpadc *adc = data; + if (adc->event0.enabled || adc->event1.enabled) + palmas_adc_reset_events(adc); +} + static int palmas_gpadc_probe(struct platform_device *pdev) { struct palmas_gpadc *adc; @@ -532,53 +904,49 @@ static int palmas_gpadc_probe(struct platform_device *pdev) adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms; adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ); - if (adc->irq < 0) { - dev_err(adc->dev, - "get virq failed: %d\n", adc->irq); - ret = adc->irq; - goto out; - } - ret = request_threaded_irq(adc->irq, NULL, - palmas_gpadc_irq, - IRQF_ONESHOT, dev_name(adc->dev), - adc); - if (ret < 0) { - dev_err(adc->dev, - "request irq %d failed: %d\n", adc->irq, ret); - goto out; - } + if (adc->irq < 0) + return dev_err_probe(adc->dev, adc->irq, "get virq failed\n"); - if (gpadc_pdata->adc_wakeup1_data) { - memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data, - sizeof(adc->wakeup1_data)); - adc->wakeup1_enable = true; - adc->irq_auto_0 = platform_get_irq(pdev, 1); - ret = request_threaded_irq(adc->irq_auto_0, NULL, - palmas_gpadc_irq_auto, - IRQF_ONESHOT, - "palmas-adc-auto-0", adc); - if (ret < 0) { - dev_err(adc->dev, "request auto0 irq %d failed: %d\n", - adc->irq_auto_0, ret); - goto out_irq_free; - } - } + ret = devm_request_threaded_irq(&pdev->dev, adc->irq, NULL, + palmas_gpadc_irq, + IRQF_ONESHOT, dev_name(adc->dev), + adc); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "request irq %d failed\n", adc->irq); - if (gpadc_pdata->adc_wakeup2_data) { - memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data, - sizeof(adc->wakeup2_data)); - adc->wakeup2_enable = true; - adc->irq_auto_1 = platform_get_irq(pdev, 2); - ret = request_threaded_irq(adc->irq_auto_1, NULL, - palmas_gpadc_irq_auto, - IRQF_ONESHOT, - "palmas-adc-auto-1", adc); - if (ret < 0) { - dev_err(adc->dev, "request auto1 irq %d failed: %d\n", - adc->irq_auto_1, ret); - goto out_irq_auto0_free; - } - } + adc->irq_auto_0 = platform_get_irq(pdev, 1); + if (adc->irq_auto_0 < 0) + return dev_err_probe(adc->dev, adc->irq_auto_0, + "get auto0 irq failed\n"); + + ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_0, NULL, + palmas_gpadc_irq_auto, IRQF_ONESHOT, + "palmas-adc-auto-0", indio_dev); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "request auto0 irq %d failed\n", + adc->irq_auto_0); + + adc->irq_auto_1 = platform_get_irq(pdev, 2); + if (adc->irq_auto_1 < 0) + return dev_err_probe(adc->dev, adc->irq_auto_1, + "get auto1 irq failed\n"); + + ret = devm_request_threaded_irq(&pdev->dev, adc->irq_auto_1, NULL, + palmas_gpadc_irq_auto, IRQF_ONESHOT, + "palmas-adc-auto-1", indio_dev); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "request auto1 irq %d failed\n", + adc->irq_auto_1); + + adc->event0.enabled = false; + adc->event0.channel = -1; + adc->event0.direction = IIO_EV_DIR_NONE; + adc->event1.enabled = false; + adc->event1.channel = -1; + adc->event1.direction = IIO_EV_DIR_NONE; /* set the current source 0 (value 0/5/15/20 uA => 0..3) */ if (gpadc_pdata->ch0_current <= 1) @@ -608,11 +976,10 @@ static int palmas_gpadc_probe(struct platform_device *pdev) indio_dev->channels = palmas_gpadc_iio_channel; indio_dev->num_channels = ARRAY_SIZE(palmas_gpadc_iio_channel); - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(adc->dev, "iio_device_register() failed: %d\n", ret); - goto out_irq_auto1_free; - } + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret < 0) + return dev_err_probe(adc->dev, ret, + "iio_device_register() failed\n"); device_set_wakeup_capable(&pdev->dev, 1); for (i = 0; i < PALMAS_ADC_CH_MAX; i++) { @@ -620,41 +987,14 @@ static int palmas_gpadc_probe(struct platform_device *pdev) palmas_gpadc_calibrate(adc, i); } - if (adc->wakeup1_enable || adc->wakeup2_enable) - device_wakeup_enable(&pdev->dev); - - return 0; - -out_irq_auto1_free: - if (gpadc_pdata->adc_wakeup2_data) - free_irq(adc->irq_auto_1, adc); -out_irq_auto0_free: - if (gpadc_pdata->adc_wakeup1_data) - free_irq(adc->irq_auto_0, adc); -out_irq_free: - free_irq(adc->irq, adc); -out: - return ret; -} - -static int palmas_gpadc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(&pdev->dev); - struct palmas_gpadc *adc = iio_priv(indio_dev); - - if (adc->wakeup1_enable || adc->wakeup2_enable) - device_wakeup_disable(&pdev->dev); - iio_device_unregister(indio_dev); - free_irq(adc->irq, adc); - if (adc->wakeup1_enable) - free_irq(adc->irq_auto_0, adc); - if (adc->wakeup2_enable) - free_irq(adc->irq_auto_1, adc); + ret = devm_add_action(&pdev->dev, palmas_gpadc_reset, adc); + if (ret) + return ret; return 0; } -static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) +static int palmas_adc_configure_events(struct palmas_gpadc *adc) { int adc_period, conv; int i; @@ -680,17 +1020,23 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) } conv = 0; - if (adc->wakeup1_enable) { + if (adc->event0.enabled) { + struct palmas_adc_event *ev = &adc->event0; int polarity; - ch0 = adc->wakeup1_data.adc_channel_number; + ch0 = ev->channel; conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN; - if (adc->wakeup1_data.adc_high_threshold > 0) { - thres = adc->wakeup1_data.adc_high_threshold; + switch (ev->direction) { + case IIO_EV_DIR_RISING: + thres = palmas_gpadc_get_high_threshold_raw(adc, ev); polarity = 0; - } else { - thres = adc->wakeup1_data.adc_low_threshold; + break; + case IIO_EV_DIR_FALLING: + thres = palmas_gpadc_get_low_threshold_raw(adc, ev); polarity = PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL; + break; + default: + return -EINVAL; } ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE, @@ -711,17 +1057,23 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) } } - if (adc->wakeup2_enable) { + if (adc->event1.enabled) { + struct palmas_adc_event *ev = &adc->event1; int polarity; - ch1 = adc->wakeup2_data.adc_channel_number; + ch1 = ev->channel; conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN; - if (adc->wakeup2_data.adc_high_threshold > 0) { - thres = adc->wakeup2_data.adc_high_threshold; + switch (ev->direction) { + case IIO_EV_DIR_RISING: + thres = palmas_gpadc_get_high_threshold_raw(adc, ev); polarity = 0; - } else { - thres = adc->wakeup2_data.adc_low_threshold; + break; + case IIO_EV_DIR_FALLING: + thres = palmas_gpadc_get_low_threshold_raw(adc, ev); polarity = PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL; + break; + default: + return -EINVAL; } ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE, @@ -759,7 +1111,7 @@ static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc) return ret; } -static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc) +static int palmas_adc_reset_events(struct palmas_gpadc *adc) { int ret; @@ -781,20 +1133,14 @@ static int palmas_gpadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; - int ret; - if (!device_may_wakeup(dev) || !wakeup) + if (!device_may_wakeup(dev)) return 0; - ret = palmas_adc_wakeup_configure(adc); - if (ret < 0) - return ret; - - if (adc->wakeup1_enable) + if (adc->event0.enabled) enable_irq_wake(adc->irq_auto_0); - if (adc->wakeup2_enable) + if (adc->event1.enabled) enable_irq_wake(adc->irq_auto_1); return 0; @@ -804,20 +1150,14 @@ static int palmas_gpadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); - int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; - int ret; - if (!device_may_wakeup(dev) || !wakeup) + if (!device_may_wakeup(dev)) return 0; - ret = palmas_adc_wakeup_reset(adc); - if (ret < 0) - return ret; - - if (adc->wakeup1_enable) + if (adc->event0.enabled) disable_irq_wake(adc->irq_auto_0); - if (adc->wakeup2_enable) + if (adc->event1.enabled) disable_irq_wake(adc->irq_auto_1); return 0; @@ -834,7 +1174,6 @@ MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl); static struct platform_driver palmas_gpadc_driver = { .probe = palmas_gpadc_probe, - .remove = palmas_gpadc_remove, .driver = { .name = MOD_NAME, .pm = pm_sleep_ptr(&palmas_pm_ops), diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index eb424496ee1d..64a3aeb6261c 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -758,7 +758,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, /* Find the right channel setting */ chid = 0; hwchan = &hw_channels[0]; - while (hwchan && hwchan->datasheet_name) { + while (hwchan->datasheet_name) { if (hwchan->pre_scale_mux == pre_scale_mux && hwchan->amux_channel == amux_channel) break; diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 27d9e147b4b7..b8972f673c9d 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -283,7 +283,7 @@ static const struct of_device_id rcar_gyroadc_match[] = { MODULE_DEVICE_TABLE(of, rcar_gyroadc_match); -static const struct of_device_id rcar_gyroadc_child_match[] = { +static const struct of_device_id rcar_gyroadc_child_match[] __maybe_unused = { /* Mode 1 ADCs */ { .compatible = "fujitsu,mb88101a", diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 45d4e79f8e55..bd7e2408bf28 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2006,16 +2006,15 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm * to get the *real* number of channels. */ ret = device_property_count_u32(dev, "st,adc-diff-channels"); - if (ret < 0) - return ret; - - ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32)); - if (ret > adc_info->max_channels) { - dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); - return -EINVAL; - } else if (ret > 0) { - adc->num_diff = ret; - num_channels += ret; + if (ret > 0) { + ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32)); + if (ret > adc_info->max_channels) { + dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); + return -EINVAL; + } else if (ret > 0) { + adc->num_diff = ret; + num_channels += ret; + } } /* Optional sample time is provided either for each, or all channels */ @@ -2037,6 +2036,7 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; struct device *dev = &indio_dev->dev; u32 num_diff = adc->num_diff; + int num_se = nchans - num_diff; int size = num_diff * sizeof(*diff) / sizeof(u32); int scan_index = 0, ret, i, c; u32 smp = 0, smps[STM32_ADC_CH_MAX], chans[STM32_ADC_CH_MAX]; @@ -2063,29 +2063,32 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, scan_index++; } } - - ret = device_property_read_u32_array(dev, "st,adc-channels", chans, - nchans); - if (ret) - return ret; - - for (c = 0; c < nchans; c++) { - if (chans[c] >= adc_info->max_channels) { - dev_err(&indio_dev->dev, "Invalid channel %d\n", - chans[c]); - return -EINVAL; + if (num_se > 0) { + ret = device_property_read_u32_array(dev, "st,adc-channels", chans, num_se); + if (ret) { + dev_err(&indio_dev->dev, "Failed to get st,adc-channels %d\n", ret); + return ret; } - /* Channel can't be configured both as single-ended & diff */ - for (i = 0; i < num_diff; i++) { - if (chans[c] == diff[i].vinp) { - dev_err(&indio_dev->dev, "channel %d misconfigured\n", chans[c]); + for (c = 0; c < num_se; c++) { + if (chans[c] >= adc_info->max_channels) { + dev_err(&indio_dev->dev, "Invalid channel %d\n", + chans[c]); return -EINVAL; } + + /* Channel can't be configured both as single-ended & diff */ + for (i = 0; i < num_diff; i++) { + if (chans[c] == diff[i].vinp) { + dev_err(&indio_dev->dev, "channel %d misconfigured\n", + chans[c]); + return -EINVAL; + } + } + stm32_adc_chan_init_one(indio_dev, &channels[scan_index], + chans[c], 0, scan_index, false); + scan_index++; } - stm32_adc_chan_init_one(indio_dev, &channels[scan_index], - chans[c], 0, scan_index, false); - scan_index++; } if (adc->nsmps > 0) { @@ -2306,7 +2309,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping) if (legacy) ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels, - num_channels); + timestamping ? num_channels - 1 : num_channels); else ret = stm32_adc_generic_chan_init(indio_dev, adc, channels); if (ret < 0) @@ -2588,7 +2591,7 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { .irq_clear = stm32f4_adc_irq_clear, }; -const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 }; +static const unsigned int stm32_adc_min_ts_h7[] = { 0, 0, 0, 4300, 9000 }; static_assert(ARRAY_SIZE(stm32_adc_min_ts_h7) == STM32_ADC_INT_CH_NB); static const struct stm32_adc_cfg stm32h7_adc_cfg = { @@ -2607,7 +2610,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .ts_int_ch = stm32_adc_min_ts_h7, }; -const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 }; +static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 }; static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB); static const struct stm32_adc_cfg stm32mp1_adc_cfg = { @@ -2627,7 +2630,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .ts_int_ch = stm32_adc_min_ts_mp1, }; -const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 }; +static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 }; static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB); static const struct stm32_adc_cfg stm32mp13_adc_cfg = { diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c new file mode 100644 index 000000000000..6b5aebb82455 --- /dev/null +++ b/drivers/iio/adc/ti-ads1100.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ADS1100 - Texas Instruments Analog-to-Digital Converter + * + * Copyright (c) 2023, Topic Embedded Products + * + * Datasheet: https://www.ti.com/lit/gpn/ads1100 + * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* The ADS1100 has a single byte config register */ + +/* Conversion in progress bit */ +#define ADS1100_CFG_ST_BSY BIT(7) +/* Single conversion bit */ +#define ADS1100_CFG_SC BIT(4) +/* Data rate */ +#define ADS1100_DR_MASK GENMASK(3, 2) +/* Gain */ +#define ADS1100_PGA_MASK GENMASK(1, 0) + +#define ADS1100_CONTINUOUS 0 +#define ADS1100_SINGLESHOT ADS1100_CFG_SC + +#define ADS1100_SLEEP_DELAY_MS 2000 + +static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; +static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; + +struct ads1100_data { + struct i2c_client *client; + struct regulator *reg_vdd; + struct mutex lock; + int scale_avail[2 * 4]; /* 4 gain settings */ + u8 config; + bool supports_data_rate; /* Only the ADS1100 can select the rate */ +}; + +static const struct iio_chan_spec ads1100_channel = { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + .datasheet_name = "AIN", +}; + +static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value) +{ + int ret; + u8 config = (data->config & ~mask) | (value & mask); + + if (data->config == config) + return 0; /* Already done */ + + ret = i2c_master_send(data->client, &config, 1); + if (ret < 0) + return ret; + + data->config = config; + + return 0; +}; + +static int ads1100_data_bits(struct ads1100_data *data) +{ + return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)]; +} + +static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) +{ + int ret; + __be16 buffer; + s16 value; + + if (chan != 0) + return -EINVAL; + + ret = pm_runtime_resume_and_get(&data->client->dev); + if (ret < 0) + return ret; + + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); + + pm_runtime_mark_last_busy(&data->client->dev); + pm_runtime_put_autosuspend(&data->client->dev); + + if (ret < 0) { + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); + return ret; + } + + /* Value is always 16-bit 2's complement */ + value = be16_to_cpu(buffer); + + /* Shift result to compensate for bit resolution vs. sample rate */ + value <<= 16 - ads1100_data_bits(data); + + *val = sign_extend32(value, 15); + + return 0; +} + +static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) +{ + int microvolts; + int gain; + + /* With Vdd between 2.7 and 5V, the scale is always below 1 */ + if (val) + return -EINVAL; + + if (!val2) + return -EINVAL; + + microvolts = regulator_get_voltage(data->reg_vdd); + /* + * val2 is in 'micro' units, n = val2 / 1000000 + * result must be millivolts, d = microvolts / 1000 + * the full-scale value is d/n, corresponds to 2^15, + * hence the gain = (d / n) >> 15, factoring out the 1000 and moving the + * bitshift so everything fits in 32-bits yields this formula. + */ + gain = DIV_ROUND_CLOSEST(microvolts, BIT(15)) * MILLI / val2; + if (gain < BIT(0) || gain > BIT(3)) + return -EINVAL; + + ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1); + + return 0; +} + +static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) +{ + unsigned int i; + unsigned int size; + + size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1; + for (i = 0; i < size; i++) { + if (ads1100_data_rate[i] == rate) + return ads1100_set_config_bits(data, ADS1100_DR_MASK, + FIELD_PREP(ADS1100_DR_MASK, i)); + } + + return -EINVAL; +} + +static int ads1100_get_vdd_millivolts(struct ads1100_data *data) +{ + return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI); +} + +static void ads1100_calc_scale_avail(struct ads1100_data *data) +{ + int millivolts = ads1100_get_vdd_millivolts(data); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) { + data->scale_avail[i * 2 + 0] = millivolts; + data->scale_avail[i * 2 + 1] = 15 + i; + } +} + +static int ads1100_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ads1100_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_VOLTAGE) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT; + *vals = ads1100_data_rate; + if (data->supports_data_rate) + *length = ARRAY_SIZE(ads1100_data_rate); + else + *length = 1; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_FRACTIONAL_LOG2; + *vals = data->scale_avail; + *length = ARRAY_SIZE(data->scale_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ads1100_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret; + struct ads1100_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + break; + + ret = ads1100_get_adc_result(data, chan->address, val); + if (ret >= 0) + ret = IIO_VAL_INT; + iio_device_release_direct_mode(indio_dev); + break; + case IIO_CHAN_INFO_SCALE: + /* full-scale is the supply voltage in millivolts */ + *val = ads1100_get_vdd_millivolts(data); + *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); + ret = IIO_VAL_FRACTIONAL_LOG2; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, + data->config)]; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&data->lock); + + return ret; +} + +static int ads1100_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads1100_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = ads1100_set_scale(data, val, val2); + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = ads1100_set_data_rate(data, chan->address, val); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&data->lock); + + return ret; +} + +static const struct iio_info ads1100_info = { + .read_avail = ads1100_read_avail, + .read_raw = ads1100_read_raw, + .write_raw = ads1100_write_raw, +}; + +static int ads1100_setup(struct ads1100_data *data) +{ + int ret; + u8 buffer[3]; + + /* Setup continuous sampling mode at 8sps */ + buffer[0] = ADS1100_DR_MASK | ADS1100_CONTINUOUS; + ret = i2c_master_send(data->client, buffer, 1); + if (ret < 0) + return ret; + + ret = i2c_master_recv(data->client, buffer, sizeof(buffer)); + if (ret < 0) + return ret; + + /* Config register returned in third byte, strip away the busy status */ + data->config = buffer[2] & ~ADS1100_CFG_ST_BSY; + + /* Detect the sample rate capability by checking the DR bits */ + data->supports_data_rate = FIELD_GET(ADS1100_DR_MASK, buffer[2]) != 0; + + return 0; +} + +static void ads1100_reg_disable(void *reg) +{ + regulator_disable(reg); +} + +static void ads1100_disable_continuous(void *data) +{ + ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT); +} + +static int ads1100_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ads1100_data *data; + struct device *dev = &client->dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, data); + data->client = client; + mutex_init(&data->lock); + + indio_dev->name = "ads1100"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &ads1100_channel; + indio_dev->num_channels = 1; + indio_dev->info = &ads1100_info; + + data->reg_vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(data->reg_vdd)) + return dev_err_probe(dev, PTR_ERR(data->reg_vdd), + "Failed to get vdd regulator\n"); + + ret = regulator_enable(data->reg_vdd); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to enable vdd regulator\n"); + + ret = devm_add_action_or_reset(dev, ads1100_reg_disable, data->reg_vdd); + if (ret) + return ret; + + ret = ads1100_setup(data); + if (ret) + return dev_err_probe(dev, ret, + "Failed to communicate with device\n"); + + ret = devm_add_action_or_reset(dev, ads1100_disable_continuous, data); + if (ret) + return ret; + + ads1100_calc_scale_avail(data); + + pm_runtime_set_autosuspend_delay(dev, ADS1100_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n"); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register IIO device\n"); + + return 0; +} + +static int ads1100_runtime_suspend(struct device *dev) +{ + struct ads1100_data *data = dev_get_drvdata(dev); + + ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_SINGLESHOT); + regulator_disable(data->reg_vdd); + + return 0; +} + +static int ads1100_runtime_resume(struct device *dev) +{ + struct ads1100_data *data = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(data->reg_vdd); + if (ret) { + dev_err(&data->client->dev, "Failed to enable Vdd\n"); + return ret; + } + + /* + * We'll always change the mode bit in the config register, so there is + * no need here to "force" a write to the config register. If the device + * has been power-cycled, we'll re-write its config register now. + */ + return ads1100_set_config_bits(data, ADS1100_CFG_SC, + ADS1100_CONTINUOUS); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops, + ads1100_runtime_suspend, + ads1100_runtime_resume, + NULL); + +static const struct i2c_device_id ads1100_id[] = { + { "ads1100" }, + { "ads1000" }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, ads1100_id); + +static const struct of_device_id ads1100_of_match[] = { + {.compatible = "ti,ads1100" }, + {.compatible = "ti,ads1000" }, + { } +}; + +MODULE_DEVICE_TABLE(of, ads1100_of_match); + +static struct i2c_driver ads1100_driver = { + .driver = { + .name = "ads1100", + .of_match_table = ads1100_of_match, + .pm = pm_ptr(&ads1100_pm_ops), + }, + .probe_new = ads1100_probe, + .id_table = ads1100_id, +}; + +module_i2c_driver(ads1100_driver); + +MODULE_AUTHOR("Mike Looijmans "); +MODULE_DESCRIPTION("Texas Instruments ADS1100 ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig index 2843fcb70e24..877f9124803c 100644 --- a/drivers/iio/addac/Kconfig +++ b/drivers/iio/addac/Kconfig @@ -35,7 +35,9 @@ config STX104 tristate "Apex Embedded Systems STX104 driver" depends on PC104 && X86 select ISA_BUS_API + select REGMAP_MMIO select GPIOLIB + select GPIO_REGMAP help Say yes here to build support for the Apex Embedded Systems STX104 integrated analog PC/104 card. diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index f32c8c2fb26d..e3366cf5eb31 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -39,6 +39,7 @@ struct ad74413r_chip_info { struct ad74413r_channel_config { u32 func; + u32 drive_strength; bool gpo_comparator; bool initialized; }; @@ -99,6 +100,7 @@ struct ad74413r_state { #define AD74413R_REG_ADC_CONFIG_X(x) (0x05 + (x)) #define AD74413R_ADC_CONFIG_RANGE_MASK GENMASK(7, 5) #define AD74413R_ADC_CONFIG_REJECTION_MASK GENMASK(4, 3) +#define AD74413R_ADC_CONFIG_CH_200K_TO_GND BIT(2) #define AD74413R_ADC_RANGE_10V 0b000 #define AD74413R_ADC_RANGE_2P5V_EXT_POW 0b001 #define AD74413R_ADC_RANGE_2P5V_INT_POW 0b010 @@ -111,6 +113,7 @@ struct ad74413r_state { #define AD74413R_REG_DIN_CONFIG_X(x) (0x09 + (x)) #define AD74413R_DIN_DEBOUNCE_MASK GENMASK(4, 0) #define AD74413R_DIN_DEBOUNCE_LEN BIT(5) +#define AD74413R_DIN_SINK_MASK GENMASK(9, 6) #define AD74413R_REG_DAC_CODE_X(x) (0x16 + (x)) #define AD74413R_DAC_CODE_MAX GENMASK(12, 0) @@ -261,6 +264,18 @@ static int ad74413r_set_comp_debounce(struct ad74413r_state *st, val); } +static int ad74413r_set_comp_drive_strength(struct ad74413r_state *st, + unsigned int offset, + unsigned int strength) +{ + strength = min(strength, 1800U); + + return regmap_update_bits(st->regmap, AD74413R_REG_DIN_CONFIG_X(offset), + AD74413R_DIN_SINK_MASK, + FIELD_PREP(AD74413R_DIN_SINK_MASK, strength / 120)); +} + + static void ad74413r_gpio_set(struct gpio_chip *chip, unsigned int offset, int val) { @@ -424,9 +439,20 @@ static int ad74413r_set_channel_dac_code(struct ad74413r_state *st, static int ad74413r_set_channel_function(struct ad74413r_state *st, unsigned int channel, u8 func) { - return regmap_update_bits(st->regmap, + int ret; + + ret = regmap_update_bits(st->regmap, AD74413R_REG_CH_FUNC_SETUP_X(channel), AD74413R_CH_FUNC_SETUP_MASK, func); + if (ret) + return ret; + + if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER) + ret = regmap_set_bits(st->regmap, + AD74413R_REG_ADC_CONFIG_X(channel), + AD74413R_ADC_CONFIG_CH_200K_TO_GND); + + return ret; } static int ad74413r_set_adc_conv_seq(struct ad74413r_state *st, @@ -981,7 +1007,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev, ret = ad74413r_get_single_adc_result(indio_dev, chan->channel, val); - if (ret) + if (ret < 0) return ret; ad74413r_adc_to_resistance_result(*val, val); @@ -1112,6 +1138,11 @@ static struct iio_chan_spec ad74413r_current_input_channels[] = { AD74413R_ADC_CURRENT_CHANNEL, }; +static struct iio_chan_spec ad74413r_current_input_loop_channels[] = { + AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)), + AD74413R_ADC_CURRENT_CHANNEL, +}; + static struct iio_chan_spec ad74413r_resistance_input_channels[] = { AD74413R_ADC_CHANNEL(IIO_RESISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)), }; @@ -1135,7 +1166,7 @@ static const struct ad74413r_channels ad74413r_channels_map[] = { [CH_FUNC_CURRENT_OUTPUT] = AD74413R_CHANNELS(current_output), [CH_FUNC_VOLTAGE_INPUT] = AD74413R_CHANNELS(voltage_input), [CH_FUNC_CURRENT_INPUT_EXT_POWER] = AD74413R_CHANNELS(current_input), - [CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74413R_CHANNELS(current_input), + [CH_FUNC_CURRENT_INPUT_LOOP_POWER] = AD74413R_CHANNELS(current_input_loop), [CH_FUNC_RESISTANCE_INPUT] = AD74413R_CHANNELS(resistance_input), [CH_FUNC_DIGITAL_INPUT_LOGIC] = AD74413R_CHANNELS(digital_input), [CH_FUNC_DIGITAL_INPUT_LOOP_POWER] = AD74413R_CHANNELS(digital_input), @@ -1190,6 +1221,9 @@ static int ad74413r_parse_channel_config(struct iio_dev *indio_dev, config->gpo_comparator = fwnode_property_read_bool(channel_node, "adi,gpo-comparator"); + fwnode_property_read_u32(channel_node, "drive-strength-microamp", + &config->drive_strength); + if (!config->gpo_comparator) st->num_gpo_gpios++; @@ -1269,6 +1303,7 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st) unsigned int gpo_gpio_i = 0; unsigned int i; u8 gpo_config; + u32 strength; int ret; for (i = 0; i < AD74413R_CHANNEL_MAX; i++) { @@ -1285,6 +1320,11 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st) config->func == CH_FUNC_DIGITAL_INPUT_LOOP_POWER) st->comp_gpio_offsets[comp_gpio_i++] = i; + strength = config->drive_strength; + ret = ad74413r_set_comp_drive_strength(st, i, strength); + if (ret) + return ret; + ret = ad74413r_set_gpo_config(st, i, gpo_config); if (ret) return ret; diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c index 48a91a95e597..d1f7ce033b46 100644 --- a/drivers/iio/addac/stx104.c +++ b/drivers/iio/addac/stx104.c @@ -3,19 +3,20 @@ * IIO driver for the Apex Embedded Systems STX104 * Copyright (C) 2016 William Breathitt Gray */ -#include +#include +#include #include -#include -#include +#include +#include #include #include -#include -#include #include #include +#include #include #include -#include +#include +#include #include #define STX104_OUT_CHAN(chan) { \ @@ -45,101 +46,211 @@ static unsigned int num_stx104; module_param_hw_array(base, uint, ioport, &num_stx104, 0); MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); -/** - * struct stx104_reg - device register structure - * @ssr_ad: Software Strobe Register and ADC Data - * @achan: ADC Channel - * @dio: Digital I/O - * @dac: DAC Channels - * @cir_asr: Clear Interrupts and ADC Status - * @acr: ADC Control - * @pccr_fsh: Pacer Clock Control and FIFO Status MSB - * @acfg: ADC Configuration - */ -struct stx104_reg { - u16 ssr_ad; - u8 achan; - u8 dio; - u16 dac[2]; - u8 cir_asr; - u8 acr; - u8 pccr_fsh; - u8 acfg; -}; +#define STX104_AIO_BASE 0x0 +#define STX104_SOFTWARE_STROBE STX104_AIO_BASE +#define STX104_ADC_DATA STX104_AIO_BASE +#define STX104_ADC_CHANNEL (STX104_AIO_BASE + 0x2) +#define STX104_DIO_REG (STX104_AIO_BASE + 0x3) +#define STX104_DAC_BASE (STX104_AIO_BASE + 0x4) +#define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8) +#define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9) +#define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11) + +#define STX104_AIO_DATA_STRIDE 2 +#define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel)) + +/* ADC Channel */ +#define STX104_FC GENMASK(3, 0) +#define STX104_LC GENMASK(7, 4) +#define STX104_SINGLE_CHANNEL(_channel) \ + (u8_encode_bits(_channel, STX104_FC) | u8_encode_bits(_channel, STX104_LC)) + +/* ADC Status */ +#define STX104_SD BIT(5) +#define STX104_CNV BIT(7) +#define STX104_DIFFERENTIAL 1 + +/* ADC Control */ +#define STX104_ALSS GENMASK(1, 0) +#define STX104_SOFTWARE_TRIGGER u8_encode_bits(0x0, STX104_ALSS) + +/* ADC Configuration */ +#define STX104_GAIN GENMASK(1, 0) +#define STX104_ADBU BIT(2) +#define STX104_BIPOLAR 0 +#define STX104_GAIN_X1 0 +#define STX104_GAIN_X2 1 +#define STX104_GAIN_X4 2 +#define STX104_GAIN_X8 3 /** * struct stx104_iio - IIO device private data structure - * @chan_out_states: channels' output states - * @reg: I/O address offset for the device registers + * @lock: synchronization lock to prevent I/O race conditions + * @aio_data_map: Regmap for analog I/O data + * @aio_ctl_map: Regmap for analog I/O control */ struct stx104_iio { - unsigned int chan_out_states[STX104_NUM_OUT_CHAN]; - struct stx104_reg __iomem *reg; + struct mutex lock; + struct regmap *aio_data_map; + struct regmap *aio_ctl_map; }; -/** - * struct stx104_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device - * @out_state: output bits state - */ -struct stx104_gpio { - struct gpio_chip chip; - spinlock_t lock; - u8 __iomem *base; - unsigned int out_state; +static const struct regmap_range aio_ctl_wr_ranges[] = { + regmap_reg_range(0x0, 0x0), regmap_reg_range(0x2, 0x2), regmap_reg_range(0x9, 0x9), + regmap_reg_range(0x11, 0x11), +}; +static const struct regmap_range aio_ctl_rd_ranges[] = { + regmap_reg_range(0x2, 0x2), regmap_reg_range(0x8, 0x9), regmap_reg_range(0x11, 0x11), +}; +static const struct regmap_range aio_ctl_volatile_ranges[] = { + regmap_reg_range(0x8, 0x8), +}; +static const struct regmap_access_table aio_ctl_wr_table = { + .yes_ranges = aio_ctl_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(aio_ctl_wr_ranges), +}; +static const struct regmap_access_table aio_ctl_rd_table = { + .yes_ranges = aio_ctl_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(aio_ctl_rd_ranges), +}; +static const struct regmap_access_table aio_ctl_volatile_table = { + .yes_ranges = aio_ctl_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(aio_ctl_volatile_ranges), +}; + +static const struct regmap_config aio_ctl_regmap_config = { + .name = "aio_ctl", + .reg_bits = 8, + .reg_stride = 1, + .reg_base = STX104_AIO_BASE, + .val_bits = 8, + .io_port = true, + .wr_table = &aio_ctl_wr_table, + .rd_table = &aio_ctl_rd_table, + .volatile_table = &aio_ctl_volatile_table, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range aio_data_wr_ranges[] = { + regmap_reg_range(0x4, 0x6), +}; +static const struct regmap_range aio_data_rd_ranges[] = { + regmap_reg_range(0x0, 0x0), +}; +static const struct regmap_access_table aio_data_wr_table = { + .yes_ranges = aio_data_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(aio_data_wr_ranges), +}; +static const struct regmap_access_table aio_data_rd_table = { + .yes_ranges = aio_data_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(aio_data_rd_ranges), +}; + +static const struct regmap_config aio_data_regmap_config = { + .name = "aio_data", + .reg_bits = 16, + .reg_stride = STX104_AIO_DATA_STRIDE, + .reg_base = STX104_AIO_BASE, + .val_bits = 16, + .io_port = true, + .wr_table = &aio_data_wr_table, + .rd_table = &aio_data_rd_table, + .volatile_table = &aio_data_rd_table, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config dio_regmap_config = { + .name = "dio", + .reg_bits = 8, + .reg_stride = 1, + .reg_base = STX104_DIO_REG, + .val_bits = 8, + .io_port = true, }; static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct stx104_iio *const priv = iio_priv(indio_dev); - struct stx104_reg __iomem *const reg = priv->reg; + int err; unsigned int adc_config; - int adbu; - int gain; + unsigned int value; + unsigned int adc_status; switch (mask) { case IIO_CHAN_INFO_HARDWAREGAIN: - /* get gain configuration */ - adc_config = ioread8(®->acfg); - gain = adc_config & 0x3; + err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config); + if (err) + return err; - *val = 1 << gain; + *val = BIT(u8_get_bits(adc_config, STX104_GAIN)); return IIO_VAL_INT; case IIO_CHAN_INFO_RAW: if (chan->output) { - *val = priv->chan_out_states[chan->channel]; + err = regmap_read(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), + &value); + if (err) + return err; + *val = value; return IIO_VAL_INT; } + mutex_lock(&priv->lock); + /* select ADC channel */ - iowrite8(chan->channel | (chan->channel << 4), ®->achan); + err = regmap_write(priv->aio_ctl_map, STX104_ADC_CHANNEL, + STX104_SINGLE_CHANNEL(chan->channel)); + if (err) { + mutex_unlock(&priv->lock); + return err; + } - /* trigger ADC sample capture by writing to the 8-bit - * Software Strobe Register and wait for completion + /* + * Trigger ADC sample capture by writing to the 8-bit Software Strobe Register and + * wait for completion; the conversion time range is 5 microseconds to 53.68 seconds + * in steps of 25 nanoseconds. The actual Analog Input Frame Timer time interval is + * calculated as: + * ai_time_frame_ns = ( AIFT + 1 ) * ( 25 nanoseconds ). + * Where 0 <= AIFT <= 2147483648. */ - iowrite8(0, ®->ssr_ad); - while (ioread8(®->cir_asr) & BIT(7)); + err = regmap_write(priv->aio_ctl_map, STX104_SOFTWARE_STROBE, 0); + if (err) { + mutex_unlock(&priv->lock); + return err; + } + err = regmap_read_poll_timeout(priv->aio_ctl_map, STX104_ADC_STATUS, adc_status, + !u8_get_bits(adc_status, STX104_CNV), 0, 53687092); + if (err) { + mutex_unlock(&priv->lock); + return err; + } - *val = ioread16(®->ssr_ad); + err = regmap_read(priv->aio_data_map, STX104_ADC_DATA, &value); + if (err) { + mutex_unlock(&priv->lock); + return err; + } + *val = value; + + mutex_unlock(&priv->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: /* get ADC bipolar/unipolar configuration */ - adc_config = ioread8(®->acfg); - adbu = !(adc_config & BIT(2)); + err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config); + if (err) + return err; - *val = -32768 * adbu; + *val = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? -32768 : 0; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* get ADC bipolar/unipolar and gain configuration */ - adc_config = ioread8(®->acfg); - adbu = !(adc_config & BIT(2)); - gain = adc_config & 0x3; + err = regmap_read(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, &adc_config); + if (err) + return err; *val = 5; - *val2 = 15 - adbu + gain; + *val2 = (u8_get_bits(adc_config, STX104_ADBU) == STX104_BIPOLAR) ? 14 : 15; + *val2 += u8_get_bits(adc_config, STX104_GAIN); return IIO_VAL_FRACTIONAL_LOG2; } @@ -150,40 +261,37 @@ static int stx104_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct stx104_iio *const priv = iio_priv(indio_dev); + u8 gain; switch (mask) { case IIO_CHAN_INFO_HARDWAREGAIN: /* Only four gain states (x1, x2, x4, x8) */ switch (val) { case 1: - iowrite8(0, &priv->reg->acfg); + gain = STX104_GAIN_X1; break; case 2: - iowrite8(1, &priv->reg->acfg); + gain = STX104_GAIN_X2; break; case 4: - iowrite8(2, &priv->reg->acfg); + gain = STX104_GAIN_X4; break; case 8: - iowrite8(3, &priv->reg->acfg); + gain = STX104_GAIN_X8; break; default: return -EINVAL; } - return 0; + return regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, gain); case IIO_CHAN_INFO_RAW: - if (chan->output) { - /* DAC can only accept up to a 16-bit value */ - if ((unsigned int)val > 65535) - return -EINVAL; + if (!chan->output) + return -EINVAL; - priv->chan_out_states[chan->channel] = val; - iowrite16(val, &priv->reg->dac[chan->channel]); + if (val < 0 || val > U16_MAX) + return -EINVAL; - return 0; - } - return -EINVAL; + return regmap_write(priv->aio_data_map, STX104_DAC_OFFSET(chan->channel), val); } return -EINVAL; @@ -212,119 +320,66 @@ static const struct iio_chan_spec stx104_channels_diff[] = { STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1) }; -static int stx104_gpio_get_direction(struct gpio_chip *chip, - unsigned int offset) -{ - /* GPIO 0-3 are input only, while the rest are output only */ - if (offset < 4) - return 1; - - return 0; -} - -static int stx104_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) +static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base, + unsigned int offset, unsigned int *const reg, + unsigned int *const mask) { + /* Output lines are located at same register bit offsets as input lines */ if (offset >= 4) - return -EINVAL; + offset -= 4; + + *reg = base; + *mask = BIT(offset); return 0; } -static int stx104_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - if (offset < 4) - return -EINVAL; - - chip->set(chip, offset, value); - return 0; -} - -static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - - if (offset >= 4) - return -EINVAL; - - return !!(ioread8(stx104gpio->base) & BIT(offset)); -} - -static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, - unsigned long *bits) -{ - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - - *bits = ioread8(stx104gpio->base); - - return 0; -} - -static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - const unsigned int mask = BIT(offset) >> 4; - unsigned long flags; - - if (offset < 4) - return; - - spin_lock_irqsave(&stx104gpio->lock, flags); - - if (value) - stx104gpio->out_state |= mask; - else - stx104gpio->out_state &= ~mask; - - iowrite8(stx104gpio->out_state, stx104gpio->base); - - spin_unlock_irqrestore(&stx104gpio->lock, flags); -} - #define STX104_NGPIO 8 static const char *stx104_names[STX104_NGPIO] = { "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3" }; -static void stx104_gpio_set_multiple(struct gpio_chip *chip, - unsigned long *mask, unsigned long *bits) +static int stx104_init_hw(struct stx104_iio *const priv) { - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - unsigned long flags; + int err; - /* verify masked GPIO are output */ - if (!(*mask & 0xF0)) - return; + /* configure device for software trigger operation */ + err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONTROL, STX104_SOFTWARE_TRIGGER); + if (err) + return err; - *mask >>= 4; - *bits >>= 4; + /* initialize gain setting to x1 */ + err = regmap_write(priv->aio_ctl_map, STX104_ADC_CONFIGURATION, STX104_GAIN_X1); + if (err) + return err; - spin_lock_irqsave(&stx104gpio->lock, flags); + /* initialize DAC outputs to 0V */ + err = regmap_write(priv->aio_data_map, STX104_DAC_BASE, 0); + if (err) + return err; + err = regmap_write(priv->aio_data_map, STX104_DAC_BASE + STX104_AIO_DATA_STRIDE, 0); + if (err) + return err; - stx104gpio->out_state &= ~*mask; - stx104gpio->out_state |= *mask & *bits; - iowrite8(stx104gpio->out_state, stx104gpio->base); - - spin_unlock_irqrestore(&stx104gpio->lock, flags); + return 0; } static int stx104_probe(struct device *dev, unsigned int id) { struct iio_dev *indio_dev; struct stx104_iio *priv; - struct stx104_gpio *stx104gpio; + struct gpio_regmap_config gpio_config; + void __iomem *stx104_base; + struct regmap *aio_ctl_map; + struct regmap *aio_data_map; + struct regmap *dio_map; int err; + unsigned int adc_status; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; - stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL); - if (!stx104gpio) - return -ENOMEM; - if (!devm_request_region(dev, base[id], STX104_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -332,16 +387,37 @@ static int stx104_probe(struct device *dev, unsigned int id) return -EBUSY; } - priv = iio_priv(indio_dev); - priv->reg = devm_ioport_map(dev, base[id], STX104_EXTENT); - if (!priv->reg) + stx104_base = devm_ioport_map(dev, base[id], STX104_EXTENT); + if (!stx104_base) return -ENOMEM; + aio_ctl_map = devm_regmap_init_mmio(dev, stx104_base, &aio_ctl_regmap_config); + if (IS_ERR(aio_ctl_map)) + return dev_err_probe(dev, PTR_ERR(aio_ctl_map), + "Unable to initialize aio_ctl register map\n"); + + aio_data_map = devm_regmap_init_mmio(dev, stx104_base, &aio_data_regmap_config); + if (IS_ERR(aio_data_map)) + return dev_err_probe(dev, PTR_ERR(aio_data_map), + "Unable to initialize aio_data register map\n"); + + dio_map = devm_regmap_init_mmio(dev, stx104_base, &dio_regmap_config); + if (IS_ERR(dio_map)) + return dev_err_probe(dev, PTR_ERR(dio_map), + "Unable to initialize dio register map\n"); + + priv = iio_priv(indio_dev); + priv->aio_ctl_map = aio_ctl_map; + priv->aio_data_map = aio_data_map; + indio_dev->info = &stx104_info; indio_dev->modes = INDIO_DIRECT_MODE; - /* determine if differential inputs */ - if (ioread8(&priv->reg->cir_asr) & BIT(5)) { + err = regmap_read(aio_ctl_map, STX104_ADC_STATUS, &adc_status); + if (err) + return err; + + if (u8_get_bits(adc_status, STX104_SD) == STX104_DIFFERENTIAL) { indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff); indio_dev->channels = stx104_channels_diff; } else { @@ -351,41 +427,29 @@ static int stx104_probe(struct device *dev, unsigned int id) indio_dev->name = dev_name(dev); - /* configure device for software trigger operation */ - iowrite8(0, &priv->reg->acr); + mutex_init(&priv->lock); - /* initialize gain setting to x1 */ - iowrite8(0, &priv->reg->acfg); - - /* initialize DAC output to 0V */ - iowrite16(0, &priv->reg->dac[0]); - iowrite16(0, &priv->reg->dac[1]); - - stx104gpio->chip.label = dev_name(dev); - stx104gpio->chip.parent = dev; - stx104gpio->chip.owner = THIS_MODULE; - stx104gpio->chip.base = -1; - stx104gpio->chip.ngpio = STX104_NGPIO; - stx104gpio->chip.names = stx104_names; - stx104gpio->chip.get_direction = stx104_gpio_get_direction; - stx104gpio->chip.direction_input = stx104_gpio_direction_input; - stx104gpio->chip.direction_output = stx104_gpio_direction_output; - stx104gpio->chip.get = stx104_gpio_get; - stx104gpio->chip.get_multiple = stx104_gpio_get_multiple; - stx104gpio->chip.set = stx104_gpio_set; - stx104gpio->chip.set_multiple = stx104_gpio_set_multiple; - stx104gpio->base = &priv->reg->dio; - stx104gpio->out_state = 0x0; - - spin_lock_init(&stx104gpio->lock); - - err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); + err = stx104_init_hw(priv); + if (err) return err; - } - return devm_iio_device_register(dev, indio_dev); + err = devm_iio_device_register(dev, indio_dev); + if (err) + return err; + + gpio_config = (struct gpio_regmap_config) { + .parent = dev, + .regmap = dio_map, + .ngpio = STX104_NGPIO, + .names = stx104_names, + .reg_dat_base = GPIO_REGMAP_ADDR(STX104_DIO_REG), + .reg_set_base = GPIO_REGMAP_ADDR(STX104_DIO_REG), + .ngpio_per_reg = STX104_NGPIO, + .reg_mask_xlate = stx104_reg_mask_xlate, + .drvdata = dio_map, + }; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); } static struct isa_driver stx104_driver = { diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index 2aed483a2fde..0cb5d9b65d62 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -68,10 +68,10 @@ static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size /* * Internally sensor stores measurements in a following manner: * - * PM1: upper two bytes, crc8, lower two bytes, crc8 + * PM1: upper two bytes, crc8, lower two bytes, crc8 * PM2P5: upper two bytes, crc8, lower two bytes, crc8 - * PM4: upper two bytes, crc8, lower two bytes, crc8 - * PM10: upper two bytes, crc8, lower two bytes, crc8 + * PM4: upper two bytes, crc8, lower two bytes, crc8 + * PM10: upper two bytes, crc8, lower two bytes, crc8 * * What follows next are number concentration measurements and * typical particle size measurement which we omit. diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 899b640c0a70..a0df9250a69f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -85,7 +85,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p) */ if (sdata->hw_irq_trigger && st_sensors_new_samples_available(indio_dev, sdata)) { - iio_trigger_poll_chained(p); + iio_trigger_poll_nested(p); } else { dev_dbg(indio_dev->dev.parent, "spurious IRQ\n"); return IRQ_NONE; @@ -110,7 +110,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p) dev_dbg(indio_dev->dev.parent, "more samples came in during polling\n"); sdata->hw_timestamp = iio_get_time_ns(indio_dev); - iio_trigger_poll_chained(p); + iio_trigger_poll_nested(p); } return IRQ_HANDLED; diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index d3f90cf86143..3acd9c3f388e 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -277,6 +277,7 @@ config CIO_DAC tristate "Measurement Computing CIO-DAC IIO driver" depends on X86 && (ISA_BUS || PC104) select ISA_BUS_API + select REGMAP_MMIO help Say yes here to build support for the Measurement Computing CIO-DAC analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 6c74fea21736..addd97a78838 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o obj-$(CONFIG_AD5592R) += ad5592r.o obj-$(CONFIG_AD5593R) += ad5593r.o obj-$(CONFIG_AD5755) += ad5755.o -obj-$(CONFIG_AD5755) += ad5758.o +obj-$(CONFIG_AD5758) += ad5758.o obj-$(CONFIG_AD5761) += ad5761.o obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5766) += ad5766.o diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 7a9b5fc1e579..076bc9ecfb49 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -124,6 +124,10 @@ static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset) return 0; } +static const char * const ad5592r_gpio_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", +}; + static int ad5592r_gpio_init(struct ad5592r_state *st) { if (!st->gpio_map) @@ -140,6 +144,7 @@ static int ad5592r_gpio_init(struct ad5592r_state *st) st->gpiochip.set = ad5592r_gpio_set; st->gpiochip.request = ad5592r_gpio_request; st->gpiochip.owner = THIS_MODULE; + st->gpiochip.names = ad5592r_gpio_names; mutex_init(&st->gpio_lock); diff --git a/drivers/iio/dac/cio-dac.c b/drivers/iio/dac/cio-dac.c index 18a64f72fc18..069904d00c2e 100644 --- a/drivers/iio/dac/cio-dac.c +++ b/drivers/iio/dac/cio-dac.c @@ -4,18 +4,17 @@ * Copyright (C) 2016 William Breathitt Gray * * This driver supports the following Measurement Computing devices: CIO-DAC16, - * CIO-DAC06, and PC104-DAC06. + * CIO-DAC08, and PC104-DAC06. */ -#include +#include #include -#include +#include #include #include -#include -#include #include #include #include +#include #include #define CIO_DAC_NUM_CHAN 16 @@ -35,25 +34,51 @@ static unsigned int num_cio_dac; module_param_hw_array(base, uint, ioport, &num_cio_dac, 0); MODULE_PARM_DESC(base, "Measurement Computing CIO-DAC base addresses"); +#define CIO_DAC_BASE 0x00 +#define CIO_DAC_CHANNEL_STRIDE 2 + +static bool cio_dac_precious_reg(struct device *dev, unsigned int reg) +{ + /* + * All registers are considered precious; if the XFER jumper is set on + * the device, then no update occurs until a DAC register is read. + */ + return true; +} + +static const struct regmap_config cio_dac_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .io_port = true, + .max_register = 0x1F, + .precious_reg = cio_dac_precious_reg, +}; + /** * struct cio_dac_iio - IIO device private data structure - * @chan_out_states: channels' output states - * @base: base memory address of the DAC device + * @map: Regmap for the device */ struct cio_dac_iio { - int chan_out_states[CIO_DAC_NUM_CHAN]; - u16 __iomem *base; + struct regmap *map; }; static int cio_dac_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct cio_dac_iio *const priv = iio_priv(indio_dev); + const unsigned int offset = chan->channel * CIO_DAC_CHANNEL_STRIDE; + int err; + unsigned int dac_val; if (mask != IIO_CHAN_INFO_RAW) return -EINVAL; - *val = priv->chan_out_states[chan->channel]; + err = regmap_read(priv->map, CIO_DAC_BASE + offset, &dac_val); + if (err) + return err; + + *val = dac_val; return IIO_VAL_INT; } @@ -62,6 +87,7 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct cio_dac_iio *const priv = iio_priv(indio_dev); + const unsigned int offset = chan->channel * CIO_DAC_CHANNEL_STRIDE; if (mask != IIO_CHAN_INFO_RAW) return -EINVAL; @@ -70,10 +96,7 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev, if ((unsigned int)val > 4095) return -EINVAL; - priv->chan_out_states[chan->channel] = val; - iowrite16(val, priv->base + chan->channel); - - return 0; + return regmap_write(priv->map, CIO_DAC_BASE + offset, val); } static const struct iio_info cio_dac_info = { @@ -92,7 +115,7 @@ static int cio_dac_probe(struct device *dev, unsigned int id) { struct iio_dev *indio_dev; struct cio_dac_iio *priv; - unsigned int i; + void __iomem *regs; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) @@ -105,21 +128,22 @@ static int cio_dac_probe(struct device *dev, unsigned int id) return -EBUSY; } - priv = iio_priv(indio_dev); - priv->base = devm_ioport_map(dev, base[id], CIO_DAC_EXTENT); - if (!priv->base) + regs = devm_ioport_map(dev, base[id], CIO_DAC_EXTENT); + if (!regs) return -ENOMEM; + priv = iio_priv(indio_dev); + priv->map = devm_regmap_init_mmio(dev, regs, &cio_dac_regmap_config); + if (IS_ERR(priv->map)) + return dev_err_probe(dev, PTR_ERR(priv->map), + "Unable to initialize register map\n"); + indio_dev->info = &cio_dac_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = cio_dac_channels; indio_dev->num_channels = CIO_DAC_NUM_CHAN; indio_dev->name = dev_name(dev); - /* initialize DAC outputs to 0V */ - for (i = 0; i < CIO_DAC_NUM_CHAN; i++) - iowrite16(0, priv->base + i); - return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index 00ba4e98fb9c..05034a306597 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -52,7 +52,7 @@ struct max5522_state { } \ } -const struct iio_chan_spec max5522_channels[] = { +static const struct iio_chan_spec max5522_channels[] = { MAX5522_CHANNEL(0), MAX5522_CHANNEL(1), }; diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 46bf758760f8..3f5661a3718f 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -47,12 +47,18 @@ static int mcp4725_suspend(struct device *dev) struct mcp4725_data *data = iio_priv(i2c_get_clientdata( to_i2c_client(dev))); u8 outbuf[2]; + int ret; outbuf[0] = (data->powerdown_mode + 1) << 4; outbuf[1] = 0; data->powerdown = true; - return i2c_master_send(data->client, outbuf, 2); + ret = i2c_master_send(data->client, outbuf, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + return 0; } static int mcp4725_resume(struct device *dev) @@ -60,13 +66,19 @@ static int mcp4725_resume(struct device *dev) struct mcp4725_data *data = iio_priv(i2c_get_clientdata( to_i2c_client(dev))); u8 outbuf[2]; + int ret; /* restore previous DAC value */ outbuf[0] = (data->dac_value >> 8) & 0xf; outbuf[1] = data->dac_value & 0xff; data->powerdown = false; - return i2c_master_send(data->client, outbuf, 2); + ret = i2c_master_send(data->client, outbuf, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume); diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index ed8167271358..9bf8337806fc 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -490,11 +490,6 @@ static int admv1013_init(struct admv1013_state *st) st->input_mode); } -static void admv1013_clk_disable(void *data) -{ - clk_disable_unprepare(data); -} - static void admv1013_reg_disable(void *data) { regulator_disable(data); @@ -559,11 +554,6 @@ static int admv1013_properties_parse(struct admv1013_state *st) return dev_err_probe(&spi->dev, PTR_ERR(st->reg), "failed to get the common-mode voltage\n"); - st->clkin = devm_clk_get(&spi->dev, "lo_in"); - if (IS_ERR(st->clkin)) - return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), - "failed to get the LO input clock\n"); - return 0; } @@ -601,13 +591,10 @@ static int admv1013_probe(struct spi_device *spi) if (ret) return ret; - ret = clk_prepare_enable(st->clkin); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, admv1013_clk_disable, st->clkin); - if (ret) - return ret; + st->clkin = devm_clk_get_enabled(&spi->dev, "lo_in"); + if (IS_ERR(st->clkin)) + return dev_err_probe(&spi->dev, PTR_ERR(st->clkin), + "failed to get the LO input clock\n"); st->nb.notifier_call = admv1013_freq_change; ret = devm_clk_notifier_register(&spi->dev, st->clkin, &st->nb); diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index 3ea1d4613080..c28d17ca6f5e 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -813,7 +813,7 @@ static irqreturn_t fxas21002c_data_rdy_thread(int irq, void *private) if (!data_ready) return IRQ_NONE; - iio_trigger_poll_chained(data->dready_trig); + iio_trigger_poll_nested(data->dready_trig); return IRQ_HANDLED; } diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 6a6d84a3deda..a791ba3a693a 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -939,7 +939,7 @@ static irqreturn_t mpu3050_irq_thread(int irq, void *p) if (!(val & MPU3050_INT_STATUS_RAW_RDY)) return IRQ_NONE; - iio_trigger_poll_chained(p); + iio_trigger_poll_nested(p); return IRQ_HANDLED; } diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index 2a4107a79662..11ef38994a95 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -68,7 +68,7 @@ static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) if (!(status & HTS221_RH_DRDY_MASK)) return IRQ_NONE; - iio_trigger_poll_chained(hw->trig); + iio_trigger_poll_nested(hw->trig); return IRQ_HANDLED; } diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index aec55f7e1f26..3abffb01ba31 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -326,11 +326,11 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq) /* * This is not an hard requirement but it's not advised to run the IMU - * with a sample rate lower than 4000Hz due to possible undersampling + * with a sample rate lower than 1900Hz due to possible undersampling * issues. However, there are users that might really want to take the risk. * Hence, we provide a module parameter for them. If set, we allow sample - * rates lower than 4KHz. By default, we won't allow this and we just roundup - * the rate to the next multiple of the input clock bigger than 4KHz. This + * rates lower than 1.9KHz. By default, we won't allow this and we just roundup + * the rate to the next multiple of the input clock bigger than 1.9KHz. This * is done like this as in some cases (when DEC_RATE is 0) might give * us the closest value to the one desired by the user... */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c index 99576b2c171f..32d7f8364230 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c @@ -275,9 +275,14 @@ static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); struct device *dev = regmap_get_device(st->map); + struct inv_icm42600_timestamp *ts = iio_priv(indio_dev); pm_runtime_get_sync(dev); + mutex_lock(&st->lock); + inv_icm42600_timestamp_reset(ts); + mutex_unlock(&st->lock); + return 0; } @@ -375,7 +380,6 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev) struct device *dev = regmap_get_device(st->map); unsigned int sensor; unsigned int *watermark; - struct inv_icm42600_timestamp *ts; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int sleep_temp = 0; unsigned int sleep_sensor = 0; @@ -385,11 +389,9 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev) if (indio_dev == st->indio_gyro) { sensor = INV_ICM42600_SENSOR_GYRO; watermark = &st->fifo.watermark.gyro; - ts = iio_priv(st->indio_gyro); } else if (indio_dev == st->indio_accel) { sensor = INV_ICM42600_SENSOR_ACCEL; watermark = &st->fifo.watermark.accel; - ts = iio_priv(st->indio_accel); } else { return -EINVAL; } @@ -417,8 +419,6 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev) if (!st->fifo.on) ret = inv_icm42600_set_temp_conf(st, false, &sleep_temp); - inv_icm42600_timestamp_reset(ts); - out_unlock: mutex_unlock(&st->lock); diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 8c16cdacf2f2..5865a295a4df 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -14,8 +14,8 @@ config IIO_ST_LSM6DSX sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr, lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx, - lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, lsm6dst and the - accelerometer/gyroscope of lsm9ds1. + lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst + and the accelerometer/gyroscope of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 499fcf8875b4..c19237717e81 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -37,9 +37,10 @@ #define ST_LSM6DSV16X_DEV_NAME "lsm6dsv16x" #define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is" #define ST_ISM330IS_DEV_NAME "ism330is" +#define ST_ASM330LHB_DEV_NAME "asm330lhb" enum st_lsm6dsx_hw_id { - ST_LSM6DS3_ID, + ST_LSM6DS3_ID = 1, ST_LSM6DS3H_ID, ST_LSM6DSL_ID, ST_LSM6DSM_ID, @@ -61,6 +62,7 @@ enum st_lsm6dsx_hw_id { ST_LSM6DSV16X_ID, ST_LSM6DSO16IS_ID, ST_ISM330IS_ID, + ST_ASM330LHB_ID, ST_LSM6DSX_MAX_ID, }; @@ -137,6 +139,13 @@ struct st_lsm6dsx_odr_table_entry { int odr_len; }; +struct st_lsm6dsx_samples_to_discard { + struct { + u32 milli_hz; + u16 samples; + } val[ST_LSM6DSX_ODR_LIST_SIZE]; +}; + struct st_lsm6dsx_fs { u32 gain; u8 val; @@ -291,6 +300,7 @@ struct st_lsm6dsx_ext_dev_settings { * @irq_config: interrupts related registers. * @drdy_mask: register info for data-ready mask (addr + mask). * @odr_table: Hw sensors odr table (Hz + val). + * @samples_to_discard: Number of samples to discard for filters settling time. * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). * @batch: List of FIFO batching register info (addr + mask). @@ -323,6 +333,7 @@ struct st_lsm6dsx_settings { } irq_config; struct st_lsm6dsx_reg drdy_mask; struct st_lsm6dsx_odr_table_entry odr_table[2]; + struct st_lsm6dsx_samples_to_discard samples_to_discard[2]; struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID]; @@ -353,6 +364,7 @@ enum st_lsm6dsx_fifo_mode { * @hw: Pointer to instance of struct st_lsm6dsx_hw. * @gain: Configured sensor sensitivity. * @odr: Output data rate of the sensor [Hz]. + * @samples_to_discard: Number of samples to discard for filters settling time. * @watermark: Sensor watermark level. * @decimator: Sensor decimation factor. * @sip: Number of samples in a given pattern. @@ -367,6 +379,7 @@ struct st_lsm6dsx_sensor { u32 gain; u32 odr; + u16 samples_to_discard; u16 watermark; u8 decimator; u8 sip; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 7dd5205aea5b..066fe561c5e8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -15,7 +15,7 @@ * value of the decimation factor and ODR set for each FIFO data set. * * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/ - * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV: + * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB: * The FIFO buffer can be configured to store data from gyroscope and * accelerometer. Each sample is queued with a tag (1B) indicating data * source (gyroscope, accelerometer, hw timer). @@ -457,17 +457,31 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) } if (gyro_sip > 0 && !(sip % gyro_sensor->decimator)) { - iio_push_to_buffers_with_timestamp( - hw->iio_devs[ST_LSM6DSX_ID_GYRO], - &hw->scan[ST_LSM6DSX_ID_GYRO], - gyro_sensor->ts_ref + ts); + /* + * We need to discards gyro samples during + * filters settling time + */ + if (gyro_sensor->samples_to_discard > 0) + gyro_sensor->samples_to_discard--; + else + iio_push_to_buffers_with_timestamp( + hw->iio_devs[ST_LSM6DSX_ID_GYRO], + &hw->scan[ST_LSM6DSX_ID_GYRO], + gyro_sensor->ts_ref + ts); gyro_sip--; } if (acc_sip > 0 && !(sip % acc_sensor->decimator)) { - iio_push_to_buffers_with_timestamp( - hw->iio_devs[ST_LSM6DSX_ID_ACC], - &hw->scan[ST_LSM6DSX_ID_ACC], - acc_sensor->ts_ref + ts); + /* + * We need to discards accel samples during + * filters settling time + */ + if (acc_sensor->samples_to_discard > 0) + acc_sensor->samples_to_discard--; + else + iio_push_to_buffers_with_timestamp( + hw->iio_devs[ST_LSM6DSX_ID_ACC], + &hw->scan[ST_LSM6DSX_ID_ACC], + acc_sensor->ts_ref + ts); acc_sip--; } if (ext_sip > 0 && !(sip % ext_sensor->decimator)) { @@ -654,6 +668,30 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) return err; } +static void +st_lsm6dsx_update_samples_to_discard(struct st_lsm6dsx_sensor *sensor) +{ + const struct st_lsm6dsx_samples_to_discard *data; + struct st_lsm6dsx_hw *hw = sensor->hw; + int i; + + if (sensor->id != ST_LSM6DSX_ID_GYRO && + sensor->id != ST_LSM6DSX_ID_ACC) + return; + + /* check if drdy mask is supported in hw */ + if (hw->settings->drdy_mask.addr) + return; + + data = &hw->settings->samples_to_discard[sensor->id]; + for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) { + if (data->val[i].milli_hz == sensor->odr) { + sensor->samples_to_discard = data->val[i].samples; + return; + } + } +} + int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable) { struct st_lsm6dsx_hw *hw = sensor->hw; @@ -673,6 +711,9 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable) goto out; } + if (enable) + st_lsm6dsx_update_samples_to_discard(sensor); + err = st_lsm6dsx_device_set_enable(sensor, enable); if (err < 0) goto out; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 3f6060c64f32..6a18b363cf73 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -634,6 +635,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .samples_to_discard = { + [ST_LSM6DSX_ID_ACC] = { + .val[0] = { 12500, 1 }, + .val[1] = { 26000, 1 }, + .val[2] = { 52000, 1 }, + .val[3] = { 104000, 2 }, + .val[4] = { 208000, 2 }, + .val[5] = { 416000, 2 }, + }, + [ST_LSM6DSX_ID_GYRO] = { + .val[0] = { 12500, 2 }, + .val[1] = { 26000, 5 }, + .val[2] = { 52000, 7 }, + .val[3] = { 104000, 12 }, + .val[4] = { 208000, 20 }, + .val[5] = { 416000, 36 }, + }, + }, .irq_config = { .irq1 = { .addr = 0x0d, @@ -1014,6 +1033,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .hw_id = ST_LSM6DSOP_ID, .name = ST_LSM6DSOP_DEV_NAME, .wai = 0x6c, + }, { + .hw_id = ST_ASM330LHB_ID, + .name = ST_ASM330LHB_DEV_NAME, + .wai = 0x6b, }, }, .channels = { @@ -2602,6 +2625,73 @@ static int st_lsm6dsx_init_regulators(struct device *dev) return 0; } +#ifdef CONFIG_ACPI + +static int lsm6dsx_get_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_device *adev = ACPI_COMPANION(dev); + union acpi_object *obj, *elements; + acpi_status status; + int i, j, val[3]; + char *str; + + if (!has_acpi_companion(dev)) + return -EINVAL; + + if (!acpi_has_method(adev->handle, "ROTM")) + return -EINVAL; + + status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer); + if (ACPI_FAILURE(status)) { + dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status); + return -EINVAL; + } + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) + goto unknown_format; + + elements = obj->package.elements; + for (i = 0; i < 3; i++) { + if (elements[i].type != ACPI_TYPE_STRING) + goto unknown_format; + + str = elements[i].string.pointer; + if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) + goto unknown_format; + + for (j = 0; j < 3; j++) { + switch (val[j]) { + case -1: str = "-1"; break; + case 0: str = "0"; break; + case 1: str = "1"; break; + default: goto unknown_format; + } + orientation->rotation[i * 3 + j] = str; + } + } + + kfree(buffer.pointer); + return 0; + +unknown_format: + dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n"); + kfree(buffer.pointer); + return -EINVAL; +} + +#else + +static int lsm6dsx_get_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation) +{ + return false; +} + +#endif + int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { @@ -2676,9 +2766,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - err = iio_read_mount_matrix(hw->dev, &hw->orientation); - if (err) - return err; + err = lsm6dsx_get_acpi_mount_matrix(hw->dev, &hw->orientation); + if (err) { + err = iio_read_mount_matrix(hw->dev, &hw->orientation); + if (err) + return err; + } for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { if (!hw->iio_devs[i]) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index df5f60925260..020717f92363 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -23,10 +23,15 @@ static const struct regmap_config st_lsm6dsx_i2c_regmap_config = { static int st_lsm6dsx_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); - int hw_id = id->driver_data; + int hw_id; struct regmap *regmap; + hw_id = (kernel_ulong_t)device_get_match_data(&client->dev); + if (!hw_id) + hw_id = i2c_client_get_device_id(client)->driver_data; + if (!hw_id) + return -EINVAL; + regmap = devm_regmap_init_i2c(client, &st_lsm6dsx_i2c_regmap_config); if (IS_ERR(regmap)) { dev_err(&client->dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap)); @@ -125,10 +130,20 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,ism330is", .data = (void *)ST_ISM330IS_ID, }, + { + .compatible = "st,asm330lhb", + .data = (void *)ST_ASM330LHB_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); +static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { + { "SMO8B30", ST_LSM6DS3TRC_ID, }, + {} +}; +MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); + static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, @@ -152,6 +167,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, + { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); @@ -161,6 +177,7 @@ static struct i2c_driver st_lsm6dsx_driver = { .name = "st_lsm6dsx_i2c", .pm = pm_sleep_ptr(&st_lsm6dsx_pm_ops), .of_match_table = st_lsm6dsx_i2c_of_match, + .acpi_match_table = st_lsm6dsx_i2c_acpi_match, }, .probe_new = st_lsm6dsx_i2c_probe, .id_table = st_lsm6dsx_i2c_id_table, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 974584bda875..f56c170c41a9 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -125,6 +125,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,ism330is", .data = (void *)ST_ISM330IS_ID, }, + { + .compatible = "st,asm330lhb", + .data = (void *)ST_ASM330LHB_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -152,6 +156,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, + { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c new file mode 100644 index 000000000000..7653261d2dc2 --- /dev/null +++ b/drivers/iio/industrialio-gts-helper.c @@ -0,0 +1,1099 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* gain-time-scale conversion helpers for IIO light sensors + * + * Copyright (c) 2023 Matti Vaittinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * iio_gts_get_gain - Convert scale to total gain + * + * Internal helper for converting scale to total gain. + * + * @max: Maximum linearized scale. As an example, when scale is created + * in magnitude of NANOs and max scale is 64.1 - The linearized + * scale is 64 100 000 000. + * @scale: Linearized scale to compute the gain for. + * + * Return: (floored) gain corresponding to the scale. -EINVAL if scale + * is invalid. + */ +static int iio_gts_get_gain(const u64 max, const u64 scale) +{ + u64 full = max; + int tmp = 1; + + if (scale > full || !scale) + return -EINVAL; + + if (U64_MAX - full < scale) { + /* Risk of overflow */ + if (full - scale < scale) + return 1; + + full -= scale; + tmp++; + } + + while (full > scale * (u64)tmp) + tmp++; + + return tmp; +} + +/** + * gain_get_scale_fraction - get the gain or time based on scale and known one + * + * @max: Maximum linearized scale. As an example, when scale is created + * in magnitude of NANOs and max scale is 64.1 - The linearized + * scale is 64 100 000 000. + * @scale: Linearized scale to compute the gain/time for. + * @known: Either integration time or gain depending on which one is known + * @unknown: Pointer to variable where the computed gain/time is stored + * + * Internal helper for computing unknown fraction of total gain. + * Compute either gain or time based on scale and either the gain or time + * depending on which one is known. + * + * Return: 0 on success. + */ +static int gain_get_scale_fraction(const u64 max, u64 scale, int known, + int *unknown) +{ + int tot_gain; + + tot_gain = iio_gts_get_gain(max, scale); + if (tot_gain < 0) + return tot_gain; + + *unknown = tot_gain / known; + + /* We require total gain to be exact multiple of known * unknown */ + if (!*unknown || *unknown * known != tot_gain) + return -EINVAL; + + return 0; +} + +static int iio_gts_delinearize(u64 lin_scale, unsigned long scaler, + int *scale_whole, int *scale_nano) +{ + int frac; + + if (scaler > NANO) + return -EOVERFLOW; + + if (!scaler) + return -EINVAL; + + frac = do_div(lin_scale, scaler); + + *scale_whole = lin_scale; + *scale_nano = frac * (NANO / scaler); + + return 0; +} + +static int iio_gts_linearize(int scale_whole, int scale_nano, + unsigned long scaler, u64 *lin_scale) +{ + /* + * Expect scale to be (mostly) NANO or MICRO. Divide divider instead of + * multiplication followed by division to avoid overflow. + */ + if (scaler > NANO || !scaler) + return -EINVAL; + + *lin_scale = (u64)scale_whole * (u64)scaler + + (u64)(scale_nano / (NANO / scaler)); + + return 0; +} + +/** + * iio_gts_total_gain_to_scale - convert gain to scale + * @gts: Gain time scale descriptor + * @total_gain: the gain to be converted + * @scale_int: Pointer to integral part of the scale (typically val1) + * @scale_nano: Pointer to fractional part of the scale (nano or ppb) + * + * Convert the total gain value to scale. NOTE: This does not separate gain + * generated by HW-gain or integration time. It is up to caller to decide what + * part of the total gain is due to integration time and what due to HW-gain. + * + * Return: 0 on success. Negative errno on failure. + */ +int iio_gts_total_gain_to_scale(struct iio_gts *gts, int total_gain, + int *scale_int, int *scale_nano) +{ + u64 tmp; + + tmp = gts->max_scale; + + do_div(tmp, total_gain); + + return iio_gts_delinearize(tmp, NANO, scale_int, scale_nano); +} +EXPORT_SYMBOL_NS_GPL(iio_gts_total_gain_to_scale, IIO_GTS_HELPER); + +/** + * iio_gts_purge_avail_scale_table - free-up the available scale tables + * @gts: Gain time scale descriptor + * + * Free the space reserved by iio_gts_build_avail_scale_table(). + */ +static void iio_gts_purge_avail_scale_table(struct iio_gts *gts) +{ + int i; + + if (gts->per_time_avail_scale_tables) { + for (i = 0; i < gts->num_itime; i++) + kfree(gts->per_time_avail_scale_tables[i]); + + kfree(gts->per_time_avail_scale_tables); + gts->per_time_avail_scale_tables = NULL; + } + + kfree(gts->avail_all_scales_table); + gts->avail_all_scales_table = NULL; + + gts->num_avail_all_scales = 0; +} + +static int iio_gts_gain_cmp(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales) +{ + int ret, i, j, new_idx, time_idx; + int *all_gains; + size_t gain_bytes; + + for (i = 0; i < gts->num_itime; i++) { + /* + * Sort the tables for nice output and for easier finding of + * unique values. + */ + sort(gains[i], gts->num_hwgain, sizeof(int), iio_gts_gain_cmp, + NULL); + + /* Convert gains to scales */ + for (j = 0; j < gts->num_hwgain; j++) { + ret = iio_gts_total_gain_to_scale(gts, gains[i][j], + &scales[i][2 * j], + &scales[i][2 * j + 1]); + if (ret) + return ret; + } + } + + gain_bytes = array_size(gts->num_hwgain, sizeof(int)); + all_gains = kcalloc(gts->num_itime, gain_bytes, GFP_KERNEL); + if (!all_gains) + return -ENOMEM; + + /* + * We assume all the gains for same integration time were unique. + * It is likely the first time table had greatest time multiplier as + * the times are in the order of preference and greater times are + * usually preferred. Hence we start from the last table which is likely + * to have the smallest total gains. + */ + time_idx = gts->num_itime - 1; + memcpy(all_gains, gains[time_idx], gain_bytes); + new_idx = gts->num_hwgain; + + while (time_idx--) { + for (j = 0; j < gts->num_hwgain; j++) { + int candidate = gains[time_idx][j]; + int chk; + + if (candidate > all_gains[new_idx - 1]) { + all_gains[new_idx] = candidate; + new_idx++; + + continue; + } + for (chk = 0; chk < new_idx; chk++) + if (candidate <= all_gains[chk]) + break; + + if (candidate == all_gains[chk]) + continue; + + memmove(&all_gains[chk + 1], &all_gains[chk], + (new_idx - chk) * sizeof(int)); + all_gains[chk] = candidate; + new_idx++; + } + } + + gts->avail_all_scales_table = kcalloc(new_idx, 2 * sizeof(int), + GFP_KERNEL); + if (!gts->avail_all_scales_table) { + ret = -ENOMEM; + goto free_out; + } + gts->num_avail_all_scales = new_idx; + + for (i = 0; i < gts->num_avail_all_scales; i++) { + ret = iio_gts_total_gain_to_scale(gts, all_gains[i], + >s->avail_all_scales_table[i * 2], + >s->avail_all_scales_table[i * 2 + 1]); + + if (ret) { + kfree(gts->avail_all_scales_table); + gts->num_avail_all_scales = 0; + goto free_out; + } + } + +free_out: + kfree(all_gains); + + return ret; +} + +/** + * iio_gts_build_avail_scale_table - create tables of available scales + * @gts: Gain time scale descriptor + * + * Build the tables which can represent the available scales based on the + * originally given gain and time tables. When both time and gain tables are + * given this results: + * 1. A set of tables representing available scales for each supported + * integration time. + * 2. A single table listing all the unique scales that any combination of + * supported gains and times can provide. + * + * NOTE: Space allocated for the tables must be freed using + * iio_gts_purge_avail_scale_table() when the tables are no longer needed. + * + * Return: 0 on success. + */ +static int iio_gts_build_avail_scale_table(struct iio_gts *gts) +{ + int **per_time_gains, **per_time_scales, i, j, ret = -ENOMEM; + + per_time_gains = kcalloc(gts->num_itime, sizeof(*per_time_gains), GFP_KERNEL); + if (!per_time_gains) + return ret; + + per_time_scales = kcalloc(gts->num_itime, sizeof(*per_time_scales), GFP_KERNEL); + if (!per_time_scales) + goto free_gains; + + for (i = 0; i < gts->num_itime; i++) { + per_time_scales[i] = kcalloc(gts->num_hwgain, 2 * sizeof(int), + GFP_KERNEL); + if (!per_time_scales[i]) + goto err_free_out; + + per_time_gains[i] = kcalloc(gts->num_hwgain, sizeof(int), + GFP_KERNEL); + if (!per_time_gains[i]) { + kfree(per_time_scales[i]); + goto err_free_out; + } + + for (j = 0; j < gts->num_hwgain; j++) + per_time_gains[i][j] = gts->hwgain_table[j].gain * + gts->itime_table[i].mul; + } + + ret = gain_to_scaletables(gts, per_time_gains, per_time_scales); + if (ret) + goto err_free_out; + + kfree(per_time_gains); + gts->per_time_avail_scale_tables = per_time_scales; + + return 0; + +err_free_out: + for (i--; i; i--) { + kfree(per_time_scales[i]); + kfree(per_time_gains[i]); + } + kfree(per_time_scales); +free_gains: + kfree(per_time_gains); + + return ret; +} + +static void iio_gts_us_to_int_micro(int *time_us, int *int_micro_times, + int num_times) +{ + int i; + + for (i = 0; i < num_times; i++) { + int_micro_times[i * 2] = time_us[i] / 1000000; + int_micro_times[i * 2 + 1] = time_us[i] % 1000000; + } +} + +/** + * iio_gts_build_avail_time_table - build table of available integration times + * @gts: Gain time scale descriptor + * + * Build the table which can represent the available times to be returned + * to users using the read_avail-callback. + * + * NOTE: Space allocated for the tables must be freed using + * iio_gts_purge_avail_time_table() when the tables are no longer needed. + * + * Return: 0 on success. + */ +static int iio_gts_build_avail_time_table(struct iio_gts *gts) +{ + int *times, i, j, idx = 0, *int_micro_times; + + if (!gts->num_itime) + return 0; + + times = kcalloc(gts->num_itime, sizeof(int), GFP_KERNEL); + if (!times) + return -ENOMEM; + + /* Sort times from all tables to one and remove duplicates */ + for (i = gts->num_itime - 1; i >= 0; i--) { + int new = gts->itime_table[i].time_us; + + if (times[idx] < new) { + times[idx++] = new; + continue; + } + + for (j = 0; j <= idx; j++) { + if (times[j] > new) { + memmove(×[j + 1], ×[j], + (idx - j) * sizeof(int)); + times[j] = new; + idx++; + } + } + } + + /* create a list of times formatted as list of IIO_VAL_INT_PLUS_MICRO */ + int_micro_times = kcalloc(idx, sizeof(int) * 2, GFP_KERNEL); + if (int_micro_times) { + /* + * This is just to survive a unlikely corner-case where times in + * the given time table were not unique. Else we could just + * trust the gts->num_itime. + */ + gts->num_avail_time_tables = idx; + iio_gts_us_to_int_micro(times, int_micro_times, idx); + } + + gts->avail_time_tables = int_micro_times; + kfree(times); + + if (!int_micro_times) + return -ENOMEM; + + return 0; +} + +/** + * iio_gts_purge_avail_time_table - free-up the available integration time table + * @gts: Gain time scale descriptor + * + * Free the space reserved by iio_gts_build_avail_time_table(). + */ +static void iio_gts_purge_avail_time_table(struct iio_gts *gts) +{ + if (gts->num_avail_time_tables) { + kfree(gts->avail_time_tables); + gts->avail_time_tables = NULL; + gts->num_avail_time_tables = 0; + } +} + +/** + * iio_gts_build_avail_tables - create tables of available scales and int times + * @gts: Gain time scale descriptor + * + * Build the tables which can represent the available scales and available + * integration times. Availability tables are built based on the originally + * given gain and given time tables. + * + * When both time and gain tables are + * given this results: + * 1. A set of sorted tables representing available scales for each supported + * integration time. + * 2. A single sorted table listing all the unique scales that any combination + * of supported gains and times can provide. + * 3. A sorted table of supported integration times + * + * After these tables are built one can use the iio_gts_all_avail_scales(), + * iio_gts_avail_scales_for_time() and iio_gts_avail_times() helpers to + * implement the read_avail operations. + * + * NOTE: Space allocated for the tables must be freed using + * iio_gts_purge_avail_tables() when the tables are no longer needed. + * + * Return: 0 on success. + */ +static int iio_gts_build_avail_tables(struct iio_gts *gts) +{ + int ret; + + ret = iio_gts_build_avail_scale_table(gts); + if (ret) + return ret; + + ret = iio_gts_build_avail_time_table(gts); + if (ret) + iio_gts_purge_avail_scale_table(gts); + + return ret; +} + +/** + * iio_gts_purge_avail_tables - free-up the availability tables + * @gts: Gain time scale descriptor + * + * Free the space reserved by iio_gts_build_avail_tables(). Frees both the + * integration time and scale tables. + */ +static void iio_gts_purge_avail_tables(struct iio_gts *gts) +{ + iio_gts_purge_avail_time_table(gts); + iio_gts_purge_avail_scale_table(gts); +} + +static void devm_iio_gts_avail_all_drop(void *res) +{ + iio_gts_purge_avail_tables(res); +} + +/** + * devm_iio_gts_build_avail_tables - manged add availability tables + * @dev: Pointer to the device whose lifetime tables are bound + * @gts: Gain time scale descriptor + * + * Build the tables which can represent the available scales and available + * integration times. Availability tables are built based on the originally + * given gain and given time tables. + * + * When both time and gain tables are given this results: + * 1. A set of sorted tables representing available scales for each supported + * integration time. + * 2. A single sorted table listing all the unique scales that any combination + * of supported gains and times can provide. + * 3. A sorted table of supported integration times + * + * After these tables are built one can use the iio_gts_all_avail_scales(), + * iio_gts_avail_scales_for_time() and iio_gts_avail_times() helpers to + * implement the read_avail operations. + * + * The tables are automatically released upon device detach. + * + * Return: 0 on success. + */ +static int devm_iio_gts_build_avail_tables(struct device *dev, + struct iio_gts *gts) +{ + int ret; + + ret = iio_gts_build_avail_tables(gts); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_iio_gts_avail_all_drop, gts); +} + +static int sanity_check_time(const struct iio_itime_sel_mul *t) +{ + if (t->sel < 0 || t->time_us < 0 || t->mul <= 0) + return -EINVAL; + + return 0; +} + +static int sanity_check_gain(const struct iio_gain_sel_pair *g) +{ + if (g->sel < 0 || g->gain <= 0) + return -EINVAL; + + return 0; +} + +static int iio_gts_sanity_check(struct iio_gts *gts) +{ + int g, t, ret; + + if (!gts->num_hwgain && !gts->num_itime) + return -EINVAL; + + for (t = 0; t < gts->num_itime; t++) { + ret = sanity_check_time(>s->itime_table[t]); + if (ret) + return ret; + } + + for (g = 0; g < gts->num_hwgain; g++) { + ret = sanity_check_gain(>s->hwgain_table[g]); + if (ret) + return ret; + } + + for (g = 0; g < gts->num_hwgain; g++) { + for (t = 0; t < gts->num_itime; t++) { + int gain, mul, res; + + gain = gts->hwgain_table[g].gain; + mul = gts->itime_table[t].mul; + + if (check_mul_overflow(gain, mul, &res)) + return -EOVERFLOW; + } + } + + return 0; +} + +static int iio_init_iio_gts(int max_scale_int, int max_scale_nano, + const struct iio_gain_sel_pair *gain_tbl, int num_gain, + const struct iio_itime_sel_mul *tim_tbl, int num_times, + struct iio_gts *gts) +{ + int ret; + + memset(gts, 0, sizeof(*gts)); + + ret = iio_gts_linearize(max_scale_int, max_scale_nano, NANO, + >s->max_scale); + if (ret) + return ret; + + gts->hwgain_table = gain_tbl; + gts->num_hwgain = num_gain; + gts->itime_table = tim_tbl; + gts->num_itime = num_times; + + return iio_gts_sanity_check(gts); +} + +/** + * devm_iio_init_iio_gts - Initialize the gain-time-scale helper + * @dev: Pointer to the device whose lifetime gts resources are + * bound + * @max_scale_int: integer part of the maximum scale value + * @max_scale_nano: fraction part of the maximum scale value + * @gain_tbl: table describing supported gains + * @num_gain: number of gains in the gain table + * @tim_tbl: table describing supported integration times. Provide + * the integration time table sorted so that the preferred + * integration time is in the first array index. The search + * functions like the + * iio_gts_find_time_and_gain_sel_for_scale() start search + * from first provided time. + * @num_times: number of times in the time table + * @gts: pointer to the helper struct + * + * Initialize the gain-time-scale helper for use. Note, gains, times, selectors + * and multipliers must be positive. Negative values are reserved for error + * checking. The total gain (maximum gain * maximum time multiplier) must not + * overflow int. The allocated resources will be released upon device detach. + * + * Return: 0 on success. + */ +int devm_iio_init_iio_gts(struct device *dev, int max_scale_int, int max_scale_nano, + const struct iio_gain_sel_pair *gain_tbl, int num_gain, + const struct iio_itime_sel_mul *tim_tbl, int num_times, + struct iio_gts *gts) +{ + int ret; + + ret = iio_init_iio_gts(max_scale_int, max_scale_nano, gain_tbl, + num_gain, tim_tbl, num_times, gts); + if (ret) + return ret; + + return devm_iio_gts_build_avail_tables(dev, gts); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_init_iio_gts, IIO_GTS_HELPER); + +/** + * iio_gts_all_avail_scales - helper for listing all available scales + * @gts: Gain time scale descriptor + * @vals: Returned array of supported scales + * @type: Type of returned scale values + * @length: Amount of returned values in array + * + * Return: a value suitable to be returned from read_avail or a negative error. + */ +int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type, + int *length) +{ + if (!gts->num_avail_all_scales) + return -EINVAL; + + *vals = gts->avail_all_scales_table; + *type = IIO_VAL_INT_PLUS_NANO; + *length = gts->num_avail_all_scales * 2; + + return IIO_AVAIL_LIST; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_all_avail_scales, IIO_GTS_HELPER); + +/** + * iio_gts_avail_scales_for_time - list scales for integration time + * @gts: Gain time scale descriptor + * @time: Integration time for which the scales are listed + * @vals: Returned array of supported scales + * @type: Type of returned scale values + * @length: Amount of returned values in array + * + * Drivers which do not allow scale setting to change integration time can + * use this helper to list only the scales which are valid for given integration + * time. + * + * Return: a value suitable to be returned from read_avail or a negative error. + */ +int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time, + const int **vals, int *type, int *length) +{ + int i; + + for (i = 0; i < gts->num_itime; i++) + if (gts->itime_table[i].time_us == time) + break; + + if (i == gts->num_itime) + return -EINVAL; + + *vals = gts->per_time_avail_scale_tables[i]; + *type = IIO_VAL_INT_PLUS_NANO; + *length = gts->num_hwgain * 2; + + return IIO_AVAIL_LIST; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_avail_scales_for_time, IIO_GTS_HELPER); + +/** + * iio_gts_avail_times - helper for listing available integration times + * @gts: Gain time scale descriptor + * @vals: Returned array of supported times + * @type: Type of returned scale values + * @length: Amount of returned values in array + * + * Return: a value suitable to be returned from read_avail or a negative error. + */ +int iio_gts_avail_times(struct iio_gts *gts, const int **vals, int *type, + int *length) +{ + if (!gts->num_avail_time_tables) + return -EINVAL; + + *vals = gts->avail_time_tables; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = gts->num_avail_time_tables * 2; + + return IIO_AVAIL_LIST; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_avail_times, IIO_GTS_HELPER); + +/** + * iio_gts_find_sel_by_gain - find selector corresponding to a HW-gain + * @gts: Gain time scale descriptor + * @gain: HW-gain for which matching selector is searched for + * + * Return: a selector matching given HW-gain or -EINVAL if selector was + * not found. + */ +int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain) +{ + int i; + + for (i = 0; i < gts->num_hwgain; i++) + if (gts->hwgain_table[i].gain == gain) + return gts->hwgain_table[i].sel; + + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_find_sel_by_gain, IIO_GTS_HELPER); + +/** + * iio_gts_find_gain_by_sel - find HW-gain corresponding to a selector + * @gts: Gain time scale descriptor + * @sel: selector for which matching HW-gain is searched for + * + * Return: a HW-gain matching given selector or -EINVAL if HW-gain was not + * found. + */ +int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel) +{ + int i; + + for (i = 0; i < gts->num_hwgain; i++) + if (gts->hwgain_table[i].sel == sel) + return gts->hwgain_table[i].gain; + + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_by_sel, IIO_GTS_HELPER); + +/** + * iio_gts_get_min_gain - find smallest valid HW-gain + * @gts: Gain time scale descriptor + * + * Return: The smallest HW-gain -EINVAL if no HW-gains were in the tables. + */ +int iio_gts_get_min_gain(struct iio_gts *gts) +{ + int i, min = -EINVAL; + + for (i = 0; i < gts->num_hwgain; i++) { + int gain = gts->hwgain_table[i].gain; + + if (min == -EINVAL) + min = gain; + else + min = min(min, gain); + } + + return min; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_get_min_gain, IIO_GTS_HELPER); + +/** + * iio_find_closest_gain_low - Find the closest lower matching gain + * @gts: Gain time scale descriptor + * @gain: HW-gain for which the closest match is searched + * @in_range: indicate if the @gain was actually in the range of + * supported gains. + * + * Search for closest supported gain that is lower than or equal to the + * gain given as a parameter. This is usable for drivers which do not require + * user to request exact matching gain but rather for rounding to a supported + * gain value which is equal or lower (setting lower gain is typical for + * avoiding saturation) + * + * Return: The closest matching supported gain or -EINVAL if @gain + * was smaller than the smallest supported gain. + */ +int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range) +{ + int i, diff = 0; + int best = -1; + + *in_range = false; + + for (i = 0; i < gts->num_hwgain; i++) { + if (gain == gts->hwgain_table[i].gain) { + *in_range = true; + return gain; + } + + if (gain > gts->hwgain_table[i].gain) { + if (!diff) { + diff = gain - gts->hwgain_table[i].gain; + best = i; + } else { + int tmp = gain - gts->hwgain_table[i].gain; + + if (tmp < diff) { + diff = tmp; + best = i; + } + } + } else { + /* + * We found valid HW-gain which is greater than + * reference. So, unless we return a failure below we + * will have found an in-range gain + */ + *in_range = true; + } + } + /* The requested gain was smaller than anything we support */ + if (!diff) { + *in_range = false; + + return -EINVAL; + } + + return gts->hwgain_table[best].gain; +} +EXPORT_SYMBOL_NS_GPL(iio_find_closest_gain_low, IIO_GTS_HELPER); + +static int iio_gts_get_int_time_gain_multiplier_by_sel(struct iio_gts *gts, + int sel) +{ + const struct iio_itime_sel_mul *time; + + time = iio_gts_find_itime_by_sel(gts, sel); + if (!time) + return -EINVAL; + + return time->mul; +} + +/** + * iio_gts_find_gain_for_scale_using_time - Find gain by time and scale + * @gts: Gain time scale descriptor + * @time_sel: Integration time selector corresponding to the time gain is + * searched for + * @scale_int: Integral part of the scale (typically val1) + * @scale_nano: Fractional part of the scale (nano or ppb) + * @gain: Pointer to value where gain is stored. + * + * In some cases the light sensors may want to find a gain setting which + * corresponds given scale and integration time. Sensors which fill the + * gain and time tables may use this helper to retrieve the gain. + * + * Return: 0 on success. -EINVAL if gain matching the parameters is not + * found. + */ +static int iio_gts_find_gain_for_scale_using_time(struct iio_gts *gts, int time_sel, + int scale_int, int scale_nano, + int *gain) +{ + u64 scale_linear; + int ret, mul; + + ret = iio_gts_linearize(scale_int, scale_nano, NANO, &scale_linear); + if (ret) + return ret; + + ret = iio_gts_get_int_time_gain_multiplier_by_sel(gts, time_sel); + if (ret < 0) + return ret; + + mul = ret; + + ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain); + if (ret) + return ret; + + if (!iio_gts_valid_gain(gts, *gain)) + return -EINVAL; + + return 0; +} + +/** + * iio_gts_find_gain_sel_for_scale_using_time - Fetch gain selector. + * @gts: Gain time scale descriptor + * @time_sel: Integration time selector corresponding to the time gain is + * searched for + * @scale_int: Integral part of the scale (typically val1) + * @scale_nano: Fractional part of the scale (nano or ppb) + * @gain_sel: Pointer to value where gain selector is stored. + * + * See iio_gts_find_gain_for_scale_using_time() for more information + */ +int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel, + int scale_int, int scale_nano, + int *gain_sel) +{ + int gain, ret; + + ret = iio_gts_find_gain_for_scale_using_time(gts, time_sel, scale_int, + scale_nano, &gain); + if (ret) + return ret; + + ret = iio_gts_find_sel_by_gain(gts, gain); + if (ret < 0) + return ret; + + *gain_sel = ret; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_sel_for_scale_using_time, IIO_GTS_HELPER); + +static int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time) +{ + const struct iio_itime_sel_mul *itime; + + if (!iio_gts_valid_gain(gts, gain)) + return -EINVAL; + + if (!gts->num_itime) + return gain; + + itime = iio_gts_find_itime_by_time(gts, time); + if (!itime) + return -EINVAL; + + return gain * itime->mul; +} + +static int iio_gts_get_scale_linear(struct iio_gts *gts, int gain, int time, + u64 *scale) +{ + int total_gain; + u64 tmp; + + total_gain = iio_gts_get_total_gain(gts, gain, time); + if (total_gain < 0) + return total_gain; + + tmp = gts->max_scale; + + do_div(tmp, total_gain); + + *scale = tmp; + + return 0; +} + +/** + * iio_gts_get_scale - get scale based on integration time and HW-gain + * @gts: Gain time scale descriptor + * @gain: HW-gain for which the scale is computed + * @time: Integration time for which the scale is computed + * @scale_int: Integral part of the scale (typically val1) + * @scale_nano: Fractional part of the scale (nano or ppb) + * + * Compute scale matching the integration time and HW-gain given as parameter. + * + * Return: 0 on success. + */ +int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int, + int *scale_nano) +{ + u64 lin_scale; + int ret; + + ret = iio_gts_get_scale_linear(gts, gain, time, &lin_scale); + if (ret) + return ret; + + return iio_gts_delinearize(lin_scale, NANO, scale_int, scale_nano); +} +EXPORT_SYMBOL_NS_GPL(iio_gts_get_scale, IIO_GTS_HELPER); + +/** + * iio_gts_find_new_gain_sel_by_old_gain_time - compensate for time change + * @gts: Gain time scale descriptor + * @old_gain: Previously set gain + * @old_time_sel: Selector corresponding previously set time + * @new_time_sel: Selector corresponding new time to be set + * @new_gain: Pointer to value where new gain is to be written + * + * We may want to mitigate the scale change caused by setting a new integration + * time (for a light sensor) by also updating the (HW)gain. This helper computes + * new gain value to maintain the scale with new integration time. + * + * Return: 0 if an exactly matching supported new gain was found. When a + * non-zero value is returned, the @new_gain will be set to a negative or + * positive value. The negative value means that no gain could be computed. + * Positive value will be the "best possible new gain there could be". There + * can be two reasons why finding the "best possible" new gain is not deemed + * successful. 1) This new value cannot be supported by the hardware. 2) The new + * gain required to maintain the scale would not be an integer. In this case, + * the "best possible" new gain will be a floored optimal gain, which may or + * may not be supported by the hardware. + */ +int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts, + int old_gain, int old_time_sel, + int new_time_sel, int *new_gain) +{ + const struct iio_itime_sel_mul *itime_old, *itime_new; + u64 scale; + int ret; + + *new_gain = -1; + + itime_old = iio_gts_find_itime_by_sel(gts, old_time_sel); + if (!itime_old) + return -EINVAL; + + itime_new = iio_gts_find_itime_by_sel(gts, new_time_sel); + if (!itime_new) + return -EINVAL; + + ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us, + &scale); + if (ret) + return ret; + + ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, + new_gain); + if (ret) + return ret; + + if (!iio_gts_valid_gain(gts, *new_gain)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_sel_by_old_gain_time, IIO_GTS_HELPER); + +/** + * iio_gts_find_new_gain_by_old_gain_time - compensate for time change + * @gts: Gain time scale descriptor + * @old_gain: Previously set gain + * @old_time: Selector corresponding previously set time + * @new_time: Selector corresponding new time to be set + * @new_gain: Pointer to value where new gain is to be written + * + * We may want to mitigate the scale change caused by setting a new integration + * time (for a light sensor) by also updating the (HW)gain. This helper computes + * new gain value to maintain the scale with new integration time. + * + * Return: 0 if an exactly matching supported new gain was found. When a + * non-zero value is returned, the @new_gain will be set to a negative or + * positive value. The negative value means that no gain could be computed. + * Positive value will be the "best possible new gain there could be". There + * can be two reasons why finding the "best possible" new gain is not deemed + * successful. 1) This new value cannot be supported by the hardware. 2) The new + * gain required to maintain the scale would not be an integer. In this case, + * the "best possible" new gain will be a floored optimal gain, which may or + * may not be supported by the hardware. + */ +int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain, + int old_time, int new_time, + int *new_gain) +{ + const struct iio_itime_sel_mul *itime_new; + u64 scale; + int ret; + + *new_gain = -1; + + itime_new = iio_gts_find_itime_by_time(gts, new_time); + if (!itime_new) + return -EINVAL; + + ret = iio_gts_get_scale_linear(gts, old_gain, old_time, &scale); + if (ret) + return ret; + + ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, + new_gain); + if (ret) + return ret; + + if (!iio_gts_valid_gain(gts, *new_gain)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_old_gain_time, IIO_GTS_HELPER); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers"); diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index a2f3cc2f65ef..784dc1e00310 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -192,6 +192,12 @@ static void iio_trigger_notify_done_atomic(struct iio_trigger *trig) schedule_work(&trig->reenable_work); } +/** + * iio_trigger_poll() - Call the IRQ trigger handler of the consumers + * @trig: trigger which occurred + * + * This function should only be called from a hard IRQ context. + */ void iio_trigger_poll(struct iio_trigger *trig) { int i; @@ -216,7 +222,14 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private) } EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); -void iio_trigger_poll_chained(struct iio_trigger *trig) +/** + * iio_trigger_poll_nested() - Call the threaded trigger handler of the + * consumers + * @trig: trigger which occurred + * + * This function should only be called from a kernel thread context. + */ +void iio_trigger_poll_nested(struct iio_trigger *trig) { int i; @@ -231,7 +244,7 @@ void iio_trigger_poll_chained(struct iio_trigger *trig) } } } -EXPORT_SYMBOL(iio_trigger_poll_chained); +EXPORT_SYMBOL(iio_trigger_poll_nested); void iio_trigger_notify_done(struct iio_trigger *trig) { diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 0d4447df7200..6fa31fcd71a1 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -289,6 +289,20 @@ config JSA1212 To compile this driver as a module, choose M here: the module will be called jsa1212. +config ROHM_BU27034 + tristate "ROHM BU27034 ambient light sensor" + depends on I2C + select REGMAP_I2C + select IIO_GTS_HELPER + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034 + is an ambient light sesnor with 3 channels and 3 photo diodes capable + of detecting a very wide range of illuminance. + Typical application is adjusting LCD and backlight power of TVs and + mobile phones. + config RPR0521 tristate "ROHM RPR0521 ALS and proximity sensor driver" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index d74d2b5ff14c..985f6feaccd4 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_MAX44009) += max44009.o obj-$(CONFIG_NOA1305) += noa1305.o obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_PA12203001) += pa12203001.o +obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SI1133) += si1133.o obj-$(CONFIG_SI1145) += si1145.o diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index e1ff6f524f4b..2d91caf24dd0 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -108,7 +108,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) { switch (event) { case ACPI_ALS_NOTIFY_ILLUMINANCE: - iio_trigger_poll_chained(als->trig); + iio_trigger_poll_nested(als->trig); break; default: /* Unhandled event */ diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 3dadace09fe2..176dcad6e8e8 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -527,6 +527,12 @@ static int max44009_probe(struct i2c_client *client) return devm_iio_device_register(&client->dev, indio_dev); } +static const struct of_device_id max44009_of_match[] = { + { .compatible = "maxim,max44009" }, + { } +}; +MODULE_DEVICE_TABLE(of, max44009_of_match); + static const struct i2c_device_id max44009_id[] = { { "max44009", 0 }, { } @@ -536,18 +542,13 @@ MODULE_DEVICE_TABLE(i2c, max44009_id); static struct i2c_driver max44009_driver = { .driver = { .name = MAX44009_DRV_NAME, + .of_match_table = max44009_of_match, }, .probe_new = max44009_probe, .id_table = max44009_id, }; module_i2c_driver(max44009_driver); -static const struct of_device_id max44009_of_match[] = { - { .compatible = "maxim,max44009" }, - { } -}; -MODULE_DEVICE_TABLE(of, max44009_of_match); - MODULE_AUTHOR("Robert Eshleman "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MAX44009 ambient light sensor driver"); diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c new file mode 100644 index 000000000000..f85194fda6b0 --- /dev/null +++ b/drivers/iio/light/rohm-bu27034.c @@ -0,0 +1,1511 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BU27034 ROHM Ambient Light Sensor + * + * Copyright (c) 2023, ROHM Semiconductor. + * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define BU27034_REG_SYSTEM_CONTROL 0x40 +#define BU27034_MASK_SW_RESET BIT(7) +#define BU27034_MASK_PART_ID GENMASK(5, 0) +#define BU27034_ID 0x19 +#define BU27034_REG_MODE_CONTROL1 0x41 +#define BU27034_MASK_MEAS_MODE GENMASK(2, 0) + +#define BU27034_REG_MODE_CONTROL2 0x42 +#define BU27034_MASK_D01_GAIN GENMASK(7, 3) +#define BU27034_MASK_D2_GAIN_HI GENMASK(7, 6) +#define BU27034_MASK_D2_GAIN_LO GENMASK(2, 0) + +#define BU27034_REG_MODE_CONTROL3 0x43 +#define BU27034_REG_MODE_CONTROL4 0x44 +#define BU27034_MASK_MEAS_EN BIT(0) +#define BU27034_MASK_VALID BIT(7) +#define BU27034_REG_DATA0_LO 0x50 +#define BU27034_REG_DATA1_LO 0x52 +#define BU27034_REG_DATA2_LO 0x54 +#define BU27034_REG_DATA2_HI 0x55 +#define BU27034_REG_MANUFACTURER_ID 0x92 +#define BU27034_REG_MAX BU27034_REG_MANUFACTURER_ID + +/* + * The BU27034 does not have interrupt to trigger the data read when a + * measurement has finished. Hence we poll the VALID bit in a thread. We will + * try to wake the thread BU27034_MEAS_WAIT_PREMATURE_MS milliseconds before + * the expected sampling time to prevent the drifting. + * + * If we constantly wake up a bit too late we would eventually skip a sample. + * And because the sleep can't wake up _exactly_ at given time this would be + * inevitable even if the sensor clock would be perfectly phase-locked to CPU + * clock - which we can't say is the case. + * + * This is still fragile. No matter how big advance do we have, we will still + * risk of losing a sample because things can in a rainy-day scenario be + * delayed a lot. Yet, more we reserve the time for polling, more we also lose + * the performance by spending cycles polling the register. So, selecting this + * value is a balancing dance between severity of wasting CPU time and severity + * of losing samples. + * + * In most cases losing the samples is not _that_ crucial because light levels + * tend to change slowly. + * + * Other option that was pointed to me would be always sleeping 1/2 of the + * measurement time, checking the VALID bit and just sleeping again if the bit + * was not set. That should be pretty tolerant against missing samples due to + * the scheduling delays while also not wasting much of cycles for polling. + * Downside is that the time-stamps would be very inaccurate as the wake-up + * would not really be tied to the sensor toggling the valid bit. This would also + * result 'jumps' in the time-stamps when the delay drifted so that wake-up was + * performed during the consecutive wake-ups (Or, when sensor and CPU clocks + * were very different and scheduling the wake-ups was very close to given + * timeout - and when the time-outs were very close to the actual sensor + * sampling, Eg. once in a blue moon, two consecutive time-outs would occur + * without having a sample ready). + */ +#define BU27034_MEAS_WAIT_PREMATURE_MS 5 +#define BU27034_DATA_WAIT_TIME_US 1000 +#define BU27034_TOTAL_DATA_WAIT_TIME_US (BU27034_MEAS_WAIT_PREMATURE_MS * 1000) + +#define BU27034_RETRY_LIMIT 18 + +enum { + BU27034_CHAN_ALS, + BU27034_CHAN_DATA0, + BU27034_CHAN_DATA1, + BU27034_CHAN_DATA2, + BU27034_NUM_CHANS +}; + +static const unsigned long bu27034_scan_masks[] = { + GENMASK(BU27034_CHAN_DATA2, BU27034_CHAN_ALS), 0 +}; + +/* + * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS + * Time impacts to gain: 1x, 2x, 4x, 8x. + * + * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768 + * + * Using NANO precision for scale we must use scale 64x corresponding gain 1x + * to avoid precision loss. (32x would result scale 976 562.5(nanos). + */ +#define BU27034_SCALE_1X 64 + +/* See the data sheet for the "Gain Setting" table */ +#define BU27034_GSEL_1X 0x00 /* 00000 */ +#define BU27034_GSEL_4X 0x08 /* 01000 */ +#define BU27034_GSEL_16X 0x0a /* 01010 */ +#define BU27034_GSEL_32X 0x0b /* 01011 */ +#define BU27034_GSEL_64X 0x0c /* 01100 */ +#define BU27034_GSEL_256X 0x18 /* 11000 */ +#define BU27034_GSEL_512X 0x19 /* 11001 */ +#define BU27034_GSEL_1024X 0x1a /* 11010 */ +#define BU27034_GSEL_2048X 0x1b /* 11011 */ +#define BU27034_GSEL_4096X 0x1c /* 11100 */ + +/* Available gain settings */ +static const struct iio_gain_sel_pair bu27034_gains[] = { + GAIN_SCALE_GAIN(1, BU27034_GSEL_1X), + GAIN_SCALE_GAIN(4, BU27034_GSEL_4X), + GAIN_SCALE_GAIN(16, BU27034_GSEL_16X), + GAIN_SCALE_GAIN(32, BU27034_GSEL_32X), + GAIN_SCALE_GAIN(64, BU27034_GSEL_64X), + GAIN_SCALE_GAIN(256, BU27034_GSEL_256X), + GAIN_SCALE_GAIN(512, BU27034_GSEL_512X), + GAIN_SCALE_GAIN(1024, BU27034_GSEL_1024X), + GAIN_SCALE_GAIN(2048, BU27034_GSEL_2048X), + GAIN_SCALE_GAIN(4096, BU27034_GSEL_4096X), +}; + +/* + * The IC has 5 modes for sampling time. 5 mS mode is exceptional as it limits + * the data collection to data0-channel only and cuts the supported range to + * 10 bit. It is not supported by the driver. + * + * "normal" modes are 55, 100, 200 and 400 mS modes - which do have direct + * multiplying impact to the register values (similar to gain). + * + * This means that if meas-mode is changed for example from 400 => 200, + * the scale is doubled. Eg, time impact to total gain is x1, x2, x4, x8. + */ +#define BU27034_MEAS_MODE_100MS 0 +#define BU27034_MEAS_MODE_55MS 1 +#define BU27034_MEAS_MODE_200MS 2 +#define BU27034_MEAS_MODE_400MS 4 + +static const struct iio_itime_sel_mul bu27034_itimes[] = { + GAIN_SCALE_ITIME_US(400000, BU27034_MEAS_MODE_400MS, 8), + GAIN_SCALE_ITIME_US(200000, BU27034_MEAS_MODE_200MS, 4), + GAIN_SCALE_ITIME_US(100000, BU27034_MEAS_MODE_100MS, 2), + GAIN_SCALE_ITIME_US(55000, BU27034_MEAS_MODE_55MS, 1), +}; + +#define BU27034_CHAN_DATA(_name, _ch2) \ +{ \ + .type = IIO_INTENSITY, \ + .channel = BU27034_CHAN_##_name, \ + .channel2 = (_ch2), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_INT_TIME), \ + .address = BU27034_REG_##_name##_LO, \ + .scan_index = BU27034_CHAN_##_name, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ + .indexed = 1, \ +} + +static const struct iio_chan_spec bu27034_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .channel = BU27034_CHAN_ALS, + .scan_index = BU27034_CHAN_ALS, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, + }, + /* + * The BU27034 DATA0 and DATA1 channels are both on the visible light + * area (mostly). The data0 sensitivity peaks at 500nm, DATA1 at 600nm. + * These wave lengths are pretty much on the border of colours making + * these a poor candidates for R/G/B standardization. Hence they're both + * marked as clear channels + */ + BU27034_CHAN_DATA(DATA0, IIO_MOD_LIGHT_CLEAR), + BU27034_CHAN_DATA(DATA1, IIO_MOD_LIGHT_CLEAR), + BU27034_CHAN_DATA(DATA2, IIO_MOD_LIGHT_IR), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +struct bu27034_data { + struct regmap *regmap; + struct device *dev; + /* + * Protect gain and time during scale adjustment and data reading. + * Protect measurement enabling/disabling. + */ + struct mutex mutex; + struct iio_gts gts; + struct task_struct *task; + __le16 raw[3]; + struct { + u32 mlux; + __le16 channels[3]; + s64 ts __aligned(8); + } scan; +}; + +struct bu27034_result { + u16 ch0; + u16 ch1; + u16 ch2; +}; + +static const struct regmap_range bu27034_volatile_ranges[] = { + { + .range_min = BU27034_REG_SYSTEM_CONTROL, + .range_max = BU27034_REG_SYSTEM_CONTROL, + }, { + .range_min = BU27034_REG_MODE_CONTROL4, + .range_max = BU27034_REG_MODE_CONTROL4, + }, { + .range_min = BU27034_REG_DATA0_LO, + .range_max = BU27034_REG_DATA2_HI, + }, +}; + +static const struct regmap_access_table bu27034_volatile_regs = { + .yes_ranges = &bu27034_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bu27034_volatile_ranges), +}; + +static const struct regmap_range bu27034_read_only_ranges[] = { + { + .range_min = BU27034_REG_DATA0_LO, + .range_max = BU27034_REG_DATA2_HI, + }, { + .range_min = BU27034_REG_MANUFACTURER_ID, + .range_max = BU27034_REG_MANUFACTURER_ID, + } +}; + +static const struct regmap_access_table bu27034_ro_regs = { + .no_ranges = &bu27034_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(bu27034_read_only_ranges), +}; + +static const struct regmap_config bu27034_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = BU27034_REG_MAX, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &bu27034_volatile_regs, + .wr_table = &bu27034_ro_regs, +}; + +struct bu27034_gain_check { + int old_gain; + int new_gain; + int chan; +}; + +static int bu27034_get_gain_sel(struct bu27034_data *data, int chan) +{ + int ret, val; + + switch (chan) { + case BU27034_CHAN_DATA0: + case BU27034_CHAN_DATA1: + { + int reg[] = { + [BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2, + [BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3, + }; + ret = regmap_read(data->regmap, reg[chan], &val); + if (ret) + return ret; + + return FIELD_GET(BU27034_MASK_D01_GAIN, val); + } + case BU27034_CHAN_DATA2: + { + int d2_lo_bits = fls(BU27034_MASK_D2_GAIN_LO); + + ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL2, &val); + if (ret) + return ret; + + /* + * The data2 channel gain is composed by 5 non continuous bits + * [7:6], [2:0]. Thus when we combine the 5-bit 'selector' + * from register value we must right shift the high bits by 3. + */ + return FIELD_GET(BU27034_MASK_D2_GAIN_HI, val) << d2_lo_bits | + FIELD_GET(BU27034_MASK_D2_GAIN_LO, val); + } + default: + return -EINVAL; + } +} + +static int bu27034_get_gain(struct bu27034_data *data, int chan, int *gain) +{ + int ret, sel; + + ret = bu27034_get_gain_sel(data, chan); + if (ret < 0) + return ret; + + sel = ret; + + ret = iio_gts_find_gain_by_sel(&data->gts, sel); + if (ret < 0) { + dev_err(data->dev, "chan %u: unknown gain value 0x%x\n", chan, + sel); + + return ret; + } + + *gain = ret; + + return 0; +} + +static int bu27034_get_int_time(struct bu27034_data *data) +{ + int ret, sel; + + ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &sel); + if (ret) + return ret; + + return iio_gts_find_int_time_by_sel(&data->gts, + sel & BU27034_MASK_MEAS_MODE); +} + +static int _bu27034_get_scale(struct bu27034_data *data, int channel, int *val, + int *val2) +{ + int gain, ret; + + ret = bu27034_get_gain(data, channel, &gain); + if (ret) + return ret; + + ret = bu27034_get_int_time(data); + if (ret < 0) + return ret; + + return iio_gts_get_scale(&data->gts, gain, ret, val, val2); +} + +static int bu27034_get_scale(struct bu27034_data *data, int channel, int *val, + int *val2) +{ + int ret; + + if (channel == BU27034_CHAN_ALS) { + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + } + + mutex_lock(&data->mutex); + ret = _bu27034_get_scale(data, channel, val, val2); + mutex_unlock(&data->mutex); + if (ret) + return ret; + + return IIO_VAL_INT_PLUS_NANO; +} + +/* Caller should hold the lock to protect lux reading */ +static int bu27034_write_gain_sel(struct bu27034_data *data, int chan, int sel) +{ + static const int reg[] = { + [BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2, + [BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3, + }; + int mask, val; + + if (chan != BU27034_CHAN_DATA0 && chan != BU27034_CHAN_DATA1) + return -EINVAL; + + val = FIELD_PREP(BU27034_MASK_D01_GAIN, sel); + + mask = BU27034_MASK_D01_GAIN; + + if (chan == BU27034_CHAN_DATA0) { + /* + * We keep the same gain for channel 2 as we set for channel 0 + * We can't allow them to be individually controlled because + * setting one will impact also the other. Also, if we don't + * always update both gains we may result unsupported bit + * combinations. + * + * This is not nice but this is yet another place where the + * user space must be prepared to surprizes. Namely, see chan 2 + * gain changed when chan 0 gain is changed. + * + * This is not fatal for most users though. I don't expect the + * channel 2 to be used in any generic cases - the intensity + * values provided by the sensor for IR area are not openly + * documented. Also, channel 2 is not used for visible light. + * + * So, if there is application which is written to utilize the + * channel 2 - then it is probably specifically targeted to this + * sensor and knows how to utilize those values. It is safe to + * hope such user can also cope with the gain changes. + */ + mask |= BU27034_MASK_D2_GAIN_LO; + + /* + * The D2 gain bits are directly the lowest bits of selector. + * Just do add those bits to the value + */ + val |= sel & BU27034_MASK_D2_GAIN_LO; + } + + return regmap_update_bits(data->regmap, reg[chan], mask, val); +} + +static int bu27034_set_gain(struct bu27034_data *data, int chan, int gain) +{ + int ret; + + /* + * We don't allow setting channel 2 gain as it messes up the + * gain for channel 0 - which shares the high bits + */ + if (chan != BU27034_CHAN_DATA0 && chan != BU27034_CHAN_DATA1) + return -EINVAL; + + ret = iio_gts_find_sel_by_gain(&data->gts, gain); + if (ret < 0) + return ret; + + return bu27034_write_gain_sel(data, chan, ret); +} + +/* Caller should hold the lock to protect data->int_time */ +static int bu27034_set_int_time(struct bu27034_data *data, int time) +{ + int ret; + + ret = iio_gts_find_sel_by_int_time(&data->gts, time); + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, + BU27034_MASK_MEAS_MODE, ret); +} + +/* + * We try to change the time in such way that the scale is maintained for + * given channels by adjusting gain so that it compensates the time change. + */ +static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) +{ + struct bu27034_gain_check gains[] = { + { .chan = BU27034_CHAN_DATA0 }, + { .chan = BU27034_CHAN_DATA1 }, + }; + int numg = ARRAY_SIZE(gains); + int ret, int_time_old, i; + + mutex_lock(&data->mutex); + ret = bu27034_get_int_time(data); + if (ret < 0) + goto unlock_out; + + int_time_old = ret; + + if (!iio_gts_valid_time(&data->gts, time_us)) { + dev_err(data->dev, "Unsupported integration time %u\n", + time_us); + ret = -EINVAL; + + goto unlock_out; + } + + if (time_us == int_time_old) { + ret = 0; + goto unlock_out; + } + + for (i = 0; i < numg; i++) { + ret = bu27034_get_gain(data, gains[i].chan, &gains[i].old_gain); + if (ret) + goto unlock_out; + + ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, + gains[i].old_gain, + int_time_old, time_us, + &gains[i].new_gain); + if (ret) { + int scale1, scale2; + bool ok; + + _bu27034_get_scale(data, gains[i].chan, &scale1, &scale2); + dev_dbg(data->dev, + "chan %u, can't support time %u with scale %u %u\n", + gains[i].chan, time_us, scale1, scale2); + + if (gains[i].new_gain < 0) + goto unlock_out; + + /* + * If caller requests for integration time change and we + * can't support the scale - then the caller should be + * prepared to 'pick up the pieces and deal with the + * fact that the scale changed'. + */ + ret = iio_find_closest_gain_low(&data->gts, + gains[i].new_gain, &ok); + + if (!ok) + dev_dbg(data->dev, + "optimal gain out of range for chan %u\n", + gains[i].chan); + + if (ret < 0) { + dev_dbg(data->dev, + "Total gain increase. Risk of saturation"); + ret = iio_gts_get_min_gain(&data->gts); + if (ret < 0) + goto unlock_out; + } + dev_dbg(data->dev, "chan %u scale changed\n", + gains[i].chan); + gains[i].new_gain = ret; + dev_dbg(data->dev, "chan %u new gain %u\n", + gains[i].chan, gains[i].new_gain); + } + } + + for (i = 0; i < numg; i++) { + ret = bu27034_set_gain(data, gains[i].chan, gains[i].new_gain); + if (ret) + goto unlock_out; + } + + ret = bu27034_set_int_time(data, time_us); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bu27034_set_scale(struct bu27034_data *data, int chan, + int val, int val2) +{ + int ret, time_sel, gain_sel, i; + bool found = false; + + if (chan == BU27034_CHAN_DATA2) + return -EINVAL; + + if (chan == BU27034_CHAN_ALS) { + if (val == 0 && val2 == 1000) + return 0; + + return -EINVAL; + } + + mutex_lock(&data->mutex); + ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel); + if (ret) + goto unlock_out; + + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, + val, val2 * 1000, &gain_sel); + if (ret) { + /* + * Could not support scale with given time. Need to change time. + * We still want to maintain the scale for all channels + */ + struct bu27034_gain_check gain; + int new_time_sel; + + /* + * Populate information for the other channel which should also + * maintain the scale. (Due to the HW limitations the chan2 + * gets the same gain as chan0, so we only need to explicitly + * set the chan 0 and 1). + */ + if (chan == BU27034_CHAN_DATA0) + gain.chan = BU27034_CHAN_DATA1; + else if (chan == BU27034_CHAN_DATA1) + gain.chan = BU27034_CHAN_DATA0; + + ret = bu27034_get_gain(data, gain.chan, &gain.old_gain); + if (ret) + goto unlock_out; + + /* + * Iterate through all the times to see if we find one which + * can support requested scale for requested channel, while + * maintaining the scale for other channels + */ + for (i = 0; i < data->gts.num_itime; i++) { + new_time_sel = data->gts.itime_table[i].sel; + + if (new_time_sel == time_sel) + continue; + + /* Can we provide requested scale with this time? */ + ret = iio_gts_find_gain_sel_for_scale_using_time( + &data->gts, new_time_sel, val, val2 * 1000, + &gain_sel); + if (ret) + continue; + + /* Can the other channel(s) maintain scale? */ + ret = iio_gts_find_new_gain_sel_by_old_gain_time( + &data->gts, gain.old_gain, time_sel, + new_time_sel, &gain.new_gain); + if (!ret) { + /* Yes - we found suitable time */ + found = true; + break; + } + } + if (!found) { + dev_dbg(data->dev, + "Can't set scale maintaining other channels\n"); + ret = -EINVAL; + + goto unlock_out; + } + + ret = bu27034_set_gain(data, gain.chan, gain.new_gain); + if (ret) + goto unlock_out; + + ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, + BU27034_MASK_MEAS_MODE, new_time_sel); + if (ret) + goto unlock_out; + } + + ret = bu27034_write_gain_sel(data, chan, gain_sel); +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +/* + * for (D1/D0 < 0.87): + * lx = 0.004521097 * D1 - 0.002663996 * D0 + + * 0.00012213 * D1 * D1 / D0 + * + * => 115.7400832 * ch1 / gain1 / mt - + * 68.1982976 * ch0 / gain0 / mt + + * 0.00012213 * 25600 * (ch1 / gain1 / mt) * 25600 * + * (ch1 /gain1 / mt) / (25600 * ch0 / gain0 / mt) + * + * A = 0.00012213 * 25600 * (ch1 /gain1 / mt) * 25600 * + * (ch1 /gain1 / mt) / (25600 * ch0 / gain0 / mt) + * => 0.00012213 * 25600 * (ch1 /gain1 / mt) * + * (ch1 /gain1 / mt) / (ch0 / gain0 / mt) + * => 0.00012213 * 25600 * (ch1 / gain1) * (ch1 /gain1 / mt) / + * (ch0 / gain0) + * => 0.00012213 * 25600 * (ch1 / gain1) * (ch1 /gain1 / mt) * + * gain0 / ch0 + * => 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / mt /ch0 + * + * lx = (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) / + * mt + A + * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) / + * mt + 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / mt / + * ch0 + * + * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0 + + * 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / ch0) / + * mt + * + * For (0.87 <= D1/D0 < 1.00) + * lx = (0.001331* D0 + 0.0000354 * D1) * ((D1/D0 – 0.87) * (0.385) + 1) + * => (0.001331 * 256 * 100 * ch0 / gain0 / mt + 0.0000354 * 256 * + * 100 * ch1 / gain1 / mt) * ((D1/D0 - 0.87) * (0.385) + 1) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * ((D1/D0 - 0.87) * (0.385) + 1) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * (0.385 * D1/D0 - 0.66505) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * (0.385 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) - 0.66505) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * (9856 * ch1 / gain1 / mt / (25600 * ch0 / gain0 / mt) + 0.66505) + * => 13.118336 * ch1 / (gain1 * mt) + * + 22.66064768 * ch0 / (gain0 * mt) + * + 8931.90144 * ch1 * ch1 * gain0 / + * (25600 * ch0 * gain1 * gain1 * mt) + * + 0.602694912 * ch1 / (gain1 * mt) + * + * => [0.3489024 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + * + 22.66064768 * ch0 / gain0 + * + 13.721030912 * ch1 / gain1 + * ] / mt + * + * For (D1/D0 >= 1.00) + * + * lx = (0.001331* D0 + 0.0000354 * D1) * ((D1/D0 – 2.0) * (-0.05) + 1) + * => (0.001331* D0 + 0.0000354 * D1) * (-0.05D1/D0 + 1.1) + * => (0.001331 * 256 * 100 * ch0 / gain0 / mt + 0.0000354 * 256 * + * 100 * ch1 / gain1 / mt) * (-0.05D1/D0 + 1.1) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * (-0.05 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) + 1.1) + * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * + * (-1280 * ch1 / (gain1 * mt * 25600 * ch0 / gain0 / mt) + 1.1) + * => (34.0736 * ch0 * -1280 * ch1 * gain0 * mt /( gain0 * mt * gain1 * mt * 25600 * ch0) + * + 34.0736 * 1.1 * ch0 / (gain0 * mt) + * + 0.90624 * ch1 * -1280 * ch1 *gain0 * mt / (gain1 * mt *gain1 * mt * 25600 * ch0) + * + 1.1 * 0.90624 * ch1 / (gain1 * mt) + * => -43614.208 * ch1 / (gain1 * mt * 25600) + * + 37.48096 ch0 / (gain0 * mt) + * - 1159.9872 * ch1 * ch1 * gain0 / (gain1 * gain1 * mt * 25600 * ch0) + * + 0.996864 ch1 / (gain1 * mt) + * => [ + * - 0.045312 * ch1 * ch1 * gain0 / (gain1 * gain1 * ch0) + * - 0.706816 * ch1 / gain1 + * + 37.48096 ch0 /gain0 + * ] * mt + * + * + * So, the first case (D1/D0 < 0.87) can be computed to a form: + * + * lx = (3.126528 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + + * 115.7400832 * ch1 / gain1 + + * -68.1982976 * ch0 / gain0 + * / mt + * + * Second case (0.87 <= D1/D0 < 1.00) goes to form: + * + * => [0.3489024 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + + * 13.721030912 * ch1 / gain1 + + * 22.66064768 * ch0 / gain0 + * ] / mt + * + * Third case (D1/D0 >= 1.00) goes to form: + * => [-0.045312 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + + * -0.706816 * ch1 / gain1 + + * 37.48096 ch0 /(gain0 + * ] / mt + * + * This can be unified to format: + * lx = [ + * A * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + + * B * ch1 / gain1 + + * C * ch0 / gain0 + * ] / mt + * + * For case 1: + * A = 3.126528, + * B = 115.7400832 + * C = -68.1982976 + * + * For case 2: + * A = 0.3489024 + * B = 13.721030912 + * C = 22.66064768 + * + * For case 3: + * A = -0.045312 + * B = -0.706816 + * C = 37.48096 + */ + +struct bu27034_lx_coeff { + unsigned int A; + unsigned int B; + unsigned int C; + /* Indicate which of the coefficients above are negative */ + bool is_neg[3]; +}; + +static inline u64 gain_mul_div_helper(u64 val, unsigned int gain, + unsigned int div) +{ + /* + * Max gain for a channel is 4096. The max u64 (0xffffffffffffffffULL) + * divided by 4096 is 0xFFFFFFFFFFFFF (GENMASK_ULL(51, 0)) (floored). + * Thus, the 0xFFFFFFFFFFFFF is the largest value we can safely multiply + * with the gain, no matter what gain is set. + * + * So, multiplication with max gain may overflow if val is greater than + * 0xFFFFFFFFFFFFF (52 bits set).. + * + * If this is the case we divide first. + */ + if (val < GENMASK_ULL(51, 0)) { + val *= gain; + do_div(val, div); + } else { + do_div(val, div); + val *= gain; + } + + return val; +} + +static u64 bu27034_fixp_calc_t1_64bit(unsigned int coeff, unsigned int ch0, + unsigned int ch1, unsigned int gain0, + unsigned int gain1) +{ + unsigned int helper; + u64 helper64; + + helper64 = (u64)coeff * (u64)ch1 * (u64)ch1; + + helper = gain1 * gain1; + if (helper > ch0) { + do_div(helper64, helper); + + return gain_mul_div_helper(helper64, gain0, ch0); + } + + do_div(helper64, ch0); + + return gain_mul_div_helper(helper64, gain0, helper); + +} + +static u64 bu27034_fixp_calc_t1(unsigned int coeff, unsigned int ch0, + unsigned int ch1, unsigned int gain0, + unsigned int gain1) +{ + unsigned int helper, tmp; + + /* + * Here we could overflow even the 64bit value. Hence we + * multiply with gain0 only after the divisions - even though + * it may result loss of accuracy + */ + helper = coeff * ch1 * ch1; + tmp = helper * gain0; + + helper = ch1 * ch1; + + if (check_mul_overflow(helper, coeff, &helper)) + return bu27034_fixp_calc_t1_64bit(coeff, ch0, ch1, gain0, gain1); + + if (check_mul_overflow(helper, gain0, &tmp)) + return bu27034_fixp_calc_t1_64bit(coeff, ch0, ch1, gain0, gain1); + + return tmp / (gain1 * gain1) / ch0; + +} + +static u64 bu27034_fixp_calc_t23(unsigned int coeff, unsigned int ch, + unsigned int gain) +{ + unsigned int helper; + u64 helper64; + + if (!check_mul_overflow(coeff, ch, &helper)) + return helper / gain; + + helper64 = (u64)coeff * (u64)ch; + do_div(helper64, gain); + + return helper64; +} + +static int bu27034_fixp_calc_lx(unsigned int ch0, unsigned int ch1, + unsigned int gain0, unsigned int gain1, + unsigned int meastime, int coeff_idx) +{ + static const struct bu27034_lx_coeff coeff[] = { + { + .A = 31265280, /* 3.126528 */ + .B = 1157400832, /*115.7400832 */ + .C = 681982976, /* -68.1982976 */ + .is_neg = {false, false, true}, + }, { + .A = 3489024, /* 0.3489024 */ + .B = 137210309, /* 13.721030912 */ + .C = 226606476, /* 22.66064768 */ + /* All terms positive */ + }, { + .A = 453120, /* -0.045312 */ + .B = 7068160, /* -0.706816 */ + .C = 374809600, /* 37.48096 */ + .is_neg = {true, true, false}, + } + }; + const struct bu27034_lx_coeff *c = &coeff[coeff_idx]; + u64 res = 0, terms[3]; + int i; + + if (coeff_idx >= ARRAY_SIZE(coeff)) + return -EINVAL; + + terms[0] = bu27034_fixp_calc_t1(c->A, ch0, ch1, gain0, gain1); + terms[1] = bu27034_fixp_calc_t23(c->B, ch1, gain1); + terms[2] = bu27034_fixp_calc_t23(c->C, ch0, gain0); + + /* First, add positive terms */ + for (i = 0; i < 3; i++) + if (!c->is_neg[i]) + res += terms[i]; + + /* No positive term => zero lux */ + if (!res) + return 0; + + /* Then, subtract negative terms (if any) */ + for (i = 0; i < 3; i++) + if (c->is_neg[i]) { + /* + * If the negative term is greater than positive - then + * the darkness has taken over and we are all doomed! Eh, + * I mean, then we can just return 0 lx and go out + */ + if (terms[i] >= res) + return 0; + + res -= terms[i]; + } + + meastime *= 10; + do_div(res, meastime); + + return (int) res; +} + +static bool bu27034_has_valid_sample(struct bu27034_data *data) +{ + int ret, val; + + ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL4, &val); + if (ret) { + dev_err(data->dev, "Read failed %d\n", ret); + + return false; + } + + return val & BU27034_MASK_VALID; +} + +/* + * Reading the register where VALID bit is clears this bit. (So does changing + * any gain / integration time configuration registers) The bit gets + * set when we have acquired new data. We use this bit to indicate data + * validity. + */ +static void bu27034_invalidate_read_data(struct bu27034_data *data) +{ + bu27034_has_valid_sample(data); +} + +static int bu27034_read_result(struct bu27034_data *data, int chan, int *res) +{ + int reg[] = { + [BU27034_CHAN_DATA0] = BU27034_REG_DATA0_LO, + [BU27034_CHAN_DATA1] = BU27034_REG_DATA1_LO, + [BU27034_CHAN_DATA2] = BU27034_REG_DATA2_LO, + }; + int valid, ret; + __le16 val; + + ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, + valid, (valid & BU27034_MASK_VALID), + BU27034_DATA_WAIT_TIME_US, 0); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, reg[chan], &val, sizeof(val)); + if (ret) + return ret; + + *res = le16_to_cpu(val); + + return 0; +} + +static int bu27034_get_result_unlocked(struct bu27034_data *data, __le16 *res, + int size) +{ + int ret = 0, retry_cnt = 0; + +retry: + /* Get new value from sensor if data is ready */ + if (bu27034_has_valid_sample(data)) { + ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO, + res, size); + if (ret) + return ret; + + bu27034_invalidate_read_data(data); + } else { + /* No new data in sensor. Wait and retry */ + retry_cnt++; + + if (retry_cnt > BU27034_RETRY_LIMIT) { + dev_err(data->dev, "No data from sensor\n"); + + return -ETIMEDOUT; + } + + msleep(25); + + goto retry; + } + + return ret; +} + +static int bu27034_meas_set(struct bu27034_data *data, bool en) +{ + if (en) + return regmap_set_bits(data->regmap, BU27034_REG_MODE_CONTROL4, + BU27034_MASK_MEAS_EN); + + return regmap_clear_bits(data->regmap, BU27034_REG_MODE_CONTROL4, + BU27034_MASK_MEAS_EN); +} + +static int bu27034_get_single_result(struct bu27034_data *data, int chan, + int *val) +{ + int ret; + + if (chan < BU27034_CHAN_DATA0 || chan > BU27034_CHAN_DATA2) + return -EINVAL; + + ret = bu27034_meas_set(data, true); + if (ret) + return ret; + + ret = bu27034_get_int_time(data); + if (ret < 0) + return ret; + + msleep(ret / 1000); + + return bu27034_read_result(data, chan, val); +} + +/* + * The formula given by vendor for computing luxes out of data0 and data1 + * (in open air) is as follows: + * + * Let's mark: + * D0 = data0/ch0_gain/meas_time_ms * 25600 + * D1 = data1/ch1_gain/meas_time_ms * 25600 + * + * Then: + * if (D1/D0 < 0.87) + * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 3.45 + 1) + * else if (D1/D0 < 1) + * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 0.385 + 1) + * else + * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 2) * -0.05 + 1) + * + * We use it here. Users who have for example some colored lens + * need to modify the calculation but I hope this gives a starting point for + * those working with such devices. + */ + +static int bu27034_calc_mlux(struct bu27034_data *data, __le16 *res, int *val) +{ + unsigned int gain0, gain1, meastime; + unsigned int d1_d0_ratio_scaled; + u16 ch0, ch1; + u64 helper64; + int ret; + + /* + * We return 0 lux if calculation fails. This should be reasonably + * easy to spot from the buffers especially if raw-data channels show + * valid values + */ + *val = 0; + + ch0 = max_t(u16, 1, le16_to_cpu(res[0])); + ch1 = max_t(u16, 1, le16_to_cpu(res[1])); + + ret = bu27034_get_gain(data, BU27034_CHAN_DATA0, &gain0); + if (ret) + return ret; + + ret = bu27034_get_gain(data, BU27034_CHAN_DATA1, &gain1); + if (ret) + return ret; + + ret = bu27034_get_int_time(data); + if (ret < 0) + return ret; + + meastime = ret; + + d1_d0_ratio_scaled = (unsigned int)ch1 * (unsigned int)gain0 * 100; + helper64 = (u64)ch1 * (u64)gain0 * 100LLU; + + if (helper64 != d1_d0_ratio_scaled) { + unsigned int div = (unsigned int)ch0 * gain1; + + do_div(helper64, div); + d1_d0_ratio_scaled = helper64; + } else { + d1_d0_ratio_scaled /= ch0 * gain1; + } + + if (d1_d0_ratio_scaled < 87) + ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 0); + else if (d1_d0_ratio_scaled < 100) + ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 1); + else + ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 2); + + if (ret < 0) + return ret; + + *val = ret; + + return 0; + +} + +static int bu27034_get_mlux(struct bu27034_data *data, int chan, int *val) +{ + __le16 res[3]; + int ret; + + ret = bu27034_meas_set(data, true); + if (ret) + return ret; + + ret = bu27034_get_result_unlocked(data, &res[0], sizeof(res)); + if (ret) + return ret; + + ret = bu27034_calc_mlux(data, res, val); + if (ret) + return ret; + + ret = bu27034_meas_set(data, false); + if (ret) + dev_err(data->dev, "failed to disable measurement\n"); + + return 0; +} + +static int bu27034_read_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bu27034_data *data = iio_priv(idev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = bu27034_get_int_time(data); + if (*val2 < 0) + return *val2; + + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CHAN_INFO_SCALE: + return bu27034_get_scale(data, chan->channel, val, val2); + + case IIO_CHAN_INFO_RAW: + { + int (*result_get)(struct bu27034_data *data, int chan, int *val); + + if (chan->type == IIO_INTENSITY) + result_get = bu27034_get_single_result; + else if (chan->type == IIO_LIGHT) + result_get = bu27034_get_mlux; + else + return -EINVAL; + + /* Don't mess with measurement enabling while buffering */ + ret = iio_device_claim_direct_mode(idev); + if (ret) + return ret; + + mutex_lock(&data->mutex); + /* + * Reading one channel at a time is inefficient but we + * don't care here. Buffered version should be used if + * performance is an issue. + */ + ret = result_get(data, chan->channel, val); + + mutex_unlock(&data->mutex); + iio_device_release_direct_mode(idev); + + if (ret) + return ret; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int bu27034_write_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bu27034_data *data = iio_priv(idev); + int ret; + + ret = iio_device_claim_direct_mode(idev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = bu27034_set_scale(data, chan->channel, val, val2); + break; + case IIO_CHAN_INFO_INT_TIME: + if (!val) + ret = bu27034_try_set_int_time(data, val2); + else + ret = -EINVAL; + break; + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(idev); + + return ret; +} + +static int bu27034_read_avail(struct iio_dev *idev, + struct iio_chan_spec const *chan, const int **vals, + int *type, int *length, long mask) +{ + struct bu27034_data *data = iio_priv(idev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return iio_gts_avail_times(&data->gts, vals, type, length); + case IIO_CHAN_INFO_SCALE: + return iio_gts_all_avail_scales(&data->gts, vals, type, length); + default: + return -EINVAL; + } +} + +static const struct iio_info bu27034_info = { + .read_raw = &bu27034_read_raw, + .write_raw = &bu27034_write_raw, + .read_avail = &bu27034_read_avail, +}; + +static int bu27034_chip_init(struct bu27034_data *data) +{ + int ret, sel; + + /* Reset */ + ret = regmap_write_bits(data->regmap, BU27034_REG_SYSTEM_CONTROL, + BU27034_MASK_SW_RESET, BU27034_MASK_SW_RESET); + if (ret) + return dev_err_probe(data->dev, ret, "Sensor reset failed\n"); + + msleep(1); + + ret = regmap_reinit_cache(data->regmap, &bu27034_regmap); + if (ret) { + dev_err(data->dev, "Failed to reinit reg cache\n"); + return ret; + } + + /* + * Read integration time here to ensure it is in regmap cache. We do + * this to speed-up the int-time acquisition in the start of the buffer + * handling thread where longer delays could make it more likely we end + * up skipping a sample, and where the longer delays make timestamps + * less accurate. + */ + ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &sel); + if (ret) + dev_err(data->dev, "reading integration time failed\n"); + + return 0; +} + +static int bu27034_wait_for_data(struct bu27034_data *data) +{ + int ret, val; + + ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, + val, val & BU27034_MASK_VALID, + BU27034_DATA_WAIT_TIME_US, + BU27034_TOTAL_DATA_WAIT_TIME_US); + if (ret) { + dev_err(data->dev, "data polling %s\n", + !(val & BU27034_MASK_VALID) ? "timeout" : "fail"); + + return ret; + } + + ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO, + &data->scan.channels[0], + sizeof(data->scan.channels)); + if (ret) + return ret; + + bu27034_invalidate_read_data(data); + + return 0; +} + +static int bu27034_buffer_thread(void *arg) +{ + struct iio_dev *idev = arg; + struct bu27034_data *data; + int wait_ms; + + data = iio_priv(idev); + + wait_ms = bu27034_get_int_time(data); + wait_ms /= 1000; + + wait_ms -= BU27034_MEAS_WAIT_PREMATURE_MS; + + while (!kthread_should_stop()) { + int ret; + int64_t tstamp; + + msleep(wait_ms); + ret = bu27034_wait_for_data(data); + if (ret) + continue; + + tstamp = iio_get_time_ns(idev); + + if (test_bit(BU27034_CHAN_ALS, idev->active_scan_mask)) { + int mlux; + + ret = bu27034_calc_mlux(data, &data->scan.channels[0], + &mlux); + if (ret) + dev_err(data->dev, "failed to calculate lux\n"); + + /* + * The maximum Milli lux value we get with gain 1x time + * 55mS data ch0 = 0xffff ch1 = 0xffff fits in 26 bits + * so there should be no problem returning int from + * computations and casting it to u32 + */ + data->scan.mlux = (u32)mlux; + } + iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp); + } + + return 0; +} + +static int bu27034_buffer_enable(struct iio_dev *idev) +{ + struct bu27034_data *data = iio_priv(idev); + struct task_struct *task; + int ret; + + mutex_lock(&data->mutex); + ret = bu27034_meas_set(data, true); + if (ret) + goto unlock_out; + + task = kthread_run(bu27034_buffer_thread, idev, + "bu27034-buffering-%u", + iio_device_id(idev)); + if (IS_ERR(task)) { + ret = PTR_ERR(task); + goto unlock_out; + } + + data->task = task; + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bu27034_buffer_disable(struct iio_dev *idev) +{ + struct bu27034_data *data = iio_priv(idev); + int ret; + + mutex_lock(&data->mutex); + if (data->task) { + kthread_stop(data->task); + data->task = NULL; + } + + ret = bu27034_meas_set(data, false); + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_buffer_setup_ops bu27034_buffer_ops = { + .postenable = &bu27034_buffer_enable, + .predisable = &bu27034_buffer_disable, +}; + +static int bu27034_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct bu27034_data *data; + struct regmap *regmap; + struct iio_dev *idev; + unsigned int part_id, reg; + int ret; + + regmap = devm_regmap_init_i2c(i2c, &bu27034_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize Regmap\n"); + + idev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!idev) + return -ENOMEM; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); + + data = iio_priv(idev); + + ret = regmap_read(regmap, BU27034_REG_SYSTEM_CONTROL, ®); + if (ret) + return dev_err_probe(dev, ret, "Failed to access sensor\n"); + + part_id = FIELD_GET(BU27034_MASK_PART_ID, reg); + + if (part_id != BU27034_ID) + dev_warn(dev, "unknown device 0x%x\n", part_id); + + ret = devm_iio_init_iio_gts(dev, BU27034_SCALE_1X, 0, bu27034_gains, + ARRAY_SIZE(bu27034_gains), bu27034_itimes, + ARRAY_SIZE(bu27034_itimes), &data->gts); + if (ret) + return ret; + + mutex_init(&data->mutex); + data->regmap = regmap; + data->dev = dev; + + idev->channels = bu27034_channels; + idev->num_channels = ARRAY_SIZE(bu27034_channels); + idev->name = "bu27034"; + idev->info = &bu27034_info; + + idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + idev->available_scan_masks = bu27034_scan_masks; + + ret = bu27034_chip_init(data); + if (ret) + return ret; + + ret = devm_iio_kfifo_buffer_setup(dev, idev, &bu27034_buffer_ops); + if (ret) + return dev_err_probe(dev, ret, "buffer setup failed\n"); + + ret = devm_iio_device_register(dev, idev); + if (ret < 0) + return dev_err_probe(dev, ret, + "Unable to register iio device\n"); + + return ret; +} + +static const struct of_device_id bu27034_of_match[] = { + { .compatible = "rohm,bu27034" }, + { } +}; +MODULE_DEVICE_TABLE(of, bu27034_of_match); + +static struct i2c_driver bu27034_i2c_driver = { + .driver = { + .name = "bu27034-als", + .of_match_table = bu27034_of_match, + }, + .probe_new = bu27034_probe, +}; +module_i2c_driver(bu27034_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("ROHM BU27034 ambient light sensor driver"); +MODULE_IMPORT_NS(IIO_GTS_HELPER); diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 668e444f6049..9d0218b7426e 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -431,7 +431,7 @@ static irqreturn_t rpr0521_drdy_irq_thread(int irq, void *private) struct rpr0521_data *data = iio_priv(indio_dev); if (rpr0521_is_triggered(data)) { - iio_trigger_poll_chained(data->drdy_trigger0); + iio_trigger_poll_nested(data->drdy_trigger0); return IRQ_HANDLED; } diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index c737d3e193ae..50f95c5d2060 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -161,7 +161,7 @@ static irqreturn_t st_uvis25_trigger_handler_thread(int irq, void *private) if (!(status & ST_UVIS25_REG_UV_DA_MASK)) return IRQ_NONE; - iio_trigger_poll_chained(hw->trig); + iio_trigger_poll_nested(hw->trig); return IRQ_HANDLED; } diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 5c44a36ab5b3..56d3963d3d66 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1077,7 +1077,7 @@ static irqreturn_t vcnl4010_irq_thread(int irq, void *p) } if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev)) - iio_trigger_poll_chained(indio_dev->trig); + iio_trigger_poll_nested(indio_dev->trig); end: return IRQ_HANDLED; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 84148b944000..94f5d611e98c 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -8,6 +8,7 @@ * TODO: Proximity */ #include +#include #include #include #include @@ -42,6 +43,7 @@ #define VCNL4035_ALS_PERS_MASK GENMASK(3, 2) #define VCNL4035_INT_ALS_IF_H_MASK BIT(12) #define VCNL4035_INT_ALS_IF_L_MASK BIT(13) +#define VCNL4035_DEV_ID_MASK GENMASK(7, 0) /* Default values */ #define VCNL4035_MODE_ALS_ENABLE BIT(0) @@ -89,7 +91,7 @@ static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private) IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), iio_get_time_ns(indio_dev)); - iio_trigger_poll_chained(data->drdy_trigger0); + iio_trigger_poll_nested(data->drdy_trigger0); return IRQ_HANDLED; } @@ -413,6 +415,7 @@ static int vcnl4035_init(struct vcnl4035_data *data) return ret; } + id = FIELD_GET(VCNL4035_DEV_ID_MASK, id); if (id != VCNL4035_DEV_ID_VAL) { dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n", id, VCNL4035_DEV_ID_VAL); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 28bb7efe8df8..e155a75b3cd2 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -296,12 +296,13 @@ static int tmag5273_read_raw(struct iio_dev *indio_dev, return ret; ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude); - if (ret) - return ret; pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); + if (ret) + return ret; + switch (chan->address) { case TEMPERATURE: *val = t; diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index b82f093f1e6a..0083e858c21e 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -118,7 +118,7 @@ static int lmp91000_read(struct lmp91000_data *data, int channel, int *val) data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; - iio_trigger_poll_chained(data->trig); + iio_trigger_poll_nested(data->trig); ret = wait_for_completion_timeout(&data->completion, HZ); reinit_completion(&data->completion); diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index c9453389e4f7..02b97e89de50 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -17,14 +17,14 @@ config ABP060MG will be called abp060mg. config BMP280 - tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor I2C driver" + tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver" depends on (I2C || SPI_MASTER) select REGMAP select BMP280_I2C if (I2C) select BMP280_SPI if (SPI_MASTER) help - Say yes here to build support for Bosch Sensortec BMP180, BMP280 and - BMP380 pressure and temperature sensors. Also supports the BME280 with + Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380 + and BMP580 pressure and temperature sensors. Also supports the BME280 with an additional humidity sensor channel. To compile this driver as a module, choose M here: the core module diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index c0aff78489b4..6089f3f9d8f4 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -13,6 +13,7 @@ * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf + * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf * * Notice: * The link to the bmp180 datasheet points to an outdated version missing these changes: @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -49,65 +51,6 @@ */ enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; -struct bmp180_calib { - s16 AC1; - s16 AC2; - s16 AC3; - u16 AC4; - u16 AC5; - u16 AC6; - s16 B1; - s16 B2; - s16 MB; - s16 MC; - s16 MD; -}; - -/* See datasheet Section 4.2.2. */ -struct bmp280_calib { - u16 T1; - s16 T2; - s16 T3; - u16 P1; - s16 P2; - s16 P3; - s16 P4; - s16 P5; - s16 P6; - s16 P7; - s16 P8; - s16 P9; - u8 H1; - s16 H2; - u8 H3; - s16 H4; - s16 H5; - s8 H6; -}; - -/* See datasheet Section 3.11.1. */ -struct bmp380_calib { - u16 T1; - u16 T2; - s8 T3; - s16 P1; - s16 P2; - s8 P3; - s8 P4; - u16 P5; - u16 P6; - s8 P7; - s8 P8; - s16 P9; - s8 P10; - s8 P11; -}; - -static const char *const bmp280_supply_names[] = { - "vddd", "vdda" -}; - -#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names) enum bmp380_odr { BMP380_ODR_200HZ, @@ -130,92 +73,39 @@ enum bmp380_odr { BMP380_ODR_0_0015HZ, }; -struct bmp280_data { - struct device *dev; - struct mutex lock; - struct regmap *regmap; - struct completion done; - bool use_eoc; - const struct bmp280_chip_info *chip_info; - union { - struct bmp180_calib bmp180; - struct bmp280_calib bmp280; - struct bmp380_calib bmp380; - } calib; - struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES]; - unsigned int start_up_time; /* in microseconds */ - - /* log of base 2 of oversampling rate */ - u8 oversampling_press; - u8 oversampling_temp; - u8 oversampling_humid; - u8 iir_filter_coeff; - - /* - * BMP380 devices introduce sampling frequency configuration. See - * datasheet sections 3.3.3. and 4.3.19 for more details. - * - * BMx280 devices allowed indirect configuration of sampling frequency - * changing the t_standby duration between measurements, as detailed on - * section 3.6.3 of the datasheet. - */ - int sampling_freq; - - /* - * Carryover value from temperature conversion, used in pressure - * calculation. - */ - s32 t_fine; - - /* - * DMA (thus cache coherency maintenance) may require the - * transfer buffers to live in their own cache lines. - */ - union { - /* Sensor data buffer */ - u8 buf[3]; - /* Calibration data buffers */ - __le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2]; - __be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2]; - u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT]; - /* Miscellaneous, endianess-aware data buffers */ - __le16 le16; - __be16 be16; - } __aligned(IIO_DMA_MINALIGN); -}; - -struct bmp280_chip_info { - unsigned int id_reg; - - const struct iio_chan_spec *channels; - int num_channels; - unsigned int start_up_time; - - const int *oversampling_temp_avail; - int num_oversampling_temp_avail; - int oversampling_temp_default; - - const int *oversampling_press_avail; - int num_oversampling_press_avail; - int oversampling_press_default; - - const int *oversampling_humid_avail; - int num_oversampling_humid_avail; - int oversampling_humid_default; - - const int *iir_filter_coeffs_avail; - int num_iir_filter_coeffs_avail; - int iir_filter_coeff_default; - - const int (*sampling_freq_avail)[2]; - int num_sampling_freq_avail; - int sampling_freq_default; - - int (*chip_config)(struct bmp280_data *); - int (*read_temp)(struct bmp280_data *, int *); - int (*read_press)(struct bmp280_data *, int *, int *); - int (*read_humid)(struct bmp280_data *, int *, int *); - int (*read_calib)(struct bmp280_data *); +enum bmp580_odr { + BMP580_ODR_240HZ, + BMP580_ODR_218HZ, + BMP580_ODR_199HZ, + BMP580_ODR_179HZ, + BMP580_ODR_160HZ, + BMP580_ODR_149HZ, + BMP580_ODR_140HZ, + BMP580_ODR_129HZ, + BMP580_ODR_120HZ, + BMP580_ODR_110HZ, + BMP580_ODR_100HZ, + BMP580_ODR_89HZ, + BMP580_ODR_80HZ, + BMP580_ODR_70HZ, + BMP580_ODR_60HZ, + BMP580_ODR_50HZ, + BMP580_ODR_45HZ, + BMP580_ODR_40HZ, + BMP580_ODR_35HZ, + BMP580_ODR_30HZ, + BMP580_ODR_25HZ, + BMP580_ODR_20HZ, + BMP580_ODR_15HZ, + BMP580_ODR_10HZ, + BMP580_ODR_5HZ, + BMP580_ODR_4HZ, + BMP580_ODR_3HZ, + BMP580_ODR_2HZ, + BMP580_ODR_1HZ, + BMP580_ODR_0_5HZ, + BMP580_ODR_0_25HZ, + BMP580_ODR_0_125HZ, }; /* @@ -473,7 +363,7 @@ static u32 bmp280_compensate_press(struct bmp280_data *data, } static int bmp280_read_temp(struct bmp280_data *data, - int *val) + int *val, int *val2) { s32 adc_temp, comp_temp; int ret; @@ -513,7 +403,7 @@ static int bmp280_read_press(struct bmp280_data *data, int ret; /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL); + ret = bmp280_read_temp(data, NULL, NULL); if (ret < 0) return ret; @@ -545,7 +435,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) int ret; /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL); + ret = bmp280_read_temp(data, NULL, NULL); if (ret < 0) return ret; @@ -589,7 +479,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, ret = data->chip_info->read_press(data, val, val2); break; case IIO_TEMP: - ret = data->chip_info->read_temp(data, val); + ret = data->chip_info->read_temp(data, val, val2); break; default: ret = -EINVAL; @@ -905,8 +795,10 @@ static int bmp280_chip_config(struct bmp280_data *data) static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 }; -static const struct bmp280_chip_info bmp280_chip_info = { +const struct bmp280_chip_info bmp280_chip_info = { .id_reg = BMP280_REG_ID, + .chip_id = BMP280_CHIP_ID, + .regmap_config = &bmp280_regmap_config, .start_up_time = 2000, .channels = bmp280_channels, .num_channels = 2, @@ -934,6 +826,7 @@ static const struct bmp280_chip_info bmp280_chip_info = { .read_press = bmp280_read_press, .read_calib = bmp280_read_calib, }; +EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280); static int bme280_chip_config(struct bmp280_data *data) { @@ -953,8 +846,10 @@ static int bme280_chip_config(struct bmp280_data *data) return bmp280_chip_config(data); } -static const struct bmp280_chip_info bme280_chip_info = { +const struct bmp280_chip_info bme280_chip_info = { .id_reg = BMP280_REG_ID, + .chip_id = BME280_CHIP_ID, + .regmap_config = &bmp280_regmap_config, .start_up_time = 2000, .channels = bmp280_channels, .num_channels = 3, @@ -977,6 +872,7 @@ static const struct bmp280_chip_info bme280_chip_info = { .read_humid = bmp280_read_humid, .read_calib = bme280_read_calib, }; +EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280); /* * Helper function to send a command to BMP3XX sensors. @@ -1095,7 +991,7 @@ static u32 bmp380_compensate_press(struct bmp280_data *data, u32 adc_press) return comp_press; } -static int bmp380_read_temp(struct bmp280_data *data, int *val) +static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2) { s32 comp_temp; u32 adc_temp; @@ -1135,7 +1031,7 @@ static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2) int ret; /* Read and compensate for temperature so we get a reading of t_fine */ - ret = bmp380_read_temp(data, NULL); + ret = bmp380_read_temp(data, NULL, NULL); if (ret) return ret; @@ -1217,6 +1113,12 @@ static const int bmp380_odr_table[][2] = { [BMP380_ODR_0_0015HZ] = {0, 1526}, }; +static int bmp380_preinit(struct bmp280_data *data) +{ + /* BMP3xx requires soft-reset as part of initialization */ + return bmp380_cmd(data, BMP380_CMD_SOFT_RESET); +} + static int bmp380_chip_config(struct bmp280_data *data) { bool change = false, aux; @@ -1319,8 +1221,10 @@ static int bmp380_chip_config(struct bmp280_data *data) static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 }; static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128}; -static const struct bmp280_chip_info bmp380_chip_info = { +const struct bmp280_chip_info bmp380_chip_info = { .id_reg = BMP380_REG_ID, + .chip_id = BMP380_CHIP_ID, + .regmap_config = &bmp380_regmap_config, .start_up_time = 2000, .channels = bmp380_channels, .num_channels = 2, @@ -1345,7 +1249,508 @@ static const struct bmp280_chip_info bmp380_chip_info = { .read_temp = bmp380_read_temp, .read_press = bmp380_read_press, .read_calib = bmp380_read_calib, + .preinit = bmp380_preinit, }; +EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280); + +static int bmp580_soft_reset(struct bmp280_data *data) +{ + unsigned int reg; + int ret; + + ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_SOFT_RESET); + if (ret) { + dev_err(data->dev, "failed to send reset command to device\n"); + return ret; + } + usleep_range(2000, 2500); + + /* Dummy read of chip_id */ + ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); + if (ret) { + dev_err(data->dev, "failed to reestablish comms after reset\n"); + return ret; + } + + ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, ®); + if (ret) { + dev_err(data->dev, "error reading interrupt status register\n"); + return ret; + } + if (!(reg & BMP580_INT_STATUS_POR_MASK)) { + dev_err(data->dev, "error resetting sensor\n"); + return -EINVAL; + } + + return 0; +} + +/** + * bmp580_nvm_operation() - Helper function to commit NVM memory operations + * @data: sensor data struct + * @is_write: flag to signal write operation + */ +static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write) +{ + unsigned long timeout, poll; + unsigned int reg; + int ret; + + /* Check NVM ready flag */ + ret = regmap_read(data->regmap, BMP580_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to check nvm status\n"); + return ret; + } + if (!(reg & BMP580_STATUS_NVM_RDY_MASK)) { + dev_err(data->dev, "sensor's nvm is not ready\n"); + return -EIO; + } + + /* Start NVM operation sequence */ + ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_OP_SEQ_0); + if (ret) { + dev_err(data->dev, "failed to send nvm operation's first sequence\n"); + return ret; + } + if (is_write) { + /* Send NVM write sequence */ + ret = regmap_write(data->regmap, BMP580_REG_CMD, + BMP580_CMD_NVM_WRITE_SEQ_1); + if (ret) { + dev_err(data->dev, "failed to send nvm write sequence\n"); + return ret; + } + /* Datasheet says on 4.8.1.2 it takes approximately 10ms */ + poll = 2000; + timeout = 12000; + } else { + /* Send NVM read sequence */ + ret = regmap_write(data->regmap, BMP580_REG_CMD, + BMP580_CMD_NVM_READ_SEQ_1); + if (ret) { + dev_err(data->dev, "failed to send nvm read sequence\n"); + return ret; + } + /* Datasheet says on 4.8.1.1 it takes approximately 200us */ + poll = 50; + timeout = 400; + } + if (ret) { + dev_err(data->dev, "failed to write command sequence\n"); + return -EIO; + } + + /* Wait until NVM is ready again */ + ret = regmap_read_poll_timeout(data->regmap, BMP580_REG_STATUS, reg, + (reg & BMP580_STATUS_NVM_RDY_MASK), + poll, timeout); + if (ret) { + dev_err(data->dev, "error checking nvm operation status\n"); + return ret; + } + + /* Check NVM error flags */ + if ((reg & BMP580_STATUS_NVM_ERR_MASK) || (reg & BMP580_STATUS_NVM_CMD_ERR_MASK)) { + dev_err(data->dev, "error processing nvm operation\n"); + return -EIO; + } + + return 0; +} + +/* + * Contrary to previous sensors families, compensation algorithm is builtin. + * We are only required to read the register raw data and adapt the ranges + * for what is expected on IIO ABI. + */ + +static int bmp580_read_temp(struct bmp280_data *data, int *val, int *val2) +{ + s32 raw_temp; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB, data->buf, + sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read temperature\n"); + return ret; + } + + raw_temp = get_unaligned_le24(data->buf); + if (raw_temp == BMP580_TEMP_SKIPPED) { + dev_err(data->dev, "reading temperature skipped\n"); + return -EIO; + } + + /* + * Temperature is returned in Celsius degrees in fractional + * form down 2^16. We reescale by x1000 to return milli Celsius + * to respect IIO ABI. + */ + *val = raw_temp * 1000; + *val2 = 16; + return IIO_VAL_FRACTIONAL_LOG2; +} + +static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2) +{ + u32 raw_press; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP580_REG_PRESS_XLSB, data->buf, + sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read pressure\n"); + return ret; + } + + raw_press = get_unaligned_le24(data->buf); + if (raw_press == BMP580_PRESS_SKIPPED) { + dev_err(data->dev, "reading pressure skipped\n"); + return -EIO; + } + /* + * Pressure is returned in Pascals in fractional form down 2^16. + * We reescale /1000 to convert to kilopascal to respect IIO ABI. + */ + *val = raw_press; + *val2 = 64000; /* 2^6 * 1000 */ + return IIO_VAL_FRACTIONAL; +} + +static const int bmp580_odr_table[][2] = { + [BMP580_ODR_240HZ] = {240, 0}, + [BMP580_ODR_218HZ] = {218, 0}, + [BMP580_ODR_199HZ] = {199, 0}, + [BMP580_ODR_179HZ] = {179, 0}, + [BMP580_ODR_160HZ] = {160, 0}, + [BMP580_ODR_149HZ] = {149, 0}, + [BMP580_ODR_140HZ] = {140, 0}, + [BMP580_ODR_129HZ] = {129, 0}, + [BMP580_ODR_120HZ] = {120, 0}, + [BMP580_ODR_110HZ] = {110, 0}, + [BMP580_ODR_100HZ] = {100, 0}, + [BMP580_ODR_89HZ] = {89, 0}, + [BMP580_ODR_80HZ] = {80, 0}, + [BMP580_ODR_70HZ] = {70, 0}, + [BMP580_ODR_60HZ] = {60, 0}, + [BMP580_ODR_50HZ] = {50, 0}, + [BMP580_ODR_45HZ] = {45, 0}, + [BMP580_ODR_40HZ] = {40, 0}, + [BMP580_ODR_35HZ] = {35, 0}, + [BMP580_ODR_30HZ] = {30, 0}, + [BMP580_ODR_25HZ] = {25, 0}, + [BMP580_ODR_20HZ] = {20, 0}, + [BMP580_ODR_15HZ] = {15, 0}, + [BMP580_ODR_10HZ] = {10, 0}, + [BMP580_ODR_5HZ] = {5, 0}, + [BMP580_ODR_4HZ] = {4, 0}, + [BMP580_ODR_3HZ] = {3, 0}, + [BMP580_ODR_2HZ] = {2, 0}, + [BMP580_ODR_1HZ] = {1, 0}, + [BMP580_ODR_0_5HZ] = {0, 500000}, + [BMP580_ODR_0_25HZ] = {0, 250000}, + [BMP580_ODR_0_125HZ] = {0, 125000}, +}; + +static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 }; + +static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct bmp280_data *data = priv; + u16 *dst = val; + int ret, addr; + + pm_runtime_get_sync(data->dev); + mutex_lock(&data->lock); + + /* Set sensor in standby mode */ + ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS, + BMP580_ODR_DEEPSLEEP_DIS | + FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP)); + if (ret) { + dev_err(data->dev, "failed to change sensor to standby mode\n"); + goto exit; + } + /* Wait standby transition time */ + usleep_range(2500, 3000); + + while (bytes >= sizeof(*dst)) { + addr = bmp580_nvmem_addrs[offset / sizeof(*dst)]; + + ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, + FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr)); + if (ret) { + dev_err(data->dev, "error writing nvm address\n"); + goto exit; + } + + ret = bmp580_nvm_operation(data, false); + if (ret) + goto exit; + + ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16, + sizeof(data->le16)); + if (ret) { + dev_err(data->dev, "error reading nvm data regs\n"); + goto exit; + } + + *dst++ = le16_to_cpu(data->le16); + bytes -= sizeof(*dst); + offset += sizeof(*dst); + } +exit: + /* Restore chip config */ + data->chip_info->chip_config(data); + mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return ret; +} + +static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct bmp280_data *data = priv; + u16 *buf = val; + int ret, addr; + + pm_runtime_get_sync(data->dev); + mutex_lock(&data->lock); + + /* Set sensor in standby mode */ + ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS, + BMP580_ODR_DEEPSLEEP_DIS | + FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP)); + if (ret) { + dev_err(data->dev, "failed to change sensor to standby mode\n"); + goto exit; + } + /* Wait standby transition time */ + usleep_range(2500, 3000); + + while (bytes >= sizeof(*buf)) { + addr = bmp580_nvmem_addrs[offset / sizeof(*buf)]; + + ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, BMP580_NVM_PROG_EN | + FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr)); + if (ret) { + dev_err(data->dev, "error writing nvm address\n"); + goto exit; + } + data->le16 = cpu_to_le16(*buf++); + + ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16, + sizeof(data->le16)); + if (ret) { + dev_err(data->dev, "error writing LSB NVM data regs\n"); + goto exit; + } + + ret = bmp580_nvm_operation(data, true); + if (ret) + goto exit; + + /* Disable programming mode bit */ + ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR, + BMP580_NVM_PROG_EN, 0); + if (ret) { + dev_err(data->dev, "error resetting nvm write\n"); + goto exit; + } + + bytes -= sizeof(*buf); + offset += sizeof(*buf); + } +exit: + /* Restore chip config */ + data->chip_info->chip_config(data); + mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + return ret; +} + +static int bmp580_preinit(struct bmp280_data *data) +{ + struct nvmem_config config = { + .dev = data->dev, + .priv = data, + .name = "bmp580_nvmem", + .word_size = sizeof(u16), + .stride = sizeof(u16), + .size = 3 * sizeof(u16), + .reg_read = bmp580_nvmem_read, + .reg_write = bmp580_nvmem_write, + }; + unsigned int reg; + int ret; + + /* Issue soft-reset command */ + ret = bmp580_soft_reset(data); + if (ret) + return ret; + + /* Post powerup sequence */ + ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); + if (ret) + return ret; + + /* Print warn message if we don't know the chip id */ + if (reg != BMP580_CHIP_ID && reg != BMP580_CHIP_ID_ALT) + dev_warn(data->dev, "preinit: unexpected chip_id\n"); + + ret = regmap_read(data->regmap, BMP580_REG_STATUS, ®); + if (ret) + return ret; + + /* Check nvm status */ + if (!(reg & BMP580_STATUS_NVM_RDY_MASK) || (reg & BMP580_STATUS_NVM_ERR_MASK)) { + dev_err(data->dev, "preinit: nvm error on powerup sequence\n"); + return -EIO; + } + + /* Register nvmem device */ + return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); +} + +static int bmp580_chip_config(struct bmp280_data *data) +{ + bool change = false, aux; + unsigned int tmp; + u8 reg_val; + int ret; + + /* Sets sensor in standby mode */ + ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS, + BMP580_ODR_DEEPSLEEP_DIS | + FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP)); + if (ret) { + dev_err(data->dev, "failed to change sensor to standby mode\n"); + return ret; + } + /* From datasheet's table 4: electrical characteristics */ + usleep_range(2500, 3000); + + /* Set default DSP mode settings */ + reg_val = FIELD_PREP(BMP580_DSP_COMP_MASK, BMP580_DSP_PRESS_TEMP_COMP_EN) | + BMP580_DSP_SHDW_IIR_TEMP_EN | BMP580_DSP_SHDW_IIR_PRESS_EN; + + ret = regmap_update_bits(data->regmap, BMP580_REG_DSP_CONFIG, + BMP580_DSP_COMP_MASK | + BMP580_DSP_SHDW_IIR_TEMP_EN | + BMP580_DSP_SHDW_IIR_PRESS_EN, reg_val); + + /* Configure oversampling */ + reg_val = FIELD_PREP(BMP580_OSR_TEMP_MASK, data->oversampling_temp) | + FIELD_PREP(BMP580_OSR_PRESS_MASK, data->oversampling_press) | + BMP580_OSR_PRESS_EN; + + ret = regmap_update_bits_check(data->regmap, BMP580_REG_OSR_CONFIG, + BMP580_OSR_TEMP_MASK | BMP580_OSR_PRESS_MASK | + BMP580_OSR_PRESS_EN, + reg_val, &aux); + if (ret) { + dev_err(data->dev, "failed to write oversampling register\n"); + return ret; + } + change = change || aux; + + /* Configure output data rate */ + ret = regmap_update_bits_check(data->regmap, BMP580_REG_ODR_CONFIG, BMP580_ODR_MASK, + FIELD_PREP(BMP580_ODR_MASK, data->sampling_freq), + &aux); + if (ret) { + dev_err(data->dev, "failed to write ODR configuration register\n"); + return ret; + } + change = change || aux; + + /* Set filter data */ + reg_val = FIELD_PREP(BMP580_DSP_IIR_PRESS_MASK, data->iir_filter_coeff) | + FIELD_PREP(BMP580_DSP_IIR_TEMP_MASK, data->iir_filter_coeff); + + ret = regmap_update_bits_check(data->regmap, BMP580_REG_DSP_IIR, + BMP580_DSP_IIR_PRESS_MASK | + BMP580_DSP_IIR_TEMP_MASK, + reg_val, &aux); + if (ret) { + dev_err(data->dev, "failed to write config register\n"); + return ret; + } + change = change || aux; + + /* Restore sensor to normal operation mode */ + ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK, + FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_NORMAL)); + if (ret) { + dev_err(data->dev, "failed to set normal mode\n"); + return ret; + } + /* From datasheet's table 4: electrical characteristics */ + usleep_range(3000, 3500); + + if (change) { + /* + * Check if ODR and OSR settings are valid or we are + * operating in a degraded mode. + */ + ret = regmap_read(data->regmap, BMP580_REG_EFF_OSR, &tmp); + if (ret) { + dev_err(data->dev, "error reading effective OSR register\n"); + return ret; + } + if (!(tmp & BMP580_EFF_OSR_VALID_ODR)) { + dev_warn(data->dev, "OSR and ODR incompatible settings detected\n"); + /* Set current OSR settings from data on effective OSR */ + data->oversampling_temp = FIELD_GET(BMP580_EFF_OSR_TEMP_MASK, tmp); + data->oversampling_press = FIELD_GET(BMP580_EFF_OSR_PRESS_MASK, tmp); + return -EINVAL; + } + } + + return 0; +} + +static const int bmp580_oversampling_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +const struct bmp280_chip_info bmp580_chip_info = { + .id_reg = BMP580_REG_CHIP_ID, + .chip_id = BMP580_CHIP_ID, + .regmap_config = &bmp580_regmap_config, + .start_up_time = 2000, + .channels = bmp380_channels, + .num_channels = 2, + + .oversampling_temp_avail = bmp580_oversampling_avail, + .num_oversampling_temp_avail = ARRAY_SIZE(bmp580_oversampling_avail), + .oversampling_temp_default = ilog2(1), + + .oversampling_press_avail = bmp580_oversampling_avail, + .num_oversampling_press_avail = ARRAY_SIZE(bmp580_oversampling_avail), + .oversampling_press_default = ilog2(4), + + .sampling_freq_avail = bmp580_odr_table, + .num_sampling_freq_avail = ARRAY_SIZE(bmp580_odr_table) * 2, + .sampling_freq_default = BMP580_ODR_50HZ, + + .iir_filter_coeffs_avail = bmp380_iir_filter_coeffs_avail, + .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp380_iir_filter_coeffs_avail), + .iir_filter_coeff_default = 2, + + .chip_config = bmp580_chip_config, + .read_temp = bmp580_read_temp, + .read_press = bmp580_read_press, + .preinit = bmp580_preinit, +}; +EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280); static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) { @@ -1467,7 +1872,7 @@ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) return (data->t_fine + 8) >> 4; } -static int bmp180_read_temp(struct bmp280_data *data, int *val) +static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2) { s32 adc_temp, comp_temp; int ret; @@ -1555,7 +1960,7 @@ static int bmp180_read_press(struct bmp280_data *data, int ret; /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp180_read_temp(data, NULL); + ret = bmp180_read_temp(data, NULL, NULL); if (ret) return ret; @@ -1579,8 +1984,10 @@ static int bmp180_chip_config(struct bmp280_data *data) static const int bmp180_oversampling_temp_avail[] = { 1 }; static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 }; -static const struct bmp280_chip_info bmp180_chip_info = { +const struct bmp280_chip_info bmp180_chip_info = { .id_reg = BMP280_REG_ID, + .chip_id = BMP180_CHIP_ID, + .regmap_config = &bmp180_regmap_config, .start_up_time = 2000, .channels = bmp280_channels, .num_channels = 2, @@ -1600,6 +2007,7 @@ static const struct bmp280_chip_info bmp180_chip_info = { .read_press = bmp180_read_press, .read_calib = bmp180_read_calib, }; +EXPORT_SYMBOL_NS(bmp180_chip_info, IIO_BMP280); static irqreturn_t bmp085_eoc_irq(int irq, void *d) { @@ -1661,11 +2069,10 @@ static void bmp280_regulators_disable(void *data) int bmp280_common_probe(struct device *dev, struct regmap *regmap, - unsigned int chip, + const struct bmp280_chip_info *chip_info, const char *name, int irq) { - const struct bmp280_chip_info *chip_info; struct iio_dev *indio_dev; struct bmp280_data *data; struct gpio_desc *gpiod; @@ -1684,22 +2091,6 @@ int bmp280_common_probe(struct device *dev, indio_dev->info = &bmp280_info; indio_dev->modes = INDIO_DIRECT_MODE; - switch (chip) { - case BMP180_CHIP_ID: - chip_info = &bmp180_chip_info; - break; - case BMP280_CHIP_ID: - chip_info = &bmp280_chip_info; - break; - case BME280_CHIP_ID: - chip_info = &bme280_chip_info; - break; - case BMP380_CHIP_ID: - chip_info = &bmp380_chip_info; - break; - default: - return -EINVAL; - } data->chip_info = chip_info; /* Apply initial values from chip info structure */ @@ -1751,17 +2142,17 @@ int bmp280_common_probe(struct device *dev, ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id); if (ret < 0) return ret; - if (chip_id != chip) { + if (chip_id != data->chip_info->chip_id) { dev_err(dev, "bad chip id: expected %x got %x\n", - chip, chip_id); + data->chip_info->chip_id, chip_id); return -EINVAL; } - /* BMP3xx requires soft-reset as part of initialization */ - if (chip_id == BMP380_CHIP_ID) { - ret = bmp380_cmd(data, BMP380_CMD_SOFT_RESET); - if (ret < 0) - return ret; + if (data->chip_info->preinit) { + ret = data->chip_info->preinit(data); + if (ret) + return dev_err_probe(data->dev, ret, + "error running preinit tasks\n"); } ret = data->chip_info->chip_config(data); @@ -1776,10 +2167,12 @@ int bmp280_common_probe(struct device *dev, * time once. They will not change. */ - ret = data->chip_info->read_calib(data); - if (ret < 0) - return dev_err_probe(data->dev, ret, - "failed to read calibration coefficients\n"); + if (data->chip_info->read_calib) { + ret = data->chip_info->read_calib(data); + if (ret < 0) + return dev_err_probe(data->dev, ret, + "failed to read calibration coefficients\n"); + } /* * Attempt to grab an optional EOC IRQ - only the BMP085 has this diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 14eab086d24a..567b945e6427 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -8,25 +8,14 @@ static int bmp280_i2c_probe(struct i2c_client *client) { struct regmap *regmap; - const struct regmap_config *regmap_config; + const struct bmp280_chip_info *chip_info; const struct i2c_device_id *id = i2c_client_get_device_id(client); - switch (id->driver_data) { - case BMP180_CHIP_ID: - regmap_config = &bmp180_regmap_config; - break; - case BMP280_CHIP_ID: - case BME280_CHIP_ID: - regmap_config = &bmp280_regmap_config; - break; - case BMP380_CHIP_ID: - regmap_config = &bmp380_regmap_config; - break; - default: - return -EINVAL; - } + chip_info = device_get_match_data(&client->dev); + if (!chip_info) + chip_info = (const struct bmp280_chip_info *) id->driver_data; - regmap = devm_regmap_init_i2c(client, regmap_config); + regmap = devm_regmap_init_i2c(client, chip_info->regmap_config); if (IS_ERR(regmap)) { dev_err(&client->dev, "failed to allocate register map\n"); return PTR_ERR(regmap); @@ -34,27 +23,29 @@ static int bmp280_i2c_probe(struct i2c_client *client) return bmp280_common_probe(&client->dev, regmap, - id->driver_data, + chip_info, id->name, client->irq); } static const struct of_device_id bmp280_of_i2c_match[] = { - { .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID }, - { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, - { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, - { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, - { .compatible = "bosch,bmp380", .data = (void *)BMP380_CHIP_ID }, + { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, + { .compatible = "bosch,bme280", .data = &bme280_chip_info }, + { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, + { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, { }, }; MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp085", BMP180_CHIP_ID }, - {"bmp180", BMP180_CHIP_ID }, - {"bmp280", BMP280_CHIP_ID }, - {"bme280", BME280_CHIP_ID }, - {"bmp380", BMP380_CHIP_ID }, + {"bmp085", (kernel_ulong_t)&bmp180_chip_info }, + {"bmp180", (kernel_ulong_t)&bmp180_chip_info }, + {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, + {"bme280", (kernel_ulong_t)&bme280_chip_info }, + {"bmp380", (kernel_ulong_t)&bmp380_chip_info }, + {"bmp580", (kernel_ulong_t)&bmp580_chip_info }, { }, }; MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index c98c67970265..3ee56720428c 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -115,6 +115,54 @@ static bool bmp380_is_volatile_reg(struct device *dev, unsigned int reg) } } +static bool bmp580_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP580_REG_NVM_DATA_MSB: + case BMP580_REG_NVM_DATA_LSB: + case BMP580_REG_NVM_ADDR: + case BMP580_REG_ODR_CONFIG: + case BMP580_REG_OSR_CONFIG: + case BMP580_REG_INT_SOURCE: + case BMP580_REG_INT_CONFIG: + case BMP580_REG_OOR_THR_MSB: + case BMP580_REG_OOR_THR_LSB: + case BMP580_REG_OOR_CONFIG: + case BMP580_REG_OOR_RANGE: + case BMP580_REG_IF_CONFIG: + case BMP580_REG_FIFO_CONFIG: + case BMP580_REG_FIFO_SEL: + case BMP580_REG_DSP_CONFIG: + case BMP580_REG_DSP_IIR: + case BMP580_REG_CMD: + return true; + default: + return false; + } +} + +static bool bmp580_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP580_REG_NVM_DATA_MSB: + case BMP580_REG_NVM_DATA_LSB: + case BMP580_REG_FIFO_COUNT: + case BMP580_REG_INT_STATUS: + case BMP580_REG_PRESS_XLSB: + case BMP580_REG_PRESS_LSB: + case BMP580_REG_PRESS_MSB: + case BMP580_REG_FIFO_DATA: + case BMP580_REG_TEMP_XLSB: + case BMP580_REG_TEMP_LSB: + case BMP580_REG_TEMP_MSB: + case BMP580_REG_EFF_OSR: + case BMP580_REG_STATUS: + return true; + default: + return false; + } +} + const struct regmap_config bmp280_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -138,3 +186,15 @@ const struct regmap_config bmp380_regmap_config = { .volatile_reg = bmp380_is_volatile_reg, }; EXPORT_SYMBOL_NS(bmp380_regmap_config, IIO_BMP280); + +const struct regmap_config bmp580_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BMP580_REG_CMD, + .cache_type = REGCACHE_RBTREE, + + .writeable_reg = bmp580_is_writeable_reg, + .volatile_reg = bmp580_is_volatile_reg, +}; +EXPORT_SYMBOL_NS(bmp580_regmap_config, IIO_BMP280); diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 011c68e07ebf..1dff9bb7c4e9 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -47,8 +47,8 @@ static struct regmap_bus bmp280_regmap_bus = { static int bmp280_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); + const struct bmp280_chip_info *chip_info; struct regmap *regmap; - const struct regmap_config *regmap_config; int ret; spi->bits_per_word = 8; @@ -58,25 +58,14 @@ static int bmp280_spi_probe(struct spi_device *spi) return ret; } - switch (id->driver_data) { - case BMP180_CHIP_ID: - regmap_config = &bmp180_regmap_config; - break; - case BMP280_CHIP_ID: - case BME280_CHIP_ID: - regmap_config = &bmp280_regmap_config; - break; - case BMP380_CHIP_ID: - regmap_config = &bmp380_regmap_config; - break; - default: - return -EINVAL; - } + chip_info = device_get_match_data(&spi->dev); + if (!chip_info) + chip_info = (const struct bmp280_chip_info *) id->driver_data; regmap = devm_regmap_init(&spi->dev, &bmp280_regmap_bus, &spi->dev, - regmap_config); + chip_info->regmap_config); if (IS_ERR(regmap)) { dev_err(&spi->dev, "failed to allocate register map\n"); return PTR_ERR(regmap); @@ -84,28 +73,30 @@ static int bmp280_spi_probe(struct spi_device *spi) return bmp280_common_probe(&spi->dev, regmap, - id->driver_data, + chip_info, id->name, spi->irq); } static const struct of_device_id bmp280_of_spi_match[] = { - { .compatible = "bosch,bmp085", }, - { .compatible = "bosch,bmp180", }, - { .compatible = "bosch,bmp181", }, - { .compatible = "bosch,bmp280", }, - { .compatible = "bosch,bme280", }, - { .compatible = "bosch,bmp380", }, + { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp181", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, + { .compatible = "bosch,bme280", .data = &bmp280_chip_info }, + { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, + { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, { }, }; MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { - { "bmp180", BMP180_CHIP_ID }, - { "bmp181", BMP180_CHIP_ID }, - { "bmp280", BMP280_CHIP_ID }, - { "bme280", BME280_CHIP_ID }, - { "bmp380", BMP380_CHIP_ID }, + { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, + { "bme280", (kernel_ulong_t)&bmp280_chip_info }, + { "bmp380", (kernel_ulong_t)&bmp380_chip_info }, + { "bmp580", (kernel_ulong_t)&bmp580_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, bmp280_spi_id); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index c791325c7416..5c0563ce7572 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -1,7 +1,114 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include #include +#include #include +#include + + +/* BMP580 specific registers */ +#define BMP580_REG_CMD 0x7E +#define BMP580_REG_EFF_OSR 0x38 +#define BMP580_REG_ODR_CONFIG 0x37 +#define BMP580_REG_OSR_CONFIG 0x36 +#define BMP580_REG_IF_CONFIG 0x13 +#define BMP580_REG_REV_ID 0x02 +#define BMP580_REG_CHIP_ID 0x01 +/* OOR allows to configure a pressure alarm */ +#define BMP580_REG_OOR_CONFIG 0x35 +#define BMP580_REG_OOR_RANGE 0x34 +#define BMP580_REG_OOR_THR_MSB 0x33 +#define BMP580_REG_OOR_THR_LSB 0x32 +/* DSP registers (IIR filters) */ +#define BMP580_REG_DSP_IIR 0x31 +#define BMP580_REG_DSP_CONFIG 0x30 +/* NVM access registers */ +#define BMP580_REG_NVM_DATA_MSB 0x2D +#define BMP580_REG_NVM_DATA_LSB 0x2C +#define BMP580_REG_NVM_ADDR 0x2B +/* Status registers */ +#define BMP580_REG_STATUS 0x28 +#define BMP580_REG_INT_STATUS 0x27 +#define BMP580_REG_CHIP_STATUS 0x11 +/* Data registers */ +#define BMP580_REG_FIFO_DATA 0x29 +#define BMP580_REG_PRESS_MSB 0x22 +#define BMP580_REG_PRESS_LSB 0x21 +#define BMP580_REG_PRESS_XLSB 0x20 +#define BMP580_REG_TEMP_MSB 0x1F +#define BMP580_REG_TEMP_LSB 0x1E +#define BMP580_REG_TEMP_XLSB 0x1D +/* FIFO config registers */ +#define BMP580_REG_FIFO_SEL 0x18 +#define BMP580_REG_FIFO_COUNT 0x17 +#define BMP580_REG_FIFO_CONFIG 0x16 +/* Interruptions config registers */ +#define BMP580_REG_INT_SOURCE 0x15 +#define BMP580_REG_INT_CONFIG 0x14 + +#define BMP580_CMD_NOOP 0x00 +#define BMP580_CMD_EXTMODE_SEQ_0 0x73 +#define BMP580_CMD_EXTMODE_SEQ_1 0xB4 +#define BMP580_CMD_EXTMODE_SEQ_2 0x69 +#define BMP580_CMD_NVM_OP_SEQ_0 0x5D +#define BMP580_CMD_NVM_READ_SEQ_1 0xA5 +#define BMP580_CMD_NVM_WRITE_SEQ_1 0xA0 +#define BMP580_CMD_SOFT_RESET 0xB6 + +#define BMP580_INT_STATUS_POR_MASK BIT(4) + +#define BMP580_STATUS_CORE_RDY_MASK BIT(0) +#define BMP580_STATUS_NVM_RDY_MASK BIT(1) +#define BMP580_STATUS_NVM_ERR_MASK BIT(2) +#define BMP580_STATUS_NVM_CMD_ERR_MASK BIT(3) + +#define BMP580_OSR_PRESS_MASK GENMASK(5, 3) +#define BMP580_OSR_TEMP_MASK GENMASK(2, 0) +#define BMP580_OSR_PRESS_EN BIT(6) +#define BMP580_EFF_OSR_PRESS_MASK GENMASK(5, 3) +#define BMP580_EFF_OSR_TEMP_MASK GENMASK(2, 0) +#define BMP580_EFF_OSR_VALID_ODR BIT(7) + +#define BMP580_ODR_MASK GENMASK(6, 2) +#define BMP580_MODE_MASK GENMASK(1, 0) +#define BMP580_MODE_SLEEP 0 +#define BMP580_MODE_NORMAL 1 +#define BMP580_MODE_FORCED 2 +#define BMP580_MODE_CONTINOUS 3 +#define BMP580_ODR_DEEPSLEEP_DIS BIT(7) + +#define BMP580_DSP_COMP_MASK GENMASK(1, 0) +#define BMP580_DSP_COMP_DIS 0 +#define BMP580_DSP_TEMP_COMP_EN 1 +/* + * In section 7.27 of datasheet, modes 2 and 3 are technically the same. + * Pressure compensation means also enabling temperature compensation + */ +#define BMP580_DSP_PRESS_COMP_EN 2 +#define BMP580_DSP_PRESS_TEMP_COMP_EN 3 +#define BMP580_DSP_IIR_FORCED_FLUSH BIT(2) +#define BMP580_DSP_SHDW_IIR_TEMP_EN BIT(3) +#define BMP580_DSP_FIFO_IIR_TEMP_EN BIT(4) +#define BMP580_DSP_SHDW_IIR_PRESS_EN BIT(5) +#define BMP580_DSP_FIFO_IIR_PRESS_EN BIT(6) +#define BMP580_DSP_OOR_IIR_PRESS_EN BIT(7) + +#define BMP580_DSP_IIR_PRESS_MASK GENMASK(5, 3) +#define BMP580_DSP_IIR_TEMP_MASK GENMASK(2, 0) +#define BMP580_FILTER_OFF 0 +#define BMP580_FILTER_1X 1 +#define BMP580_FILTER_3X 2 +#define BMP580_FILTER_7X 3 +#define BMP580_FILTER_15X 4 +#define BMP580_FILTER_31X 5 +#define BMP580_FILTER_63X 6 +#define BMP580_FILTER_127X 7 + +#define BMP580_NVM_ROW_ADDR_MASK GENMASK(5, 0) +#define BMP580_NVM_PROG_EN BIT(6) + +#define BMP580_TEMP_SKIPPED 0x7f7f7f +#define BMP580_PRESS_SKIPPED 0x7f7f7f /* BMP380 specific registers */ #define BMP380_REG_CMD 0x7E @@ -181,6 +288,8 @@ #define BMP280_REG_ID 0xD0 #define BMP380_CHIP_ID 0x50 +#define BMP580_CHIP_ID 0x50 +#define BMP580_CHIP_ID_ALT 0x51 #define BMP180_CHIP_ID 0x55 #define BMP280_CHIP_ID 0x58 #define BME280_CHIP_ID 0x60 @@ -191,15 +300,177 @@ #define BMP280_PRESS_SKIPPED 0x80000 #define BMP280_HUMIDITY_SKIPPED 0x8000 +/* Core exported structs */ + +static const char *const bmp280_supply_names[] = { + "vddd", "vdda" +}; + +#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names) + +struct bmp180_calib { + s16 AC1; + s16 AC2; + s16 AC3; + u16 AC4; + u16 AC5; + u16 AC6; + s16 B1; + s16 B2; + s16 MB; + s16 MC; + s16 MD; +}; + +/* See datasheet Section 4.2.2. */ +struct bmp280_calib { + u16 T1; + s16 T2; + s16 T3; + u16 P1; + s16 P2; + s16 P3; + s16 P4; + s16 P5; + s16 P6; + s16 P7; + s16 P8; + s16 P9; + u8 H1; + s16 H2; + u8 H3; + s16 H4; + s16 H5; + s8 H6; +}; + +/* See datasheet Section 3.11.1. */ +struct bmp380_calib { + u16 T1; + u16 T2; + s8 T3; + s16 P1; + s16 P2; + s8 P3; + s8 P4; + u16 P5; + u16 P6; + s8 P7; + s8 P8; + s16 P9; + s8 P10; + s8 P11; +}; + +struct bmp280_data { + struct device *dev; + struct mutex lock; + struct regmap *regmap; + struct completion done; + bool use_eoc; + const struct bmp280_chip_info *chip_info; + union { + struct bmp180_calib bmp180; + struct bmp280_calib bmp280; + struct bmp380_calib bmp380; + } calib; + struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES]; + unsigned int start_up_time; /* in microseconds */ + + /* log of base 2 of oversampling rate */ + u8 oversampling_press; + u8 oversampling_temp; + u8 oversampling_humid; + u8 iir_filter_coeff; + + /* + * BMP380 devices introduce sampling frequency configuration. See + * datasheet sections 3.3.3. and 4.3.19 for more details. + * + * BMx280 devices allowed indirect configuration of sampling frequency + * changing the t_standby duration between measurements, as detailed on + * section 3.6.3 of the datasheet. + */ + int sampling_freq; + + /* + * Carryover value from temperature conversion, used in pressure + * calculation. + */ + s32 t_fine; + + /* + * DMA (thus cache coherency maintenance) may require the + * transfer buffers to live in their own cache lines. + */ + union { + /* Sensor data buffer */ + u8 buf[3]; + /* Calibration data buffers */ + __le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2]; + __be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2]; + u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT]; + /* Miscellaneous, endianess-aware data buffers */ + __le16 le16; + __be16 be16; + } __aligned(IIO_DMA_MINALIGN); +}; + +struct bmp280_chip_info { + unsigned int id_reg; + const unsigned int chip_id; + + const struct regmap_config *regmap_config; + + const struct iio_chan_spec *channels; + int num_channels; + unsigned int start_up_time; + + const int *oversampling_temp_avail; + int num_oversampling_temp_avail; + int oversampling_temp_default; + + const int *oversampling_press_avail; + int num_oversampling_press_avail; + int oversampling_press_default; + + const int *oversampling_humid_avail; + int num_oversampling_humid_avail; + int oversampling_humid_default; + + const int *iir_filter_coeffs_avail; + int num_iir_filter_coeffs_avail; + int iir_filter_coeff_default; + + const int (*sampling_freq_avail)[2]; + int num_sampling_freq_avail; + int sampling_freq_default; + + int (*chip_config)(struct bmp280_data *); + int (*read_temp)(struct bmp280_data *, int *, int *); + int (*read_press)(struct bmp280_data *, int *, int *); + int (*read_humid)(struct bmp280_data *, int *, int *); + int (*read_calib)(struct bmp280_data *); + int (*preinit)(struct bmp280_data *); +}; + +/* Chip infos for each variant */ +extern const struct bmp280_chip_info bmp180_chip_info; +extern const struct bmp280_chip_info bmp280_chip_info; +extern const struct bmp280_chip_info bme280_chip_info; +extern const struct bmp280_chip_info bmp380_chip_info; +extern const struct bmp280_chip_info bmp580_chip_info; + /* Regmap configurations */ extern const struct regmap_config bmp180_regmap_config; extern const struct regmap_config bmp280_regmap_config; extern const struct regmap_config bmp380_regmap_config; +extern const struct regmap_config bmp580_regmap_config; /* Probe called from different transports */ int bmp280_common_probe(struct device *dev, struct regmap *regmap, - unsigned int chip, + const struct bmp280_chip_info *, const char *name, int irq); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 67119a9b95fc..421e059d1f19 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -829,7 +829,7 @@ static irqreturn_t zpa2326_handle_threaded_irq(int irq, void *data) } /* New sample available: dispatch internal trigger consumers. */ - iio_trigger_poll_chained(priv->trigger); + iio_trigger_poll_nested(priv->trigger); if (cont) /* diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index ebc95cf8f5f4..96fa97451cbf 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -257,7 +257,7 @@ static void as3935_event_work(struct work_struct *work) switch (val) { case AS3935_EVENT_INT: - iio_trigger_poll_chained(st->trig); + iio_trigger_poll_nested(st->trig); break; case AS3935_DISTURB_INT: case AS3935_NOISE_INT: diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 977cf17cec52..9a40ca32bb1c 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -783,73 +783,75 @@ static int sx9324_write_raw(struct iio_dev *indio_dev, static const struct sx_common_reg_default sx9324_default_regs[] = { { SX9324_REG_IRQ_MSK, 0x00 }, - { SX9324_REG_IRQ_CFG0, 0x00 }, - { SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND }, - { SX9324_REG_IRQ_CFG2, 0x00 }, - { SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS }, + { SX9324_REG_IRQ_CFG0, 0x00, "irq_cfg0" }, + { SX9324_REG_IRQ_CFG1, SX9324_REG_IRQ_CFG1_FAILCOND, "irq_cfg1" }, + { SX9324_REG_IRQ_CFG2, 0x00, "irq_cfg2" }, + { SX9324_REG_GNRL_CTRL0, SX9324_REG_GNRL_CTRL0_SCANPERIOD_100MS, "gnrl_ctrl0" }, /* * The lower 4 bits should not be set as it enable sensors measurements. * Turning the detection on before the configuration values are set to * good values can cause the device to return erroneous readings. */ - { SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL }, + { SX9324_REG_GNRL_CTRL1, SX9324_REG_GNRL_CTRL1_PAUSECTRL, "gnrl_ctrl1" }, - { SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL0_RINT_LOWEST }, - { SX9324_REG_AFE_CTRL3, 0x00 }, + { SX9324_REG_AFE_CTRL0, SX9324_REG_AFE_CTRL0_RINT_LOWEST, "afe_ctrl0" }, + { SX9324_REG_AFE_CTRL3, 0x00, "afe_ctrl3" }, { SX9324_REG_AFE_CTRL4, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | - SX9324_REG_AFE_CTRL4_RES_100 }, - { SX9324_REG_AFE_CTRL6, 0x00 }, + SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl4" }, + { SX9324_REG_AFE_CTRL6, 0x00, "afe_ctrl6" }, { SX9324_REG_AFE_CTRL7, SX9324_REG_AFE_CTRL4_FREQ_83_33HZ | - SX9324_REG_AFE_CTRL4_RES_100 }, + SX9324_REG_AFE_CTRL4_RES_100, "afe_ctrl7" }, /* TODO(gwendal): PHx use chip default or all grounded? */ - { SX9324_REG_AFE_PH0, 0x29 }, - { SX9324_REG_AFE_PH1, 0x26 }, - { SX9324_REG_AFE_PH2, 0x1a }, - { SX9324_REG_AFE_PH3, 0x16 }, + { SX9324_REG_AFE_PH0, 0x29, "afe_ph0" }, + { SX9324_REG_AFE_PH1, 0x26, "afe_ph1" }, + { SX9324_REG_AFE_PH2, 0x1a, "afe_ph2" }, + { SX9324_REG_AFE_PH3, 0x16, "afe_ph3" }, { SX9324_REG_AFE_CTRL8, SX9324_REG_AFE_CTRL8_RESERVED | - SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM }, - { SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1 }, + SX9324_REG_AFE_CTRL8_RESFILTIN_4KOHM, "afe_ctrl8" }, + { SX9324_REG_AFE_CTRL9, SX9324_REG_AFE_CTRL9_AGAIN_1, "afe_ctrl9" }, { SX9324_REG_PROX_CTRL0, SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT | - SX9324_REG_PROX_CTRL0_RAWFILT_1P50 }, + SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0" }, { SX9324_REG_PROX_CTRL1, SX9324_REG_PROX_CTRL0_GAIN_1 << SX9324_REG_PROX_CTRL0_GAIN_SHIFT | - SX9324_REG_PROX_CTRL0_RAWFILT_1P50 }, - { SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K }, + SX9324_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl1" }, + { SX9324_REG_PROX_CTRL2, SX9324_REG_PROX_CTRL2_AVGNEG_THRESH_16K, "prox_ctrl2" }, { SX9324_REG_PROX_CTRL3, SX9324_REG_PROX_CTRL3_AVGDEB_2SAMPLES | - SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K }, + SX9324_REG_PROX_CTRL3_AVGPOS_THRESH_16K, "prox_ctrl3" }, { SX9324_REG_PROX_CTRL4, SX9324_REG_PROX_CTRL4_AVGNEG_FILT_2 | - SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256 }, - { SX9324_REG_PROX_CTRL5, 0x00 }, - { SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 }, - { SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32 }, - { SX9324_REG_ADV_CTRL0, 0x00 }, - { SX9324_REG_ADV_CTRL1, 0x00 }, - { SX9324_REG_ADV_CTRL2, 0x00 }, - { SX9324_REG_ADV_CTRL3, 0x00 }, - { SX9324_REG_ADV_CTRL4, 0x00 }, + SX9324_REG_PROX_CTRL4_AVGPOS_FILT_256, "prox_ctrl4" }, + { SX9324_REG_PROX_CTRL5, 0x00, "prox_ctrl5" }, + { SX9324_REG_PROX_CTRL6, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl6" }, + { SX9324_REG_PROX_CTRL7, SX9324_REG_PROX_CTRL6_PROXTHRESH_32, "prox_ctrl7" }, + { SX9324_REG_ADV_CTRL0, 0x00, "adv_ctrl0" }, + { SX9324_REG_ADV_CTRL1, 0x00, "adv_ctrl1" }, + { SX9324_REG_ADV_CTRL2, 0x00, "adv_ctrl2" }, + { SX9324_REG_ADV_CTRL3, 0x00, "adv_ctrl3" }, + { SX9324_REG_ADV_CTRL4, 0x00, "adv_ctrl4" }, { SX9324_REG_ADV_CTRL5, SX9324_REG_ADV_CTRL5_STARTUP_SENSOR_1 | - SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1 }, - { SX9324_REG_ADV_CTRL6, 0x00 }, - { SX9324_REG_ADV_CTRL7, 0x00 }, - { SX9324_REG_ADV_CTRL8, 0x00 }, - { SX9324_REG_ADV_CTRL9, 0x00 }, + SX9324_REG_ADV_CTRL5_STARTUP_METHOD_1, "adv_ctrl5" }, + { SX9324_REG_ADV_CTRL6, 0x00, "adv_ctrl6" }, + { SX9324_REG_ADV_CTRL7, 0x00, "adv_ctrl7" }, + { SX9324_REG_ADV_CTRL8, 0x00, "adv_ctrl8" }, + { SX9324_REG_ADV_CTRL9, 0x00, "adv_ctrl9" }, /* Body/Table threshold */ - { SX9324_REG_ADV_CTRL10, 0x00 }, - { SX9324_REG_ADV_CTRL11, 0x00 }, - { SX9324_REG_ADV_CTRL12, 0x00 }, + { SX9324_REG_ADV_CTRL10, 0x00, "adv_ctrl10" }, + { SX9324_REG_ADV_CTRL11, 0x00, "adv_ctrl11" }, + { SX9324_REG_ADV_CTRL12, 0x00, "adv_ctrl12" }, /* TODO(gwendal): SAR currenly disabled */ - { SX9324_REG_ADV_CTRL13, 0x00 }, - { SX9324_REG_ADV_CTRL14, 0x00 }, - { SX9324_REG_ADV_CTRL15, 0x00 }, - { SX9324_REG_ADV_CTRL16, 0x00 }, - { SX9324_REG_ADV_CTRL17, 0x00 }, - { SX9324_REG_ADV_CTRL18, 0x00 }, - { SX9324_REG_ADV_CTRL19, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION }, - { SX9324_REG_ADV_CTRL20, SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION }, + { SX9324_REG_ADV_CTRL13, 0x00, "adv_ctrl13" }, + { SX9324_REG_ADV_CTRL14, 0x00, "adv_ctrl14" }, + { SX9324_REG_ADV_CTRL15, 0x00, "adv_ctrl15" }, + { SX9324_REG_ADV_CTRL16, 0x00, "adv_ctrl16" }, + { SX9324_REG_ADV_CTRL17, 0x00, "adv_ctrl17" }, + { SX9324_REG_ADV_CTRL18, 0x00, "adv_ctrl18" }, + { SX9324_REG_ADV_CTRL19, + SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl19" }, + { SX9324_REG_ADV_CTRL20, + SX9324_REG_ADV_CTRL19_HIGHT_FAILURE_THRESH_SATURATION, "adv_ctrl20" }, }; /* Activate all channels and perform an initial compensation. */ @@ -889,13 +891,15 @@ sx9324_get_default_reg(struct device *dev, int idx, const char *res; memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def)); + + sx_common_get_raw_register_config(dev, reg_def); switch (reg_def->reg) { case SX9324_REG_AFE_PH0: case SX9324_REG_AFE_PH1: case SX9324_REG_AFE_PH2: case SX9324_REG_AFE_PH3: ph = reg_def->reg - SX9324_REG_AFE_PH0; - scnprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); + snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph); count = device_property_count_u32(dev, prop); if (count != ARRAY_SIZE(pin_defs)) diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 6e19d22e6a01..a50d9176411a 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -663,37 +663,37 @@ static int sx9360_write_raw(struct iio_dev *indio_dev, static const struct sx_common_reg_default sx9360_default_regs[] = { { SX9360_REG_IRQ_MSK, 0x00 }, - { SX9360_REG_IRQ_CFG, 0x00 }, + { SX9360_REG_IRQ_CFG, 0x00, "irq_cfg" }, /* * The lower 2 bits should not be set as it enable sensors measurements. * Turning the detection on before the configuration values are set to * good values can cause the device to return erroneous readings. */ - { SX9360_REG_GNRL_CTRL0, 0x00 }, - { SX9360_REG_GNRL_CTRL1, 0x00 }, - { SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS }, + { SX9360_REG_GNRL_CTRL0, 0x00, "gnrl_ctrl0" }, + { SX9360_REG_GNRL_CTRL1, 0x00, "gnrl_ctrl1" }, + { SX9360_REG_GNRL_CTRL2, SX9360_REG_GNRL_CTRL2_PERIOD_102MS, "gnrl_ctrl2" }, - { SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS }, + { SX9360_REG_AFE_CTRL1, SX9360_REG_AFE_CTRL1_RESFILTIN_0OHMS, "afe_ctrl0" }, { SX9360_REG_AFE_PARAM0_PHR, SX9360_REG_AFE_PARAM0_RSVD | - SX9360_REG_AFE_PARAM0_RESOLUTION_128 }, + SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phr" }, { SX9360_REG_AFE_PARAM1_PHR, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF | - SX9360_REG_AFE_PARAM1_FREQ_83_33HZ }, + SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phr" }, { SX9360_REG_AFE_PARAM0_PHM, SX9360_REG_AFE_PARAM0_RSVD | - SX9360_REG_AFE_PARAM0_RESOLUTION_128 }, + SX9360_REG_AFE_PARAM0_RESOLUTION_128, "afe_param0_phm" }, { SX9360_REG_AFE_PARAM1_PHM, SX9360_REG_AFE_PARAM1_AGAIN_PHM_6PF | - SX9360_REG_AFE_PARAM1_FREQ_83_33HZ }, + SX9360_REG_AFE_PARAM1_FREQ_83_33HZ, "afe_param1_phm" }, { SX9360_REG_PROX_CTRL0_PHR, SX9360_REG_PROX_CTRL0_GAIN_1 | - SX9360_REG_PROX_CTRL0_RAWFILT_1P50 }, + SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phr" }, { SX9360_REG_PROX_CTRL0_PHM, SX9360_REG_PROX_CTRL0_GAIN_1 | - SX9360_REG_PROX_CTRL0_RAWFILT_1P50 }, - { SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K }, + SX9360_REG_PROX_CTRL0_RAWFILT_1P50, "prox_ctrl0_phm" }, + { SX9360_REG_PROX_CTRL1, SX9360_REG_PROX_CTRL1_AVGNEG_THRESH_16K, "prox_ctrl1" }, { SX9360_REG_PROX_CTRL2, SX9360_REG_PROX_CTRL2_AVGDEB_2SAMPLES | - SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K }, + SX9360_REG_PROX_CTRL2_AVGPOS_THRESH_16K, "prox_ctrl2" }, { SX9360_REG_PROX_CTRL3, SX9360_REG_PROX_CTRL3_AVGNEG_FILT_2 | - SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256 }, - { SX9360_REG_PROX_CTRL4, 0x00 }, - { SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32 }, + SX9360_REG_PROX_CTRL3_AVGPOS_FILT_256, "prox_ctrl3" }, + { SX9360_REG_PROX_CTRL4, 0x00, "prox_ctrl4" }, + { SX9360_REG_PROX_CTRL5, SX9360_REG_PROX_CTRL5_PROXTHRESH_32, "prox_ctrl5" }, }; /* Activate all channels and perform an initial compensation. */ diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 8794e75e5bf9..9b2cfcade6a4 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1051,8 +1051,8 @@ MODULE_DEVICE_TABLE(i2c, sx9500_id); static struct i2c_driver sx9500_driver = { .driver = { .name = SX9500_DRIVER_NAME, - .acpi_match_table = ACPI_PTR(sx9500_acpi_match), - .of_match_table = of_match_ptr(sx9500_of_match), + .acpi_match_table = sx9500_acpi_match, + .of_match_table = sx9500_of_match, .pm = pm_sleep_ptr(&sx9500_pm_ops), }, .probe_new = sx9500_probe, diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index eba9256730ec..fe07d1444ac3 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -424,6 +424,27 @@ static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = { .postdisable = sx_common_buffer_postdisable, }; +void sx_common_get_raw_register_config(struct device *dev, + struct sx_common_reg_default *reg_def) +{ +#ifdef CONFIG_ACPI + struct acpi_device *adev = ACPI_COMPANION(dev); + u32 raw = 0, ret; + char prop[80]; + + if (!reg_def->property || !adev) + return; + + snprintf(prop, ARRAY_SIZE(prop), "%s,reg_%s", acpi_device_hid(adev), reg_def->property); + ret = device_property_read_u32(dev, prop, &raw); + if (ret) + return; + + reg_def->def = raw; +#endif +} +EXPORT_SYMBOL_NS_GPL(sx_common_get_raw_register_config, SEMTECH_PROX); + #define SX_COMMON_SOFT_RESET 0xde static int sx_common_init_device(struct device *dev, struct iio_dev *indio_dev) diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h index 49d4517103b0..101b90e52ff2 100644 --- a/drivers/iio/proximity/sx_common.h +++ b/drivers/iio/proximity/sx_common.h @@ -8,6 +8,7 @@ #ifndef IIO_SX_COMMON_H #define IIO_SX_COMMON_H +#include #include #include #include @@ -26,6 +27,7 @@ static_assert(SX_COMMON_MAX_NUM_CHANNELS < BITS_PER_LONG); struct sx_common_reg_default { u8 reg; u8 def; + const char *property; }; /** @@ -101,7 +103,6 @@ struct sx_common_chip_info { * @client: I2C client structure. * @trig: IIO trigger object. * @regmap: Register map. - * @num_default_regs: Number of default registers to set at init. * @chan_prox_stat: Last reading of the proximity status for each channel. * We only send an event to user space when this changes. * @trigger_enabled: True when the device trigger is enabled. @@ -149,6 +150,9 @@ int sx_common_probe(struct i2c_client *client, const struct sx_common_chip_info *chip_info, const struct regmap_config *regmap_config); +void sx_common_get_raw_register_config(struct device *dev, + struct sx_common_reg_default *reg_def); + /* 3 is the number of events defined by a single phase. */ extern const struct iio_event_spec sx_common_events[3]; diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index f9b8f2b570f6..638e3a5bd6b8 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -31,17 +32,19 @@ #define TMP117_REG_DEVICE_ID 0xF #define TMP117_RESOLUTION_10UC 78125 -#define TMP117_DEVICE_ID 0x0117 #define MICRODEGREE_PER_10MILLIDEGREE 10000 +#define TMP116_DEVICE_ID 0x1116 +#define TMP117_DEVICE_ID 0x0117 + struct tmp117_data { struct i2c_client *client; s16 calibbias; }; static int tmp117_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *channel, int *val, - int *val2, long mask) + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) { struct tmp117_data *data = iio_priv(indio_dev); s32 ret; @@ -49,7 +52,7 @@ static int tmp117_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: ret = i2c_smbus_read_word_swapped(data->client, - TMP117_REG_TEMP); + TMP117_REG_TEMP); if (ret < 0) return ret; *val = sign_extend32(ret, 15); @@ -57,7 +60,7 @@ static int tmp117_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBBIAS: ret = i2c_smbus_read_word_swapped(data->client, - TMP117_REG_TEMP_OFFSET); + TMP117_REG_TEMP_OFFSET); if (ret < 0) return ret; *val = sign_extend32(ret, 15); @@ -79,9 +82,8 @@ static int tmp117_read_raw(struct iio_dev *indio_dev, } } -static int tmp117_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *channel, int val, - int val2, long mask) +static int tmp117_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec + const *channel, int val, int val2, long mask) { struct tmp117_data *data = iio_priv(indio_dev); s16 off; @@ -104,7 +106,16 @@ static const struct iio_chan_spec tmp117_channels[] = { { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct iio_chan_spec tmp116_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), }, }; @@ -115,23 +126,41 @@ static const struct iio_info tmp117_info = { static int tmp117_identify(struct i2c_client *client) { + const struct i2c_device_id *id; + unsigned long match_data; int dev_id; dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); if (dev_id < 0) return dev_id; - if (dev_id != TMP117_DEVICE_ID) { - dev_err(&client->dev, "TMP117 not found\n"); - return -ENODEV; + + switch (dev_id) { + case TMP116_DEVICE_ID: + case TMP117_DEVICE_ID: + return dev_id; } - return 0; + + dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n", + dev_id); + + match_data = (uintptr_t)device_get_match_data(&client->dev); + if (match_data) + return match_data; + + id = i2c_client_get_device_id(client); + if (id) + return id->driver_data; + + dev_err(&client->dev, "Failed to identify unsupported device\n"); + + return -ENODEV; } static int tmp117_probe(struct i2c_client *client) { struct tmp117_data *data; struct iio_dev *indio_dev; - int ret; + int ret, dev_id; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; @@ -140,6 +169,8 @@ static int tmp117_probe(struct i2c_client *client) if (ret < 0) return ret; + dev_id = ret; + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; @@ -148,24 +179,35 @@ static int tmp117_probe(struct i2c_client *client) data->client = client; data->calibbias = 0; - indio_dev->name = "tmp117"; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &tmp117_info; - indio_dev->channels = tmp117_channels; - indio_dev->num_channels = ARRAY_SIZE(tmp117_channels); + switch (dev_id) { + case TMP116_DEVICE_ID: + indio_dev->channels = tmp116_channels; + indio_dev->num_channels = ARRAY_SIZE(tmp116_channels); + indio_dev->name = "tmp116"; + break; + case TMP117_DEVICE_ID: + indio_dev->channels = tmp117_channels; + indio_dev->num_channels = ARRAY_SIZE(tmp117_channels); + indio_dev->name = "tmp117"; + break; + } return devm_iio_device_register(&client->dev, indio_dev); } static const struct of_device_id tmp117_of_match[] = { - { .compatible = "ti,tmp117", }, + { .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID }, + { .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID }, { } }; MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { - { "tmp117", 0 }, + { "tmp116", TMP116_DEVICE_ID }, + { "tmp117", TMP117_DEVICE_ID }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c index 96ec06bbe546..7aaed0611899 100644 --- a/drivers/iio/trigger/iio-trig-loop.c +++ b/drivers/iio/trigger/iio-trig-loop.c @@ -46,7 +46,7 @@ static int iio_loop_thread(void *data) set_freezable(); do { - iio_trigger_poll_chained(trig); + iio_trigger_poll_nested(trig); } while (likely(!kthread_freezable_should_stop(NULL))); return 0; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 603c0aecc361..ff58058aeadc 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -2912,6 +2912,8 @@ static int cm_send_rej_locked(struct cm_id_private *cm_id_priv, (ari && ari_length > IB_CM_REJ_ARI_LENGTH)) return -EINVAL; + trace_icm_send_rej(&cm_id_priv->id, reason); + switch (state) { case IB_CM_REQ_SENT: case IB_CM_MRA_REQ_RCVD: @@ -2942,7 +2944,6 @@ static int cm_send_rej_locked(struct cm_id_private *cm_id_priv, return -EINVAL; } - trace_icm_send_rej(&cm_id_priv->id, reason); ret = ib_post_send_mad(msg, NULL); if (ret) { cm_free_msg(msg); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 6b9563d4f23c..93a1c48d0c32 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -709,8 +709,7 @@ cma_validate_port(struct ib_device *device, u32 port, } sgid_attr = rdma_find_gid_by_port(device, gid, gid_type, port, ndev); - if (ndev) - dev_put(ndev); + dev_put(ndev); return sgid_attr; } @@ -2429,8 +2428,7 @@ err_unlock: mutex_unlock(&listen_id->handler_mutex); net_dev_put: - if (net_dev) - dev_put(net_dev); + dev_put(net_dev); return ret; } diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index f83954180a33..7e5c33aad161 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -131,6 +131,11 @@ struct ib_umad_packet { struct ib_user_mad mad; }; +struct ib_rmpp_mad_hdr { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; +} __packed; + #define CREATE_TRACE_POINTS #include @@ -494,11 +499,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct ib_umad_file *file = filp->private_data; + struct ib_rmpp_mad_hdr *rmpp_mad_hdr; struct ib_umad_packet *packet; struct ib_mad_agent *agent; struct rdma_ah_attr ah_attr; struct ib_ah *ah; - struct ib_rmpp_mad *rmpp_mad; __be64 *tid; int ret, data_len, hdr_len, copy_offset, rmpp_active; u8 base_version; @@ -506,7 +511,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, if (count < hdr_size(file) + IB_MGMT_RMPP_HDR) return -EINVAL; - packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); + packet = kzalloc(sizeof(*packet) + IB_MGMT_RMPP_HDR, GFP_KERNEL); if (!packet) return -ENOMEM; @@ -560,13 +565,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err_up; } - rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; - hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); + rmpp_mad_hdr = (struct ib_rmpp_mad_hdr *)packet->mad.data; + hdr_len = ib_get_mad_data_offset(rmpp_mad_hdr->mad_hdr.mgmt_class); - if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class) + if (ib_is_mad_class_rmpp(rmpp_mad_hdr->mad_hdr.mgmt_class) && ib_mad_kernel_rmpp_agent(agent)) { copy_offset = IB_MGMT_RMPP_HDR; - rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + rmpp_active = ib_get_rmpp_flags(&rmpp_mad_hdr->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE; } else { copy_offset = IB_MGMT_MAD_HDR; @@ -615,12 +620,12 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | (be64_to_cpup(tid) & 0xffffffff)); - rmpp_mad->mad_hdr.tid = *tid; + rmpp_mad_hdr->mad_hdr.tid = *tid; } if (!ib_mad_kernel_rmpp_agent(agent) - && ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class) - && (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) { + && ib_is_mad_class_rmpp(rmpp_mad_hdr->mad_hdr.mgmt_class) + && (ib_get_rmpp_flags(&rmpp_mad_hdr->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) { spin_lock_irq(&file->send_lock); list_add_tail(&packet->list, &file->send_list); spin_unlock_irq(&file->send_lock); @@ -1229,8 +1234,8 @@ static char *umad_devnode(const struct device *dev, umode_t *mode) return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev)); } -static ssize_t abi_version_show(struct class *class, - struct class_attribute *attr, char *buf) +static ssize_t abi_version_show(const struct class *class, + const struct class_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", IB_USER_MAD_ABI_VERSION); } diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index bdb179a09d77..fbace69672ca 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -1264,7 +1264,7 @@ static int __init ib_uverbs_init(void) goto out_alloc; } - uverbs_class = class_create(THIS_MODULE, "infiniband_verbs"); + uverbs_class = class_create("infiniband_verbs"); if (IS_ERR(uverbs_class)) { ret = PTR_ERR(uverbs_class); pr_err("user_verbs: couldn't create class infiniband_verbs\n"); diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 989edc789633..b1c36412025f 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2912,6 +2912,106 @@ fail: return rc; } +static void bnxt_re_resize_cq_complete(struct bnxt_re_cq *cq) +{ + struct bnxt_re_dev *rdev = cq->rdev; + + bnxt_qplib_resize_cq_complete(&rdev->qplib_res, &cq->qplib_cq); + + cq->qplib_cq.max_wqe = cq->resize_cqe; + if (cq->resize_umem) { + ib_umem_release(cq->umem); + cq->umem = cq->resize_umem; + cq->resize_umem = NULL; + cq->resize_cqe = 0; + } +} + +int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) +{ + struct bnxt_qplib_sg_info sg_info = {}; + struct bnxt_qplib_dpi *orig_dpi = NULL; + struct bnxt_qplib_dev_attr *dev_attr; + struct bnxt_re_ucontext *uctx = NULL; + struct bnxt_re_resize_cq_req req; + struct bnxt_re_dev *rdev; + struct bnxt_re_cq *cq; + int rc, entries; + + cq = container_of(ibcq, struct bnxt_re_cq, ib_cq); + rdev = cq->rdev; + dev_attr = &rdev->dev_attr; + if (!ibcq->uobject) { + ibdev_err(&rdev->ibdev, "Kernel CQ Resize not supported"); + return -EOPNOTSUPP; + } + + if (cq->resize_umem) { + ibdev_err(&rdev->ibdev, "Resize CQ %#x failed - Busy", + cq->qplib_cq.id); + return -EBUSY; + } + + /* Check the requested cq depth out of supported depth */ + if (cqe < 1 || cqe > dev_attr->max_cq_wqes) { + ibdev_err(&rdev->ibdev, "Resize CQ %#x failed - out of range cqe %d", + cq->qplib_cq.id, cqe); + return -EINVAL; + } + + entries = roundup_pow_of_two(cqe + 1); + if (entries > dev_attr->max_cq_wqes + 1) + entries = dev_attr->max_cq_wqes + 1; + + uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, + ib_uctx); + /* uverbs consumer */ + if (ib_copy_from_udata(&req, udata, sizeof(req))) { + rc = -EFAULT; + goto fail; + } + + cq->resize_umem = ib_umem_get(&rdev->ibdev, req.cq_va, + entries * sizeof(struct cq_base), + IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(cq->resize_umem)) { + rc = PTR_ERR(cq->resize_umem); + cq->resize_umem = NULL; + ibdev_err(&rdev->ibdev, "%s: ib_umem_get failed! rc = %d\n", + __func__, rc); + goto fail; + } + cq->resize_cqe = entries; + memcpy(&sg_info, &cq->qplib_cq.sg_info, sizeof(sg_info)); + orig_dpi = cq->qplib_cq.dpi; + + cq->qplib_cq.sg_info.umem = cq->resize_umem; + cq->qplib_cq.sg_info.pgsize = PAGE_SIZE; + cq->qplib_cq.sg_info.pgshft = PAGE_SHIFT; + cq->qplib_cq.dpi = &uctx->dpi; + + rc = bnxt_qplib_resize_cq(&rdev->qplib_res, &cq->qplib_cq, entries); + if (rc) { + ibdev_err(&rdev->ibdev, "Resize HW CQ %#x failed!", + cq->qplib_cq.id); + goto fail; + } + + cq->ib_cq.cqe = cq->resize_cqe; + + return 0; + +fail: + if (cq->resize_umem) { + ib_umem_release(cq->resize_umem); + cq->resize_umem = NULL; + cq->resize_cqe = 0; + memcpy(&cq->qplib_cq.sg_info, &sg_info, sizeof(sg_info)); + cq->qplib_cq.dpi = orig_dpi; + } + return rc; +} + static u8 __req_to_ib_wc_status(u8 qstatus) { switch (qstatus) { @@ -3241,9 +3341,7 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *gsi_qp, udwr.remote_qkey = gsi_sqp->qplib_qp.qkey; /* post data received in the send queue */ - rc = bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr); - - return 0; + return bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr); } static void bnxt_re_process_res_rawqp1_wc(struct ib_wc *wc, @@ -3425,6 +3523,15 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) struct bnxt_re_sqp_entries *sqp_entry = NULL; unsigned long flags; + /* User CQ; the only processing we do is to + * complete any pending CQ resize operation. + */ + if (cq->umem) { + if (cq->resize_umem) + bnxt_re_resize_cq_complete(cq); + return 0; + } + spin_lock_irqsave(&cq->cq_lock, flags); budget = min_t(u32, num_entries, cq->max_cql); num_entries = budget; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index 94326267f9bb..31f7e34040f7 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -104,6 +104,8 @@ struct bnxt_re_cq { #define MAX_CQL_PER_POLL 1024 u32 max_cql; struct ib_umem *umem; + struct ib_umem *resize_umem; + int resize_cqe; }; struct bnxt_re_mr { @@ -191,6 +193,7 @@ int bnxt_re_post_recv(struct ib_qp *qp, const struct ib_recv_wr *recv_wr, const struct ib_recv_wr **bad_recv_wr); int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, struct ib_udata *udata); +int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata); int bnxt_re_destroy_cq(struct ib_cq *cq, struct ib_udata *udata); int bnxt_re_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc); int bnxt_re_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index c5867e78f231..e34eccd178d0 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -553,6 +553,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = { .query_srq = bnxt_re_query_srq, .reg_user_mr = bnxt_re_reg_user_mr, .req_notify_cq = bnxt_re_req_notify_cq, + .resize_cq = bnxt_re_resize_cq, INIT_RDMA_OBJ_SIZE(ib_ah, bnxt_re_ah, ib_ah), INIT_RDMA_OBJ_SIZE(ib_cq, bnxt_re_cq, ib_cq), INIT_RDMA_OBJ_SIZE(ib_pd, bnxt_re_pd, ib_pd), @@ -584,6 +585,7 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) return ret; dma_set_max_seg_size(&rdev->en_dev->pdev->dev, UINT_MAX); + ibdev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POLL_CQ); return ib_register_device(ibdev, "bnxt_re%d", &rdev->en_dev->pdev->dev); } @@ -919,49 +921,6 @@ static void bnxt_re_dispatch_event(struct ib_device *ibdev, struct ib_qp *qp, } } -#define HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN 0x02 -static int bnxt_re_query_hwrm_pri2cos(struct bnxt_re_dev *rdev, u8 dir, - u64 *cid_map) -{ - struct hwrm_queue_pri2cos_qcfg_input req = {0}; - struct hwrm_queue_pri2cos_qcfg_output resp; - struct bnxt_en_dev *en_dev = rdev->en_dev; - struct bnxt_fw_msg fw_msg; - u32 flags = 0; - u8 *qcfgmap, *tmp_map; - int rc = 0, i; - - if (!cid_map) - return -EINVAL; - - memset(&fw_msg, 0, sizeof(fw_msg)); - bnxt_re_init_hwrm_hdr(rdev, (void *)&req, - HWRM_QUEUE_PRI2COS_QCFG, -1, -1); - flags |= (dir & 0x01); - flags |= HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN; - req.flags = cpu_to_le32(flags); - req.port_id = en_dev->pf_port_id; - - bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, - sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); - rc = bnxt_send_msg(en_dev, &fw_msg); - if (rc) - return rc; - - if (resp.queue_cfg_info) { - ibdev_warn(&rdev->ibdev, - "Asymmetric cos queue configuration detected"); - ibdev_warn(&rdev->ibdev, - " on device, QoS may not be fully functional\n"); - } - qcfgmap = &resp.pri0_cos_queue_id; - tmp_map = (u8 *)cid_map; - for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) - tmp_map[i] = qcfgmap[i]; - - return rc; -} - static bool bnxt_re_is_qp1_or_shadow_qp(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) { @@ -1054,26 +1013,9 @@ static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev) return prio_map; } -static void bnxt_re_parse_cid_map(u8 prio_map, u8 *cid_map, u16 *cosq) -{ - u16 prio; - u8 id; - - for (prio = 0, id = 0; prio < 8; prio++) { - if (prio_map & (1 << prio)) { - cosq[id] = cid_map[prio]; - id++; - if (id == 2) /* Max 2 tcs supported */ - break; - } - } -} - static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) { u8 prio_map = 0; - u64 cid_map; - int rc; /* Get priority for roce */ prio_map = bnxt_re_get_priority_mask(rdev); @@ -1081,23 +1023,6 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) if (prio_map == rdev->cur_prio_map) return 0; rdev->cur_prio_map = prio_map; - /* Get cosq id for this priority */ - rc = bnxt_re_query_hwrm_pri2cos(rdev, 0, &cid_map); - if (rc) { - ibdev_warn(&rdev->ibdev, "no cos for p_mask %x\n", prio_map); - return rc; - } - /* Parse CoS IDs for app priority */ - bnxt_re_parse_cid_map(prio_map, (u8 *)&cid_map, rdev->cosq); - - /* Config BONO. */ - rc = bnxt_qplib_map_tc2cos(&rdev->qplib_res, rdev->cosq); - if (rc) { - ibdev_warn(&rdev->ibdev, "no tc for cos{%x, %x}\n", - rdev->cosq[0], rdev->cosq[1]); - return rc; - } - /* Actual priorities are not programmed as they are already * done by L2 driver; just enable or disable priority vlan tagging */ @@ -1407,6 +1332,31 @@ exit: return rc; } +static void bnxt_re_setup_cc(struct bnxt_re_dev *rdev, bool enable) +{ + struct bnxt_qplib_cc_param cc_param = {}; + + /* Do not enable congestion control on VFs */ + if (rdev->is_virtfn) + return; + + /* Currently enabling only for GenP5 adapters */ + if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) + return; + + if (enable) { + cc_param.enable = 1; + cc_param.cc_mode = CMDQ_MODIFY_ROCE_CC_CC_MODE_PROBABILISTIC_CC_MODE; + } + + cc_param.mask = (CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE | + CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC | + CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN); + + if (bnxt_qplib_modify_cc(&rdev->qplib_res, &cc_param)) + ibdev_err(&rdev->ibdev, "Failed to setup CC enable = %d\n", enable); +} + /* * "Notifier chain callback can be invoked for the same chain from * different CPUs at the same time". @@ -1475,7 +1425,7 @@ static void bnxt_re_remove(struct auxiliary_device *adev) */ goto skip_remove; } - + bnxt_re_setup_cc(rdev, false); ib_unregister_device(&rdev->ibdev); ib_dealloc_device(&rdev->ibdev); bnxt_re_dev_uninit(rdev); @@ -1507,6 +1457,7 @@ static int bnxt_re_probe(struct auxiliary_device *adev, goto err; } + bnxt_re_setup_cc(rdev, true); mutex_unlock(&bnxt_re_mutex); return 0; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 96e581ced50e..8974f6235cfa 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -300,8 +300,6 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) { struct bnxt_qplib_nq *nq = from_tasklet(nq, t, nq_tasklet); struct bnxt_qplib_hwq *hwq = &nq->hwq; - int num_srqne_processed = 0; - int num_cqne_processed = 0; struct bnxt_qplib_cq *cq; int budget = nq->budget; u32 sw_cons, raw_cons; @@ -340,9 +338,7 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) DBC_DBC_TYPE_CQ_ARMENA); spin_lock_bh(&cq->compl_lock); atomic_set(&cq->arm_state, 0); - if (!nq->cqn_handler(nq, (cq))) - num_cqne_processed++; - else + if (nq->cqn_handler(nq, (cq))) dev_warn(&nq->pdev->dev, "cqn - type 0x%x not handled\n", type); cq->cnq_events++; @@ -361,11 +357,9 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t) srq = (struct bnxt_qplib_srq *)q_handle; bnxt_qplib_armen_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ_ARMENA); - if (!nq->srqn_handler(nq, - (struct bnxt_qplib_srq *)q_handle, - nqsrqe->event)) - num_srqne_processed++; - else + if (nq->srqn_handler(nq, + (struct bnxt_qplib_srq *)q_handle, + nqsrqe->event)) dev_warn(&nq->pdev->dev, "SRQ event 0x%x not handled\n", nqsrqe->event); @@ -581,18 +575,20 @@ void bnxt_qplib_destroy_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_destroy_srq req; - struct creq_destroy_srq_resp resp; - u16 cmd_flags = 0; + struct creq_destroy_srq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_destroy_srq req = {}; int rc; - RCFW_CMD_PREP(req, DESTROY_SRQ, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DESTROY_SRQ, + sizeof(req)); /* Configure the request */ req.srq_cid = cpu_to_le32(srq->id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (struct cmdq_base *)&req, - (struct creq_base *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); kfree(srq->swq); if (rc) return; @@ -604,10 +600,10 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, { struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct bnxt_qplib_hwq_attr hwq_attr = {}; - struct creq_create_srq_resp resp; - struct cmdq_create_srq req; + struct creq_create_srq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_create_srq req = {}; struct bnxt_qplib_pbl *pbl; - u16 cmd_flags = 0; u16 pg_sz_lvl; int rc, idx; @@ -627,7 +623,9 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, goto fail; } - RCFW_CMD_PREP(req, CREATE_SRQ, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_SRQ, + sizeof(req)); /* Configure the request */ req.dpi = cpu_to_le32(srq->dpi->dpi); @@ -644,8 +642,8 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res, req.pd_id = cpu_to_le32(srq->pd->id); req.eventq_id = cpu_to_le16(srq->eventq_hw_ring_id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto fail; @@ -700,14 +698,16 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_srq *srq) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_query_srq req; - struct creq_query_srq_resp resp; + struct creq_query_srq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_rcfw_sbuf *sbuf; struct creq_query_srq_resp_sb *sb; - u16 cmd_flags = 0; + struct cmdq_query_srq req = {}; int rc = 0; - RCFW_CMD_PREP(req, QUERY_SRQ, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_QUERY_SRQ, + sizeof(req)); /* Configure the request */ sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); @@ -716,8 +716,9 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; req.srq_cid = cpu_to_le32(srq->id); sb = sbuf->sb; - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - (void *)sbuf, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); srq->threshold = le16_to_cpu(sb->srq_limit); bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); @@ -811,19 +812,20 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) { struct bnxt_qplib_hwq_attr hwq_attr = {}; struct bnxt_qplib_rcfw *rcfw = res->rcfw; + struct creq_create_qp1_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_q *sq = &qp->sq; struct bnxt_qplib_q *rq = &qp->rq; - struct creq_create_qp1_resp resp; - struct cmdq_create_qp1 req; + struct cmdq_create_qp1 req = {}; struct bnxt_qplib_pbl *pbl; - u16 cmd_flags = 0; u32 qp_flags = 0; u8 pg_sz_lvl; u32 tbl_indx; int rc; - RCFW_CMD_PREP(req, CREATE_QP1, cmd_flags); - + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_QP1, + sizeof(req)); /* General */ req.type = qp->type; req.dpi = cpu_to_le32(qp->dpi->dpi); @@ -891,8 +893,8 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) req.qp_flags = cpu_to_le32(qp_flags); req.pd_id = cpu_to_le32(qp->pd->id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto fail; @@ -952,20 +954,22 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct bnxt_qplib_hwq_attr hwq_attr = {}; struct bnxt_qplib_sg_info sginfo = {}; + struct creq_create_qp_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_q *sq = &qp->sq; struct bnxt_qplib_q *rq = &qp->rq; - struct creq_create_qp_resp resp; + struct cmdq_create_qp req = {}; int rc, req_size, psn_sz = 0; struct bnxt_qplib_hwq *xrrq; struct bnxt_qplib_pbl *pbl; - struct cmdq_create_qp req; - u16 cmd_flags = 0; u32 qp_flags = 0; u8 pg_sz_lvl; u32 tbl_indx; u16 nsge; - RCFW_CMD_PREP(req, CREATE_QP, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_QP, + sizeof(req)); /* General */ req.type = qp->type; @@ -1098,8 +1102,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) } req.pd_id = cpu_to_le32(qp->pd->id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto fail; @@ -1231,14 +1236,16 @@ static void __filter_modify_flags(struct bnxt_qplib_qp *qp) int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_modify_qp req; - struct creq_modify_qp_resp resp; - u16 cmd_flags = 0; + struct creq_modify_qp_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_modify_qp req = {}; u32 temp32[4]; u32 bmask; int rc; - RCFW_CMD_PREP(req, MODIFY_QP, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_MODIFY_QP, + sizeof(req)); /* Filter out the qp_attr_mask based on the state->new transition */ __filter_modify_flags(qp); @@ -1286,7 +1293,7 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) memcpy(req.dest_mac, qp->ah.dmac, 6); if (bmask & CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU) - req.path_mtu = qp->path_mtu; + req.path_mtu_pingpong_push_enable |= qp->path_mtu; if (bmask & CMDQ_MODIFY_QP_MODIFY_MASK_TIMEOUT) req.timeout = qp->timeout; @@ -1324,8 +1331,8 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) req.vlan_pcp_vlan_dei_vlan_id = cpu_to_le16(qp->vlan_id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; qp->cur_qp_state = qp->state; @@ -1335,15 +1342,17 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_query_qp req; - struct creq_query_qp_resp resp; + struct creq_query_qp_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_rcfw_sbuf *sbuf; struct creq_query_qp_resp_sb *sb; - u16 cmd_flags = 0; + struct cmdq_query_qp req = {}; u32 temp32[4]; int i, rc = 0; - RCFW_CMD_PREP(req, QUERY_QP, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_QUERY_QP, + sizeof(req)); sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); if (!sbuf) @@ -1352,8 +1361,9 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) req.qp_cid = cpu_to_le32(qp->id); req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - (void *)sbuf, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto bail; /* Extract the context from the side buffer */ @@ -1460,9 +1470,9 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_destroy_qp req; - struct creq_destroy_qp_resp resp; - u16 cmd_flags = 0; + struct creq_destroy_qp_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_destroy_qp req = {}; u32 tbl_indx; int rc; @@ -1470,11 +1480,14 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, rcfw->qp_tbl[tbl_indx].qp_id = BNXT_QPLIB_QP_ID_INVALID; rcfw->qp_tbl[tbl_indx].qp_handle = NULL; - RCFW_CMD_PREP(req, DESTROY_QP, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DESTROY_QP, + sizeof(req)); req.qp_cid = cpu_to_le32(qp->id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) { rcfw->qp_tbl[tbl_indx].qp_id = qp->id; rcfw->qp_tbl[tbl_indx].qp_handle = qp; @@ -2036,13 +2049,19 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct bnxt_qplib_hwq_attr hwq_attr = {}; - struct creq_create_cq_resp resp; + struct creq_create_cq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_create_cq req = {}; struct bnxt_qplib_pbl *pbl; - struct cmdq_create_cq req; - u16 cmd_flags = 0; u32 pg_sz_lvl; int rc; + if (!cq->dpi) { + dev_err(&rcfw->pdev->dev, + "FP: CREATE_CQ failed due to NULL DPI\n"); + return -EINVAL; + } + hwq_attr.res = res; hwq_attr.depth = cq->max_wqe; hwq_attr.stride = sizeof(struct cq_base); @@ -2052,13 +2071,10 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) if (rc) goto exit; - RCFW_CMD_PREP(req, CREATE_CQ, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_CQ, + sizeof(req)); - if (!cq->dpi) { - dev_err(&rcfw->pdev->dev, - "FP: CREATE_CQ failed due to NULL DPI\n"); - return -EINVAL; - } req.dpi = cpu_to_le32(cq->dpi->dpi); req.cq_handle = cpu_to_le64(cq->cq_handle); req.cq_size = cpu_to_le32(cq->hwq.max_elements); @@ -2071,9 +2087,9 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) req.cq_fco_cnq_id = cpu_to_le32( (cq->cnq_hw_ring_id & CMDQ_CREATE_CQ_CNQ_ID_MASK) << CMDQ_CREATE_CQ_CNQ_ID_SFT); - - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto fail; @@ -2100,20 +2116,70 @@ exit: return rc; } +void bnxt_qplib_resize_cq_complete(struct bnxt_qplib_res *res, + struct bnxt_qplib_cq *cq) +{ + bnxt_qplib_free_hwq(res, &cq->hwq); + memcpy(&cq->hwq, &cq->resize_hwq, sizeof(cq->hwq)); +} + +int bnxt_qplib_resize_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq, + int new_cqes) +{ + struct bnxt_qplib_hwq_attr hwq_attr = {}; + struct bnxt_qplib_rcfw *rcfw = res->rcfw; + struct creq_resize_cq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_resize_cq req = {}; + struct bnxt_qplib_pbl *pbl; + u32 pg_sz, lvl, new_sz; + int rc; + + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_RESIZE_CQ, + sizeof(req)); + hwq_attr.sginfo = &cq->sg_info; + hwq_attr.res = res; + hwq_attr.depth = new_cqes; + hwq_attr.stride = sizeof(struct cq_base); + hwq_attr.type = HWQ_TYPE_QUEUE; + rc = bnxt_qplib_alloc_init_hwq(&cq->resize_hwq, &hwq_attr); + if (rc) + return rc; + + req.cq_cid = cpu_to_le32(cq->id); + pbl = &cq->resize_hwq.pbl[PBL_LVL_0]; + pg_sz = bnxt_qplib_base_pg_size(&cq->resize_hwq); + lvl = (cq->resize_hwq.level << CMDQ_RESIZE_CQ_LVL_SFT) & + CMDQ_RESIZE_CQ_LVL_MASK; + new_sz = (new_cqes << CMDQ_RESIZE_CQ_NEW_CQ_SIZE_SFT) & + CMDQ_RESIZE_CQ_NEW_CQ_SIZE_MASK; + req.new_cq_size_pg_size_lvl = cpu_to_le32(new_sz | pg_sz | lvl); + req.new_pbl = cpu_to_le64(pbl->pg_map_arr[0]); + + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); + return rc; +} + int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_destroy_cq req; - struct creq_destroy_cq_resp resp; + struct creq_destroy_cq_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_destroy_cq req = {}; u16 total_cnq_events; - u16 cmd_flags = 0; int rc; - RCFW_CMD_PREP(req, DESTROY_CQ, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DESTROY_CQ, + sizeof(req)); req.cq_cid = cpu_to_le32(cq->id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; total_cnq_events = le16_to_cpu(resp.total_cnq_events); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 037501952543..d74d5ead2e32 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -400,6 +400,7 @@ struct bnxt_qplib_cq { u16 count; u16 period; struct bnxt_qplib_hwq hwq; + struct bnxt_qplib_hwq resize_hwq; u32 cnq_hw_ring_id; struct bnxt_qplib_nq *nq; bool resize_in_progress; @@ -532,6 +533,10 @@ void bnxt_qplib_post_recv_db(struct bnxt_qplib_qp *qp); int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp, struct bnxt_qplib_swqe *wqe); int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq); +int bnxt_qplib_resize_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq, + int new_cqes); +void bnxt_qplib_resize_cq_complete(struct bnxt_qplib_res *res, + struct bnxt_qplib_cq *cq); int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq); int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe, int num, struct bnxt_qplib_qp **qp); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 061b2895dd9b..de9069103177 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -49,6 +49,7 @@ #include "qplib_rcfw.h" #include "qplib_sp.h" #include "qplib_fp.h" +#include "qplib_tlv.h" static void bnxt_qplib_service_creq(struct tasklet_struct *t); @@ -85,8 +86,8 @@ done: return count ? 0 : -ETIMEDOUT; }; -static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, - struct creq_base *resp, void *sb, u8 is_block) +static int __send_message(struct bnxt_qplib_rcfw *rcfw, + struct bnxt_qplib_cmdqmsg *msg) { struct bnxt_qplib_cmdq_ctx *cmdq = &rcfw->cmdq; struct bnxt_qplib_hwq *hwq = &cmdq->hwq; @@ -95,13 +96,13 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, u32 sw_prod, cmdq_prod; struct pci_dev *pdev; unsigned long flags; - u32 size, opcode; + u32 bsize, opcode; u16 cookie, cbit; u8 *preq; pdev = rcfw->pdev; - opcode = req->opcode; + opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz); if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) && (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC && opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW && @@ -124,7 +125,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, * cmdqe */ spin_lock_irqsave(&hwq->lock, flags); - if (req->cmd_size >= HWQ_FREE_SLOTS(hwq)) { + if (msg->req->cmd_size >= HWQ_FREE_SLOTS(hwq)) { dev_err(&pdev->dev, "RCFW: CMDQ is full!\n"); spin_unlock_irqrestore(&hwq->lock, flags); return -EAGAIN; @@ -133,36 +134,34 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, cookie = cmdq->seq_num & RCFW_MAX_COOKIE_VALUE; cbit = cookie % rcfw->cmdq_depth; - if (is_block) + if (msg->block) cookie |= RCFW_CMD_IS_BLOCKING; set_bit(cbit, cmdq->cmdq_bitmap); - req->cookie = cpu_to_le16(cookie); + __set_cmdq_base_cookie(msg->req, msg->req_sz, cpu_to_le16(cookie)); crsqe = &rcfw->crsqe_tbl[cbit]; if (crsqe->resp) { spin_unlock_irqrestore(&hwq->lock, flags); return -EBUSY; } - size = req->cmd_size; /* change the cmd_size to the number of 16byte cmdq unit. * req->cmd_size is modified here */ - bnxt_qplib_set_cmd_slots(req); + bsize = bnxt_qplib_set_cmd_slots(msg->req); - memset(resp, 0, sizeof(*resp)); - crsqe->resp = (struct creq_qp_event *)resp; - crsqe->resp->cookie = req->cookie; - crsqe->req_size = req->cmd_size; - if (req->resp_size && sb) { - struct bnxt_qplib_rcfw_sbuf *sbuf = sb; - - req->resp_addr = cpu_to_le64(sbuf->dma_addr); - req->resp_size = (sbuf->size + BNXT_QPLIB_CMDQE_UNITS - 1) / - BNXT_QPLIB_CMDQE_UNITS; + memset(msg->resp, 0, sizeof(*msg->resp)); + crsqe->resp = (struct creq_qp_event *)msg->resp; + crsqe->resp->cookie = cpu_to_le16(cookie); + crsqe->req_size = __get_cmdq_base_cmd_size(msg->req, msg->req_sz); + if (__get_cmdq_base_resp_size(msg->req, msg->req_sz) && msg->sb) { + struct bnxt_qplib_rcfw_sbuf *sbuf = msg->sb; + __set_cmdq_base_resp_addr(msg->req, msg->req_sz, cpu_to_le64(sbuf->dma_addr)); + __set_cmdq_base_resp_size(msg->req, msg->req_sz, + ALIGN(sbuf->size, BNXT_QPLIB_CMDQE_UNITS)); } - preq = (u8 *)req; + preq = (u8 *)msg->req; do { /* Locate the next cmdq slot */ sw_prod = HWQ_CMP(hwq->prod, hwq); @@ -174,11 +173,11 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, } /* Copy a segment of the req cmd to the cmdq */ memset(cmdqe, 0, sizeof(*cmdqe)); - memcpy(cmdqe, preq, min_t(u32, size, sizeof(*cmdqe))); - preq += min_t(u32, size, sizeof(*cmdqe)); - size -= min_t(u32, size, sizeof(*cmdqe)); + memcpy(cmdqe, preq, min_t(u32, bsize, sizeof(*cmdqe))); + preq += min_t(u32, bsize, sizeof(*cmdqe)); + bsize -= min_t(u32, bsize, sizeof(*cmdqe)); hwq->prod++; - } while (size > 0); + } while (bsize > 0); cmdq->seq_num++; cmdq_prod = hwq->prod; @@ -191,7 +190,6 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, cmdq_prod |= BIT(FIRMWARE_FIRST_FLAG); clear_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags); } - /* ring CMDQ DB */ wmb(); writel(cmdq_prod, cmdq->cmdq_mbox.prod); @@ -203,11 +201,9 @@ done: } int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, - struct cmdq_base *req, - struct creq_base *resp, - void *sb, u8 is_block) + struct bnxt_qplib_cmdqmsg *msg) { - struct creq_qp_event *evnt = (struct creq_qp_event *)resp; + struct creq_qp_event *evnt = (struct creq_qp_event *)msg->resp; u16 cookie; u8 opcode, retry_cnt = 0xFF; int rc = 0; @@ -217,23 +213,23 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, return 0; do { - opcode = req->opcode; - rc = __send_message(rcfw, req, resp, sb, is_block); - cookie = le16_to_cpu(req->cookie) & RCFW_MAX_COOKIE_VALUE; + opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz); + rc = __send_message(rcfw, msg); + cookie = le16_to_cpu(__get_cmdq_base_cookie(msg->req, msg->req_sz)) & + RCFW_MAX_COOKIE_VALUE; if (!rc) break; - if (!retry_cnt || (rc != -EAGAIN && rc != -EBUSY)) { /* send failed */ dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x send failed\n", cookie, opcode); return rc; } - is_block ? mdelay(1) : usleep_range(500, 1000); + msg->block ? mdelay(1) : usleep_range(500, 1000); } while (retry_cnt--); - if (is_block) + if (msg->block) rc = __block_for_resp(rcfw, cookie); else rc = __wait_for_resp(rcfw, cookie); @@ -452,14 +448,17 @@ static irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance) /* RCFW */ int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw) { - struct cmdq_deinitialize_fw req; - struct creq_deinitialize_fw_resp resp; - u16 cmd_flags = 0; + struct creq_deinitialize_fw_resp resp = {}; + struct cmdq_deinitialize_fw req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; int rc; - RCFW_CMD_PREP(req, DEINITIALIZE_FW, cmd_flags); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - NULL, 0); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DEINITIALIZE_FW, + sizeof(req)); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, + sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; @@ -470,13 +469,15 @@ int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw) int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_ctx *ctx, int is_virtfn) { - struct creq_initialize_fw_resp resp; - struct cmdq_initialize_fw req; - u16 cmd_flags = 0; + struct creq_initialize_fw_resp resp = {}; + struct cmdq_initialize_fw req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; u8 pgsz, lvl; int rc; - RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_INITIALIZE_FW, + sizeof(req)); /* Supply (log-base-2-of-host-page-size - base-page-shift) * to bono to adjust the doorbell page sizes. */ @@ -545,8 +546,8 @@ config_vf_res: skip_ctx_setup: req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 0a3d8e7da3d4..dd5651478bbb 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -39,6 +39,8 @@ #ifndef __BNXT_QPLIB_RCFW_H__ #define __BNXT_QPLIB_RCFW_H__ +#include "qplib_tlv.h" + #define RCFW_CMDQ_TRIG_VAL 1 #define RCFW_COMM_PCI_BAR_REGION 0 #define RCFW_COMM_CONS_PCI_BAR_REGION 2 @@ -51,25 +53,25 @@ #define RCFW_DBR_PCI_BAR_REGION 2 #define RCFW_DBR_BASE_PAGE_SHIFT 12 -#define RCFW_CMD_PREP(req, CMD, cmd_flags) \ - do { \ - memset(&(req), 0, sizeof((req))); \ - (req).opcode = CMDQ_BASE_OPCODE_##CMD; \ - (req).cmd_size = sizeof((req)); \ - (req).flags = cpu_to_le16(cmd_flags); \ - } while (0) - -#define RCFW_CMD_WAIT_TIME_MS 20000 /* 20 Seconds timeout */ - /* Cmdq contains a fix number of a 16-Byte slots */ struct bnxt_qplib_cmdqe { u8 data[16]; }; +#define BNXT_QPLIB_CMDQE_UNITS sizeof(struct bnxt_qplib_cmdqe) + +static inline void bnxt_qplib_rcfw_cmd_prep(struct cmdq_base *req, + u8 opcode, u8 cmd_size) +{ + req->opcode = opcode; + req->cmd_size = cmd_size; +} + +#define RCFW_CMD_WAIT_TIME_MS 20000 /* 20 Seconds timeout */ + /* CMDQ elements */ #define BNXT_QPLIB_CMDQE_MAX_CNT_256 256 #define BNXT_QPLIB_CMDQE_MAX_CNT_8192 8192 -#define BNXT_QPLIB_CMDQE_UNITS sizeof(struct bnxt_qplib_cmdqe) #define BNXT_QPLIB_CMDQE_BYTES(depth) ((depth) * BNXT_QPLIB_CMDQE_UNITS) static inline u32 bnxt_qplib_cmdqe_npages(u32 depth) @@ -87,11 +89,21 @@ static inline u32 bnxt_qplib_cmdqe_page_size(u32 depth) return (bnxt_qplib_cmdqe_npages(depth) * PAGE_SIZE); } -/* Set the cmd_size to a factor of CMDQE unit */ -static inline void bnxt_qplib_set_cmd_slots(struct cmdq_base *req) +static inline u32 bnxt_qplib_set_cmd_slots(struct cmdq_base *req) { - req->cmd_size = (req->cmd_size + BNXT_QPLIB_CMDQE_UNITS - 1) / - BNXT_QPLIB_CMDQE_UNITS; + u32 cmd_byte = 0; + + if (HAS_TLV_HEADER(req)) { + struct roce_tlv *tlv_req = (struct roce_tlv *)req; + + cmd_byte = tlv_req->total_size * BNXT_QPLIB_CMDQE_UNITS; + } else { + cmd_byte = req->cmd_size; + req->cmd_size = (req->cmd_size + BNXT_QPLIB_CMDQE_UNITS - 1) / + BNXT_QPLIB_CMDQE_UNITS; + } + + return cmd_byte; } #define RCFW_MAX_COOKIE_VALUE 0x7FFF @@ -190,6 +202,27 @@ struct bnxt_qplib_rcfw { u32 cmdq_depth; }; +struct bnxt_qplib_cmdqmsg { + struct cmdq_base *req; + struct creq_base *resp; + void *sb; + u32 req_sz; + u32 res_sz; + u8 block; +}; + +static inline void bnxt_qplib_fill_cmdqmsg(struct bnxt_qplib_cmdqmsg *msg, + void *req, void *resp, void *sb, + u32 req_sz, u32 res_sz, u8 block) +{ + msg->req = req; + msg->resp = resp; + msg->sb = sb; + msg->req_sz = req_sz; + msg->res_sz = res_sz; + msg->block = block; +} + void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); int bnxt_qplib_alloc_rcfw_channel(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw *rcfw, @@ -210,8 +243,7 @@ struct bnxt_qplib_rcfw_sbuf *bnxt_qplib_rcfw_alloc_sbuf( void bnxt_qplib_rcfw_free_sbuf(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_rcfw_sbuf *sbuf); int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, - struct cmdq_base *req, struct creq_base *resp, - void *sbuf, u8 is_block); + struct bnxt_qplib_cmdqmsg *msg); int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw); int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 126d4f26f75a..81b0c5e879f9 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -215,17 +215,9 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, return -EINVAL; hwq_attr->sginfo->npages = npages; } else { - unsigned long sginfo_num_pages = ib_umem_num_dma_blocks( - hwq_attr->sginfo->umem, hwq_attr->sginfo->pgsize); - + npages = ib_umem_num_dma_blocks(hwq_attr->sginfo->umem, + hwq_attr->sginfo->pgsize); hwq->is_user = true; - npages = sginfo_num_pages; - npages = (npages * PAGE_SIZE) / - BIT_ULL(hwq_attr->sginfo->pgshft); - if ((sginfo_num_pages * PAGE_SIZE) % - BIT_ULL(hwq_attr->sginfo->pgshft)) - if (!npages) - npages++; } if (npages == MAX_PBL_LVL_0_PGS && !hwq_attr->sginfo->nopte) { diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index b802981b7171..b967a17a44be 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -48,6 +48,7 @@ #include "qplib_res.h" #include "qplib_rcfw.h" #include "qplib_sp.h" +#include "qplib_tlv.h" const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -68,15 +69,17 @@ static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw) static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, char *fw_ver) { - struct cmdq_query_version req; - struct creq_query_version_resp resp; - u16 cmd_flags = 0; + struct creq_query_version_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_query_version req = {}; int rc = 0; - RCFW_CMD_PREP(req, QUERY_VERSION, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_QUERY_VERSION, + sizeof(req)); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return; fw_ver[0] = resp.fw_maj; @@ -88,16 +91,18 @@ static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_dev_attr *attr, bool vf) { - struct cmdq_query_func req; - struct creq_query_func_resp resp; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct creq_query_func_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct creq_query_func_resp_sb *sb; - u16 cmd_flags = 0; - u32 temp; + struct bnxt_qplib_rcfw_sbuf *sbuf; + struct cmdq_query_func req = {}; u8 *tqm_alloc; int i, rc = 0; + u32 temp; - RCFW_CMD_PREP(req, QUERY_FUNC, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_QUERY_FUNC, + sizeof(req)); sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); if (!sbuf) { @@ -108,8 +113,9 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, sb = sbuf->sb; req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - (void *)sbuf, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto bail; @@ -174,12 +180,14 @@ int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_ctx *ctx) { - struct cmdq_set_func_resources req; - struct creq_set_func_resources_resp resp; - u16 cmd_flags = 0; + struct creq_set_func_resources_resp resp = {}; + struct cmdq_set_func_resources req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; int rc = 0; - RCFW_CMD_PREP(req, SET_FUNC_RESOURCES, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_SET_FUNC_RESOURCES, + sizeof(req)); req.number_of_qp = cpu_to_le32(ctx->qpc_count); req.number_of_mrw = cpu_to_le32(ctx->mrw_count); @@ -192,9 +200,9 @@ int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, req.max_cq_per_vf = cpu_to_le32(ctx->vf_res.max_cq_per_vf); req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, - NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) { dev_err(&res->pdev->dev, "Failed to set function resources\n"); } @@ -245,20 +253,23 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, } /* Remove GID from the SGID table */ if (update) { - struct cmdq_delete_gid req; - struct creq_delete_gid_resp resp; - u16 cmd_flags = 0; + struct creq_delete_gid_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_delete_gid req = {}; int rc; - RCFW_CMD_PREP(req, DELETE_GID, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DELETE_GID, + sizeof(req)); if (sgid_tbl->hw_id[index] == 0xFFFF) { dev_err(&res->pdev->dev, "GID entry contains an invalid HW id\n"); return -EINVAL; } req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; } @@ -315,12 +326,14 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, return -ENOMEM; } if (update) { - struct cmdq_add_gid req; - struct creq_add_gid_resp resp; - u16 cmd_flags = 0; + struct creq_add_gid_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_add_gid req = {}; int rc; - RCFW_CMD_PREP(req, ADD_GID, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_ADD_GID, + sizeof(req)); req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]); req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]); @@ -345,8 +358,9 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]); req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; sgid_tbl->hw_id[free_idx] = le32_to_cpu(resp.xid); @@ -375,12 +389,14 @@ int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, struct bnxt_qplib_res, sgid_tbl); struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct creq_modify_gid_resp resp; - struct cmdq_modify_gid req; + struct creq_modify_gid_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_modify_gid req = {}; int rc; - u16 cmd_flags = 0; - RCFW_CMD_PREP(req, MODIFY_GID, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_MODIFY_GID, + sizeof(req)); req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]); req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]); @@ -399,8 +415,9 @@ int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, req.gid_index = cpu_to_le16(gid_idx); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); return rc; } @@ -409,14 +426,16 @@ int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah, bool block) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_create_ah req; - struct creq_create_ah_resp resp; - u16 cmd_flags = 0; + struct creq_create_ah_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_create_ah req = {}; u32 temp32[4]; u16 temp16[3]; int rc; - RCFW_CMD_PREP(req, CREATE_AH, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_CREATE_AH, + sizeof(req)); memcpy(temp32, ah->dgid.data, sizeof(struct bnxt_qplib_gid)); req.dgid[0] = cpu_to_le32(temp32[0]); @@ -439,8 +458,9 @@ int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah, req.dest_mac[1] = cpu_to_le16(temp16[1]); req.dest_mac[2] = cpu_to_le16(temp16[2]); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - NULL, block); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), block); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; @@ -452,26 +472,29 @@ void bnxt_qplib_destroy_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah, bool block) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_destroy_ah req; - struct creq_destroy_ah_resp resp; - u16 cmd_flags = 0; + struct creq_destroy_ah_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_destroy_ah req = {}; /* Clean up the AH table in the device */ - RCFW_CMD_PREP(req, DESTROY_AH, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DESTROY_AH, + sizeof(req)); req.ah_cid = cpu_to_le32(ah->id); - bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, NULL, - block); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), block); + bnxt_qplib_rcfw_send_message(rcfw, &msg); } /* MRW */ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) { + struct creq_deallocate_key_resp resp = {}; struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_deallocate_key req; - struct creq_deallocate_key_resp resp; - u16 cmd_flags = 0; + struct cmdq_deallocate_key req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; int rc; if (mrw->lkey == 0xFFFFFFFF) { @@ -479,7 +502,9 @@ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) return 0; } - RCFW_CMD_PREP(req, DEALLOCATE_KEY, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DEALLOCATE_KEY, + sizeof(req)); req.mrw_flags = mrw->type; @@ -490,8 +515,9 @@ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) else req.key = cpu_to_le32(mrw->lkey); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; @@ -505,13 +531,15 @@ int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_allocate_mrw req; - struct creq_allocate_mrw_resp resp; - u16 cmd_flags = 0; + struct creq_allocate_mrw_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_allocate_mrw req = {}; unsigned long tmp; int rc; - RCFW_CMD_PREP(req, ALLOCATE_MRW, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_ALLOCATE_MRW, + sizeof(req)); req.pd_id = cpu_to_le32(mrw->pd->id); req.mrw_flags = mrw->type; @@ -523,8 +551,9 @@ int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) tmp = (unsigned long)mrw; req.mrw_handle = cpu_to_le64(tmp); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; @@ -541,16 +570,19 @@ int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw, bool block) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_deregister_mr req; - struct creq_deregister_mr_resp resp; - u16 cmd_flags = 0; + struct creq_deregister_mr_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_deregister_mr req = {}; int rc; - RCFW_CMD_PREP(req, DEREGISTER_MR, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_DEREGISTER_MR, + sizeof(req)); req.lkey = cpu_to_le32(mrw->lkey); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, block); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), block); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) return rc; @@ -570,11 +602,12 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct bnxt_qplib_hwq_attr hwq_attr = {}; struct bnxt_qplib_sg_info sginfo = {}; - struct creq_register_mr_resp resp; - struct cmdq_register_mr req; - u16 cmd_flags = 0, level; + struct creq_register_mr_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_register_mr req = {}; int pages, rc; u32 pg_size; + u16 level; if (num_pbls) { pages = roundup_pow_of_two(num_pbls); @@ -584,16 +617,15 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, /* Free the hwq if it already exist, must be a rereg */ if (mr->hwq.max_elements) bnxt_qplib_free_hwq(res, &mr->hwq); - /* Use system PAGE_SIZE */ hwq_attr.res = res; hwq_attr.depth = pages; - hwq_attr.stride = buf_pg_size; + hwq_attr.stride = sizeof(dma_addr_t); hwq_attr.type = HWQ_TYPE_MR; hwq_attr.sginfo = &sginfo; hwq_attr.sginfo->umem = umem; hwq_attr.sginfo->npages = pages; - hwq_attr.sginfo->pgsize = PAGE_SIZE; - hwq_attr.sginfo->pgshft = PAGE_SHIFT; + hwq_attr.sginfo->pgsize = buf_pg_size; + hwq_attr.sginfo->pgshft = ilog2(buf_pg_size); rc = bnxt_qplib_alloc_init_hwq(&mr->hwq, &hwq_attr); if (rc) { dev_err(&res->pdev->dev, @@ -602,7 +634,9 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, } } - RCFW_CMD_PREP(req, REGISTER_MR, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_REGISTER_MR, + sizeof(req)); /* Configure the request */ if (mr->hwq.level == PBL_LVL_MAX) { @@ -627,8 +661,9 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, req.key = cpu_to_le32(mr->lkey); req.mr_size = cpu_to_le64(mr->total_size); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, NULL, false); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto fail; @@ -679,32 +714,19 @@ int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res, return 0; } -int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids) -{ - struct bnxt_qplib_rcfw *rcfw = res->rcfw; - struct cmdq_map_tc_to_cos req; - struct creq_map_tc_to_cos_resp resp; - u16 cmd_flags = 0; - - RCFW_CMD_PREP(req, MAP_TC_TO_COS, cmd_flags); - req.cos0 = cpu_to_le16(cids[0]); - req.cos1 = cpu_to_le16(cids[1]); - - return bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - NULL, 0); -} - int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_roce_stats *stats) { - struct cmdq_query_roce_stats req; - struct creq_query_roce_stats_resp resp; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct creq_query_roce_stats_resp resp = {}; struct creq_query_roce_stats_resp_sb *sb; - u16 cmd_flags = 0; + struct cmdq_query_roce_stats req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct bnxt_qplib_rcfw_sbuf *sbuf; int rc = 0; - RCFW_CMD_PREP(req, QUERY_ROCE_STATS, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_QUERY_ROCE_STATS, + sizeof(req)); sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); if (!sbuf) { @@ -715,8 +737,9 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, sb = sbuf->sb; req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, - (void *)sbuf, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto bail; /* Extract the context from the side buffer */ @@ -780,8 +803,8 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, struct creq_query_roce_stats_ext_resp resp = {}; struct creq_query_roce_stats_ext_resp_sb *sb; struct cmdq_query_roce_stats_ext req = {}; + struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_rcfw_sbuf *sbuf; - u16 cmd_flags = 0; int rc; sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); @@ -791,15 +814,18 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, return -ENOMEM; } - RCFW_CMD_PREP(req, QUERY_ROCE_STATS_EXT, cmd_flags); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_QUERY_ROCE_STATS, + sizeof(req)); req.resp_size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); req.resp_addr = cpu_to_le64(sbuf->dma_addr); req.function_id = cpu_to_le32(fid); req.flags = cpu_to_le16(CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_FUNCTION_ID); - rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, - (void *)&resp, (void *)sbuf, 0); + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto bail; @@ -823,3 +849,111 @@ bail: bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); return rc; } + +static void bnxt_qplib_fill_cc_gen1(struct cmdq_modify_roce_cc_gen1_tlv *ext_req, + struct bnxt_qplib_cc_param_ext *cc_ext) +{ + ext_req->modify_mask = cpu_to_le64(cc_ext->ext_mask); + cc_ext->ext_mask = 0; + ext_req->inactivity_th_hi = cpu_to_le16(cc_ext->inact_th_hi); + ext_req->min_time_between_cnps = cpu_to_le16(cc_ext->min_delta_cnp); + ext_req->init_cp = cpu_to_le16(cc_ext->init_cp); + ext_req->tr_update_mode = cc_ext->tr_update_mode; + ext_req->tr_update_cycles = cc_ext->tr_update_cyls; + ext_req->fr_num_rtts = cc_ext->fr_rtt; + ext_req->ai_rate_increase = cc_ext->ai_rate_incr; + ext_req->reduction_relax_rtts_th = cpu_to_le16(cc_ext->rr_rtt_th); + ext_req->additional_relax_cr_th = cpu_to_le16(cc_ext->ar_cr_th); + ext_req->cr_min_th = cpu_to_le16(cc_ext->cr_min_th); + ext_req->bw_avg_weight = cc_ext->bw_avg_weight; + ext_req->actual_cr_factor = cc_ext->cr_factor; + ext_req->max_cp_cr_th = cpu_to_le16(cc_ext->cr_th_max_cp); + ext_req->cp_bias_en = cc_ext->cp_bias_en; + ext_req->cp_bias = cc_ext->cp_bias; + ext_req->cnp_ecn = cc_ext->cnp_ecn; + ext_req->rtt_jitter_en = cc_ext->rtt_jitter_en; + ext_req->link_bytes_per_usec = cpu_to_le16(cc_ext->bytes_per_usec); + ext_req->reset_cc_cr_th = cpu_to_le16(cc_ext->cc_cr_reset_th); + ext_req->cr_width = cc_ext->cr_width; + ext_req->quota_period_min = cc_ext->min_quota; + ext_req->quota_period_max = cc_ext->max_quota; + ext_req->quota_period_abs_max = cc_ext->abs_max_quota; + ext_req->tr_lower_bound = cpu_to_le16(cc_ext->tr_lb); + ext_req->cr_prob_factor = cc_ext->cr_prob_fac; + ext_req->tr_prob_factor = cc_ext->tr_prob_fac; + ext_req->fairness_cr_th = cpu_to_le16(cc_ext->fair_cr_th); + ext_req->red_div = cc_ext->red_div; + ext_req->cnp_ratio_th = cc_ext->cnp_ratio_th; + ext_req->exp_ai_rtts = cpu_to_le16(cc_ext->ai_ext_rtt); + ext_req->exp_ai_cr_cp_ratio = cc_ext->exp_crcp_ratio; + ext_req->use_rate_table = cc_ext->low_rate_en; + ext_req->cp_exp_update_th = cpu_to_le16(cc_ext->cpcr_update_th); + ext_req->high_exp_ai_rtts_th1 = cpu_to_le16(cc_ext->ai_rtt_th1); + ext_req->high_exp_ai_rtts_th2 = cpu_to_le16(cc_ext->ai_rtt_th2); + ext_req->actual_cr_cong_free_rtts_th = cpu_to_le16(cc_ext->cf_rtt_th); + ext_req->severe_cong_cr_th1 = cpu_to_le16(cc_ext->sc_cr_th1); + ext_req->severe_cong_cr_th2 = cpu_to_le16(cc_ext->sc_cr_th2); + ext_req->link64B_per_rtt = cpu_to_le32(cc_ext->l64B_per_rtt); + ext_req->cc_ack_bytes = cc_ext->cc_ack_bytes; +} + +int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res, + struct bnxt_qplib_cc_param *cc_param) +{ + struct bnxt_qplib_tlv_modify_cc_req tlv_req = {}; + struct creq_modify_roce_cc_resp resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_modify_roce_cc *req; + int req_size; + void *cmd; + int rc; + + /* Prepare the older base command */ + req = &tlv_req.base_req; + cmd = req; + req_size = sizeof(*req); + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)req, CMDQ_BASE_OPCODE_MODIFY_ROCE_CC, + sizeof(*req)); + req->modify_mask = cpu_to_le32(cc_param->mask); + req->enable_cc = cc_param->enable; + req->g = cc_param->g; + req->num_phases_per_state = cc_param->nph_per_state; + req->time_per_phase = cc_param->time_pph; + req->pkts_per_phase = cc_param->pkts_pph; + req->init_cr = cpu_to_le16(cc_param->init_cr); + req->init_tr = cpu_to_le16(cc_param->init_tr); + req->tos_dscp_tos_ecn = (cc_param->tos_dscp << CMDQ_MODIFY_ROCE_CC_TOS_DSCP_SFT) | + (cc_param->tos_ecn & CMDQ_MODIFY_ROCE_CC_TOS_ECN_MASK); + req->alt_vlan_pcp = cc_param->alt_vlan_pcp; + req->alt_tos_dscp = cpu_to_le16(cc_param->alt_tos_dscp); + req->rtt = cpu_to_le16(cc_param->rtt); + req->tcp_cp = cpu_to_le16(cc_param->tcp_cp); + req->cc_mode = cc_param->cc_mode; + req->inactivity_th = cpu_to_le16(cc_param->inact_th); + + /* For chip gen P5 onwards fill extended cmd and header */ + if (bnxt_qplib_is_chip_gen_p5(res->cctx)) { + struct roce_tlv *hdr; + u32 payload; + u32 chunks; + + cmd = &tlv_req; + req_size = sizeof(tlv_req); + /* Prepare primary tlv header */ + hdr = &tlv_req.tlv_hdr; + chunks = CHUNKS(sizeof(struct bnxt_qplib_tlv_modify_cc_req)); + payload = sizeof(struct cmdq_modify_roce_cc); + __roce_1st_tlv_prep(hdr, chunks, payload, true); + /* Prepare secondary tlv header */ + hdr = (struct roce_tlv *)&tlv_req.ext_req; + payload = sizeof(struct cmdq_modify_roce_cc_gen1_tlv) - + sizeof(struct roce_tlv); + __roce_ext_tlv_prep(hdr, TLV_TYPE_MODIFY_ROCE_CC_GEN1, payload, false, true); + bnxt_qplib_fill_cc_gen1(&tlv_req.ext_req, &cc_param->cc_ext); + } + + bnxt_qplib_fill_cmdqmsg(&msg, cmd, &resp, NULL, req_size, + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(res->rcfw, &msg); + return rc; +} diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index 5939e8fc8353..5de874659cdf 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -244,6 +244,71 @@ struct bnxt_qplib_ext_stat { u64 rx_ecn_marked; }; +struct bnxt_qplib_cc_param_ext { + u64 ext_mask; + u16 inact_th_hi; + u16 min_delta_cnp; + u16 init_cp; + u8 tr_update_mode; + u8 tr_update_cyls; + u8 fr_rtt; + u8 ai_rate_incr; + u16 rr_rtt_th; + u16 ar_cr_th; + u16 cr_min_th; + u8 bw_avg_weight; + u8 cr_factor; + u16 cr_th_max_cp; + u8 cp_bias_en; + u8 cp_bias; + u8 cnp_ecn; + u8 rtt_jitter_en; + u16 bytes_per_usec; + u16 cc_cr_reset_th; + u8 cr_width; + u8 min_quota; + u8 max_quota; + u8 abs_max_quota; + u16 tr_lb; + u8 cr_prob_fac; + u8 tr_prob_fac; + u16 fair_cr_th; + u8 red_div; + u8 cnp_ratio_th; + u16 ai_ext_rtt; + u8 exp_crcp_ratio; + u8 low_rate_en; + u16 cpcr_update_th; + u16 ai_rtt_th1; + u16 ai_rtt_th2; + u16 cf_rtt_th; + u16 sc_cr_th1; /* severe congestion cr threshold 1 */ + u16 sc_cr_th2; /* severe congestion cr threshold 2 */ + u32 l64B_per_rtt; + u8 cc_ack_bytes; + u16 reduce_cf_rtt_th; +}; + +struct bnxt_qplib_cc_param { + u8 alt_vlan_pcp; + u16 alt_tos_dscp; + u8 cc_mode; + u8 enable; + u16 inact_th; + u16 init_cr; + u16 init_tr; + u16 rtt; + u8 g; + u8 nph_per_state; + u8 time_pph; + u8 pkts_pph; + u8 tos_ecn; + u8 tos_dscp; + u16 tcp_cp; + struct bnxt_qplib_cc_param_ext cc_ext; + u32 mask; +}; + int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, struct bnxt_qplib_sgid_tbl *sgid_tbl, int index, struct bnxt_qplib_gid *gid); @@ -277,10 +342,11 @@ int bnxt_qplib_alloc_fast_reg_page_list(struct bnxt_qplib_res *res, struct bnxt_qplib_frpl *frpl, int max); int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res, struct bnxt_qplib_frpl *frpl); -int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids); int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_roce_stats *stats); int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, struct bnxt_qplib_ext_stat *estat); +int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res, + struct bnxt_qplib_cc_param *cc_param); #endif /* __BNXT_QPLIB_SP_H__*/ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_tlv.h b/drivers/infiniband/hw/bnxt_re/qplib_tlv.h new file mode 100644 index 000000000000..402c220734f6 --- /dev/null +++ b/drivers/infiniband/hw/bnxt_re/qplib_tlv.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ + +#ifndef __QPLIB_TLV_H__ +#define __QPLIB_TLV_H__ + +struct roce_tlv { + struct tlv tlv; + u8 total_size; // in units of 16 byte chunks + u8 unused[7]; // for 16 byte alignment +}; + +#define CHUNK_SIZE 16 +#define CHUNKS(x) (((x) + CHUNK_SIZE - 1) / CHUNK_SIZE) + +static inline void __roce_1st_tlv_prep(struct roce_tlv *rtlv, u8 tot_chunks, + u16 content_bytes, u8 flags) +{ + rtlv->tlv.cmd_discr = cpu_to_le16(CMD_DISCR_TLV_ENCAP); + rtlv->tlv.tlv_type = cpu_to_le16(TLV_TYPE_ROCE_SP_COMMAND); + rtlv->tlv.length = cpu_to_le16(content_bytes); + rtlv->tlv.flags = TLV_FLAGS_REQUIRED; + rtlv->tlv.flags |= flags ? TLV_FLAGS_MORE : 0; + rtlv->total_size = (tot_chunks); +} + +static inline void __roce_ext_tlv_prep(struct roce_tlv *rtlv, u16 tlv_type, + u16 content_bytes, u8 more, u8 flags) +{ + rtlv->tlv.cmd_discr = cpu_to_le16(CMD_DISCR_TLV_ENCAP); + rtlv->tlv.tlv_type = cpu_to_le16(tlv_type); + rtlv->tlv.length = cpu_to_le16(content_bytes); + rtlv->tlv.flags |= more ? TLV_FLAGS_MORE : 0; + rtlv->tlv.flags |= flags ? TLV_FLAGS_REQUIRED : 0; +} + +/* + * TLV size in units of 16 byte chunks + */ +#define TLV_SIZE ((sizeof(struct roce_tlv) + 15) / 16) +/* + * TLV length in bytes + */ +#define TLV_BYTES (TLV_SIZE * 16) + +#define HAS_TLV_HEADER(msg) (le16_to_cpu(((struct tlv *)(msg))->cmd_discr) == CMD_DISCR_TLV_ENCAP) +#define GET_TLV_DATA(tlv) ((void *)&((uint8_t *)(tlv))[TLV_BYTES]) + +static inline u8 __get_cmdq_base_opcode(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct cmdq_base *)GET_TLV_DATA(req))->opcode; + else + return req->opcode; +} + +static inline void __set_cmdq_base_opcode(struct cmdq_base *req, + u32 size, u8 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->opcode = val; + else + req->opcode = val; +} + +static inline __le16 __get_cmdq_base_cookie(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct cmdq_base *)GET_TLV_DATA(req))->cookie; + else + return req->cookie; +} + +static inline void __set_cmdq_base_cookie(struct cmdq_base *req, + u32 size, __le16 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->cookie = val; + else + req->cookie = val; +} + +static inline __le64 __get_cmdq_base_resp_addr(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct cmdq_base *)GET_TLV_DATA(req))->resp_addr; + else + return req->resp_addr; +} + +static inline void __set_cmdq_base_resp_addr(struct cmdq_base *req, + u32 size, __le64 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->resp_addr = val; + else + req->resp_addr = val; +} + +static inline u8 __get_cmdq_base_resp_size(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct cmdq_base *)GET_TLV_DATA(req))->resp_size; + else + return req->resp_size; +} + +static inline void __set_cmdq_base_resp_size(struct cmdq_base *req, + u32 size, u8 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->resp_size = val; + else + req->resp_size = val; +} + +static inline u8 __get_cmdq_base_cmd_size(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct roce_tlv *)(req))->total_size; + else + return req->cmd_size; +} + +static inline void __set_cmdq_base_cmd_size(struct cmdq_base *req, + u32 size, u8 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->cmd_size = val; + else + req->cmd_size = val; +} + +static inline __le16 __get_cmdq_base_flags(struct cmdq_base *req, u32 size) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + return ((struct cmdq_base *)GET_TLV_DATA(req))->flags; + else + return req->flags; +} + +static inline void __set_cmdq_base_flags(struct cmdq_base *req, + u32 size, __le16 val) +{ + if (HAS_TLV_HEADER(req) && size > TLV_BYTES) + ((struct cmdq_base *)GET_TLV_DATA(req))->flags = val; + else + req->flags = val; +} + +struct bnxt_qplib_tlv_modify_cc_req { + struct roce_tlv tlv_hdr; + struct cmdq_modify_roce_cc base_req; + __le64 tlvpad; + struct cmdq_modify_roce_cc_gen1_tlv ext_req; +}; + +struct bnxt_qplib_tlv_query_rcc_sb { + struct roce_tlv tlv_hdr; + struct creq_query_roce_cc_resp_sb base_sb; + struct creq_query_roce_cc_gen1_resp_sb_tlv gen1_sb; +}; +#endif /* __QPLIB_TLV_H__ */ diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index ecb719098b75..4a10303e0392 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -42,1505 +42,1334 @@ /* include bnxt_hsi.h from bnxt_en driver */ #include "bnxt_hsi.h" -/* CMP Door Bell Format (4 bytes) */ +/* tx_doorbell (size:32b/4B) */ +struct tx_doorbell { + __le32 key_idx; + #define TX_DOORBELL_IDX_MASK 0xffffffUL + #define TX_DOORBELL_IDX_SFT 0 + #define TX_DOORBELL_KEY_MASK 0xf0000000UL + #define TX_DOORBELL_KEY_SFT 28 + #define TX_DOORBELL_KEY_TX (0x0UL << 28) + #define TX_DOORBELL_KEY_LAST TX_DOORBELL_KEY_TX +}; + +/* rx_doorbell (size:32b/4B) */ +struct rx_doorbell { + __le32 key_idx; + #define RX_DOORBELL_IDX_MASK 0xffffffUL + #define RX_DOORBELL_IDX_SFT 0 + #define RX_DOORBELL_KEY_MASK 0xf0000000UL + #define RX_DOORBELL_KEY_SFT 28 + #define RX_DOORBELL_KEY_RX (0x1UL << 28) + #define RX_DOORBELL_KEY_LAST RX_DOORBELL_KEY_RX +}; + +/* cmpl_doorbell (size:32b/4B) */ struct cmpl_doorbell { - __le32 key_mask_valid_idx; - #define CMPL_DOORBELL_IDX_MASK 0xffffffUL - #define CMPL_DOORBELL_IDX_SFT 0 - #define CMPL_DOORBELL_RESERVED_MASK 0x3000000UL - #define CMPL_DOORBELL_RESERVED_SFT 24 - #define CMPL_DOORBELL_IDX_VALID 0x4000000UL - #define CMPL_DOORBELL_MASK 0x8000000UL - #define CMPL_DOORBELL_KEY_MASK 0xf0000000UL - #define CMPL_DOORBELL_KEY_SFT 28 - #define CMPL_DOORBELL_KEY_CMPL (0x2UL << 28) + __le32 key_mask_valid_idx; + #define CMPL_DOORBELL_IDX_MASK 0xffffffUL + #define CMPL_DOORBELL_IDX_SFT 0 + #define CMPL_DOORBELL_IDX_VALID 0x4000000UL + #define CMPL_DOORBELL_MASK 0x8000000UL + #define CMPL_DOORBELL_KEY_MASK 0xf0000000UL + #define CMPL_DOORBELL_KEY_SFT 28 + #define CMPL_DOORBELL_KEY_CMPL (0x2UL << 28) + #define CMPL_DOORBELL_KEY_LAST CMPL_DOORBELL_KEY_CMPL }; -/* Status Door Bell Format (4 bytes) */ +/* status_doorbell (size:32b/4B) */ struct status_doorbell { - __le32 key_idx; - #define STATUS_DOORBELL_IDX_MASK 0xffffffUL - #define STATUS_DOORBELL_IDX_SFT 0 - #define STATUS_DOORBELL_RESERVED_MASK 0xf000000UL - #define STATUS_DOORBELL_RESERVED_SFT 24 - #define STATUS_DOORBELL_KEY_MASK 0xf0000000UL - #define STATUS_DOORBELL_KEY_SFT 28 - #define STATUS_DOORBELL_KEY_STAT (0x3UL << 28) + __le32 key_idx; + #define STATUS_DOORBELL_IDX_MASK 0xffffffUL + #define STATUS_DOORBELL_IDX_SFT 0 + #define STATUS_DOORBELL_KEY_MASK 0xf0000000UL + #define STATUS_DOORBELL_KEY_SFT 28 + #define STATUS_DOORBELL_KEY_STAT (0x3UL << 28) + #define STATUS_DOORBELL_KEY_LAST STATUS_DOORBELL_KEY_STAT }; -/* RoCE Host Structures */ - -/* Doorbell Structures */ -/* dbc_dbc (size:64b/8B) */ -struct dbc_dbc { - __le32 index; - #define DBC_DBC_INDEX_MASK 0xffffffUL - #define DBC_DBC_INDEX_SFT 0 - __le32 type_path_xid; - #define DBC_DBC_XID_MASK 0xfffffUL - #define DBC_DBC_XID_SFT 0 - #define DBC_DBC_PATH_MASK 0x3000000UL - #define DBC_DBC_PATH_SFT 24 - #define DBC_DBC_PATH_ROCE (0x0UL << 24) - #define DBC_DBC_PATH_L2 (0x1UL << 24) - #define DBC_DBC_PATH_ENGINE (0x2UL << 24) - #define DBC_DBC_PATH_LAST DBC_DBC_PATH_ENGINE - #define DBC_DBC_DEBUG_TRACE 0x8000000UL - #define DBC_DBC_TYPE_MASK 0xf0000000UL - #define DBC_DBC_TYPE_SFT 28 - #define DBC_DBC_TYPE_SQ (0x0UL << 28) - #define DBC_DBC_TYPE_RQ (0x1UL << 28) - #define DBC_DBC_TYPE_SRQ (0x2UL << 28) - #define DBC_DBC_TYPE_SRQ_ARM (0x3UL << 28) - #define DBC_DBC_TYPE_CQ (0x4UL << 28) - #define DBC_DBC_TYPE_CQ_ARMSE (0x5UL << 28) - #define DBC_DBC_TYPE_CQ_ARMALL (0x6UL << 28) - #define DBC_DBC_TYPE_CQ_ARMENA (0x7UL << 28) - #define DBC_DBC_TYPE_SRQ_ARMENA (0x8UL << 28) - #define DBC_DBC_TYPE_CQ_CUTOFF_ACK (0x9UL << 28) - #define DBC_DBC_TYPE_NQ (0xaUL << 28) - #define DBC_DBC_TYPE_NQ_ARM (0xbUL << 28) - #define DBC_DBC_TYPE_NULL (0xfUL << 28) - #define DBC_DBC_TYPE_LAST DBC_DBC_TYPE_NULL -}; - -/* dbc_dbc32 (size:32b/4B) */ -struct dbc_dbc32 { - __le32 type_abs_incr_xid; - #define DBC_DBC32_XID_MASK 0xfffffUL - #define DBC_DBC32_XID_SFT 0 - #define DBC_DBC32_PATH_MASK 0xc00000UL - #define DBC_DBC32_PATH_SFT 22 - #define DBC_DBC32_PATH_ROCE (0x0UL << 22) - #define DBC_DBC32_PATH_L2 (0x1UL << 22) - #define DBC_DBC32_PATH_LAST DBC_DBC32_PATH_L2 - #define DBC_DBC32_INCR_MASK 0xf000000UL - #define DBC_DBC32_INCR_SFT 24 - #define DBC_DBC32_ABS 0x10000000UL - #define DBC_DBC32_TYPE_MASK 0xe0000000UL - #define DBC_DBC32_TYPE_SFT 29 - #define DBC_DBC32_TYPE_SQ (0x0UL << 29) - #define DBC_DBC32_TYPE_LAST DBC_DBC32_TYPE_SQ -}; - -/* SQ WQE Structures */ -/* Base SQ WQE (8 bytes) */ -struct sq_base { - u8 wqe_type; - #define SQ_BASE_WQE_TYPE_SEND 0x0UL - #define SQ_BASE_WQE_TYPE_SEND_W_IMMEAD 0x1UL - #define SQ_BASE_WQE_TYPE_SEND_W_INVALID 0x2UL - #define SQ_BASE_WQE_TYPE_WRITE_WQE 0x4UL - #define SQ_BASE_WQE_TYPE_WRITE_W_IMMEAD 0x5UL - #define SQ_BASE_WQE_TYPE_READ_WQE 0x6UL - #define SQ_BASE_WQE_TYPE_ATOMIC_CS 0x8UL - #define SQ_BASE_WQE_TYPE_ATOMIC_FA 0xbUL - #define SQ_BASE_WQE_TYPE_LOCAL_INVALID 0xcUL - #define SQ_BASE_WQE_TYPE_FR_PMR 0xdUL - #define SQ_BASE_WQE_TYPE_BIND 0xeUL - u8 unused_0[7]; -}; - -/* WQE SGE (16 bytes) */ -struct sq_sge { - __le64 va_or_pa; - __le32 l_key; - __le32 size; -}; - -/* PSN Search Structure (8 bytes) */ -struct sq_psn_search { - __le32 opcode_start_psn; - #define SQ_PSN_SEARCH_START_PSN_MASK 0xffffffUL - #define SQ_PSN_SEARCH_START_PSN_SFT 0 - #define SQ_PSN_SEARCH_OPCODE_MASK 0xff000000UL - #define SQ_PSN_SEARCH_OPCODE_SFT 24 - __le32 flags_next_psn; - #define SQ_PSN_SEARCH_NEXT_PSN_MASK 0xffffffUL - #define SQ_PSN_SEARCH_NEXT_PSN_SFT 0 - #define SQ_PSN_SEARCH_FLAGS_MASK 0xff000000UL - #define SQ_PSN_SEARCH_FLAGS_SFT 24 -}; - -/* sq_psn_search_ext (size:128b/16B) */ -struct sq_psn_search_ext { - __le32 opcode_start_psn; - #define SQ_PSN_SEARCH_EXT_START_PSN_MASK 0xffffffUL - #define SQ_PSN_SEARCH_EXT_START_PSN_SFT 0 - #define SQ_PSN_SEARCH_EXT_OPCODE_MASK 0xff000000UL - #define SQ_PSN_SEARCH_EXT_OPCODE_SFT 24 - __le32 flags_next_psn; - #define SQ_PSN_SEARCH_EXT_NEXT_PSN_MASK 0xffffffUL - #define SQ_PSN_SEARCH_EXT_NEXT_PSN_SFT 0 - #define SQ_PSN_SEARCH_EXT_FLAGS_MASK 0xff000000UL - #define SQ_PSN_SEARCH_EXT_FLAGS_SFT 24 - __le16 start_slot_idx; - __le16 reserved16; - __le32 reserved32; -}; - -/* Send SQ WQE (40 bytes) */ -struct sq_send { - u8 wqe_type; - #define SQ_SEND_WQE_TYPE_SEND 0x0UL - #define SQ_SEND_WQE_TYPE_SEND_W_IMMEAD 0x1UL - #define SQ_SEND_WQE_TYPE_SEND_W_INVALID 0x2UL - u8 flags; - #define SQ_SEND_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_SEND_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_SEND_FLAGS_UC_FENCE 0x4UL - #define SQ_SEND_FLAGS_SE 0x8UL - #define SQ_SEND_FLAGS_INLINE 0x10UL - u8 wqe_size; - u8 reserved8_1; - __le32 inv_key_or_imm_data; - __le32 length; - __le32 q_key; - __le32 dst_qp; - #define SQ_SEND_DST_QP_MASK 0xffffffUL - #define SQ_SEND_DST_QP_SFT 0 - #define SQ_SEND_RESERVED8_2_MASK 0xff000000UL - #define SQ_SEND_RESERVED8_2_SFT 24 - __le32 avid; - #define SQ_SEND_AVID_MASK 0xfffffUL - #define SQ_SEND_AVID_SFT 0 - #define SQ_SEND_RESERVED_AVID_MASK 0xfff00000UL - #define SQ_SEND_RESERVED_AVID_SFT 20 - __le64 reserved64; - __le32 data[24]; -}; - -/* sq_send_hdr (size:256b/32B) */ -struct sq_send_hdr { - u8 wqe_type; - u8 flags; - u8 wqe_size; - u8 reserved8_1; - __le32 inv_key_or_imm_data; - __le32 length; - __le32 q_key; - __le32 dst_qp; - __le32 avid; - __le64 reserved64; -}; - -/* Send Raw Ethernet and QP1 SQ WQE (40 bytes) */ -struct sq_send_raweth_qp1 { - u8 wqe_type; - #define SQ_SEND_RAWETH_QP1_WQE_TYPE_SEND 0x0UL - u8 flags; - #define SQ_SEND_RAWETH_QP1_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_SEND_RAWETH_QP1_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_SEND_RAWETH_QP1_FLAGS_UC_FENCE 0x4UL - #define SQ_SEND_RAWETH_QP1_FLAGS_SE 0x8UL - #define SQ_SEND_RAWETH_QP1_FLAGS_INLINE 0x10UL - u8 wqe_size; - u8 reserved8; - __le16 lflags; - #define SQ_SEND_RAWETH_QP1_LFLAGS_TCP_UDP_CHKSUM 0x1UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_IP_CHKSUM 0x2UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_NOCRC 0x4UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_STAMP 0x8UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_T_IP_CHKSUM 0x10UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_RESERVED1_1 0x20UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_RESERVED1_2 0x40UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_RESERVED1_3 0x80UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_ROCE_CRC 0x100UL - #define SQ_SEND_RAWETH_QP1_LFLAGS_FCOE_CRC 0x200UL - __le16 cfa_action; - __le32 length; - __le32 reserved32_1; - __le32 cfa_meta; - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_VID_MASK 0xfffUL - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_VID_SFT 0 - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_DE 0x1000UL - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_PRI_MASK 0xe000UL - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_PRI_SFT 13 - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_MASK 0x70000UL - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_SFT 16 - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID88A8 (0x0UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID8100 (0x1UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9100 (0x2UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9200 (0x3UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9300 (0x4UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPIDCFG (0x5UL << 16) - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_LAST \ - SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPIDCFG - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_RESERVED_MASK 0xff80000UL - #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_RESERVED_SFT 19 - #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_MASK 0xf0000000UL - #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_SFT 28 - #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_NONE (0x0UL << 28) - #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_VLAN_TAG (0x1UL << 28) - #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_LAST \ - SQ_SEND_RAWETH_QP1_CFA_META_KEY_VLAN_TAG - __le32 reserved32_2; - __le64 reserved64; - __le32 data[24]; -}; - -/* sq_send_raweth_qp1_hdr (size:256b/32B) */ -struct sq_send_raweth_qp1_hdr { - u8 wqe_type; - u8 flags; - u8 wqe_size; - u8 reserved8; - __le16 lflags; - __le16 cfa_action; - __le32 length; - __le32 reserved32_1; - __le32 cfa_meta; - __le32 reserved32_2; - __le64 reserved64; -}; - -/* RDMA SQ WQE (40 bytes) */ -struct sq_rdma { - u8 wqe_type; - #define SQ_RDMA_WQE_TYPE_WRITE_WQE 0x4UL - #define SQ_RDMA_WQE_TYPE_WRITE_W_IMMEAD 0x5UL - #define SQ_RDMA_WQE_TYPE_READ_WQE 0x6UL - u8 flags; - #define SQ_RDMA_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_RDMA_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_RDMA_FLAGS_UC_FENCE 0x4UL - #define SQ_RDMA_FLAGS_SE 0x8UL - #define SQ_RDMA_FLAGS_INLINE 0x10UL - u8 wqe_size; - u8 reserved8; - __le32 imm_data; - __le32 length; - __le32 reserved32_1; - __le64 remote_va; - __le32 remote_key; - __le32 reserved32_2; - __le32 data[24]; -}; - -/* sq_rdma_hdr (size:256b/32B) */ -struct sq_rdma_hdr { - u8 wqe_type; - u8 flags; - u8 wqe_size; - u8 reserved8; - __le32 imm_data; - __le32 length; - __le32 reserved32_1; - __le64 remote_va; - __le32 remote_key; - __le32 reserved32_2; -}; - -/* Atomic SQ WQE (40 bytes) */ -struct sq_atomic { - u8 wqe_type; - #define SQ_ATOMIC_WQE_TYPE_ATOMIC_CS 0x8UL - #define SQ_ATOMIC_WQE_TYPE_ATOMIC_FA 0xbUL - u8 flags; - #define SQ_ATOMIC_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_ATOMIC_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_ATOMIC_FLAGS_UC_FENCE 0x4UL - #define SQ_ATOMIC_FLAGS_SE 0x8UL - #define SQ_ATOMIC_FLAGS_INLINE 0x10UL - __le16 reserved16; - __le32 remote_key; - __le64 remote_va; - __le64 swap_data; - __le64 cmp_data; - __le32 data[24]; -}; - -/* sq_atomic_hdr (size:256b/32B) */ -struct sq_atomic_hdr { - u8 wqe_type; - u8 flags; - __le16 reserved16; - __le32 remote_key; - __le64 remote_va; - __le64 swap_data; - __le64 cmp_data; -}; - -/* Local Invalidate SQ WQE (40 bytes) */ -struct sq_localinvalidate { - u8 wqe_type; - #define SQ_LOCALINVALIDATE_WQE_TYPE_LOCAL_INVALID 0xcUL - u8 flags; - #define SQ_LOCALINVALIDATE_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_LOCALINVALIDATE_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_LOCALINVALIDATE_FLAGS_UC_FENCE 0x4UL - #define SQ_LOCALINVALIDATE_FLAGS_SE 0x8UL - #define SQ_LOCALINVALIDATE_FLAGS_INLINE 0x10UL - __le16 reserved16; - __le32 inv_l_key; - __le64 reserved64; - __le32 reserved128[4]; - __le32 data[24]; -}; - -/* sq_localinvalidate_hdr (size:256b/32B) */ -struct sq_localinvalidate_hdr { - u8 wqe_type; - u8 flags; - __le16 reserved16; - __le32 inv_l_key; - __le64 reserved64; - u8 reserved128[16]; -}; - -/* FR-PMR SQ WQE (40 bytes) */ -struct sq_fr_pmr { - u8 wqe_type; - #define SQ_FR_PMR_WQE_TYPE_FR_PMR 0xdUL - u8 flags; - #define SQ_FR_PMR_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_FR_PMR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_FR_PMR_FLAGS_UC_FENCE 0x4UL - #define SQ_FR_PMR_FLAGS_SE 0x8UL - #define SQ_FR_PMR_FLAGS_INLINE 0x10UL - u8 access_cntl; - #define SQ_FR_PMR_ACCESS_CNTL_LOCAL_WRITE 0x1UL - #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_READ 0x2UL - #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_WRITE 0x4UL - #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL - #define SQ_FR_PMR_ACCESS_CNTL_WINDOW_BIND 0x10UL - u8 zero_based_page_size_log; - #define SQ_FR_PMR_PAGE_SIZE_LOG_MASK 0x1fUL - #define SQ_FR_PMR_PAGE_SIZE_LOG_SFT 0 - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4K 0x0UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8K 0x1UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_64K 0x4UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_256K 0x6UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_1M 0x8UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_2M 0x9UL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4M 0xaUL - #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_1G 0x12UL - #define SQ_FR_PMR_ZERO_BASED 0x20UL - #define SQ_FR_PMR_RESERVED2_MASK 0xc0UL - #define SQ_FR_PMR_RESERVED2_SFT 6 - __le32 l_key; - u8 length[5]; - u8 reserved8_1; - u8 reserved8_2; - u8 numlevels_pbl_page_size_log; - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_MASK 0x1fUL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_SFT 0 - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4K 0x0UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8K 0x1UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_64K 0x4UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_256K 0x6UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_1M 0x8UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_2M 0x9UL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4M 0xaUL - #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_1G 0x12UL - #define SQ_FR_PMR_RESERVED1 0x20UL - #define SQ_FR_PMR_NUMLEVELS_MASK 0xc0UL - #define SQ_FR_PMR_NUMLEVELS_SFT 6 - #define SQ_FR_PMR_NUMLEVELS_PHYSICAL (0x0UL << 6) - #define SQ_FR_PMR_NUMLEVELS_LAYER1 (0x1UL << 6) - #define SQ_FR_PMR_NUMLEVELS_LAYER2 (0x2UL << 6) - __le64 pblptr; - __le64 va; - __le32 data[24]; -}; - -/* sq_fr_pmr_hdr (size:256b/32B) */ -struct sq_fr_pmr_hdr { - u8 wqe_type; - u8 flags; - u8 access_cntl; - u8 zero_based_page_size_log; - __le32 l_key; - u8 length[5]; - u8 reserved8_1; - u8 reserved8_2; - u8 numlevels_pbl_page_size_log; - __le64 pblptr; - __le64 va; -}; - -/* Bind SQ WQE (40 bytes) */ -struct sq_bind { - u8 wqe_type; - #define SQ_BIND_WQE_TYPE_BIND 0xeUL - u8 flags; - #define SQ_BIND_FLAGS_SIGNAL_COMP 0x1UL - #define SQ_BIND_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL - #define SQ_BIND_FLAGS_UC_FENCE 0x4UL - #define SQ_BIND_FLAGS_SE 0x8UL - #define SQ_BIND_FLAGS_INLINE 0x10UL - u8 access_cntl; - #define SQ_BIND_ACCESS_CNTL_LOCAL_WRITE 0x1UL - #define SQ_BIND_ACCESS_CNTL_REMOTE_READ 0x2UL - #define SQ_BIND_ACCESS_CNTL_REMOTE_WRITE 0x4UL - #define SQ_BIND_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL - #define SQ_BIND_ACCESS_CNTL_WINDOW_BIND 0x10UL - u8 reserved8_1; - u8 mw_type_zero_based; - #define SQ_BIND_ZERO_BASED 0x1UL - #define SQ_BIND_MW_TYPE 0x2UL - #define SQ_BIND_MW_TYPE_TYPE1 (0x0UL << 1) - #define SQ_BIND_MW_TYPE_TYPE2 (0x1UL << 1) - #define SQ_BIND_RESERVED6_MASK 0xfcUL - #define SQ_BIND_RESERVED6_SFT 2 - u8 reserved8_2; - __le16 reserved16; - __le32 parent_l_key; - __le32 l_key; - __le64 va; - u8 length[5]; - u8 data_reserved24[99]; - #define SQ_BIND_RESERVED24_MASK 0xffffff00UL - #define SQ_BIND_RESERVED24_SFT 8 - #define SQ_BIND_DATA_MASK 0xffffffffUL - #define SQ_BIND_DATA_SFT 0 -}; - -/* sq_bind_hdr (size:256b/32B) */ -struct sq_bind_hdr { - u8 wqe_type; - u8 flags; - u8 access_cntl; - u8 reserved8_1; - u8 mw_type_zero_based; - u8 reserved8_2; - __le16 reserved16; - __le32 parent_l_key; - __le32 l_key; - __le64 va; - u8 length[5]; - u8 reserved24[3]; -}; - -/* RQ/SRQ WQE Structures */ -/* RQ/SRQ WQE (40 bytes) */ -struct rq_wqe { - u8 wqe_type; - #define RQ_WQE_WQE_TYPE_RCV 0x80UL - u8 flags; - u8 wqe_size; - u8 reserved8; - __le32 reserved32; - __le32 wr_id[2]; - #define RQ_WQE_WR_ID_MASK 0xfffffUL - #define RQ_WQE_WR_ID_SFT 0 - #define RQ_WQE_RESERVED44_MASK 0xfff00000UL - #define RQ_WQE_RESERVED44_SFT 20 - __le32 reserved128[4]; - __le32 data[24]; -}; - -/* rq_wqe_hdr (size:256b/32B) */ -struct rq_wqe_hdr { - u8 wqe_type; - u8 flags; - u8 wqe_size; - u8 reserved8; - __le32 reserved32; - __le32 wr_id[2]; - u8 reserved128[16]; -}; - -/* CQ CQE Structures */ -/* Base CQE (32 bytes) */ -struct cq_base { - __le64 reserved64_1; - __le64 reserved64_2; - __le64 reserved64_3; - u8 cqe_type_toggle; - #define CQ_BASE_TOGGLE 0x1UL - #define CQ_BASE_CQE_TYPE_MASK 0x1eUL - #define CQ_BASE_CQE_TYPE_SFT 1 - #define CQ_BASE_CQE_TYPE_REQ (0x0UL << 1) - #define CQ_BASE_CQE_TYPE_RES_RC (0x1UL << 1) - #define CQ_BASE_CQE_TYPE_RES_UD (0x2UL << 1) - #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) - #define CQ_BASE_CQE_TYPE_TERMINAL (0xeUL << 1) - #define CQ_BASE_CQE_TYPE_CUT_OFF (0xfUL << 1) - #define CQ_BASE_RESERVED3_MASK 0xe0UL - #define CQ_BASE_RESERVED3_SFT 5 - u8 status; - __le16 reserved16; - __le32 reserved32; -}; - -/* Requester CQ CQE (32 bytes) */ -struct cq_req { - __le64 qp_handle; - __le16 sq_cons_idx; - __le16 reserved16_1; - __le32 reserved32_2; - __le64 reserved64; - u8 cqe_type_toggle; - #define CQ_REQ_TOGGLE 0x1UL - #define CQ_REQ_CQE_TYPE_MASK 0x1eUL - #define CQ_REQ_CQE_TYPE_SFT 1 - #define CQ_REQ_CQE_TYPE_REQ (0x0UL << 1) - #define CQ_REQ_RESERVED3_MASK 0xe0UL - #define CQ_REQ_RESERVED3_SFT 5 - u8 status; - #define CQ_REQ_STATUS_OK 0x0UL - #define CQ_REQ_STATUS_BAD_RESPONSE_ERR 0x1UL - #define CQ_REQ_STATUS_LOCAL_LENGTH_ERR 0x2UL - #define CQ_REQ_STATUS_LOCAL_QP_OPERATION_ERR 0x3UL - #define CQ_REQ_STATUS_LOCAL_PROTECTION_ERR 0x4UL - #define CQ_REQ_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL - #define CQ_REQ_STATUS_REMOTE_INVALID_REQUEST_ERR 0x6UL - #define CQ_REQ_STATUS_REMOTE_ACCESS_ERR 0x7UL - #define CQ_REQ_STATUS_REMOTE_OPERATION_ERR 0x8UL - #define CQ_REQ_STATUS_RNR_NAK_RETRY_CNT_ERR 0x9UL - #define CQ_REQ_STATUS_TRANSPORT_RETRY_CNT_ERR 0xaUL - #define CQ_REQ_STATUS_WORK_REQUEST_FLUSHED_ERR 0xbUL - __le16 reserved16_2; - __le32 reserved32_1; -}; - -/* Responder RC CQE (32 bytes) */ -struct cq_res_rc { - __le32 length; - __le32 imm_data_or_inv_r_key; - __le64 qp_handle; - __le64 mr_handle; - u8 cqe_type_toggle; - #define CQ_RES_RC_TOGGLE 0x1UL - #define CQ_RES_RC_CQE_TYPE_MASK 0x1eUL - #define CQ_RES_RC_CQE_TYPE_SFT 1 - #define CQ_RES_RC_CQE_TYPE_RES_RC (0x1UL << 1) - #define CQ_RES_RC_RESERVED3_MASK 0xe0UL - #define CQ_RES_RC_RESERVED3_SFT 5 - u8 status; - #define CQ_RES_RC_STATUS_OK 0x0UL - #define CQ_RES_RC_STATUS_LOCAL_ACCESS_ERROR 0x1UL - #define CQ_RES_RC_STATUS_LOCAL_LENGTH_ERR 0x2UL - #define CQ_RES_RC_STATUS_LOCAL_PROTECTION_ERR 0x3UL - #define CQ_RES_RC_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL - #define CQ_RES_RC_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL - #define CQ_RES_RC_STATUS_REMOTE_INVALID_REQUEST_ERR 0x6UL - #define CQ_RES_RC_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL - #define CQ_RES_RC_STATUS_HW_FLUSH_ERR 0x8UL - __le16 flags; - #define CQ_RES_RC_FLAGS_SRQ 0x1UL - #define CQ_RES_RC_FLAGS_SRQ_RQ (0x0UL << 0) - #define CQ_RES_RC_FLAGS_SRQ_SRQ (0x1UL << 0) - #define CQ_RES_RC_FLAGS_SRQ_LAST CQ_RES_RC_FLAGS_SRQ_SRQ - #define CQ_RES_RC_FLAGS_IMM 0x2UL - #define CQ_RES_RC_FLAGS_INV 0x4UL - #define CQ_RES_RC_FLAGS_RDMA 0x8UL - #define CQ_RES_RC_FLAGS_RDMA_SEND (0x0UL << 3) - #define CQ_RES_RC_FLAGS_RDMA_RDMA_WRITE (0x1UL << 3) - #define CQ_RES_RC_FLAGS_RDMA_LAST CQ_RES_RC_FLAGS_RDMA_RDMA_WRITE - __le32 srq_or_rq_wr_id; - #define CQ_RES_RC_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL - #define CQ_RES_RC_SRQ_OR_RQ_WR_ID_SFT 0 - #define CQ_RES_RC_RESERVED12_MASK 0xfff00000UL - #define CQ_RES_RC_RESERVED12_SFT 20 -}; - -/* Responder UD CQE (32 bytes) */ -struct cq_res_ud { - __le16 length; - #define CQ_RES_UD_LENGTH_MASK 0x3fffUL - #define CQ_RES_UD_LENGTH_SFT 0 - __le16 cfa_metadata; - #define CQ_RES_UD_CFA_METADATA_VID_MASK 0xfffUL - #define CQ_RES_UD_CFA_METADATA_VID_SFT 0 - #define CQ_RES_UD_CFA_METADATA_DE 0x1000UL - #define CQ_RES_UD_CFA_METADATA_PRI_MASK 0xe000UL - #define CQ_RES_UD_CFA_METADATA_PRI_SFT 13 - __le32 imm_data; - __le64 qp_handle; - __le16 src_mac[3]; - __le16 src_qp_low; - u8 cqe_type_toggle; - #define CQ_RES_UD_TOGGLE 0x1UL - #define CQ_RES_UD_CQE_TYPE_MASK 0x1eUL - #define CQ_RES_UD_CQE_TYPE_SFT 1 - #define CQ_RES_UD_CQE_TYPE_RES_UD (0x2UL << 1) - u8 status; - #define CQ_RES_UD_STATUS_OK 0x0UL - #define CQ_RES_UD_STATUS_LOCAL_ACCESS_ERROR 0x1UL - #define CQ_RES_UD_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL - #define CQ_RES_UD_STATUS_LOCAL_PROTECTION_ERR 0x3UL - #define CQ_RES_UD_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL - #define CQ_RES_UD_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL - #define CQ_RES_UD_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL - #define CQ_RES_UD_STATUS_HW_FLUSH_ERR 0x8UL - __le16 flags; - #define CQ_RES_UD_FLAGS_SRQ 0x1UL - #define CQ_RES_UD_FLAGS_SRQ_RQ (0x0UL << 0) - #define CQ_RES_UD_FLAGS_SRQ_SRQ (0x1UL << 0) - #define CQ_RES_UD_FLAGS_SRQ_LAST CQ_RES_UD_FLAGS_SRQ_SRQ - #define CQ_RES_UD_FLAGS_IMM 0x2UL - #define CQ_RES_UD_FLAGS_UNUSED_MASK 0xcUL - #define CQ_RES_UD_FLAGS_UNUSED_SFT 2 - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_MASK 0x30UL - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_SFT 4 - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V1 (0x0UL << 4) - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV4 (0x2UL << 4) - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV6 (0x3UL << 4) - #define CQ_RES_UD_FLAGS_ROCE_IP_VER_LAST \ - CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV6 - #define CQ_RES_UD_FLAGS_META_FORMAT_MASK 0x3c0UL - #define CQ_RES_UD_FLAGS_META_FORMAT_SFT 6 - #define CQ_RES_UD_FLAGS_META_FORMAT_NONE (0x0UL << 6) - #define CQ_RES_UD_FLAGS_META_FORMAT_VLAN (0x1UL << 6) - #define CQ_RES_UD_FLAGS_META_FORMAT_TUNNEL_ID (0x2UL << 6) - #define CQ_RES_UD_FLAGS_META_FORMAT_CHDR_DATA (0x3UL << 6) - #define CQ_RES_UD_FLAGS_META_FORMAT_HDR_OFFSET (0x4UL << 6) - #define CQ_RES_UD_FLAGS_META_FORMAT_LAST \ - CQ_RES_UD_FLAGS_META_FORMAT_HDR_OFFSET - #define CQ_RES_UD_FLAGS_EXT_META_FORMAT_MASK 0xc00UL - #define CQ_RES_UD_FLAGS_EXT_META_FORMAT_SFT 10 - - __le32 src_qp_high_srq_or_rq_wr_id; - #define CQ_RES_UD_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL - #define CQ_RES_UD_SRQ_OR_RQ_WR_ID_SFT 0 - #define CQ_RES_UD_SRC_QP_HIGH_MASK 0xff000000UL - #define CQ_RES_UD_SRC_QP_HIGH_SFT 24 -}; - -/* Responder RawEth and QP1 CQE (32 bytes) */ -struct cq_res_raweth_qp1 { - __le16 length; - #define CQ_RES_RAWETH_QP1_LENGTH_MASK 0x3fffUL - #define CQ_RES_RAWETH_QP1_LENGTH_SFT 0 - #define CQ_RES_RAWETH_QP1_RESERVED2_MASK 0xc000UL - #define CQ_RES_RAWETH_QP1_RESERVED2_SFT 14 - __le16 raweth_qp1_flags; - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ERROR 0x1UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_RESERVED5_1_MASK 0x3eUL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_RESERVED5_1_SFT 1 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_MASK 0x3c0UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_SFT 6 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_NOT_KNOWN (0x0UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_IP (0x1UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_TCP (0x2UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_UDP (0x3UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_FCOE (0x4UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_ROCE (0x5UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_ICMP (0x7UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_WO_TIMESTAMP \ - (0x8UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP \ - (0x9UL << 6) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_LAST \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_MASK 0x3ffUL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_SFT 0 - #define CQ_RES_RAWETH_QP1_RESERVED6_MASK 0xfc00UL - #define CQ_RES_RAWETH_QP1_RESERVED6_SFT 10 - __le16 raweth_qp1_errors; - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_RESERVED4_MASK 0xfUL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_RESERVED4_SFT 0 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_IP_CS_ERROR 0x10UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_L4_CS_ERROR 0x20UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_IP_CS_ERROR 0x40UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_L4_CS_ERROR 0x80UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_CRC_ERROR 0x100UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_MASK 0xe00UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_SFT 9 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_NO_ERROR \ - (0x0UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION \ - (0x1UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN \ - (0x2UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_TUNNEL_TOTAL_ERROR \ - (0x3UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR \ - (0x4UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR \ - (0x5UL << 9) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL \ - (0x6UL << 9) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_LAST \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_MASK 0xf000UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_SFT 12 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_NO_ERROR \ - (0x0UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_VERSION \ - (0x1UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN \ - (0x2UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_TTL \ - (0x3UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_IP_TOTAL_ERROR \ - (0x4UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR \ - (0x5UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN \ - (0x6UL << 12) - #define \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL\ - (0x7UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN \ - (0x8UL << 12) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_LAST \ - CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN - __le16 raweth_qp1_cfa_code; - __le64 qp_handle; - __le32 raweth_qp1_flags2; - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_IP_CS_CALC 0x1UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_L4_CS_CALC 0x2UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_T_IP_CS_CALC 0x4UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_T_L4_CS_CALC 0x8UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_MASK 0xf0UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_SFT 4 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_NONE \ - (0x0UL << 4) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_VLAN \ - (0x1UL << 4) - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_LAST\ - CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_VLAN - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_IP_TYPE 0x100UL - __le32 raweth_qp1_metadata; - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_VID_MASK 0xfffUL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_VID_SFT 0 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_DE 0x1000UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_MASK 0xe000UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_SFT 13 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_TPID_MASK 0xffff0000UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_TPID_SFT 16 - u8 cqe_type_toggle; - #define CQ_RES_RAWETH_QP1_TOGGLE 0x1UL - #define CQ_RES_RAWETH_QP1_CQE_TYPE_MASK 0x1eUL - #define CQ_RES_RAWETH_QP1_CQE_TYPE_SFT 1 - #define CQ_RES_RAWETH_QP1_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) - #define CQ_RES_RAWETH_QP1_RESERVED3_MASK 0xe0UL - #define CQ_RES_RAWETH_QP1_RESERVED3_SFT 5 - u8 status; - #define CQ_RES_RAWETH_QP1_STATUS_OK 0x0UL - #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_ACCESS_ERROR 0x1UL - #define CQ_RES_RAWETH_QP1_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL - #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_PROTECTION_ERR 0x3UL - #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL - #define CQ_RES_RAWETH_QP1_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL - #define CQ_RES_RAWETH_QP1_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL - #define CQ_RES_RAWETH_QP1_STATUS_HW_FLUSH_ERR 0x8UL - __le16 flags; - #define CQ_RES_RAWETH_QP1_FLAGS_SRQ 0x1UL - #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_RQ 0x0UL - #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_SRQ 0x1UL - #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_LAST \ - CQ_RES_RAWETH_QP1_FLAGS_SRQ_SRQ - __le32 raweth_qp1_payload_offset_srq_or_rq_wr_id; - #define CQ_RES_RAWETH_QP1_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL - #define CQ_RES_RAWETH_QP1_SRQ_OR_RQ_WR_ID_SFT 0 - #define CQ_RES_RAWETH_QP1_RESERVED4_MASK 0xf00000UL - #define CQ_RES_RAWETH_QP1_RESERVED4_SFT 20 - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_PAYLOAD_OFFSET_MASK 0xff000000UL - #define CQ_RES_RAWETH_QP1_RAWETH_QP1_PAYLOAD_OFFSET_SFT 24 -}; - -/* Terminal CQE (32 bytes) */ -struct cq_terminal { - __le64 qp_handle; - __le16 sq_cons_idx; - __le16 rq_cons_idx; - __le32 reserved32_1; - __le64 reserved64_3; - u8 cqe_type_toggle; - #define CQ_TERMINAL_TOGGLE 0x1UL - #define CQ_TERMINAL_CQE_TYPE_MASK 0x1eUL - #define CQ_TERMINAL_CQE_TYPE_SFT 1 - #define CQ_TERMINAL_CQE_TYPE_TERMINAL (0xeUL << 1) - #define CQ_TERMINAL_RESERVED3_MASK 0xe0UL - #define CQ_TERMINAL_RESERVED3_SFT 5 - u8 status; - #define CQ_TERMINAL_STATUS_OK 0x0UL - __le16 reserved16; - __le32 reserved32_2; -}; - -/* Cutoff CQE (32 bytes) */ -struct cq_cutoff { - __le64 reserved64_1; - __le64 reserved64_2; - __le64 reserved64_3; - u8 cqe_type_toggle; - #define CQ_CUTOFF_TOGGLE 0x1UL - #define CQ_CUTOFF_CQE_TYPE_MASK 0x1eUL - #define CQ_CUTOFF_CQE_TYPE_SFT 1 - #define CQ_CUTOFF_CQE_TYPE_CUT_OFF (0xfUL << 1) - #define CQ_CUTOFF_RESERVED3_MASK 0xe0UL - #define CQ_CUTOFF_RESERVED3_SFT 5 - u8 status; - #define CQ_CUTOFF_STATUS_OK 0x0UL - __le16 reserved16; - __le32 reserved32; -}; - -/* Notification Queue (NQ) Structures */ -/* Base NQ Record (16 bytes) */ -struct nq_base { - __le16 info10_type; - #define NQ_BASE_TYPE_MASK 0x3fUL - #define NQ_BASE_TYPE_SFT 0 - #define NQ_BASE_TYPE_CQ_NOTIFICATION 0x30UL - #define NQ_BASE_TYPE_SRQ_EVENT 0x32UL - #define NQ_BASE_TYPE_DBQ_EVENT 0x34UL - #define NQ_BASE_TYPE_QP_EVENT 0x38UL - #define NQ_BASE_TYPE_FUNC_EVENT 0x3aUL - #define NQ_BASE_INFO10_MASK 0xffc0UL - #define NQ_BASE_INFO10_SFT 6 - __le16 info16; - __le32 info32; - __le32 info63_v[2]; - #define NQ_BASE_V 0x1UL - #define NQ_BASE_INFO63_MASK 0xfffffffeUL - #define NQ_BASE_INFO63_SFT 1 -}; - -/* Completion Queue Notification (16 bytes) */ -struct nq_cn { - __le16 type; - #define NQ_CN_TYPE_MASK 0x3fUL - #define NQ_CN_TYPE_SFT 0 - #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL - #define NQ_CN_RESERVED9_MASK 0xffc0UL - #define NQ_CN_RESERVED9_SFT 6 - __le16 reserved16; - __le32 cq_handle_low; - __le32 v; - #define NQ_CN_V 0x1UL - #define NQ_CN_RESERVED31_MASK 0xfffffffeUL - #define NQ_CN_RESERVED31_SFT 1 - __le32 cq_handle_high; -}; - -/* SRQ Event Notification (16 bytes) */ -struct nq_srq_event { - u8 type; - #define NQ_SRQ_EVENT_TYPE_MASK 0x3fUL - #define NQ_SRQ_EVENT_TYPE_SFT 0 - #define NQ_SRQ_EVENT_TYPE_SRQ_EVENT 0x32UL - #define NQ_SRQ_EVENT_RESERVED1_MASK 0xc0UL - #define NQ_SRQ_EVENT_RESERVED1_SFT 6 - u8 event; - #define NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT 0x1UL - __le16 reserved16; - __le32 srq_handle_low; - __le32 v; - #define NQ_SRQ_EVENT_V 0x1UL - #define NQ_SRQ_EVENT_RESERVED31_MASK 0xfffffffeUL - #define NQ_SRQ_EVENT_RESERVED31_SFT 1 - __le32 srq_handle_high; -}; - -/* DBQ Async Event Notification (16 bytes) */ -struct nq_dbq_event { - u8 type; - #define NQ_DBQ_EVENT_TYPE_MASK 0x3fUL - #define NQ_DBQ_EVENT_TYPE_SFT 0 - #define NQ_DBQ_EVENT_TYPE_DBQ_EVENT 0x34UL - #define NQ_DBQ_EVENT_RESERVED1_MASK 0xc0UL - #define NQ_DBQ_EVENT_RESERVED1_SFT 6 - u8 event; - #define NQ_DBQ_EVENT_EVENT_DBQ_THRESHOLD_EVENT 0x1UL - __le16 db_pfid; - #define NQ_DBQ_EVENT_DB_PFID_MASK 0xfUL - #define NQ_DBQ_EVENT_DB_PFID_SFT 0 - #define NQ_DBQ_EVENT_RESERVED12_MASK 0xfff0UL - #define NQ_DBQ_EVENT_RESERVED12_SFT 4 - __le32 db_dpi; - #define NQ_DBQ_EVENT_DB_DPI_MASK 0xfffffUL - #define NQ_DBQ_EVENT_DB_DPI_SFT 0 - #define NQ_DBQ_EVENT_RESERVED12_2_MASK 0xfff00000UL - #define NQ_DBQ_EVENT_RESERVED12_2_SFT 20 - __le32 v; - #define NQ_DBQ_EVENT_V 0x1UL - #define NQ_DBQ_EVENT_RESERVED32_MASK 0xfffffffeUL - #define NQ_DBQ_EVENT_RESERVED32_SFT 1 - __le32 db_type_db_xid; - #define NQ_DBQ_EVENT_DB_XID_MASK 0xfffffUL - #define NQ_DBQ_EVENT_DB_XID_SFT 0 - #define NQ_DBQ_EVENT_RESERVED8_MASK 0xff00000UL - #define NQ_DBQ_EVENT_RESERVED8_SFT 20 - #define NQ_DBQ_EVENT_DB_TYPE_MASK 0xf0000000UL - #define NQ_DBQ_EVENT_DB_TYPE_SFT 28 -}; - -/* Read Request/Response Queue Structures */ -/* Input Read Request Queue (IRRQ) Message (32 bytes) */ -struct xrrq_irrq { - __le16 credits_type; - #define XRRQ_IRRQ_TYPE 0x1UL - #define XRRQ_IRRQ_TYPE_READ_REQ 0x0UL - #define XRRQ_IRRQ_TYPE_ATOMIC_REQ 0x1UL - #define XRRQ_IRRQ_RESERVED10_MASK 0x7feUL - #define XRRQ_IRRQ_RESERVED10_SFT 1 - #define XRRQ_IRRQ_CREDITS_MASK 0xf800UL - #define XRRQ_IRRQ_CREDITS_SFT 11 - __le16 reserved16; - __le32 reserved32; - __le32 psn; - #define XRRQ_IRRQ_PSN_MASK 0xffffffUL - #define XRRQ_IRRQ_PSN_SFT 0 - #define XRRQ_IRRQ_RESERVED8_1_MASK 0xff000000UL - #define XRRQ_IRRQ_RESERVED8_1_SFT 24 - __le32 msn; - #define XRRQ_IRRQ_MSN_MASK 0xffffffUL - #define XRRQ_IRRQ_MSN_SFT 0 - #define XRRQ_IRRQ_RESERVED8_2_MASK 0xff000000UL - #define XRRQ_IRRQ_RESERVED8_2_SFT 24 - __le64 va_or_atomic_result; - __le32 rdma_r_key; - __le32 length; -}; - -/* Output Read Request Queue (ORRQ) Message (32 bytes) */ -struct xrrq_orrq { - __le16 num_sges_type; - #define XRRQ_ORRQ_TYPE 0x1UL - #define XRRQ_ORRQ_TYPE_READ_REQ 0x0UL - #define XRRQ_ORRQ_TYPE_ATOMIC_REQ 0x1UL - #define XRRQ_ORRQ_RESERVED10_MASK 0x7feUL - #define XRRQ_ORRQ_RESERVED10_SFT 1 - #define XRRQ_ORRQ_NUM_SGES_MASK 0xf800UL - #define XRRQ_ORRQ_NUM_SGES_SFT 11 - __le16 reserved16; - __le32 length; - __le32 psn; - #define XRRQ_ORRQ_PSN_MASK 0xffffffUL - #define XRRQ_ORRQ_PSN_SFT 0 - #define XRRQ_ORRQ_RESERVED8_1_MASK 0xff000000UL - #define XRRQ_ORRQ_RESERVED8_1_SFT 24 - __le32 end_psn; - #define XRRQ_ORRQ_END_PSN_MASK 0xffffffUL - #define XRRQ_ORRQ_END_PSN_SFT 0 - #define XRRQ_ORRQ_RESERVED8_2_MASK 0xff000000UL - #define XRRQ_ORRQ_RESERVED8_2_SFT 24 - __le64 first_sge_phy_or_sing_sge_va; - __le32 single_sge_l_key; - __le32 single_sge_size; -}; - -/* Page Buffer List Memory Structures (PBL) */ -/* Page Table Entry (PTE) (8 bytes) */ -struct ptu_pte { - __le32 page_next_to_last_last_valid[2]; - #define PTU_PTE_VALID 0x1UL - #define PTU_PTE_LAST 0x2UL - #define PTU_PTE_NEXT_TO_LAST 0x4UL - #define PTU_PTE_PAGE_MASK 0xfffff000UL - #define PTU_PTE_PAGE_SFT 12 -}; - -/* Page Directory Entry (PDE) (8 bytes) */ -struct ptu_pde { - __le32 page_valid[2]; - #define PTU_PDE_VALID 0x1UL - #define PTU_PDE_PAGE_MASK 0xfffff000UL - #define PTU_PDE_PAGE_SFT 12 -}; - -/* RoCE Fastpath Host Structures */ -/* Command Queue (CMDQ) Interface */ -/* Init CMDQ (16 bytes) */ +/* cmdq_init (size:128b/16B) */ struct cmdq_init { - __le64 cmdq_pbl; - __le16 cmdq_size_cmdq_lvl; - #define CMDQ_INIT_CMDQ_LVL_MASK 0x3UL - #define CMDQ_INIT_CMDQ_LVL_SFT 0 - #define CMDQ_INIT_CMDQ_SIZE_MASK 0xfffcUL - #define CMDQ_INIT_CMDQ_SIZE_SFT 2 - __le16 creq_ring_id; - __le32 prod_idx; + __le64 cmdq_pbl; + __le16 cmdq_size_cmdq_lvl; + #define CMDQ_INIT_CMDQ_LVL_MASK 0x3UL + #define CMDQ_INIT_CMDQ_LVL_SFT 0 + #define CMDQ_INIT_CMDQ_SIZE_MASK 0xfffcUL + #define CMDQ_INIT_CMDQ_SIZE_SFT 2 + __le16 creq_ring_id; + __le32 prod_idx; }; -/* Update CMDQ producer index (16 bytes) */ -struct cmdq_update { - __le64 reserved64; - __le32 reserved32; - __le32 prod_idx; -}; - -/* CMDQ common header structure (16 bytes) */ +/* cmdq_base (size:128b/16B) */ struct cmdq_base { - u8 opcode; - #define CMDQ_BASE_OPCODE_CREATE_QP 0x1UL - #define CMDQ_BASE_OPCODE_DESTROY_QP 0x2UL - #define CMDQ_BASE_OPCODE_MODIFY_QP 0x3UL - #define CMDQ_BASE_OPCODE_QUERY_QP 0x4UL - #define CMDQ_BASE_OPCODE_CREATE_SRQ 0x5UL - #define CMDQ_BASE_OPCODE_DESTROY_SRQ 0x6UL - #define CMDQ_BASE_OPCODE_QUERY_SRQ 0x8UL - #define CMDQ_BASE_OPCODE_CREATE_CQ 0x9UL - #define CMDQ_BASE_OPCODE_DESTROY_CQ 0xaUL - #define CMDQ_BASE_OPCODE_RESIZE_CQ 0xcUL - #define CMDQ_BASE_OPCODE_ALLOCATE_MRW 0xdUL - #define CMDQ_BASE_OPCODE_DEALLOCATE_KEY 0xeUL - #define CMDQ_BASE_OPCODE_REGISTER_MR 0xfUL - #define CMDQ_BASE_OPCODE_DEREGISTER_MR 0x10UL - #define CMDQ_BASE_OPCODE_ADD_GID 0x11UL - #define CMDQ_BASE_OPCODE_DELETE_GID 0x12UL - #define CMDQ_BASE_OPCODE_MODIFY_GID 0x17UL - #define CMDQ_BASE_OPCODE_QUERY_GID 0x18UL - #define CMDQ_BASE_OPCODE_CREATE_QP1 0x13UL - #define CMDQ_BASE_OPCODE_DESTROY_QP1 0x14UL - #define CMDQ_BASE_OPCODE_CREATE_AH 0x15UL - #define CMDQ_BASE_OPCODE_DESTROY_AH 0x16UL - #define CMDQ_BASE_OPCODE_INITIALIZE_FW 0x80UL - #define CMDQ_BASE_OPCODE_DEINITIALIZE_FW 0x81UL - #define CMDQ_BASE_OPCODE_STOP_FUNC 0x82UL - #define CMDQ_BASE_OPCODE_QUERY_FUNC 0x83UL - #define CMDQ_BASE_OPCODE_SET_FUNC_RESOURCES 0x84UL - #define CMDQ_BASE_OPCODE_READ_CONTEXT 0x85UL - #define CMDQ_BASE_OPCODE_VF_BACKCHANNEL_REQUEST 0x86UL - #define CMDQ_BASE_OPCODE_READ_VF_MEMORY 0x87UL - #define CMDQ_BASE_OPCODE_COMPLETE_VF_REQUEST 0x88UL - #define CMDQ_BASE_OPCODE_EXTEND_CONTEXT_ARRRAY 0x89UL - #define CMDQ_BASE_OPCODE_MAP_TC_TO_COS 0x8aUL - #define CMDQ_BASE_OPCODE_QUERY_VERSION 0x8bUL - #define CMDQ_BASE_OPCODE_MODIFY_CC 0x8cUL - #define CMDQ_BASE_OPCODE_QUERY_CC 0x8dUL - #define CMDQ_BASE_OPCODE_QUERY_ROCE_STATS 0x8eUL - #define CMDQ_BASE_OPCODE_QUERY_ROCE_STATS_EXT 0x92UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; + u8 opcode; + #define CMDQ_BASE_OPCODE_CREATE_QP 0x1UL + #define CMDQ_BASE_OPCODE_DESTROY_QP 0x2UL + #define CMDQ_BASE_OPCODE_MODIFY_QP 0x3UL + #define CMDQ_BASE_OPCODE_QUERY_QP 0x4UL + #define CMDQ_BASE_OPCODE_CREATE_SRQ 0x5UL + #define CMDQ_BASE_OPCODE_DESTROY_SRQ 0x6UL + #define CMDQ_BASE_OPCODE_QUERY_SRQ 0x8UL + #define CMDQ_BASE_OPCODE_CREATE_CQ 0x9UL + #define CMDQ_BASE_OPCODE_DESTROY_CQ 0xaUL + #define CMDQ_BASE_OPCODE_RESIZE_CQ 0xcUL + #define CMDQ_BASE_OPCODE_ALLOCATE_MRW 0xdUL + #define CMDQ_BASE_OPCODE_DEALLOCATE_KEY 0xeUL + #define CMDQ_BASE_OPCODE_REGISTER_MR 0xfUL + #define CMDQ_BASE_OPCODE_DEREGISTER_MR 0x10UL + #define CMDQ_BASE_OPCODE_ADD_GID 0x11UL + #define CMDQ_BASE_OPCODE_DELETE_GID 0x12UL + #define CMDQ_BASE_OPCODE_MODIFY_GID 0x17UL + #define CMDQ_BASE_OPCODE_QUERY_GID 0x18UL + #define CMDQ_BASE_OPCODE_CREATE_QP1 0x13UL + #define CMDQ_BASE_OPCODE_DESTROY_QP1 0x14UL + #define CMDQ_BASE_OPCODE_CREATE_AH 0x15UL + #define CMDQ_BASE_OPCODE_DESTROY_AH 0x16UL + #define CMDQ_BASE_OPCODE_INITIALIZE_FW 0x80UL + #define CMDQ_BASE_OPCODE_DEINITIALIZE_FW 0x81UL + #define CMDQ_BASE_OPCODE_STOP_FUNC 0x82UL + #define CMDQ_BASE_OPCODE_QUERY_FUNC 0x83UL + #define CMDQ_BASE_OPCODE_SET_FUNC_RESOURCES 0x84UL + #define CMDQ_BASE_OPCODE_READ_CONTEXT 0x85UL + #define CMDQ_BASE_OPCODE_VF_BACKCHANNEL_REQUEST 0x86UL + #define CMDQ_BASE_OPCODE_READ_VF_MEMORY 0x87UL + #define CMDQ_BASE_OPCODE_COMPLETE_VF_REQUEST 0x88UL + #define CMDQ_BASE_OPCODE_EXTEND_CONTEXT_ARRRAY 0x89UL + #define CMDQ_BASE_OPCODE_MAP_TC_TO_COS 0x8aUL + #define CMDQ_BASE_OPCODE_QUERY_VERSION 0x8bUL + #define CMDQ_BASE_OPCODE_MODIFY_ROCE_CC 0x8cUL + #define CMDQ_BASE_OPCODE_QUERY_ROCE_CC 0x8dUL + #define CMDQ_BASE_OPCODE_QUERY_ROCE_STATS 0x8eUL + #define CMDQ_BASE_OPCODE_SET_LINK_AGGR_MODE 0x8fUL + #define CMDQ_BASE_OPCODE_MODIFY_CQ 0x90UL + #define CMDQ_BASE_OPCODE_QUERY_QP_EXTEND 0x91UL + #define CMDQ_BASE_OPCODE_QUERY_ROCE_STATS_EXT 0x92UL + #define CMDQ_BASE_OPCODE_LAST CMDQ_BASE_OPCODE_QUERY_ROCE_STATS_EXT + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; }; -/* Create QP command (96 bytes) */ +/* creq_base (size:128b/16B) */ +struct creq_base { + u8 type; + #define CREQ_BASE_TYPE_MASK 0x3fUL + #define CREQ_BASE_TYPE_SFT 0 + #define CREQ_BASE_TYPE_QP_EVENT 0x38UL + #define CREQ_BASE_TYPE_FUNC_EVENT 0x3aUL + #define CREQ_BASE_TYPE_LAST CREQ_BASE_TYPE_FUNC_EVENT + u8 reserved56[7]; + u8 v; + #define CREQ_BASE_V 0x1UL + u8 event; + u8 reserved48[6]; +}; + +/* cmdq_query_version (size:128b/16B) */ +struct cmdq_query_version { + u8 opcode; + #define CMDQ_QUERY_VERSION_OPCODE_QUERY_VERSION 0x8bUL + #define CMDQ_QUERY_VERSION_OPCODE_LAST CMDQ_QUERY_VERSION_OPCODE_QUERY_VERSION + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; +}; + +/* creq_query_version_resp (size:128b/16B) */ +struct creq_query_version_resp { + u8 type; + #define CREQ_QUERY_VERSION_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_VERSION_RESP_TYPE_SFT 0 + #define CREQ_QUERY_VERSION_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_VERSION_RESP_TYPE_LAST CREQ_QUERY_VERSION_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + u8 fw_maj; + u8 fw_minor; + u8 fw_bld; + u8 fw_rsvd; + u8 v; + #define CREQ_QUERY_VERSION_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_VERSION_RESP_EVENT_QUERY_VERSION 0x8bUL + #define CREQ_QUERY_VERSION_RESP_EVENT_LAST \ + CREQ_QUERY_VERSION_RESP_EVENT_QUERY_VERSION + __le16 reserved16; + u8 intf_maj; + u8 intf_minor; + u8 intf_bld; + u8 intf_rsvd; +}; + +/* cmdq_initialize_fw (size:896b/112B) */ +struct cmdq_initialize_fw { + u8 opcode; + #define CMDQ_INITIALIZE_FW_OPCODE_INITIALIZE_FW 0x80UL + #define CMDQ_INITIALIZE_FW_OPCODE_LAST CMDQ_INITIALIZE_FW_OPCODE_INITIALIZE_FW + u8 cmd_size; + __le16 flags; + #define CMDQ_INITIALIZE_FW_FLAGS_MRAV_RESERVATION_SPLIT 0x1UL + #define CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED 0x2UL + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + u8 qpc_pg_size_qpc_lvl; + #define CMDQ_INITIALIZE_FW_QPC_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_QPC_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_QPC_LVL_LAST CMDQ_INITIALIZE_FW_QPC_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_LAST CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_1G + u8 mrw_pg_size_mrw_lvl; + #define CMDQ_INITIALIZE_FW_MRW_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_MRW_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_MRW_LVL_LAST CMDQ_INITIALIZE_FW_MRW_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_LAST CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_1G + u8 srq_pg_size_srq_lvl; + #define CMDQ_INITIALIZE_FW_SRQ_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_SRQ_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_SRQ_LVL_LAST CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_LAST CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_1G + u8 cq_pg_size_cq_lvl; + #define CMDQ_INITIALIZE_FW_CQ_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_CQ_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_CQ_LVL_LAST CMDQ_INITIALIZE_FW_CQ_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_LAST CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_1G + u8 tqm_pg_size_tqm_lvl; + #define CMDQ_INITIALIZE_FW_TQM_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_TQM_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_TQM_LVL_LAST CMDQ_INITIALIZE_FW_TQM_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_LAST CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_1G + u8 tim_pg_size_tim_lvl; + #define CMDQ_INITIALIZE_FW_TIM_LVL_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_TIM_LVL_SFT 0 + #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_0 0x0UL + #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_1 0x1UL + #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_2 0x2UL + #define CMDQ_INITIALIZE_FW_TIM_LVL_LAST CMDQ_INITIALIZE_FW_TIM_LVL_LVL_2 + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_MASK 0xf0UL + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_SFT 4 + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_LAST CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G + __le16 log2_dbr_pg_size; + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL + #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ + CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M + #define CMDQ_INITIALIZE_FW_RSVD_MASK 0xfff0UL + #define CMDQ_INITIALIZE_FW_RSVD_SFT 4 + __le64 qpc_page_dir; + __le64 mrw_page_dir; + __le64 srq_page_dir; + __le64 cq_page_dir; + __le64 tqm_page_dir; + __le64 tim_page_dir; + __le32 number_of_qp; + __le32 number_of_mrw; + __le32 number_of_srq; + __le32 number_of_cq; + __le32 max_qp_per_vf; + __le32 max_mrw_per_vf; + __le32 max_srq_per_vf; + __le32 max_cq_per_vf; + __le32 max_gid_per_vf; + __le32 stat_ctx_id; +}; + +/* creq_initialize_fw_resp (size:128b/16B) */ +struct creq_initialize_fw_resp { + u8 type; + #define CREQ_INITIALIZE_FW_RESP_TYPE_MASK 0x3fUL + #define CREQ_INITIALIZE_FW_RESP_TYPE_SFT 0 + #define CREQ_INITIALIZE_FW_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_INITIALIZE_FW_RESP_TYPE_LAST CREQ_INITIALIZE_FW_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_INITIALIZE_FW_RESP_V 0x1UL + u8 event; + #define CREQ_INITIALIZE_FW_RESP_EVENT_INITIALIZE_FW 0x80UL + #define CREQ_INITIALIZE_FW_RESP_EVENT_LAST \ + CREQ_INITIALIZE_FW_RESP_EVENT_INITIALIZE_FW + u8 reserved48[6]; +}; + +/* cmdq_deinitialize_fw (size:128b/16B) */ +struct cmdq_deinitialize_fw { + u8 opcode; + #define CMDQ_DEINITIALIZE_FW_OPCODE_DEINITIALIZE_FW 0x81UL + #define CMDQ_DEINITIALIZE_FW_OPCODE_LAST \ + CMDQ_DEINITIALIZE_FW_OPCODE_DEINITIALIZE_FW + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; +}; + +/* creq_deinitialize_fw_resp (size:128b/16B) */ +struct creq_deinitialize_fw_resp { + u8 type; + #define CREQ_DEINITIALIZE_FW_RESP_TYPE_MASK 0x3fUL + #define CREQ_DEINITIALIZE_FW_RESP_TYPE_SFT 0 + #define CREQ_DEINITIALIZE_FW_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DEINITIALIZE_FW_RESP_TYPE_LAST CREQ_DEINITIALIZE_FW_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_DEINITIALIZE_FW_RESP_V 0x1UL + u8 event; + #define CREQ_DEINITIALIZE_FW_RESP_EVENT_DEINITIALIZE_FW 0x81UL + #define CREQ_DEINITIALIZE_FW_RESP_EVENT_LAST \ + CREQ_DEINITIALIZE_FW_RESP_EVENT_DEINITIALIZE_FW + u8 reserved48[6]; +}; + +/* cmdq_create_qp (size:768b/96B) */ struct cmdq_create_qp { - u8 opcode; - #define CMDQ_CREATE_QP_OPCODE_CREATE_QP 0x1UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 qp_handle; - __le32 qp_flags; - #define CMDQ_CREATE_QP_QP_FLAGS_SRQ_USED 0x1UL - #define CMDQ_CREATE_QP_QP_FLAGS_FORCE_COMPLETION 0x2UL - #define CMDQ_CREATE_QP_QP_FLAGS_RESERVED_LKEY_ENABLE 0x4UL - #define CMDQ_CREATE_QP_QP_FLAGS_FR_PMR_ENABLED 0x8UL + u8 opcode; + #define CMDQ_CREATE_QP_OPCODE_CREATE_QP 0x1UL + #define CMDQ_CREATE_QP_OPCODE_LAST CMDQ_CREATE_QP_OPCODE_CREATE_QP + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 qp_handle; + __le32 qp_flags; + #define CMDQ_CREATE_QP_QP_FLAGS_SRQ_USED 0x1UL + #define CMDQ_CREATE_QP_QP_FLAGS_FORCE_COMPLETION 0x2UL + #define CMDQ_CREATE_QP_QP_FLAGS_RESERVED_LKEY_ENABLE 0x4UL + #define CMDQ_CREATE_QP_QP_FLAGS_FR_PMR_ENABLED 0x8UL #define CMDQ_CREATE_QP_QP_FLAGS_VARIABLE_SIZED_WQE_ENABLED 0x10UL + #define CMDQ_CREATE_QP_QP_FLAGS_OPTIMIZED_TRANSMIT_ENABLED 0x20UL + #define CMDQ_CREATE_QP_QP_FLAGS_RESPONDER_UD_CQE_WITH_CFA 0x40UL #define CMDQ_CREATE_QP_QP_FLAGS_EXT_STATS_ENABLED 0x80UL - #define CMDQ_CREATE_QP_QP_FLAGS_LAST \ + #define CMDQ_CREATE_QP_QP_FLAGS_LAST \ CMDQ_CREATE_QP_QP_FLAGS_EXT_STATS_ENABLED - - u8 type; - #define CMDQ_CREATE_QP_TYPE_RC 0x2UL - #define CMDQ_CREATE_QP_TYPE_UD 0x4UL - #define CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE 0x6UL - #define CMDQ_CREATE_QP_TYPE_GSI 0x7UL - u8 sq_pg_size_sq_lvl; - #define CMDQ_CREATE_QP_SQ_LVL_MASK 0xfUL - #define CMDQ_CREATE_QP_SQ_LVL_SFT 0 - #define CMDQ_CREATE_QP_SQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_QP_SQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_QP_SQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_QP_SQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_CREATE_QP_SQ_PG_SIZE_SFT 4 - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 rq_pg_size_rq_lvl; - #define CMDQ_CREATE_QP_RQ_LVL_MASK 0xfUL - #define CMDQ_CREATE_QP_RQ_LVL_SFT 0 - #define CMDQ_CREATE_QP_RQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_QP_RQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_QP_RQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_QP_RQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_CREATE_QP_RQ_PG_SIZE_SFT 4 - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 unused_0; - __le32 dpi; - __le32 sq_size; - __le32 rq_size; - __le16 sq_fwo_sq_sge; - #define CMDQ_CREATE_QP_SQ_SGE_MASK 0xfUL - #define CMDQ_CREATE_QP_SQ_SGE_SFT 0 - #define CMDQ_CREATE_QP_SQ_FWO_MASK 0xfff0UL - #define CMDQ_CREATE_QP_SQ_FWO_SFT 4 - __le16 rq_fwo_rq_sge; - #define CMDQ_CREATE_QP_RQ_SGE_MASK 0xfUL - #define CMDQ_CREATE_QP_RQ_SGE_SFT 0 - #define CMDQ_CREATE_QP_RQ_FWO_MASK 0xfff0UL - #define CMDQ_CREATE_QP_RQ_FWO_SFT 4 - __le32 scq_cid; - __le32 rcq_cid; - __le32 srq_cid; - __le32 pd_id; - __le64 sq_pbl; - __le64 rq_pbl; - __le64 irrq_addr; - __le64 orrq_addr; + u8 type; + #define CMDQ_CREATE_QP_TYPE_RC 0x2UL + #define CMDQ_CREATE_QP_TYPE_UD 0x4UL + #define CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE 0x6UL + #define CMDQ_CREATE_QP_TYPE_GSI 0x7UL + #define CMDQ_CREATE_QP_TYPE_LAST CMDQ_CREATE_QP_TYPE_GSI + u8 sq_pg_size_sq_lvl; + #define CMDQ_CREATE_QP_SQ_LVL_MASK 0xfUL + #define CMDQ_CREATE_QP_SQ_LVL_SFT 0 + #define CMDQ_CREATE_QP_SQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_QP_SQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_QP_SQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_QP_SQ_LVL_LAST CMDQ_CREATE_QP_SQ_LVL_LVL_2 + #define CMDQ_CREATE_QP_SQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_CREATE_QP_SQ_PG_SIZE_SFT 4 + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_CREATE_QP_SQ_PG_SIZE_LAST CMDQ_CREATE_QP_SQ_PG_SIZE_PG_1G + u8 rq_pg_size_rq_lvl; + #define CMDQ_CREATE_QP_RQ_LVL_MASK 0xfUL + #define CMDQ_CREATE_QP_RQ_LVL_SFT 0 + #define CMDQ_CREATE_QP_RQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_QP_RQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_QP_RQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_QP_RQ_LVL_LAST CMDQ_CREATE_QP_RQ_LVL_LVL_2 + #define CMDQ_CREATE_QP_RQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_CREATE_QP_RQ_PG_SIZE_SFT 4 + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_CREATE_QP_RQ_PG_SIZE_LAST CMDQ_CREATE_QP_RQ_PG_SIZE_PG_1G + u8 unused_0; + __le32 dpi; + __le32 sq_size; + __le32 rq_size; + __le16 sq_fwo_sq_sge; + #define CMDQ_CREATE_QP_SQ_SGE_MASK 0xfUL + #define CMDQ_CREATE_QP_SQ_SGE_SFT 0 + #define CMDQ_CREATE_QP_SQ_FWO_MASK 0xfff0UL + #define CMDQ_CREATE_QP_SQ_FWO_SFT 4 + __le16 rq_fwo_rq_sge; + #define CMDQ_CREATE_QP_RQ_SGE_MASK 0xfUL + #define CMDQ_CREATE_QP_RQ_SGE_SFT 0 + #define CMDQ_CREATE_QP_RQ_FWO_MASK 0xfff0UL + #define CMDQ_CREATE_QP_RQ_FWO_SFT 4 + __le32 scq_cid; + __le32 rcq_cid; + __le32 srq_cid; + __le32 pd_id; + __le64 sq_pbl; + __le64 rq_pbl; + __le64 irrq_addr; + __le64 orrq_addr; }; -/* Destroy QP command (24 bytes) */ +/* creq_create_qp_resp (size:128b/16B) */ +struct creq_create_qp_resp { + u8 type; + #define CREQ_CREATE_QP_RESP_TYPE_MASK 0x3fUL + #define CREQ_CREATE_QP_RESP_TYPE_SFT 0 + #define CREQ_CREATE_QP_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_CREATE_QP_RESP_TYPE_LAST CREQ_CREATE_QP_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_CREATE_QP_RESP_V 0x1UL + u8 event; + #define CREQ_CREATE_QP_RESP_EVENT_CREATE_QP 0x1UL + #define CREQ_CREATE_QP_RESP_EVENT_LAST CREQ_CREATE_QP_RESP_EVENT_CREATE_QP + u8 optimized_transmit_enabled; + u8 reserved48[5]; +}; + +/* cmdq_destroy_qp (size:192b/24B) */ struct cmdq_destroy_qp { - u8 opcode; - #define CMDQ_DESTROY_QP_OPCODE_DESTROY_QP 0x2UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 qp_cid; - __le32 unused_0; + u8 opcode; + #define CMDQ_DESTROY_QP_OPCODE_DESTROY_QP 0x2UL + #define CMDQ_DESTROY_QP_OPCODE_LAST CMDQ_DESTROY_QP_OPCODE_DESTROY_QP + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 qp_cid; + __le32 unused_0; }; -/* Modify QP command (112 bytes) */ +/* creq_destroy_qp_resp (size:128b/16B) */ +struct creq_destroy_qp_resp { + u8 type; + #define CREQ_DESTROY_QP_RESP_TYPE_MASK 0x3fUL + #define CREQ_DESTROY_QP_RESP_TYPE_SFT 0 + #define CREQ_DESTROY_QP_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DESTROY_QP_RESP_TYPE_LAST CREQ_DESTROY_QP_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DESTROY_QP_RESP_V 0x1UL + u8 event; + #define CREQ_DESTROY_QP_RESP_EVENT_DESTROY_QP 0x2UL + #define CREQ_DESTROY_QP_RESP_EVENT_LAST CREQ_DESTROY_QP_RESP_EVENT_DESTROY_QP + u8 reserved48[6]; +}; + +/* cmdq_modify_qp (size:1024b/128B) */ struct cmdq_modify_qp { - u8 opcode; - #define CMDQ_MODIFY_QP_OPCODE_MODIFY_QP 0x3UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 modify_mask; - #define CMDQ_MODIFY_QP_MODIFY_MASK_STATE 0x1UL + u8 opcode; + #define CMDQ_MODIFY_QP_OPCODE_MODIFY_QP 0x3UL + #define CMDQ_MODIFY_QP_OPCODE_LAST CMDQ_MODIFY_QP_OPCODE_MODIFY_QP + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 modify_mask; + #define CMDQ_MODIFY_QP_MODIFY_MASK_STATE 0x1UL #define CMDQ_MODIFY_QP_MODIFY_MASK_EN_SQD_ASYNC_NOTIFY 0x2UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_ACCESS 0x4UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_PKEY 0x8UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_QKEY 0x10UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_DGID 0x20UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_FLOW_LABEL 0x40UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_SGID_INDEX 0x80UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_HOP_LIMIT 0x100UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_TRAFFIC_CLASS 0x200UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_DEST_MAC 0x400UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU 0x1000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_TIMEOUT 0x2000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_RETRY_CNT 0x4000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_RNR_RETRY 0x8000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_PSN 0x10000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_MAX_RD_ATOMIC 0x20000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_MIN_RNR_TIMER 0x40000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN 0x80000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_ACCESS 0x4UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_PKEY 0x8UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_QKEY 0x10UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_DGID 0x20UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_FLOW_LABEL 0x40UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_SGID_INDEX 0x80UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_HOP_LIMIT 0x100UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_TRAFFIC_CLASS 0x200UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_DEST_MAC 0x400UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_PINGPONG_PUSH_MODE 0x800UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU 0x1000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_TIMEOUT 0x2000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_RETRY_CNT 0x4000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_RNR_RETRY 0x8000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_PSN 0x10000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_MAX_RD_ATOMIC 0x20000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_MIN_RNR_TIMER 0x40000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN 0x80000UL #define CMDQ_MODIFY_QP_MODIFY_MASK_MAX_DEST_RD_ATOMIC 0x100000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE 0x200000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE 0x400000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SGE 0x800000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SGE 0x1000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_MAX_INLINE_DATA 0x2000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_DEST_QP_ID 0x4000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_SRC_MAC 0x8000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_VLAN_ID 0x10000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_ENABLE_CC 0x20000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_TOS_ECN 0x40000000UL - #define CMDQ_MODIFY_QP_MODIFY_MASK_TOS_DSCP 0x80000000UL - __le32 qp_cid; - u8 network_type_en_sqd_async_notify_new_state; - #define CMDQ_MODIFY_QP_NEW_STATE_MASK 0xfUL - #define CMDQ_MODIFY_QP_NEW_STATE_SFT 0 - #define CMDQ_MODIFY_QP_NEW_STATE_RESET 0x0UL - #define CMDQ_MODIFY_QP_NEW_STATE_INIT 0x1UL - #define CMDQ_MODIFY_QP_NEW_STATE_RTR 0x2UL - #define CMDQ_MODIFY_QP_NEW_STATE_RTS 0x3UL - #define CMDQ_MODIFY_QP_NEW_STATE_SQD 0x4UL - #define CMDQ_MODIFY_QP_NEW_STATE_SQE 0x5UL - #define CMDQ_MODIFY_QP_NEW_STATE_ERR 0x6UL - #define CMDQ_MODIFY_QP_EN_SQD_ASYNC_NOTIFY 0x10UL - #define CMDQ_MODIFY_QP_NETWORK_TYPE_MASK 0xc0UL - #define CMDQ_MODIFY_QP_NETWORK_TYPE_SFT 6 - #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV1 (0x0UL << 6) - #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV4 (0x2UL << 6) - #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 (0x3UL << 6) - u8 access; - #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL - #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL - __le16 pkey; - __le32 qkey; - __le32 dgid[4]; - __le32 flow_label; - __le16 sgid_index; - u8 hop_limit; - u8 traffic_class; - __le16 dest_mac[3]; - u8 tos_dscp_tos_ecn; - #define CMDQ_MODIFY_QP_TOS_ECN_MASK 0x3UL - #define CMDQ_MODIFY_QP_TOS_ECN_SFT 0 - #define CMDQ_MODIFY_QP_TOS_DSCP_MASK 0xfcUL - #define CMDQ_MODIFY_QP_TOS_DSCP_SFT 2 - u8 path_mtu; - #define CMDQ_MODIFY_QP_PATH_MTU_MASK 0xf0UL - #define CMDQ_MODIFY_QP_PATH_MTU_SFT 4 - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_256 (0x0UL << 4) - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_512 (0x1UL << 4) - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_1024 (0x2UL << 4) - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_2048 (0x3UL << 4) - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_4096 (0x4UL << 4) - #define CMDQ_MODIFY_QP_PATH_MTU_MTU_8192 (0x5UL << 4) - u8 timeout; - u8 retry_cnt; - u8 rnr_retry; - u8 min_rnr_timer; - __le32 rq_psn; - __le32 sq_psn; - u8 max_rd_atomic; - u8 max_dest_rd_atomic; - __le16 enable_cc; - #define CMDQ_MODIFY_QP_ENABLE_CC 0x1UL - __le32 sq_size; - __le32 rq_size; - __le16 sq_sge; - __le16 rq_sge; - __le32 max_inline_data; - __le32 dest_qp_id; - __le32 unused_3; - __le16 src_mac[3]; - __le16 vlan_pcp_vlan_dei_vlan_id; - #define CMDQ_MODIFY_QP_VLAN_ID_MASK 0xfffUL - #define CMDQ_MODIFY_QP_VLAN_ID_SFT 0 - #define CMDQ_MODIFY_QP_VLAN_DEI 0x1000UL - #define CMDQ_MODIFY_QP_VLAN_PCP_MASK 0xe000UL - #define CMDQ_MODIFY_QP_VLAN_PCP_SFT 13 + #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE 0x200000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE 0x400000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SGE 0x800000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SGE 0x1000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_MAX_INLINE_DATA 0x2000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_DEST_QP_ID 0x4000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_SRC_MAC 0x8000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_VLAN_ID 0x10000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_ENABLE_CC 0x20000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_TOS_ECN 0x40000000UL + #define CMDQ_MODIFY_QP_MODIFY_MASK_TOS_DSCP 0x80000000UL + __le32 qp_cid; + u8 network_type_en_sqd_async_notify_new_state; + #define CMDQ_MODIFY_QP_NEW_STATE_MASK 0xfUL + #define CMDQ_MODIFY_QP_NEW_STATE_SFT 0 + #define CMDQ_MODIFY_QP_NEW_STATE_RESET 0x0UL + #define CMDQ_MODIFY_QP_NEW_STATE_INIT 0x1UL + #define CMDQ_MODIFY_QP_NEW_STATE_RTR 0x2UL + #define CMDQ_MODIFY_QP_NEW_STATE_RTS 0x3UL + #define CMDQ_MODIFY_QP_NEW_STATE_SQD 0x4UL + #define CMDQ_MODIFY_QP_NEW_STATE_SQE 0x5UL + #define CMDQ_MODIFY_QP_NEW_STATE_ERR 0x6UL + #define CMDQ_MODIFY_QP_NEW_STATE_LAST CMDQ_MODIFY_QP_NEW_STATE_ERR + #define CMDQ_MODIFY_QP_EN_SQD_ASYNC_NOTIFY 0x10UL + #define CMDQ_MODIFY_QP_UNUSED1 0x20UL + #define CMDQ_MODIFY_QP_NETWORK_TYPE_MASK 0xc0UL + #define CMDQ_MODIFY_QP_NETWORK_TYPE_SFT 6 + #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV1 (0x0UL << 6) + #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV4 (0x2UL << 6) + #define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 (0x3UL << 6) + #define CMDQ_MODIFY_QP_NETWORK_TYPE_LAST CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 + u8 access; + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK \ + 0xffUL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT \ + 0 + #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL + #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL + __le16 pkey; + __le32 qkey; + __le32 dgid[4]; + __le32 flow_label; + __le16 sgid_index; + u8 hop_limit; + u8 traffic_class; + __le16 dest_mac[3]; + u8 tos_dscp_tos_ecn; + #define CMDQ_MODIFY_QP_TOS_ECN_MASK 0x3UL + #define CMDQ_MODIFY_QP_TOS_ECN_SFT 0 + #define CMDQ_MODIFY_QP_TOS_DSCP_MASK 0xfcUL + #define CMDQ_MODIFY_QP_TOS_DSCP_SFT 2 + u8 path_mtu_pingpong_push_enable; + #define CMDQ_MODIFY_QP_PINGPONG_PUSH_ENABLE 0x1UL + #define CMDQ_MODIFY_QP_UNUSED3_MASK 0xeUL + #define CMDQ_MODIFY_QP_UNUSED3_SFT 1 + #define CMDQ_MODIFY_QP_PATH_MTU_MASK 0xf0UL + #define CMDQ_MODIFY_QP_PATH_MTU_SFT 4 + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_256 (0x0UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_512 (0x1UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_1024 (0x2UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_2048 (0x3UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_4096 (0x4UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_MTU_8192 (0x5UL << 4) + #define CMDQ_MODIFY_QP_PATH_MTU_LAST CMDQ_MODIFY_QP_PATH_MTU_MTU_8192 + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 min_rnr_timer; + __le32 rq_psn; + __le32 sq_psn; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + __le16 enable_cc; + #define CMDQ_MODIFY_QP_ENABLE_CC 0x1UL + #define CMDQ_MODIFY_QP_UNUSED15_MASK 0xfffeUL + #define CMDQ_MODIFY_QP_UNUSED15_SFT 1 + __le32 sq_size; + __le32 rq_size; + __le16 sq_sge; + __le16 rq_sge; + __le32 max_inline_data; + __le32 dest_qp_id; + __le32 pingpong_push_dpi; + __le16 src_mac[3]; + __le16 vlan_pcp_vlan_dei_vlan_id; + #define CMDQ_MODIFY_QP_VLAN_ID_MASK 0xfffUL + #define CMDQ_MODIFY_QP_VLAN_ID_SFT 0 + #define CMDQ_MODIFY_QP_VLAN_DEI 0x1000UL + #define CMDQ_MODIFY_QP_VLAN_PCP_MASK 0xe000UL + #define CMDQ_MODIFY_QP_VLAN_PCP_SFT 13 + __le64 irrq_addr; + __le64 orrq_addr; }; -/* Query QP command (24 bytes) */ +/* creq_modify_qp_resp (size:128b/16B) */ +struct creq_modify_qp_resp { + u8 type; + #define CREQ_MODIFY_QP_RESP_TYPE_MASK 0x3fUL + #define CREQ_MODIFY_QP_RESP_TYPE_SFT 0 + #define CREQ_MODIFY_QP_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_MODIFY_QP_RESP_TYPE_LAST CREQ_MODIFY_QP_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_MODIFY_QP_RESP_V 0x1UL + u8 event; + #define CREQ_MODIFY_QP_RESP_EVENT_MODIFY_QP 0x3UL + #define CREQ_MODIFY_QP_RESP_EVENT_LAST CREQ_MODIFY_QP_RESP_EVENT_MODIFY_QP + u8 pingpong_push_state_index_enabled; + #define CREQ_MODIFY_QP_RESP_PINGPONG_PUSH_ENABLED 0x1UL + #define CREQ_MODIFY_QP_RESP_PINGPONG_PUSH_INDEX_MASK 0xeUL + #define CREQ_MODIFY_QP_RESP_PINGPONG_PUSH_INDEX_SFT 1 + #define CREQ_MODIFY_QP_RESP_PINGPONG_PUSH_STATE 0x10UL + u8 reserved8; + __le32 lag_src_mac; +}; + +/* cmdq_query_qp (size:192b/24B) */ struct cmdq_query_qp { - u8 opcode; - #define CMDQ_QUERY_QP_OPCODE_QUERY_QP 0x4UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 qp_cid; - __le32 unused_0; + u8 opcode; + #define CMDQ_QUERY_QP_OPCODE_QUERY_QP 0x4UL + #define CMDQ_QUERY_QP_OPCODE_LAST CMDQ_QUERY_QP_OPCODE_QUERY_QP + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 qp_cid; + __le32 unused_0; }; -/* Create SRQ command (48 bytes) */ +/* creq_query_qp_resp (size:128b/16B) */ +struct creq_query_qp_resp { + u8 type; + #define CREQ_QUERY_QP_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_QP_RESP_TYPE_SFT 0 + #define CREQ_QUERY_QP_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_QP_RESP_TYPE_LAST CREQ_QUERY_QP_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_QP_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_QP_RESP_EVENT_QUERY_QP 0x4UL + #define CREQ_QUERY_QP_RESP_EVENT_LAST CREQ_QUERY_QP_RESP_EVENT_QUERY_QP + u8 reserved48[6]; +}; + +/* creq_query_qp_resp_sb (size:832b/104B) */ +struct creq_query_qp_resp_sb { + u8 opcode; + #define CREQ_QUERY_QP_RESP_SB_OPCODE_QUERY_QP 0x4UL + #define CREQ_QUERY_QP_RESP_SB_OPCODE_LAST CREQ_QUERY_QP_RESP_SB_OPCODE_QUERY_QP + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le32 xid; + u8 en_sqd_async_notify_state; + #define CREQ_QUERY_QP_RESP_SB_STATE_MASK 0xfUL + #define CREQ_QUERY_QP_RESP_SB_STATE_SFT 0 + #define CREQ_QUERY_QP_RESP_SB_STATE_RESET 0x0UL + #define CREQ_QUERY_QP_RESP_SB_STATE_INIT 0x1UL + #define CREQ_QUERY_QP_RESP_SB_STATE_RTR 0x2UL + #define CREQ_QUERY_QP_RESP_SB_STATE_RTS 0x3UL + #define CREQ_QUERY_QP_RESP_SB_STATE_SQD 0x4UL + #define CREQ_QUERY_QP_RESP_SB_STATE_SQE 0x5UL + #define CREQ_QUERY_QP_RESP_SB_STATE_ERR 0x6UL + #define CREQ_QUERY_QP_RESP_SB_STATE_LAST CREQ_QUERY_QP_RESP_SB_STATE_ERR + #define CREQ_QUERY_QP_RESP_SB_EN_SQD_ASYNC_NOTIFY 0x10UL + #define CREQ_QUERY_QP_RESP_SB_UNUSED3_MASK 0xe0UL + #define CREQ_QUERY_QP_RESP_SB_UNUSED3_SFT 5 + u8 access; + #define \ + CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK\ + 0xffUL + #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT\ + 0 + #define CREQ_QUERY_QP_RESP_SB_ACCESS_LOCAL_WRITE 0x1UL + #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_WRITE 0x2UL + #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_READ 0x4UL + #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_ATOMIC 0x8UL + __le16 pkey; + __le32 qkey; + __le32 reserved32; + __le32 dgid[4]; + __le32 flow_label; + __le16 sgid_index; + u8 hop_limit; + u8 traffic_class; + __le16 dest_mac[3]; + __le16 path_mtu_dest_vlan_id; + #define CREQ_QUERY_QP_RESP_SB_DEST_VLAN_ID_MASK 0xfffUL + #define CREQ_QUERY_QP_RESP_SB_DEST_VLAN_ID_SFT 0 + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MASK 0xf000UL + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_SFT 12 + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_256 (0x0UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_512 (0x1UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_1024 (0x2UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_2048 (0x3UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_4096 (0x4UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_8192 (0x5UL << 12) + #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_LAST CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_8192 + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 min_rnr_timer; + __le32 rq_psn; + __le32 sq_psn; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + u8 tos_dscp_tos_ecn; + #define CREQ_QUERY_QP_RESP_SB_TOS_ECN_MASK 0x3UL + #define CREQ_QUERY_QP_RESP_SB_TOS_ECN_SFT 0 + #define CREQ_QUERY_QP_RESP_SB_TOS_DSCP_MASK 0xfcUL + #define CREQ_QUERY_QP_RESP_SB_TOS_DSCP_SFT 2 + u8 enable_cc; + #define CREQ_QUERY_QP_RESP_SB_ENABLE_CC 0x1UL + __le32 sq_size; + __le32 rq_size; + __le16 sq_sge; + __le16 rq_sge; + __le32 max_inline_data; + __le32 dest_qp_id; + __le16 port_id; + u8 unused_0; + u8 stat_collection_id; + __le16 src_mac[3]; + __le16 vlan_pcp_vlan_dei_vlan_id; + #define CREQ_QUERY_QP_RESP_SB_VLAN_ID_MASK 0xfffUL + #define CREQ_QUERY_QP_RESP_SB_VLAN_ID_SFT 0 + #define CREQ_QUERY_QP_RESP_SB_VLAN_DEI 0x1000UL + #define CREQ_QUERY_QP_RESP_SB_VLAN_PCP_MASK 0xe000UL + #define CREQ_QUERY_QP_RESP_SB_VLAN_PCP_SFT 13 +}; + +/* cmdq_query_qp_extend (size:192b/24B) */ +struct cmdq_query_qp_extend { + u8 opcode; + #define CMDQ_QUERY_QP_EXTEND_OPCODE_QUERY_QP_EXTEND 0x91UL + #define CMDQ_QUERY_QP_EXTEND_OPCODE_LAST CMDQ_QUERY_QP_EXTEND_OPCODE_QUERY_QP_EXTEND + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 num_qps; + __le64 resp_addr; + __le32 function_id; + #define CMDQ_QUERY_QP_EXTEND_PF_NUM_MASK 0xffUL + #define CMDQ_QUERY_QP_EXTEND_PF_NUM_SFT 0 + #define CMDQ_QUERY_QP_EXTEND_VF_NUM_MASK 0xffff00UL + #define CMDQ_QUERY_QP_EXTEND_VF_NUM_SFT 8 + #define CMDQ_QUERY_QP_EXTEND_VF_VALID 0x1000000UL + __le32 current_index; +}; + +/* creq_query_qp_extend_resp (size:128b/16B) */ +struct creq_query_qp_extend_resp { + u8 type; + #define CREQ_QUERY_QP_EXTEND_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_QP_EXTEND_RESP_TYPE_SFT 0 + #define CREQ_QUERY_QP_EXTEND_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_QP_EXTEND_RESP_TYPE_LAST CREQ_QUERY_QP_EXTEND_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_QP_EXTEND_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_QP_EXTEND_RESP_EVENT_QUERY_QP_EXTEND 0x91UL + #define CREQ_QUERY_QP_EXTEND_RESP_EVENT_LAST CREQ_QUERY_QP_EXTEND_RESP_EVENT_QUERY_QP_EXTEND + __le16 reserved16; + __le32 current_index; +}; + +/* creq_query_qp_extend_resp_sb (size:384b/48B) */ +struct creq_query_qp_extend_resp_sb { + u8 opcode; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_OPCODE_QUERY_QP_EXTEND 0x91UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_OPCODE_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_OPCODE_QUERY_QP_EXTEND + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le32 xid; + u8 state; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_MASK 0xfUL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_SFT 0 + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_RESET 0x0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_INIT 0x1UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_RTR 0x2UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_RTS 0x3UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_SQD 0x4UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_SQE 0x5UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_ERR 0x6UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_LAST CREQ_QUERY_QP_EXTEND_RESP_SB_STATE_ERR + #define CREQ_QUERY_QP_EXTEND_RESP_SB_UNUSED4_MASK 0xf0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_UNUSED4_SFT 4 + u8 reserved_8; + __le16 port_id; + __le32 qkey; + __le16 sgid_index; + u8 network_type; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_NETWORK_TYPE_ROCEV1 0x0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_NETWORK_TYPE_ROCEV2_IPV4 0x2UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_NETWORK_TYPE_ROCEV2_IPV6 0x3UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_NETWORK_TYPE_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_NETWORK_TYPE_ROCEV2_IPV6 + u8 unused_0; + __le32 dgid[4]; + __le32 dest_qp_id; + u8 stat_collection_id; + u8 reservred_8; + __le16 reserved_16; +}; + +/* creq_query_qp_extend_resp_sb_tlv (size:512b/64B) */ +struct creq_query_qp_extend_resp_sb_tlv { + __le16 cmd_discr; + u8 reserved_8b; + u8 tlv_flags; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_MORE 0x1UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_MORE_LAST 0x0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_MORE_NOT_LAST 0x1UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_REQUIRED 0x2UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_REQUIRED_NO (0x0UL << 1) + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES (0x1UL << 1) + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_REQUIRED_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES + __le16 tlv_type; + __le16 length; + u8 total_size; + u8 reserved56[7]; + u8 opcode; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_OPCODE_QUERY_QP_EXTEND 0x91UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_OPCODE_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_OPCODE_QUERY_QP_EXTEND + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le32 xid; + u8 state; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_MASK 0xfUL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_SFT 0 + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_RESET 0x0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_INIT 0x1UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_RTR 0x2UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_RTS 0x3UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_SQD 0x4UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_SQE 0x5UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_ERR 0x6UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_STATE_ERR + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_UNUSED4_MASK 0xf0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_UNUSED4_SFT 4 + u8 reserved_8; + __le16 port_id; + __le32 qkey; + __le16 sgid_index; + u8 network_type; + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_NETWORK_TYPE_ROCEV1 0x0UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_NETWORK_TYPE_ROCEV2_IPV4 0x2UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_NETWORK_TYPE_ROCEV2_IPV6 0x3UL + #define CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_NETWORK_TYPE_LAST \ + CREQ_QUERY_QP_EXTEND_RESP_SB_TLV_NETWORK_TYPE_ROCEV2_IPV6 + u8 unused_0; + __le32 dgid[4]; + __le32 dest_qp_id; + u8 stat_collection_id; + u8 reservred_8; + __le16 reserved_16; +}; + +/* cmdq_create_srq (size:384b/48B) */ struct cmdq_create_srq { - u8 opcode; - #define CMDQ_CREATE_SRQ_OPCODE_CREATE_SRQ 0x5UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 srq_handle; - __le16 pg_size_lvl; - #define CMDQ_CREATE_SRQ_LVL_MASK 0x3UL - #define CMDQ_CREATE_SRQ_LVL_SFT 0 - #define CMDQ_CREATE_SRQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_SRQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_SRQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_SRQ_PG_SIZE_MASK 0x1cUL - #define CMDQ_CREATE_SRQ_PG_SIZE_SFT 2 - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_4K (0x0UL << 2) - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_8K (0x1UL << 2) - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_64K (0x2UL << 2) - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_2M (0x3UL << 2) - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_8M (0x4UL << 2) - #define CMDQ_CREATE_SRQ_PG_SIZE_PG_1G (0x5UL << 2) - __le16 eventq_id; - #define CMDQ_CREATE_SRQ_EVENTQ_ID_MASK 0xfffUL - #define CMDQ_CREATE_SRQ_EVENTQ_ID_SFT 0 - __le16 srq_size; - __le16 srq_fwo; - __le32 dpi; - __le32 pd_id; - __le64 pbl; + u8 opcode; + #define CMDQ_CREATE_SRQ_OPCODE_CREATE_SRQ 0x5UL + #define CMDQ_CREATE_SRQ_OPCODE_LAST CMDQ_CREATE_SRQ_OPCODE_CREATE_SRQ + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 srq_handle; + __le16 pg_size_lvl; + #define CMDQ_CREATE_SRQ_LVL_MASK 0x3UL + #define CMDQ_CREATE_SRQ_LVL_SFT 0 + #define CMDQ_CREATE_SRQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_SRQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_SRQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_SRQ_LVL_LAST CMDQ_CREATE_SRQ_LVL_LVL_2 + #define CMDQ_CREATE_SRQ_PG_SIZE_MASK 0x1cUL + #define CMDQ_CREATE_SRQ_PG_SIZE_SFT 2 + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_4K (0x0UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_8K (0x1UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_64K (0x2UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_2M (0x3UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_8M (0x4UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_PG_1G (0x5UL << 2) + #define CMDQ_CREATE_SRQ_PG_SIZE_LAST CMDQ_CREATE_SRQ_PG_SIZE_PG_1G + #define CMDQ_CREATE_SRQ_UNUSED11_MASK 0xffe0UL + #define CMDQ_CREATE_SRQ_UNUSED11_SFT 5 + __le16 eventq_id; + #define CMDQ_CREATE_SRQ_EVENTQ_ID_MASK 0xfffUL + #define CMDQ_CREATE_SRQ_EVENTQ_ID_SFT 0 + #define CMDQ_CREATE_SRQ_UNUSED4_MASK 0xf000UL + #define CMDQ_CREATE_SRQ_UNUSED4_SFT 12 + __le16 srq_size; + __le16 srq_fwo; + __le32 dpi; + __le32 pd_id; + __le64 pbl; }; -/* Destroy SRQ command (24 bytes) */ +/* creq_create_srq_resp (size:128b/16B) */ +struct creq_create_srq_resp { + u8 type; + #define CREQ_CREATE_SRQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_CREATE_SRQ_RESP_TYPE_SFT 0 + #define CREQ_CREATE_SRQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_CREATE_SRQ_RESP_TYPE_LAST CREQ_CREATE_SRQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_CREATE_SRQ_RESP_V 0x1UL + u8 event; + #define CREQ_CREATE_SRQ_RESP_EVENT_CREATE_SRQ 0x5UL + #define CREQ_CREATE_SRQ_RESP_EVENT_LAST CREQ_CREATE_SRQ_RESP_EVENT_CREATE_SRQ + u8 reserved48[6]; +}; + +/* cmdq_destroy_srq (size:192b/24B) */ struct cmdq_destroy_srq { - u8 opcode; - #define CMDQ_DESTROY_SRQ_OPCODE_DESTROY_SRQ 0x6UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 srq_cid; - __le32 unused_0; + u8 opcode; + #define CMDQ_DESTROY_SRQ_OPCODE_DESTROY_SRQ 0x6UL + #define CMDQ_DESTROY_SRQ_OPCODE_LAST CMDQ_DESTROY_SRQ_OPCODE_DESTROY_SRQ + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 srq_cid; + __le32 unused_0; }; -/* Query SRQ command (24 bytes) */ +/* creq_destroy_srq_resp (size:128b/16B) */ +struct creq_destroy_srq_resp { + u8 type; + #define CREQ_DESTROY_SRQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_DESTROY_SRQ_RESP_TYPE_SFT 0 + #define CREQ_DESTROY_SRQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DESTROY_SRQ_RESP_TYPE_LAST CREQ_DESTROY_SRQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DESTROY_SRQ_RESP_V 0x1UL + u8 event; + #define CREQ_DESTROY_SRQ_RESP_EVENT_DESTROY_SRQ 0x6UL + #define CREQ_DESTROY_SRQ_RESP_EVENT_LAST CREQ_DESTROY_SRQ_RESP_EVENT_DESTROY_SRQ + __le16 enable_for_arm[3]; + #define CREQ_DESTROY_SRQ_RESP_UNUSED0_MASK 0xffffUL + #define CREQ_DESTROY_SRQ_RESP_UNUSED0_SFT 0 + #define CREQ_DESTROY_SRQ_RESP_ENABLE_FOR_ARM_MASK 0x30000UL + #define CREQ_DESTROY_SRQ_RESP_ENABLE_FOR_ARM_SFT 16 +}; + +/* cmdq_query_srq (size:192b/24B) */ struct cmdq_query_srq { - u8 opcode; - #define CMDQ_QUERY_SRQ_OPCODE_QUERY_SRQ 0x8UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 srq_cid; - __le32 unused_0; + u8 opcode; + #define CMDQ_QUERY_SRQ_OPCODE_QUERY_SRQ 0x8UL + #define CMDQ_QUERY_SRQ_OPCODE_LAST CMDQ_QUERY_SRQ_OPCODE_QUERY_SRQ + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 srq_cid; + __le32 unused_0; }; -/* Create CQ command (48 bytes) */ +/* creq_query_srq_resp (size:128b/16B) */ +struct creq_query_srq_resp { + u8 type; + #define CREQ_QUERY_SRQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_SRQ_RESP_TYPE_SFT 0 + #define CREQ_QUERY_SRQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_SRQ_RESP_TYPE_LAST CREQ_QUERY_SRQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_SRQ_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_SRQ_RESP_EVENT_QUERY_SRQ 0x8UL + #define CREQ_QUERY_SRQ_RESP_EVENT_LAST CREQ_QUERY_SRQ_RESP_EVENT_QUERY_SRQ + u8 reserved48[6]; +}; + +/* creq_query_srq_resp_sb (size:256b/32B) */ +struct creq_query_srq_resp_sb { + u8 opcode; + #define CREQ_QUERY_SRQ_RESP_SB_OPCODE_QUERY_SRQ 0x8UL + #define CREQ_QUERY_SRQ_RESP_SB_OPCODE_LAST CREQ_QUERY_SRQ_RESP_SB_OPCODE_QUERY_SRQ + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le32 xid; + __le16 srq_limit; + __le16 reserved16; + __le32 data[4]; +}; + +/* cmdq_create_cq (size:384b/48B) */ struct cmdq_create_cq { - u8 opcode; - #define CMDQ_CREATE_CQ_OPCODE_CREATE_CQ 0x9UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 cq_handle; - __le32 pg_size_lvl; - #define CMDQ_CREATE_CQ_LVL_MASK 0x3UL - #define CMDQ_CREATE_CQ_LVL_SFT 0 - #define CMDQ_CREATE_CQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_CQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_CQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_CQ_PG_SIZE_MASK 0x1cUL - #define CMDQ_CREATE_CQ_PG_SIZE_SFT 2 - #define CMDQ_CREATE_CQ_PG_SIZE_PG_4K (0x0UL << 2) - #define CMDQ_CREATE_CQ_PG_SIZE_PG_8K (0x1UL << 2) - #define CMDQ_CREATE_CQ_PG_SIZE_PG_64K (0x2UL << 2) - #define CMDQ_CREATE_CQ_PG_SIZE_PG_2M (0x3UL << 2) - #define CMDQ_CREATE_CQ_PG_SIZE_PG_8M (0x4UL << 2) - #define CMDQ_CREATE_CQ_PG_SIZE_PG_1G (0x5UL << 2) - __le32 cq_fco_cnq_id; - #define CMDQ_CREATE_CQ_CNQ_ID_MASK 0xfffUL - #define CMDQ_CREATE_CQ_CNQ_ID_SFT 0 - #define CMDQ_CREATE_CQ_CQ_FCO_MASK 0xfffff000UL - #define CMDQ_CREATE_CQ_CQ_FCO_SFT 12 - __le32 dpi; - __le32 cq_size; - __le64 pbl; + u8 opcode; + #define CMDQ_CREATE_CQ_OPCODE_CREATE_CQ 0x9UL + #define CMDQ_CREATE_CQ_OPCODE_LAST CMDQ_CREATE_CQ_OPCODE_CREATE_CQ + u8 cmd_size; + __le16 flags; + #define CMDQ_CREATE_CQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x1UL + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 cq_handle; + __le32 pg_size_lvl; + #define CMDQ_CREATE_CQ_LVL_MASK 0x3UL + #define CMDQ_CREATE_CQ_LVL_SFT 0 + #define CMDQ_CREATE_CQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_CQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_CQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_CQ_LVL_LAST CMDQ_CREATE_CQ_LVL_LVL_2 + #define CMDQ_CREATE_CQ_PG_SIZE_MASK 0x1cUL + #define CMDQ_CREATE_CQ_PG_SIZE_SFT 2 + #define CMDQ_CREATE_CQ_PG_SIZE_PG_4K (0x0UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_PG_8K (0x1UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_PG_64K (0x2UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_PG_2M (0x3UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_PG_8M (0x4UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_PG_1G (0x5UL << 2) + #define CMDQ_CREATE_CQ_PG_SIZE_LAST CMDQ_CREATE_CQ_PG_SIZE_PG_1G + #define CMDQ_CREATE_CQ_UNUSED27_MASK 0xffffffe0UL + #define CMDQ_CREATE_CQ_UNUSED27_SFT 5 + __le32 cq_fco_cnq_id; + #define CMDQ_CREATE_CQ_CNQ_ID_MASK 0xfffUL + #define CMDQ_CREATE_CQ_CNQ_ID_SFT 0 + #define CMDQ_CREATE_CQ_CQ_FCO_MASK 0xfffff000UL + #define CMDQ_CREATE_CQ_CQ_FCO_SFT 12 + __le32 dpi; + __le32 cq_size; + __le64 pbl; }; -/* Destroy CQ command (24 bytes) */ +/* creq_create_cq_resp (size:128b/16B) */ +struct creq_create_cq_resp { + u8 type; + #define CREQ_CREATE_CQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_CREATE_CQ_RESP_TYPE_SFT 0 + #define CREQ_CREATE_CQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_CREATE_CQ_RESP_TYPE_LAST CREQ_CREATE_CQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_CREATE_CQ_RESP_V 0x1UL + u8 event; + #define CREQ_CREATE_CQ_RESP_EVENT_CREATE_CQ 0x9UL + #define CREQ_CREATE_CQ_RESP_EVENT_LAST CREQ_CREATE_CQ_RESP_EVENT_CREATE_CQ + u8 reserved48[6]; +}; + +/* cmdq_destroy_cq (size:192b/24B) */ struct cmdq_destroy_cq { - u8 opcode; - #define CMDQ_DESTROY_CQ_OPCODE_DESTROY_CQ 0xaUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 cq_cid; - __le32 unused_0; + u8 opcode; + #define CMDQ_DESTROY_CQ_OPCODE_DESTROY_CQ 0xaUL + #define CMDQ_DESTROY_CQ_OPCODE_LAST CMDQ_DESTROY_CQ_OPCODE_DESTROY_CQ + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 cq_cid; + __le32 unused_0; }; -/* Resize CQ command (40 bytes) */ +/* creq_destroy_cq_resp (size:128b/16B) */ +struct creq_destroy_cq_resp { + u8 type; + #define CREQ_DESTROY_CQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_DESTROY_CQ_RESP_TYPE_SFT 0 + #define CREQ_DESTROY_CQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DESTROY_CQ_RESP_TYPE_LAST CREQ_DESTROY_CQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DESTROY_CQ_RESP_V 0x1UL + u8 event; + #define CREQ_DESTROY_CQ_RESP_EVENT_DESTROY_CQ 0xaUL + #define CREQ_DESTROY_CQ_RESP_EVENT_LAST CREQ_DESTROY_CQ_RESP_EVENT_DESTROY_CQ + __le16 cq_arm_lvl; + #define CREQ_DESTROY_CQ_RESP_CQ_ARM_LVL_MASK 0x3UL + #define CREQ_DESTROY_CQ_RESP_CQ_ARM_LVL_SFT 0 + __le16 total_cnq_events; + __le16 reserved16; +}; + +/* cmdq_resize_cq (size:320b/40B) */ struct cmdq_resize_cq { - u8 opcode; - #define CMDQ_RESIZE_CQ_OPCODE_RESIZE_CQ 0xcUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 cq_cid; - __le32 new_cq_size_pg_size_lvl; - #define CMDQ_RESIZE_CQ_LVL_MASK 0x3UL - #define CMDQ_RESIZE_CQ_LVL_SFT 0 - #define CMDQ_RESIZE_CQ_LVL_LVL_0 0x0UL - #define CMDQ_RESIZE_CQ_LVL_LVL_1 0x1UL - #define CMDQ_RESIZE_CQ_LVL_LVL_2 0x2UL - #define CMDQ_RESIZE_CQ_PG_SIZE_MASK 0x1cUL - #define CMDQ_RESIZE_CQ_PG_SIZE_SFT 2 - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_4K (0x0UL << 2) - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_8K (0x1UL << 2) - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_64K (0x2UL << 2) - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_2M (0x3UL << 2) - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_8M (0x4UL << 2) - #define CMDQ_RESIZE_CQ_PG_SIZE_PG_1G (0x5UL << 2) - #define CMDQ_RESIZE_CQ_NEW_CQ_SIZE_MASK 0x1fffe0UL - #define CMDQ_RESIZE_CQ_NEW_CQ_SIZE_SFT 5 - __le64 new_pbl; - __le32 new_cq_fco; - __le32 unused_2; + u8 opcode; + #define CMDQ_RESIZE_CQ_OPCODE_RESIZE_CQ 0xcUL + #define CMDQ_RESIZE_CQ_OPCODE_LAST CMDQ_RESIZE_CQ_OPCODE_RESIZE_CQ + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 cq_cid; + __le32 new_cq_size_pg_size_lvl; + #define CMDQ_RESIZE_CQ_LVL_MASK 0x3UL + #define CMDQ_RESIZE_CQ_LVL_SFT 0 + #define CMDQ_RESIZE_CQ_LVL_LVL_0 0x0UL + #define CMDQ_RESIZE_CQ_LVL_LVL_1 0x1UL + #define CMDQ_RESIZE_CQ_LVL_LVL_2 0x2UL + #define CMDQ_RESIZE_CQ_LVL_LAST CMDQ_RESIZE_CQ_LVL_LVL_2 + #define CMDQ_RESIZE_CQ_PG_SIZE_MASK 0x1cUL + #define CMDQ_RESIZE_CQ_PG_SIZE_SFT 2 + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_4K (0x0UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_8K (0x1UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_64K (0x2UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_2M (0x3UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_8M (0x4UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_PG_1G (0x5UL << 2) + #define CMDQ_RESIZE_CQ_PG_SIZE_LAST CMDQ_RESIZE_CQ_PG_SIZE_PG_1G + #define CMDQ_RESIZE_CQ_NEW_CQ_SIZE_MASK 0x1fffffe0UL + #define CMDQ_RESIZE_CQ_NEW_CQ_SIZE_SFT 5 + __le64 new_pbl; + __le32 new_cq_fco; + __le32 unused_0; }; -/* Allocate MRW command (32 bytes) */ +/* creq_resize_cq_resp (size:128b/16B) */ +struct creq_resize_cq_resp { + u8 type; + #define CREQ_RESIZE_CQ_RESP_TYPE_MASK 0x3fUL + #define CREQ_RESIZE_CQ_RESP_TYPE_SFT 0 + #define CREQ_RESIZE_CQ_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_RESIZE_CQ_RESP_TYPE_LAST CREQ_RESIZE_CQ_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_RESIZE_CQ_RESP_V 0x1UL + u8 event; + #define CREQ_RESIZE_CQ_RESP_EVENT_RESIZE_CQ 0xcUL + #define CREQ_RESIZE_CQ_RESP_EVENT_LAST CREQ_RESIZE_CQ_RESP_EVENT_RESIZE_CQ + u8 reserved48[6]; +}; + +/* cmdq_allocate_mrw (size:256b/32B) */ struct cmdq_allocate_mrw { - u8 opcode; - #define CMDQ_ALLOCATE_MRW_OPCODE_ALLOCATE_MRW 0xdUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 mrw_handle; - u8 mrw_flags; - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MASK 0xfUL - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_SFT 0 - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MR 0x0UL - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR 0x1UL - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1 0x2UL - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A 0x3UL - #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B 0x4UL - u8 access; - #define CMDQ_ALLOCATE_MRW_ACCESS_RESERVED_MASK 0x1fUL - #define CMDQ_ALLOCATE_MRW_ACCESS_RESERVED_SFT 0 - #define CMDQ_ALLOCATE_MRW_ACCESS_CONSUMER_OWNED_KEY 0x20UL - __le16 unused_1; - __le32 pd_id; + u8 opcode; + #define CMDQ_ALLOCATE_MRW_OPCODE_ALLOCATE_MRW 0xdUL + #define CMDQ_ALLOCATE_MRW_OPCODE_LAST CMDQ_ALLOCATE_MRW_OPCODE_ALLOCATE_MRW + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 mrw_handle; + u8 mrw_flags; + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MASK 0xfUL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_SFT 0 + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MR 0x0UL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR 0x1UL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1 0x2UL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A 0x3UL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B 0x4UL + #define CMDQ_ALLOCATE_MRW_MRW_FLAGS_LAST CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B + #define CMDQ_ALLOCATE_MRW_UNUSED4_MASK 0xf0UL + #define CMDQ_ALLOCATE_MRW_UNUSED4_SFT 4 + u8 access; + #define CMDQ_ALLOCATE_MRW_ACCESS_CONSUMER_OWNED_KEY 0x20UL + __le16 unused16; + __le32 pd_id; }; -/* De-allocate key command (24 bytes) */ +/* creq_allocate_mrw_resp (size:128b/16B) */ +struct creq_allocate_mrw_resp { + u8 type; + #define CREQ_ALLOCATE_MRW_RESP_TYPE_MASK 0x3fUL + #define CREQ_ALLOCATE_MRW_RESP_TYPE_SFT 0 + #define CREQ_ALLOCATE_MRW_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_ALLOCATE_MRW_RESP_TYPE_LAST CREQ_ALLOCATE_MRW_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_ALLOCATE_MRW_RESP_V 0x1UL + u8 event; + #define CREQ_ALLOCATE_MRW_RESP_EVENT_ALLOCATE_MRW 0xdUL + #define CREQ_ALLOCATE_MRW_RESP_EVENT_LAST CREQ_ALLOCATE_MRW_RESP_EVENT_ALLOCATE_MRW + u8 reserved48[6]; +}; + +/* cmdq_deallocate_key (size:192b/24B) */ struct cmdq_deallocate_key { - u8 opcode; - #define CMDQ_DEALLOCATE_KEY_OPCODE_DEALLOCATE_KEY 0xeUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - u8 mrw_flags; - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MASK 0xfUL - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_SFT 0 - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MR 0x0UL - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_PMR 0x1UL - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE1 0x2UL - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE2A 0x3UL - #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE2B 0x4UL - u8 unused_1[3]; - __le32 key; + u8 opcode; + #define CMDQ_DEALLOCATE_KEY_OPCODE_DEALLOCATE_KEY 0xeUL + #define CMDQ_DEALLOCATE_KEY_OPCODE_LAST CMDQ_DEALLOCATE_KEY_OPCODE_DEALLOCATE_KEY + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + u8 mrw_flags; + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MASK 0xfUL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_SFT 0 + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MR 0x0UL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_PMR 0x1UL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE1 0x2UL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE2A 0x3UL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE2B 0x4UL + #define CMDQ_DEALLOCATE_KEY_MRW_FLAGS_LAST CMDQ_DEALLOCATE_KEY_MRW_FLAGS_MW_TYPE2B + #define CMDQ_DEALLOCATE_KEY_UNUSED4_MASK 0xf0UL + #define CMDQ_DEALLOCATE_KEY_UNUSED4_SFT 4 + u8 unused24[3]; + __le32 key; }; -/* Register MR command (48 bytes) */ +/* creq_deallocate_key_resp (size:128b/16B) */ +struct creq_deallocate_key_resp { + u8 type; + #define CREQ_DEALLOCATE_KEY_RESP_TYPE_MASK 0x3fUL + #define CREQ_DEALLOCATE_KEY_RESP_TYPE_SFT 0 + #define CREQ_DEALLOCATE_KEY_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DEALLOCATE_KEY_RESP_TYPE_LAST CREQ_DEALLOCATE_KEY_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DEALLOCATE_KEY_RESP_V 0x1UL + u8 event; + #define CREQ_DEALLOCATE_KEY_RESP_EVENT_DEALLOCATE_KEY 0xeUL + #define CREQ_DEALLOCATE_KEY_RESP_EVENT_LAST CREQ_DEALLOCATE_KEY_RESP_EVENT_DEALLOCATE_KEY + __le16 reserved16; + __le32 bound_window_info; +}; + +/* cmdq_register_mr (size:384b/48B) */ struct cmdq_register_mr { - u8 opcode; - #define CMDQ_REGISTER_MR_OPCODE_REGISTER_MR 0xfUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - u8 log2_pg_size_lvl; - #define CMDQ_REGISTER_MR_LVL_MASK 0x3UL - #define CMDQ_REGISTER_MR_LVL_SFT 0 - #define CMDQ_REGISTER_MR_LVL_LVL_0 0x0UL - #define CMDQ_REGISTER_MR_LVL_LVL_1 0x1UL - #define CMDQ_REGISTER_MR_LVL_LVL_2 0x2UL + u8 opcode; + #define CMDQ_REGISTER_MR_OPCODE_REGISTER_MR 0xfUL + #define CMDQ_REGISTER_MR_OPCODE_LAST CMDQ_REGISTER_MR_OPCODE_REGISTER_MR + u8 cmd_size; + __le16 flags; + #define CMDQ_REGISTER_MR_FLAGS_ALLOC_MR 0x1UL + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + u8 log2_pg_size_lvl; + #define CMDQ_REGISTER_MR_LVL_MASK 0x3UL + #define CMDQ_REGISTER_MR_LVL_SFT 0 + #define CMDQ_REGISTER_MR_LVL_LVL_0 0x0UL + #define CMDQ_REGISTER_MR_LVL_LVL_1 0x1UL + #define CMDQ_REGISTER_MR_LVL_LVL_2 0x2UL #define CMDQ_REGISTER_MR_LVL_LAST CMDQ_REGISTER_MR_LVL_LVL_2 - #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_MASK 0x7cUL - #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_SFT 2 + #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_MASK 0x7cUL + #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_SFT 2 #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_4K (0xcUL << 2) #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_8K (0xdUL << 2) #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_64K (0x10UL << 2) @@ -1549,16 +1378,15 @@ struct cmdq_register_mr { #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_2M (0x15UL << 2) #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_4M (0x16UL << 2) #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_1G (0x1eUL << 2) - #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_LAST \ - CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_1G + #define CMDQ_REGISTER_MR_LOG2_PG_SIZE_LAST CMDQ_REGISTER_MR_LOG2_PG_SIZE_PG_1G #define CMDQ_REGISTER_MR_UNUSED1 0x80UL - u8 access; - #define CMDQ_REGISTER_MR_ACCESS_LOCAL_WRITE 0x1UL - #define CMDQ_REGISTER_MR_ACCESS_REMOTE_READ 0x2UL - #define CMDQ_REGISTER_MR_ACCESS_REMOTE_WRITE 0x4UL - #define CMDQ_REGISTER_MR_ACCESS_REMOTE_ATOMIC 0x8UL - #define CMDQ_REGISTER_MR_ACCESS_MW_BIND 0x10UL - #define CMDQ_REGISTER_MR_ACCESS_ZERO_BASED 0x20UL + u8 access; + #define CMDQ_REGISTER_MR_ACCESS_LOCAL_WRITE 0x1UL + #define CMDQ_REGISTER_MR_ACCESS_REMOTE_READ 0x2UL + #define CMDQ_REGISTER_MR_ACCESS_REMOTE_WRITE 0x4UL + #define CMDQ_REGISTER_MR_ACCESS_REMOTE_ATOMIC 0x8UL + #define CMDQ_REGISTER_MR_ACCESS_MW_BIND 0x10UL + #define CMDQ_REGISTER_MR_ACCESS_ZERO_BASED 0x20UL __le16 log2_pbl_pg_size; #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_MASK 0x1fUL #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_SFT 0 @@ -1570,1448 +1398,509 @@ struct cmdq_register_mr { #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_PG_2M 0x15UL #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_PG_4M 0x16UL #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_PG_1G 0x1eUL - #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_LAST \ - CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_PG_1G + #define CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_LAST CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_PG_1G #define CMDQ_REGISTER_MR_UNUSED11_MASK 0xffe0UL #define CMDQ_REGISTER_MR_UNUSED11_SFT 5 - __le32 key; - __le64 pbl; - __le64 va; - __le64 mr_size; + __le32 key; + __le64 pbl; + __le64 va; + __le64 mr_size; }; -/* Deregister MR command (24 bytes) */ +/* creq_register_mr_resp (size:128b/16B) */ +struct creq_register_mr_resp { + u8 type; + #define CREQ_REGISTER_MR_RESP_TYPE_MASK 0x3fUL + #define CREQ_REGISTER_MR_RESP_TYPE_SFT 0 + #define CREQ_REGISTER_MR_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_REGISTER_MR_RESP_TYPE_LAST CREQ_REGISTER_MR_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_REGISTER_MR_RESP_V 0x1UL + u8 event; + #define CREQ_REGISTER_MR_RESP_EVENT_REGISTER_MR 0xfUL + #define CREQ_REGISTER_MR_RESP_EVENT_LAST CREQ_REGISTER_MR_RESP_EVENT_REGISTER_MR + u8 reserved48[6]; +}; + +/* cmdq_deregister_mr (size:192b/24B) */ struct cmdq_deregister_mr { - u8 opcode; - #define CMDQ_DEREGISTER_MR_OPCODE_DEREGISTER_MR 0x10UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 lkey; - __le32 unused_0; -}; - -/* Add GID command (48 bytes) */ -struct cmdq_add_gid { - u8 opcode; - #define CMDQ_ADD_GID_OPCODE_ADD_GID 0x11UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __be32 gid[4]; - __be16 src_mac[3]; - __le16 vlan; - #define CMDQ_ADD_GID_VLAN_VLAN_ID_MASK 0xfffUL - #define CMDQ_ADD_GID_VLAN_VLAN_ID_SFT 0 - #define CMDQ_ADD_GID_VLAN_TPID_MASK 0x7000UL - #define CMDQ_ADD_GID_VLAN_TPID_SFT 12 - #define CMDQ_ADD_GID_VLAN_TPID_TPID_88A8 (0x0UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_8100 (0x1UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_9100 (0x2UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_9200 (0x3UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_9300 (0x4UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG1 (0x5UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG2 (0x6UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG3 (0x7UL << 12) - #define CMDQ_ADD_GID_VLAN_TPID_LAST CMDQ_ADD_GID_VLAN_TPID_TPID_CFG3 - #define CMDQ_ADD_GID_VLAN_VLAN_EN 0x8000UL - __le16 ipid; - __le16 stats_ctx; - #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_ID_MASK 0x7fffUL - #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_ID_SFT 0 - #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_VALID 0x8000UL - __le32 unused_0; -}; - -/* Delete GID command (24 bytes) */ -struct cmdq_delete_gid { - u8 opcode; - #define CMDQ_DELETE_GID_OPCODE_DELETE_GID 0x12UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le16 gid_index; - __le16 unused_0; - __le32 unused_1; -}; - -/* Modify GID command (48 bytes) */ -struct cmdq_modify_gid { - u8 opcode; - #define CMDQ_MODIFY_GID_OPCODE_MODIFY_GID 0x17UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __be32 gid[4]; - __be16 src_mac[3]; - __le16 vlan; - #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_MASK 0xfffUL - #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_SFT 0 - #define CMDQ_MODIFY_GID_VLAN_TPID_MASK 0x7000UL - #define CMDQ_MODIFY_GID_VLAN_TPID_SFT 12 - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_88A8 (0x0UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_8100 (0x1UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9100 (0x2UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9200 (0x3UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9300 (0x4UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG1 (0x5UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG2 (0x6UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG3 (0x7UL << 12) - #define CMDQ_MODIFY_GID_VLAN_TPID_LAST \ - CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG3 - #define CMDQ_MODIFY_GID_VLAN_VLAN_EN 0x8000UL - __le16 ipid; - __le16 gid_index; - __le16 stats_ctx; - #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_ID_MASK 0x7fffUL - #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_ID_SFT 0 - #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_VALID 0x8000UL - __le16 unused_0; -}; - -/* Query GID command (24 bytes) */ -struct cmdq_query_gid { - u8 opcode; - #define CMDQ_QUERY_GID_OPCODE_QUERY_GID 0x18UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le16 gid_index; - __le16 unused_0; - __le32 unused_1; -}; - -/* Create QP1 command (80 bytes) */ -struct cmdq_create_qp1 { - u8 opcode; - #define CMDQ_CREATE_QP1_OPCODE_CREATE_QP1 0x13UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 qp_handle; - __le32 qp_flags; - #define CMDQ_CREATE_QP1_QP_FLAGS_SRQ_USED 0x1UL - #define CMDQ_CREATE_QP1_QP_FLAGS_FORCE_COMPLETION 0x2UL - #define CMDQ_CREATE_QP1_QP_FLAGS_RESERVED_LKEY_ENABLE 0x4UL - u8 type; - #define CMDQ_CREATE_QP1_TYPE_GSI 0x1UL - u8 sq_pg_size_sq_lvl; - #define CMDQ_CREATE_QP1_SQ_LVL_MASK 0xfUL - #define CMDQ_CREATE_QP1_SQ_LVL_SFT 0 - #define CMDQ_CREATE_QP1_SQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_QP1_SQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_QP1_SQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_SFT 4 - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 rq_pg_size_rq_lvl; - #define CMDQ_CREATE_QP1_RQ_LVL_MASK 0xfUL - #define CMDQ_CREATE_QP1_RQ_LVL_SFT 0 - #define CMDQ_CREATE_QP1_RQ_LVL_LVL_0 0x0UL - #define CMDQ_CREATE_QP1_RQ_LVL_LVL_1 0x1UL - #define CMDQ_CREATE_QP1_RQ_LVL_LVL_2 0x2UL - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_SFT 4 - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 unused_0; - __le32 dpi; - __le32 sq_size; - __le32 rq_size; - __le16 sq_fwo_sq_sge; - #define CMDQ_CREATE_QP1_SQ_SGE_MASK 0xfUL - #define CMDQ_CREATE_QP1_SQ_SGE_SFT 0 - #define CMDQ_CREATE_QP1_SQ_FWO_MASK 0xfff0UL - #define CMDQ_CREATE_QP1_SQ_FWO_SFT 4 - __le16 rq_fwo_rq_sge; - #define CMDQ_CREATE_QP1_RQ_SGE_MASK 0xfUL - #define CMDQ_CREATE_QP1_RQ_SGE_SFT 0 - #define CMDQ_CREATE_QP1_RQ_FWO_MASK 0xfff0UL - #define CMDQ_CREATE_QP1_RQ_FWO_SFT 4 - __le32 scq_cid; - __le32 rcq_cid; - __le32 srq_cid; - __le32 pd_id; - __le64 sq_pbl; - __le64 rq_pbl; -}; - -/* Destroy QP1 command (24 bytes) */ -struct cmdq_destroy_qp1 { - u8 opcode; - #define CMDQ_DESTROY_QP1_OPCODE_DESTROY_QP1 0x14UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 qp1_cid; - __le32 unused_0; -}; - -/* Create AH command (64 bytes) */ -struct cmdq_create_ah { - u8 opcode; - #define CMDQ_CREATE_AH_OPCODE_CREATE_AH 0x15UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le64 ah_handle; - __le32 dgid[4]; - u8 type; - #define CMDQ_CREATE_AH_TYPE_V1 0x0UL - #define CMDQ_CREATE_AH_TYPE_V2IPV4 0x2UL - #define CMDQ_CREATE_AH_TYPE_V2IPV6 0x3UL - u8 hop_limit; - __le16 sgid_index; - __le32 dest_vlan_id_flow_label; - #define CMDQ_CREATE_AH_FLOW_LABEL_MASK 0xfffffUL - #define CMDQ_CREATE_AH_FLOW_LABEL_SFT 0 - #define CMDQ_CREATE_AH_DEST_VLAN_ID_MASK 0xfff00000UL - #define CMDQ_CREATE_AH_DEST_VLAN_ID_SFT 20 - __le32 pd_id; - __le32 unused_0; - __le16 dest_mac[3]; - u8 traffic_class; - u8 unused_1; -}; - -/* Destroy AH command (24 bytes) */ -struct cmdq_destroy_ah { - u8 opcode; - #define CMDQ_DESTROY_AH_OPCODE_DESTROY_AH 0x16UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 ah_cid; - __le32 unused_0; -}; - -/* Initialize Firmware command (112 bytes) */ -struct cmdq_initialize_fw { - u8 opcode; - #define CMDQ_INITIALIZE_FW_OPCODE_INITIALIZE_FW 0x80UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - u8 qpc_pg_size_qpc_lvl; - #define CMDQ_INITIALIZE_FW_QPC_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_QPC_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_QPC_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_1G (0x5UL << 4) - u8 mrw_pg_size_mrw_lvl; - #define CMDQ_INITIALIZE_FW_MRW_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_MRW_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_MRW_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_MRW_PG_SIZE_PG_1G (0x5UL << 4) - u8 srq_pg_size_srq_lvl; - #define CMDQ_INITIALIZE_FW_SRQ_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_SRQ_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_SRQ_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_SRQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 cq_pg_size_cq_lvl; - #define CMDQ_INITIALIZE_FW_CQ_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_CQ_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_CQ_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_CQ_PG_SIZE_PG_1G (0x5UL << 4) - u8 tqm_pg_size_tqm_lvl; - #define CMDQ_INITIALIZE_FW_TQM_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_TQM_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_TQM_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_TQM_PG_SIZE_PG_1G (0x5UL << 4) - u8 tim_pg_size_tim_lvl; - #define CMDQ_INITIALIZE_FW_TIM_LVL_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_TIM_LVL_SFT 0 - #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_0 0x0UL - #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_1 0x1UL - #define CMDQ_INITIALIZE_FW_TIM_LVL_LVL_2 0x2UL - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_MASK 0xf0UL - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_SFT 4 - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_4K (0x0UL << 4) - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8K (0x1UL << 4) - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_64K (0x2UL << 4) - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M (0x3UL << 4) - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M (0x4UL << 4) - #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G (0x5UL << 4) - /* This value is (log-base-2-of-DBR-page-size - 12). - * 0 for 4KB. HW supported values are enumerated below. - */ - __le16 log2_dbr_pg_size; - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK 0xfUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT 0 - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K 0x0UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K 0x1UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K 0x2UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K 0x3UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K 0x4UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K 0x5UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K 0x6UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K 0x7UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M 0x8UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M 0x9UL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M 0xaUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M 0xbUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M 0xcUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M 0xdUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M 0xeUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M 0xfUL - #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST \ - CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M - __le64 qpc_page_dir; - __le64 mrw_page_dir; - __le64 srq_page_dir; - __le64 cq_page_dir; - __le64 tqm_page_dir; - __le64 tim_page_dir; - __le32 number_of_qp; - __le32 number_of_mrw; - __le32 number_of_srq; - __le32 number_of_cq; - __le32 max_qp_per_vf; - __le32 max_mrw_per_vf; - __le32 max_srq_per_vf; - __le32 max_cq_per_vf; - __le32 max_gid_per_vf; - __le32 stat_ctx_id; -}; - -/* De-initialize Firmware command (16 bytes) */ -struct cmdq_deinitialize_fw { - u8 opcode; - #define CMDQ_DEINITIALIZE_FW_OPCODE_DEINITIALIZE_FW 0x81UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; -}; - -/* Stop function command (16 bytes) */ -struct cmdq_stop_func { - u8 opcode; - #define CMDQ_STOP_FUNC_OPCODE_STOP_FUNC 0x82UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; -}; - -/* Query function command (16 bytes) */ -struct cmdq_query_func { - u8 opcode; - #define CMDQ_QUERY_FUNC_OPCODE_QUERY_FUNC 0x83UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; -}; - -/* Set function resources command (16 bytes) */ -struct cmdq_set_func_resources { - u8 opcode; - #define CMDQ_SET_FUNC_RESOURCES_OPCODE_SET_FUNC_RESOURCES 0x84UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 number_of_qp; - __le32 number_of_mrw; - __le32 number_of_srq; - __le32 number_of_cq; - __le32 max_qp_per_vf; - __le32 max_mrw_per_vf; - __le32 max_srq_per_vf; - __le32 max_cq_per_vf; - __le32 max_gid_per_vf; - __le32 stat_ctx_id; -}; - -/* Read hardware resource context command (24 bytes) */ -struct cmdq_read_context { - u8 opcode; - #define CMDQ_READ_CONTEXT_OPCODE_READ_CONTEXT 0x85UL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le32 type_xid; - #define CMDQ_READ_CONTEXT_XID_MASK 0xffffffUL - #define CMDQ_READ_CONTEXT_XID_SFT 0 - #define CMDQ_READ_CONTEXT_TYPE_MASK 0xff000000UL - #define CMDQ_READ_CONTEXT_TYPE_SFT 24 - #define CMDQ_READ_CONTEXT_TYPE_QPC (0x0UL << 24) - #define CMDQ_READ_CONTEXT_TYPE_CQ (0x1UL << 24) - #define CMDQ_READ_CONTEXT_TYPE_MRW (0x2UL << 24) - #define CMDQ_READ_CONTEXT_TYPE_SRQ (0x3UL << 24) - __le32 unused_0; -}; - -/* Map TC to COS. Can only be issued from a PF (24 bytes) */ -struct cmdq_map_tc_to_cos { - u8 opcode; - #define CMDQ_MAP_TC_TO_COS_OPCODE_MAP_TC_TO_COS 0x8aUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; - __le16 cos0; - #define CMDQ_MAP_TC_TO_COS_COS0_NO_CHANGE 0xffffUL - __le16 cos1; - #define CMDQ_MAP_TC_TO_COS_COS1_DISABLE 0x8000UL - #define CMDQ_MAP_TC_TO_COS_COS1_NO_CHANGE 0xffffUL - __le32 unused_0; -}; - -/* Query version command (16 bytes) */ -struct cmdq_query_version { - u8 opcode; - #define CMDQ_QUERY_VERSION_OPCODE_QUERY_VERSION 0x8bUL - u8 cmd_size; - __le16 flags; - __le16 cookie; - u8 resp_size; - u8 reserved8; - __le64 resp_addr; -}; - -/* Command-Response Event Queue (CREQ) Structures */ -/* Base CREQ Record (16 bytes) */ -struct creq_base { - u8 type; - #define CREQ_BASE_TYPE_MASK 0x3fUL - #define CREQ_BASE_TYPE_SFT 0 - #define CREQ_BASE_TYPE_QP_EVENT 0x38UL - #define CREQ_BASE_TYPE_FUNC_EVENT 0x3aUL - #define CREQ_BASE_RESERVED2_MASK 0xc0UL - #define CREQ_BASE_RESERVED2_SFT 6 - u8 reserved56[7]; - u8 v; - #define CREQ_BASE_V 0x1UL - #define CREQ_BASE_RESERVED7_MASK 0xfeUL - #define CREQ_BASE_RESERVED7_SFT 1 - u8 event; - __le16 reserved48[3]; -}; - -/* RoCE Function Async Event Notification (16 bytes) */ -struct creq_func_event { - u8 type; - #define CREQ_FUNC_EVENT_TYPE_MASK 0x3fUL - #define CREQ_FUNC_EVENT_TYPE_SFT 0 - #define CREQ_FUNC_EVENT_TYPE_FUNC_EVENT 0x3aUL - #define CREQ_FUNC_EVENT_RESERVED2_MASK 0xc0UL - #define CREQ_FUNC_EVENT_RESERVED2_SFT 6 - u8 reserved56[7]; - u8 v; - #define CREQ_FUNC_EVENT_V 0x1UL - #define CREQ_FUNC_EVENT_RESERVED7_MASK 0xfeUL - #define CREQ_FUNC_EVENT_RESERVED7_SFT 1 - u8 event; - #define CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR 0x1UL - #define CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR 0x2UL - #define CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR 0x3UL - #define CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR 0x4UL - #define CREQ_FUNC_EVENT_EVENT_CQ_ERROR 0x5UL - #define CREQ_FUNC_EVENT_EVENT_TQM_ERROR 0x6UL - #define CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR 0x7UL - #define CREQ_FUNC_EVENT_EVENT_CFCS_ERROR 0x8UL - #define CREQ_FUNC_EVENT_EVENT_CFCC_ERROR 0x9UL - #define CREQ_FUNC_EVENT_EVENT_CFCM_ERROR 0xaUL - #define CREQ_FUNC_EVENT_EVENT_TIM_ERROR 0xbUL - #define CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST 0x80UL - #define CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED 0x81UL - __le16 reserved48[3]; -}; - -/* RoCE Slowpath Command Completion (16 bytes) */ -struct creq_qp_event { - u8 type; - #define CREQ_QP_EVENT_TYPE_MASK 0x3fUL - #define CREQ_QP_EVENT_TYPE_SFT 0 - #define CREQ_QP_EVENT_TYPE_QP_EVENT 0x38UL - #define CREQ_QP_EVENT_RESERVED2_MASK 0xc0UL - #define CREQ_QP_EVENT_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_QP_EVENT_V 0x1UL - #define CREQ_QP_EVENT_RESERVED7_MASK 0xfeUL - #define CREQ_QP_EVENT_RESERVED7_SFT 1 - u8 event; - #define CREQ_QP_EVENT_EVENT_CREATE_QP 0x1UL - #define CREQ_QP_EVENT_EVENT_DESTROY_QP 0x2UL - #define CREQ_QP_EVENT_EVENT_MODIFY_QP 0x3UL - #define CREQ_QP_EVENT_EVENT_QUERY_QP 0x4UL - #define CREQ_QP_EVENT_EVENT_CREATE_SRQ 0x5UL - #define CREQ_QP_EVENT_EVENT_DESTROY_SRQ 0x6UL - #define CREQ_QP_EVENT_EVENT_QUERY_SRQ 0x8UL - #define CREQ_QP_EVENT_EVENT_CREATE_CQ 0x9UL - #define CREQ_QP_EVENT_EVENT_DESTROY_CQ 0xaUL - #define CREQ_QP_EVENT_EVENT_RESIZE_CQ 0xcUL - #define CREQ_QP_EVENT_EVENT_ALLOCATE_MRW 0xdUL - #define CREQ_QP_EVENT_EVENT_DEALLOCATE_KEY 0xeUL - #define CREQ_QP_EVENT_EVENT_REGISTER_MR 0xfUL - #define CREQ_QP_EVENT_EVENT_DEREGISTER_MR 0x10UL - #define CREQ_QP_EVENT_EVENT_ADD_GID 0x11UL - #define CREQ_QP_EVENT_EVENT_DELETE_GID 0x12UL - #define CREQ_QP_EVENT_EVENT_MODIFY_GID 0x17UL - #define CREQ_QP_EVENT_EVENT_QUERY_GID 0x18UL - #define CREQ_QP_EVENT_EVENT_CREATE_QP1 0x13UL - #define CREQ_QP_EVENT_EVENT_DESTROY_QP1 0x14UL - #define CREQ_QP_EVENT_EVENT_CREATE_AH 0x15UL - #define CREQ_QP_EVENT_EVENT_DESTROY_AH 0x16UL - #define CREQ_QP_EVENT_EVENT_INITIALIZE_FW 0x80UL - #define CREQ_QP_EVENT_EVENT_DEINITIALIZE_FW 0x81UL - #define CREQ_QP_EVENT_EVENT_STOP_FUNC 0x82UL - #define CREQ_QP_EVENT_EVENT_QUERY_FUNC 0x83UL - #define CREQ_QP_EVENT_EVENT_SET_FUNC_RESOURCES 0x84UL - #define CREQ_QP_EVENT_EVENT_MAP_TC_TO_COS 0x8aUL - #define CREQ_QP_EVENT_EVENT_QUERY_VERSION 0x8bUL - #define CREQ_QP_EVENT_EVENT_MODIFY_CC 0x8cUL - #define CREQ_QP_EVENT_EVENT_QUERY_CC 0x8dUL - #define CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION 0xc0UL - __le16 reserved48[3]; -}; - -/* Create QP command response (16 bytes) */ -struct creq_create_qp_resp { - u8 type; - #define CREQ_CREATE_QP_RESP_TYPE_MASK 0x3fUL - #define CREQ_CREATE_QP_RESP_TYPE_SFT 0 - #define CREQ_CREATE_QP_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_CREATE_QP_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_CREATE_QP_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_CREATE_QP_RESP_V 0x1UL - #define CREQ_CREATE_QP_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_CREATE_QP_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_CREATE_QP_RESP_EVENT_CREATE_QP 0x1UL - __le16 reserved48[3]; -}; - -/* Destroy QP command response (16 bytes) */ -struct creq_destroy_qp_resp { - u8 type; - #define CREQ_DESTROY_QP_RESP_TYPE_MASK 0x3fUL - #define CREQ_DESTROY_QP_RESP_TYPE_SFT 0 - #define CREQ_DESTROY_QP_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DESTROY_QP_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DESTROY_QP_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DESTROY_QP_RESP_V 0x1UL - #define CREQ_DESTROY_QP_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DESTROY_QP_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DESTROY_QP_RESP_EVENT_DESTROY_QP 0x2UL - __le16 reserved48[3]; -}; - -/* Modify QP command response (16 bytes) */ -struct creq_modify_qp_resp { - u8 type; - #define CREQ_MODIFY_QP_RESP_TYPE_MASK 0x3fUL - #define CREQ_MODIFY_QP_RESP_TYPE_SFT 0 - #define CREQ_MODIFY_QP_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_MODIFY_QP_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_MODIFY_QP_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_MODIFY_QP_RESP_V 0x1UL - #define CREQ_MODIFY_QP_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_MODIFY_QP_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_MODIFY_QP_RESP_EVENT_MODIFY_QP 0x3UL - __le16 reserved48[3]; -}; - -/* cmdq_query_roce_stats (size:128b/16B) */ -struct cmdq_query_roce_stats { u8 opcode; - #define CMDQ_QUERY_ROCE_STATS_OPCODE_QUERY_ROCE_STATS 0x8eUL - #define CMDQ_QUERY_ROCE_STATS_OPCODE_LAST \ - CMDQ_QUERY_ROCE_STATS_OPCODE_QUERY_ROCE_STATS + #define CMDQ_DEREGISTER_MR_OPCODE_DEREGISTER_MR 0x10UL + #define CMDQ_DEREGISTER_MR_OPCODE_LAST CMDQ_DEREGISTER_MR_OPCODE_DEREGISTER_MR u8 cmd_size; __le16 flags; __le16 cookie; u8 resp_size; u8 reserved8; __le64 resp_addr; + __le32 lkey; + __le32 unused_0; }; -/* Query QP command response (16 bytes) */ -struct creq_query_qp_resp { - u8 type; - #define CREQ_QUERY_QP_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_QP_RESP_TYPE_SFT 0 - #define CREQ_QUERY_QP_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_QP_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_QP_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 size; - u8 v; - #define CREQ_QUERY_QP_RESP_V 0x1UL - #define CREQ_QUERY_QP_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_QP_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_QP_RESP_EVENT_QUERY_QP 0x4UL - __le16 reserved48[3]; -}; - -/* Query QP command response side buffer structure (104 bytes) */ -struct creq_query_qp_resp_sb { - u8 opcode; - #define CREQ_QUERY_QP_RESP_SB_OPCODE_QUERY_QP 0x4UL - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 reserved8; - __le32 xid; - u8 en_sqd_async_notify_state; - #define CREQ_QUERY_QP_RESP_SB_STATE_MASK 0xfUL - #define CREQ_QUERY_QP_RESP_SB_STATE_SFT 0 - #define CREQ_QUERY_QP_RESP_SB_STATE_RESET 0x0UL - #define CREQ_QUERY_QP_RESP_SB_STATE_INIT 0x1UL - #define CREQ_QUERY_QP_RESP_SB_STATE_RTR 0x2UL - #define CREQ_QUERY_QP_RESP_SB_STATE_RTS 0x3UL - #define CREQ_QUERY_QP_RESP_SB_STATE_SQD 0x4UL - #define CREQ_QUERY_QP_RESP_SB_STATE_SQE 0x5UL - #define CREQ_QUERY_QP_RESP_SB_STATE_ERR 0x6UL - #define CREQ_QUERY_QP_RESP_SB_EN_SQD_ASYNC_NOTIFY 0x10UL - u8 access; - #define CREQ_QUERY_QP_RESP_SB_ACCESS_LOCAL_WRITE 0x1UL - #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_WRITE 0x2UL - #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_READ 0x4UL - #define CREQ_QUERY_QP_RESP_SB_ACCESS_REMOTE_ATOMIC 0x8UL - __le16 pkey; - __le32 qkey; - __le32 reserved32; - __le32 dgid[4]; - __le32 flow_label; - __le16 sgid_index; - u8 hop_limit; - u8 traffic_class; - __le16 dest_mac[3]; - __le16 path_mtu_dest_vlan_id; - #define CREQ_QUERY_QP_RESP_SB_DEST_VLAN_ID_MASK 0xfffUL - #define CREQ_QUERY_QP_RESP_SB_DEST_VLAN_ID_SFT 0 - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MASK 0xf000UL - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_SFT 12 - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_256 (0x0UL << 12) - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_512 (0x1UL << 12) - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_1024 (0x2UL << 12) - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_2048 (0x3UL << 12) - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_4096 (0x4UL << 12) - #define CREQ_QUERY_QP_RESP_SB_PATH_MTU_MTU_8192 (0x5UL << 12) - u8 timeout; - u8 retry_cnt; - u8 rnr_retry; - u8 min_rnr_timer; - __le32 rq_psn; - __le32 sq_psn; - u8 max_rd_atomic; - u8 max_dest_rd_atomic; - u8 tos_dscp_tos_ecn; - #define CREQ_QUERY_QP_RESP_SB_TOS_ECN_MASK 0x3UL - #define CREQ_QUERY_QP_RESP_SB_TOS_ECN_SFT 0 - #define CREQ_QUERY_QP_RESP_SB_TOS_DSCP_MASK 0xfcUL - #define CREQ_QUERY_QP_RESP_SB_TOS_DSCP_SFT 2 - u8 enable_cc; - #define CREQ_QUERY_QP_RESP_SB_ENABLE_CC 0x1UL - #define CREQ_QUERY_QP_RESP_SB_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_QP_RESP_SB_RESERVED7_SFT 1 - __le32 sq_size; - __le32 rq_size; - __le16 sq_sge; - __le16 rq_sge; - __le32 max_inline_data; - __le32 dest_qp_id; - __le32 unused_1; - __le16 src_mac[3]; - __le16 vlan_pcp_vlan_dei_vlan_id; - #define CREQ_QUERY_QP_RESP_SB_VLAN_ID_MASK 0xfffUL - #define CREQ_QUERY_QP_RESP_SB_VLAN_ID_SFT 0 - #define CREQ_QUERY_QP_RESP_SB_VLAN_DEI 0x1000UL - #define CREQ_QUERY_QP_RESP_SB_VLAN_PCP_MASK 0xe000UL - #define CREQ_QUERY_QP_RESP_SB_VLAN_PCP_SFT 13 -}; - -/* Create SRQ command response (16 bytes) */ -struct creq_create_srq_resp { - u8 type; - #define CREQ_CREATE_SRQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_CREATE_SRQ_RESP_TYPE_SFT 0 - #define CREQ_CREATE_SRQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_CREATE_SRQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_CREATE_SRQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_CREATE_SRQ_RESP_V 0x1UL - #define CREQ_CREATE_SRQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_CREATE_SRQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_CREATE_SRQ_RESP_EVENT_CREATE_SRQ 0x5UL - __le16 reserved48[3]; -}; - -/* Destroy SRQ command response (16 bytes) */ -struct creq_destroy_srq_resp { - u8 type; - #define CREQ_DESTROY_SRQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_DESTROY_SRQ_RESP_TYPE_SFT 0 - #define CREQ_DESTROY_SRQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DESTROY_SRQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DESTROY_SRQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DESTROY_SRQ_RESP_V 0x1UL - #define CREQ_DESTROY_SRQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DESTROY_SRQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DESTROY_SRQ_RESP_EVENT_DESTROY_SRQ 0x6UL - __le16 enable_for_arm[3]; - #define CREQ_DESTROY_SRQ_RESP_ENABLE_FOR_ARM_MASK 0x30000UL - #define CREQ_DESTROY_SRQ_RESP_ENABLE_FOR_ARM_SFT 16 - #define CREQ_DESTROY_SRQ_RESP_RESERVED46_MASK 0xfffc0000UL - #define CREQ_DESTROY_SRQ_RESP_RESERVED46_SFT 18 -}; - -/* Query SRQ command response (16 bytes) */ -struct creq_query_srq_resp { - u8 type; - #define CREQ_QUERY_SRQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_SRQ_RESP_TYPE_SFT 0 - #define CREQ_QUERY_SRQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_SRQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_SRQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 size; - u8 v; - #define CREQ_QUERY_SRQ_RESP_V 0x1UL - #define CREQ_QUERY_SRQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_SRQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_SRQ_RESP_EVENT_QUERY_SRQ 0x8UL - __le16 reserved48[3]; -}; - -/* Query SRQ command response side buffer structure (24 bytes) */ -struct creq_query_srq_resp_sb { - u8 opcode; - #define CREQ_QUERY_SRQ_RESP_SB_OPCODE_QUERY_SRQ 0x8UL - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 reserved8; - __le32 xid; - __le16 srq_limit; - __le16 reserved16; - __le32 data[4]; -}; - -/* Create CQ command Response (16 bytes) */ -struct creq_create_cq_resp { - u8 type; - #define CREQ_CREATE_CQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_CREATE_CQ_RESP_TYPE_SFT 0 - #define CREQ_CREATE_CQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_CREATE_CQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_CREATE_CQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_CREATE_CQ_RESP_V 0x1UL - #define CREQ_CREATE_CQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_CREATE_CQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_CREATE_CQ_RESP_EVENT_CREATE_CQ 0x9UL - __le16 reserved48[3]; -}; - -/* Destroy CQ command response (16 bytes) */ -struct creq_destroy_cq_resp { - u8 type; - #define CREQ_DESTROY_CQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_DESTROY_CQ_RESP_TYPE_SFT 0 - #define CREQ_DESTROY_CQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DESTROY_CQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DESTROY_CQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DESTROY_CQ_RESP_V 0x1UL - #define CREQ_DESTROY_CQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DESTROY_CQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DESTROY_CQ_RESP_EVENT_DESTROY_CQ 0xaUL - __le16 cq_arm_lvl; - #define CREQ_DESTROY_CQ_RESP_CQ_ARM_LVL_MASK 0x3UL - #define CREQ_DESTROY_CQ_RESP_CQ_ARM_LVL_SFT 0 - #define CREQ_DESTROY_CQ_RESP_RESERVED14_MASK 0xfffcUL - #define CREQ_DESTROY_CQ_RESP_RESERVED14_SFT 2 - __le16 total_cnq_events; - __le16 reserved16; -}; - -/* Resize CQ command response (16 bytes) */ -struct creq_resize_cq_resp { - u8 type; - #define CREQ_RESIZE_CQ_RESP_TYPE_MASK 0x3fUL - #define CREQ_RESIZE_CQ_RESP_TYPE_SFT 0 - #define CREQ_RESIZE_CQ_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_RESIZE_CQ_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_RESIZE_CQ_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_RESIZE_CQ_RESP_V 0x1UL - #define CREQ_RESIZE_CQ_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_RESIZE_CQ_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_RESIZE_CQ_RESP_EVENT_RESIZE_CQ 0xcUL - __le16 reserved48[3]; -}; - -/* Allocate MRW command response (16 bytes) */ -struct creq_allocate_mrw_resp { - u8 type; - #define CREQ_ALLOCATE_MRW_RESP_TYPE_MASK 0x3fUL - #define CREQ_ALLOCATE_MRW_RESP_TYPE_SFT 0 - #define CREQ_ALLOCATE_MRW_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_ALLOCATE_MRW_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_ALLOCATE_MRW_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_ALLOCATE_MRW_RESP_V 0x1UL - #define CREQ_ALLOCATE_MRW_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_ALLOCATE_MRW_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_ALLOCATE_MRW_RESP_EVENT_ALLOCATE_MRW 0xdUL - __le16 reserved48[3]; -}; - -/* De-allocate key command response (16 bytes) */ -struct creq_deallocate_key_resp { - u8 type; - #define CREQ_DEALLOCATE_KEY_RESP_TYPE_MASK 0x3fUL - #define CREQ_DEALLOCATE_KEY_RESP_TYPE_SFT 0 - #define CREQ_DEALLOCATE_KEY_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DEALLOCATE_KEY_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DEALLOCATE_KEY_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DEALLOCATE_KEY_RESP_V 0x1UL - #define CREQ_DEALLOCATE_KEY_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DEALLOCATE_KEY_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DEALLOCATE_KEY_RESP_EVENT_DEALLOCATE_KEY 0xeUL - __le16 reserved16; - __le32 bound_window_info; -}; - -/* Register MR command response (16 bytes) */ -struct creq_register_mr_resp { - u8 type; - #define CREQ_REGISTER_MR_RESP_TYPE_MASK 0x3fUL - #define CREQ_REGISTER_MR_RESP_TYPE_SFT 0 - #define CREQ_REGISTER_MR_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_REGISTER_MR_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_REGISTER_MR_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_REGISTER_MR_RESP_V 0x1UL - #define CREQ_REGISTER_MR_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_REGISTER_MR_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_REGISTER_MR_RESP_EVENT_REGISTER_MR 0xfUL - __le16 reserved48[3]; -}; - -/* Deregister MR command response (16 bytes) */ +/* creq_deregister_mr_resp (size:128b/16B) */ struct creq_deregister_mr_resp { - u8 type; - #define CREQ_DEREGISTER_MR_RESP_TYPE_MASK 0x3fUL - #define CREQ_DEREGISTER_MR_RESP_TYPE_SFT 0 - #define CREQ_DEREGISTER_MR_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DEREGISTER_MR_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DEREGISTER_MR_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DEREGISTER_MR_RESP_V 0x1UL - #define CREQ_DEREGISTER_MR_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DEREGISTER_MR_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DEREGISTER_MR_RESP_EVENT_DEREGISTER_MR 0x10UL - __le16 reserved16; - __le32 bound_windows; + u8 type; + #define CREQ_DEREGISTER_MR_RESP_TYPE_MASK 0x3fUL + #define CREQ_DEREGISTER_MR_RESP_TYPE_SFT 0 + #define CREQ_DEREGISTER_MR_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DEREGISTER_MR_RESP_TYPE_LAST CREQ_DEREGISTER_MR_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DEREGISTER_MR_RESP_V 0x1UL + u8 event; + #define CREQ_DEREGISTER_MR_RESP_EVENT_DEREGISTER_MR 0x10UL + #define CREQ_DEREGISTER_MR_RESP_EVENT_LAST CREQ_DEREGISTER_MR_RESP_EVENT_DEREGISTER_MR + __le16 reserved16; + __le32 bound_windows; }; -/* Add GID command response (16 bytes) */ +/* cmdq_add_gid (size:384b/48B) */ +struct cmdq_add_gid { + u8 opcode; + #define CMDQ_ADD_GID_OPCODE_ADD_GID 0x11UL + #define CMDQ_ADD_GID_OPCODE_LAST CMDQ_ADD_GID_OPCODE_ADD_GID + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __be32 gid[4]; + __be16 src_mac[3]; + __le16 vlan; + #define CMDQ_ADD_GID_VLAN_VLAN_EN_TPID_VLAN_ID_MASK 0xffffUL + #define CMDQ_ADD_GID_VLAN_VLAN_EN_TPID_VLAN_ID_SFT 0 + #define CMDQ_ADD_GID_VLAN_VLAN_ID_MASK 0xfffUL + #define CMDQ_ADD_GID_VLAN_VLAN_ID_SFT 0 + #define CMDQ_ADD_GID_VLAN_TPID_MASK 0x7000UL + #define CMDQ_ADD_GID_VLAN_TPID_SFT 12 + #define CMDQ_ADD_GID_VLAN_TPID_TPID_88A8 (0x0UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_8100 (0x1UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_9100 (0x2UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_9200 (0x3UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_9300 (0x4UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG1 (0x5UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG2 (0x6UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_TPID_CFG3 (0x7UL << 12) + #define CMDQ_ADD_GID_VLAN_TPID_LAST CMDQ_ADD_GID_VLAN_TPID_TPID_CFG3 + #define CMDQ_ADD_GID_VLAN_VLAN_EN 0x8000UL + __le16 ipid; + __le16 stats_ctx; + #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_VALID_STATS_CTX_ID_MASK 0xffffUL + #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_VALID_STATS_CTX_ID_SFT 0 + #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_ID_MASK 0x7fffUL + #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_ID_SFT 0 + #define CMDQ_ADD_GID_STATS_CTX_STATS_CTX_VALID 0x8000UL + __le32 unused_0; +}; + +/* creq_add_gid_resp (size:128b/16B) */ struct creq_add_gid_resp { - u8 type; - #define CREQ_ADD_GID_RESP_TYPE_MASK 0x3fUL - #define CREQ_ADD_GID_RESP_TYPE_SFT 0 - #define CREQ_ADD_GID_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_ADD_GID_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_ADD_GID_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_ADD_GID_RESP_V 0x1UL - #define CREQ_ADD_GID_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_ADD_GID_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_ADD_GID_RESP_EVENT_ADD_GID 0x11UL - __le16 reserved48[3]; + u8 type; + #define CREQ_ADD_GID_RESP_TYPE_MASK 0x3fUL + #define CREQ_ADD_GID_RESP_TYPE_SFT 0 + #define CREQ_ADD_GID_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_ADD_GID_RESP_TYPE_LAST CREQ_ADD_GID_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_ADD_GID_RESP_V 0x1UL + u8 event; + #define CREQ_ADD_GID_RESP_EVENT_ADD_GID 0x11UL + #define CREQ_ADD_GID_RESP_EVENT_LAST CREQ_ADD_GID_RESP_EVENT_ADD_GID + u8 reserved48[6]; }; -/* Delete GID command response (16 bytes) */ +/* cmdq_delete_gid (size:192b/24B) */ +struct cmdq_delete_gid { + u8 opcode; + #define CMDQ_DELETE_GID_OPCODE_DELETE_GID 0x12UL + #define CMDQ_DELETE_GID_OPCODE_LAST CMDQ_DELETE_GID_OPCODE_DELETE_GID + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le16 gid_index; + u8 unused_0[6]; +}; + +/* creq_delete_gid_resp (size:128b/16B) */ struct creq_delete_gid_resp { - u8 type; - #define CREQ_DELETE_GID_RESP_TYPE_MASK 0x3fUL - #define CREQ_DELETE_GID_RESP_TYPE_SFT 0 - #define CREQ_DELETE_GID_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DELETE_GID_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DELETE_GID_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DELETE_GID_RESP_V 0x1UL - #define CREQ_DELETE_GID_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DELETE_GID_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DELETE_GID_RESP_EVENT_DELETE_GID 0x12UL - __le16 reserved48[3]; + u8 type; + #define CREQ_DELETE_GID_RESP_TYPE_MASK 0x3fUL + #define CREQ_DELETE_GID_RESP_TYPE_SFT 0 + #define CREQ_DELETE_GID_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DELETE_GID_RESP_TYPE_LAST CREQ_DELETE_GID_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DELETE_GID_RESP_V 0x1UL + u8 event; + #define CREQ_DELETE_GID_RESP_EVENT_DELETE_GID 0x12UL + #define CREQ_DELETE_GID_RESP_EVENT_LAST CREQ_DELETE_GID_RESP_EVENT_DELETE_GID + u8 reserved48[6]; }; -/* Modify GID command response (16 bytes) */ +/* cmdq_modify_gid (size:384b/48B) */ +struct cmdq_modify_gid { + u8 opcode; + #define CMDQ_MODIFY_GID_OPCODE_MODIFY_GID 0x17UL + #define CMDQ_MODIFY_GID_OPCODE_LAST CMDQ_MODIFY_GID_OPCODE_MODIFY_GID + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __be32 gid[4]; + __be16 src_mac[3]; + __le16 vlan; + #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_MASK 0xfffUL + #define CMDQ_MODIFY_GID_VLAN_VLAN_ID_SFT 0 + #define CMDQ_MODIFY_GID_VLAN_TPID_MASK 0x7000UL + #define CMDQ_MODIFY_GID_VLAN_TPID_SFT 12 + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_88A8 (0x0UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_8100 (0x1UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9100 (0x2UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9200 (0x3UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_9300 (0x4UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG1 (0x5UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG2 (0x6UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG3 (0x7UL << 12) + #define CMDQ_MODIFY_GID_VLAN_TPID_LAST CMDQ_MODIFY_GID_VLAN_TPID_TPID_CFG3 + #define CMDQ_MODIFY_GID_VLAN_VLAN_EN 0x8000UL + __le16 ipid; + __le16 gid_index; + __le16 stats_ctx; + #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_ID_MASK 0x7fffUL + #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_ID_SFT 0 + #define CMDQ_MODIFY_GID_STATS_CTX_STATS_CTX_VALID 0x8000UL + __le16 unused_0; +}; + +/* creq_modify_gid_resp (size:128b/16B) */ struct creq_modify_gid_resp { - u8 type; - #define CREQ_MODIFY_GID_RESP_TYPE_MASK 0x3fUL - #define CREQ_MODIFY_GID_RESP_TYPE_SFT 0 - #define CREQ_MODIFY_GID_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_MODIFY_GID_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_MODIFY_GID_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_MODIFY_GID_RESP_V 0x1UL - #define CREQ_MODIFY_GID_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_MODIFY_GID_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_MODIFY_GID_RESP_EVENT_ADD_GID 0x11UL - __le16 reserved48[3]; + u8 type; + #define CREQ_MODIFY_GID_RESP_TYPE_MASK 0x3fUL + #define CREQ_MODIFY_GID_RESP_TYPE_SFT 0 + #define CREQ_MODIFY_GID_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_MODIFY_GID_RESP_TYPE_LAST CREQ_MODIFY_GID_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_MODIFY_GID_RESP_V 0x1UL + u8 event; + #define CREQ_MODIFY_GID_RESP_EVENT_ADD_GID 0x11UL + #define CREQ_MODIFY_GID_RESP_EVENT_LAST CREQ_MODIFY_GID_RESP_EVENT_ADD_GID + u8 reserved48[6]; }; -/* Query GID command response (16 bytes) */ +/* cmdq_query_gid (size:192b/24B) */ +struct cmdq_query_gid { + u8 opcode; + #define CMDQ_QUERY_GID_OPCODE_QUERY_GID 0x18UL + #define CMDQ_QUERY_GID_OPCODE_LAST CMDQ_QUERY_GID_OPCODE_QUERY_GID + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le16 gid_index; + u8 unused16[6]; +}; + +/* creq_query_gid_resp (size:128b/16B) */ struct creq_query_gid_resp { - u8 type; - #define CREQ_QUERY_GID_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_GID_RESP_TYPE_SFT 0 - #define CREQ_QUERY_GID_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_GID_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_GID_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 size; - u8 v; - #define CREQ_QUERY_GID_RESP_V 0x1UL - #define CREQ_QUERY_GID_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_GID_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_GID_RESP_EVENT_QUERY_GID 0x18UL - __le16 reserved48[3]; + u8 type; + #define CREQ_QUERY_GID_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_GID_RESP_TYPE_SFT 0 + #define CREQ_QUERY_GID_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_GID_RESP_TYPE_LAST CREQ_QUERY_GID_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_GID_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_GID_RESP_EVENT_QUERY_GID 0x18UL + #define CREQ_QUERY_GID_RESP_EVENT_LAST CREQ_QUERY_GID_RESP_EVENT_QUERY_GID + u8 reserved48[6]; }; -/* Query GID command response side buffer structure (40 bytes) */ +/* creq_query_gid_resp_sb (size:320b/40B) */ struct creq_query_gid_resp_sb { - u8 opcode; - #define CREQ_QUERY_GID_RESP_SB_OPCODE_QUERY_GID 0x18UL - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 reserved8; - __le32 gid[4]; - __le16 src_mac[3]; - __le16 vlan; - #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_ID_MASK 0xfffUL - #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_ID_SFT 0 - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_MASK 0x7000UL - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_SFT 12 - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_88A8 (0x0UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_8100 (0x1UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9100 (0x2UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9200 (0x3UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9300 (0x4UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG1 (0x5UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG2 (0x6UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG3 (0x7UL << 12) - #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_LAST \ - CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG3 - #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_EN 0x8000UL - __le16 ipid; - __le16 gid_index; - __le32 unused_0; + u8 opcode; + #define CREQ_QUERY_GID_RESP_SB_OPCODE_QUERY_GID 0x18UL + #define CREQ_QUERY_GID_RESP_SB_OPCODE_LAST CREQ_QUERY_GID_RESP_SB_OPCODE_QUERY_GID + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le32 gid[4]; + __le16 src_mac[3]; + __le16 vlan; + #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_EN_TPID_VLAN_ID_MASK 0xffffUL + #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_EN_TPID_VLAN_ID_SFT 0 + #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_ID_MASK 0xfffUL + #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_ID_SFT 0 + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_MASK 0x7000UL + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_SFT 12 + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_88A8 (0x0UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_8100 (0x1UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9100 (0x2UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9200 (0x3UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_9300 (0x4UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG1 (0x5UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG2 (0x6UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG3 (0x7UL << 12) + #define CREQ_QUERY_GID_RESP_SB_VLAN_TPID_LAST CREQ_QUERY_GID_RESP_SB_VLAN_TPID_TPID_CFG3 + #define CREQ_QUERY_GID_RESP_SB_VLAN_VLAN_EN 0x8000UL + __le16 ipid; + __le16 gid_index; + __le32 unused_0; }; -/* Create QP1 command response (16 bytes) */ +/* cmdq_create_qp1 (size:640b/80B) */ +struct cmdq_create_qp1 { + u8 opcode; + #define CMDQ_CREATE_QP1_OPCODE_CREATE_QP1 0x13UL + #define CMDQ_CREATE_QP1_OPCODE_LAST CMDQ_CREATE_QP1_OPCODE_CREATE_QP1 + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 qp_handle; + __le32 qp_flags; + #define CMDQ_CREATE_QP1_QP_FLAGS_SRQ_USED 0x1UL + #define CMDQ_CREATE_QP1_QP_FLAGS_FORCE_COMPLETION 0x2UL + #define CMDQ_CREATE_QP1_QP_FLAGS_RESERVED_LKEY_ENABLE 0x4UL + #define CMDQ_CREATE_QP1_QP_FLAGS_LAST CMDQ_CREATE_QP1_QP_FLAGS_RESERVED_LKEY_ENABLE + u8 type; + #define CMDQ_CREATE_QP1_TYPE_GSI 0x1UL + #define CMDQ_CREATE_QP1_TYPE_LAST CMDQ_CREATE_QP1_TYPE_GSI + u8 sq_pg_size_sq_lvl; + #define CMDQ_CREATE_QP1_SQ_LVL_MASK 0xfUL + #define CMDQ_CREATE_QP1_SQ_LVL_SFT 0 + #define CMDQ_CREATE_QP1_SQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_QP1_SQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_QP1_SQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_QP1_SQ_LVL_LAST CMDQ_CREATE_QP1_SQ_LVL_LVL_2 + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_SFT 4 + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_CREATE_QP1_SQ_PG_SIZE_LAST CMDQ_CREATE_QP1_SQ_PG_SIZE_PG_1G + u8 rq_pg_size_rq_lvl; + #define CMDQ_CREATE_QP1_RQ_LVL_MASK 0xfUL + #define CMDQ_CREATE_QP1_RQ_LVL_SFT 0 + #define CMDQ_CREATE_QP1_RQ_LVL_LVL_0 0x0UL + #define CMDQ_CREATE_QP1_RQ_LVL_LVL_1 0x1UL + #define CMDQ_CREATE_QP1_RQ_LVL_LVL_2 0x2UL + #define CMDQ_CREATE_QP1_RQ_LVL_LAST CMDQ_CREATE_QP1_RQ_LVL_LVL_2 + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_MASK 0xf0UL + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_SFT 4 + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_4K (0x0UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_8K (0x1UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_64K (0x2UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_2M (0x3UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_8M (0x4UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_1G (0x5UL << 4) + #define CMDQ_CREATE_QP1_RQ_PG_SIZE_LAST CMDQ_CREATE_QP1_RQ_PG_SIZE_PG_1G + u8 unused_0; + __le32 dpi; + __le32 sq_size; + __le32 rq_size; + __le16 sq_fwo_sq_sge; + #define CMDQ_CREATE_QP1_SQ_SGE_MASK 0xfUL + #define CMDQ_CREATE_QP1_SQ_SGE_SFT 0 + #define CMDQ_CREATE_QP1_SQ_FWO_MASK 0xfff0UL + #define CMDQ_CREATE_QP1_SQ_FWO_SFT 4 + __le16 rq_fwo_rq_sge; + #define CMDQ_CREATE_QP1_RQ_SGE_MASK 0xfUL + #define CMDQ_CREATE_QP1_RQ_SGE_SFT 0 + #define CMDQ_CREATE_QP1_RQ_FWO_MASK 0xfff0UL + #define CMDQ_CREATE_QP1_RQ_FWO_SFT 4 + __le32 scq_cid; + __le32 rcq_cid; + __le32 srq_cid; + __le32 pd_id; + __le64 sq_pbl; + __le64 rq_pbl; +}; + +/* creq_create_qp1_resp (size:128b/16B) */ struct creq_create_qp1_resp { - u8 type; - #define CREQ_CREATE_QP1_RESP_TYPE_MASK 0x3fUL - #define CREQ_CREATE_QP1_RESP_TYPE_SFT 0 - #define CREQ_CREATE_QP1_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_CREATE_QP1_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_CREATE_QP1_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_CREATE_QP1_RESP_V 0x1UL - #define CREQ_CREATE_QP1_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_CREATE_QP1_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_CREATE_QP1_RESP_EVENT_CREATE_QP1 0x13UL - __le16 reserved48[3]; + u8 type; + #define CREQ_CREATE_QP1_RESP_TYPE_MASK 0x3fUL + #define CREQ_CREATE_QP1_RESP_TYPE_SFT 0 + #define CREQ_CREATE_QP1_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_CREATE_QP1_RESP_TYPE_LAST CREQ_CREATE_QP1_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_CREATE_QP1_RESP_V 0x1UL + u8 event; + #define CREQ_CREATE_QP1_RESP_EVENT_CREATE_QP1 0x13UL + #define CREQ_CREATE_QP1_RESP_EVENT_LAST CREQ_CREATE_QP1_RESP_EVENT_CREATE_QP1 + u8 reserved48[6]; }; -/* Destroy QP1 command response (16 bytes) */ +/* cmdq_destroy_qp1 (size:192b/24B) */ +struct cmdq_destroy_qp1 { + u8 opcode; + #define CMDQ_DESTROY_QP1_OPCODE_DESTROY_QP1 0x14UL + #define CMDQ_DESTROY_QP1_OPCODE_LAST CMDQ_DESTROY_QP1_OPCODE_DESTROY_QP1 + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 qp1_cid; + __le32 unused_0; +}; + +/* creq_destroy_qp1_resp (size:128b/16B) */ struct creq_destroy_qp1_resp { - u8 type; - #define CREQ_DESTROY_QP1_RESP_TYPE_MASK 0x3fUL - #define CREQ_DESTROY_QP1_RESP_TYPE_SFT 0 - #define CREQ_DESTROY_QP1_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DESTROY_QP1_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DESTROY_QP1_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DESTROY_QP1_RESP_V 0x1UL - #define CREQ_DESTROY_QP1_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DESTROY_QP1_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DESTROY_QP1_RESP_EVENT_DESTROY_QP1 0x14UL - __le16 reserved48[3]; + u8 type; + #define CREQ_DESTROY_QP1_RESP_TYPE_MASK 0x3fUL + #define CREQ_DESTROY_QP1_RESP_TYPE_SFT 0 + #define CREQ_DESTROY_QP1_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DESTROY_QP1_RESP_TYPE_LAST CREQ_DESTROY_QP1_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DESTROY_QP1_RESP_V 0x1UL + u8 event; + #define CREQ_DESTROY_QP1_RESP_EVENT_DESTROY_QP1 0x14UL + #define CREQ_DESTROY_QP1_RESP_EVENT_LAST CREQ_DESTROY_QP1_RESP_EVENT_DESTROY_QP1 + u8 reserved48[6]; }; -/* Create AH command response (16 bytes) */ +/* cmdq_create_ah (size:512b/64B) */ +struct cmdq_create_ah { + u8 opcode; + #define CMDQ_CREATE_AH_OPCODE_CREATE_AH 0x15UL + #define CMDQ_CREATE_AH_OPCODE_LAST CMDQ_CREATE_AH_OPCODE_CREATE_AH + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le64 ah_handle; + __le32 dgid[4]; + u8 type; + #define CMDQ_CREATE_AH_TYPE_V1 0x0UL + #define CMDQ_CREATE_AH_TYPE_V2IPV4 0x2UL + #define CMDQ_CREATE_AH_TYPE_V2IPV6 0x3UL + #define CMDQ_CREATE_AH_TYPE_LAST CMDQ_CREATE_AH_TYPE_V2IPV6 + u8 hop_limit; + __le16 sgid_index; + __le32 dest_vlan_id_flow_label; + #define CMDQ_CREATE_AH_FLOW_LABEL_MASK 0xfffffUL + #define CMDQ_CREATE_AH_FLOW_LABEL_SFT 0 + #define CMDQ_CREATE_AH_DEST_VLAN_ID_MASK 0xfff00000UL + #define CMDQ_CREATE_AH_DEST_VLAN_ID_SFT 20 + __le32 pd_id; + __le32 unused_0; + __le16 dest_mac[3]; + u8 traffic_class; + u8 enable_cc; + #define CMDQ_CREATE_AH_ENABLE_CC 0x1UL +}; + +/* creq_create_ah_resp (size:128b/16B) */ struct creq_create_ah_resp { - u8 type; - #define CREQ_CREATE_AH_RESP_TYPE_MASK 0x3fUL - #define CREQ_CREATE_AH_RESP_TYPE_SFT 0 - #define CREQ_CREATE_AH_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_CREATE_AH_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_CREATE_AH_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_CREATE_AH_RESP_V 0x1UL - #define CREQ_CREATE_AH_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_CREATE_AH_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_CREATE_AH_RESP_EVENT_CREATE_AH 0x15UL - __le16 reserved48[3]; + u8 type; + #define CREQ_CREATE_AH_RESP_TYPE_MASK 0x3fUL + #define CREQ_CREATE_AH_RESP_TYPE_SFT 0 + #define CREQ_CREATE_AH_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_CREATE_AH_RESP_TYPE_LAST CREQ_CREATE_AH_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_CREATE_AH_RESP_V 0x1UL + u8 event; + #define CREQ_CREATE_AH_RESP_EVENT_CREATE_AH 0x15UL + #define CREQ_CREATE_AH_RESP_EVENT_LAST CREQ_CREATE_AH_RESP_EVENT_CREATE_AH + u8 reserved48[6]; }; -/* Destroy AH command response (16 bytes) */ +/* cmdq_destroy_ah (size:192b/24B) */ +struct cmdq_destroy_ah { + u8 opcode; + #define CMDQ_DESTROY_AH_OPCODE_DESTROY_AH 0x16UL + #define CMDQ_DESTROY_AH_OPCODE_LAST CMDQ_DESTROY_AH_OPCODE_DESTROY_AH + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 ah_cid; + __le32 unused_0; +}; + +/* creq_destroy_ah_resp (size:128b/16B) */ struct creq_destroy_ah_resp { - u8 type; - #define CREQ_DESTROY_AH_RESP_TYPE_MASK 0x3fUL - #define CREQ_DESTROY_AH_RESP_TYPE_SFT 0 - #define CREQ_DESTROY_AH_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DESTROY_AH_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DESTROY_AH_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 xid; - u8 v; - #define CREQ_DESTROY_AH_RESP_V 0x1UL - #define CREQ_DESTROY_AH_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DESTROY_AH_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DESTROY_AH_RESP_EVENT_DESTROY_AH 0x16UL - __le16 reserved48[3]; + u8 type; + #define CREQ_DESTROY_AH_RESP_TYPE_MASK 0x3fUL + #define CREQ_DESTROY_AH_RESP_TYPE_SFT 0 + #define CREQ_DESTROY_AH_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_DESTROY_AH_RESP_TYPE_LAST CREQ_DESTROY_AH_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 xid; + u8 v; + #define CREQ_DESTROY_AH_RESP_V 0x1UL + u8 event; + #define CREQ_DESTROY_AH_RESP_EVENT_DESTROY_AH 0x16UL + #define CREQ_DESTROY_AH_RESP_EVENT_LAST CREQ_DESTROY_AH_RESP_EVENT_DESTROY_AH + u8 reserved48[6]; }; -/* Initialize Firmware command response (16 bytes) */ -struct creq_initialize_fw_resp { - u8 type; - #define CREQ_INITIALIZE_FW_RESP_TYPE_MASK 0x3fUL - #define CREQ_INITIALIZE_FW_RESP_TYPE_SFT 0 - #define CREQ_INITIALIZE_FW_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_INITIALIZE_FW_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_INITIALIZE_FW_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_INITIALIZE_FW_RESP_V 0x1UL - #define CREQ_INITIALIZE_FW_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_INITIALIZE_FW_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_INITIALIZE_FW_RESP_EVENT_INITIALIZE_FW 0x80UL - __le16 reserved48[3]; -}; - -/* De-initialize Firmware command response (16 bytes) */ -struct creq_deinitialize_fw_resp { - u8 type; - #define CREQ_DEINITIALIZE_FW_RESP_TYPE_MASK 0x3fUL - #define CREQ_DEINITIALIZE_FW_RESP_TYPE_SFT 0 - #define CREQ_DEINITIALIZE_FW_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_DEINITIALIZE_FW_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_DEINITIALIZE_FW_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_DEINITIALIZE_FW_RESP_V 0x1UL - #define CREQ_DEINITIALIZE_FW_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_DEINITIALIZE_FW_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_DEINITIALIZE_FW_RESP_EVENT_DEINITIALIZE_FW 0x81UL - __le16 reserved48[3]; -}; - -/* Stop function command response (16 bytes) */ -struct creq_stop_func_resp { - u8 type; - #define CREQ_STOP_FUNC_RESP_TYPE_MASK 0x3fUL - #define CREQ_STOP_FUNC_RESP_TYPE_SFT 0 - #define CREQ_STOP_FUNC_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_STOP_FUNC_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_STOP_FUNC_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_STOP_FUNC_RESP_V 0x1UL - #define CREQ_STOP_FUNC_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_STOP_FUNC_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_STOP_FUNC_RESP_EVENT_STOP_FUNC 0x82UL - __le16 reserved48[3]; -}; - -/* Query function command response (16 bytes) */ -struct creq_query_func_resp { - u8 type; - #define CREQ_QUERY_FUNC_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_FUNC_RESP_TYPE_SFT 0 - #define CREQ_QUERY_FUNC_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_FUNC_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_FUNC_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 size; - u8 v; - #define CREQ_QUERY_FUNC_RESP_V 0x1UL - #define CREQ_QUERY_FUNC_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_FUNC_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_FUNC_RESP_EVENT_QUERY_FUNC 0x83UL - __le16 reserved48[3]; -}; - -/* Query function command response side buffer structure (88 bytes) */ -struct creq_query_func_resp_sb { - u8 opcode; - #define CREQ_QUERY_FUNC_RESP_SB_OPCODE_QUERY_FUNC 0x83UL - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 reserved8; - __le64 max_mr_size; - __le32 max_qp; - __le16 max_qp_wr; - __le16 dev_cap_flags; - #define CREQ_QUERY_FUNC_RESP_SB_DEV_CAP_FLAGS_RESIZE_QP 0x1UL - #define CREQ_QUERY_FUNC_RESP_SB_EXT_STATS 0x10UL - __le32 max_cq; - __le32 max_cqe; - __le32 max_pd; - u8 max_sge; - u8 max_srq_sge; - u8 max_qp_rd_atom; - u8 max_qp_init_rd_atom; - __le32 max_mr; - __le32 max_mw; - __le32 max_raw_eth_qp; - __le32 max_ah; - __le32 max_fmr; - __le32 max_srq_wr; - __le32 max_pkeys; - __le32 max_inline_data; - u8 max_map_per_fmr; - u8 l2_db_space_size; - __le16 max_srq; - __le32 max_gid; - __le32 tqm_alloc_reqs[12]; - __le32 max_dpi; - __le32 reserved_32; -}; - -/* Set resources command response (16 bytes) */ -struct creq_set_func_resources_resp { - u8 type; - #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_MASK 0x3fUL - #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_SFT 0 - #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_SET_FUNC_RESOURCES_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_SET_FUNC_RESOURCES_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_SET_FUNC_RESOURCES_RESP_V 0x1UL - #define CREQ_SET_FUNC_RESOURCES_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_SET_FUNC_RESOURCES_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_SET_FUNC_RESOURCES_RESP_EVENT_SET_FUNC_RESOURCES 0x84UL - __le16 reserved48[3]; -}; - -/* Map TC to COS response (16 bytes) */ -struct creq_map_tc_to_cos_resp { - u8 type; - #define CREQ_MAP_TC_TO_COS_RESP_TYPE_MASK 0x3fUL - #define CREQ_MAP_TC_TO_COS_RESP_TYPE_SFT 0 - #define CREQ_MAP_TC_TO_COS_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_MAP_TC_TO_COS_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_MAP_TC_TO_COS_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_MAP_TC_TO_COS_RESP_V 0x1UL - #define CREQ_MAP_TC_TO_COS_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_MAP_TC_TO_COS_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_MAP_TC_TO_COS_RESP_EVENT_MAP_TC_TO_COS 0x8aUL - __le16 reserved48[3]; -}; - -/* Query version response (16 bytes) */ -struct creq_query_version_resp { - u8 type; - #define CREQ_QUERY_VERSION_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_VERSION_RESP_TYPE_SFT 0 - #define CREQ_QUERY_VERSION_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_VERSION_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_VERSION_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - u8 fw_maj; - u8 fw_minor; - u8 fw_bld; - u8 fw_rsvd; - u8 v; - #define CREQ_QUERY_VERSION_RESP_V 0x1UL - #define CREQ_QUERY_VERSION_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_VERSION_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_VERSION_RESP_EVENT_QUERY_VERSION 0x8bUL - __le16 reserved16; - u8 intf_maj; - u8 intf_minor; - u8 intf_bld; - u8 intf_rsvd; -}; - -/* Modify congestion control command response (16 bytes) */ -struct creq_modify_cc_resp { - u8 type; - #define CREQ_MODIFY_CC_RESP_TYPE_MASK 0x3fUL - #define CREQ_MODIFY_CC_RESP_TYPE_SFT 0 - #define CREQ_MODIFY_CC_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_MODIFY_CC_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_MODIFY_CC_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 reserved32; - u8 v; - #define CREQ_MODIFY_CC_RESP_V 0x1UL - #define CREQ_MODIFY_CC_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_MODIFY_CC_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_MODIFY_CC_RESP_EVENT_MODIFY_CC 0x8cUL - __le16 reserved48[3]; -}; - -/* Query congestion control command response (16 bytes) */ -struct creq_query_cc_resp { - u8 type; - #define CREQ_QUERY_CC_RESP_TYPE_MASK 0x3fUL - #define CREQ_QUERY_CC_RESP_TYPE_SFT 0 - #define CREQ_QUERY_CC_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_CC_RESP_RESERVED2_MASK 0xc0UL - #define CREQ_QUERY_CC_RESP_RESERVED2_SFT 6 - u8 status; - __le16 cookie; - __le32 size; - u8 v; - #define CREQ_QUERY_CC_RESP_V 0x1UL - #define CREQ_QUERY_CC_RESP_RESERVED7_MASK 0xfeUL - #define CREQ_QUERY_CC_RESP_RESERVED7_SFT 1 - u8 event; - #define CREQ_QUERY_CC_RESP_EVENT_QUERY_CC 0x8dUL - __le16 reserved48[3]; -}; - -/* Query congestion control command response side buffer structure (32 bytes) */ -struct creq_query_cc_resp_sb { - u8 opcode; - #define CREQ_QUERY_CC_RESP_SB_OPCODE_QUERY_CC 0x8dUL - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 reserved8; - u8 enable_cc; - #define CREQ_QUERY_CC_RESP_SB_ENABLE_CC 0x1UL - u8 g; - #define CREQ_QUERY_CC_RESP_SB_G_MASK 0x7UL - #define CREQ_QUERY_CC_RESP_SB_G_SFT 0 - u8 num_phases_per_state; - __le16 init_cr; - u8 unused_2; - __le16 unused_3; - u8 unused_4; - __le16 init_tr; - u8 tos_dscp_tos_ecn; - #define CREQ_QUERY_CC_RESP_SB_TOS_ECN_MASK 0x3UL - #define CREQ_QUERY_CC_RESP_SB_TOS_ECN_SFT 0 - #define CREQ_QUERY_CC_RESP_SB_TOS_DSCP_MASK 0xfcUL - #define CREQ_QUERY_CC_RESP_SB_TOS_DSCP_SFT 2 - __le64 reserved64; - __le64 reserved64_1; +/* cmdq_query_roce_stats (size:192b/24B) */ +struct cmdq_query_roce_stats { + u8 opcode; + #define CMDQ_QUERY_ROCE_STATS_OPCODE_QUERY_ROCE_STATS 0x8eUL + #define CMDQ_QUERY_ROCE_STATS_OPCODE_LAST CMDQ_QUERY_ROCE_STATS_OPCODE_QUERY_ROCE_STATS + u8 cmd_size; + __le16 flags; + #define CMDQ_QUERY_ROCE_STATS_FLAGS_COLLECTION_ID 0x1UL + #define CMDQ_QUERY_ROCE_STATS_FLAGS_FUNCTION_ID 0x2UL + __le16 cookie; + u8 resp_size; + u8 collection_id; + __le64 resp_addr; + __le32 function_id; + #define CMDQ_QUERY_ROCE_STATS_PF_NUM_MASK 0xffUL + #define CMDQ_QUERY_ROCE_STATS_PF_NUM_SFT 0 + #define CMDQ_QUERY_ROCE_STATS_VF_NUM_MASK 0xffff00UL + #define CMDQ_QUERY_ROCE_STATS_VF_NUM_SFT 8 + #define CMDQ_QUERY_ROCE_STATS_VF_VALID 0x1000000UL + __le32 reserved32; }; /* creq_query_roce_stats_resp (size:128b/16B) */ @@ -3020,8 +1909,7 @@ struct creq_query_roce_stats_resp { #define CREQ_QUERY_ROCE_STATS_RESP_TYPE_MASK 0x3fUL #define CREQ_QUERY_ROCE_STATS_RESP_TYPE_SFT 0 #define CREQ_QUERY_ROCE_STATS_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_ROCE_STATS_RESP_TYPE_LAST \ - CREQ_QUERY_ROCE_STATS_RESP_TYPE_QP_EVENT + #define CREQ_QUERY_ROCE_STATS_RESP_TYPE_LAST CREQ_QUERY_ROCE_STATS_RESP_TYPE_QP_EVENT u8 status; __le16 cookie; __le32 size; @@ -3029,17 +1917,17 @@ struct creq_query_roce_stats_resp { #define CREQ_QUERY_ROCE_STATS_RESP_V 0x1UL u8 event; #define CREQ_QUERY_ROCE_STATS_RESP_EVENT_QUERY_ROCE_STATS 0x8eUL - #define CREQ_QUERY_ROCE_STATS_RESP_EVENT_LAST \ - CREQ_QUERY_ROCE_STATS_RESP_EVENT_QUERY_ROCE_STATS + #define CREQ_QUERY_ROCE_STATS_RESP_EVENT_LAST \ + CREQ_QUERY_ROCE_STATS_RESP_EVENT_QUERY_ROCE_STATS u8 reserved48[6]; }; -/* creq_query_roce_stats_resp_sb (size:2624b/328B) */ +/* creq_query_roce_stats_resp_sb (size:2944b/368B) */ struct creq_query_roce_stats_resp_sb { u8 opcode; #define CREQ_QUERY_ROCE_STATS_RESP_SB_OPCODE_QUERY_ROCE_STATS 0x8eUL #define CREQ_QUERY_ROCE_STATS_RESP_SB_OPCODE_LAST \ - CREQ_QUERY_ROCE_STATS_RESP_SB_OPCODE_QUERY_ROCE_STATS + CREQ_QUERY_ROCE_STATS_RESP_SB_OPCODE_QUERY_ROCE_STATS u8 status; __le16 cookie; __le16 flags; @@ -3086,125 +1974,2508 @@ struct creq_query_roce_stats_resp_sb { __le64 res_srq_load_err; __le64 res_tx_pci_err; __le64 res_rx_pci_err; - __le64 res_oos_drop_count; - __le64 active_qp_count_p0; - __le64 active_qp_count_p1; - __le64 active_qp_count_p2; - __le64 active_qp_count_p3; + __le64 res_oos_drop_count; + __le64 active_qp_count_p0; + __le64 active_qp_count_p1; + __le64 active_qp_count_p2; + __le64 active_qp_count_p3; }; /* cmdq_query_roce_stats_ext (size:192b/24B) */ struct cmdq_query_roce_stats_ext { - u8 opcode; + u8 opcode; #define CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_QUERY_ROCE_STATS 0x92UL - #define CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_LAST \ - CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_QUERY_ROCE_STATS - u8 cmd_size; - __le16 flags; + #define CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_LAST \ + CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_QUERY_ROCE_STATS + u8 cmd_size; + __le16 flags; #define CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_COLLECTION_ID 0x1UL #define CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_FUNCTION_ID 0x2UL - __le16 cookie; - u8 resp_size; - u8 collection_id; - __le64 resp_addr; - __le32 function_id; + __le16 cookie; + u8 resp_size; + u8 collection_id; + __le64 resp_addr; + __le32 function_id; #define CMDQ_QUERY_ROCE_STATS_EXT_PF_NUM_MASK 0xffUL #define CMDQ_QUERY_ROCE_STATS_EXT_PF_NUM_SFT 0 #define CMDQ_QUERY_ROCE_STATS_EXT_VF_NUM_MASK 0xffff00UL #define CMDQ_QUERY_ROCE_STATS_EXT_VF_NUM_SFT 8 #define CMDQ_QUERY_ROCE_STATS_EXT_VF_VALID 0x1000000UL - __le32 reserved32; + __le32 reserved32; }; /* creq_query_roce_stats_ext_resp (size:128b/16B) */ struct creq_query_roce_stats_ext_resp { - u8 type; + u8 type; #define CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_MASK 0x3fUL #define CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_SFT 0 #define CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_QP_EVENT 0x38UL - #define CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_LAST \ + #define CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_LAST \ CREQ_QUERY_ROCE_STATS_EXT_RESP_TYPE_QP_EVENT - u8 status; - __le16 cookie; - __le32 size; - u8 v; + u8 status; + __le16 cookie; + __le32 size; + u8 v; #define CREQ_QUERY_ROCE_STATS_EXT_RESP_V 0x1UL - u8 event; + u8 event; #define CREQ_QUERY_ROCE_STATS_EXT_RESP_EVENT_QUERY_ROCE_STATS_EXT 0x92UL #define CREQ_QUERY_ROCE_STATS_EXT_RESP_EVENT_LAST \ CREQ_QUERY_ROCE_STATS_EXT_RESP_EVENT_QUERY_ROCE_STATS_EXT - u8 reserved48[6]; + u8 reserved48[6]; }; -/* creq_query_roce_stats_ext_resp_sb (size:1536b/192B) */ +/* creq_query_roce_stats_ext_resp_sb (size:1856b/232B) */ struct creq_query_roce_stats_ext_resp_sb { - u8 opcode; + u8 opcode; #define CREQ_QUERY_ROCE_STATS_EXT_RESP_SB_OPCODE_QUERY_ROCE_STATS_EXT 0x92UL #define CREQ_QUERY_ROCE_STATS_EXT_RESP_SB_OPCODE_LAST \ CREQ_QUERY_ROCE_STATS_EXT_RESP_SB_OPCODE_QUERY_ROCE_STATS_EXT - u8 status; - __le16 cookie; - __le16 flags; - u8 resp_size; - u8 rsvd; - __le64 tx_atomic_req_pkts; - __le64 tx_read_req_pkts; - __le64 tx_read_res_pkts; - __le64 tx_write_req_pkts; - __le64 tx_send_req_pkts; - __le64 tx_roce_pkts; - __le64 tx_roce_bytes; - __le64 rx_atomic_req_pkts; - __le64 rx_read_req_pkts; - __le64 rx_read_res_pkts; - __le64 rx_write_req_pkts; - __le64 rx_send_req_pkts; - __le64 rx_roce_pkts; - __le64 rx_roce_bytes; - __le64 rx_roce_good_pkts; - __le64 rx_roce_good_bytes; - __le64 rx_out_of_buffer_pkts; - __le64 rx_out_of_sequence_pkts; - __le64 tx_cnp_pkts; - __le64 rx_cnp_pkts; - __le64 rx_ecn_marked_pkts; - __le64 tx_cnp_bytes; - __le64 rx_cnp_bytes; + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 rsvd; + __le64 tx_atomic_req_pkts; + __le64 tx_read_req_pkts; + __le64 tx_read_res_pkts; + __le64 tx_write_req_pkts; + __le64 tx_send_req_pkts; + __le64 tx_roce_pkts; + __le64 tx_roce_bytes; + __le64 rx_atomic_req_pkts; + __le64 rx_read_req_pkts; + __le64 rx_read_res_pkts; + __le64 rx_write_req_pkts; + __le64 rx_send_req_pkts; + __le64 rx_roce_pkts; + __le64 rx_roce_bytes; + __le64 rx_roce_good_pkts; + __le64 rx_roce_good_bytes; + __le64 rx_out_of_buffer_pkts; + __le64 rx_out_of_sequence_pkts; + __le64 tx_cnp_pkts; + __le64 rx_cnp_pkts; + __le64 rx_ecn_marked_pkts; + __le64 tx_cnp_bytes; + __le64 rx_cnp_bytes; + __le64 seq_err_naks_rcvd; + __le64 rnr_naks_rcvd; + __le64 missing_resp; + __le64 to_retransmit; + __le64 dup_req; }; -/* QP error notification event (16 bytes) */ +/* cmdq_query_func (size:128b/16B) */ +struct cmdq_query_func { + u8 opcode; + #define CMDQ_QUERY_FUNC_OPCODE_QUERY_FUNC 0x83UL + #define CMDQ_QUERY_FUNC_OPCODE_LAST CMDQ_QUERY_FUNC_OPCODE_QUERY_FUNC + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; +}; + +/* creq_query_func_resp (size:128b/16B) */ +struct creq_query_func_resp { + u8 type; + #define CREQ_QUERY_FUNC_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_FUNC_RESP_TYPE_SFT 0 + #define CREQ_QUERY_FUNC_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_FUNC_RESP_TYPE_LAST CREQ_QUERY_FUNC_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_FUNC_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_FUNC_RESP_EVENT_QUERY_FUNC 0x83UL + #define CREQ_QUERY_FUNC_RESP_EVENT_LAST CREQ_QUERY_FUNC_RESP_EVENT_QUERY_FUNC + u8 reserved48[6]; +}; + +/* creq_query_func_resp_sb (size:1088b/136B) */ +struct creq_query_func_resp_sb { + u8 opcode; + #define CREQ_QUERY_FUNC_RESP_SB_OPCODE_QUERY_FUNC 0x83UL + #define CREQ_QUERY_FUNC_RESP_SB_OPCODE_LAST CREQ_QUERY_FUNC_RESP_SB_OPCODE_QUERY_FUNC + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + __le64 max_mr_size; + __le32 max_qp; + __le16 max_qp_wr; + __le16 dev_cap_flags; + #define CREQ_QUERY_FUNC_RESP_SB_RESIZE_QP 0x1UL + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_MASK 0xeUL + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_SFT 1 + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_CC_GEN0 (0x0UL << 1) + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_CC_GEN1 (0x1UL << 1) + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_CC_GEN1_EXT (0x2UL << 1) + #define CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_LAST \ + CREQ_QUERY_FUNC_RESP_SB_CC_GENERATION_CC_GEN1_EXT + #define CREQ_QUERY_FUNC_RESP_SB_EXT_STATS 0x10UL + #define CREQ_QUERY_FUNC_RESP_SB_MR_REGISTER_ALLOC 0x20UL + #define CREQ_QUERY_FUNC_RESP_SB_OPTIMIZED_TRANSMIT_ENABLED 0x40UL + #define CREQ_QUERY_FUNC_RESP_SB_CQE_V2 0x80UL + #define CREQ_QUERY_FUNC_RESP_SB_PINGPONG_PUSH_MODE 0x100UL + #define CREQ_QUERY_FUNC_RESP_SB_HW_REQUESTER_RETX_ENABLED 0x200UL + #define CREQ_QUERY_FUNC_RESP_SB_HW_RESPONDER_RETX_ENABLED 0x400UL + __le32 max_cq; + __le32 max_cqe; + __le32 max_pd; + u8 max_sge; + u8 max_srq_sge; + u8 max_qp_rd_atom; + u8 max_qp_init_rd_atom; + __le32 max_mr; + __le32 max_mw; + __le32 max_raw_eth_qp; + __le32 max_ah; + __le32 max_fmr; + __le32 max_srq_wr; + __le32 max_pkeys; + __le32 max_inline_data; + u8 max_map_per_fmr; + u8 l2_db_space_size; + __le16 max_srq; + __le32 max_gid; + __le32 tqm_alloc_reqs[12]; + __le32 max_dpi; + u8 max_sge_var_wqe; + u8 reserved_8; + __le16 max_inline_data_var_wqe; +}; + +/* cmdq_set_func_resources (size:448b/56B) */ +struct cmdq_set_func_resources { + u8 opcode; + #define CMDQ_SET_FUNC_RESOURCES_OPCODE_SET_FUNC_RESOURCES 0x84UL + #define CMDQ_SET_FUNC_RESOURCES_OPCODE_LAST\ + CMDQ_SET_FUNC_RESOURCES_OPCODE_SET_FUNC_RESOURCES + u8 cmd_size; + __le16 flags; + #define CMDQ_SET_FUNC_RESOURCES_FLAGS_MRAV_RESERVATION_SPLIT 0x1UL + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 number_of_qp; + __le32 number_of_mrw; + __le32 number_of_srq; + __le32 number_of_cq; + __le32 max_qp_per_vf; + __le32 max_mrw_per_vf; + __le32 max_srq_per_vf; + __le32 max_cq_per_vf; + __le32 max_gid_per_vf; + __le32 stat_ctx_id; +}; + +/* creq_set_func_resources_resp (size:128b/16B) */ +struct creq_set_func_resources_resp { + u8 type; + #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_MASK 0x3fUL + #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_SFT 0 + #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_SET_FUNC_RESOURCES_RESP_TYPE_LAST CREQ_SET_FUNC_RESOURCES_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_SET_FUNC_RESOURCES_RESP_V 0x1UL + u8 event; + #define CREQ_SET_FUNC_RESOURCES_RESP_EVENT_SET_FUNC_RESOURCES 0x84UL + #define CREQ_SET_FUNC_RESOURCES_RESP_EVENT_LAST \ + CREQ_SET_FUNC_RESOURCES_RESP_EVENT_SET_FUNC_RESOURCES + u8 reserved48[6]; +}; + +/* cmdq_map_tc_to_cos (size:192b/24B) */ +struct cmdq_map_tc_to_cos { + u8 opcode; + #define CMDQ_MAP_TC_TO_COS_OPCODE_MAP_TC_TO_COS 0x8aUL + #define CMDQ_MAP_TC_TO_COS_OPCODE_LAST CMDQ_MAP_TC_TO_COS_OPCODE_MAP_TC_TO_COS + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le16 cos0; + #define CMDQ_MAP_TC_TO_COS_COS0_NO_CHANGE 0xffffUL + #define CMDQ_MAP_TC_TO_COS_COS0_LAST CMDQ_MAP_TC_TO_COS_COS0_NO_CHANGE + __le16 cos1; + #define CMDQ_MAP_TC_TO_COS_COS1_DISABLE 0x8000UL + #define CMDQ_MAP_TC_TO_COS_COS1_NO_CHANGE 0xffffUL + #define CMDQ_MAP_TC_TO_COS_COS1_LAST CMDQ_MAP_TC_TO_COS_COS1_NO_CHANGE + __le32 unused_0; +}; + +/* creq_map_tc_to_cos_resp (size:128b/16B) */ +struct creq_map_tc_to_cos_resp { + u8 type; + #define CREQ_MAP_TC_TO_COS_RESP_TYPE_MASK 0x3fUL + #define CREQ_MAP_TC_TO_COS_RESP_TYPE_SFT 0 + #define CREQ_MAP_TC_TO_COS_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_MAP_TC_TO_COS_RESP_TYPE_LAST CREQ_MAP_TC_TO_COS_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_MAP_TC_TO_COS_RESP_V 0x1UL + u8 event; + #define CREQ_MAP_TC_TO_COS_RESP_EVENT_MAP_TC_TO_COS 0x8aUL + #define CREQ_MAP_TC_TO_COS_RESP_EVENT_LAST CREQ_MAP_TC_TO_COS_RESP_EVENT_MAP_TC_TO_COS + u8 reserved48[6]; +}; + +/* cmdq_query_roce_cc (size:128b/16B) */ +struct cmdq_query_roce_cc { + u8 opcode; + #define CMDQ_QUERY_ROCE_CC_OPCODE_QUERY_ROCE_CC 0x8dUL + #define CMDQ_QUERY_ROCE_CC_OPCODE_LAST CMDQ_QUERY_ROCE_CC_OPCODE_QUERY_ROCE_CC + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; +}; + +/* creq_query_roce_cc_resp (size:128b/16B) */ +struct creq_query_roce_cc_resp { + u8 type; + #define CREQ_QUERY_ROCE_CC_RESP_TYPE_MASK 0x3fUL + #define CREQ_QUERY_ROCE_CC_RESP_TYPE_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_QUERY_ROCE_CC_RESP_TYPE_LAST CREQ_QUERY_ROCE_CC_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 size; + u8 v; + #define CREQ_QUERY_ROCE_CC_RESP_V 0x1UL + u8 event; + #define CREQ_QUERY_ROCE_CC_RESP_EVENT_QUERY_ROCE_CC 0x8dUL + #define CREQ_QUERY_ROCE_CC_RESP_EVENT_LAST CREQ_QUERY_ROCE_CC_RESP_EVENT_QUERY_ROCE_CC + u8 reserved48[6]; +}; + +/* creq_query_roce_cc_resp_sb (size:256b/32B) */ +struct creq_query_roce_cc_resp_sb { + u8 opcode; + #define CREQ_QUERY_ROCE_CC_RESP_SB_OPCODE_QUERY_ROCE_CC 0x8dUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_OPCODE_LAST \ + CREQ_QUERY_ROCE_CC_RESP_SB_OPCODE_QUERY_ROCE_CC + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + u8 enable_cc; + #define CREQ_QUERY_ROCE_CC_RESP_SB_ENABLE_CC 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_UNUSED7_MASK 0xfeUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_UNUSED7_SFT 1 + u8 tos_dscp_tos_ecn; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TOS_ECN_MASK 0x3UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TOS_ECN_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TOS_DSCP_MASK 0xfcUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TOS_DSCP_SFT 2 + u8 g; + u8 num_phases_per_state; + __le16 init_cr; + __le16 init_tr; + u8 alt_vlan_pcp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_ALT_VLAN_PCP_MASK 0x7UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_ALT_VLAN_PCP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD1_MASK 0xf8UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD1_SFT 3 + u8 alt_tos_dscp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_ALT_TOS_DSCP_MASK 0x3fUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_ALT_TOS_DSCP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD4_MASK 0xc0UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD4_SFT 6 + u8 cc_mode; + #define CREQ_QUERY_ROCE_CC_RESP_SB_CC_MODE_DCTCP 0x0UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_CC_MODE_PROBABILISTIC 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_CC_MODE_LAST \ + CREQ_QUERY_ROCE_CC_RESP_SB_CC_MODE_PROBABILISTIC + u8 tx_queue; + __le16 rtt; + #define CREQ_QUERY_ROCE_CC_RESP_SB_RTT_MASK 0x3fffUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_RTT_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD5_MASK 0xc000UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD5_SFT 14 + __le16 tcp_cp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TCP_CP_MASK 0x3ffUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TCP_CP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD6_MASK 0xfc00UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_RSVD6_SFT 10 + __le16 inactivity_th; + u8 pkts_per_phase; + u8 time_per_phase; + __le32 reserved32; +}; + +/* creq_query_roce_cc_resp_sb_tlv (size:384b/48B) */ +struct creq_query_roce_cc_resp_sb_tlv { + __le16 cmd_discr; + u8 reserved_8b; + u8 tlv_flags; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_MORE 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_MORE_LAST 0x0UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_MORE_NOT_LAST 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_REQUIRED 0x2UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_REQUIRED_NO (0x0UL << 1) + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES (0x1UL << 1) + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_REQUIRED_LAST \ + CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES + __le16 tlv_type; + __le16 length; + u8 total_size; + u8 reserved56[7]; + u8 opcode; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_OPCODE_QUERY_ROCE_CC 0x8dUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_OPCODE_LAST \ + CREQ_QUERY_ROCE_CC_RESP_SB_TLV_OPCODE_QUERY_ROCE_CC + u8 status; + __le16 cookie; + __le16 flags; + u8 resp_size; + u8 reserved8; + u8 enable_cc; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_ENABLE_CC 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_UNUSED7_MASK 0xfeUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_UNUSED7_SFT 1 + u8 tos_dscp_tos_ecn; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TOS_ECN_MASK 0x3UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TOS_ECN_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TOS_DSCP_MASK 0xfcUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TOS_DSCP_SFT 2 + u8 g; + u8 num_phases_per_state; + __le16 init_cr; + __le16 init_tr; + u8 alt_vlan_pcp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_ALT_VLAN_PCP_MASK 0x7UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_ALT_VLAN_PCP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD1_MASK 0xf8UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD1_SFT 3 + u8 alt_tos_dscp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_ALT_TOS_DSCP_MASK 0x3fUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_ALT_TOS_DSCP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD4_MASK 0xc0UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD4_SFT 6 + u8 cc_mode; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_CC_MODE_DCTCP 0x0UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_CC_MODE_PROBABILISTIC 0x1UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_CC_MODE_LAST\ + CREQ_QUERY_ROCE_CC_RESP_SB_TLV_CC_MODE_PROBABILISTIC + u8 tx_queue; + __le16 rtt; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RTT_MASK 0x3fffUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RTT_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD5_MASK 0xc000UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD5_SFT 14 + __le16 tcp_cp; + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TCP_CP_MASK 0x3ffUL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_TCP_CP_SFT 0 + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD6_MASK 0xfc00UL + #define CREQ_QUERY_ROCE_CC_RESP_SB_TLV_RSVD6_SFT 10 + __le16 inactivity_th; + u8 pkts_per_phase; + u8 time_per_phase; + __le32 reserved32; +}; + +/* creq_query_roce_cc_gen1_resp_sb_tlv (size:704b/88B) */ +struct creq_query_roce_cc_gen1_resp_sb_tlv { + __le16 cmd_discr; + u8 reserved_8b; + u8 tlv_flags; + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_MORE 0x1UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_MORE_LAST 0x0UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_MORE_NOT_LAST 0x1UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_REQUIRED 0x2UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_REQUIRED_NO (0x0UL << 1) + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES (0x1UL << 1) + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_REQUIRED_LAST \ + CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_TLV_FLAGS_REQUIRED_YES + __le16 tlv_type; + __le16 length; + __le64 reserved64; + __le16 inactivity_th_hi; + __le16 min_time_between_cnps; + __le16 init_cp; + u8 tr_update_mode; + u8 tr_update_cycles; + u8 fr_num_rtts; + u8 ai_rate_increase; + __le16 reduction_relax_rtts_th; + __le16 additional_relax_cr_th; + __le16 cr_min_th; + u8 bw_avg_weight; + u8 actual_cr_factor; + __le16 max_cp_cr_th; + u8 cp_bias_en; + u8 cp_bias; + u8 cnp_ecn; + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_CNP_ECN_NOT_ECT 0x0UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_CNP_ECN_ECT_1 0x1UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_CNP_ECN_ECT_0 0x2UL + #define CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_CNP_ECN_LAST \ + CREQ_QUERY_ROCE_CC_GEN1_RESP_SB_TLV_CNP_ECN_ECT_0 + u8 rtt_jitter_en; + __le16 link_bytes_per_usec; + __le16 reset_cc_cr_th; + u8 cr_width; + u8 quota_period_min; + u8 quota_period_max; + u8 quota_period_abs_max; + __le16 tr_lower_bound; + u8 cr_prob_factor; + u8 tr_prob_factor; + __le16 fairness_cr_th; + u8 red_div; + u8 cnp_ratio_th; + __le16 exp_ai_rtts; + u8 exp_ai_cr_cp_ratio; + u8 use_rate_table; + __le16 cp_exp_update_th; + __le16 high_exp_ai_rtts_th1; + __le16 high_exp_ai_rtts_th2; + __le16 actual_cr_cong_free_rtts_th; + __le16 severe_cong_cr_th1; + __le16 severe_cong_cr_th2; + __le32 link64B_per_rtt; + u8 cc_ack_bytes; + u8 reduce_init_en; + __le16 reduce_init_cong_free_rtts_th; + u8 random_no_red_en; + u8 actual_cr_shift_correction_en; + u8 quota_period_adjust_en; + u8 reserved[5]; +}; + +/* cmdq_modify_roce_cc (size:448b/56B) */ +struct cmdq_modify_roce_cc { + u8 opcode; + #define CMDQ_MODIFY_ROCE_CC_OPCODE_MODIFY_ROCE_CC 0x8cUL + #define CMDQ_MODIFY_ROCE_CC_OPCODE_LAST CMDQ_MODIFY_ROCE_CC_OPCODE_MODIFY_ROCE_CC + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 modify_mask; + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC 0x1UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G 0x2UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE 0x4UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR 0x8UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR 0x10UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN 0x20UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP 0x40UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP 0x80UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP 0x100UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT 0x200UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE 0x400UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP 0x800UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE 0x1000UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP 0x2000UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE 0x4000UL + #define CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_PKTS_PER_PHASE 0x8000UL + u8 enable_cc; + #define CMDQ_MODIFY_ROCE_CC_ENABLE_CC 0x1UL + #define CMDQ_MODIFY_ROCE_CC_RSVD1_MASK 0xfeUL + #define CMDQ_MODIFY_ROCE_CC_RSVD1_SFT 1 + u8 g; + u8 num_phases_per_state; + u8 pkts_per_phase; + __le16 init_cr; + __le16 init_tr; + u8 tos_dscp_tos_ecn; + #define CMDQ_MODIFY_ROCE_CC_TOS_ECN_MASK 0x3UL + #define CMDQ_MODIFY_ROCE_CC_TOS_ECN_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TOS_DSCP_MASK 0xfcUL + #define CMDQ_MODIFY_ROCE_CC_TOS_DSCP_SFT 2 + u8 alt_vlan_pcp; + #define CMDQ_MODIFY_ROCE_CC_ALT_VLAN_PCP_MASK 0x7UL + #define CMDQ_MODIFY_ROCE_CC_ALT_VLAN_PCP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_RSVD3_MASK 0xf8UL + #define CMDQ_MODIFY_ROCE_CC_RSVD3_SFT 3 + __le16 alt_tos_dscp; + #define CMDQ_MODIFY_ROCE_CC_ALT_TOS_DSCP_MASK 0x3fUL + #define CMDQ_MODIFY_ROCE_CC_ALT_TOS_DSCP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_RSVD4_MASK 0xffc0UL + #define CMDQ_MODIFY_ROCE_CC_RSVD4_SFT 6 + __le16 rtt; + #define CMDQ_MODIFY_ROCE_CC_RTT_MASK 0x3fffUL + #define CMDQ_MODIFY_ROCE_CC_RTT_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_RSVD5_MASK 0xc000UL + #define CMDQ_MODIFY_ROCE_CC_RSVD5_SFT 14 + __le16 tcp_cp; + #define CMDQ_MODIFY_ROCE_CC_TCP_CP_MASK 0x3ffUL + #define CMDQ_MODIFY_ROCE_CC_TCP_CP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_RSVD6_MASK 0xfc00UL + #define CMDQ_MODIFY_ROCE_CC_RSVD6_SFT 10 + u8 cc_mode; + #define CMDQ_MODIFY_ROCE_CC_CC_MODE_DCTCP_CC_MODE 0x0UL + #define CMDQ_MODIFY_ROCE_CC_CC_MODE_PROBABILISTIC_CC_MODE 0x1UL + #define CMDQ_MODIFY_ROCE_CC_CC_MODE_LAST CMDQ_MODIFY_ROCE_CC_CC_MODE_PROBABILISTIC_CC_MODE + u8 tx_queue; + __le16 inactivity_th; + u8 time_per_phase; + u8 reserved8_1; + __le16 reserved16; + __le32 reserved32; + __le64 reserved64; +}; + +/* cmdq_modify_roce_cc_tlv (size:640b/80B) */ +struct cmdq_modify_roce_cc_tlv { + __le16 cmd_discr; + u8 reserved_8b; + u8 tlv_flags; + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_MORE 0x1UL + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_MORE_LAST 0x0UL + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_MORE_NOT_LAST 0x1UL + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_REQUIRED 0x2UL + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_REQUIRED_NO (0x0UL << 1) + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_REQUIRED_YES (0x1UL << 1) + #define CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_REQUIRED_LAST \ + CMDQ_MODIFY_ROCE_CC_TLV_TLV_FLAGS_REQUIRED_YES + __le16 tlv_type; + __le16 length; + u8 total_size; + u8 reserved56[7]; + u8 opcode; + #define CMDQ_MODIFY_ROCE_CC_TLV_OPCODE_MODIFY_ROCE_CC 0x8cUL + #define CMDQ_MODIFY_ROCE_CC_TLV_OPCODE_LAST CMDQ_MODIFY_ROCE_CC_TLV_OPCODE_MODIFY_ROCE_CC + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 modify_mask; + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_ENABLE_CC 0x1UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_G 0x2UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_NUMPHASEPERSTATE 0x4UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_INIT_CR 0x8UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_INIT_TR 0x10UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_TOS_ECN 0x20UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_TOS_DSCP 0x40UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_ALT_VLAN_PCP 0x80UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_ALT_TOS_DSCP 0x100UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_RTT 0x200UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_CC_MODE 0x400UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_TCP_CP 0x800UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_TX_QUEUE 0x1000UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_INACTIVITY_CP 0x2000UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_TIME_PER_PHASE 0x4000UL + #define CMDQ_MODIFY_ROCE_CC_TLV_MODIFY_MASK_PKTS_PER_PHASE 0x8000UL + u8 enable_cc; + #define CMDQ_MODIFY_ROCE_CC_TLV_ENABLE_CC 0x1UL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD1_MASK 0xfeUL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD1_SFT 1 + u8 g; + u8 num_phases_per_state; + u8 pkts_per_phase; + __le16 init_cr; + __le16 init_tr; + u8 tos_dscp_tos_ecn; + #define CMDQ_MODIFY_ROCE_CC_TLV_TOS_ECN_MASK 0x3UL + #define CMDQ_MODIFY_ROCE_CC_TLV_TOS_ECN_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TLV_TOS_DSCP_MASK 0xfcUL + #define CMDQ_MODIFY_ROCE_CC_TLV_TOS_DSCP_SFT 2 + u8 alt_vlan_pcp; + #define CMDQ_MODIFY_ROCE_CC_TLV_ALT_VLAN_PCP_MASK 0x7UL + #define CMDQ_MODIFY_ROCE_CC_TLV_ALT_VLAN_PCP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD3_MASK 0xf8UL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD3_SFT 3 + __le16 alt_tos_dscp; + #define CMDQ_MODIFY_ROCE_CC_TLV_ALT_TOS_DSCP_MASK 0x3fUL + #define CMDQ_MODIFY_ROCE_CC_TLV_ALT_TOS_DSCP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD4_MASK 0xffc0UL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD4_SFT 6 + __le16 rtt; + #define CMDQ_MODIFY_ROCE_CC_TLV_RTT_MASK 0x3fffUL + #define CMDQ_MODIFY_ROCE_CC_TLV_RTT_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD5_MASK 0xc000UL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD5_SFT 14 + __le16 tcp_cp; + #define CMDQ_MODIFY_ROCE_CC_TLV_TCP_CP_MASK 0x3ffUL + #define CMDQ_MODIFY_ROCE_CC_TLV_TCP_CP_SFT 0 + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD6_MASK 0xfc00UL + #define CMDQ_MODIFY_ROCE_CC_TLV_RSVD6_SFT 10 + u8 cc_mode; + #define CMDQ_MODIFY_ROCE_CC_TLV_CC_MODE_DCTCP_CC_MODE 0x0UL + #define CMDQ_MODIFY_ROCE_CC_TLV_CC_MODE_PROBABILISTIC_CC_MODE 0x1UL + #define CMDQ_MODIFY_ROCE_CC_TLV_CC_MODE_LAST\ + CMDQ_MODIFY_ROCE_CC_TLV_CC_MODE_PROBABILISTIC_CC_MODE + u8 tx_queue; + __le16 inactivity_th; + u8 time_per_phase; + u8 reserved8_1; + __le16 reserved16; + __le32 reserved32; + __le64 reserved64; + __le64 reservedtlvpad; +}; + +/* cmdq_modify_roce_cc_gen1_tlv (size:768b/96B) */ +struct cmdq_modify_roce_cc_gen1_tlv { + __le16 cmd_discr; + u8 reserved_8b; + u8 tlv_flags; + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_MORE 0x1UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_MORE_LAST 0x0UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_MORE_NOT_LAST 0x1UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_REQUIRED 0x2UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_REQUIRED_NO (0x0UL << 1) + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_REQUIRED_YES (0x1UL << 1) + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_REQUIRED_LAST\ + CMDQ_MODIFY_ROCE_CC_GEN1_TLV_TLV_FLAGS_REQUIRED_YES + __le16 tlv_type; + __le16 length; + __le64 reserved64; + __le64 modify_mask; + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_MIN_TIME_BETWEEN_CNPS 0x1UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_INIT_CP 0x2UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_TR_UPDATE_MODE 0x4UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_TR_UPDATE_CYCLES 0x8UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_FR_NUM_RTTS 0x10UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_AI_RATE_INCREASE 0x20UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_REDUCTION_RELAX_RTTS_TH 0x40UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_ADDITIONAL_RELAX_CR_TH 0x80UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CR_MIN_TH 0x100UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_BW_AVG_WEIGHT 0x200UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_ACTUAL_CR_FACTOR 0x400UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_MAX_CP_CR_TH 0x800UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CP_BIAS_EN 0x1000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CP_BIAS 0x2000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CNP_ECN 0x4000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_RTT_JITTER_EN 0x8000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_LINK_BYTES_PER_USEC 0x10000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_RESET_CC_CR_TH 0x20000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CR_WIDTH 0x40000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_QUOTA_PERIOD_MIN 0x80000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_QUOTA_PERIOD_MAX 0x100000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_QUOTA_PERIOD_ABS_MAX 0x200000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_TR_LOWER_BOUND 0x400000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CR_PROB_FACTOR 0x800000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_TR_PROB_FACTOR 0x1000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_FAIRNESS_CR_TH 0x2000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_RED_DIV 0x4000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CNP_RATIO_TH 0x8000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_EXP_AI_RTTS 0x10000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_EXP_AI_CR_CP_RATIO 0x20000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CP_EXP_UPDATE_TH 0x40000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_HIGH_EXP_AI_RTTS_TH1 0x80000000UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_HIGH_EXP_AI_RTTS_TH2 0x100000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_USE_RATE_TABLE 0x200000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_LINK64B_PER_RTT 0x400000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_ACTUAL_CR_CONG_FREE_RTTS_TH 0x800000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_SEVERE_CONG_CR_TH1 0x1000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_SEVERE_CONG_CR_TH2 0x2000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_CC_ACK_BYTES 0x4000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_REDUCE_INIT_EN 0x8000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_REDUCE_INIT_CONG_FREE_RTTS_TH \ + 0x10000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_RANDOM_NO_RED_EN 0x20000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_ACTUAL_CR_SHIFT_CORRECTION_EN \ + 0x40000000000ULL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_MODIFY_MASK_QUOTA_PERIOD_ADJUST_EN 0x80000000000ULL + __le16 inactivity_th_hi; + __le16 min_time_between_cnps; + __le16 init_cp; + u8 tr_update_mode; + u8 tr_update_cycles; + u8 fr_num_rtts; + u8 ai_rate_increase; + __le16 reduction_relax_rtts_th; + __le16 additional_relax_cr_th; + __le16 cr_min_th; + u8 bw_avg_weight; + u8 actual_cr_factor; + __le16 max_cp_cr_th; + u8 cp_bias_en; + u8 cp_bias; + u8 cnp_ecn; + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_CNP_ECN_NOT_ECT 0x0UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_CNP_ECN_ECT_1 0x1UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_CNP_ECN_ECT_0 0x2UL + #define CMDQ_MODIFY_ROCE_CC_GEN1_TLV_CNP_ECN_LAST CMDQ_MODIFY_ROCE_CC_GEN1_TLV_CNP_ECN_ECT_0 + u8 rtt_jitter_en; + __le16 link_bytes_per_usec; + __le16 reset_cc_cr_th; + u8 cr_width; + u8 quota_period_min; + u8 quota_period_max; + u8 quota_period_abs_max; + __le16 tr_lower_bound; + u8 cr_prob_factor; + u8 tr_prob_factor; + __le16 fairness_cr_th; + u8 red_div; + u8 cnp_ratio_th; + __le16 exp_ai_rtts; + u8 exp_ai_cr_cp_ratio; + u8 use_rate_table; + __le16 cp_exp_update_th; + __le16 high_exp_ai_rtts_th1; + __le16 high_exp_ai_rtts_th2; + __le16 actual_cr_cong_free_rtts_th; + __le16 severe_cong_cr_th1; + __le16 severe_cong_cr_th2; + __le32 link64B_per_rtt; + u8 cc_ack_bytes; + u8 reduce_init_en; + __le16 reduce_init_cong_free_rtts_th; + u8 random_no_red_en; + u8 actual_cr_shift_correction_en; + u8 quota_period_adjust_en; + u8 reserved[5]; +}; + +/* creq_modify_roce_cc_resp (size:128b/16B) */ +struct creq_modify_roce_cc_resp { + u8 type; + #define CREQ_MODIFY_ROCE_CC_RESP_TYPE_MASK 0x3fUL + #define CREQ_MODIFY_ROCE_CC_RESP_TYPE_SFT 0 + #define CREQ_MODIFY_ROCE_CC_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_MODIFY_ROCE_CC_RESP_TYPE_LAST CREQ_MODIFY_ROCE_CC_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_MODIFY_ROCE_CC_RESP_V 0x1UL + u8 event; + #define CREQ_MODIFY_ROCE_CC_RESP_EVENT_MODIFY_ROCE_CC 0x8cUL + #define CREQ_MODIFY_ROCE_CC_RESP_EVENT_LAST CREQ_MODIFY_ROCE_CC_RESP_EVENT_MODIFY_ROCE_CC + u8 reserved48[6]; +}; + +/* cmdq_set_link_aggr_mode_cc (size:320b/40B) */ +struct cmdq_set_link_aggr_mode_cc { + u8 opcode; + #define CMDQ_SET_LINK_AGGR_MODE_OPCODE_SET_LINK_AGGR_MODE 0x8fUL + #define CMDQ_SET_LINK_AGGR_MODE_OPCODE_LAST \ + CMDQ_SET_LINK_AGGR_MODE_OPCODE_SET_LINK_AGGR_MODE + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 modify_mask; + #define CMDQ_SET_LINK_AGGR_MODE_MODIFY_MASK_AGGR_EN 0x1UL + #define CMDQ_SET_LINK_AGGR_MODE_MODIFY_MASK_ACTIVE_PORT_MAP 0x2UL + #define CMDQ_SET_LINK_AGGR_MODE_MODIFY_MASK_MEMBER_PORT_MAP 0x4UL + #define CMDQ_SET_LINK_AGGR_MODE_MODIFY_MASK_AGGR_MODE 0x8UL + #define CMDQ_SET_LINK_AGGR_MODE_MODIFY_MASK_STAT_CTX_ID 0x10UL + u8 aggr_enable; + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_ENABLE 0x1UL + #define CMDQ_SET_LINK_AGGR_MODE_RSVD1_MASK 0xfeUL + #define CMDQ_SET_LINK_AGGR_MODE_RSVD1_SFT 1 + u8 active_port_map; + #define CMDQ_SET_LINK_AGGR_MODE_ACTIVE_PORT_MAP_MASK 0xfUL + #define CMDQ_SET_LINK_AGGR_MODE_ACTIVE_PORT_MAP_SFT 0 + #define CMDQ_SET_LINK_AGGR_MODE_RSVD2_MASK 0xf0UL + #define CMDQ_SET_LINK_AGGR_MODE_RSVD2_SFT 4 + u8 member_port_map; + u8 link_aggr_mode; + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_ACTIVE_ACTIVE 0x1UL + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_ACTIVE_BACKUP 0x2UL + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_BALANCE_XOR 0x3UL + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_802_3_AD 0x4UL + #define CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_LAST CMDQ_SET_LINK_AGGR_MODE_AGGR_MODE_802_3_AD + __le16 stat_ctx_id[4]; + __le64 rsvd1; +}; + +/* creq_set_link_aggr_mode_resources_resp (size:128b/16B) */ +struct creq_set_link_aggr_mode_resources_resp { + u8 type; + #define CREQ_SET_LINK_AGGR_MODE_RESP_TYPE_MASK 0x3fUL + #define CREQ_SET_LINK_AGGR_MODE_RESP_TYPE_SFT 0 + #define CREQ_SET_LINK_AGGR_MODE_RESP_TYPE_QP_EVENT 0x38UL + #define CREQ_SET_LINK_AGGR_MODE_RESP_TYPE_LAST CREQ_SET_LINK_AGGR_MODE_RESP_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_SET_LINK_AGGR_MODE_RESP_V 0x1UL + u8 event; + #define CREQ_SET_LINK_AGGR_MODE_RESP_EVENT_SET_LINK_AGGR_MODE 0x8fUL + #define CREQ_SET_LINK_AGGR_MODE_RESP_EVENT_LAST\ + CREQ_SET_LINK_AGGR_MODE_RESP_EVENT_SET_LINK_AGGR_MODE + u8 reserved48[6]; +}; + +/* creq_func_event (size:128b/16B) */ +struct creq_func_event { + u8 type; + #define CREQ_FUNC_EVENT_TYPE_MASK 0x3fUL + #define CREQ_FUNC_EVENT_TYPE_SFT 0 + #define CREQ_FUNC_EVENT_TYPE_FUNC_EVENT 0x3aUL + #define CREQ_FUNC_EVENT_TYPE_LAST CREQ_FUNC_EVENT_TYPE_FUNC_EVENT + u8 reserved56[7]; + u8 v; + #define CREQ_FUNC_EVENT_V 0x1UL + u8 event; + #define CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR 0x1UL + #define CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR 0x2UL + #define CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR 0x3UL + #define CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR 0x4UL + #define CREQ_FUNC_EVENT_EVENT_CQ_ERROR 0x5UL + #define CREQ_FUNC_EVENT_EVENT_TQM_ERROR 0x6UL + #define CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR 0x7UL + #define CREQ_FUNC_EVENT_EVENT_CFCS_ERROR 0x8UL + #define CREQ_FUNC_EVENT_EVENT_CFCC_ERROR 0x9UL + #define CREQ_FUNC_EVENT_EVENT_CFCM_ERROR 0xaUL + #define CREQ_FUNC_EVENT_EVENT_TIM_ERROR 0xbUL + #define CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST 0x80UL + #define CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED 0x81UL + #define CREQ_FUNC_EVENT_EVENT_LAST CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED + u8 reserved48[6]; +}; + +/* creq_qp_event (size:128b/16B) */ +struct creq_qp_event { + u8 type; + #define CREQ_QP_EVENT_TYPE_MASK 0x3fUL + #define CREQ_QP_EVENT_TYPE_SFT 0 + #define CREQ_QP_EVENT_TYPE_QP_EVENT 0x38UL + #define CREQ_QP_EVENT_TYPE_LAST CREQ_QP_EVENT_TYPE_QP_EVENT + u8 status; + #define CREQ_QP_EVENT_STATUS_SUCCESS 0x0UL + #define CREQ_QP_EVENT_STATUS_FAIL 0x1UL + #define CREQ_QP_EVENT_STATUS_RESOURCES 0x2UL + #define CREQ_QP_EVENT_STATUS_INVALID_CMD 0x3UL + #define CREQ_QP_EVENT_STATUS_NOT_IMPLEMENTED 0x4UL + #define CREQ_QP_EVENT_STATUS_INVALID_PARAMETER 0x5UL + #define CREQ_QP_EVENT_STATUS_HARDWARE_ERROR 0x6UL + #define CREQ_QP_EVENT_STATUS_INTERNAL_ERROR 0x7UL + #define CREQ_QP_EVENT_STATUS_LAST CREQ_QP_EVENT_STATUS_INTERNAL_ERROR + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_QP_EVENT_V 0x1UL + u8 event; + #define CREQ_QP_EVENT_EVENT_CREATE_QP 0x1UL + #define CREQ_QP_EVENT_EVENT_DESTROY_QP 0x2UL + #define CREQ_QP_EVENT_EVENT_MODIFY_QP 0x3UL + #define CREQ_QP_EVENT_EVENT_QUERY_QP 0x4UL + #define CREQ_QP_EVENT_EVENT_CREATE_SRQ 0x5UL + #define CREQ_QP_EVENT_EVENT_DESTROY_SRQ 0x6UL + #define CREQ_QP_EVENT_EVENT_QUERY_SRQ 0x8UL + #define CREQ_QP_EVENT_EVENT_CREATE_CQ 0x9UL + #define CREQ_QP_EVENT_EVENT_DESTROY_CQ 0xaUL + #define CREQ_QP_EVENT_EVENT_RESIZE_CQ 0xcUL + #define CREQ_QP_EVENT_EVENT_ALLOCATE_MRW 0xdUL + #define CREQ_QP_EVENT_EVENT_DEALLOCATE_KEY 0xeUL + #define CREQ_QP_EVENT_EVENT_REGISTER_MR 0xfUL + #define CREQ_QP_EVENT_EVENT_DEREGISTER_MR 0x10UL + #define CREQ_QP_EVENT_EVENT_ADD_GID 0x11UL + #define CREQ_QP_EVENT_EVENT_DELETE_GID 0x12UL + #define CREQ_QP_EVENT_EVENT_MODIFY_GID 0x17UL + #define CREQ_QP_EVENT_EVENT_QUERY_GID 0x18UL + #define CREQ_QP_EVENT_EVENT_CREATE_QP1 0x13UL + #define CREQ_QP_EVENT_EVENT_DESTROY_QP1 0x14UL + #define CREQ_QP_EVENT_EVENT_CREATE_AH 0x15UL + #define CREQ_QP_EVENT_EVENT_DESTROY_AH 0x16UL + #define CREQ_QP_EVENT_EVENT_INITIALIZE_FW 0x80UL + #define CREQ_QP_EVENT_EVENT_DEINITIALIZE_FW 0x81UL + #define CREQ_QP_EVENT_EVENT_STOP_FUNC 0x82UL + #define CREQ_QP_EVENT_EVENT_QUERY_FUNC 0x83UL + #define CREQ_QP_EVENT_EVENT_SET_FUNC_RESOURCES 0x84UL + #define CREQ_QP_EVENT_EVENT_READ_CONTEXT 0x85UL + #define CREQ_QP_EVENT_EVENT_MAP_TC_TO_COS 0x8aUL + #define CREQ_QP_EVENT_EVENT_QUERY_VERSION 0x8bUL + #define CREQ_QP_EVENT_EVENT_MODIFY_CC 0x8cUL + #define CREQ_QP_EVENT_EVENT_QUERY_CC 0x8dUL + #define CREQ_QP_EVENT_EVENT_QUERY_ROCE_STATS 0x8eUL + #define CREQ_QP_EVENT_EVENT_SET_LINK_AGGR_MODE 0x8fUL + #define CREQ_QP_EVENT_EVENT_QUERY_QP_EXTEND 0x91UL + #define CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION 0xc0UL + #define CREQ_QP_EVENT_EVENT_CQ_ERROR_NOTIFICATION 0xc1UL + #define CREQ_QP_EVENT_EVENT_LAST CREQ_QP_EVENT_EVENT_CQ_ERROR_NOTIFICATION + u8 reserved48[6]; +}; + +/* creq_qp_error_notification (size:128b/16B) */ struct creq_qp_error_notification { - u8 type; - #define CREQ_QP_ERROR_NOTIFICATION_TYPE_MASK 0x3fUL - #define CREQ_QP_ERROR_NOTIFICATION_TYPE_SFT 0 - #define CREQ_QP_ERROR_NOTIFICATION_TYPE_QP_EVENT 0x38UL - #define CREQ_QP_ERROR_NOTIFICATION_RESERVED2_MASK 0xc0UL - #define CREQ_QP_ERROR_NOTIFICATION_RESERVED2_SFT 6 - u8 status; - u8 req_slow_path_state; - u8 req_err_state_reason; - __le32 xid; - u8 v; - #define CREQ_QP_ERROR_NOTIFICATION_V 0x1UL - #define CREQ_QP_ERROR_NOTIFICATION_RESERVED7_MASK 0xfeUL - #define CREQ_QP_ERROR_NOTIFICATION_RESERVED7_SFT 1 - u8 event; + u8 type; + #define CREQ_QP_ERROR_NOTIFICATION_TYPE_MASK 0x3fUL + #define CREQ_QP_ERROR_NOTIFICATION_TYPE_SFT 0 + #define CREQ_QP_ERROR_NOTIFICATION_TYPE_QP_EVENT 0x38UL + #define CREQ_QP_ERROR_NOTIFICATION_TYPE_LAST CREQ_QP_ERROR_NOTIFICATION_TYPE_QP_EVENT + u8 status; + u8 req_slow_path_state; + u8 req_err_state_reason; + __le32 xid; + u8 v; + #define CREQ_QP_ERROR_NOTIFICATION_V 0x1UL + u8 event; #define CREQ_QP_ERROR_NOTIFICATION_EVENT_QP_ERROR_NOTIFICATION 0xc0UL - u8 res_slow_path_state; - u8 res_err_state_reason; - __le16 sq_cons_idx; - __le16 rq_cons_idx; + #define CREQ_QP_ERROR_NOTIFICATION_EVENT_LAST \ + CREQ_QP_ERROR_NOTIFICATION_EVENT_QP_ERROR_NOTIFICATION + u8 res_slow_path_state; + u8 res_err_state_reason; + __le16 sq_cons_idx; + __le16 rq_cons_idx; }; -/* RoCE Slowpath HSI Specification 1.6.0 */ -#define ROCE_SP_HSI_VERSION_MAJOR 1 -#define ROCE_SP_HSI_VERSION_MINOR 6 -#define ROCE_SP_HSI_VERSION_UPDATE 0 +/* creq_cq_error_notification (size:128b/16B) */ +struct creq_cq_error_notification { + u8 type; + #define CREQ_CQ_ERROR_NOTIFICATION_TYPE_MASK 0x3fUL + #define CREQ_CQ_ERROR_NOTIFICATION_TYPE_SFT 0 + #define CREQ_CQ_ERROR_NOTIFICATION_TYPE_CQ_EVENT 0x38UL + #define CREQ_CQ_ERROR_NOTIFICATION_TYPE_LAST CREQ_CQ_ERROR_NOTIFICATION_TYPE_CQ_EVENT + u8 status; + u8 cq_err_reason; + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_REQ_CQ_INVALID_ERROR 0x1UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_REQ_CQ_OVERFLOW_ERROR 0x2UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_REQ_CQ_LOAD_ERROR 0x3UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_RES_CQ_INVALID_ERROR 0x4UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_RES_CQ_OVERFLOW_ERROR 0x5UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_RES_CQ_LOAD_ERROR 0x6UL + #define CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_LAST \ + CREQ_CQ_ERROR_NOTIFICATION_CQ_ERR_REASON_RES_CQ_LOAD_ERROR + u8 reserved8; + __le32 xid; + u8 v; + #define CREQ_CQ_ERROR_NOTIFICATION_V 0x1UL + u8 event; + #define CREQ_CQ_ERROR_NOTIFICATION_EVENT_CQ_ERROR_NOTIFICATION 0xc1UL + #define CREQ_CQ_ERROR_NOTIFICATION_EVENT_LAST \ + CREQ_CQ_ERROR_NOTIFICATION_EVENT_CQ_ERROR_NOTIFICATION + u8 reserved48[6]; +}; -#define ROCE_SP_HSI_VERSION_STR "1.6.0" -/* - * Following is the signature for ROCE_SP_HSI message field that indicates not - * applicable (All F's). Need to cast it the size of the field if needed. - */ -#define ROCE_SP_HSI_NA_SIGNATURE ((__le32)(-1)) -#endif /* __BNXT_RE_HSI_H__ */ +/* sq_base (size:64b/8B) */ +struct sq_base { + u8 wqe_type; + #define SQ_BASE_WQE_TYPE_SEND 0x0UL + #define SQ_BASE_WQE_TYPE_SEND_W_IMMEAD 0x1UL + #define SQ_BASE_WQE_TYPE_SEND_W_INVALID 0x2UL + #define SQ_BASE_WQE_TYPE_WRITE_WQE 0x4UL + #define SQ_BASE_WQE_TYPE_WRITE_W_IMMEAD 0x5UL + #define SQ_BASE_WQE_TYPE_READ_WQE 0x6UL + #define SQ_BASE_WQE_TYPE_ATOMIC_CS 0x8UL + #define SQ_BASE_WQE_TYPE_ATOMIC_FA 0xbUL + #define SQ_BASE_WQE_TYPE_LOCAL_INVALID 0xcUL + #define SQ_BASE_WQE_TYPE_FR_PMR 0xdUL + #define SQ_BASE_WQE_TYPE_BIND 0xeUL + #define SQ_BASE_WQE_TYPE_FR_PPMR 0xfUL + #define SQ_BASE_WQE_TYPE_LAST SQ_BASE_WQE_TYPE_FR_PPMR + u8 unused_0[7]; +}; + +/* sq_sge (size:128b/16B) */ +struct sq_sge { + __le64 va_or_pa; + __le32 l_key; + __le32 size; +}; + +/* sq_psn_search (size:64b/8B) */ +struct sq_psn_search { + __le32 opcode_start_psn; + #define SQ_PSN_SEARCH_START_PSN_MASK 0xffffffUL + #define SQ_PSN_SEARCH_START_PSN_SFT 0 + #define SQ_PSN_SEARCH_OPCODE_MASK 0xff000000UL + #define SQ_PSN_SEARCH_OPCODE_SFT 24 + __le32 flags_next_psn; + #define SQ_PSN_SEARCH_NEXT_PSN_MASK 0xffffffUL + #define SQ_PSN_SEARCH_NEXT_PSN_SFT 0 + #define SQ_PSN_SEARCH_FLAGS_MASK 0xff000000UL + #define SQ_PSN_SEARCH_FLAGS_SFT 24 +}; + +/* sq_psn_search_ext (size:128b/16B) */ +struct sq_psn_search_ext { + __le32 opcode_start_psn; + #define SQ_PSN_SEARCH_EXT_START_PSN_MASK 0xffffffUL + #define SQ_PSN_SEARCH_EXT_START_PSN_SFT 0 + #define SQ_PSN_SEARCH_EXT_OPCODE_MASK 0xff000000UL + #define SQ_PSN_SEARCH_EXT_OPCODE_SFT 24 + __le32 flags_next_psn; + #define SQ_PSN_SEARCH_EXT_NEXT_PSN_MASK 0xffffffUL + #define SQ_PSN_SEARCH_EXT_NEXT_PSN_SFT 0 + #define SQ_PSN_SEARCH_EXT_FLAGS_MASK 0xff000000UL + #define SQ_PSN_SEARCH_EXT_FLAGS_SFT 24 + __le16 start_slot_idx; + __le16 reserved16; + __le32 reserved32; +}; + +/* sq_send (size:1024b/128B) */ +struct sq_send { + u8 wqe_type; + #define SQ_SEND_WQE_TYPE_SEND 0x0UL + #define SQ_SEND_WQE_TYPE_SEND_W_IMMEAD 0x1UL + #define SQ_SEND_WQE_TYPE_SEND_W_INVALID 0x2UL + #define SQ_SEND_WQE_TYPE_LAST SQ_SEND_WQE_TYPE_SEND_W_INVALID + u8 flags; + #define SQ_SEND_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_SEND_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_SEND_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_SEND_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_SEND_FLAGS_UC_FENCE 0x4UL + #define SQ_SEND_FLAGS_SE 0x8UL + #define SQ_SEND_FLAGS_INLINE 0x10UL + #define SQ_SEND_FLAGS_WQE_TS_EN 0x20UL + #define SQ_SEND_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8_1; + __le32 inv_key_or_imm_data; + __le32 length; + __le32 q_key; + __le32 dst_qp; + #define SQ_SEND_DST_QP_MASK 0xffffffUL + #define SQ_SEND_DST_QP_SFT 0 + __le32 avid; + #define SQ_SEND_AVID_MASK 0xfffffUL + #define SQ_SEND_AVID_SFT 0 + __le32 reserved32; + __le32 timestamp; + #define SQ_SEND_TIMESTAMP_MASK 0xffffffUL + #define SQ_SEND_TIMESTAMP_SFT 0 + __le32 data[24]; +}; + +/* sq_send_hdr (size:256b/32B) */ +struct sq_send_hdr { + u8 wqe_type; + #define SQ_SEND_HDR_WQE_TYPE_SEND 0x0UL + #define SQ_SEND_HDR_WQE_TYPE_SEND_W_IMMEAD 0x1UL + #define SQ_SEND_HDR_WQE_TYPE_SEND_W_INVALID 0x2UL + #define SQ_SEND_HDR_WQE_TYPE_LAST SQ_SEND_HDR_WQE_TYPE_SEND_W_INVALID + u8 flags; + #define SQ_SEND_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_SEND_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_SEND_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_SEND_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_SEND_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_SEND_HDR_FLAGS_SE 0x8UL + #define SQ_SEND_HDR_FLAGS_INLINE 0x10UL + #define SQ_SEND_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_SEND_HDR_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8_1; + __le32 inv_key_or_imm_data; + __le32 length; + __le32 q_key; + __le32 dst_qp; + #define SQ_SEND_HDR_DST_QP_MASK 0xffffffUL + #define SQ_SEND_HDR_DST_QP_SFT 0 + __le32 avid; + #define SQ_SEND_HDR_AVID_MASK 0xfffffUL + #define SQ_SEND_HDR_AVID_SFT 0 + __le32 reserved32; + __le32 timestamp; + #define SQ_SEND_HDR_TIMESTAMP_MASK 0xffffffUL + #define SQ_SEND_HDR_TIMESTAMP_SFT 0 +}; + +/* sq_send_raweth_qp1 (size:1024b/128B) */ +struct sq_send_raweth_qp1 { + u8 wqe_type; + #define SQ_SEND_RAWETH_QP1_WQE_TYPE_SEND 0x0UL + #define SQ_SEND_RAWETH_QP1_WQE_TYPE_LAST SQ_SEND_RAWETH_QP1_WQE_TYPE_SEND + u8 flags; + #define SQ_SEND_RAWETH_QP1_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK \ + 0xffUL + #define SQ_SEND_RAWETH_QP1_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT \ + 0 + #define SQ_SEND_RAWETH_QP1_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_SEND_RAWETH_QP1_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_SEND_RAWETH_QP1_FLAGS_UC_FENCE 0x4UL + #define SQ_SEND_RAWETH_QP1_FLAGS_SE 0x8UL + #define SQ_SEND_RAWETH_QP1_FLAGS_INLINE 0x10UL + #define SQ_SEND_RAWETH_QP1_FLAGS_WQE_TS_EN 0x20UL + #define SQ_SEND_RAWETH_QP1_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8; + __le16 lflags; + #define SQ_SEND_RAWETH_QP1_LFLAGS_TCP_UDP_CHKSUM 0x1UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_IP_CHKSUM 0x2UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_NOCRC 0x4UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_STAMP 0x8UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_T_IP_CHKSUM 0x10UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_ROCE_CRC 0x100UL + #define SQ_SEND_RAWETH_QP1_LFLAGS_FCOE_CRC 0x200UL + __le16 cfa_action; + __le32 length; + __le32 reserved32_1; + __le32 cfa_meta; + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_VID_MASK 0xfffUL + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_VID_SFT 0 + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_DE 0x1000UL + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_PRI_MASK 0xe000UL + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_PRI_SFT 13 + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_MASK 0x70000UL + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_SFT 16 + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID88A8 (0x0UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID8100 (0x1UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9100 (0x2UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9200 (0x3UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPID9300 (0x4UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPIDCFG (0x5UL << 16) + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_LAST\ + SQ_SEND_RAWETH_QP1_CFA_META_VLAN_TPID_TPIDCFG + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_RESERVED_MASK 0xff80000UL + #define SQ_SEND_RAWETH_QP1_CFA_META_VLAN_RESERVED_SFT 19 + #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_MASK 0xf0000000UL + #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_SFT 28 + #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_NONE (0x0UL << 28) + #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_VLAN_TAG (0x1UL << 28) + #define SQ_SEND_RAWETH_QP1_CFA_META_KEY_LAST SQ_SEND_RAWETH_QP1_CFA_META_KEY_VLAN_TAG + __le32 reserved32_2; + __le32 reserved32_3; + __le32 timestamp; + #define SQ_SEND_RAWETH_QP1_TIMESTAMP_MASK 0xffffffUL + #define SQ_SEND_RAWETH_QP1_TIMESTAMP_SFT 0 + __le32 data[24]; +}; + +/* sq_send_raweth_qp1_hdr (size:256b/32B) */ +struct sq_send_raweth_qp1_hdr { + u8 wqe_type; + #define SQ_SEND_RAWETH_QP1_HDR_WQE_TYPE_SEND 0x0UL + #define SQ_SEND_RAWETH_QP1_HDR_WQE_TYPE_LAST SQ_SEND_RAWETH_QP1_HDR_WQE_TYPE_SEND + u8 flags; + #define \ + SQ_SEND_RAWETH_QP1_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT\ + 0 + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_SE 0x8UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_INLINE 0x10UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_SEND_RAWETH_QP1_HDR_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8; + __le16 lflags; + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_TCP_UDP_CHKSUM 0x1UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_IP_CHKSUM 0x2UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_NOCRC 0x4UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_STAMP 0x8UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_T_IP_CHKSUM 0x10UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_ROCE_CRC 0x100UL + #define SQ_SEND_RAWETH_QP1_HDR_LFLAGS_FCOE_CRC 0x200UL + __le16 cfa_action; + __le32 length; + __le32 reserved32_1; + __le32 cfa_meta; + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_VID_MASK 0xfffUL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_VID_SFT 0 + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_DE 0x1000UL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_PRI_MASK 0xe000UL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_PRI_SFT 13 + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_MASK 0x70000UL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_SFT 16 + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPID88A8 (0x0UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPID8100 (0x1UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPID9100 (0x2UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPID9200 (0x3UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPID9300 (0x4UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPIDCFG (0x5UL << 16) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_LAST\ + SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_TPID_TPIDCFG + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_RESERVED_MASK 0xff80000UL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_VLAN_RESERVED_SFT 19 + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_MASK 0xf0000000UL + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_SFT 28 + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_NONE (0x0UL << 28) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_VLAN_TAG (0x1UL << 28) + #define SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_LAST\ + SQ_SEND_RAWETH_QP1_HDR_CFA_META_KEY_VLAN_TAG + __le32 reserved32_2; + __le32 reserved32_3; + __le32 timestamp; + #define SQ_SEND_RAWETH_QP1_HDR_TIMESTAMP_MASK 0xffffffUL + #define SQ_SEND_RAWETH_QP1_HDR_TIMESTAMP_SFT 0 +}; + +/* sq_rdma (size:1024b/128B) */ +struct sq_rdma { + u8 wqe_type; + #define SQ_RDMA_WQE_TYPE_WRITE_WQE 0x4UL + #define SQ_RDMA_WQE_TYPE_WRITE_W_IMMEAD 0x5UL + #define SQ_RDMA_WQE_TYPE_READ_WQE 0x6UL + #define SQ_RDMA_WQE_TYPE_LAST SQ_RDMA_WQE_TYPE_READ_WQE + u8 flags; + #define SQ_RDMA_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_RDMA_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_RDMA_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_RDMA_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_RDMA_FLAGS_UC_FENCE 0x4UL + #define SQ_RDMA_FLAGS_SE 0x8UL + #define SQ_RDMA_FLAGS_INLINE 0x10UL + #define SQ_RDMA_FLAGS_WQE_TS_EN 0x20UL + #define SQ_RDMA_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8; + __le32 imm_data; + __le32 length; + __le32 reserved32_1; + __le64 remote_va; + __le32 remote_key; + __le32 timestamp; + #define SQ_RDMA_TIMESTAMP_MASK 0xffffffUL + #define SQ_RDMA_TIMESTAMP_SFT 0 + __le32 data[24]; +}; + +/* sq_rdma_hdr (size:256b/32B) */ +struct sq_rdma_hdr { + u8 wqe_type; + #define SQ_RDMA_HDR_WQE_TYPE_WRITE_WQE 0x4UL + #define SQ_RDMA_HDR_WQE_TYPE_WRITE_W_IMMEAD 0x5UL + #define SQ_RDMA_HDR_WQE_TYPE_READ_WQE 0x6UL + #define SQ_RDMA_HDR_WQE_TYPE_LAST SQ_RDMA_HDR_WQE_TYPE_READ_WQE + u8 flags; + #define SQ_RDMA_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_RDMA_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_RDMA_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_RDMA_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_RDMA_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_RDMA_HDR_FLAGS_SE 0x8UL + #define SQ_RDMA_HDR_FLAGS_INLINE 0x10UL + #define SQ_RDMA_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_RDMA_HDR_FLAGS_DEBUG_TRACE 0x40UL + u8 wqe_size; + u8 reserved8; + __le32 imm_data; + __le32 length; + __le32 reserved32_1; + __le64 remote_va; + __le32 remote_key; + __le32 timestamp; + #define SQ_RDMA_HDR_TIMESTAMP_MASK 0xffffffUL + #define SQ_RDMA_HDR_TIMESTAMP_SFT 0 +}; + +/* sq_atomic (size:1024b/128B) */ +struct sq_atomic { + u8 wqe_type; + #define SQ_ATOMIC_WQE_TYPE_ATOMIC_CS 0x8UL + #define SQ_ATOMIC_WQE_TYPE_ATOMIC_FA 0xbUL + #define SQ_ATOMIC_WQE_TYPE_LAST SQ_ATOMIC_WQE_TYPE_ATOMIC_FA + u8 flags; + #define SQ_ATOMIC_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_ATOMIC_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_ATOMIC_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_ATOMIC_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_ATOMIC_FLAGS_UC_FENCE 0x4UL + #define SQ_ATOMIC_FLAGS_SE 0x8UL + #define SQ_ATOMIC_FLAGS_INLINE 0x10UL + #define SQ_ATOMIC_FLAGS_WQE_TS_EN 0x20UL + #define SQ_ATOMIC_FLAGS_DEBUG_TRACE 0x40UL + __le16 reserved16; + __le32 remote_key; + __le64 remote_va; + __le64 swap_data; + __le64 cmp_data; + __le32 data[24]; +}; + +/* sq_atomic_hdr (size:256b/32B) */ +struct sq_atomic_hdr { + u8 wqe_type; + #define SQ_ATOMIC_HDR_WQE_TYPE_ATOMIC_CS 0x8UL + #define SQ_ATOMIC_HDR_WQE_TYPE_ATOMIC_FA 0xbUL + #define SQ_ATOMIC_HDR_WQE_TYPE_LAST SQ_ATOMIC_HDR_WQE_TYPE_ATOMIC_FA + u8 flags; + #define SQ_ATOMIC_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_ATOMIC_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_ATOMIC_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_ATOMIC_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_ATOMIC_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_ATOMIC_HDR_FLAGS_SE 0x8UL + #define SQ_ATOMIC_HDR_FLAGS_INLINE 0x10UL + #define SQ_ATOMIC_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_ATOMIC_HDR_FLAGS_DEBUG_TRACE 0x40UL + __le16 reserved16; + __le32 remote_key; + __le64 remote_va; + __le64 swap_data; + __le64 cmp_data; +}; + +/* sq_localinvalidate (size:1024b/128B) */ +struct sq_localinvalidate { + u8 wqe_type; + #define SQ_LOCALINVALIDATE_WQE_TYPE_LOCAL_INVALID 0xcUL + #define SQ_LOCALINVALIDATE_WQE_TYPE_LAST SQ_LOCALINVALIDATE_WQE_TYPE_LOCAL_INVALID + u8 flags; + #define SQ_LOCALINVALIDATE_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK\ + 0xffUL + #define SQ_LOCALINVALIDATE_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT\ + 0 + #define SQ_LOCALINVALIDATE_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_LOCALINVALIDATE_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_LOCALINVALIDATE_FLAGS_UC_FENCE 0x4UL + #define SQ_LOCALINVALIDATE_FLAGS_SE 0x8UL + #define SQ_LOCALINVALIDATE_FLAGS_INLINE 0x10UL + #define SQ_LOCALINVALIDATE_FLAGS_WQE_TS_EN 0x20UL + #define SQ_LOCALINVALIDATE_FLAGS_DEBUG_TRACE 0x40UL + __le16 reserved16; + __le32 inv_l_key; + __le64 reserved64; + u8 reserved128[16]; + __le32 data[24]; +}; + +/* sq_localinvalidate_hdr (size:256b/32B) */ +struct sq_localinvalidate_hdr { + u8 wqe_type; + #define SQ_LOCALINVALIDATE_HDR_WQE_TYPE_LOCAL_INVALID 0xcUL + #define SQ_LOCALINVALIDATE_HDR_WQE_TYPE_LAST SQ_LOCALINVALIDATE_HDR_WQE_TYPE_LOCAL_INVALID + u8 flags; + #define \ + SQ_LOCALINVALIDATE_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT\ + 0 + #define SQ_LOCALINVALIDATE_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_SE 0x8UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_INLINE 0x10UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_LOCALINVALIDATE_HDR_FLAGS_DEBUG_TRACE 0x40UL + __le16 reserved16; + __le32 inv_l_key; + __le64 reserved64; + u8 reserved128[16]; +}; + +/* sq_fr_pmr (size:1024b/128B) */ +struct sq_fr_pmr { + u8 wqe_type; + #define SQ_FR_PMR_WQE_TYPE_FR_PMR 0xdUL + #define SQ_FR_PMR_WQE_TYPE_LAST SQ_FR_PMR_WQE_TYPE_FR_PMR + u8 flags; + #define SQ_FR_PMR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_FR_PMR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_FR_PMR_FLAGS_UC_FENCE 0x4UL + #define SQ_FR_PMR_FLAGS_SE 0x8UL + #define SQ_FR_PMR_FLAGS_INLINE 0x10UL + #define SQ_FR_PMR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_FR_PMR_FLAGS_DEBUG_TRACE 0x40UL + u8 access_cntl; + #define SQ_FR_PMR_ACCESS_CNTL_LOCAL_WRITE 0x1UL + #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_READ 0x2UL + #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_WRITE 0x4UL + #define SQ_FR_PMR_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL + #define SQ_FR_PMR_ACCESS_CNTL_WINDOW_BIND 0x10UL + u8 zero_based_page_size_log; + #define SQ_FR_PMR_PAGE_SIZE_LOG_MASK 0x1fUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_SFT 0 + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4K 0x0UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8K 0x1UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_16K 0x2UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_32K 0x3UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_64K 0x4UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_128K 0x5UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_256K 0x6UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_512K 0x7UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_1M 0x8UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_2M 0x9UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4M 0xaUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8M 0xbUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_16M 0xcUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_32M 0xdUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_64M 0xeUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_128M 0xfUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_256M 0x10UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_512M 0x11UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_1G 0x12UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_2G 0x13UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4G 0x14UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8G 0x15UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_16G 0x16UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_32G 0x17UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_64G 0x18UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_128G 0x19UL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_256G 0x1aUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_512G 0x1bUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_1T 0x1cUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_2T 0x1dUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_4T 0x1eUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8T 0x1fUL + #define SQ_FR_PMR_PAGE_SIZE_LOG_LAST SQ_FR_PMR_PAGE_SIZE_LOG_PGSZ_8T + #define SQ_FR_PMR_ZERO_BASED 0x20UL + __le32 l_key; + u8 length[5]; + u8 reserved8_1; + u8 reserved8_2; + u8 numlevels_pbl_page_size_log; + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_MASK 0x1fUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_SFT 0 + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4K 0x0UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8K 0x1UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_16K 0x2UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_32K 0x3UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_64K 0x4UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_128K 0x5UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_256K 0x6UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_512K 0x7UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_1M 0x8UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_2M 0x9UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4M 0xaUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8M 0xbUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_16M 0xcUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_32M 0xdUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_64M 0xeUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_128M 0xfUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_256M 0x10UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_512M 0x11UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_1G 0x12UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_2G 0x13UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4G 0x14UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8G 0x15UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_16G 0x16UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_32G 0x17UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_64G 0x18UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_128G 0x19UL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_256G 0x1aUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_512G 0x1bUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_1T 0x1cUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_2T 0x1dUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_4T 0x1eUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8T 0x1fUL + #define SQ_FR_PMR_PBL_PAGE_SIZE_LOG_LAST SQ_FR_PMR_PBL_PAGE_SIZE_LOG_PGSZ_8T + #define SQ_FR_PMR_NUMLEVELS_MASK 0xc0UL + #define SQ_FR_PMR_NUMLEVELS_SFT 6 + #define SQ_FR_PMR_NUMLEVELS_PHYSICAL (0x0UL << 6) + #define SQ_FR_PMR_NUMLEVELS_LAYER1 (0x1UL << 6) + #define SQ_FR_PMR_NUMLEVELS_LAYER2 (0x2UL << 6) + #define SQ_FR_PMR_NUMLEVELS_LAST SQ_FR_PMR_NUMLEVELS_LAYER2 + __le64 pblptr; + __le64 va; + __le32 data[24]; +}; + +/* sq_fr_pmr_hdr (size:256b/32B) */ +struct sq_fr_pmr_hdr { + u8 wqe_type; + #define SQ_FR_PMR_HDR_WQE_TYPE_FR_PMR 0xdUL + #define SQ_FR_PMR_HDR_WQE_TYPE_LAST SQ_FR_PMR_HDR_WQE_TYPE_FR_PMR + u8 flags; + #define SQ_FR_PMR_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_FR_PMR_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_FR_PMR_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_FR_PMR_HDR_FLAGS_SE 0x8UL + #define SQ_FR_PMR_HDR_FLAGS_INLINE 0x10UL + #define SQ_FR_PMR_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_FR_PMR_HDR_FLAGS_DEBUG_TRACE 0x40UL + u8 access_cntl; + #define SQ_FR_PMR_HDR_ACCESS_CNTL_LOCAL_WRITE 0x1UL + #define SQ_FR_PMR_HDR_ACCESS_CNTL_REMOTE_READ 0x2UL + #define SQ_FR_PMR_HDR_ACCESS_CNTL_REMOTE_WRITE 0x4UL + #define SQ_FR_PMR_HDR_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL + #define SQ_FR_PMR_HDR_ACCESS_CNTL_WINDOW_BIND 0x10UL + u8 zero_based_page_size_log; + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_MASK 0x1fUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_SFT 0 + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_4K 0x0UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_8K 0x1UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_16K 0x2UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_32K 0x3UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_64K 0x4UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_128K 0x5UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_256K 0x6UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_512K 0x7UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_1M 0x8UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_2M 0x9UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_4M 0xaUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_8M 0xbUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_16M 0xcUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_32M 0xdUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_64M 0xeUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_128M 0xfUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_256M 0x10UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_512M 0x11UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_1G 0x12UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_2G 0x13UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_4G 0x14UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_8G 0x15UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_16G 0x16UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_32G 0x17UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_64G 0x18UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_128G 0x19UL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_256G 0x1aUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_512G 0x1bUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_1T 0x1cUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_2T 0x1dUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_4T 0x1eUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_8T 0x1fUL + #define SQ_FR_PMR_HDR_PAGE_SIZE_LOG_LAST SQ_FR_PMR_HDR_PAGE_SIZE_LOG_PGSZ_8T + #define SQ_FR_PMR_HDR_ZERO_BASED 0x20UL + __le32 l_key; + u8 length[5]; + u8 reserved8_1; + u8 reserved8_2; + u8 numlevels_pbl_page_size_log; + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_MASK 0x1fUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_SFT 0 + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_4K 0x0UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_8K 0x1UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_16K 0x2UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_32K 0x3UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_64K 0x4UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_128K 0x5UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_256K 0x6UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_512K 0x7UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_1M 0x8UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_2M 0x9UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_4M 0xaUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_8M 0xbUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_16M 0xcUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_32M 0xdUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_64M 0xeUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_128M 0xfUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_256M 0x10UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_512M 0x11UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_1G 0x12UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_2G 0x13UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_4G 0x14UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_8G 0x15UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_16G 0x16UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_32G 0x17UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_64G 0x18UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_128G 0x19UL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_256G 0x1aUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_512G 0x1bUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_1T 0x1cUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_2T 0x1dUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_4T 0x1eUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_8T 0x1fUL + #define SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_LAST SQ_FR_PMR_HDR_PBL_PAGE_SIZE_LOG_PGSZ_8T + #define SQ_FR_PMR_HDR_NUMLEVELS_MASK 0xc0UL + #define SQ_FR_PMR_HDR_NUMLEVELS_SFT 6 + #define SQ_FR_PMR_HDR_NUMLEVELS_PHYSICAL (0x0UL << 6) + #define SQ_FR_PMR_HDR_NUMLEVELS_LAYER1 (0x1UL << 6) + #define SQ_FR_PMR_HDR_NUMLEVELS_LAYER2 (0x2UL << 6) + #define SQ_FR_PMR_HDR_NUMLEVELS_LAST SQ_FR_PMR_HDR_NUMLEVELS_LAYER2 + __le64 pblptr; + __le64 va; +}; + +/* sq_bind (size:1024b/128B) */ +struct sq_bind { + u8 wqe_type; + #define SQ_BIND_WQE_TYPE_BIND 0xeUL + #define SQ_BIND_WQE_TYPE_LAST SQ_BIND_WQE_TYPE_BIND + u8 flags; + #define SQ_BIND_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_BIND_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_BIND_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_BIND_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_BIND_FLAGS_UC_FENCE 0x4UL + #define SQ_BIND_FLAGS_SE 0x8UL + #define SQ_BIND_FLAGS_INLINE 0x10UL + #define SQ_BIND_FLAGS_WQE_TS_EN 0x20UL + #define SQ_BIND_FLAGS_DEBUG_TRACE 0x40UL + u8 access_cntl; + #define \ + SQ_BIND_ACCESS_CNTL_WINDOW_BIND_REMOTE_ATOMIC_REMOTE_WRITE_REMOTE_READ_LOCAL_WRITE_MASK\ + 0xffUL + #define \ + SQ_BIND_ACCESS_CNTL_WINDOW_BIND_REMOTE_ATOMIC_REMOTE_WRITE_REMOTE_READ_LOCAL_WRITE_SFT 0 + #define SQ_BIND_ACCESS_CNTL_LOCAL_WRITE 0x1UL + #define SQ_BIND_ACCESS_CNTL_REMOTE_READ 0x2UL + #define SQ_BIND_ACCESS_CNTL_REMOTE_WRITE 0x4UL + #define SQ_BIND_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL + #define SQ_BIND_ACCESS_CNTL_WINDOW_BIND 0x10UL + u8 reserved8_1; + u8 mw_type_zero_based; + #define SQ_BIND_ZERO_BASED 0x1UL + #define SQ_BIND_MW_TYPE 0x2UL + #define SQ_BIND_MW_TYPE_TYPE1 (0x0UL << 1) + #define SQ_BIND_MW_TYPE_TYPE2 (0x1UL << 1) + #define SQ_BIND_MW_TYPE_LAST SQ_BIND_MW_TYPE_TYPE2 + u8 reserved8_2; + __le16 reserved16; + __le32 parent_l_key; + __le32 l_key; + __le64 va; + u8 length[5]; + u8 reserved24[3]; + __le32 data[24]; +}; + +/* sq_bind_hdr (size:256b/32B) */ +struct sq_bind_hdr { + u8 wqe_type; + #define SQ_BIND_HDR_WQE_TYPE_BIND 0xeUL + #define SQ_BIND_HDR_WQE_TYPE_LAST SQ_BIND_HDR_WQE_TYPE_BIND + u8 flags; + #define SQ_BIND_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_MASK 0xffUL + #define SQ_BIND_HDR_FLAGS_INLINE_SE_UC_FENCE_RD_OR_ATOMIC_FENCE_SIGNAL_COMP_SFT 0 + #define SQ_BIND_HDR_FLAGS_SIGNAL_COMP 0x1UL + #define SQ_BIND_HDR_FLAGS_RD_OR_ATOMIC_FENCE 0x2UL + #define SQ_BIND_HDR_FLAGS_UC_FENCE 0x4UL + #define SQ_BIND_HDR_FLAGS_SE 0x8UL + #define SQ_BIND_HDR_FLAGS_INLINE 0x10UL + #define SQ_BIND_HDR_FLAGS_WQE_TS_EN 0x20UL + #define SQ_BIND_HDR_FLAGS_DEBUG_TRACE 0x40UL + u8 access_cntl; + #define \ + SQ_BIND_HDR_ACCESS_CNTL_WINDOW_BIND_REMOTE_ATOMIC_REMOTE_WRITE_REMOTE_READ_LOCAL_WRITE_MASK\ + 0xffUL + #define \ + SQ_BIND_HDR_ACCESS_CNTL_WINDOW_BIND_REMOTE_ATOMIC_REMOTE_WRITE_REMOTE_READ_LOCAL_WRITE_SFT \ + 0 + #define SQ_BIND_HDR_ACCESS_CNTL_LOCAL_WRITE 0x1UL + #define SQ_BIND_HDR_ACCESS_CNTL_REMOTE_READ 0x2UL + #define SQ_BIND_HDR_ACCESS_CNTL_REMOTE_WRITE 0x4UL + #define SQ_BIND_HDR_ACCESS_CNTL_REMOTE_ATOMIC 0x8UL + #define SQ_BIND_HDR_ACCESS_CNTL_WINDOW_BIND 0x10UL + u8 reserved8_1; + u8 mw_type_zero_based; + #define SQ_BIND_HDR_ZERO_BASED 0x1UL + #define SQ_BIND_HDR_MW_TYPE 0x2UL + #define SQ_BIND_HDR_MW_TYPE_TYPE1 (0x0UL << 1) + #define SQ_BIND_HDR_MW_TYPE_TYPE2 (0x1UL << 1) + #define SQ_BIND_HDR_MW_TYPE_LAST SQ_BIND_HDR_MW_TYPE_TYPE2 + u8 reserved8_2; + __le16 reserved16; + __le32 parent_l_key; + __le32 l_key; + __le64 va; + u8 length[5]; + u8 reserved24[3]; +}; + +/* rq_wqe (size:1024b/128B) */ +struct rq_wqe { + u8 wqe_type; + #define RQ_WQE_WQE_TYPE_RCV 0x80UL + #define RQ_WQE_WQE_TYPE_LAST RQ_WQE_WQE_TYPE_RCV + u8 flags; + u8 wqe_size; + u8 reserved8; + __le32 reserved32; + __le32 wr_id[2]; + #define RQ_WQE_WR_ID_MASK 0xfffffUL + #define RQ_WQE_WR_ID_SFT 0 + u8 reserved128[16]; + __le32 data[24]; +}; + +/* rq_wqe_hdr (size:256b/32B) */ +struct rq_wqe_hdr { + u8 wqe_type; + #define RQ_WQE_HDR_WQE_TYPE_RCV 0x80UL + #define RQ_WQE_HDR_WQE_TYPE_LAST RQ_WQE_HDR_WQE_TYPE_RCV + u8 flags; + u8 wqe_size; + u8 reserved8; + __le32 reserved32; + __le32 wr_id[2]; + #define RQ_WQE_HDR_WR_ID_MASK 0xfffffUL + #define RQ_WQE_HDR_WR_ID_SFT 0 + u8 reserved128[16]; +}; + +/* cq_base (size:256b/32B) */ +struct cq_base { + __le64 reserved64_1; + __le64 reserved64_2; + __le64 reserved64_3; + u8 cqe_type_toggle; + #define CQ_BASE_TOGGLE 0x1UL + #define CQ_BASE_CQE_TYPE_MASK 0x1eUL + #define CQ_BASE_CQE_TYPE_SFT 1 + #define CQ_BASE_CQE_TYPE_REQ (0x0UL << 1) + #define CQ_BASE_CQE_TYPE_RES_RC (0x1UL << 1) + #define CQ_BASE_CQE_TYPE_RES_UD (0x2UL << 1) + #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) + #define CQ_BASE_CQE_TYPE_RES_UD_CFA (0x4UL << 1) + #define CQ_BASE_CQE_TYPE_NO_OP (0xdUL << 1) + #define CQ_BASE_CQE_TYPE_TERMINAL (0xeUL << 1) + #define CQ_BASE_CQE_TYPE_CUT_OFF (0xfUL << 1) + #define CQ_BASE_CQE_TYPE_LAST CQ_BASE_CQE_TYPE_CUT_OFF + u8 status; + __le16 reserved16; + __le32 reserved32; +}; + +/* cq_req (size:256b/32B) */ +struct cq_req { + __le64 qp_handle; + __le16 sq_cons_idx; + __le16 reserved16_1; + __le32 reserved32_2; + __le64 reserved64; + u8 cqe_type_toggle; + #define CQ_REQ_TOGGLE 0x1UL + #define CQ_REQ_CQE_TYPE_MASK 0x1eUL + #define CQ_REQ_CQE_TYPE_SFT 1 + #define CQ_REQ_CQE_TYPE_REQ (0x0UL << 1) + #define CQ_REQ_CQE_TYPE_LAST CQ_REQ_CQE_TYPE_REQ + #define CQ_REQ_PUSH 0x20UL + u8 status; + #define CQ_REQ_STATUS_OK 0x0UL + #define CQ_REQ_STATUS_BAD_RESPONSE_ERR 0x1UL + #define CQ_REQ_STATUS_LOCAL_LENGTH_ERR 0x2UL + #define CQ_REQ_STATUS_LOCAL_QP_OPERATION_ERR 0x3UL + #define CQ_REQ_STATUS_LOCAL_PROTECTION_ERR 0x4UL + #define CQ_REQ_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_REQ_STATUS_REMOTE_INVALID_REQUEST_ERR 0x6UL + #define CQ_REQ_STATUS_REMOTE_ACCESS_ERR 0x7UL + #define CQ_REQ_STATUS_REMOTE_OPERATION_ERR 0x8UL + #define CQ_REQ_STATUS_RNR_NAK_RETRY_CNT_ERR 0x9UL + #define CQ_REQ_STATUS_TRANSPORT_RETRY_CNT_ERR 0xaUL + #define CQ_REQ_STATUS_WORK_REQUEST_FLUSHED_ERR 0xbUL + #define CQ_REQ_STATUS_LAST CQ_REQ_STATUS_WORK_REQUEST_FLUSHED_ERR + __le16 reserved16_2; + __le32 reserved32_1; +}; + +/* cq_res_rc (size:256b/32B) */ +struct cq_res_rc { + __le32 length; + __le32 imm_data_or_inv_r_key; + __le64 qp_handle; + __le64 mr_handle; + u8 cqe_type_toggle; + #define CQ_RES_RC_TOGGLE 0x1UL + #define CQ_RES_RC_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_RC_CQE_TYPE_SFT 1 + #define CQ_RES_RC_CQE_TYPE_RES_RC (0x1UL << 1) + #define CQ_RES_RC_CQE_TYPE_LAST CQ_RES_RC_CQE_TYPE_RES_RC + u8 status; + #define CQ_RES_RC_STATUS_OK 0x0UL + #define CQ_RES_RC_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_RC_STATUS_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_RC_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_RC_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_RC_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_RC_STATUS_REMOTE_INVALID_REQUEST_ERR 0x6UL + #define CQ_RES_RC_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_RC_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_RC_STATUS_LAST CQ_RES_RC_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_RC_FLAGS_SRQ 0x1UL + #define CQ_RES_RC_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_RC_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_RC_FLAGS_SRQ_LAST CQ_RES_RC_FLAGS_SRQ_SRQ + #define CQ_RES_RC_FLAGS_IMM 0x2UL + #define CQ_RES_RC_FLAGS_INV 0x4UL + #define CQ_RES_RC_FLAGS_RDMA 0x8UL + #define CQ_RES_RC_FLAGS_RDMA_SEND (0x0UL << 3) + #define CQ_RES_RC_FLAGS_RDMA_RDMA_WRITE (0x1UL << 3) + #define CQ_RES_RC_FLAGS_RDMA_LAST CQ_RES_RC_FLAGS_RDMA_RDMA_WRITE + __le32 srq_or_rq_wr_id; + #define CQ_RES_RC_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_RC_SRQ_OR_RQ_WR_ID_SFT 0 +}; + +/* cq_res_ud (size:256b/32B) */ +struct cq_res_ud { + __le16 length; + #define CQ_RES_UD_LENGTH_MASK 0x3fffUL + #define CQ_RES_UD_LENGTH_SFT 0 + __le16 cfa_metadata; + #define CQ_RES_UD_CFA_METADATA_VID_MASK 0xfffUL + #define CQ_RES_UD_CFA_METADATA_VID_SFT 0 + #define CQ_RES_UD_CFA_METADATA_DE 0x1000UL + #define CQ_RES_UD_CFA_METADATA_PRI_MASK 0xe000UL + #define CQ_RES_UD_CFA_METADATA_PRI_SFT 13 + __le32 imm_data; + __le64 qp_handle; + __le16 src_mac[3]; + __le16 src_qp_low; + u8 cqe_type_toggle; + #define CQ_RES_UD_TOGGLE 0x1UL + #define CQ_RES_UD_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_UD_CQE_TYPE_SFT 1 + #define CQ_RES_UD_CQE_TYPE_RES_UD (0x2UL << 1) + #define CQ_RES_UD_CQE_TYPE_LAST CQ_RES_UD_CQE_TYPE_RES_UD + u8 status; + #define CQ_RES_UD_STATUS_OK 0x0UL + #define CQ_RES_UD_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_UD_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_UD_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_UD_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_UD_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_UD_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_UD_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_UD_STATUS_LAST CQ_RES_UD_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_UD_FLAGS_SRQ 0x1UL + #define CQ_RES_UD_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_UD_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_UD_FLAGS_SRQ_LAST CQ_RES_UD_FLAGS_SRQ_SRQ + #define CQ_RES_UD_FLAGS_IMM 0x2UL + #define CQ_RES_UD_FLAGS_UNUSED_MASK 0xcUL + #define CQ_RES_UD_FLAGS_UNUSED_SFT 2 + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_MASK 0x30UL + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_SFT 4 + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V1 (0x0UL << 4) + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV4 (0x2UL << 4) + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV6 (0x3UL << 4) + #define CQ_RES_UD_FLAGS_ROCE_IP_VER_LAST CQ_RES_UD_FLAGS_ROCE_IP_VER_V2IPV6 + #define CQ_RES_UD_FLAGS_META_FORMAT_MASK 0x3c0UL + #define CQ_RES_UD_FLAGS_META_FORMAT_SFT 6 + #define CQ_RES_UD_FLAGS_META_FORMAT_NONE (0x0UL << 6) + #define CQ_RES_UD_FLAGS_META_FORMAT_VLAN (0x1UL << 6) + #define CQ_RES_UD_FLAGS_META_FORMAT_TUNNEL_ID (0x2UL << 6) + #define CQ_RES_UD_FLAGS_META_FORMAT_CHDR_DATA (0x3UL << 6) + #define CQ_RES_UD_FLAGS_META_FORMAT_HDR_OFFSET (0x4UL << 6) + #define CQ_RES_UD_FLAGS_META_FORMAT_LAST CQ_RES_UD_FLAGS_META_FORMAT_HDR_OFFSET + #define CQ_RES_UD_FLAGS_EXT_META_FORMAT_MASK 0xc00UL + #define CQ_RES_UD_FLAGS_EXT_META_FORMAT_SFT 10 + __le32 src_qp_high_srq_or_rq_wr_id; + #define CQ_RES_UD_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_UD_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_UD_SRC_QP_HIGH_MASK 0xff000000UL + #define CQ_RES_UD_SRC_QP_HIGH_SFT 24 +}; + +/* cq_res_ud_v2 (size:256b/32B) */ +struct cq_res_ud_v2 { + __le16 length; + #define CQ_RES_UD_V2_LENGTH_MASK 0x3fffUL + #define CQ_RES_UD_V2_LENGTH_SFT 0 + __le16 cfa_metadata0; + #define CQ_RES_UD_V2_CFA_METADATA0_VID_MASK 0xfffUL + #define CQ_RES_UD_V2_CFA_METADATA0_VID_SFT 0 + #define CQ_RES_UD_V2_CFA_METADATA0_DE 0x1000UL + #define CQ_RES_UD_V2_CFA_METADATA0_PRI_MASK 0xe000UL + #define CQ_RES_UD_V2_CFA_METADATA0_PRI_SFT 13 + __le32 imm_data; + __le64 qp_handle; + __le16 src_mac[3]; + __le16 src_qp_low; + u8 cqe_type_toggle; + #define CQ_RES_UD_V2_TOGGLE 0x1UL + #define CQ_RES_UD_V2_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_UD_V2_CQE_TYPE_SFT 1 + #define CQ_RES_UD_V2_CQE_TYPE_RES_UD (0x2UL << 1) + #define CQ_RES_UD_V2_CQE_TYPE_LAST CQ_RES_UD_V2_CQE_TYPE_RES_UD + u8 status; + #define CQ_RES_UD_V2_STATUS_OK 0x0UL + #define CQ_RES_UD_V2_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_UD_V2_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_UD_V2_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_UD_V2_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_UD_V2_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_UD_V2_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_UD_V2_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_UD_V2_STATUS_LAST CQ_RES_UD_V2_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_UD_V2_FLAGS_SRQ 0x1UL + #define CQ_RES_UD_V2_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_UD_V2_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_UD_V2_FLAGS_SRQ_LAST CQ_RES_UD_V2_FLAGS_SRQ_SRQ + #define CQ_RES_UD_V2_FLAGS_IMM 0x2UL + #define CQ_RES_UD_V2_FLAGS_UNUSED_MASK 0xcUL + #define CQ_RES_UD_V2_FLAGS_UNUSED_SFT 2 + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_MASK 0x30UL + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_SFT 4 + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_V1 (0x0UL << 4) + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_V2IPV4 (0x2UL << 4) + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_V2IPV6 (0x3UL << 4) + #define CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_LAST CQ_RES_UD_V2_FLAGS_ROCE_IP_VER_V2IPV6 + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_MASK 0x3c0UL + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_SFT 6 + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_NONE (0x0UL << 6) + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_ACT_REC_PTR (0x1UL << 6) + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_TUNNEL_ID (0x2UL << 6) + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_CHDR_DATA (0x3UL << 6) + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_HDR_OFFSET (0x4UL << 6) + #define CQ_RES_UD_V2_FLAGS_META_FORMAT_LAST CQ_RES_UD_V2_FLAGS_META_FORMAT_HDR_OFFSET + __le32 src_qp_high_srq_or_rq_wr_id; + #define CQ_RES_UD_V2_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_UD_V2_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_UD_V2_CFA_METADATA1_MASK 0xf00000UL + #define CQ_RES_UD_V2_CFA_METADATA1_SFT 20 + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_MASK 0x700000UL + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_SFT 20 + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPID88A8 (0x0UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPID8100 (0x1UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPID9100 (0x2UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPID9200 (0x3UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPID9300 (0x4UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPIDCFG (0x5UL << 20) + #define CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_LAST CQ_RES_UD_V2_CFA_METADATA1_TPID_SEL_TPIDCFG + #define CQ_RES_UD_V2_CFA_METADATA1_VALID 0x800000UL + #define CQ_RES_UD_V2_SRC_QP_HIGH_MASK 0xff000000UL + #define CQ_RES_UD_V2_SRC_QP_HIGH_SFT 24 +}; + +/* cq_res_ud_cfa (size:256b/32B) */ +struct cq_res_ud_cfa { + __le16 length; + #define CQ_RES_UD_CFA_LENGTH_MASK 0x3fffUL + #define CQ_RES_UD_CFA_LENGTH_SFT 0 + __le16 cfa_code; + __le32 imm_data; + __le32 qid; + #define CQ_RES_UD_CFA_QID_MASK 0xfffffUL + #define CQ_RES_UD_CFA_QID_SFT 0 + __le32 cfa_metadata; + #define CQ_RES_UD_CFA_CFA_METADATA_VID_MASK 0xfffUL + #define CQ_RES_UD_CFA_CFA_METADATA_VID_SFT 0 + #define CQ_RES_UD_CFA_CFA_METADATA_DE 0x1000UL + #define CQ_RES_UD_CFA_CFA_METADATA_PRI_MASK 0xe000UL + #define CQ_RES_UD_CFA_CFA_METADATA_PRI_SFT 13 + #define CQ_RES_UD_CFA_CFA_METADATA_TPID_MASK 0xffff0000UL + #define CQ_RES_UD_CFA_CFA_METADATA_TPID_SFT 16 + __le16 src_mac[3]; + __le16 src_qp_low; + u8 cqe_type_toggle; + #define CQ_RES_UD_CFA_TOGGLE 0x1UL + #define CQ_RES_UD_CFA_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_UD_CFA_CQE_TYPE_SFT 1 + #define CQ_RES_UD_CFA_CQE_TYPE_RES_UD_CFA (0x4UL << 1) + #define CQ_RES_UD_CFA_CQE_TYPE_LAST CQ_RES_UD_CFA_CQE_TYPE_RES_UD_CFA + u8 status; + #define CQ_RES_UD_CFA_STATUS_OK 0x0UL + #define CQ_RES_UD_CFA_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_UD_CFA_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_UD_CFA_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_UD_CFA_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_UD_CFA_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_UD_CFA_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_UD_CFA_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_UD_CFA_STATUS_LAST CQ_RES_UD_CFA_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_UD_CFA_FLAGS_SRQ 0x1UL + #define CQ_RES_UD_CFA_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_UD_CFA_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_UD_CFA_FLAGS_SRQ_LAST CQ_RES_UD_CFA_FLAGS_SRQ_SRQ + #define CQ_RES_UD_CFA_FLAGS_IMM 0x2UL + #define CQ_RES_UD_CFA_FLAGS_UNUSED_MASK 0xcUL + #define CQ_RES_UD_CFA_FLAGS_UNUSED_SFT 2 + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_MASK 0x30UL + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_SFT 4 + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_V1 (0x0UL << 4) + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_V2IPV4 (0x2UL << 4) + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_V2IPV6 (0x3UL << 4) + #define CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_LAST CQ_RES_UD_CFA_FLAGS_ROCE_IP_VER_V2IPV6 + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_MASK 0x3c0UL + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_SFT 6 + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_NONE (0x0UL << 6) + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_VLAN (0x1UL << 6) + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_TUNNEL_ID (0x2UL << 6) + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_CHDR_DATA (0x3UL << 6) + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_HDR_OFFSET (0x4UL << 6) + #define CQ_RES_UD_CFA_FLAGS_META_FORMAT_LAST CQ_RES_UD_CFA_FLAGS_META_FORMAT_HDR_OFFSET + #define CQ_RES_UD_CFA_FLAGS_EXT_META_FORMAT_MASK 0xc00UL + #define CQ_RES_UD_CFA_FLAGS_EXT_META_FORMAT_SFT 10 + __le32 src_qp_high_srq_or_rq_wr_id; + #define CQ_RES_UD_CFA_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_UD_CFA_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_UD_CFA_SRC_QP_HIGH_MASK 0xff000000UL + #define CQ_RES_UD_CFA_SRC_QP_HIGH_SFT 24 +}; + +/* cq_res_ud_cfa_v2 (size:256b/32B) */ +struct cq_res_ud_cfa_v2 { + __le16 length; + #define CQ_RES_UD_CFA_V2_LENGTH_MASK 0x3fffUL + #define CQ_RES_UD_CFA_V2_LENGTH_SFT 0 + __le16 cfa_metadata0; + #define CQ_RES_UD_CFA_V2_CFA_METADATA0_VID_MASK 0xfffUL + #define CQ_RES_UD_CFA_V2_CFA_METADATA0_VID_SFT 0 + #define CQ_RES_UD_CFA_V2_CFA_METADATA0_DE 0x1000UL + #define CQ_RES_UD_CFA_V2_CFA_METADATA0_PRI_MASK 0xe000UL + #define CQ_RES_UD_CFA_V2_CFA_METADATA0_PRI_SFT 13 + __le32 imm_data; + __le32 qid; + #define CQ_RES_UD_CFA_V2_QID_MASK 0xfffffUL + #define CQ_RES_UD_CFA_V2_QID_SFT 0 + __le32 cfa_metadata2; + __le16 src_mac[3]; + __le16 src_qp_low; + u8 cqe_type_toggle; + #define CQ_RES_UD_CFA_V2_TOGGLE 0x1UL + #define CQ_RES_UD_CFA_V2_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_UD_CFA_V2_CQE_TYPE_SFT 1 + #define CQ_RES_UD_CFA_V2_CQE_TYPE_RES_UD_CFA (0x4UL << 1) + #define CQ_RES_UD_CFA_V2_CQE_TYPE_LAST CQ_RES_UD_CFA_V2_CQE_TYPE_RES_UD_CFA + u8 status; + #define CQ_RES_UD_CFA_V2_STATUS_OK 0x0UL + #define CQ_RES_UD_CFA_V2_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_UD_CFA_V2_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_UD_CFA_V2_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_UD_CFA_V2_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_UD_CFA_V2_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_UD_CFA_V2_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_UD_CFA_V2_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_UD_CFA_V2_STATUS_LAST CQ_RES_UD_CFA_V2_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_UD_CFA_V2_FLAGS_SRQ 0x1UL + #define CQ_RES_UD_CFA_V2_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_UD_CFA_V2_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_UD_CFA_V2_FLAGS_SRQ_LAST CQ_RES_UD_CFA_V2_FLAGS_SRQ_SRQ + #define CQ_RES_UD_CFA_V2_FLAGS_IMM 0x2UL + #define CQ_RES_UD_CFA_V2_FLAGS_UNUSED_MASK 0xcUL + #define CQ_RES_UD_CFA_V2_FLAGS_UNUSED_SFT 2 + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_MASK 0x30UL + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_SFT 4 + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_V1 (0x0UL << 4) + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_V2IPV4 (0x2UL << 4) + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_V2IPV6 (0x3UL << 4) + #define CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_LAST CQ_RES_UD_CFA_V2_FLAGS_ROCE_IP_VER_V2IPV6 + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_MASK 0x3c0UL + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_SFT 6 + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_NONE (0x0UL << 6) + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_ACT_REC_PTR (0x1UL << 6) + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_TUNNEL_ID (0x2UL << 6) + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_CHDR_DATA (0x3UL << 6) + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_HDR_OFFSET (0x4UL << 6) + #define CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_LAST \ + CQ_RES_UD_CFA_V2_FLAGS_META_FORMAT_HDR_OFFSET + __le32 src_qp_high_srq_or_rq_wr_id; + #define CQ_RES_UD_CFA_V2_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_UD_CFA_V2_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_MASK 0xf00000UL + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_SFT 20 + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_MASK 0x700000UL + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_SFT 20 + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPID88A8 (0x0UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPID8100 (0x1UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPID9100 (0x2UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPID9200 (0x3UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPID9300 (0x4UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPIDCFG (0x5UL << 20) + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_LAST \ + CQ_RES_UD_CFA_V2_CFA_METADATA1_TPID_SEL_TPIDCFG + #define CQ_RES_UD_CFA_V2_CFA_METADATA1_VALID 0x800000UL + #define CQ_RES_UD_CFA_V2_SRC_QP_HIGH_MASK 0xff000000UL + #define CQ_RES_UD_CFA_V2_SRC_QP_HIGH_SFT 24 +}; + +/* cq_res_raweth_qp1 (size:256b/32B) */ +struct cq_res_raweth_qp1 { + __le16 length; + #define CQ_RES_RAWETH_QP1_LENGTH_MASK 0x3fffUL + #define CQ_RES_RAWETH_QP1_LENGTH_SFT 0 + __le16 raweth_qp1_flags; + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_MASK 0x3ffUL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_SFT 0 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ERROR 0x1UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_MASK 0x3c0UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_SFT 6 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_NOT_KNOWN (0x0UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_IP (0x1UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_TCP (0x2UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_UDP (0x3UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_FCOE (0x4UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_ROCE (0x5UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_ICMP (0x7UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_WO_TIMESTAMP (0x8UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP (0x9UL << 6) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_LAST \ + CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP + __le16 raweth_qp1_errors; + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_IP_CS_ERROR 0x10UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_L4_CS_ERROR 0x20UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_IP_CS_ERROR 0x40UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_L4_CS_ERROR 0x80UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_CRC_ERROR 0x100UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_MASK 0xe00UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_SFT 9 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_NO_ERROR (0x0UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION (0x1UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN (0x2UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_TUNNEL_TOTAL_ERROR (0x3UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR (0x4UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR (0x5UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL (0x6UL << 9) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_LAST \ + CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_MASK 0xf000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_SFT 12 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_NO_ERROR (0x0UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_VERSION (0x1UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN (0x2UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_TTL (0x3UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_IP_TOTAL_ERROR (0x4UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR (0x5UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN (0x6UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL (0x7UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN (0x8UL << 12) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_LAST \ + CQ_RES_RAWETH_QP1_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN + __le16 raweth_qp1_cfa_code; + __le64 qp_handle; + __le32 raweth_qp1_flags2; + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_IP_CS_CALC 0x1UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_L4_CS_CALC 0x2UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_T_IP_CS_CALC 0x4UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_T_L4_CS_CALC 0x8UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_MASK 0xf0UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_SFT 4 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_NONE (0x0UL << 4) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_VLAN (0x1UL << 4) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_TUNNEL_ID (0x2UL << 4) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_CHDR_DATA (0x3UL << 4) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_HDR_OFFSET (0x4UL << 4) + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_LAST \ + CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_META_FORMAT_HDR_OFFSET + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_IP_TYPE 0x100UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_CALC 0x200UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_EXT_META_FORMAT_MASK 0xc00UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_EXT_META_FORMAT_SFT 10 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_MASK 0xffff0000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_SFT 16 + __le32 raweth_qp1_metadata; + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_DE_VID_MASK 0xffffUL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_DE_VID_SFT 0 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_VID_MASK 0xfffUL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_VID_SFT 0 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_DE 0x1000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_MASK 0xe000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_PRI_SFT 13 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_TPID_MASK 0xffff0000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_METADATA_TPID_SFT 16 + u8 cqe_type_toggle; + #define CQ_RES_RAWETH_QP1_TOGGLE 0x1UL + #define CQ_RES_RAWETH_QP1_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_RAWETH_QP1_CQE_TYPE_SFT 1 + #define CQ_RES_RAWETH_QP1_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) + #define CQ_RES_RAWETH_QP1_CQE_TYPE_LAST CQ_RES_RAWETH_QP1_CQE_TYPE_RES_RAWETH_QP1 + u8 status; + #define CQ_RES_RAWETH_QP1_STATUS_OK 0x0UL + #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_RAWETH_QP1_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_RAWETH_QP1_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_RAWETH_QP1_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_RAWETH_QP1_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_RAWETH_QP1_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_RAWETH_QP1_STATUS_LAST CQ_RES_RAWETH_QP1_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_RAWETH_QP1_FLAGS_SRQ 0x1UL + #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_RAWETH_QP1_FLAGS_SRQ_LAST CQ_RES_RAWETH_QP1_FLAGS_SRQ_SRQ + __le32 raweth_qp1_payload_offset_srq_or_rq_wr_id; + #define CQ_RES_RAWETH_QP1_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_RAWETH_QP1_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_PAYLOAD_OFFSET_MASK 0xff000000UL + #define CQ_RES_RAWETH_QP1_RAWETH_QP1_PAYLOAD_OFFSET_SFT 24 +}; + +/* cq_res_raweth_qp1_v2 (size:256b/32B) */ +struct cq_res_raweth_qp1_v2 { + __le16 length; + #define CQ_RES_RAWETH_QP1_V2_LENGTH_MASK 0x3fffUL + #define CQ_RES_RAWETH_QP1_V2_LENGTH_SFT 0 + __le16 raweth_qp1_flags; + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_MASK 0x3ffUL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_SFT 0 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ERROR 0x1UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_MASK 0x3c0UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_SFT 6 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_NOT_KNOWN (0x0UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_IP (0x1UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_TCP (0x2UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_UDP (0x3UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_FCOE (0x4UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_ROCE (0x5UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_ICMP (0x7UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_PTP_WO_TIMESTAMP (0x8UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP (0x9UL << 6) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_LAST \ + CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS_ITYPE_PTP_W_TIMESTAMP + __le16 raweth_qp1_errors; + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_IP_CS_ERROR 0x10UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_L4_CS_ERROR 0x20UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_IP_CS_ERROR 0x40UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_L4_CS_ERROR 0x80UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_CRC_ERROR 0x100UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_MASK 0xe00UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_SFT 9 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_NO_ERROR (0x0UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION (0x1UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN (0x2UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_TUNNEL_TOTAL_ERROR (0x3UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR (0x4UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR (0x5UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL (0x6UL << 9) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_LAST \ + CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_MASK 0xf000UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_SFT 12 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_NO_ERROR (0x0UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_VERSION (0x1UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN (0x2UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L3_BAD_TTL (0x3UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_IP_TOTAL_ERROR (0x4UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR (0x5UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN (0x6UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL \ + (0x7UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN \ + (0x8UL << 12) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_LAST \ + CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN + __le16 cfa_metadata0; + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA0_VID_MASK 0xfffUL + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA0_VID_SFT 0 + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA0_DE 0x1000UL + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA0_PRI_MASK 0xe000UL + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA0_PRI_SFT 13 + __le64 qp_handle; + __le32 raweth_qp1_flags2; + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_CS_ALL_OK_MODE 0x8UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_MASK 0xf0UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_SFT 4 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_NONE (0x0UL << 4) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_ACT_REC_PTR (0x1UL << 4) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_TUNNEL_ID (0x2UL << 4) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_CHDR_DATA (0x3UL << 4) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_HDR_OFFSET (0x4UL << 4) + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_LAST \ + CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_META_FORMAT_HDR_OFFSET + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_IP_TYPE 0x100UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_CALC 0x200UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_CS_OK_MASK 0xfc00UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_CS_OK_SFT 10 + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_MASK 0xffff0000UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_FLAGS2_COMPLETE_CHECKSUM_SFT 16 + __le32 cfa_metadata2; + u8 cqe_type_toggle; + #define CQ_RES_RAWETH_QP1_V2_TOGGLE 0x1UL + #define CQ_RES_RAWETH_QP1_V2_CQE_TYPE_MASK 0x1eUL + #define CQ_RES_RAWETH_QP1_V2_CQE_TYPE_SFT 1 + #define CQ_RES_RAWETH_QP1_V2_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1) + #define CQ_RES_RAWETH_QP1_V2_CQE_TYPE_LAST CQ_RES_RAWETH_QP1_V2_CQE_TYPE_RES_RAWETH_QP1 + u8 status; + #define CQ_RES_RAWETH_QP1_V2_STATUS_OK 0x0UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_LOCAL_ACCESS_ERROR 0x1UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_HW_LOCAL_LENGTH_ERR 0x2UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_LOCAL_PROTECTION_ERR 0x3UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_MEMORY_MGT_OPERATION_ERR 0x5UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_WORK_REQUEST_FLUSHED_ERR 0x7UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_HW_FLUSH_ERR 0x8UL + #define CQ_RES_RAWETH_QP1_V2_STATUS_LAST CQ_RES_RAWETH_QP1_V2_STATUS_HW_FLUSH_ERR + __le16 flags; + #define CQ_RES_RAWETH_QP1_V2_FLAGS_SRQ 0x1UL + #define CQ_RES_RAWETH_QP1_V2_FLAGS_SRQ_RQ 0x0UL + #define CQ_RES_RAWETH_QP1_V2_FLAGS_SRQ_SRQ 0x1UL + #define CQ_RES_RAWETH_QP1_V2_FLAGS_SRQ_LAST CQ_RES_RAWETH_QP1_V2_FLAGS_SRQ_SRQ + __le32 raweth_qp1_payload_offset_srq_or_rq_wr_id; + #define CQ_RES_RAWETH_QP1_V2_SRQ_OR_RQ_WR_ID_MASK 0xfffffUL + #define CQ_RES_RAWETH_QP1_V2_SRQ_OR_RQ_WR_ID_SFT 0 + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_MASK 0xf00000UL + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_SFT 20 + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_MASK 0x700000UL + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_SFT 20 + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPID88A8 (0x0UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPID8100 (0x1UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPID9100 (0x2UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPID9200 (0x3UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPID9300 (0x4UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPIDCFG (0x5UL << 20) + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_LAST \ + CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_TPID_SEL_TPIDCFG + #define CQ_RES_RAWETH_QP1_V2_CFA_METADATA1_VALID 0x800000UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_PAYLOAD_OFFSET_MASK 0xff000000UL + #define CQ_RES_RAWETH_QP1_V2_RAWETH_QP1_PAYLOAD_OFFSET_SFT 24 +}; + +/* cq_terminal (size:256b/32B) */ +struct cq_terminal { + __le64 qp_handle; + __le16 sq_cons_idx; + __le16 rq_cons_idx; + __le32 reserved32_1; + __le64 reserved64_3; + u8 cqe_type_toggle; + #define CQ_TERMINAL_TOGGLE 0x1UL + #define CQ_TERMINAL_CQE_TYPE_MASK 0x1eUL + #define CQ_TERMINAL_CQE_TYPE_SFT 1 + #define CQ_TERMINAL_CQE_TYPE_TERMINAL (0xeUL << 1) + #define CQ_TERMINAL_CQE_TYPE_LAST CQ_TERMINAL_CQE_TYPE_TERMINAL + u8 status; + #define CQ_TERMINAL_STATUS_OK 0x0UL + #define CQ_TERMINAL_STATUS_LAST CQ_TERMINAL_STATUS_OK + __le16 reserved16; + __le32 reserved32_2; +}; + +/* cq_cutoff (size:256b/32B) */ +struct cq_cutoff { + __le64 reserved64_1; + __le64 reserved64_2; + __le64 reserved64_3; + u8 cqe_type_toggle; + #define CQ_CUTOFF_TOGGLE 0x1UL + #define CQ_CUTOFF_CQE_TYPE_MASK 0x1eUL + #define CQ_CUTOFF_CQE_TYPE_SFT 1 + #define CQ_CUTOFF_CQE_TYPE_CUT_OFF (0xfUL << 1) + #define CQ_CUTOFF_CQE_TYPE_LAST CQ_CUTOFF_CQE_TYPE_CUT_OFF + u8 status; + #define CQ_CUTOFF_STATUS_OK 0x0UL + #define CQ_CUTOFF_STATUS_LAST CQ_CUTOFF_STATUS_OK + __le16 reserved16; + __le32 reserved32; +}; + +/* nq_base (size:128b/16B) */ +struct nq_base { + __le16 info10_type; + #define NQ_BASE_TYPE_MASK 0x3fUL + #define NQ_BASE_TYPE_SFT 0 + #define NQ_BASE_TYPE_CQ_NOTIFICATION 0x30UL + #define NQ_BASE_TYPE_SRQ_EVENT 0x32UL + #define NQ_BASE_TYPE_DBQ_EVENT 0x34UL + #define NQ_BASE_TYPE_QP_EVENT 0x38UL + #define NQ_BASE_TYPE_FUNC_EVENT 0x3aUL + #define NQ_BASE_TYPE_LAST NQ_BASE_TYPE_FUNC_EVENT + #define NQ_BASE_INFO10_MASK 0xffc0UL + #define NQ_BASE_INFO10_SFT 6 + __le16 info16; + __le32 info32; + __le32 info63_v[2]; + #define NQ_BASE_V 0x1UL + #define NQ_BASE_INFO63_MASK 0xfffffffeUL + #define NQ_BASE_INFO63_SFT 1 +}; + +/* nq_cn (size:128b/16B) */ +struct nq_cn { + __le16 type; + #define NQ_CN_TYPE_MASK 0x3fUL + #define NQ_CN_TYPE_SFT 0 + #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL + #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION + #define NQ_CN_TOGGLE_MASK 0xc0UL + #define NQ_CN_TOGGLE_SFT 6 + __le16 reserved16; + __le32 cq_handle_low; + __le32 v; + #define NQ_CN_V 0x1UL + __le32 cq_handle_high; +}; + +/* nq_srq_event (size:128b/16B) */ +struct nq_srq_event { + u8 type; + #define NQ_SRQ_EVENT_TYPE_MASK 0x3fUL + #define NQ_SRQ_EVENT_TYPE_SFT 0 + #define NQ_SRQ_EVENT_TYPE_SRQ_EVENT 0x32UL + #define NQ_SRQ_EVENT_TYPE_LAST NQ_SRQ_EVENT_TYPE_SRQ_EVENT + u8 event; + #define NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT 0x1UL + #define NQ_SRQ_EVENT_EVENT_LAST NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT + __le16 reserved16; + __le32 srq_handle_low; + __le32 v; + #define NQ_SRQ_EVENT_V 0x1UL + __le32 srq_handle_high; +}; + +/* nq_dbq_event (size:128b/16B) */ +struct nq_dbq_event { + u8 type; + #define NQ_DBQ_EVENT_TYPE_MASK 0x3fUL + #define NQ_DBQ_EVENT_TYPE_SFT 0 + #define NQ_DBQ_EVENT_TYPE_DBQ_EVENT 0x34UL + #define NQ_DBQ_EVENT_TYPE_LAST NQ_DBQ_EVENT_TYPE_DBQ_EVENT + u8 event; + #define NQ_DBQ_EVENT_EVENT_DBQ_THRESHOLD_EVENT 0x1UL + #define NQ_DBQ_EVENT_EVENT_LAST NQ_DBQ_EVENT_EVENT_DBQ_THRESHOLD_EVENT + __le16 db_pfid; + #define NQ_DBQ_EVENT_DB_PFID_MASK 0xfUL + #define NQ_DBQ_EVENT_DB_PFID_SFT 0 + __le32 db_dpi; + #define NQ_DBQ_EVENT_DB_DPI_MASK 0xfffffUL + #define NQ_DBQ_EVENT_DB_DPI_SFT 0 + __le32 v; + #define NQ_DBQ_EVENT_V 0x1UL + __le32 db_type_db_xid; + #define NQ_DBQ_EVENT_DB_XID_MASK 0xfffffUL + #define NQ_DBQ_EVENT_DB_XID_SFT 0 + #define NQ_DBQ_EVENT_DB_TYPE_MASK 0xf0000000UL + #define NQ_DBQ_EVENT_DB_TYPE_SFT 28 +}; + +/* xrrq_irrq (size:256b/32B) */ +struct xrrq_irrq { + __le16 credits_type; + #define XRRQ_IRRQ_TYPE 0x1UL + #define XRRQ_IRRQ_TYPE_READ_REQ 0x0UL + #define XRRQ_IRRQ_TYPE_ATOMIC_REQ 0x1UL + #define XRRQ_IRRQ_TYPE_LAST XRRQ_IRRQ_TYPE_ATOMIC_REQ + #define XRRQ_IRRQ_CREDITS_MASK 0xf800UL + #define XRRQ_IRRQ_CREDITS_SFT 11 + __le16 reserved16; + __le32 reserved32; + __le32 psn; + #define XRRQ_IRRQ_PSN_MASK 0xffffffUL + #define XRRQ_IRRQ_PSN_SFT 0 + __le32 msn; + #define XRRQ_IRRQ_MSN_MASK 0xffffffUL + #define XRRQ_IRRQ_MSN_SFT 0 + __le64 va_or_atomic_result; + __le32 rdma_r_key; + __le32 length; +}; + +/* xrrq_orrq (size:256b/32B) */ +struct xrrq_orrq { + __le16 num_sges_type; + #define XRRQ_ORRQ_TYPE 0x1UL + #define XRRQ_ORRQ_TYPE_READ_REQ 0x0UL + #define XRRQ_ORRQ_TYPE_ATOMIC_REQ 0x1UL + #define XRRQ_ORRQ_TYPE_LAST XRRQ_ORRQ_TYPE_ATOMIC_REQ + #define XRRQ_ORRQ_NUM_SGES_MASK 0xf800UL + #define XRRQ_ORRQ_NUM_SGES_SFT 11 + __le16 reserved16; + __le32 length; + __le32 psn; + #define XRRQ_ORRQ_PSN_MASK 0xffffffUL + #define XRRQ_ORRQ_PSN_SFT 0 + __le32 end_psn; + #define XRRQ_ORRQ_END_PSN_MASK 0xffffffUL + #define XRRQ_ORRQ_END_PSN_SFT 0 + __le64 first_sge_phy_or_sing_sge_va; + __le32 single_sge_l_key; + __le32 single_sge_size; +}; + +/* ptu_pte (size:64b/8B) */ +struct ptu_pte { + __le32 page_next_to_last_last_valid[2]; + #define PTU_PTE_VALID 0x1UL + #define PTU_PTE_LAST 0x2UL + #define PTU_PTE_NEXT_TO_LAST 0x4UL + #define PTU_PTE_UNUSED_MASK 0xff8UL + #define PTU_PTE_UNUSED_SFT 3 + #define PTU_PTE_PAGE_MASK 0xfffff000UL + #define PTU_PTE_PAGE_SFT 12 +}; + +/* ptu_pde (size:64b/8B) */ +struct ptu_pde { + __le32 page_valid[2]; + #define PTU_PDE_VALID 0x1UL + #define PTU_PDE_UNUSED_MASK 0xffeUL + #define PTU_PDE_UNUSED_SFT 1 + #define PTU_PDE_PAGE_MASK 0xfffff000UL + #define PTU_PDE_PAGE_SFT 12 +}; + +#endif /* ___BNXT_RE_HSI_H__ */ diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h index d4b9226088bd..4e93ef7f84ee 100644 --- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* - * Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_ADMIN_CMDS_H_ @@ -376,7 +376,9 @@ struct efa_admin_reg_mr_cmd { * 0 : local_write_enable - Local write permissions: * must be set for RQ buffers and buffers posted for * RDMA Read requests - * 1 : reserved1 - MBZ + * 1 : remote_write_enable - Remote write + * permissions: must be set to enable RDMA write to + * the region * 2 : remote_read_enable - Remote read permissions: * must be set to enable RDMA read from the region * 7:3 : reserved2 - MBZ @@ -618,7 +620,11 @@ struct efa_admin_feature_device_attr_desc { * TX queues * 1 : rnr_retry - If set, RNR retry is supported on * modify QP command - * 31:2 : reserved - MBZ + * 2 : data_polling_128 - If set, 128 bytes data + * polling is supported + * 3 : rdma_write - If set, RDMA Write is supported + * on TX queues + * 31:4 : reserved - MBZ */ u32 device_caps; @@ -672,7 +678,7 @@ struct efa_admin_feature_queue_attr_desc { /* The maximum size of LLQ in bytes */ u32 max_llq_size; - /* Maximum number of SGEs for a single RDMA read WQE */ + /* Maximum number of SGEs for a single RDMA read/write WQE */ u16 max_wr_rdma_sges; /* @@ -977,6 +983,7 @@ struct efa_admin_host_info { #define EFA_ADMIN_REG_MR_CMD_PHYS_PAGE_SIZE_SHIFT_MASK GENMASK(4, 0) #define EFA_ADMIN_REG_MR_CMD_MEM_ADDR_PHY_MODE_EN_MASK BIT(7) #define EFA_ADMIN_REG_MR_CMD_LOCAL_WRITE_ENABLE_MASK BIT(0) +#define EFA_ADMIN_REG_MR_CMD_REMOTE_WRITE_ENABLE_MASK BIT(1) #define EFA_ADMIN_REG_MR_CMD_REMOTE_READ_ENABLE_MASK BIT(2) /* create_cq_cmd */ @@ -991,6 +998,8 @@ struct efa_admin_host_info { /* feature_device_attr_desc */ #define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_RDMA_READ_MASK BIT(0) #define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_RNR_RETRY_MASK BIT(1) +#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_DATA_POLLING_128_MASK BIT(2) +#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_RDMA_WRITE_MASK BIT(3) /* create_eq_cmd */ #define EFA_ADMIN_CREATE_EQ_CMD_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0) diff --git a/drivers/infiniband/hw/efa/efa_io_defs.h b/drivers/infiniband/hw/efa/efa_io_defs.h index 17ba8984b11e..2d8eb96eaa81 100644 --- a/drivers/infiniband/hw/efa/efa_io_defs.h +++ b/drivers/infiniband/hw/efa/efa_io_defs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* - * Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_IO_H_ @@ -23,6 +23,8 @@ enum efa_io_send_op_type { EFA_IO_SEND = 0, /* RDMA read */ EFA_IO_RDMA_READ = 1, + /* RDMA write */ + EFA_IO_RDMA_WRITE = 2, }; enum efa_io_comp_status { @@ -62,8 +64,7 @@ struct efa_io_tx_meta_desc { /* * control flags - * 3:0 : op_type - operation type: send/rdma/fast mem - * ops/etc + * 3:0 : op_type - enum efa_io_send_op_type * 4 : has_imm - immediate_data field carries valid * data. * 5 : inline_msg - inline mode - inline message data @@ -219,21 +220,22 @@ struct efa_io_cdesc_common { * 2:1 : q_type - enum efa_io_queue_type: send/recv * 3 : has_imm - indicates that immediate data is * present - for RX completions only - * 7:4 : reserved28 - MBZ + * 6:4 : op_type - enum efa_io_send_op_type + * 7 : reserved31 - MBZ */ u8 flags; /* local QP number */ u16 qp_num; - - /* Transferred length */ - u16 length; }; /* Tx completion descriptor */ struct efa_io_tx_cdesc { /* Common completion info */ struct efa_io_cdesc_common common; + + /* MBZ */ + u16 reserved16; }; /* Rx Completion Descriptor */ @@ -241,6 +243,9 @@ struct efa_io_rx_cdesc { /* Common completion info */ struct efa_io_cdesc_common common; + /* Transferred length bits[15:0] */ + u16 length; + /* Remote Address Handle FW index, 0xFFFF indicates invalid ah */ u16 ah; @@ -250,16 +255,26 @@ struct efa_io_rx_cdesc { u32 imm; }; +/* Rx Completion Descriptor RDMA write info */ +struct efa_io_rx_cdesc_rdma_write { + /* Transferred length bits[31:16] */ + u16 length_hi; +}; + /* Extended Rx Completion Descriptor */ struct efa_io_rx_cdesc_ex { /* Base RX completion info */ - struct efa_io_rx_cdesc rx_cdesc_base; + struct efa_io_rx_cdesc base; - /* - * Valid only in case of unknown AH (0xFFFF) and CQ set_src_addr is - * enabled. - */ - u8 src_addr[16]; + union { + struct efa_io_rx_cdesc_rdma_write rdma_write; + + /* + * Valid only in case of unknown AH (0xFFFF) and CQ + * set_src_addr is enabled. + */ + u8 src_addr[16]; + } u; }; /* tx_meta_desc */ @@ -285,5 +300,6 @@ struct efa_io_rx_cdesc_ex { #define EFA_IO_CDESC_COMMON_PHASE_MASK BIT(0) #define EFA_IO_CDESC_COMMON_Q_TYPE_MASK GENMASK(2, 1) #define EFA_IO_CDESC_COMMON_HAS_IMM_MASK BIT(3) +#define EFA_IO_CDESC_COMMON_OP_TYPE_MASK GENMASK(6, 4) #endif /* _EFA_IO_H_ */ diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 31454643f8c5..2a195c4b0f17 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* - * Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved. */ #include @@ -250,6 +250,12 @@ int efa_query_device(struct ib_device *ibdev, if (EFA_DEV_CAP(dev, RNR_RETRY)) resp.device_caps |= EFA_QUERY_DEVICE_CAPS_RNR_RETRY; + if (EFA_DEV_CAP(dev, DATA_POLLING_128)) + resp.device_caps |= EFA_QUERY_DEVICE_CAPS_DATA_POLLING_128; + + if (EFA_DEV_CAP(dev, RDMA_WRITE)) + resp.device_caps |= EFA_QUERY_DEVICE_CAPS_RDMA_WRITE; + if (dev->neqs) resp.device_caps |= EFA_QUERY_DEVICE_CAPS_CQ_NOTIFICATIONS; @@ -1397,7 +1403,7 @@ static int pbl_continuous_initialize(struct efa_dev *dev, */ static int pbl_indirect_initialize(struct efa_dev *dev, struct pbl_context *pbl) { - u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, PAGE_SIZE); + u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, EFA_CHUNK_PAYLOAD_SIZE); struct scatterlist *sgl; int sg_dma_cnt, err; @@ -1569,7 +1575,8 @@ static struct efa_mr *efa_alloc_mr(struct ib_pd *ibpd, int access_flags, supp_access_flags = IB_ACCESS_LOCAL_WRITE | - (EFA_DEV_CAP(dev, RDMA_READ) ? IB_ACCESS_REMOTE_READ : 0); + (EFA_DEV_CAP(dev, RDMA_READ) ? IB_ACCESS_REMOTE_READ : 0) | + (EFA_DEV_CAP(dev, RDMA_WRITE) ? IB_ACCESS_REMOTE_WRITE : 0); access_flags &= ~IB_ACCESS_OPTIONAL; if (access_flags & ~supp_access_flags) { diff --git a/drivers/infiniband/hw/erdma/erdma.h b/drivers/infiniband/hw/erdma/erdma.h index 3d8c11aa23a2..e819e4032490 100644 --- a/drivers/infiniband/hw/erdma/erdma.h +++ b/drivers/infiniband/hw/erdma/erdma.h @@ -32,7 +32,7 @@ struct erdma_eq { atomic64_t event_num; atomic64_t notify_num; - u64 __iomem *db_addr; + void __iomem *db; u64 *db_record; }; diff --git a/drivers/infiniband/hw/erdma/erdma_cm.h b/drivers/infiniband/hw/erdma/erdma_cm.h index 8a3f998fec9b..a26d80770188 100644 --- a/drivers/infiniband/hw/erdma/erdma_cm.h +++ b/drivers/infiniband/hw/erdma/erdma_cm.h @@ -33,11 +33,11 @@ struct mpa_rr_params { * MPA request/response Hdr bits & fields */ enum { - MPA_RR_FLAG_MARKERS = __cpu_to_be16(0x8000), - MPA_RR_FLAG_CRC = __cpu_to_be16(0x4000), - MPA_RR_FLAG_REJECT = __cpu_to_be16(0x2000), - MPA_RR_RESERVED = __cpu_to_be16(0x1f00), - MPA_RR_MASK_REVISION = __cpu_to_be16(0x00ff) + MPA_RR_FLAG_MARKERS = cpu_to_be16(0x8000), + MPA_RR_FLAG_CRC = cpu_to_be16(0x4000), + MPA_RR_FLAG_REJECT = cpu_to_be16(0x2000), + MPA_RR_RESERVED = cpu_to_be16(0x1f00), + MPA_RR_MASK_REVISION = cpu_to_be16(0x00ff) }; /* diff --git a/drivers/infiniband/hw/erdma/erdma_cmdq.c b/drivers/infiniband/hw/erdma/erdma_cmdq.c index 6ebfa6989b11..a151a7bdd504 100644 --- a/drivers/infiniband/hw/erdma/erdma_cmdq.c +++ b/drivers/infiniband/hw/erdma/erdma_cmdq.c @@ -166,8 +166,7 @@ static int erdma_cmdq_eq_init(struct erdma_dev *dev) spin_lock_init(&eq->lock); atomic64_set(&eq->event_num, 0); - eq->db_addr = - (u64 __iomem *)(dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG); + eq->db = dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG; eq->db_record = (u64 *)(eq->qbuf + buf_size); erdma_reg_write32(dev, ERDMA_REGS_CMDQ_EQ_ADDR_H_REG, @@ -183,9 +182,8 @@ static int erdma_cmdq_eq_init(struct erdma_dev *dev) int erdma_cmdq_init(struct erdma_dev *dev) { - int err, i; struct erdma_cmdq *cmdq = &dev->cmdq; - u32 sts, ctrl; + int err; cmdq->max_outstandings = ERDMA_CMDQ_MAX_OUTSTANDING; cmdq->use_event = false; @@ -208,34 +206,10 @@ int erdma_cmdq_init(struct erdma_dev *dev) if (err) goto err_destroy_cq; - ctrl = FIELD_PREP(ERDMA_REG_DEV_CTRL_INIT_MASK, 1); - erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, ctrl); - - for (i = 0; i < ERDMA_WAIT_DEV_DONE_CNT; i++) { - sts = erdma_reg_read32_filed(dev, ERDMA_REGS_DEV_ST_REG, - ERDMA_REG_DEV_ST_INIT_DONE_MASK); - if (sts) - break; - - msleep(ERDMA_REG_ACCESS_WAIT_MS); - } - - if (i == ERDMA_WAIT_DEV_DONE_CNT) { - dev_err(&dev->pdev->dev, "wait init done failed.\n"); - err = -ETIMEDOUT; - goto err_destroy_eq; - } - set_bit(ERDMA_CMDQ_STATE_OK_BIT, &cmdq->state); return 0; -err_destroy_eq: - dma_free_coherent(&dev->pdev->dev, - (cmdq->eq.depth << EQE_SHIFT) + - ERDMA_EXTRA_BUFFER_SIZE, - cmdq->eq.qbuf, cmdq->eq.qbuf_dma_addr); - err_destroy_cq: dma_free_coherent(&dev->pdev->dev, (cmdq->cq.depth << CQE_SHIFT) + @@ -283,7 +257,7 @@ static void *get_next_valid_cmdq_cqe(struct erdma_cmdq *cmdq) __be32 *cqe = get_queue_entry(cmdq->cq.qbuf, cmdq->cq.ci, cmdq->cq.depth, CQE_SHIFT); u32 owner = FIELD_GET(ERDMA_CQE_HDR_OWNER_MASK, - __be32_to_cpu(READ_ONCE(*cqe))); + be32_to_cpu(READ_ONCE(*cqe))); return owner ^ !!(cmdq->cq.ci & cmdq->cq.depth) ? cqe : NULL; } @@ -319,7 +293,6 @@ static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq) __be32 *cqe; u16 ctx_id; u64 *sqe; - int i; cqe = get_next_valid_cmdq_cqe(cmdq); if (!cqe) @@ -328,8 +301,8 @@ static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq) cmdq->cq.ci++; dma_rmb(); - hdr0 = __be32_to_cpu(*cqe); - sqe_idx = __be32_to_cpu(*(cqe + 1)); + hdr0 = be32_to_cpu(*cqe); + sqe_idx = be32_to_cpu(*(cqe + 1)); sqe = get_queue_entry(cmdq->sq.qbuf, sqe_idx, cmdq->sq.depth, SQEBB_SHIFT); @@ -341,9 +314,8 @@ static int erdma_poll_single_cmd_completion(struct erdma_cmdq *cmdq) comp_wait->cmd_status = ERDMA_CMD_STATUS_FINISHED; comp_wait->comp_status = FIELD_GET(ERDMA_CQE_HDR_SYNDROME_MASK, hdr0); cmdq->sq.ci += cmdq->sq.wqebb_cnt; - - for (i = 0; i < 4; i++) - comp_wait->comp_data[i] = __be32_to_cpu(*(cqe + 2 + i)); + /* Copy 16B comp data after cqe hdr to outer */ + be32_to_cpu_array(comp_wait->comp_data, cqe + 2, 4); if (cmdq->use_event) complete(&comp_wait->wait_event); diff --git a/drivers/infiniband/hw/erdma/erdma_cq.c b/drivers/infiniband/hw/erdma/erdma_cq.c index 7bc354273d4e..c1cb5568eab2 100644 --- a/drivers/infiniband/hw/erdma/erdma_cq.c +++ b/drivers/infiniband/hw/erdma/erdma_cq.c @@ -11,7 +11,7 @@ static void *get_next_valid_cqe(struct erdma_cq *cq) __be32 *cqe = get_queue_entry(cq->kern_cq.qbuf, cq->kern_cq.ci, cq->depth, CQE_SHIFT); u32 owner = FIELD_GET(ERDMA_CQE_HDR_OWNER_MASK, - __be32_to_cpu(READ_ONCE(*cqe))); + be32_to_cpu(READ_ONCE(*cqe))); return owner ^ !!(cq->kern_cq.ci & cq->depth) ? cqe : NULL; } diff --git a/drivers/infiniband/hw/erdma/erdma_eq.c b/drivers/infiniband/hw/erdma/erdma_eq.c index ed54130d924b..ea47cb21fdb8 100644 --- a/drivers/infiniband/hw/erdma/erdma_eq.c +++ b/drivers/infiniband/hw/erdma/erdma_eq.c @@ -14,7 +14,7 @@ void notify_eq(struct erdma_eq *eq) FIELD_PREP(ERDMA_EQDB_ARM_MASK, 1); *eq->db_record = db_data; - writeq(db_data, eq->db_addr); + writeq(db_data, eq->db); atomic64_inc(&eq->notify_num); } @@ -98,7 +98,7 @@ int erdma_aeq_init(struct erdma_dev *dev) atomic64_set(&eq->event_num, 0); atomic64_set(&eq->notify_num, 0); - eq->db_addr = (u64 __iomem *)(dev->func_bar + ERDMA_REGS_AEQ_DB_REG); + eq->db = dev->func_bar + ERDMA_REGS_AEQ_DB_REG; eq->db_record = (u64 *)(eq->qbuf + buf_size); erdma_reg_write32(dev, ERDMA_REGS_AEQ_ADDR_H_REG, @@ -243,9 +243,8 @@ static int erdma_ceq_init_one(struct erdma_dev *dev, u16 ceqn) atomic64_set(&eq->notify_num, 0); eq->depth = ERDMA_DEFAULT_EQ_DEPTH; - eq->db_addr = - (u64 __iomem *)(dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG + - (ceqn + 1) * ERDMA_DB_SIZE); + eq->db = dev->func_bar + ERDMA_REGS_CEQ_DB_BASE_REG + + (ceqn + 1) * ERDMA_DB_SIZE; eq->db_record = (u64 *)(eq->qbuf + buf_size); eq->ci = 0; dev->ceqs[ceqn].dev = dev; diff --git a/drivers/infiniband/hw/erdma/erdma_hw.h b/drivers/infiniband/hw/erdma/erdma_hw.h index 37ad1bb1917c..76ce2856be28 100644 --- a/drivers/infiniband/hw/erdma/erdma_hw.h +++ b/drivers/infiniband/hw/erdma/erdma_hw.h @@ -112,6 +112,10 @@ #define ERDMA_PAGE_SIZE_SUPPORT 0x7FFFF000 +/* Hardware page size definition */ +#define ERDMA_HW_PAGE_SHIFT 12 +#define ERDMA_HW_PAGE_SIZE 4096 + /* WQE related. */ #define EQE_SIZE 16 #define EQE_SHIFT 4 diff --git a/drivers/infiniband/hw/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c index 4a29a53a6652..7c74abeee864 100644 --- a/drivers/infiniband/hw/erdma/erdma_main.c +++ b/drivers/infiniband/hw/erdma/erdma_main.c @@ -211,13 +211,36 @@ static int erdma_device_init(struct erdma_dev *dev, struct pci_dev *pdev) return 0; } -static void erdma_device_uninit(struct erdma_dev *dev) +static void erdma_hw_reset(struct erdma_dev *dev) { u32 ctrl = FIELD_PREP(ERDMA_REG_DEV_CTRL_RESET_MASK, 1); erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, ctrl); } +static int erdma_wait_hw_init_done(struct erdma_dev *dev) +{ + int i; + + erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, + FIELD_PREP(ERDMA_REG_DEV_CTRL_INIT_MASK, 1)); + + for (i = 0; i < ERDMA_WAIT_DEV_DONE_CNT; i++) { + if (erdma_reg_read32_filed(dev, ERDMA_REGS_DEV_ST_REG, + ERDMA_REG_DEV_ST_INIT_DONE_MASK)) + break; + + msleep(ERDMA_REG_ACCESS_WAIT_MS); + } + + if (i == ERDMA_WAIT_DEV_DONE_CNT) { + dev_err(&dev->pdev->dev, "wait init done failed.\n"); + return -ETIMEDOUT; + } + + return 0; +} + static const struct pci_device_id erdma_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_ALIBABA, 0x107f) }, {} @@ -293,16 +316,22 @@ static int erdma_probe_dev(struct pci_dev *pdev) if (err) goto err_uninit_aeq; - err = erdma_ceqs_init(dev); + err = erdma_wait_hw_init_done(dev); if (err) goto err_uninit_cmdq; + err = erdma_ceqs_init(dev); + if (err) + goto err_reset_hw; + erdma_finish_cmdq_init(dev); return 0; +err_reset_hw: + erdma_hw_reset(dev); + err_uninit_cmdq: - erdma_device_uninit(dev); erdma_cmdq_destroy(dev); err_uninit_aeq: @@ -334,9 +363,7 @@ static void erdma_remove_dev(struct pci_dev *pdev) struct erdma_dev *dev = pci_get_drvdata(pdev); erdma_ceqs_uninit(dev); - - erdma_device_uninit(dev); - + erdma_hw_reset(dev); erdma_cmdq_destroy(dev); erdma_aeq_destroy(dev); erdma_comm_irq_uninit(dev); diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 9c30d78730aa..83e1b0d55977 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -38,7 +38,7 @@ static int create_qp_cmd(struct erdma_dev *dev, struct erdma_qp *qp) FIELD_PREP(ERDMA_CMD_CREATE_QP_PD_MASK, pd->pdn); if (rdma_is_kernel_res(&qp->ibqp.res)) { - u32 pgsz_range = ilog2(SZ_1M) - PAGE_SHIFT; + u32 pgsz_range = ilog2(SZ_1M) - ERDMA_HW_PAGE_SHIFT; req.sq_cqn_mtt_cfg = FIELD_PREP(ERDMA_CMD_CREATE_QP_PAGE_SIZE_MASK, @@ -66,13 +66,13 @@ static int create_qp_cmd(struct erdma_dev *dev, struct erdma_qp *qp) user_qp = &qp->user_qp; req.sq_cqn_mtt_cfg = FIELD_PREP( ERDMA_CMD_CREATE_QP_PAGE_SIZE_MASK, - ilog2(user_qp->sq_mtt.page_size) - PAGE_SHIFT); + ilog2(user_qp->sq_mtt.page_size) - ERDMA_HW_PAGE_SHIFT); req.sq_cqn_mtt_cfg |= FIELD_PREP(ERDMA_CMD_CREATE_QP_CQN_MASK, qp->scq->cqn); req.rq_cqn_mtt_cfg = FIELD_PREP( ERDMA_CMD_CREATE_QP_PAGE_SIZE_MASK, - ilog2(user_qp->rq_mtt.page_size) - PAGE_SHIFT); + ilog2(user_qp->rq_mtt.page_size) - ERDMA_HW_PAGE_SHIFT); req.rq_cqn_mtt_cfg |= FIELD_PREP(ERDMA_CMD_CREATE_QP_CQN_MASK, qp->rcq->cqn); @@ -162,7 +162,7 @@ static int create_cq_cmd(struct erdma_dev *dev, struct erdma_cq *cq) if (rdma_is_kernel_res(&cq->ibcq.res)) { page_size = SZ_32M; req.cfg0 |= FIELD_PREP(ERDMA_CMD_CREATE_CQ_PAGESIZE_MASK, - ilog2(page_size) - PAGE_SHIFT); + ilog2(page_size) - ERDMA_HW_PAGE_SHIFT); req.qbuf_addr_l = lower_32_bits(cq->kern_cq.qbuf_dma_addr); req.qbuf_addr_h = upper_32_bits(cq->kern_cq.qbuf_dma_addr); @@ -175,8 +175,9 @@ static int create_cq_cmd(struct erdma_dev *dev, struct erdma_cq *cq) cq->kern_cq.qbuf_dma_addr + (cq->depth << CQE_SHIFT); } else { mtt = &cq->user_cq.qbuf_mtt; - req.cfg0 |= FIELD_PREP(ERDMA_CMD_CREATE_CQ_PAGESIZE_MASK, - ilog2(mtt->page_size) - PAGE_SHIFT); + req.cfg0 |= + FIELD_PREP(ERDMA_CMD_CREATE_CQ_PAGESIZE_MASK, + ilog2(mtt->page_size) - ERDMA_HW_PAGE_SHIFT); if (mtt->mtt_nents == 1) { req.qbuf_addr_l = lower_32_bits(*(u64 *)mtt->mtt_buf); req.qbuf_addr_h = upper_32_bits(*(u64 *)mtt->mtt_buf); @@ -636,7 +637,7 @@ static int init_user_qp(struct erdma_qp *qp, struct erdma_ucontext *uctx, u32 rq_offset; int ret; - if (len < (PAGE_ALIGN(qp->attrs.sq_size * SQEBB_SIZE) + + if (len < (ALIGN(qp->attrs.sq_size * SQEBB_SIZE, ERDMA_HW_PAGE_SIZE) + qp->attrs.rq_size * RQE_SIZE)) return -EINVAL; @@ -646,7 +647,7 @@ static int init_user_qp(struct erdma_qp *qp, struct erdma_ucontext *uctx, if (ret) return ret; - rq_offset = PAGE_ALIGN(qp->attrs.sq_size << SQEBB_SHIFT); + rq_offset = ALIGN(qp->attrs.sq_size << SQEBB_SHIFT, ERDMA_HW_PAGE_SIZE); qp->user_qp.rq_offset = rq_offset; ret = get_mtt_entries(qp->dev, &qp->user_qp.rq_mtt, va + rq_offset, diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 90b672feed83..9dbb89e9f4af 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -12135,7 +12135,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, set_intr_bits(dd, IS_RCVURGENT_START + rcd->ctxt, IS_RCVURGENT_START + rcd->ctxt, false); - hfi1_cdbg(RCVCTRL, "ctxt %d rcvctrl 0x%llx\n", ctxt, rcvctrl); + hfi1_cdbg(RCVCTRL, "ctxt %d rcvctrl 0x%llx", ctxt, rcvctrl); write_kctxt_csr(dd, ctxt, RCV_CTXT_CTRL, rcvctrl); /* work around sticky RcvCtxtStatus.BlockedRHQFull */ @@ -12205,10 +12205,10 @@ u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp) hfi1_cdbg(CNTR, "reading %s", entry->name); if (entry->flags & CNTR_DISABLED) { /* Nothing */ - hfi1_cdbg(CNTR, "\tDisabled\n"); + hfi1_cdbg(CNTR, "\tDisabled"); } else { if (entry->flags & CNTR_VL) { - hfi1_cdbg(CNTR, "\tPer VL\n"); + hfi1_cdbg(CNTR, "\tPer VL"); for (j = 0; j < C_VL_COUNT; j++) { val = entry->rw_cntr(entry, dd, j, @@ -12216,21 +12216,21 @@ u32 hfi1_read_cntrs(struct hfi1_devdata *dd, char **namep, u64 **cntrp) 0); hfi1_cdbg( CNTR, - "\t\tRead 0x%llx for %d\n", + "\t\tRead 0x%llx for %d", val, j); dd->cntrs[entry->offset + j] = val; } } else if (entry->flags & CNTR_SDMA) { hfi1_cdbg(CNTR, - "\t Per SDMA Engine\n"); + "\t Per SDMA Engine"); for (j = 0; j < chip_sdma_engines(dd); j++) { val = entry->rw_cntr(entry, dd, j, CNTR_MODE_R, 0); hfi1_cdbg(CNTR, - "\t\tRead 0x%llx for %d\n", + "\t\tRead 0x%llx for %d", val, j); dd->cntrs[entry->offset + j] = val; @@ -12271,7 +12271,7 @@ u32 hfi1_read_portcntrs(struct hfi1_pportdata *ppd, char **namep, u64 **cntrp) hfi1_cdbg(CNTR, "reading %s", entry->name); if (entry->flags & CNTR_DISABLED) { /* Nothing */ - hfi1_cdbg(CNTR, "\tDisabled\n"); + hfi1_cdbg(CNTR, "\tDisabled"); continue; } @@ -12513,7 +12513,7 @@ static void do_update_synth_timer(struct work_struct *work) hfi1_cdbg( CNTR, - "[%d] curr tx=0x%llx rx=0x%llx :: last tx=0x%llx rx=0x%llx\n", + "[%d] curr tx=0x%llx rx=0x%llx :: last tx=0x%llx rx=0x%llx", dd->unit, cur_tx, cur_rx, dd->last_tx, dd->last_rx); if ((cur_tx < dd->last_tx) || (cur_rx < dd->last_rx)) { @@ -12527,7 +12527,7 @@ static void do_update_synth_timer(struct work_struct *work) } else { total_flits = (cur_tx - dd->last_tx) + (cur_rx - dd->last_rx); hfi1_cdbg(CNTR, - "[%d] total flits 0x%llx limit 0x%llx\n", dd->unit, + "[%d] total flits 0x%llx limit 0x%llx", dd->unit, total_flits, (u64)CNTR_32BIT_MAX); if (total_flits >= CNTR_32BIT_MAX) { hfi1_cdbg(CNTR, "[%d] 32bit limit hit, updating", diff --git a/drivers/infiniband/hw/hfi1/device.c b/drivers/infiniband/hw/hfi1/device.c index 1f4496032170..05be0d119f79 100644 --- a/drivers/infiniband/hw/hfi1/device.c +++ b/drivers/infiniband/hw/hfi1/device.c @@ -102,7 +102,7 @@ int __init dev_init(void) goto done; } - class = class_create(THIS_MODULE, class_name()); + class = class_create(class_name()); if (IS_ERR(class)) { ret = PTR_ERR(class); pr_err("Could not create device class (err %d)\n", -ret); @@ -111,7 +111,7 @@ int __init dev_init(void) } class->devnode = hfi1_devnode; - user_class = class_create(THIS_MODULE, class_name_user()); + user_class = class_create(class_name_user()); if (IS_ERR(user_class)) { ret = PTR_ERR(user_class); pr_err("Could not create device class for user accessible files (err %d)\n", diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c index bcc6bc0540f0..f4492fa407e0 100644 --- a/drivers/infiniband/hw/hfi1/driver.c +++ b/drivers/infiniband/hw/hfi1/driver.c @@ -1597,7 +1597,7 @@ static int hfi1_setup_bypass_packet(struct hfi1_packet *packet) return 0; drop: - hfi1_cdbg(PKT, "%s: packet dropped\n", __func__); + hfi1_cdbg(PKT, "%s: packet dropped", __func__); ibp->rvp.n_pkt_drops++; return -EINVAL; } diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index f3d6ce45c397..a5ab22cedd41 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -975,7 +975,7 @@ static int allocate_ctxt(struct hfi1_filedata *fd, struct hfi1_devdata *dd, ret = -ENOMEM; goto ctxdata_free; } - hfi1_cdbg(PROC, "allocated send context %u(%u)\n", uctxt->sc->sw_index, + hfi1_cdbg(PROC, "allocated send context %u(%u)", uctxt->sc->sw_index, uctxt->sc->hw_context); ret = sc_enable(uctxt->sc); if (ret) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 62b6c5020039..6de37c5d7d27 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -342,7 +342,7 @@ int hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, int numa, INIT_LIST_HEAD(&rcd->flow_queue.queue_head); INIT_LIST_HEAD(&rcd->rarr_queue.queue_head); - hfi1_cdbg(PROC, "setting up context %u\n", rcd->ctxt); + hfi1_cdbg(PROC, "setting up context %u", rcd->ctxt); /* * Calculate the context's RcvArray entry starting point. @@ -400,7 +400,7 @@ int hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, int numa, rcd->egrbufs.count = MAX_EAGER_ENTRIES; } hfi1_cdbg(PROC, - "ctxt%u: max Eager buffer RcvArray entries: %u\n", + "ctxt%u: max Eager buffer RcvArray entries: %u", rcd->ctxt, rcd->egrbufs.count); /* @@ -432,7 +432,7 @@ int hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, int numa, if (rcd->egrbufs.size < hfi1_max_mtu) { rcd->egrbufs.size = __roundup_pow_of_two(hfi1_max_mtu); hfi1_cdbg(PROC, - "ctxt%u: eager bufs size too small. Adjusting to %u\n", + "ctxt%u: eager bufs size too small. Adjusting to %u", rcd->ctxt, rcd->egrbufs.size); } rcd->egrbufs.rcvtid_size = HFI1_MAX_EAGER_BUFFER_SIZE; @@ -1920,7 +1920,7 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd) rcd->egrbufs.size = alloced_bytes; hfi1_cdbg(PROC, - "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %uKB\n", + "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %uKB", rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size / 1024, rcd->egrbufs.size / 1024); @@ -1943,13 +1943,13 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd) rcd->expected_count = MAX_TID_PAIR_ENTRIES * 2; rcd->expected_base = rcd->eager_base + egrtop; - hfi1_cdbg(PROC, "ctxt%u: eager:%u, exp:%u, egrbase:%u, expbase:%u\n", + hfi1_cdbg(PROC, "ctxt%u: eager:%u, exp:%u, egrbase:%u, expbase:%u", rcd->ctxt, rcd->egrbufs.alloced, rcd->expected_count, rcd->eager_base, rcd->expected_base); if (!hfi1_rcvbuf_validate(rcd->egrbufs.rcvtid_size, PT_EAGER, &order)) { hfi1_cdbg(PROC, - "ctxt%u: current Eager buffer size is invalid %u\n", + "ctxt%u: current Eager buffer size is invalid %u", rcd->ctxt, rcd->egrbufs.rcvtid_size); ret = -EINVAL; goto bail_rcvegrbuf_phys; diff --git a/drivers/infiniband/hw/hfi1/ipoib_tx.c b/drivers/infiniband/hw/hfi1/ipoib_tx.c index 5d9a7b09ca37..8973a081d641 100644 --- a/drivers/infiniband/hw/hfi1/ipoib_tx.c +++ b/drivers/infiniband/hw/hfi1/ipoib_tx.c @@ -215,6 +215,7 @@ static int hfi1_ipoib_build_ulp_payload(struct ipoib_txreq *tx, const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ret = sdma_txadd_page(dd, + NULL, txreq, skb_frag_page(frag), frag->bv_offset, @@ -737,10 +738,13 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv) txq->tx_ring.shift = ilog2(tx_item_size); txq->tx_ring.avail = hfi1_ipoib_ring_hwat(txq); tx_ring = &txq->tx_ring; - for (j = 0; j < tx_ring_size; j++) + for (j = 0; j < tx_ring_size; j++) { hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr = kzalloc_node(sizeof(*tx->sdma_hdr), GFP_KERNEL, priv->dd->node); + if (!hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr) + goto free_txqs; + } netif_napi_add_tx(dev, &txq->napi, hfi1_ipoib_poll_tx_ring); } diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c index 7333646021bb..1cea8b0c78e0 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.c +++ b/drivers/infiniband/hw/hfi1/mmu_rb.c @@ -46,12 +46,14 @@ int hfi1_mmu_rb_register(void *ops_arg, struct mmu_rb_handler **handler) { struct mmu_rb_handler *h; + void *free_ptr; int ret; - h = kzalloc(sizeof(*h), GFP_KERNEL); - if (!h) + free_ptr = kzalloc(sizeof(*h) + cache_line_size() - 1, GFP_KERNEL); + if (!free_ptr) return -ENOMEM; + h = PTR_ALIGN(free_ptr, cache_line_size()); h->root = RB_ROOT_CACHED; h->ops = ops; h->ops_arg = ops_arg; @@ -62,10 +64,11 @@ int hfi1_mmu_rb_register(void *ops_arg, INIT_LIST_HEAD(&h->del_list); INIT_LIST_HEAD(&h->lru_list); h->wq = wq; + h->free_ptr = free_ptr; ret = mmu_notifier_register(&h->mn, current->mm); if (ret) { - kfree(h); + kfree(free_ptr); return ret; } @@ -108,7 +111,7 @@ void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) /* Now the mm may be freed. */ mmdrop(handler->mn.mm); - kfree(handler); + kfree(handler->free_ptr); } int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, @@ -126,11 +129,11 @@ int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, spin_lock_irqsave(&handler->lock, flags); node = __mmu_rb_search(handler, mnode->addr, mnode->len); if (node) { - ret = -EINVAL; + ret = -EEXIST; goto unlock; } __mmu_int_rb_insert(mnode, &handler->root); - list_add(&mnode->list, &handler->lru_list); + list_add_tail(&mnode->list, &handler->lru_list); ret = handler->ops->insert(handler->ops_arg, mnode); if (ret) { @@ -143,6 +146,19 @@ unlock: return ret; } +/* Caller must hold handler lock */ +struct mmu_rb_node *hfi1_mmu_rb_get_first(struct mmu_rb_handler *handler, + unsigned long addr, unsigned long len) +{ + struct mmu_rb_node *node; + + trace_hfi1_mmu_rb_search(addr, len); + node = __mmu_int_rb_iter_first(&handler->root, addr, (addr + len) - 1); + if (node) + list_move_tail(&node->list, &handler->lru_list); + return node; +} + /* Caller must hold handler lock */ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, unsigned long addr, @@ -167,32 +183,6 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, return node; } -bool hfi1_mmu_rb_remove_unless_exact(struct mmu_rb_handler *handler, - unsigned long addr, unsigned long len, - struct mmu_rb_node **rb_node) -{ - struct mmu_rb_node *node; - unsigned long flags; - bool ret = false; - - if (current->mm != handler->mn.mm) - return ret; - - spin_lock_irqsave(&handler->lock, flags); - node = __mmu_rb_search(handler, addr, len); - if (node) { - if (node->addr == addr && node->len == len) - goto unlock; - __mmu_int_rb_remove(node, &handler->root); - list_del(&node->list); /* remove from LRU list */ - ret = true; - } -unlock: - spin_unlock_irqrestore(&handler->lock, flags); - *rb_node = node; - return ret; -} - void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg) { struct mmu_rb_node *rbnode, *ptr; @@ -206,8 +196,7 @@ void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg) INIT_LIST_HEAD(&del_list); spin_lock_irqsave(&handler->lock, flags); - list_for_each_entry_safe_reverse(rbnode, ptr, &handler->lru_list, - list) { + list_for_each_entry_safe(rbnode, ptr, &handler->lru_list, list) { if (handler->ops->evict(handler->ops_arg, rbnode, evict_arg, &stop)) { __mmu_int_rb_remove(rbnode, &handler->root); @@ -219,36 +208,11 @@ void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg) } spin_unlock_irqrestore(&handler->lock, flags); - while (!list_empty(&del_list)) { - rbnode = list_first_entry(&del_list, struct mmu_rb_node, list); - list_del(&rbnode->list); + list_for_each_entry_safe(rbnode, ptr, &del_list, list) { handler->ops->remove(handler->ops_arg, rbnode); } } -/* - * It is up to the caller to ensure that this function does not race with the - * mmu invalidate notifier which may be calling the users remove callback on - * 'node'. - */ -void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, - struct mmu_rb_node *node) -{ - unsigned long flags; - - if (current->mm != handler->mn.mm) - return; - - /* Validity of handler and node pointers has been checked by caller. */ - trace_hfi1_mmu_rb_remove(node->addr, node->len); - spin_lock_irqsave(&handler->lock, flags); - __mmu_int_rb_remove(node, &handler->root); - list_del(&node->list); /* remove from LRU list */ - spin_unlock_irqrestore(&handler->lock, flags); - - handler->ops->remove(handler->ops_arg, node); -} - static int mmu_notifier_range_start(struct mmu_notifier *mn, const struct mmu_notifier_range *range) { diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.h b/drivers/infiniband/hw/hfi1/mmu_rb.h index 7417be2b9dc8..c4da064188c9 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.h +++ b/drivers/infiniband/hw/hfi1/mmu_rb.h @@ -33,15 +33,25 @@ struct mmu_rb_ops { }; struct mmu_rb_handler { + /* + * struct mmu_notifier is 56 bytes, and spinlock_t is 4 bytes, so + * they fit together in one cache line. mn is relatively rarely + * accessed, so co-locating the spinlock with it achieves much of + * the cacheline contention reduction of giving the spinlock its own + * cacheline without the overhead of doing so. + */ struct mmu_notifier mn; - struct rb_root_cached root; - void *ops_arg; spinlock_t lock; /* protect the RB tree */ + + /* Begin on a new cachline boundary here */ + struct rb_root_cached root ____cacheline_aligned_in_smp; + void *ops_arg; struct mmu_rb_ops *ops; struct list_head lru_list; struct work_struct del_work; struct list_head del_list; struct workqueue_struct *wq; + void *free_ptr; }; int hfi1_mmu_rb_register(void *ops_arg, @@ -52,10 +62,8 @@ void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler); int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, struct mmu_rb_node *mnode); void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg); -void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, - struct mmu_rb_node *mnode); -bool hfi1_mmu_rb_remove_unless_exact(struct mmu_rb_handler *handler, - unsigned long addr, unsigned long len, - struct mmu_rb_node **rb_node); +struct mmu_rb_node *hfi1_mmu_rb_get_first(struct mmu_rb_handler *handler, + unsigned long addr, + unsigned long len); #endif /* _HFI1_MMU_RB_H */ diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c index a0802332c8cb..08732e1ac966 100644 --- a/drivers/infiniband/hw/hfi1/pcie.c +++ b/drivers/infiniband/hw/hfi1/pcie.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "hfi.h" @@ -65,7 +64,6 @@ int hfi1_pcie_init(struct hfi1_devdata *dd) } pci_set_master(pdev); - (void)pci_enable_pcie_error_reporting(pdev); return 0; bail: diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 51ae58c02b15..62e7dc9bea7b 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -820,7 +820,7 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type, } hfi1_cdbg(PIO, - "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u\n", + "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u", sw_index, hw_context, sc_type_name(type), diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 8ed20392e9f0..bb2552dd29c1 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -1593,22 +1593,7 @@ static inline void sdma_unmap_desc( struct hfi1_devdata *dd, struct sdma_desc *descp) { - switch (sdma_mapping_type(descp)) { - case SDMA_MAP_SINGLE: - dma_unmap_single( - &dd->pcidev->dev, - sdma_mapping_addr(descp), - sdma_mapping_len(descp), - DMA_TO_DEVICE); - break; - case SDMA_MAP_PAGE: - dma_unmap_page( - &dd->pcidev->dev, - sdma_mapping_addr(descp), - sdma_mapping_len(descp), - DMA_TO_DEVICE); - break; - } + system_descriptor_complete(dd, descp); } /* @@ -3128,7 +3113,7 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx, /* Add descriptor for coalesce buffer */ tx->desc_limit = MAX_DESC; - return _sdma_txadd_daddr(dd, SDMA_MAP_SINGLE, tx, + return _sdma_txadd_daddr(dd, SDMA_MAP_SINGLE, NULL, tx, addr, tx->tlen); } @@ -3167,10 +3152,12 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) return rval; } } + /* finish the one just added */ make_tx_sdma_desc( tx, SDMA_MAP_NONE, + NULL, dd->sdma_pad_phys, sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1))); tx->num_desc++; diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index b023fc461bd5..95aaec14c6c2 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -594,6 +594,7 @@ static inline dma_addr_t sdma_mapping_addr(struct sdma_desc *d) static inline void make_tx_sdma_desc( struct sdma_txreq *tx, int type, + void *pinning_ctx, dma_addr_t addr, size_t len) { @@ -612,6 +613,7 @@ static inline void make_tx_sdma_desc( << SDMA_DESC0_PHY_ADDR_SHIFT) | (((u64)len & SDMA_DESC0_BYTE_COUNT_MASK) << SDMA_DESC0_BYTE_COUNT_SHIFT); + desc->pinning_ctx = pinning_ctx; } /* helper to extend txreq */ @@ -643,6 +645,7 @@ static inline void _sdma_close_tx(struct hfi1_devdata *dd, static inline int _sdma_txadd_daddr( struct hfi1_devdata *dd, int type, + void *pinning_ctx, struct sdma_txreq *tx, dma_addr_t addr, u16 len) @@ -652,6 +655,7 @@ static inline int _sdma_txadd_daddr( make_tx_sdma_desc( tx, type, + pinning_ctx, addr, len); WARN_ON(len > tx->tlen); tx->num_desc++; @@ -672,6 +676,7 @@ static inline int _sdma_txadd_daddr( /** * sdma_txadd_page() - add a page to the sdma_txreq * @dd: the device to use for mapping + * @pinning_ctx: context to be released at descriptor retirement * @tx: tx request to which the page is added * @page: page to map * @offset: offset within the page @@ -687,6 +692,7 @@ static inline int _sdma_txadd_daddr( */ static inline int sdma_txadd_page( struct hfi1_devdata *dd, + void *pinning_ctx, struct sdma_txreq *tx, struct page *page, unsigned long offset, @@ -714,8 +720,7 @@ static inline int sdma_txadd_page( return -ENOSPC; } - return _sdma_txadd_daddr( - dd, SDMA_MAP_PAGE, tx, addr, len); + return _sdma_txadd_daddr(dd, SDMA_MAP_PAGE, pinning_ctx, tx, addr, len); } /** @@ -749,7 +754,8 @@ static inline int sdma_txadd_daddr( return rval; } - return _sdma_txadd_daddr(dd, SDMA_MAP_NONE, tx, addr, len); + return _sdma_txadd_daddr(dd, SDMA_MAP_NONE, NULL, tx, + addr, len); } /** @@ -795,8 +801,7 @@ static inline int sdma_txadd_kvaddr( return -ENOSPC; } - return _sdma_txadd_daddr( - dd, SDMA_MAP_SINGLE, tx, addr, len); + return _sdma_txadd_daddr(dd, SDMA_MAP_SINGLE, NULL, tx, addr, len); } struct iowait_work; @@ -1030,4 +1035,5 @@ extern uint mod_num_sdma; void sdma_update_lmc(struct hfi1_devdata *dd, u64 mask, u32 lid); +void system_descriptor_complete(struct hfi1_devdata *dd, struct sdma_desc *descp); #endif diff --git a/drivers/infiniband/hw/hfi1/sdma_txreq.h b/drivers/infiniband/hw/hfi1/sdma_txreq.h index e262fb5c5ec6..fad946cb5e0d 100644 --- a/drivers/infiniband/hw/hfi1/sdma_txreq.h +++ b/drivers/infiniband/hw/hfi1/sdma_txreq.h @@ -19,6 +19,7 @@ struct sdma_desc { /* private: don't use directly */ u64 qw[2]; + void *pinning_ctx; }; /** diff --git a/drivers/infiniband/hw/hfi1/trace_dbg.h b/drivers/infiniband/hw/hfi1/trace_dbg.h index 582b6f68df3d..489395bfb5b3 100644 --- a/drivers/infiniband/hw/hfi1/trace_dbg.h +++ b/drivers/infiniband/hw/hfi1/trace_dbg.h @@ -22,6 +22,11 @@ #define MAX_MSG_LEN 512 +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +#endif + DECLARE_EVENT_CLASS(hfi1_trace_template, TP_PROTO(const char *function, struct va_format *vaf), TP_ARGS(function, vaf), @@ -36,6 +41,8 @@ DECLARE_EVENT_CLASS(hfi1_trace_template, __get_str(msg)) ); +#pragma GCC diagnostic pop + /* * It may be nice to macroize the __hfi1_trace but the va_* stuff requires an * actual function to work and can not be in a macro. diff --git a/drivers/infiniband/hw/hfi1/trace_mmu.h b/drivers/infiniband/hw/hfi1/trace_mmu.h index 187e9244fe5e..57900ebb7702 100644 --- a/drivers/infiniband/hw/hfi1/trace_mmu.h +++ b/drivers/infiniband/hw/hfi1/trace_mmu.h @@ -37,10 +37,6 @@ DEFINE_EVENT(hfi1_mmu_rb_template, hfi1_mmu_rb_search, TP_PROTO(unsigned long addr, unsigned long len), TP_ARGS(addr, len)); -DEFINE_EVENT(hfi1_mmu_rb_template, hfi1_mmu_rb_remove, - TP_PROTO(unsigned long addr, unsigned long len), - TP_ARGS(addr, len)); - DEFINE_EVENT(hfi1_mmu_rb_template, hfi1_mmu_mem_invalidate, TP_PROTO(unsigned long addr, unsigned long len), TP_ARGS(addr, len)); diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index a71c5a36ceba..ae58b48afe07 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -24,7 +24,6 @@ #include "hfi.h" #include "sdma.h" -#include "mmu_rb.h" #include "user_sdma.h" #include "verbs.h" /* for the headers */ #include "common.h" /* for struct hfi1_tid_info */ @@ -39,11 +38,7 @@ static unsigned initial_pkt_count = 8; static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts); static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status); static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq); -static void user_sdma_free_request(struct user_sdma_request *req, bool unpin); -static int pin_vector_pages(struct user_sdma_request *req, - struct user_sdma_iovec *iovec); -static void unpin_vector_pages(struct mm_struct *mm, struct page **pages, - unsigned start, unsigned npages); +static void user_sdma_free_request(struct user_sdma_request *req); static int check_header_template(struct user_sdma_request *req, struct hfi1_pkt_header *hdr, u32 lrhlen, u32 datalen); @@ -81,6 +76,11 @@ static struct mmu_rb_ops sdma_rb_ops = { .invalidate = sdma_rb_invalidate }; +static int add_system_pages_to_sdma_packet(struct user_sdma_request *req, + struct user_sdma_txreq *tx, + struct user_sdma_iovec *iovec, + u32 *pkt_remaining); + static int defer_packet_queue( struct sdma_engine *sde, struct iowait_work *wait, @@ -410,6 +410,7 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, ret = -EINVAL; goto free_req; } + /* Copy the header from the user buffer */ ret = copy_from_user(&req->hdr, iovec[idx].iov_base + sizeof(info), sizeof(req->hdr)); @@ -484,9 +485,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(req->iovs[i].iov)); - ret = pin_vector_pages(req, &req->iovs[i]); - if (ret) { - req->data_iovs = i; + if (req->iovs[i].iov.iov_len == 0) { + ret = -EINVAL; goto free_req; } req->data_len += req->iovs[i].iov.iov_len; @@ -584,7 +584,7 @@ free_req: if (req->seqsubmitted) wait_event(pq->busy.wait_dma, (req->seqcomp == req->seqsubmitted - 1)); - user_sdma_free_request(req, true); + user_sdma_free_request(req); pq_update(pq); set_comp_state(pq, cq, info.comp_idx, ERROR, ret); } @@ -696,48 +696,6 @@ static int user_sdma_txadd_ahg(struct user_sdma_request *req, return ret; } -static int user_sdma_txadd(struct user_sdma_request *req, - struct user_sdma_txreq *tx, - struct user_sdma_iovec *iovec, u32 datalen, - u32 *queued_ptr, u32 *data_sent_ptr, - u64 *iov_offset_ptr) -{ - int ret; - unsigned int pageidx, len; - unsigned long base, offset; - u64 iov_offset = *iov_offset_ptr; - u32 queued = *queued_ptr, data_sent = *data_sent_ptr; - struct hfi1_user_sdma_pkt_q *pq = req->pq; - - base = (unsigned long)iovec->iov.iov_base; - offset = offset_in_page(base + iovec->offset + iov_offset); - pageidx = (((iovec->offset + iov_offset + base) - (base & PAGE_MASK)) >> - PAGE_SHIFT); - len = offset + req->info.fragsize > PAGE_SIZE ? - PAGE_SIZE - offset : req->info.fragsize; - len = min((datalen - queued), len); - ret = sdma_txadd_page(pq->dd, &tx->txreq, iovec->pages[pageidx], - offset, len); - if (ret) { - SDMA_DBG(req, "SDMA txreq add page failed %d\n", ret); - return ret; - } - iov_offset += len; - queued += len; - data_sent += len; - if (unlikely(queued < datalen && pageidx == iovec->npages && - req->iov_idx < req->data_iovs - 1)) { - iovec->offset += iov_offset; - iovec = &req->iovs[++req->iov_idx]; - iov_offset = 0; - } - - *queued_ptr = queued; - *data_sent_ptr = data_sent; - *iov_offset_ptr = iov_offset; - return ret; -} - static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) { int ret = 0; @@ -769,8 +727,7 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) maxpkts = req->info.npkts - req->seqnum; while (npkts < maxpkts) { - u32 datalen = 0, queued = 0, data_sent = 0; - u64 iov_offset = 0; + u32 datalen = 0; /* * Check whether any of the completions have come back @@ -863,27 +820,17 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, u16 maxpkts) goto free_txreq; } - /* - * If the request contains any data vectors, add up to - * fragsize bytes to the descriptor. - */ - while (queued < datalen && - (req->sent + data_sent) < req->data_len) { - ret = user_sdma_txadd(req, tx, iovec, datalen, - &queued, &data_sent, &iov_offset); - if (ret) - goto free_txreq; - } - /* - * The txreq was submitted successfully so we can update - * the counters. - */ req->koffset += datalen; if (req_opcode(req->info.ctrl) == EXPECTED) req->tidoffset += datalen; - req->sent += data_sent; - if (req->data_len) - iovec->offset += iov_offset; + req->sent += datalen; + while (datalen) { + ret = add_system_pages_to_sdma_packet(req, tx, iovec, + &datalen); + if (ret) + goto free_txreq; + iovec = &req->iovs[req->iov_idx]; + } list_add_tail(&tx->txreq.list, &req->txps); /* * It is important to increment this here as it is used to @@ -920,133 +867,14 @@ free_tx: static u32 sdma_cache_evict(struct hfi1_user_sdma_pkt_q *pq, u32 npages) { struct evict_data evict_data; + struct mmu_rb_handler *handler = pq->handler; evict_data.cleared = 0; evict_data.target = npages; - hfi1_mmu_rb_evict(pq->handler, &evict_data); + hfi1_mmu_rb_evict(handler, &evict_data); return evict_data.cleared; } -static int pin_sdma_pages(struct user_sdma_request *req, - struct user_sdma_iovec *iovec, - struct sdma_mmu_node *node, - int npages) -{ - int pinned, cleared; - struct page **pages; - struct hfi1_user_sdma_pkt_q *pq = req->pq; - - pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); - if (!pages) - return -ENOMEM; - memcpy(pages, node->pages, node->npages * sizeof(*pages)); - - npages -= node->npages; -retry: - if (!hfi1_can_pin_pages(pq->dd, current->mm, - atomic_read(&pq->n_locked), npages)) { - cleared = sdma_cache_evict(pq, npages); - if (cleared >= npages) - goto retry; - } - pinned = hfi1_acquire_user_pages(current->mm, - ((unsigned long)iovec->iov.iov_base + - (node->npages * PAGE_SIZE)), npages, 0, - pages + node->npages); - if (pinned < 0) { - kfree(pages); - return pinned; - } - if (pinned != npages) { - unpin_vector_pages(current->mm, pages, node->npages, pinned); - return -EFAULT; - } - kfree(node->pages); - node->rb.len = iovec->iov.iov_len; - node->pages = pages; - atomic_add(pinned, &pq->n_locked); - return pinned; -} - -static void unpin_sdma_pages(struct sdma_mmu_node *node) -{ - if (node->npages) { - unpin_vector_pages(mm_from_sdma_node(node), node->pages, 0, - node->npages); - atomic_sub(node->npages, &node->pq->n_locked); - } -} - -static int pin_vector_pages(struct user_sdma_request *req, - struct user_sdma_iovec *iovec) -{ - int ret = 0, pinned, npages; - struct hfi1_user_sdma_pkt_q *pq = req->pq; - struct sdma_mmu_node *node = NULL; - struct mmu_rb_node *rb_node; - struct iovec *iov; - bool extracted; - - extracted = - hfi1_mmu_rb_remove_unless_exact(pq->handler, - (unsigned long) - iovec->iov.iov_base, - iovec->iov.iov_len, &rb_node); - if (rb_node) { - node = container_of(rb_node, struct sdma_mmu_node, rb); - if (!extracted) { - atomic_inc(&node->refcount); - iovec->pages = node->pages; - iovec->npages = node->npages; - iovec->node = node; - return 0; - } - } - - if (!node) { - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - return -ENOMEM; - - node->rb.addr = (unsigned long)iovec->iov.iov_base; - node->pq = pq; - atomic_set(&node->refcount, 0); - } - - iov = &iovec->iov; - npages = num_user_pages((unsigned long)iov->iov_base, iov->iov_len); - if (node->npages < npages) { - pinned = pin_sdma_pages(req, iovec, node, npages); - if (pinned < 0) { - ret = pinned; - goto bail; - } - node->npages += pinned; - npages = node->npages; - } - iovec->pages = node->pages; - iovec->npages = npages; - iovec->node = node; - - ret = hfi1_mmu_rb_insert(req->pq->handler, &node->rb); - if (ret) { - iovec->node = NULL; - goto bail; - } - return 0; -bail: - unpin_sdma_pages(node); - kfree(node); - return ret; -} - -static void unpin_vector_pages(struct mm_struct *mm, struct page **pages, - unsigned start, unsigned npages) -{ - hfi1_release_user_pages(mm, pages + start, npages, false); - kfree(pages); -} - static int check_header_template(struct user_sdma_request *req, struct hfi1_pkt_header *hdr, u32 lrhlen, u32 datalen) @@ -1388,7 +1216,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status) if (req->seqcomp != req->info.npkts - 1) return; - user_sdma_free_request(req, false); + user_sdma_free_request(req); set_comp_state(pq, cq, req->info.comp_idx, state, status); pq_update(pq); } @@ -1399,10 +1227,8 @@ static inline void pq_update(struct hfi1_user_sdma_pkt_q *pq) wake_up(&pq->wait); } -static void user_sdma_free_request(struct user_sdma_request *req, bool unpin) +static void user_sdma_free_request(struct user_sdma_request *req) { - int i; - if (!list_empty(&req->txps)) { struct sdma_txreq *t, *p; @@ -1415,21 +1241,6 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin) } } - for (i = 0; i < req->data_iovs; i++) { - struct sdma_mmu_node *node = req->iovs[i].node; - - if (!node) - continue; - - req->iovs[i].node = NULL; - - if (unpin) - hfi1_mmu_rb_remove(req->pq->handler, - &node->rb); - else - atomic_dec(&node->refcount); - } - kfree(req->tids); clear_bit(req->info.comp_idx, req->pq->req_in_use); } @@ -1447,6 +1258,368 @@ static inline void set_comp_state(struct hfi1_user_sdma_pkt_q *pq, idx, state, ret); } +static void unpin_vector_pages(struct mm_struct *mm, struct page **pages, + unsigned int start, unsigned int npages) +{ + hfi1_release_user_pages(mm, pages + start, npages, false); + kfree(pages); +} + +static void free_system_node(struct sdma_mmu_node *node) +{ + if (node->npages) { + unpin_vector_pages(mm_from_sdma_node(node), node->pages, 0, + node->npages); + atomic_sub(node->npages, &node->pq->n_locked); + } + kfree(node); +} + +static inline void acquire_node(struct sdma_mmu_node *node) +{ + atomic_inc(&node->refcount); + WARN_ON(atomic_read(&node->refcount) < 0); +} + +static inline void release_node(struct mmu_rb_handler *handler, + struct sdma_mmu_node *node) +{ + atomic_dec(&node->refcount); + WARN_ON(atomic_read(&node->refcount) < 0); +} + +static struct sdma_mmu_node *find_system_node(struct mmu_rb_handler *handler, + unsigned long start, + unsigned long end) +{ + struct mmu_rb_node *rb_node; + struct sdma_mmu_node *node; + unsigned long flags; + + spin_lock_irqsave(&handler->lock, flags); + rb_node = hfi1_mmu_rb_get_first(handler, start, (end - start)); + if (!rb_node) { + spin_unlock_irqrestore(&handler->lock, flags); + return NULL; + } + node = container_of(rb_node, struct sdma_mmu_node, rb); + acquire_node(node); + spin_unlock_irqrestore(&handler->lock, flags); + + return node; +} + +static int pin_system_pages(struct user_sdma_request *req, + uintptr_t start_address, size_t length, + struct sdma_mmu_node *node, int npages) +{ + struct hfi1_user_sdma_pkt_q *pq = req->pq; + int pinned, cleared; + struct page **pages; + + pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); + if (!pages) + return -ENOMEM; + +retry: + if (!hfi1_can_pin_pages(pq->dd, current->mm, atomic_read(&pq->n_locked), + npages)) { + SDMA_DBG(req, "Evicting: nlocked %u npages %u", + atomic_read(&pq->n_locked), npages); + cleared = sdma_cache_evict(pq, npages); + if (cleared >= npages) + goto retry; + } + + SDMA_DBG(req, "Acquire user pages start_address %lx node->npages %u npages %u", + start_address, node->npages, npages); + pinned = hfi1_acquire_user_pages(current->mm, start_address, npages, 0, + pages); + + if (pinned < 0) { + kfree(pages); + SDMA_DBG(req, "pinned %d", pinned); + return pinned; + } + if (pinned != npages) { + unpin_vector_pages(current->mm, pages, node->npages, pinned); + SDMA_DBG(req, "npages %u pinned %d", npages, pinned); + return -EFAULT; + } + node->rb.addr = start_address; + node->rb.len = length; + node->pages = pages; + node->npages = npages; + atomic_add(pinned, &pq->n_locked); + SDMA_DBG(req, "done. pinned %d", pinned); + return 0; +} + +static int add_system_pinning(struct user_sdma_request *req, + struct sdma_mmu_node **node_p, + unsigned long start, unsigned long len) + +{ + struct hfi1_user_sdma_pkt_q *pq = req->pq; + struct sdma_mmu_node *node; + int ret; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + node->pq = pq; + ret = pin_system_pages(req, start, len, node, PFN_DOWN(len)); + if (ret == 0) { + ret = hfi1_mmu_rb_insert(pq->handler, &node->rb); + if (ret) + free_system_node(node); + else + *node_p = node; + + return ret; + } + + kfree(node); + return ret; +} + +static int get_system_cache_entry(struct user_sdma_request *req, + struct sdma_mmu_node **node_p, + size_t req_start, size_t req_len) +{ + struct hfi1_user_sdma_pkt_q *pq = req->pq; + u64 start = ALIGN_DOWN(req_start, PAGE_SIZE); + u64 end = PFN_ALIGN(req_start + req_len); + struct mmu_rb_handler *handler = pq->handler; + int ret; + + if ((end - start) == 0) { + SDMA_DBG(req, + "Request for empty cache entry req_start %lx req_len %lx start %llx end %llx", + req_start, req_len, start, end); + return -EINVAL; + } + + SDMA_DBG(req, "req_start %lx req_len %lu", req_start, req_len); + + while (1) { + struct sdma_mmu_node *node = + find_system_node(handler, start, end); + u64 prepend_len = 0; + + SDMA_DBG(req, "node %p start %llx end %llu", node, start, end); + if (!node) { + ret = add_system_pinning(req, node_p, start, + end - start); + if (ret == -EEXIST) { + /* + * Another execution context has inserted a + * conficting entry first. + */ + continue; + } + return ret; + } + + if (node->rb.addr <= start) { + /* + * This entry covers at least part of the region. If it doesn't extend + * to the end, then this will be called again for the next segment. + */ + *node_p = node; + return 0; + } + + SDMA_DBG(req, "prepend: node->rb.addr %lx, node->refcount %d", + node->rb.addr, atomic_read(&node->refcount)); + prepend_len = node->rb.addr - start; + + /* + * This node will not be returned, instead a new node + * will be. So release the reference. + */ + release_node(handler, node); + + /* Prepend a node to cover the beginning of the allocation */ + ret = add_system_pinning(req, node_p, start, prepend_len); + if (ret == -EEXIST) { + /* Another execution context has inserted a conficting entry first. */ + continue; + } + return ret; + } +} + +static int add_mapping_to_sdma_packet(struct user_sdma_request *req, + struct user_sdma_txreq *tx, + struct sdma_mmu_node *cache_entry, + size_t start, + size_t from_this_cache_entry) +{ + struct hfi1_user_sdma_pkt_q *pq = req->pq; + unsigned int page_offset; + unsigned int from_this_page; + size_t page_index; + void *ctx; + int ret; + + /* + * Because the cache may be more fragmented than the memory that is being accessed, + * it's not strictly necessary to have a descriptor per cache entry. + */ + + while (from_this_cache_entry) { + page_index = PFN_DOWN(start - cache_entry->rb.addr); + + if (page_index >= cache_entry->npages) { + SDMA_DBG(req, + "Request for page_index %zu >= cache_entry->npages %u", + page_index, cache_entry->npages); + return -EINVAL; + } + + page_offset = start - ALIGN_DOWN(start, PAGE_SIZE); + from_this_page = PAGE_SIZE - page_offset; + + if (from_this_page < from_this_cache_entry) { + ctx = NULL; + } else { + /* + * In the case they are equal the next line has no practical effect, + * but it's better to do a register to register copy than a conditional + * branch. + */ + from_this_page = from_this_cache_entry; + ctx = cache_entry; + } + + ret = sdma_txadd_page(pq->dd, ctx, &tx->txreq, + cache_entry->pages[page_index], + page_offset, from_this_page); + if (ret) { + /* + * When there's a failure, the entire request is freed by + * user_sdma_send_pkts(). + */ + SDMA_DBG(req, + "sdma_txadd_page failed %d page_index %lu page_offset %u from_this_page %u", + ret, page_index, page_offset, from_this_page); + return ret; + } + start += from_this_page; + from_this_cache_entry -= from_this_page; + } + return 0; +} + +static int add_system_iovec_to_sdma_packet(struct user_sdma_request *req, + struct user_sdma_txreq *tx, + struct user_sdma_iovec *iovec, + size_t from_this_iovec) +{ + struct mmu_rb_handler *handler = req->pq->handler; + + while (from_this_iovec > 0) { + struct sdma_mmu_node *cache_entry; + size_t from_this_cache_entry; + size_t start; + int ret; + + start = (uintptr_t)iovec->iov.iov_base + iovec->offset; + ret = get_system_cache_entry(req, &cache_entry, start, + from_this_iovec); + if (ret) { + SDMA_DBG(req, "pin system segment failed %d", ret); + return ret; + } + + from_this_cache_entry = cache_entry->rb.len - (start - cache_entry->rb.addr); + if (from_this_cache_entry > from_this_iovec) + from_this_cache_entry = from_this_iovec; + + ret = add_mapping_to_sdma_packet(req, tx, cache_entry, start, + from_this_cache_entry); + if (ret) { + /* + * We're guaranteed that there will be no descriptor + * completion callback that releases this node + * because only the last descriptor referencing it + * has a context attached, and a failure means the + * last descriptor was never added. + */ + release_node(handler, cache_entry); + SDMA_DBG(req, "add system segment failed %d", ret); + return ret; + } + + iovec->offset += from_this_cache_entry; + from_this_iovec -= from_this_cache_entry; + } + + return 0; +} + +static int add_system_pages_to_sdma_packet(struct user_sdma_request *req, + struct user_sdma_txreq *tx, + struct user_sdma_iovec *iovec, + u32 *pkt_data_remaining) +{ + size_t remaining_to_add = *pkt_data_remaining; + /* + * Walk through iovec entries, ensure the associated pages + * are pinned and mapped, add data to the packet until no more + * data remains to be added. + */ + while (remaining_to_add > 0) { + struct user_sdma_iovec *cur_iovec; + size_t from_this_iovec; + int ret; + + cur_iovec = iovec; + from_this_iovec = iovec->iov.iov_len - iovec->offset; + + if (from_this_iovec > remaining_to_add) { + from_this_iovec = remaining_to_add; + } else { + /* The current iovec entry will be consumed by this pass. */ + req->iov_idx++; + iovec++; + } + + ret = add_system_iovec_to_sdma_packet(req, tx, cur_iovec, + from_this_iovec); + if (ret) + return ret; + + remaining_to_add -= from_this_iovec; + } + *pkt_data_remaining = remaining_to_add; + + return 0; +} + +void system_descriptor_complete(struct hfi1_devdata *dd, + struct sdma_desc *descp) +{ + switch (sdma_mapping_type(descp)) { + case SDMA_MAP_SINGLE: + dma_unmap_single(&dd->pcidev->dev, sdma_mapping_addr(descp), + sdma_mapping_len(descp), DMA_TO_DEVICE); + break; + case SDMA_MAP_PAGE: + dma_unmap_page(&dd->pcidev->dev, sdma_mapping_addr(descp), + sdma_mapping_len(descp), DMA_TO_DEVICE); + break; + } + + if (descp->pinning_ctx) { + struct sdma_mmu_node *node = descp->pinning_ctx; + + release_node(node->rb.handler, node); + } +} + static bool sdma_rb_filter(struct mmu_rb_node *node, unsigned long addr, unsigned long len) { @@ -1493,8 +1666,7 @@ static void sdma_rb_remove(void *arg, struct mmu_rb_node *mnode) struct sdma_mmu_node *node = container_of(mnode, struct sdma_mmu_node, rb); - unpin_sdma_pages(node); - kfree(node); + free_system_node(node); } static int sdma_rb_invalidate(void *arg, struct mmu_rb_node *mnode) diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index ea56eb57e656..a241836371dc 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h @@ -112,16 +112,11 @@ struct sdma_mmu_node { struct user_sdma_iovec { struct list_head list; struct iovec iov; - /* number of pages in this vector */ - unsigned int npages; - /* array of pinned pages for this vector */ - struct page **pages; /* * offset into the virtual address space of the vector at * which we last left off. */ u64 offset; - struct sdma_mmu_node *node; }; /* evict operation argument */ diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 7f6d7fc7951d..fbdcfecb1768 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -778,8 +778,8 @@ static int build_verbs_tx_desc( /* add icrc, lt byte, and padding to flit */ if (extra_bytes) - ret = sdma_txadd_daddr(sde->dd, &tx->txreq, - sde->dd->sdma_pad_phys, extra_bytes); + ret = sdma_txadd_daddr(sde->dd, &tx->txreq, sde->dd->sdma_pad_phys, + extra_bytes); bail_txadd: return ret; diff --git a/drivers/infiniband/hw/hfi1/vnic_sdma.c b/drivers/infiniband/hw/hfi1/vnic_sdma.c index c3f0f8d877c3..727eedfba332 100644 --- a/drivers/infiniband/hw/hfi1/vnic_sdma.c +++ b/drivers/infiniband/hw/hfi1/vnic_sdma.c @@ -64,6 +64,7 @@ static noinline int build_vnic_ulp_payload(struct sdma_engine *sde, /* combine physically continuous fragments later? */ ret = sdma_txadd_page(sde->dd, + NULL, &tx->txreq, skb_frag_page(frag), skb_frag_off(frag), diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index dbf97fe5948f..d4c6b9bc0a4e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1960,100 +1960,6 @@ static int hns_roce_v2_set_bt(struct hns_roce_dev *hr_dev) return hns_roce_cmq_send(hr_dev, &desc, 1); } -/* Use default caps when hns_roce_query_pf_caps() failed or init VF profile */ -static void set_default_caps(struct hns_roce_dev *hr_dev) -{ - struct hns_roce_caps *caps = &hr_dev->caps; - - caps->num_qps = HNS_ROCE_V2_MAX_QP_NUM; - caps->max_wqes = HNS_ROCE_V2_MAX_WQE_NUM; - caps->num_cqs = HNS_ROCE_V2_MAX_CQ_NUM; - caps->num_srqs = HNS_ROCE_V2_MAX_SRQ_NUM; - caps->min_cqes = HNS_ROCE_MIN_CQE_NUM; - caps->max_cqes = HNS_ROCE_V2_MAX_CQE_NUM; - caps->max_sq_sg = HNS_ROCE_V2_MAX_SQ_SGE_NUM; - caps->max_rq_sg = HNS_ROCE_V2_MAX_RQ_SGE_NUM; - - caps->num_uars = HNS_ROCE_V2_UAR_NUM; - caps->phy_num_uars = HNS_ROCE_V2_PHY_UAR_NUM; - caps->num_aeq_vectors = HNS_ROCE_V2_AEQE_VEC_NUM; - caps->num_other_vectors = HNS_ROCE_V2_ABNORMAL_VEC_NUM; - caps->num_comp_vectors = 0; - - caps->num_mtpts = HNS_ROCE_V2_MAX_MTPT_NUM; - caps->num_pds = HNS_ROCE_V2_MAX_PD_NUM; - caps->qpc_timer_bt_num = HNS_ROCE_V2_MAX_QPC_TIMER_BT_NUM; - caps->cqc_timer_bt_num = HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM; - - caps->max_qp_init_rdma = HNS_ROCE_V2_MAX_QP_INIT_RDMA; - caps->max_qp_dest_rdma = HNS_ROCE_V2_MAX_QP_DEST_RDMA; - caps->max_sq_desc_sz = HNS_ROCE_V2_MAX_SQ_DESC_SZ; - caps->max_rq_desc_sz = HNS_ROCE_V2_MAX_RQ_DESC_SZ; - caps->irrl_entry_sz = HNS_ROCE_V2_IRRL_ENTRY_SZ; - caps->trrl_entry_sz = HNS_ROCE_V2_EXT_ATOMIC_TRRL_ENTRY_SZ; - caps->cqc_entry_sz = HNS_ROCE_V2_CQC_ENTRY_SZ; - caps->srqc_entry_sz = HNS_ROCE_V2_SRQC_ENTRY_SZ; - caps->mtpt_entry_sz = HNS_ROCE_V2_MTPT_ENTRY_SZ; - caps->idx_entry_sz = HNS_ROCE_V2_IDX_ENTRY_SZ; - caps->page_size_cap = HNS_ROCE_V2_PAGE_SIZE_SUPPORTED; - caps->reserved_lkey = 0; - caps->reserved_pds = 0; - caps->reserved_mrws = 1; - caps->reserved_uars = 0; - caps->reserved_cqs = 0; - caps->reserved_srqs = 0; - caps->reserved_qps = HNS_ROCE_V2_RSV_QPS; - - caps->qpc_hop_num = HNS_ROCE_CONTEXT_HOP_NUM; - caps->srqc_hop_num = HNS_ROCE_CONTEXT_HOP_NUM; - caps->cqc_hop_num = HNS_ROCE_CONTEXT_HOP_NUM; - caps->mpt_hop_num = HNS_ROCE_CONTEXT_HOP_NUM; - caps->sccc_hop_num = HNS_ROCE_SCCC_HOP_NUM; - - caps->mtt_hop_num = HNS_ROCE_MTT_HOP_NUM; - caps->wqe_sq_hop_num = HNS_ROCE_SQWQE_HOP_NUM; - caps->wqe_sge_hop_num = HNS_ROCE_EXT_SGE_HOP_NUM; - caps->wqe_rq_hop_num = HNS_ROCE_RQWQE_HOP_NUM; - caps->cqe_hop_num = HNS_ROCE_CQE_HOP_NUM; - caps->srqwqe_hop_num = HNS_ROCE_SRQWQE_HOP_NUM; - caps->idx_hop_num = HNS_ROCE_IDX_HOP_NUM; - caps->chunk_sz = HNS_ROCE_V2_TABLE_CHUNK_SIZE; - - caps->flags = HNS_ROCE_CAP_FLAG_REREG_MR | - HNS_ROCE_CAP_FLAG_ROCE_V1_V2 | - HNS_ROCE_CAP_FLAG_CQ_RECORD_DB | - HNS_ROCE_CAP_FLAG_QP_RECORD_DB; - - caps->pkey_table_len[0] = 1; - caps->ceqe_depth = HNS_ROCE_V2_COMP_EQE_NUM; - caps->aeqe_depth = HNS_ROCE_V2_ASYNC_EQE_NUM; - caps->local_ca_ack_delay = 0; - caps->max_mtu = IB_MTU_4096; - - caps->max_srq_wrs = HNS_ROCE_V2_MAX_SRQ_WR; - caps->max_srq_sges = HNS_ROCE_V2_MAX_SRQ_SGE; - - caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC | HNS_ROCE_CAP_FLAG_MW | - HNS_ROCE_CAP_FLAG_SRQ | HNS_ROCE_CAP_FLAG_FRMR | - HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL; - - caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM; - - if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) { - caps->flags |= HNS_ROCE_CAP_FLAG_STASH | - HNS_ROCE_CAP_FLAG_DIRECT_WQE | - HNS_ROCE_CAP_FLAG_XRC; - caps->max_sq_inline = HNS_ROCE_V3_MAX_SQ_INLINE; - } else { - caps->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INLINE; - - /* The following configuration are only valid for HIP08 */ - caps->qpc_sz = HNS_ROCE_V2_QPC_SZ; - caps->sccc_sz = HNS_ROCE_V2_SCCC_SZ; - caps->cqe_sz = HNS_ROCE_V2_CQE_SIZE; - } -} - static void calc_pg_sz(u32 obj_num, u32 obj_size, u32 hop_num, u32 ctx_bt_num, u32 *buf_page_size, u32 *bt_page_size, u32 hem_type) { @@ -2239,7 +2145,7 @@ static void apply_func_caps(struct hns_roce_dev *hr_dev) set_hem_page_size(hr_dev); } -static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) +static int hns_roce_query_caps(struct hns_roce_dev *hr_dev) { struct hns_roce_cmq_desc desc[HNS_ROCE_QUERY_PF_CAPS_CMD_NUM]; struct hns_roce_caps *caps = &hr_dev->caps; @@ -2248,15 +2154,17 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) struct hns_roce_query_pf_caps_c *resp_c; struct hns_roce_query_pf_caps_d *resp_d; struct hns_roce_query_pf_caps_e *resp_e; + enum hns_roce_opcode_type cmd; int ctx_hop_num; int pbl_hop_num; int ret; int i; + cmd = hr_dev->is_vf ? HNS_ROCE_OPC_QUERY_VF_CAPS_NUM : + HNS_ROCE_OPC_QUERY_PF_CAPS_NUM; + for (i = 0; i < HNS_ROCE_QUERY_PF_CAPS_CMD_NUM; i++) { - hns_roce_cmq_setup_basic_desc(&desc[i], - HNS_ROCE_OPC_QUERY_PF_CAPS_NUM, - true); + hns_roce_cmq_setup_basic_desc(&desc[i], cmd, true); if (i < (HNS_ROCE_QUERY_PF_CAPS_CMD_NUM - 1)) desc[i].flag |= cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT); else @@ -2273,35 +2181,33 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) resp_d = (struct hns_roce_query_pf_caps_d *)desc[3].data; resp_e = (struct hns_roce_query_pf_caps_e *)desc[4].data; - caps->local_ca_ack_delay = resp_a->local_ca_ack_delay; - caps->max_sq_sg = le16_to_cpu(resp_a->max_sq_sg); - caps->max_sq_inline = le16_to_cpu(resp_a->max_sq_inline); - caps->max_rq_sg = le16_to_cpu(resp_a->max_rq_sg); + caps->local_ca_ack_delay = resp_a->local_ca_ack_delay; + caps->max_sq_sg = le16_to_cpu(resp_a->max_sq_sg); + caps->max_sq_inline = le16_to_cpu(resp_a->max_sq_inline); + caps->max_rq_sg = le16_to_cpu(resp_a->max_rq_sg); caps->max_rq_sg = roundup_pow_of_two(caps->max_rq_sg); - caps->max_srq_sges = le16_to_cpu(resp_a->max_srq_sges); + caps->max_srq_sges = le16_to_cpu(resp_a->max_srq_sges); caps->max_srq_sges = roundup_pow_of_two(caps->max_srq_sges); - caps->num_aeq_vectors = resp_a->num_aeq_vectors; - caps->num_other_vectors = resp_a->num_other_vectors; - caps->max_sq_desc_sz = resp_a->max_sq_desc_sz; - caps->max_rq_desc_sz = resp_a->max_rq_desc_sz; - caps->cqe_sz = resp_a->cqe_sz; + caps->num_aeq_vectors = resp_a->num_aeq_vectors; + caps->num_other_vectors = resp_a->num_other_vectors; + caps->max_sq_desc_sz = resp_a->max_sq_desc_sz; + caps->max_rq_desc_sz = resp_a->max_rq_desc_sz; - caps->mtpt_entry_sz = resp_b->mtpt_entry_sz; - caps->irrl_entry_sz = resp_b->irrl_entry_sz; - caps->trrl_entry_sz = resp_b->trrl_entry_sz; - caps->cqc_entry_sz = resp_b->cqc_entry_sz; - caps->srqc_entry_sz = resp_b->srqc_entry_sz; - caps->idx_entry_sz = resp_b->idx_entry_sz; - caps->sccc_sz = resp_b->sccc_sz; - caps->max_mtu = resp_b->max_mtu; - caps->qpc_sz = le16_to_cpu(resp_b->qpc_sz); - caps->min_cqes = resp_b->min_cqes; - caps->min_wqes = resp_b->min_wqes; - caps->page_size_cap = le32_to_cpu(resp_b->page_size_cap); - caps->pkey_table_len[0] = resp_b->pkey_table_len; - caps->phy_num_uars = resp_b->phy_num_uars; - ctx_hop_num = resp_b->ctx_hop_num; - pbl_hop_num = resp_b->pbl_hop_num; + caps->mtpt_entry_sz = resp_b->mtpt_entry_sz; + caps->irrl_entry_sz = resp_b->irrl_entry_sz; + caps->trrl_entry_sz = resp_b->trrl_entry_sz; + caps->cqc_entry_sz = resp_b->cqc_entry_sz; + caps->srqc_entry_sz = resp_b->srqc_entry_sz; + caps->idx_entry_sz = resp_b->idx_entry_sz; + caps->sccc_sz = resp_b->sccc_sz; + caps->max_mtu = resp_b->max_mtu; + caps->min_cqes = resp_b->min_cqes; + caps->min_wqes = resp_b->min_wqes; + caps->page_size_cap = le32_to_cpu(resp_b->page_size_cap); + caps->pkey_table_len[0] = resp_b->pkey_table_len; + caps->phy_num_uars = resp_b->phy_num_uars; + ctx_hop_num = resp_b->ctx_hop_num; + pbl_hop_num = resp_b->pbl_hop_num; caps->num_pds = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_PDS); @@ -2324,8 +2230,6 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) caps->ceqe_depth = 1 << hr_reg_read(resp_d, PF_CAPS_D_CEQ_DEPTH); caps->num_comp_vectors = hr_reg_read(resp_d, PF_CAPS_D_NUM_CEQS); caps->aeqe_depth = 1 << hr_reg_read(resp_d, PF_CAPS_D_AEQ_DEPTH); - caps->default_aeq_arm_st = hr_reg_read(resp_d, PF_CAPS_D_AEQ_ARM_ST); - caps->default_ceq_arm_st = hr_reg_read(resp_d, PF_CAPS_D_CEQ_ARM_ST); caps->reserved_pds = hr_reg_read(resp_d, PF_CAPS_D_RSV_PDS); caps->num_uars = 1 << hr_reg_read(resp_d, PF_CAPS_D_NUM_UARS); caps->reserved_qps = hr_reg_read(resp_d, PF_CAPS_D_RSV_QPS); @@ -2336,10 +2240,6 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) caps->reserved_cqs = hr_reg_read(resp_e, PF_CAPS_E_RSV_CQS); caps->reserved_srqs = hr_reg_read(resp_e, PF_CAPS_E_RSV_SRQS); caps->reserved_lkey = hr_reg_read(resp_e, PF_CAPS_E_RSV_LKEYS); - caps->default_ceq_max_cnt = le16_to_cpu(resp_e->ceq_max_cnt); - caps->default_ceq_period = le16_to_cpu(resp_e->ceq_period); - caps->default_aeq_max_cnt = le16_to_cpu(resp_e->aeq_max_cnt); - caps->default_aeq_period = le16_to_cpu(resp_e->aeq_period); caps->qpc_hop_num = ctx_hop_num; caps->sccc_hop_num = ctx_hop_num; @@ -2357,6 +2257,19 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev) if (!(caps->page_size_cap & PAGE_SIZE)) caps->page_size_cap = HNS_ROCE_V2_PAGE_SIZE_SUPPORTED; + if (!hr_dev->is_vf) { + caps->cqe_sz = resp_a->cqe_sz; + caps->qpc_sz = le16_to_cpu(resp_b->qpc_sz); + caps->default_aeq_arm_st = + hr_reg_read(resp_d, PF_CAPS_D_AEQ_ARM_ST); + caps->default_ceq_arm_st = + hr_reg_read(resp_d, PF_CAPS_D_CEQ_ARM_ST); + caps->default_ceq_max_cnt = le16_to_cpu(resp_e->ceq_max_cnt); + caps->default_ceq_period = le16_to_cpu(resp_e->ceq_period); + caps->default_aeq_max_cnt = le16_to_cpu(resp_e->aeq_max_cnt); + caps->default_aeq_period = le16_to_cpu(resp_e->aeq_period); + } + return 0; } @@ -2404,7 +2317,11 @@ static int hns_roce_v2_vf_profile(struct hns_roce_dev *hr_dev) hr_dev->func_num = 1; - set_default_caps(hr_dev); + ret = hns_roce_query_caps(hr_dev); + if (ret) { + dev_err(dev, "failed to query VF caps, ret = %d.\n", ret); + return ret; + } ret = hns_roce_query_vf_resource(hr_dev); if (ret) { @@ -2444,9 +2361,11 @@ static int hns_roce_v2_pf_profile(struct hns_roce_dev *hr_dev) return ret; } - ret = hns_roce_query_pf_caps(hr_dev); - if (ret) - set_default_caps(hr_dev); + ret = hns_roce_query_caps(hr_dev); + if (ret) { + dev_err(dev, "failed to query PF caps, ret = %d.\n", ret); + return ret; + } ret = hns_roce_query_pf_resource(hr_dev); if (ret) { @@ -4664,11 +4583,9 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp, mtu = ib_mtu_enum_to_int(ib_mtu); if (WARN_ON(mtu <= 0)) return -EINVAL; -#define MAX_LP_MSG_LEN 16384 - /* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 16KB */ - lp_pktn_ini = ilog2(MAX_LP_MSG_LEN / mtu); - if (WARN_ON(lp_pktn_ini >= 0xF)) - return -EINVAL; +#define MIN_LP_MSG_LEN 1024 + /* mtu * (2 ^ lp_pktn_ini) should be in the range of 1024 to mtu */ + lp_pktn_ini = ilog2(max(mtu, MIN_LP_MSG_LEN) / mtu); if (attr_mask & IB_QP_PATH_MTU) { hr_reg_write(context, QPC_MTU, ib_mtu); @@ -5093,7 +5010,6 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp, static bool check_qp_timeout_cfg_range(struct hns_roce_dev *hr_dev, u8 *timeout) { #define QP_ACK_TIMEOUT_MAX_HIP08 20 -#define QP_ACK_TIMEOUT_OFFSET 10 #define QP_ACK_TIMEOUT_MAX 31 if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) { @@ -5102,7 +5018,7 @@ static bool check_qp_timeout_cfg_range(struct hns_roce_dev *hr_dev, u8 *timeout) "local ACK timeout shall be 0 to 20.\n"); return false; } - *timeout += QP_ACK_TIMEOUT_OFFSET; + *timeout += HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08; } else if (hr_dev->pci_dev->revision > PCI_REVISION_ID_HIP08) { if (*timeout > QP_ACK_TIMEOUT_MAX) { ibdev_warn(&hr_dev->ib_dev, @@ -5388,6 +5304,18 @@ out: return ret; } +static u8 get_qp_timeout_attr(struct hns_roce_dev *hr_dev, + struct hns_roce_v2_qp_context *context) +{ + u8 timeout; + + timeout = (u8)hr_reg_read(context, QPC_AT); + if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) + timeout -= HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08; + + return timeout; +} + static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) @@ -5465,7 +5393,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, qp_attr->max_dest_rd_atomic = 1 << hr_reg_read(&context, QPC_RR_MAX); qp_attr->min_rnr_timer = (u8)hr_reg_read(&context, QPC_MIN_RNR_TIME); - qp_attr->timeout = (u8)hr_reg_read(&context, QPC_AT); + qp_attr->timeout = get_qp_timeout_attr(hr_dev, &context); qp_attr->retry_cnt = hr_reg_read(&context, QPC_RETRY_NUM_INIT); qp_attr->rnr_retry = hr_reg_read(&context, QPC_RNR_NUM_INIT); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index af9d00225cdf..7033eae2407c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -35,43 +35,17 @@ #include -#define HNS_ROCE_V2_MAX_QP_NUM 0x1000 -#define HNS_ROCE_V2_MAX_WQE_NUM 0x8000 -#define HNS_ROCE_V2_MAX_SRQ_WR 0x8000 -#define HNS_ROCE_V2_MAX_SRQ_SGE 64 -#define HNS_ROCE_V2_MAX_CQ_NUM 0x100000 -#define HNS_ROCE_V2_MAX_QPC_TIMER_BT_NUM 0x100 -#define HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM 0x100 -#define HNS_ROCE_V2_MAX_SRQ_NUM 0x100000 -#define HNS_ROCE_V2_MAX_CQE_NUM 0x400000 -#define HNS_ROCE_V2_MAX_RQ_SGE_NUM 64 -#define HNS_ROCE_V2_MAX_SQ_SGE_NUM 64 -#define HNS_ROCE_V2_MAX_SQ_INLINE 0x20 -#define HNS_ROCE_V3_MAX_SQ_INLINE 0x400 #define HNS_ROCE_V2_MAX_RC_INL_INN_SZ 32 -#define HNS_ROCE_V2_UAR_NUM 256 -#define HNS_ROCE_V2_PHY_UAR_NUM 1 +#define HNS_ROCE_V2_MTT_ENTRY_SZ 64 #define HNS_ROCE_V2_AEQE_VEC_NUM 1 #define HNS_ROCE_V2_ABNORMAL_VEC_NUM 1 -#define HNS_ROCE_V2_MAX_MTPT_NUM 0x100000 #define HNS_ROCE_V2_MAX_SRQWQE_SEGS 0x1000000 #define HNS_ROCE_V2_MAX_IDX_SEGS 0x1000000 -#define HNS_ROCE_V2_MAX_PD_NUM 0x1000000 #define HNS_ROCE_V2_MAX_XRCD_NUM 0x1000000 #define HNS_ROCE_V2_RSV_XRCD_NUM 0 -#define HNS_ROCE_V2_MAX_QP_INIT_RDMA 128 -#define HNS_ROCE_V2_MAX_QP_DEST_RDMA 128 -#define HNS_ROCE_V2_MAX_SQ_DESC_SZ 64 -#define HNS_ROCE_V2_MAX_RQ_DESC_SZ 16 -#define HNS_ROCE_V2_IRRL_ENTRY_SZ 64 -#define HNS_ROCE_V2_EXT_ATOMIC_TRRL_ENTRY_SZ 100 -#define HNS_ROCE_V2_CQC_ENTRY_SZ 64 -#define HNS_ROCE_V2_SRQC_ENTRY_SZ 64 -#define HNS_ROCE_V2_MTPT_ENTRY_SZ 64 -#define HNS_ROCE_V2_MTT_ENTRY_SZ 64 -#define HNS_ROCE_V2_IDX_ENTRY_SZ 4 -#define HNS_ROCE_V2_SCCC_SZ 32 +#define HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08 10 + #define HNS_ROCE_V3_SCCC_SZ 64 #define HNS_ROCE_V3_GMV_ENTRY_SZ 32 @@ -232,6 +206,7 @@ enum hns_roce_opcode_type { HNS_ROCE_OPC_QUERY_FUNC_INFO = 0x8407, HNS_ROCE_OPC_QUERY_PF_CAPS_NUM = 0x8408, HNS_ROCE_OPC_CFG_ENTRY_SIZE = 0x8409, + HNS_ROCE_OPC_QUERY_VF_CAPS_NUM = 0x8410, HNS_ROCE_OPC_CFG_SGID_TB = 0x8500, HNS_ROCE_OPC_CFG_SMAC_TB = 0x8501, HNS_ROCE_OPC_POST_MB = 0x8504, diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 37a5cf62f88b..14376490ac22 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -33,6 +33,7 @@ #include #include +#include #include "hns_roce_device.h" #include "hns_roce_cmd.h" #include "hns_roce_hem.h" @@ -909,6 +910,44 @@ static int mtr_init_buf_cfg(struct hns_roce_dev *hr_dev, return page_cnt; } +static u64 cal_pages_per_l1ba(unsigned int ba_per_bt, unsigned int hopnum) +{ + return int_pow(ba_per_bt, hopnum - 1); +} + +static unsigned int cal_best_bt_pg_sz(struct hns_roce_dev *hr_dev, + struct hns_roce_mtr *mtr, + unsigned int pg_shift) +{ + unsigned long cap = hr_dev->caps.page_size_cap; + struct hns_roce_buf_region *re; + unsigned int pgs_per_l1ba; + unsigned int ba_per_bt; + unsigned int ba_num; + int i; + + for_each_set_bit_from(pg_shift, &cap, sizeof(cap) * BITS_PER_BYTE) { + if (!(BIT(pg_shift) & cap)) + continue; + + ba_per_bt = BIT(pg_shift) / BA_BYTE_LEN; + ba_num = 0; + for (i = 0; i < mtr->hem_cfg.region_count; i++) { + re = &mtr->hem_cfg.region[i]; + if (re->hopnum == 0) + continue; + + pgs_per_l1ba = cal_pages_per_l1ba(ba_per_bt, re->hopnum); + ba_num += DIV_ROUND_UP(re->count, pgs_per_l1ba); + } + + if (ba_num <= ba_per_bt) + return pg_shift; + } + + return 0; +} + static int mtr_alloc_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr, unsigned int ba_page_shift) { @@ -917,6 +956,10 @@ static int mtr_alloc_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr, hns_roce_hem_list_init(&mtr->hem_list); if (!cfg->is_direct) { + ba_page_shift = cal_best_bt_pg_sz(hr_dev, mtr, ba_page_shift); + if (!ba_page_shift) + return -ERANGE; + ret = hns_roce_hem_list_request(hr_dev, &mtr->hem_list, cfg->region, cfg->region_count, ba_page_shift); diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 8817864154af..70009b970e08 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -337,7 +337,7 @@ static struct irdma_puda_buf *irdma_form_ah_cm_frame(struct irdma_cm_node *cm_no pktsize = sizeof(*tcph) + opts_len + hdr_len + pd_len; - memset(buf, 0, pktsize); + memset(buf, 0, sizeof(*tcph)); sqbuf->totallen = pktsize; sqbuf->tcphlen = sizeof(*tcph) + opts_len; diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c index a41e0d21143a..d88c9184007e 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -1867,8 +1867,6 @@ void irdma_sc_vsi_init(struct irdma_sc_vsi *vsi, vsi->mtu = info->params->mtu; vsi->exception_lan_q = info->exception_lan_q; vsi->vsi_idx = info->pf_data_vsi_num; - if (vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) - vsi->fcn_id = info->dev->hmc_fn_id; irdma_set_qos_info(vsi, info->params); for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) { @@ -1887,32 +1885,56 @@ void irdma_sc_vsi_init(struct irdma_sc_vsi *vsi, } /** - * irdma_get_fcn_id - Return the function id + * irdma_get_stats_idx - Return stats index * @vsi: pointer to the vsi */ -static u8 irdma_get_fcn_id(struct irdma_sc_vsi *vsi) +static u8 irdma_get_stats_idx(struct irdma_sc_vsi *vsi) { struct irdma_stats_inst_info stats_info = {}; struct irdma_sc_dev *dev = vsi->dev; - u8 fcn_id = IRDMA_INVALID_FCN_ID; - u8 start_idx, max_stats, i; + u8 i; - if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1) { + if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { if (!irdma_cqp_stats_inst_cmd(vsi, IRDMA_OP_STATS_ALLOCATE, &stats_info)) return stats_info.stats_idx; } - start_idx = 1; - max_stats = 16; - for (i = start_idx; i < max_stats; i++) - if (!dev->fcn_id_array[i]) { - fcn_id = i; - dev->fcn_id_array[i] = true; - break; + for (i = 0; i < IRDMA_MAX_STATS_COUNT_GEN_1; i++) { + if (!dev->stats_idx_array[i]) { + dev->stats_idx_array[i] = true; + return i; } + } - return fcn_id; + return IRDMA_INVALID_STATS_IDX; +} + +/** + * irdma_hw_stats_init_gen1 - Initialize stat reg table used for gen1 + * @vsi: vsi structure where hw_regs are set + * + * Populate the HW stats table + */ +static void irdma_hw_stats_init_gen1(struct irdma_sc_vsi *vsi) +{ + struct irdma_sc_dev *dev = vsi->dev; + const struct irdma_hw_stat_map *map; + u64 *stat_reg = vsi->hw_stats_regs; + u64 *regs = dev->hw_stats_regs; + u16 i, stats_reg_set = vsi->stats_idx; + + map = dev->hw_stats_map; + + /* First 4 stat instances are reserved for port level statistics. */ + stats_reg_set += vsi->stats_inst_alloc ? IRDMA_FIRST_NON_PF_STAT : 0; + + for (i = 0; i < dev->hw_attrs.max_stat_idx; i++) { + if (map[i].bitmask <= IRDMA_MAX_STATS_32) + stat_reg[i] = regs[i] + stats_reg_set * sizeof(u32); + else + stat_reg[i] = regs[i] + stats_reg_set * sizeof(u64); + } } /** @@ -1923,7 +1945,6 @@ static u8 irdma_get_fcn_id(struct irdma_sc_vsi *vsi) int irdma_vsi_stats_init(struct irdma_sc_vsi *vsi, struct irdma_vsi_stats_info *info) { - u8 fcn_id = info->fcn_id; struct irdma_dma_mem *stats_buff_mem; vsi->pestat = info->pestat; @@ -1944,26 +1965,24 @@ int irdma_vsi_stats_init(struct irdma_sc_vsi *vsi, IRDMA_GATHER_STATS_BUF_SIZE); irdma_hw_stats_start_timer(vsi); - if (info->alloc_fcn_id) - fcn_id = irdma_get_fcn_id(vsi); - if (fcn_id == IRDMA_INVALID_FCN_ID) - goto stats_error; - vsi->stats_fcn_id_alloc = info->alloc_fcn_id; - vsi->fcn_id = fcn_id; - if (info->alloc_fcn_id) { - vsi->pestat->gather_info.use_stats_inst = true; - vsi->pestat->gather_info.stats_inst_index = fcn_id; + /* when stat allocation is not required default to fcn_id. */ + vsi->stats_idx = info->fcn_id; + if (info->alloc_stats_inst) { + u8 stats_idx = irdma_get_stats_idx(vsi); + + if (stats_idx != IRDMA_INVALID_STATS_IDX) { + vsi->stats_inst_alloc = true; + vsi->stats_idx = stats_idx; + vsi->pestat->gather_info.use_stats_inst = true; + vsi->pestat->gather_info.stats_inst_index = stats_idx; + } } + if (vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) + irdma_hw_stats_init_gen1(vsi); + return 0; - -stats_error: - dma_free_coherent(vsi->pestat->hw->device, stats_buff_mem->size, - stats_buff_mem->va, stats_buff_mem->pa); - stats_buff_mem->va = NULL; - - return -EIO; } /** @@ -1973,19 +1992,19 @@ stats_error: void irdma_vsi_stats_free(struct irdma_sc_vsi *vsi) { struct irdma_stats_inst_info stats_info = {}; - u8 fcn_id = vsi->fcn_id; struct irdma_sc_dev *dev = vsi->dev; + u8 stats_idx = vsi->stats_idx; - if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1) { - if (vsi->stats_fcn_id_alloc) { - stats_info.stats_idx = vsi->fcn_id; + if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { + if (vsi->stats_inst_alloc) { + stats_info.stats_idx = vsi->stats_idx; irdma_cqp_stats_inst_cmd(vsi, IRDMA_OP_STATS_FREE, &stats_info); } } else { - if (vsi->stats_fcn_id_alloc && - fcn_id < vsi->dev->hw_attrs.max_stat_inst) - vsi->dev->fcn_id_array[fcn_id] = false; + if (vsi->stats_inst_alloc && + stats_idx < vsi->dev->hw_attrs.max_stat_inst) + vsi->dev->stats_idx_array[stats_idx] = false; } if (!vsi->pestat) @@ -5297,7 +5316,8 @@ void sc_vsi_update_stats(struct irdma_sc_vsi *vsi) gather_stats = vsi->pestat->gather_info.gather_stats_va; last_gather_stats = vsi->pestat->gather_info.last_gather_stats_va; irdma_update_stats(&vsi->pestat->hw_stats, gather_stats, - last_gather_stats); + last_gather_stats, vsi->dev->hw_stats_map, + vsi->dev->hw_attrs.max_stat_idx); } /** @@ -5404,186 +5424,62 @@ int irdma_sc_dev_init(enum irdma_vers ver, struct irdma_sc_dev *dev, return ret_code; } +/** + * irdma_stat_val - Extract HW counter value from statistics buffer + * @stats_val: pointer to statistics buffer + * @byteoff: byte offset of counter value in the buffer (8B-aligned) + * @bitoff: bit offset of counter value within 8B entry + * @bitmask: maximum counter value (e.g. 0xffffff for 24-bit counter) + */ +static inline u64 irdma_stat_val(const u64 *stats_val, u16 byteoff, u8 bitoff, + u64 bitmask) +{ + u16 idx = byteoff / sizeof(*stats_val); + + return (stats_val[idx] >> bitoff) & bitmask; +} + +/** + * irdma_stat_delta - Calculate counter delta + * @new_val: updated counter value + * @old_val: last counter value + * @max_val: maximum counter value (e.g. 0xffffff for 24-bit counter) + */ +static inline u64 irdma_stat_delta(u64 new_val, u64 old_val, u64 max_val) +{ + if (new_val >= old_val) + return new_val - old_val; + + /* roll-over case */ + return max_val - old_val + new_val + 1; +} + /** * irdma_update_stats - Update statistics * @hw_stats: hw_stats instance to update * @gather_stats: updated stat counters * @last_gather_stats: last stat counters + * @map: HW stat map (hw_stats => gather_stats) + * @max_stat_idx: number of HW stats */ void irdma_update_stats(struct irdma_dev_hw_stats *hw_stats, struct irdma_gather_stats *gather_stats, - struct irdma_gather_stats *last_gather_stats) + struct irdma_gather_stats *last_gather_stats, + const struct irdma_hw_stat_map *map, u16 max_stat_idx) { - u64 *stats_val = hw_stats->stats_val_32; + u64 *stats_val = hw_stats->stats_val; + u16 i; + + for (i = 0; i < max_stat_idx; i++) { + u64 new_val = irdma_stat_val(gather_stats->val, map[i].byteoff, + map[i].bitoff, map[i].bitmask); + u64 last_val = irdma_stat_val(last_gather_stats->val, + map[i].byteoff, map[i].bitoff, + map[i].bitmask); + + stats_val[i] += + irdma_stat_delta(new_val, last_val, map[i].bitmask); + } - stats_val[IRDMA_HW_STAT_INDEX_RXVLANERR] += - IRDMA_STATS_DELTA(gather_stats->rxvlanerr, - last_gather_stats->rxvlanerr, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP4RXDISCARD] += - IRDMA_STATS_DELTA(gather_stats->ip4rxdiscard, - last_gather_stats->ip4rxdiscard, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP4RXTRUNC] += - IRDMA_STATS_DELTA(gather_stats->ip4rxtrunc, - last_gather_stats->ip4rxtrunc, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] += - IRDMA_STATS_DELTA(gather_stats->ip4txnoroute, - last_gather_stats->ip4txnoroute, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXDISCARD] += - IRDMA_STATS_DELTA(gather_stats->ip6rxdiscard, - last_gather_stats->ip6rxdiscard, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXTRUNC] += - IRDMA_STATS_DELTA(gather_stats->ip6rxtrunc, - last_gather_stats->ip6rxtrunc, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] += - IRDMA_STATS_DELTA(gather_stats->ip6txnoroute, - last_gather_stats->ip6txnoroute, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_TCPRTXSEG] += - IRDMA_STATS_DELTA(gather_stats->tcprtxseg, - last_gather_stats->tcprtxseg, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_TCPRXOPTERR] += - IRDMA_STATS_DELTA(gather_stats->tcprxopterr, - last_gather_stats->tcprxopterr, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_TCPRXPROTOERR] += - IRDMA_STATS_DELTA(gather_stats->tcprxprotoerr, - last_gather_stats->tcprxprotoerr, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED] += - IRDMA_STATS_DELTA(gather_stats->rxrpcnphandled, - last_gather_stats->rxrpcnphandled, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED] += - IRDMA_STATS_DELTA(gather_stats->rxrpcnpignored, - last_gather_stats->rxrpcnpignored, - IRDMA_MAX_STATS_32); - stats_val[IRDMA_HW_STAT_INDEX_TXNPCNPSENT] += - IRDMA_STATS_DELTA(gather_stats->txnpcnpsent, - last_gather_stats->txnpcnpsent, - IRDMA_MAX_STATS_32); - stats_val = hw_stats->stats_val_64; - stats_val[IRDMA_HW_STAT_INDEX_IP4RXOCTS] += - IRDMA_STATS_DELTA(gather_stats->ip4rxocts, - last_gather_stats->ip4rxocts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4RXPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip4rxpkts, - last_gather_stats->ip4rxpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4RXFRAGS] += - IRDMA_STATS_DELTA(gather_stats->ip4txfrag, - last_gather_stats->ip4txfrag, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4RXMCPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip4rxmcpkts, - last_gather_stats->ip4rxmcpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4TXOCTS] += - IRDMA_STATS_DELTA(gather_stats->ip4txocts, - last_gather_stats->ip4txocts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4TXPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip4txpkts, - last_gather_stats->ip4txpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4TXFRAGS] += - IRDMA_STATS_DELTA(gather_stats->ip4txfrag, - last_gather_stats->ip4txfrag, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP4TXMCPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip4txmcpkts, - last_gather_stats->ip4txmcpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXOCTS] += - IRDMA_STATS_DELTA(gather_stats->ip6rxocts, - last_gather_stats->ip6rxocts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip6rxpkts, - last_gather_stats->ip6rxpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXFRAGS] += - IRDMA_STATS_DELTA(gather_stats->ip6txfrags, - last_gather_stats->ip6txfrags, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6RXMCPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip6rxmcpkts, - last_gather_stats->ip6rxmcpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6TXOCTS] += - IRDMA_STATS_DELTA(gather_stats->ip6txocts, - last_gather_stats->ip6txocts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6TXPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip6txpkts, - last_gather_stats->ip6txpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6TXFRAGS] += - IRDMA_STATS_DELTA(gather_stats->ip6txfrags, - last_gather_stats->ip6txfrags, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_IP6TXMCPKTS] += - IRDMA_STATS_DELTA(gather_stats->ip6txmcpkts, - last_gather_stats->ip6txmcpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_TCPRXSEGS] += - IRDMA_STATS_DELTA(gather_stats->tcprxsegs, - last_gather_stats->tcprxsegs, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_TCPTXSEG] += - IRDMA_STATS_DELTA(gather_stats->tcptxsegs, - last_gather_stats->tcptxsegs, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMARXRDS] += - IRDMA_STATS_DELTA(gather_stats->rdmarxrds, - last_gather_stats->rdmarxrds, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMARXSNDS] += - IRDMA_STATS_DELTA(gather_stats->rdmarxsnds, - last_gather_stats->rdmarxsnds, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMARXWRS] += - IRDMA_STATS_DELTA(gather_stats->rdmarxwrs, - last_gather_stats->rdmarxwrs, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMATXRDS] += - IRDMA_STATS_DELTA(gather_stats->rdmatxrds, - last_gather_stats->rdmatxrds, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMATXSNDS] += - IRDMA_STATS_DELTA(gather_stats->rdmatxsnds, - last_gather_stats->rdmatxsnds, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMATXWRS] += - IRDMA_STATS_DELTA(gather_stats->rdmatxwrs, - last_gather_stats->rdmatxwrs, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMAVBND] += - IRDMA_STATS_DELTA(gather_stats->rdmavbn, - last_gather_stats->rdmavbn, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RDMAVINV] += - IRDMA_STATS_DELTA(gather_stats->rdmavinv, - last_gather_stats->rdmavinv, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_UDPRXPKTS] += - IRDMA_STATS_DELTA(gather_stats->udprxpkts, - last_gather_stats->udprxpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_UDPTXPKTS] += - IRDMA_STATS_DELTA(gather_stats->udptxpkts, - last_gather_stats->udptxpkts, - IRDMA_MAX_STATS_48); - stats_val[IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS] += - IRDMA_STATS_DELTA(gather_stats->rxnpecnmrkpkts, - last_gather_stats->rxnpecnmrkpkts, - IRDMA_MAX_STATS_48); memcpy(last_gather_stats, gather_stats, sizeof(*last_gather_stats)); } diff --git a/drivers/infiniband/hw/irdma/defs.h b/drivers/infiniband/hw/irdma/defs.h index c1906cab5c8a..6014b9d06a9b 100644 --- a/drivers/infiniband/hw/irdma/defs.h +++ b/drivers/infiniband/hw/irdma/defs.h @@ -36,6 +36,7 @@ enum irdma_protocol_used { #define IRDMA_QP_STATE_ERROR 6 #define IRDMA_MAX_TRAFFIC_CLASS 8 +#define IRDMA_MAX_STATS_COUNT_GEN_1 12 #define IRDMA_MAX_USER_PRIORITY 8 #define IRDMA_MAX_APPS 8 #define IRDMA_MAX_STATS_COUNT 128 @@ -365,9 +366,11 @@ enum irdma_cqp_op_type { #define FLD_RS_32(dev, val, field) \ ((u64)((val) & (dev)->hw_masks[field ## _M]) >> (dev)->hw_shifts[field ## _S]) -#define IRDMA_STATS_DELTA(a, b, c) ((a) >= (b) ? (a) - (b) : (a) + (c) - (b)) -#define IRDMA_MAX_STATS_32 0xFFFFFFFFULL -#define IRDMA_MAX_STATS_48 0xFFFFFFFFFFFFULL +#define IRDMA_MAX_STATS_24 0xffffffULL +#define IRDMA_MAX_STATS_32 0xffffffffULL +#define IRDMA_MAX_STATS_48 0xffffffffffffULL +#define IRDMA_MAX_STATS_56 0xffffffffffffffULL +#define IRDMA_MAX_STATS_64 0xffffffffffffffffULL #define IRDMA_MAX_CQ_READ_THRESH 0x3FFFF #define IRDMA_CQPSQ_QHASH_VLANID GENMASK_ULL(43, 32) diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c index 43dfa4761f06..795f7fd4f257 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -1092,14 +1092,19 @@ static int irdma_cfg_ceq_vector(struct irdma_pci_f *rf, struct irdma_ceq *iwceq, int status; if (rf->msix_shared && !ceq_id) { + snprintf(msix_vec->name, sizeof(msix_vec->name) - 1, + "irdma-%s-AEQCEQ-0", dev_name(&rf->pcidev->dev)); tasklet_setup(&rf->dpc_tasklet, irdma_dpc); status = request_irq(msix_vec->irq, irdma_irq_handler, 0, - "AEQCEQ", rf); + msix_vec->name, rf); } else { + snprintf(msix_vec->name, sizeof(msix_vec->name) - 1, + "irdma-%s-CEQ-%d", + dev_name(&rf->pcidev->dev), ceq_id); tasklet_setup(&iwceq->dpc_tasklet, irdma_ceq_dpc); status = request_irq(msix_vec->irq, irdma_ceq_handler, 0, - "CEQ", iwceq); + msix_vec->name, iwceq); } cpumask_clear(&msix_vec->mask); cpumask_set_cpu(msix_vec->cpu_affinity, &msix_vec->mask); @@ -1128,9 +1133,11 @@ static int irdma_cfg_aeq_vector(struct irdma_pci_f *rf) u32 ret = 0; if (!rf->msix_shared) { + snprintf(msix_vec->name, sizeof(msix_vec->name) - 1, + "irdma-%s-AEQ", dev_name(&rf->pcidev->dev)); tasklet_setup(&rf->dpc_tasklet, irdma_dpc); ret = request_irq(msix_vec->irq, irdma_irq_handler, 0, - "irdma", rf); + msix_vec->name, rf); } if (ret) { ibdev_dbg(&rf->iwdev->ibdev, "ERR: aeq irq config fail\n"); @@ -1904,8 +1911,8 @@ int irdma_ctrl_init_hw(struct irdma_pci_f *rf) break; rf->init_state = CEQ0_CREATED; /* Handles processing of CQP completions */ - rf->cqp_cmpl_wq = alloc_ordered_workqueue("cqp_cmpl_wq", - WQ_HIGHPRI | WQ_UNBOUND); + rf->cqp_cmpl_wq = + alloc_ordered_workqueue("cqp_cmpl_wq", WQ_HIGHPRI); if (!rf->cqp_cmpl_wq) { status = -ENOMEM; break; diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.c b/drivers/infiniband/hw/irdma/i40iw_hw.c index 50299f58b6b3..37a40fb4d0d7 100644 --- a/drivers/infiniband/hw/irdma/i40iw_hw.c +++ b/drivers/infiniband/hw/irdma/i40iw_hw.c @@ -32,7 +32,7 @@ static u32 i40iw_regs[IRDMA_MAX_REGS] = { 0xffffffff /* PFINT_RATEN not used in FPK */ }; -static u32 i40iw_stat_offsets_32[IRDMA_HW_STAT_INDEX_MAX_32] = { +static u32 i40iw_stat_offsets[] = { I40E_GLPES_PFIP4RXDISCARD(0), I40E_GLPES_PFIP4RXTRUNC(0), I40E_GLPES_PFIP4TXNOROUTE(0), @@ -42,10 +42,8 @@ static u32 i40iw_stat_offsets_32[IRDMA_HW_STAT_INDEX_MAX_32] = { I40E_GLPES_PFTCPRTXSEG(0), I40E_GLPES_PFTCPRXOPTERR(0), I40E_GLPES_PFTCPRXPROTOERR(0), - I40E_GLPES_PFRXVLANERR(0) -}; + I40E_GLPES_PFRXVLANERR(0), -static u32 i40iw_stat_offsets_64[IRDMA_HW_STAT_INDEX_MAX_64] = { I40E_GLPES_PFIP4RXOCTSLO(0), I40E_GLPES_PFIP4RXPKTSLO(0), I40E_GLPES_PFIP4RXFRAGSLO(0), @@ -158,6 +156,51 @@ static const struct irdma_irq_ops i40iw_irq_ops = { .irdma_en_irq = i40iw_ena_irq, }; +static const struct irdma_hw_stat_map i40iw_hw_stat_map[] = { + [IRDMA_HW_STAT_INDEX_RXVLANERR] = { 0, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_IP4RXOCTS] = { 8, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXPKTS] = { 16, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXDISCARD] = { 24, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP4RXTRUNC] = { 32, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP4RXFRAGS] = { 40, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXMCPKTS] = { 48, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXOCTS] = { 56, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXPKTS] = { 64, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXDISCARD] = { 72, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP6RXTRUNC] = { 80, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP6RXFRAGS] = { 88, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXMCPKTS] = { 96, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXOCTS] = { 104, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXPKTS] = { 112, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXFRAGS] = { 120, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXMCPKTS] = { 128, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXOCTS] = { 136, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXPKTS] = { 144, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXFRAGS] = { 152, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXMCPKTS] = { 160, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] = { 168, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] = { 176, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPRXSEGS] = { 184, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_TCPRXOPTERR] = { 192, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPRXPROTOERR] = { 200, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPTXSEG] = { 208, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_TCPRTXSEG] = { 216, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_RDMARXWRS] = { 224, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMARXRDS] = { 232, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMARXSNDS] = { 240, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXWRS] = { 248, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXRDS] = { 256, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXSNDS] = { 264, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMAVBND] = { 272, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMAVINV] = { 280, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXMCOCTS] = { 288, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXMCOCTS] = { 296, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXMCOCTS] = { 304, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXMCOCTS] = { 312, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_UDPRXPKTS] = { 320, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_UDPTXPKTS] = { 328, 0, IRDMA_MAX_STATS_48 }, +}; + void i40iw_init_hw(struct irdma_sc_dev *dev) { int i; @@ -172,11 +215,8 @@ void i40iw_init_hw(struct irdma_sc_dev *dev) dev->hw_regs[i] = (u32 __iomem *)(i40iw_regs[i] + hw_addr); } - for (i = 0; i < IRDMA_HW_STAT_INDEX_MAX_32; ++i) - dev->hw_stats_regs_32[i] = i40iw_stat_offsets_32[i]; - - for (i = 0; i < IRDMA_HW_STAT_INDEX_MAX_64; ++i) - dev->hw_stats_regs_64[i] = i40iw_stat_offsets_64[i]; + for (i = 0; i < IRDMA_HW_STAT_INDEX_MAX_GEN_1; ++i) + dev->hw_stats_regs[i] = i40iw_stat_offsets[i]; dev->hw_attrs.first_hw_vf_fpm_id = I40IW_FIRST_VF_FPM_ID; dev->hw_attrs.max_hw_vf_fpm_id = IRDMA_MAX_VF_FPM_ID; @@ -195,6 +235,7 @@ void i40iw_init_hw(struct irdma_sc_dev *dev) dev->ceq_itr_mask_db = NULL; dev->aeq_itr_mask_db = NULL; dev->irq_ops = &i40iw_irq_ops; + dev->hw_stats_map = i40iw_hw_stat_map; /* Setup the hardware limits, hmc may limit further */ dev->hw_attrs.uk_attrs.max_hw_wq_frags = I40IW_MAX_WQ_FRAGMENT_COUNT; @@ -210,6 +251,7 @@ void i40iw_init_hw(struct irdma_sc_dev *dev) dev->hw_attrs.uk_attrs.max_hw_sq_chunk = I40IW_MAX_QUANTA_PER_WR; dev->hw_attrs.max_hw_pds = I40IW_MAX_PDS; dev->hw_attrs.max_stat_inst = I40IW_MAX_STATS_COUNT; + dev->hw_attrs.max_stat_idx = IRDMA_HW_STAT_INDEX_MAX_GEN_1; dev->hw_attrs.max_hw_outbound_msg_size = I40IW_MAX_OUTBOUND_MSG_SIZE; dev->hw_attrs.max_hw_inbound_msg_size = I40IW_MAX_INBOUND_MSG_SIZE; dev->hw_attrs.max_qp_wr = I40IW_MAX_QP_WRS; diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.c b/drivers/infiniband/hw/irdma/icrdma_hw.c index 5986fd906308..298d14905993 100644 --- a/drivers/infiniband/hw/irdma/icrdma_hw.c +++ b/drivers/infiniband/hw/irdma/icrdma_hw.c @@ -111,6 +111,55 @@ static const struct irdma_irq_ops icrdma_irq_ops = { .irdma_en_irq = icrdma_ena_irq, }; +static const struct irdma_hw_stat_map icrdma_hw_stat_map[] = { + [IRDMA_HW_STAT_INDEX_RXVLANERR] = { 0, 32, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_IP4RXOCTS] = { 8, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXPKTS] = { 16, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXDISCARD] = { 24, 32, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP4RXTRUNC] = { 24, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP4RXFRAGS] = { 32, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXMCOCTS] = { 40, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4RXMCPKTS] = { 48, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXOCTS] = { 56, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXPKTS] = { 64, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXDISCARD] = { 72, 32, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP6RXTRUNC] = { 72, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_IP6RXFRAGS] = { 80, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXMCOCTS] = { 88, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6RXMCPKTS] = { 96, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXOCTS] = { 104, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXPKTS] = { 112, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXFRAGS] = { 120, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXMCOCTS] = { 128, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXMCPKTS] = { 136, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXOCTS] = { 144, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXPKTS] = { 152, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXFRAGS] = { 160, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXMCOCTS] = { 168, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP6TXMCPKTS] = { 176, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] = { 184, 32, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] = { 184, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPRXSEGS] = { 192, 32, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_TCPRXOPTERR] = { 200, 32, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPRXPROTOERR] = { 200, 0, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_TCPTXSEG] = { 208, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_TCPRTXSEG] = { 216, 32, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_UDPRXPKTS] = { 224, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_UDPTXPKTS] = { 232, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMARXWRS] = { 240, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMARXRDS] = { 248, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMARXSNDS] = { 256, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXWRS] = { 264, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXRDS] = { 272, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMATXSNDS] = { 280, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMAVBND] = { 288, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RDMAVINV] = { 296, 0, IRDMA_MAX_STATS_48 }, + [IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS] = { 304, 0, IRDMA_MAX_STATS_56 }, + [IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED] = { 312, 32, IRDMA_MAX_STATS_24 }, + [IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED] = { 312, 0, IRDMA_MAX_STATS_32 }, + [IRDMA_HW_STAT_INDEX_TXNPCNPSENT] = { 320, 0, IRDMA_MAX_STATS_32 }, +}; + void icrdma_init_hw(struct irdma_sc_dev *dev) { int i; @@ -140,9 +189,11 @@ void icrdma_init_hw(struct irdma_sc_dev *dev) dev->cq_ack_db = dev->hw_regs[IRDMA_CQACK]; dev->irq_ops = &icrdma_irq_ops; dev->hw_attrs.page_size_cap = SZ_4K | SZ_2M | SZ_1G; + dev->hw_stats_map = icrdma_hw_stat_map; dev->hw_attrs.max_hw_ird = ICRDMA_MAX_IRD_SIZE; dev->hw_attrs.max_hw_ord = ICRDMA_MAX_ORD_SIZE; dev->hw_attrs.max_stat_inst = ICRDMA_MAX_STATS_COUNT; + dev->hw_attrs.max_stat_idx = IRDMA_HW_STAT_INDEX_MAX_GEN_2; dev->hw_attrs.uk_attrs.max_hw_sq_chunk = IRDMA_MAX_QUANTA_PER_WR; dev->hw_attrs.uk_attrs.feature_flags |= IRDMA_FEATURE_RTS_AE | diff --git a/drivers/infiniband/hw/irdma/irdma.h b/drivers/infiniband/hw/irdma/irdma.h index 4789e85d717b..173e2dc2fc35 100644 --- a/drivers/infiniband/hw/irdma/irdma.h +++ b/drivers/infiniband/hw/irdma/irdma.h @@ -147,6 +147,7 @@ struct irdma_hw_attrs { u32 max_sleep_count; u32 max_cqp_compl_wait_time_ms; u16 max_stat_inst; + u16 max_stat_idx; }; void i40iw_init_hw(struct irdma_sc_dev *dev); diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h index 65e966ad3453..def6dd58dcd4 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -115,6 +115,8 @@ extern struct auxiliary_driver i40iw_auxiliary_drv; #define IRDMA_REFLUSH BIT(2) #define IRDMA_FLUSH_WAIT BIT(3) +#define IRDMA_IRQ_NAME_STR_LEN (64) + enum init_completion_state { INVALID_STATE = 0, INITIAL_STATE, @@ -212,6 +214,7 @@ struct irdma_msix_vector { u32 cpu_affinity; u32 ceq_id; cpumask_t mask; + char name[IRDMA_IRQ_NAME_STR_LEN]; }; struct irdma_mc_table_info { diff --git a/drivers/infiniband/hw/irdma/pble.c b/drivers/infiniband/hw/irdma/pble.c index cdc0b8a6ed48..c0bef11436b9 100644 --- a/drivers/infiniband/hw/irdma/pble.c +++ b/drivers/infiniband/hw/irdma/pble.c @@ -423,15 +423,15 @@ static int get_lvl1_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, * get_lvl1_lvl2_pble - calls get_lvl1 and get_lvl2 pble routine * @pble_rsrc: pble resources * @palloc: contains all inforamtion regarding pble (idx + pble addr) - * @level1_only: flag for a level 1 PBLE + * @lvl: Bitmask for requested pble level */ static int get_lvl1_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, - struct irdma_pble_alloc *palloc, bool level1_only) + struct irdma_pble_alloc *palloc, u8 lvl) { int status = 0; status = get_lvl1_pble(pble_rsrc, palloc); - if (!status || level1_only || palloc->total_cnt <= PBLE_PER_PAGE) + if (!status || lvl == PBLE_LEVEL_1 || palloc->total_cnt <= PBLE_PER_PAGE) return status; status = get_lvl2_pble(pble_rsrc, palloc); @@ -444,11 +444,11 @@ static int get_lvl1_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, * @pble_rsrc: pble resources * @palloc: contains all inforamtion regarding pble (idx + pble addr) * @pble_cnt: #of pbles requested - * @level1_only: true if only pble level 1 to acquire + * @lvl: requested pble level mask */ int irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, struct irdma_pble_alloc *palloc, u32 pble_cnt, - bool level1_only) + u8 lvl) { int status = 0; int max_sds = 0; @@ -462,7 +462,7 @@ int irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, /*check first to see if we can get pble's without acquiring * additional sd's */ - status = get_lvl1_lvl2_pble(pble_rsrc, palloc, level1_only); + status = get_lvl1_lvl2_pble(pble_rsrc, palloc, lvl); if (!status) goto exit; @@ -472,9 +472,9 @@ int irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, if (status) break; - status = get_lvl1_lvl2_pble(pble_rsrc, palloc, level1_only); + status = get_lvl1_lvl2_pble(pble_rsrc, palloc, lvl); /* if level1_only, only go through it once */ - if (!status || level1_only) + if (!status || lvl) break; } diff --git a/drivers/infiniband/hw/irdma/pble.h b/drivers/infiniband/hw/irdma/pble.h index 29d295463559..b31b7c5d66fe 100644 --- a/drivers/infiniband/hw/irdma/pble.h +++ b/drivers/infiniband/hw/irdma/pble.h @@ -114,7 +114,7 @@ void irdma_free_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, struct irdma_pble_alloc *palloc); int irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc, struct irdma_pble_alloc *palloc, u32 pble_cnt, - bool level1_only); + u8 lvl); int irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm, struct irdma_chunk *pchunk); int irdma_prm_get_pbles(struct irdma_pble_prm *pprm, diff --git a/drivers/infiniband/hw/irdma/protos.h b/drivers/infiniband/hw/irdma/protos.h index 9b6e919ae2a9..113096b60323 100644 --- a/drivers/infiniband/hw/irdma/protos.h +++ b/drivers/infiniband/hw/irdma/protos.h @@ -28,9 +28,7 @@ int irdma_cqp_gather_stats_cmd(struct irdma_sc_dev *dev, void irdma_cqp_gather_stats_gen1(struct irdma_sc_dev *dev, struct irdma_vsi_pestat *pestat); void irdma_hw_stats_read_all(struct irdma_vsi_pestat *stats, - struct irdma_dev_hw_stats *stats_values, - u64 *hw_stats_regs_32, u64 *hw_stats_regs_64, - u8 hw_rev); + const u64 *hw_stats_regs); int irdma_cqp_ws_node_cmd(struct irdma_sc_dev *dev, u8 cmd, struct irdma_ws_node_info *node_info); int irdma_cqp_ceq_cmd(struct irdma_sc_dev *dev, struct irdma_sc_ceq *sc_ceq, @@ -43,7 +41,9 @@ u16 irdma_alloc_ws_node_id(struct irdma_sc_dev *dev); void irdma_free_ws_node_id(struct irdma_sc_dev *dev, u16 node_id); void irdma_update_stats(struct irdma_dev_hw_stats *hw_stats, struct irdma_gather_stats *gather_stats, - struct irdma_gather_stats *last_gather_stats); + struct irdma_gather_stats *last_gather_stats, + const struct irdma_hw_stat_map *map, u16 max_stat_idx); + /* vsi functions */ int irdma_vsi_stats_init(struct irdma_sc_vsi *vsi, struct irdma_vsi_stats_info *info); diff --git a/drivers/infiniband/hw/irdma/type.h b/drivers/infiniband/hw/irdma/type.h index 517d41a1c289..5ee68604e59f 100644 --- a/drivers/infiniband/hw/irdma/type.h +++ b/drivers/infiniband/hw/irdma/type.h @@ -101,7 +101,8 @@ enum irdma_qp_event_type { IRDMA_QP_EVENT_REQ_ERR, }; -enum irdma_hw_stats_index_32b { +enum irdma_hw_stats_index { + /* gen1 - 32-bit */ IRDMA_HW_STAT_INDEX_IP4RXDISCARD = 0, IRDMA_HW_STAT_INDEX_IP4RXTRUNC = 1, IRDMA_HW_STAT_INDEX_IP4TXNOROUTE = 2, @@ -111,50 +112,48 @@ enum irdma_hw_stats_index_32b { IRDMA_HW_STAT_INDEX_TCPRTXSEG = 6, IRDMA_HW_STAT_INDEX_TCPRXOPTERR = 7, IRDMA_HW_STAT_INDEX_TCPRXPROTOERR = 8, - IRDMA_HW_STAT_INDEX_MAX_32_GEN_1 = 9, /* Must be same value as next entry */ IRDMA_HW_STAT_INDEX_RXVLANERR = 9, - IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED = 10, - IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED = 11, - IRDMA_HW_STAT_INDEX_TXNPCNPSENT = 12, - IRDMA_HW_STAT_INDEX_MAX_32, /* Must be last entry */ -}; - -enum irdma_hw_stats_index_64b { - IRDMA_HW_STAT_INDEX_IP4RXOCTS = 0, - IRDMA_HW_STAT_INDEX_IP4RXPKTS = 1, - IRDMA_HW_STAT_INDEX_IP4RXFRAGS = 2, - IRDMA_HW_STAT_INDEX_IP4RXMCPKTS = 3, - IRDMA_HW_STAT_INDEX_IP4TXOCTS = 4, - IRDMA_HW_STAT_INDEX_IP4TXPKTS = 5, - IRDMA_HW_STAT_INDEX_IP4TXFRAGS = 6, - IRDMA_HW_STAT_INDEX_IP4TXMCPKTS = 7, - IRDMA_HW_STAT_INDEX_IP6RXOCTS = 8, - IRDMA_HW_STAT_INDEX_IP6RXPKTS = 9, - IRDMA_HW_STAT_INDEX_IP6RXFRAGS = 10, - IRDMA_HW_STAT_INDEX_IP6RXMCPKTS = 11, - IRDMA_HW_STAT_INDEX_IP6TXOCTS = 12, - IRDMA_HW_STAT_INDEX_IP6TXPKTS = 13, - IRDMA_HW_STAT_INDEX_IP6TXFRAGS = 14, - IRDMA_HW_STAT_INDEX_IP6TXMCPKTS = 15, - IRDMA_HW_STAT_INDEX_TCPRXSEGS = 16, - IRDMA_HW_STAT_INDEX_TCPTXSEG = 17, - IRDMA_HW_STAT_INDEX_RDMARXRDS = 18, - IRDMA_HW_STAT_INDEX_RDMARXSNDS = 19, - IRDMA_HW_STAT_INDEX_RDMARXWRS = 20, - IRDMA_HW_STAT_INDEX_RDMATXRDS = 21, - IRDMA_HW_STAT_INDEX_RDMATXSNDS = 22, - IRDMA_HW_STAT_INDEX_RDMATXWRS = 23, - IRDMA_HW_STAT_INDEX_RDMAVBND = 24, - IRDMA_HW_STAT_INDEX_RDMAVINV = 25, - IRDMA_HW_STAT_INDEX_MAX_64_GEN_1 = 26, /* Must be same value as next entry */ - IRDMA_HW_STAT_INDEX_IP4RXMCOCTS = 26, - IRDMA_HW_STAT_INDEX_IP4TXMCOCTS = 27, - IRDMA_HW_STAT_INDEX_IP6RXMCOCTS = 28, - IRDMA_HW_STAT_INDEX_IP6TXMCOCTS = 29, - IRDMA_HW_STAT_INDEX_UDPRXPKTS = 30, - IRDMA_HW_STAT_INDEX_UDPTXPKTS = 31, - IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS = 32, - IRDMA_HW_STAT_INDEX_MAX_64, /* Must be last entry */ + /* gen1 - 64-bit */ + IRDMA_HW_STAT_INDEX_IP4RXOCTS = 10, + IRDMA_HW_STAT_INDEX_IP4RXPKTS = 11, + IRDMA_HW_STAT_INDEX_IP4RXFRAGS = 12, + IRDMA_HW_STAT_INDEX_IP4RXMCPKTS = 13, + IRDMA_HW_STAT_INDEX_IP4TXOCTS = 14, + IRDMA_HW_STAT_INDEX_IP4TXPKTS = 15, + IRDMA_HW_STAT_INDEX_IP4TXFRAGS = 16, + IRDMA_HW_STAT_INDEX_IP4TXMCPKTS = 17, + IRDMA_HW_STAT_INDEX_IP6RXOCTS = 18, + IRDMA_HW_STAT_INDEX_IP6RXPKTS = 19, + IRDMA_HW_STAT_INDEX_IP6RXFRAGS = 20, + IRDMA_HW_STAT_INDEX_IP6RXMCPKTS = 21, + IRDMA_HW_STAT_INDEX_IP6TXOCTS = 22, + IRDMA_HW_STAT_INDEX_IP6TXPKTS = 23, + IRDMA_HW_STAT_INDEX_IP6TXFRAGS = 24, + IRDMA_HW_STAT_INDEX_IP6TXMCPKTS = 25, + IRDMA_HW_STAT_INDEX_TCPRXSEGS = 26, + IRDMA_HW_STAT_INDEX_TCPTXSEG = 27, + IRDMA_HW_STAT_INDEX_RDMARXRDS = 28, + IRDMA_HW_STAT_INDEX_RDMARXSNDS = 29, + IRDMA_HW_STAT_INDEX_RDMARXWRS = 30, + IRDMA_HW_STAT_INDEX_RDMATXRDS = 31, + IRDMA_HW_STAT_INDEX_RDMATXSNDS = 32, + IRDMA_HW_STAT_INDEX_RDMATXWRS = 33, + IRDMA_HW_STAT_INDEX_RDMAVBND = 34, + IRDMA_HW_STAT_INDEX_RDMAVINV = 35, + IRDMA_HW_STAT_INDEX_IP4RXMCOCTS = 36, + IRDMA_HW_STAT_INDEX_IP4TXMCOCTS = 37, + IRDMA_HW_STAT_INDEX_IP6RXMCOCTS = 38, + IRDMA_HW_STAT_INDEX_IP6TXMCOCTS = 39, + IRDMA_HW_STAT_INDEX_UDPRXPKTS = 40, + IRDMA_HW_STAT_INDEX_UDPTXPKTS = 41, + IRDMA_HW_STAT_INDEX_MAX_GEN_1 = 42, /* Must be same value as next entry */ + /* gen2 - 64-bit */ + IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS = 42, + /* gen2 - 32-bit */ + IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED = 43, + IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED = 44, + IRDMA_HW_STAT_INDEX_TXNPCNPSENT = 45, + IRDMA_HW_STAT_INDEX_MAX_GEN_2 = 46, }; enum irdma_feature_type { @@ -274,65 +273,21 @@ struct irdma_cq_shadow_area { }; struct irdma_dev_hw_stats_offsets { - u32 stats_offset_32[IRDMA_HW_STAT_INDEX_MAX_32]; - u32 stats_offset_64[IRDMA_HW_STAT_INDEX_MAX_64]; + u32 stats_offset[IRDMA_HW_STAT_INDEX_MAX_GEN_1]; }; struct irdma_dev_hw_stats { - u64 stats_val_32[IRDMA_HW_STAT_INDEX_MAX_32]; - u64 stats_val_64[IRDMA_HW_STAT_INDEX_MAX_64]; + u64 stats_val[IRDMA_GATHER_STATS_BUF_SIZE / sizeof(u64)]; }; struct irdma_gather_stats { - u32 rsvd1; - u32 rxvlanerr; - u64 ip4rxocts; - u64 ip4rxpkts; - u32 ip4rxtrunc; - u32 ip4rxdiscard; - u64 ip4rxfrags; - u64 ip4rxmcocts; - u64 ip4rxmcpkts; - u64 ip6rxocts; - u64 ip6rxpkts; - u32 ip6rxtrunc; - u32 ip6rxdiscard; - u64 ip6rxfrags; - u64 ip6rxmcocts; - u64 ip6rxmcpkts; - u64 ip4txocts; - u64 ip4txpkts; - u64 ip4txfrag; - u64 ip4txmcocts; - u64 ip4txmcpkts; - u64 ip6txocts; - u64 ip6txpkts; - u64 ip6txfrags; - u64 ip6txmcocts; - u64 ip6txmcpkts; - u32 ip6txnoroute; - u32 ip4txnoroute; - u64 tcprxsegs; - u32 tcprxprotoerr; - u32 tcprxopterr; - u64 tcptxsegs; - u32 rsvd2; - u32 tcprtxseg; - u64 udprxpkts; - u64 udptxpkts; - u64 rdmarxwrs; - u64 rdmarxrds; - u64 rdmarxsnds; - u64 rdmatxwrs; - u64 rdmatxrds; - u64 rdmatxsnds; - u64 rdmavbn; - u64 rdmavinv; - u64 rxnpecnmrkpkts; - u32 rxrpcnphandled; - u32 rxrpcnpignored; - u32 txnpcnpsent; - u32 rsvd3[88]; + u64 val[IRDMA_GATHER_STATS_BUF_SIZE / sizeof(u64)]; +}; + +struct irdma_hw_stat_map { + u16 byteoff; + u8 bitoff; + u64 bitmask; }; struct irdma_stats_gather_info { @@ -584,7 +539,7 @@ struct irdma_qos { bool valid; }; -#define IRDMA_INVALID_FCN_ID 0xff +#define IRDMA_INVALID_STATS_IDX 0xff struct irdma_sc_vsi { u16 vsi_idx; struct irdma_sc_dev *dev; @@ -598,11 +553,9 @@ struct irdma_sc_vsi { u32 exception_lan_q; u16 mtu; u16 vm_id; - u8 fcn_id; enum irdma_vm_vf_type vm_vf_type; - bool stats_fcn_id_alloc:1; + bool stats_inst_alloc:1; bool tc_change_pending:1; - struct irdma_qos qos[IRDMA_MAX_USER_PRIORITY]; struct irdma_vsi_pestat *pestat; atomic_t qp_suspend_reqs; int (*register_qset)(struct irdma_sc_vsi *vsi, @@ -611,14 +564,17 @@ struct irdma_sc_vsi { struct irdma_ws_node *tc_node); u8 qos_rel_bw; u8 qos_prio_type; + u8 stats_idx; u8 dscp_map[IIDC_MAX_DSCP_MAPPING]; + struct irdma_qos qos[IRDMA_MAX_USER_PRIORITY]; + u64 hw_stats_regs[IRDMA_HW_STAT_INDEX_MAX_GEN_1]; bool dscp_mode:1; }; struct irdma_sc_dev { struct list_head cqp_cmd_head; /* head of the CQP command list */ spinlock_t cqp_lock; /* protect CQP list access */ - bool fcn_id_array[IRDMA_MAX_STATS_COUNT]; + bool stats_idx_array[IRDMA_MAX_STATS_COUNT_GEN_1]; struct irdma_dma_mem vf_fpm_query_buf[IRDMA_MAX_PE_ENA_VF_COUNT]; u64 fpm_query_buf_pa; u64 fpm_commit_buf_pa; @@ -637,8 +593,8 @@ struct irdma_sc_dev { u32 ceq_itr; /* Interrupt throttle, usecs between interrupts: 0 disabled. 2 - 8160 */ u64 hw_masks[IRDMA_MAX_MASKS]; u64 hw_shifts[IRDMA_MAX_SHIFTS]; - u64 hw_stats_regs_32[IRDMA_HW_STAT_INDEX_MAX_32]; - u64 hw_stats_regs_64[IRDMA_HW_STAT_INDEX_MAX_64]; + const struct irdma_hw_stat_map *hw_stats_map; + u64 hw_stats_regs[IRDMA_HW_STAT_INDEX_MAX_GEN_1]; u64 feature_info[IRDMA_MAX_FEATURES]; u64 cqp_cmd_stats[IRDMA_MAX_CQP_OPS]; struct irdma_hw_attrs hw_attrs; @@ -763,7 +719,7 @@ struct irdma_vsi_init_info { struct irdma_vsi_stats_info { struct irdma_vsi_pestat *pestat; u8 fcn_id; - bool alloc_fcn_id; + bool alloc_stats_inst; }; struct irdma_device_init_info { diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index 7887230c867b..71e1c5d34709 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -1634,10 +1634,10 @@ static void irdma_hw_stats_timeout(struct timer_list *t) from_timer(pf_devstat, t, stats_timer); struct irdma_sc_vsi *sc_vsi = pf_devstat->vsi; - if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) - irdma_cqp_gather_stats_gen1(sc_vsi->dev, sc_vsi->pestat); - else + if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) irdma_cqp_gather_stats_cmd(sc_vsi->dev, sc_vsi->pestat, false); + else + irdma_cqp_gather_stats_gen1(sc_vsi->dev, sc_vsi->pestat); mod_timer(&pf_devstat->stats_timer, jiffies + msecs_to_jiffies(STATS_TIMER_DELAY)); @@ -1686,164 +1686,28 @@ void irdma_cqp_gather_stats_gen1(struct irdma_sc_dev *dev, { struct irdma_gather_stats *gather_stats = pestat->gather_info.gather_stats_va; + const struct irdma_hw_stat_map *map = dev->hw_stats_map; + u16 max_stats_idx = dev->hw_attrs.max_stat_idx; u32 stats_inst_offset_32; u32 stats_inst_offset_64; + u64 new_val; + u16 i; stats_inst_offset_32 = (pestat->gather_info.use_stats_inst) ? - pestat->gather_info.stats_inst_index : - pestat->hw->hmc.hmc_fn_id; + pestat->gather_info.stats_inst_index : + pestat->hw->hmc.hmc_fn_id; stats_inst_offset_32 *= 4; stats_inst_offset_64 = stats_inst_offset_32 * 2; - gather_stats->rxvlanerr = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_RXVLANERR] - + stats_inst_offset_32); - gather_stats->ip4rxdiscard = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4RXDISCARD] - + stats_inst_offset_32); - gather_stats->ip4rxtrunc = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4RXTRUNC] - + stats_inst_offset_32); - gather_stats->ip4txnoroute = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] - + stats_inst_offset_32); - gather_stats->ip6rxdiscard = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6RXDISCARD] - + stats_inst_offset_32); - gather_stats->ip6rxtrunc = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6RXTRUNC] - + stats_inst_offset_32); - gather_stats->ip6txnoroute = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] - + stats_inst_offset_32); - gather_stats->tcprtxseg = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_TCPRTXSEG] - + stats_inst_offset_32); - gather_stats->tcprxopterr = - rd32(dev->hw, - dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_TCPRXOPTERR] - + stats_inst_offset_32); - - gather_stats->ip4rxocts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXOCTS] - + stats_inst_offset_64); - gather_stats->ip4rxpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXPKTS] - + stats_inst_offset_64); - gather_stats->ip4txfrag = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXFRAGS] - + stats_inst_offset_64); - gather_stats->ip4rxmcpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXMCPKTS] - + stats_inst_offset_64); - gather_stats->ip4txocts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXOCTS] - + stats_inst_offset_64); - gather_stats->ip4txpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXPKTS] - + stats_inst_offset_64); - gather_stats->ip4txfrag = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXFRAGS] - + stats_inst_offset_64); - gather_stats->ip4txmcpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXMCPKTS] - + stats_inst_offset_64); - gather_stats->ip6rxocts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXOCTS] - + stats_inst_offset_64); - gather_stats->ip6rxpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXPKTS] - + stats_inst_offset_64); - gather_stats->ip6txfrags = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXFRAGS] - + stats_inst_offset_64); - gather_stats->ip6rxmcpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXMCPKTS] - + stats_inst_offset_64); - gather_stats->ip6txocts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXOCTS] - + stats_inst_offset_64); - gather_stats->ip6txpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXPKTS] - + stats_inst_offset_64); - gather_stats->ip6txfrags = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXFRAGS] - + stats_inst_offset_64); - gather_stats->ip6txmcpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXMCPKTS] - + stats_inst_offset_64); - gather_stats->tcprxsegs = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_TCPRXSEGS] - + stats_inst_offset_64); - gather_stats->tcptxsegs = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_TCPTXSEG] - + stats_inst_offset_64); - gather_stats->rdmarxrds = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXRDS] - + stats_inst_offset_64); - gather_stats->rdmarxsnds = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXSNDS] - + stats_inst_offset_64); - gather_stats->rdmarxwrs = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXWRS] - + stats_inst_offset_64); - gather_stats->rdmatxrds = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXRDS] - + stats_inst_offset_64); - gather_stats->rdmatxsnds = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXSNDS] - + stats_inst_offset_64); - gather_stats->rdmatxwrs = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXWRS] - + stats_inst_offset_64); - gather_stats->rdmavbn = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMAVBND] - + stats_inst_offset_64); - gather_stats->rdmavinv = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMAVINV] - + stats_inst_offset_64); - gather_stats->udprxpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_UDPRXPKTS] - + stats_inst_offset_64); - gather_stats->udptxpkts = - rd64(dev->hw, - dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_UDPTXPKTS] - + stats_inst_offset_64); + for (i = 0; i < max_stats_idx; i++) { + if (map[i].bitmask <= IRDMA_MAX_STATS_32) + new_val = rd32(dev->hw, + dev->hw_stats_regs[i] + stats_inst_offset_32); + else + new_val = rd64(dev->hw, + dev->hw_stats_regs[i] + stats_inst_offset_64); + gather_stats->val[map[i].byteoff / sizeof(u64)] = new_val; + } irdma_process_stats(pestat); } diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 1b2e3e800c9a..eaa12c124598 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -522,11 +522,6 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) if (!iwqp->user_mode) cancel_delayed_work_sync(&iwqp->dwork_flush); - irdma_qp_rem_ref(&iwqp->ibqp); - wait_for_completion(&iwqp->free_qp); - irdma_free_lsmm_rsrc(iwqp); - irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp); - if (!iwqp->user_mode) { if (iwqp->iwscq) { irdma_clean_cqes(iwqp, iwqp->iwscq); @@ -534,6 +529,12 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) irdma_clean_cqes(iwqp, iwqp->iwrcq); } } + + irdma_qp_rem_ref(&iwqp->ibqp); + wait_for_completion(&iwqp->free_qp); + irdma_free_lsmm_rsrc(iwqp); + irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp); + irdma_remove_push_mmap_entries(iwqp); irdma_free_qp_rsrc(iwqp); @@ -1226,10 +1227,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, udp_info->ipv4 = false; irdma_copy_ip_ntohl(local_ip, daddr); - udp_info->arp_idx = irdma_arp_table(iwdev->rf, - &local_ip[0], - false, NULL, - IRDMA_ARP_RESOLVE); } else if (av->net_type == RDMA_NETWORK_IPV4) { __be32 saddr = av->sgid_addr.saddr_in.sin_addr.s_addr; __be32 daddr = av->dgid_addr.saddr_in.sin_addr.s_addr; @@ -2329,11 +2326,10 @@ static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc, * irdma_setup_pbles - copy user pg address to pble's * @rf: RDMA PCI function * @iwmr: mr pointer for this memory registration - * @use_pbles: flag if to use pble's - * @lvl_1_only: request only level 1 pble if true + * @lvl: requested pble levels */ static int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr, - bool use_pbles, bool lvl_1_only) + u8 lvl) { struct irdma_pbl *iwpbl = &iwmr->iwpbl; struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc; @@ -2342,9 +2338,9 @@ static int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr, int status; enum irdma_pble_level level = PBLE_LEVEL_1; - if (use_pbles) { + if (lvl) { status = irdma_get_pble(rf->pble_rsrc, palloc, iwmr->page_cnt, - lvl_1_only); + lvl); if (status) return status; @@ -2359,7 +2355,7 @@ static int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr, irdma_copy_user_pgaddrs(iwmr, pbl, level); - if (use_pbles) + if (lvl) iwmr->pgaddrmem[0] = *pbl; return 0; @@ -2370,11 +2366,11 @@ static int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr, * @iwdev: irdma device * @req: information for q memory management * @iwpbl: pble struct - * @use_pbles: flag to use pble + * @lvl: pble level mask */ static int irdma_handle_q_mem(struct irdma_device *iwdev, struct irdma_mem_reg_req *req, - struct irdma_pbl *iwpbl, bool use_pbles) + struct irdma_pbl *iwpbl, u8 lvl) { struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc; struct irdma_mr *iwmr = iwpbl->iwmr; @@ -2387,11 +2383,11 @@ static int irdma_handle_q_mem(struct irdma_device *iwdev, bool ret = true; pg_size = iwmr->page_size; - err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles, true); + err = irdma_setup_pbles(iwdev->rf, iwmr, lvl); if (err) return err; - if (use_pbles) + if (lvl) arr = palloc->level1.addr; switch (iwmr->type) { @@ -2400,7 +2396,7 @@ static int irdma_handle_q_mem(struct irdma_device *iwdev, hmc_p = &qpmr->sq_pbl; qpmr->shadow = (dma_addr_t)arr[total]; - if (use_pbles) { + if (lvl) { ret = irdma_check_mem_contiguous(arr, req->sq_pages, pg_size); if (ret) @@ -2425,7 +2421,7 @@ static int irdma_handle_q_mem(struct irdma_device *iwdev, if (!cqmr->split) cqmr->shadow = (dma_addr_t)arr[req->cq_pages]; - if (use_pbles) + if (lvl) ret = irdma_check_mem_contiguous(arr, req->cq_pages, pg_size); @@ -2439,7 +2435,7 @@ static int irdma_handle_q_mem(struct irdma_device *iwdev, err = -EINVAL; } - if (use_pbles && ret) { + if (lvl && ret) { irdma_free_pble(iwdev->rf->pble_rsrc, palloc); iwpbl->pbl_allocated = false; } @@ -2749,17 +2745,17 @@ static int irdma_reg_user_mr_type_mem(struct irdma_mr *iwmr, int access) { struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device); struct irdma_pbl *iwpbl = &iwmr->iwpbl; - bool use_pbles; u32 stag; + u8 lvl; int err; - use_pbles = iwmr->page_cnt != 1; + lvl = iwmr->page_cnt != 1 ? PBLE_LEVEL_1 | PBLE_LEVEL_2 : PBLE_LEVEL_0; - err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles, false); + err = irdma_setup_pbles(iwdev->rf, iwmr, lvl); if (err) return err; - if (use_pbles) { + if (lvl) { err = irdma_check_mr_contiguous(&iwpbl->pble_alloc, iwmr->page_size); if (err) { @@ -2843,17 +2839,17 @@ static int irdma_reg_user_mr_type_qp(struct irdma_mem_reg_req req, struct irdma_pbl *iwpbl = &iwmr->iwpbl; struct irdma_ucontext *ucontext = NULL; unsigned long flags; - bool use_pbles; u32 total; int err; + u8 lvl; total = req.sq_pages + req.rq_pages + 1; if (total > iwmr->page_cnt) return -EINVAL; total = req.sq_pages + req.rq_pages; - use_pbles = total > 2; - err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles); + lvl = total > 2 ? PBLE_LEVEL_1 : PBLE_LEVEL_0; + err = irdma_handle_q_mem(iwdev, &req, iwpbl, lvl); if (err) return err; @@ -2876,9 +2872,9 @@ static int irdma_reg_user_mr_type_cq(struct irdma_mem_reg_req req, struct irdma_ucontext *ucontext = NULL; u8 shadow_pgcnt = 1; unsigned long flags; - bool use_pbles; u32 total; int err; + u8 lvl; if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_CQ_RESIZE) shadow_pgcnt = 0; @@ -2886,8 +2882,8 @@ static int irdma_reg_user_mr_type_cq(struct irdma_mem_reg_req req, if (total > iwmr->page_cnt) return -EINVAL; - use_pbles = req.cq_pages > 1; - err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles); + lvl = req.cq_pages > 1 ? PBLE_LEVEL_1 : PBLE_LEVEL_0; + err = irdma_handle_q_mem(iwdev, &req, iwpbl, lvl); if (err) return err; @@ -3296,6 +3292,7 @@ static int irdma_post_send(struct ib_qp *ibqp, break; case IB_WR_LOCAL_INV: info.op_type = IRDMA_OP_TYPE_INV_STAG; + info.local_fence = info.read_fence; info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey; err = irdma_uk_stag_local_invalidate(ukqp, &info, true); break; @@ -3708,89 +3705,59 @@ static int irdma_iw_port_immutable(struct ib_device *ibdev, u32 port_num, return 0; } -static const struct rdma_stat_desc irdma_hw_stat_descs[] = { - /* 32bit names */ - [IRDMA_HW_STAT_INDEX_RXVLANERR].name = "rxVlanErrors", - [IRDMA_HW_STAT_INDEX_IP4RXDISCARD].name = "ip4InDiscards", - [IRDMA_HW_STAT_INDEX_IP4RXTRUNC].name = "ip4InTruncatedPkts", - [IRDMA_HW_STAT_INDEX_IP4TXNOROUTE].name = "ip4OutNoRoutes", - [IRDMA_HW_STAT_INDEX_IP6RXDISCARD].name = "ip6InDiscards", - [IRDMA_HW_STAT_INDEX_IP6RXTRUNC].name = "ip6InTruncatedPkts", - [IRDMA_HW_STAT_INDEX_IP6TXNOROUTE].name = "ip6OutNoRoutes", - [IRDMA_HW_STAT_INDEX_TCPRTXSEG].name = "tcpRetransSegs", - [IRDMA_HW_STAT_INDEX_TCPRXOPTERR].name = "tcpInOptErrors", - [IRDMA_HW_STAT_INDEX_TCPRXPROTOERR].name = "tcpInProtoErrors", - [IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED].name = "cnpHandled", - [IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED].name = "cnpIgnored", - [IRDMA_HW_STAT_INDEX_TXNPCNPSENT].name = "cnpSent", +static const struct rdma_stat_desc irdma_hw_stat_names[] = { + /* gen1 - 32-bit */ + [IRDMA_HW_STAT_INDEX_IP4RXDISCARD].name = "ip4InDiscards", + [IRDMA_HW_STAT_INDEX_IP4RXTRUNC].name = "ip4InTruncatedPkts", + [IRDMA_HW_STAT_INDEX_IP4TXNOROUTE].name = "ip4OutNoRoutes", + [IRDMA_HW_STAT_INDEX_IP6RXDISCARD].name = "ip6InDiscards", + [IRDMA_HW_STAT_INDEX_IP6RXTRUNC].name = "ip6InTruncatedPkts", + [IRDMA_HW_STAT_INDEX_IP6TXNOROUTE].name = "ip6OutNoRoutes", + [IRDMA_HW_STAT_INDEX_TCPRTXSEG].name = "tcpRetransSegs", + [IRDMA_HW_STAT_INDEX_TCPRXOPTERR].name = "tcpInOptErrors", + [IRDMA_HW_STAT_INDEX_TCPRXPROTOERR].name = "tcpInProtoErrors", + [IRDMA_HW_STAT_INDEX_RXVLANERR].name = "rxVlanErrors", + /* gen1 - 64-bit */ + [IRDMA_HW_STAT_INDEX_IP4RXOCTS].name = "ip4InOctets", + [IRDMA_HW_STAT_INDEX_IP4RXPKTS].name = "ip4InPkts", + [IRDMA_HW_STAT_INDEX_IP4RXFRAGS].name = "ip4InReasmRqd", + [IRDMA_HW_STAT_INDEX_IP4RXMCPKTS].name = "ip4InMcastPkts", + [IRDMA_HW_STAT_INDEX_IP4TXOCTS].name = "ip4OutOctets", + [IRDMA_HW_STAT_INDEX_IP4TXPKTS].name = "ip4OutPkts", + [IRDMA_HW_STAT_INDEX_IP4TXFRAGS].name = "ip4OutSegRqd", + [IRDMA_HW_STAT_INDEX_IP4TXMCPKTS].name = "ip4OutMcastPkts", + [IRDMA_HW_STAT_INDEX_IP6RXOCTS].name = "ip6InOctets", + [IRDMA_HW_STAT_INDEX_IP6RXPKTS].name = "ip6InPkts", + [IRDMA_HW_STAT_INDEX_IP6RXFRAGS].name = "ip6InReasmRqd", + [IRDMA_HW_STAT_INDEX_IP6RXMCPKTS].name = "ip6InMcastPkts", + [IRDMA_HW_STAT_INDEX_IP6TXOCTS].name = "ip6OutOctets", + [IRDMA_HW_STAT_INDEX_IP6TXPKTS].name = "ip6OutPkts", + [IRDMA_HW_STAT_INDEX_IP6TXFRAGS].name = "ip6OutSegRqd", + [IRDMA_HW_STAT_INDEX_IP6TXMCPKTS].name = "ip6OutMcastPkts", + [IRDMA_HW_STAT_INDEX_TCPRXSEGS].name = "tcpInSegs", + [IRDMA_HW_STAT_INDEX_TCPTXSEG].name = "tcpOutSegs", + [IRDMA_HW_STAT_INDEX_RDMARXRDS].name = "iwInRdmaReads", + [IRDMA_HW_STAT_INDEX_RDMARXSNDS].name = "iwInRdmaSends", + [IRDMA_HW_STAT_INDEX_RDMARXWRS].name = "iwInRdmaWrites", + [IRDMA_HW_STAT_INDEX_RDMATXRDS].name = "iwOutRdmaReads", + [IRDMA_HW_STAT_INDEX_RDMATXSNDS].name = "iwOutRdmaSends", + [IRDMA_HW_STAT_INDEX_RDMATXWRS].name = "iwOutRdmaWrites", + [IRDMA_HW_STAT_INDEX_RDMAVBND].name = "iwRdmaBnd", + [IRDMA_HW_STAT_INDEX_RDMAVINV].name = "iwRdmaInv", + + /* gen2 - 32-bit */ + [IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED].name = "cnpHandled", + [IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED].name = "cnpIgnored", + [IRDMA_HW_STAT_INDEX_TXNPCNPSENT].name = "cnpSent", + /* gen2 - 64-bit */ + [IRDMA_HW_STAT_INDEX_IP4RXMCOCTS].name = "ip4InMcastOctets", + [IRDMA_HW_STAT_INDEX_IP4TXMCOCTS].name = "ip4OutMcastOctets", + [IRDMA_HW_STAT_INDEX_IP6RXMCOCTS].name = "ip6InMcastOctets", + [IRDMA_HW_STAT_INDEX_IP6TXMCOCTS].name = "ip6OutMcastOctets", + [IRDMA_HW_STAT_INDEX_UDPRXPKTS].name = "RxUDP", + [IRDMA_HW_STAT_INDEX_UDPTXPKTS].name = "TxUDP", + [IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS].name = "RxECNMrkd", - /* 64bit names */ - [IRDMA_HW_STAT_INDEX_IP4RXOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4InOctets", - [IRDMA_HW_STAT_INDEX_IP4RXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4InPkts", - [IRDMA_HW_STAT_INDEX_IP4RXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4InReasmRqd", - [IRDMA_HW_STAT_INDEX_IP4RXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4InMcastOctets", - [IRDMA_HW_STAT_INDEX_IP4RXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4InMcastPkts", - [IRDMA_HW_STAT_INDEX_IP4TXOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4OutOctets", - [IRDMA_HW_STAT_INDEX_IP4TXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4OutPkts", - [IRDMA_HW_STAT_INDEX_IP4TXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4OutSegRqd", - [IRDMA_HW_STAT_INDEX_IP4TXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4OutMcastOctets", - [IRDMA_HW_STAT_INDEX_IP4TXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip4OutMcastPkts", - [IRDMA_HW_STAT_INDEX_IP6RXOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6InOctets", - [IRDMA_HW_STAT_INDEX_IP6RXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6InPkts", - [IRDMA_HW_STAT_INDEX_IP6RXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6InReasmRqd", - [IRDMA_HW_STAT_INDEX_IP6RXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6InMcastOctets", - [IRDMA_HW_STAT_INDEX_IP6RXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6InMcastPkts", - [IRDMA_HW_STAT_INDEX_IP6TXOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6OutOctets", - [IRDMA_HW_STAT_INDEX_IP6TXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6OutPkts", - [IRDMA_HW_STAT_INDEX_IP6TXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6OutSegRqd", - [IRDMA_HW_STAT_INDEX_IP6TXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6OutMcastOctets", - [IRDMA_HW_STAT_INDEX_IP6TXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "ip6OutMcastPkts", - [IRDMA_HW_STAT_INDEX_TCPRXSEGS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "tcpInSegs", - [IRDMA_HW_STAT_INDEX_TCPTXSEG + IRDMA_HW_STAT_INDEX_MAX_32].name = - "tcpOutSegs", - [IRDMA_HW_STAT_INDEX_RDMARXRDS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwInRdmaReads", - [IRDMA_HW_STAT_INDEX_RDMARXSNDS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwInRdmaSends", - [IRDMA_HW_STAT_INDEX_RDMARXWRS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwInRdmaWrites", - [IRDMA_HW_STAT_INDEX_RDMATXRDS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwOutRdmaReads", - [IRDMA_HW_STAT_INDEX_RDMATXSNDS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwOutRdmaSends", - [IRDMA_HW_STAT_INDEX_RDMATXWRS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwOutRdmaWrites", - [IRDMA_HW_STAT_INDEX_RDMAVBND + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwRdmaBnd", - [IRDMA_HW_STAT_INDEX_RDMAVINV + IRDMA_HW_STAT_INDEX_MAX_32].name = - "iwRdmaInv", - [IRDMA_HW_STAT_INDEX_UDPRXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "RxUDP", - [IRDMA_HW_STAT_INDEX_UDPTXPKTS + IRDMA_HW_STAT_INDEX_MAX_32].name = - "TxUDP", - [IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS + IRDMA_HW_STAT_INDEX_MAX_32] - .name = "RxECNMrkd", }; static void irdma_get_dev_fw_str(struct ib_device *dev, char *str) @@ -3810,14 +3777,13 @@ static void irdma_get_dev_fw_str(struct ib_device *dev, char *str) static struct rdma_hw_stats *irdma_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num) { - int num_counters = IRDMA_HW_STAT_INDEX_MAX_32 + - IRDMA_HW_STAT_INDEX_MAX_64; + struct irdma_device *iwdev = to_iwdev(ibdev); + struct irdma_sc_dev *dev = &iwdev->rf->sc_dev; + + int num_counters = dev->hw_attrs.max_stat_idx; unsigned long lifespan = RDMA_HW_STATS_DEFAULT_LIFESPAN; - BUILD_BUG_ON(ARRAY_SIZE(irdma_hw_stat_descs) != - (IRDMA_HW_STAT_INDEX_MAX_32 + IRDMA_HW_STAT_INDEX_MAX_64)); - - return rdma_alloc_hw_stats_struct(irdma_hw_stat_descs, num_counters, + return rdma_alloc_hw_stats_struct(irdma_hw_stat_names, num_counters, lifespan); } @@ -3840,7 +3806,7 @@ static int irdma_get_hw_stats(struct ib_device *ibdev, else irdma_cqp_gather_stats_gen1(&iwdev->rf->sc_dev, iwdev->vsi.pestat); - memcpy(&stats->value[0], hw_stats, sizeof(*hw_stats)); + memcpy(&stats->value[0], hw_stats, sizeof(u64) * stats->num_counters); return stats->num_counters; } @@ -4054,7 +4020,7 @@ static int irdma_attach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid) mc_qht_elem->mc_grp_ctx.vlan_id = vlan_id; if (vlan_id < VLAN_N_VID) mc_qht_elem->mc_grp_ctx.vlan_valid = true; - mc_qht_elem->mc_grp_ctx.hmc_fcn_id = iwdev->vsi.fcn_id; + mc_qht_elem->mc_grp_ctx.hmc_fcn_id = iwdev->rf->sc_dev.hmc_fn_id; mc_qht_elem->mc_grp_ctx.qs_handle = iwqp->sc_qp.vsi->qos[iwqp->sc_qp.user_pri].qs_handle; ether_addr_copy(mc_qht_elem->mc_grp_ctx.dest_mac_addr, dmac); diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 884825b2e5f7..456656617c33 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -447,9 +447,13 @@ static int set_user_sq_size(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, struct mlx4_ib_create_qp *ucmd) { + u32 cnt; + /* Sanity check SQ size before proceeding */ - if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes || - ucmd->log_sq_stride > + if (check_shl_overflow(1, ucmd->log_sq_bb_count, &cnt) || + cnt > dev->dev->caps.max_wqes) + return -EINVAL; + if (ucmd->log_sq_stride > ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) || ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE) return -EINVAL; diff --git a/drivers/infiniband/hw/mlx5/counters.c b/drivers/infiniband/hw/mlx5/counters.c index 3e1272695d99..1c06920505d2 100644 --- a/drivers/infiniband/hw/mlx5/counters.c +++ b/drivers/infiniband/hw/mlx5/counters.c @@ -5,6 +5,7 @@ #include "mlx5_ib.h" #include +#include #include "counters.h" #include "ib_rep.h" #include "qp.h" @@ -18,6 +19,10 @@ struct mlx5_ib_counter { #define INIT_Q_COUNTER(_name) \ { .name = #_name, .offset = MLX5_BYTE_OFF(query_q_counter_out, _name)} +#define INIT_VPORT_Q_COUNTER(_name) \ + { .name = "vport_" #_name, .offset = \ + MLX5_BYTE_OFF(query_q_counter_out, _name)} + static const struct mlx5_ib_counter basic_q_cnts[] = { INIT_Q_COUNTER(rx_write_requests), INIT_Q_COUNTER(rx_read_requests), @@ -37,6 +42,25 @@ static const struct mlx5_ib_counter retrans_q_cnts[] = { INIT_Q_COUNTER(local_ack_timeout_err), }; +static const struct mlx5_ib_counter vport_basic_q_cnts[] = { + INIT_VPORT_Q_COUNTER(rx_write_requests), + INIT_VPORT_Q_COUNTER(rx_read_requests), + INIT_VPORT_Q_COUNTER(rx_atomic_requests), + INIT_VPORT_Q_COUNTER(out_of_buffer), +}; + +static const struct mlx5_ib_counter vport_out_of_seq_q_cnts[] = { + INIT_VPORT_Q_COUNTER(out_of_sequence), +}; + +static const struct mlx5_ib_counter vport_retrans_q_cnts[] = { + INIT_VPORT_Q_COUNTER(duplicate_request), + INIT_VPORT_Q_COUNTER(rnr_nak_retry_err), + INIT_VPORT_Q_COUNTER(packet_seq_err), + INIT_VPORT_Q_COUNTER(implied_nak_seq_err), + INIT_VPORT_Q_COUNTER(local_ack_timeout_err), +}; + #define INIT_CONG_COUNTER(_name) \ { .name = #_name, .offset = \ MLX5_BYTE_OFF(query_cong_statistics_out, _name ## _high)} @@ -67,6 +91,25 @@ static const struct mlx5_ib_counter roce_accl_cnts[] = { INIT_Q_COUNTER(roce_slow_restart_trans), }; +static const struct mlx5_ib_counter vport_extended_err_cnts[] = { + INIT_VPORT_Q_COUNTER(resp_local_length_error), + INIT_VPORT_Q_COUNTER(resp_cqe_error), + INIT_VPORT_Q_COUNTER(req_cqe_error), + INIT_VPORT_Q_COUNTER(req_remote_invalid_request), + INIT_VPORT_Q_COUNTER(req_remote_access_errors), + INIT_VPORT_Q_COUNTER(resp_remote_access_errors), + INIT_VPORT_Q_COUNTER(resp_cqe_flush_error), + INIT_VPORT_Q_COUNTER(req_cqe_flush_error), +}; + +static const struct mlx5_ib_counter vport_roce_accl_cnts[] = { + INIT_VPORT_Q_COUNTER(roce_adp_retrans), + INIT_VPORT_Q_COUNTER(roce_adp_retrans_to), + INIT_VPORT_Q_COUNTER(roce_slow_restart), + INIT_VPORT_Q_COUNTER(roce_slow_restart_cnps), + INIT_VPORT_Q_COUNTER(roce_slow_restart_trans), +}; + #define INIT_EXT_PPCNT_COUNTER(_name) \ { .name = #_name, .offset = \ MLX5_BYTE_OFF(ppcnt_reg, \ @@ -153,12 +196,20 @@ static int mlx5_ib_create_counters(struct ib_counters *counters, return 0; } +static bool vport_qcounters_supported(struct mlx5_ib_dev *dev) +{ + return MLX5_CAP_GEN(dev->mdev, q_counter_other_vport) && + MLX5_CAP_GEN(dev->mdev, q_counter_aggregation); +} static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev, u32 port_num) { - return is_mdev_switchdev_mode(dev->mdev) ? &dev->port[0].cnts : - &dev->port[port_num].cnts; + if ((is_mdev_switchdev_mode(dev->mdev) && + !vport_qcounters_supported(dev)) || !port_num) + return &dev->port[0].cnts; + + return &dev->port[port_num - 1].cnts; } /** @@ -172,7 +223,7 @@ static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev, */ u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u32 port_num) { - const struct mlx5_ib_counters *cnts = get_counters(dev, port_num); + const struct mlx5_ib_counters *cnts = get_counters(dev, port_num + 1); return cnts->set_id; } @@ -270,12 +321,44 @@ free: return ret; } +static int mlx5_ib_query_q_counters_vport(struct mlx5_ib_dev *dev, + u32 port_num, + const struct mlx5_ib_counters *cnts, + struct rdma_hw_stats *stats) + +{ + u32 out[MLX5_ST_SZ_DW(query_q_counter_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_q_counter_in)] = {}; + __be32 val; + int ret, i; + + if (!dev->port[port_num].rep || + dev->port[port_num].rep->vport == MLX5_VPORT_UPLINK) + return 0; + + MLX5_SET(query_q_counter_in, in, opcode, MLX5_CMD_OP_QUERY_Q_COUNTER); + MLX5_SET(query_q_counter_in, in, other_vport, 1); + MLX5_SET(query_q_counter_in, in, vport_number, + dev->port[port_num].rep->vport); + MLX5_SET(query_q_counter_in, in, aggregate, 1); + ret = mlx5_cmd_exec_inout(dev->mdev, query_q_counter, in, out); + if (ret) + return ret; + + for (i = 0; i < cnts->num_q_counters; i++) { + val = *(__be32 *)((void *)out + cnts->offsets[i]); + stats->value[i] = (u64)be32_to_cpu(val); + } + + return 0; +} + static int do_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats, u32 port_num, int index) { struct mlx5_ib_dev *dev = to_mdev(ibdev); - const struct mlx5_ib_counters *cnts = get_counters(dev, port_num - 1); + const struct mlx5_ib_counters *cnts = get_counters(dev, port_num); struct mlx5_core_dev *mdev; int ret, num_counters; @@ -286,11 +369,19 @@ static int do_get_hw_stats(struct ib_device *ibdev, cnts->num_cong_counters + cnts->num_ext_ppcnt_counters; - /* q_counters are per IB device, query the master mdev */ - ret = mlx5_ib_query_q_counters(dev->mdev, cnts, stats, cnts->set_id); + if (is_mdev_switchdev_mode(dev->mdev) && dev->is_rep && port_num != 0) + ret = mlx5_ib_query_q_counters_vport(dev, port_num - 1, cnts, + stats); + else + ret = mlx5_ib_query_q_counters(dev->mdev, cnts, stats, + cnts->set_id); if (ret) return ret; + /* We don't expose device counters over Vports */ + if (is_mdev_switchdev_mode(dev->mdev) && port_num != 0) + goto done; + if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { ret = mlx5_ib_query_ext_ppcnt_counters(dev, cnts, stats); if (ret) @@ -335,7 +426,8 @@ static int do_get_op_stat(struct ib_device *ibdev, u32 type; int ret; - cnts = get_counters(dev, port_num - 1); + cnts = get_counters(dev, port_num); + opfcs = cnts->opfcs; type = *(u32 *)cnts->descs[index].priv; if (type >= MLX5_IB_OPCOUNTER_MAX) @@ -362,7 +454,7 @@ static int do_get_op_stats(struct ib_device *ibdev, const struct mlx5_ib_counters *cnts; int index, ret, num_hw_counters; - cnts = get_counters(dev, port_num - 1); + cnts = get_counters(dev, port_num); num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + cnts->num_ext_ppcnt_counters; for (index = num_hw_counters; @@ -383,7 +475,7 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev, struct mlx5_ib_dev *dev = to_mdev(ibdev); const struct mlx5_ib_counters *cnts; - cnts = get_counters(dev, port_num - 1); + cnts = get_counters(dev, port_num); num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + cnts->num_ext_ppcnt_counters; num_counters = num_hw_counters + cnts->num_op_counters; @@ -410,8 +502,7 @@ static struct rdma_hw_stats * mlx5_ib_counter_alloc_stats(struct rdma_counter *counter) { struct mlx5_ib_dev *dev = to_mdev(counter->device); - const struct mlx5_ib_counters *cnts = - get_counters(dev, counter->port - 1); + const struct mlx5_ib_counters *cnts = get_counters(dev, counter->port); return do_alloc_stats(cnts); } @@ -419,8 +510,7 @@ mlx5_ib_counter_alloc_stats(struct rdma_counter *counter) static int mlx5_ib_counter_update_stats(struct rdma_counter *counter) { struct mlx5_ib_dev *dev = to_mdev(counter->device); - const struct mlx5_ib_counters *cnts = - get_counters(dev, counter->port - 1); + const struct mlx5_ib_counters *cnts = get_counters(dev, counter->port); return mlx5_ib_query_q_counters(dev->mdev, cnts, counter->stats, counter->id); @@ -479,44 +569,55 @@ static int mlx5_ib_counter_unbind_qp(struct ib_qp *qp) } static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev, - struct rdma_stat_desc *descs, size_t *offsets) + struct rdma_stat_desc *descs, size_t *offsets, + u32 port_num) { - int i; - int j = 0; + bool is_vport = is_mdev_switchdev_mode(dev->mdev) && + port_num != MLX5_VPORT_PF; + const struct mlx5_ib_counter *names; + int j = 0, i; + names = is_vport ? vport_basic_q_cnts : basic_q_cnts; for (i = 0; i < ARRAY_SIZE(basic_q_cnts); i++, j++) { - descs[j].name = basic_q_cnts[i].name; + descs[j].name = names[i].name; offsets[j] = basic_q_cnts[i].offset; } + names = is_vport ? vport_out_of_seq_q_cnts : out_of_seq_q_cnts; if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) { for (i = 0; i < ARRAY_SIZE(out_of_seq_q_cnts); i++, j++) { - descs[j].name = out_of_seq_q_cnts[i].name; + descs[j].name = names[i].name; offsets[j] = out_of_seq_q_cnts[i].offset; } } + names = is_vport ? vport_retrans_q_cnts : retrans_q_cnts; if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) { for (i = 0; i < ARRAY_SIZE(retrans_q_cnts); i++, j++) { - descs[j].name = retrans_q_cnts[i].name; + descs[j].name = names[i].name; offsets[j] = retrans_q_cnts[i].offset; } } + names = is_vport ? vport_extended_err_cnts : extended_err_cnts; if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) { for (i = 0; i < ARRAY_SIZE(extended_err_cnts); i++, j++) { - descs[j].name = extended_err_cnts[i].name; + descs[j].name = names[i].name; offsets[j] = extended_err_cnts[i].offset; } } + names = is_vport ? vport_roce_accl_cnts : roce_accl_cnts; if (MLX5_CAP_GEN(dev->mdev, roce_accl)) { for (i = 0; i < ARRAY_SIZE(roce_accl_cnts); i++, j++) { - descs[j].name = roce_accl_cnts[i].name; + descs[j].name = names[i].name; offsets[j] = roce_accl_cnts[i].offset; } } + if (is_vport) + return; + if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { for (i = 0; i < ARRAY_SIZE(cong_cnts); i++, j++) { descs[j].name = cong_cnts[i].name; @@ -558,9 +659,9 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev, static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, - struct mlx5_ib_counters *cnts) + struct mlx5_ib_counters *cnts, u32 port_num) { - u32 num_counters, num_op_counters; + u32 num_counters, num_op_counters = 0; num_counters = ARRAY_SIZE(basic_q_cnts); @@ -578,6 +679,9 @@ static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, cnts->num_q_counters = num_counters; + if (is_mdev_switchdev_mode(dev->mdev) && port_num != MLX5_VPORT_PF) + goto skip_non_qcounters; + if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { cnts->num_cong_counters = ARRAY_SIZE(cong_cnts); num_counters += ARRAY_SIZE(cong_cnts); @@ -597,6 +701,7 @@ static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, ft_field_support_2_nic_transmit_rdma.bth_opcode)) num_op_counters += ARRAY_SIZE(rdmatx_cnp_op_cnts); +skip_non_qcounters: cnts->num_op_counters = num_op_counters; num_counters += num_op_counters; cnts->descs = kcalloc(num_counters, @@ -623,7 +728,8 @@ static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) int num_cnt_ports; int i, j; - num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; + num_cnt_ports = (!is_mdev_switchdev_mode(dev->mdev) || + vport_qcounters_supported(dev)) ? dev->num_ports : 1; MLX5_SET(dealloc_q_counter_in, in, opcode, MLX5_CMD_OP_DEALLOC_Q_COUNTER); @@ -662,15 +768,16 @@ static int mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev) MLX5_SET(alloc_q_counter_in, in, opcode, MLX5_CMD_OP_ALLOC_Q_COUNTER); is_shared = MLX5_CAP_GEN(dev->mdev, log_max_uctx) != 0; - num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; + num_cnt_ports = (!is_mdev_switchdev_mode(dev->mdev) || + vport_qcounters_supported(dev)) ? dev->num_ports : 1; for (i = 0; i < num_cnt_ports; i++) { - err = __mlx5_ib_alloc_counters(dev, &dev->port[i].cnts); + err = __mlx5_ib_alloc_counters(dev, &dev->port[i].cnts, i); if (err) goto err_alloc; mlx5_ib_fill_counters(dev, dev->port[i].cnts.descs, - dev->port[i].cnts.offsets); + dev->port[i].cnts.offsets, i); MLX5_SET(alloc_q_counter_in, in, uid, is_shared ? MLX5_SHARED_RESOURCE_UID : 0); @@ -889,6 +996,10 @@ static const struct ib_device_ops hw_stats_ops = { mlx5_ib_modify_stat : NULL, }; +static const struct ib_device_ops hw_switchdev_vport_op = { + .alloc_hw_port_stats = mlx5_ib_alloc_hw_port_stats, +}; + static const struct ib_device_ops hw_switchdev_stats_ops = { .alloc_hw_device_stats = mlx5_ib_alloc_hw_device_stats, .get_hw_stats = mlx5_ib_get_hw_stats, @@ -914,9 +1025,11 @@ int mlx5_ib_counters_init(struct mlx5_ib_dev *dev) if (!MLX5_CAP_GEN(dev->mdev, max_qp_cnt)) return 0; - if (is_mdev_switchdev_mode(dev->mdev)) + if (is_mdev_switchdev_mode(dev->mdev)) { ib_set_device_ops(&dev->ib_dev, &hw_switchdev_stats_ops); - else + if (vport_qcounters_supported(dev)) + ib_set_device_ops(&dev->ib_dev, &hw_switchdev_vport_op); + } else ib_set_device_ops(&dev->ib_dev, &hw_stats_ops); return mlx5_ib_alloc_counters(dev); } diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 2211a0be16f3..db5fb196c728 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -666,7 +666,21 @@ static bool devx_is_valid_obj_id(struct uverbs_attr_bundle *attrs, obj_id; case MLX5_IB_OBJECT_DEVX_OBJ: - return ((struct devx_obj *)uobj->object)->obj_id == obj_id; + { + u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); + struct devx_obj *devx_uobj = uobj->object; + + if (opcode == MLX5_CMD_OP_QUERY_FLOW_COUNTER && + devx_uobj->flow_counter_bulk_size) { + u64 end; + + end = devx_uobj->obj_id + + devx_uobj->flow_counter_bulk_size; + return devx_uobj->obj_id <= obj_id && end > obj_id; + } + + return devx_uobj->obj_id == obj_id; + } default: return false; @@ -1517,10 +1531,17 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)( goto obj_free; if (opcode == MLX5_CMD_OP_ALLOC_FLOW_COUNTER) { - u8 bulk = MLX5_GET(alloc_flow_counter_in, - cmd_in, - flow_counter_bulk); - obj->flow_counter_bulk_size = 128UL * bulk; + u32 bulk = MLX5_GET(alloc_flow_counter_in, + cmd_in, + flow_counter_bulk_log_size); + + if (bulk) + bulk = 1 << bulk; + else + bulk = 128UL * MLX5_GET(alloc_flow_counter_in, + cmd_in, + flow_counter_bulk); + obj->flow_counter_bulk_size = bulk; } uobj->object = obj; @@ -1993,7 +2014,6 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT)( int redirect_fd; bool use_eventfd = false; int num_events; - int num_alloc_xa_entries = 0; u16 obj_type = 0; u64 cookie = 0; u32 obj_id = 0; @@ -2075,7 +2095,6 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_SUBSCRIBE_EVENT)( if (err) goto err; - num_alloc_xa_entries++; event_sub = kzalloc(sizeof(*event_sub), GFP_KERNEL); if (!event_sub) { err = -ENOMEM; diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 67356f515261..2017ede100a6 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -67,11 +67,14 @@ static void set_mkc_access_pd_addr_fields(void *mkc, int acc, u64 start_addr, MLX5_SET(mkc, mkc, lw, !!(acc & IB_ACCESS_LOCAL_WRITE)); MLX5_SET(mkc, mkc, lr, 1); - if ((acc & IB_ACCESS_RELAXED_ORDERING) && - pcie_relaxed_ordering_enabled(dev->mdev->pdev)) { + if (acc & IB_ACCESS_RELAXED_ORDERING) { if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write)) MLX5_SET(mkc, mkc, relaxed_ordering_write, 1); - if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read)) + + if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) || + (MLX5_CAP_GEN(dev->mdev, + relaxed_ordering_read_pci_enabled) && + pcie_relaxed_ordering_enabled(dev->mdev->pdev))) MLX5_SET(mkc, mkc, relaxed_ordering_read, 1); } @@ -791,7 +794,8 @@ static int get_unchangeable_access_flags(struct mlx5_ib_dev *dev, ret |= IB_ACCESS_RELAXED_ORDERING; if ((access_flags & IB_ACCESS_RELAXED_ORDERING) && - MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) && + (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) || + MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_pci_enabled)) && !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr)) ret |= IB_ACCESS_RELAXED_ORDERING; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 7cc3b973dec7..70ca8ffa9256 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -60,6 +60,10 @@ enum raw_qp_set_mask_map { MLX5_RAW_QP_RATE_LIMIT = 1UL << 1, }; +enum { + MLX5_QP_RM_GO_BACK_N = 0x1, +}; + struct mlx5_modify_raw_qp_param { u16 operation; @@ -2519,6 +2523,10 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, 1); + if (qp->flags & IB_QP_CREATE_INTEGRITY_EN && + MLX5_CAP_GEN(mdev, go_back_n)) + MLX5_SET(qpc, qpc, retry_mode, MLX5_QP_RM_GO_BACK_N); + err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out); kvfree(in); if (err) @@ -2846,9 +2854,9 @@ static void process_vendor_flag(struct mlx5_ib_dev *dev, int *flags, int flag, case MLX5_QP_FLAG_SCATTER_CQE: case MLX5_QP_FLAG_ALLOW_SCATTER_CQE: /* - * We don't return error if these flags were provided, - * and mlx5 doesn't have right capability. - */ + * We don't return error if these flags were provided, + * and mlx5 doesn't have right capability. + */ *flags &= ~(MLX5_QP_FLAG_SCATTER_CQE | MLX5_QP_FLAG_ALLOW_SCATTER_CQE); return; @@ -4485,7 +4493,7 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, return -EINVAL; if (attr->port_num == 0 || - attr->port_num > MLX5_CAP_GEN(dev->mdev, num_ports)) { + attr->port_num > dev->num_ports) { mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n", attr->port_num, dev->num_ports); return -EINVAL; @@ -5592,8 +5600,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, if (wq_attr->flags_mask & IB_WQ_FLAGS_CVLAN_STRIPPING) { if (!(MLX5_CAP_GEN(dev->mdev, eth_net_offloads) && MLX5_CAP_ETH(dev->mdev, vlan_cap))) { - mlx5_ib_dbg(dev, "VLAN offloads are not " - "supported\n"); + mlx5_ib_dbg(dev, "VLAN offloads are not supported\n"); err = -EOPNOTSUPP; goto out; } diff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c index 55f4e048d947..234bf30db731 100644 --- a/drivers/infiniband/hw/mlx5/umr.c +++ b/drivers/infiniband/hw/mlx5/umr.c @@ -380,6 +380,10 @@ static void mlx5r_umr_set_access_flags(struct mlx5_ib_dev *dev, struct mlx5_mkey_seg *seg, unsigned int access_flags) { + bool ro_read = (access_flags & IB_ACCESS_RELAXED_ORDERING) && + (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) || + pcie_relaxed_ordering_enabled(dev->mdev->pdev)); + MLX5_SET(mkc, seg, a, !!(access_flags & IB_ACCESS_REMOTE_ATOMIC)); MLX5_SET(mkc, seg, rw, !!(access_flags & IB_ACCESS_REMOTE_WRITE)); MLX5_SET(mkc, seg, rr, !!(access_flags & IB_ACCESS_REMOTE_READ)); @@ -387,8 +391,7 @@ static void mlx5r_umr_set_access_flags(struct mlx5_ib_dev *dev, MLX5_SET(mkc, seg, lr, 1); MLX5_SET(mkc, seg, relaxed_ordering_write, !!(access_flags & IB_ACCESS_RELAXED_ORDERING)); - MLX5_SET(mkc, seg, relaxed_ordering_read, - !!(access_flags & IB_ACCESS_RELAXED_ORDERING)); + MLX5_SET(mkc, seg, relaxed_ordering_read, ro_read); } int mlx5r_umr_rereg_pd_access(struct mlx5_ib_mr *mr, struct ib_pd *pd, diff --git a/drivers/infiniband/hw/mlx5/umr.h b/drivers/infiniband/hw/mlx5/umr.h index c9d0021381a2..3799bb758e49 100644 --- a/drivers/infiniband/hw/mlx5/umr.h +++ b/drivers/infiniband/hw/mlx5/umr.h @@ -62,7 +62,8 @@ static inline bool mlx5r_umr_can_reconfig(struct mlx5_ib_dev *dev, return false; if ((diffs & IB_ACCESS_RELAXED_ORDERING) && - MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) && + (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) || + MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_pci_enabled)) && !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr)) return false; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index dd4021b11963..58f994341e9a 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -1589,7 +1589,6 @@ static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq) { unsigned long cq_flags; unsigned long flags; - int discard_cnt = 0; u32 cur_getp, stop_getp; struct ocrdma_cqe *cqe; u32 qpn = 0, wqe_idx = 0; @@ -1641,7 +1640,6 @@ static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq) /* mark cqe discarded so that it is not picked up later * in the poll_cq(). */ - discard_cnt += 1; cqe->cmn.qpn = 0; skip_cqe: cur_getp = (cur_getp + 1) % cq->max_hw_cqe; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 815ea72ad473..ef85bc8d9384 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -484,7 +484,7 @@ static int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt, const struct qib_tid_info *ti) { int ret = 0; - u32 tid, ctxttid, cnt, limit, tidcnt; + u32 tid, ctxttid, limit, tidcnt; struct qib_devdata *dd = rcd->dd; u64 __iomem *tidbase; unsigned long tidmap[8]; @@ -520,7 +520,7 @@ static int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt, /* just in case size changes in future */ limit = tidcnt; tid = find_first_bit(tidmap, limit); - for (cnt = 0; tid < limit; tid++) { + for (; tid < limit; tid++) { /* * small optimization; if we detect a run of 3 or so without * any set, use find_first_bit again. That's mainly to @@ -530,7 +530,7 @@ static int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt, */ if (!test_bit(tid, tidmap)) continue; - cnt++; + if (dd->pageshadow[ctxttid + tid]) { struct page *p; dma_addr_t phys; @@ -1768,7 +1768,7 @@ static void unlock_expected_tids(struct qib_ctxtdata *rcd) { struct qib_devdata *dd = rcd->dd; int ctxt_tidbase = rcd->ctxt * dd->rcvtidcnt; - int i, cnt = 0, maxtid = ctxt_tidbase + dd->rcvtidcnt; + int i, maxtid = ctxt_tidbase + dd->rcvtidcnt; for (i = ctxt_tidbase; i < maxtid; i++) { struct page *p = dd->pageshadow[i]; @@ -1783,7 +1783,6 @@ static void unlock_expected_tids(struct qib_ctxtdata *rcd) dma_unmap_page(&dd->pcidev->dev, phys, PAGE_SIZE, DMA_FROM_DEVICE); qib_release_user_pages(&p, 1); - cnt++; } } @@ -2326,7 +2325,7 @@ int __init qib_dev_init(void) goto done; } - qib_class = class_create(THIS_MODULE, "ipath"); + qib_class = class_create("ipath"); if (IS_ERR(qib_class)) { ret = PTR_ERR(qib_class); pr_err("Could not create device class (err %d)\n", -ret); diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 692b64efad97..47bf64ace05c 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include "qib.h" @@ -105,13 +104,6 @@ int qib_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); - ret = pci_enable_pcie_error_reporting(pdev); - if (ret) { - qib_early_err(&pdev->dev, - "Unable to enable pcie error reporting: %d\n", - ret); - ret = 0; - } goto done; bail: diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c index 9fe03d6ffac1..336eb15a721f 100644 --- a/drivers/infiniband/hw/qib/qib_user_sdma.c +++ b/drivers/infiniband/hw/qib/qib_user_sdma.c @@ -320,7 +320,6 @@ static int qib_user_sdma_page_to_frags(const struct qib_devdata *dd, unpin_user_page(page); } else { /* coalesce case */ - kunmap(page); __free_page(page); } ret = -ENOMEM; @@ -572,7 +571,7 @@ static int qib_user_sdma_coalesce(const struct qib_devdata *dd, goto done; } - mpage = kmap(page); + mpage = page_address(page); mpage_save = mpage; for (i = 0; i < niov; i++) { int cfur; @@ -581,7 +580,7 @@ static int qib_user_sdma_coalesce(const struct qib_devdata *dd, iov[i].iov_base, iov[i].iov_len); if (cfur) { ret = -EFAULT; - goto free_unmap; + goto page_free; } mpage += iov[i].iov_len; @@ -592,8 +591,7 @@ static int qib_user_sdma_coalesce(const struct qib_devdata *dd, page, 0, 0, len, mpage_save); goto done; -free_unmap: - kunmap(page); +page_free: __free_page(page); done: return ret; @@ -627,9 +625,6 @@ static void qib_user_sdma_free_pkt_frag(struct device *dev, pkt->addr[i].dma_length, DMA_TO_DEVICE); - if (pkt->addr[i].kvaddr) - kunmap(pkt->addr[i].page); - if (pkt->addr[i].put_page) unpin_user_page(pkt->addr[i].page); else diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c index 46653ad56f5a..13b654ddd3cc 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_main.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c @@ -602,7 +602,6 @@ out_clean_vnic: usnic_vnic_free(vf->vnic); out_release_regions: pci_set_drvdata(pdev, NULL); - pci_clear_master(pdev); pci_release_regions(pdev); out_disable_device: pci_disable_device(pdev); @@ -623,7 +622,6 @@ static void usnic_ib_pci_remove(struct pci_dev *pdev) kref_put(&pf->vf_cnt, usnic_ib_undiscover_pf); usnic_vnic_free(vf->vnic); pci_set_drvdata(pdev, NULL); - pci_clear_master(pdev); pci_release_regions(pdev); pci_disable_device(pdev); kfree(vf); diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 9b4c0389d2c0..dc83d0ac6a38 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -464,8 +464,6 @@ void rvt_qp_exit(struct rvt_dev_info *rdi) if (qps_inuse) rvt_pr_err(rdi, "QP memory leak! %u still in use\n", qps_inuse); - if (!rdi->qp_dev) - return; kfree(rdi->qp_dev->qp_table); free_qpn_table(&rdi->qp_dev->qpn_table); @@ -2040,7 +2038,7 @@ static int rvt_post_one_wr(struct rvt_qp *qp, wqe = rvt_get_swqe_ptr(qp, qp->s_head); /* cplen has length from above */ - memcpy(&wqe->wr, wr, cplen); + memcpy(&wqe->ud_wr, wr, cplen); wqe->length = 0; j = 0; diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c index 136c2efe3466..7a7e713de52d 100644 --- a/drivers/infiniband/sw/rxe/rxe.c +++ b/drivers/infiniband/sw/rxe/rxe.c @@ -160,6 +160,8 @@ void rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu) port->attr.active_mtu = mtu; port->mtu_cap = ib_mtu_enum_to_int(mtu); + + rxe_info_dev(rxe, "Set mtu to %d", port->mtu_cap); } /* called by ifc layer to create new rxe device. @@ -175,26 +177,26 @@ int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name) static int rxe_newlink(const char *ibdev_name, struct net_device *ndev) { - struct rxe_dev *exists; + struct rxe_dev *rxe; int err = 0; if (is_vlan_dev(ndev)) { - pr_err("rxe creation allowed on top of a real device only\n"); + rxe_err("rxe creation allowed on top of a real device only"); err = -EPERM; goto err; } - exists = rxe_get_dev_from_net(ndev); - if (exists) { - ib_device_put(&exists->ib_dev); - rxe_dbg(exists, "already configured on %s\n", ndev->name); + rxe = rxe_get_dev_from_net(ndev); + if (rxe) { + ib_device_put(&rxe->ib_dev); + rxe_err_dev(rxe, "already configured on %s", ndev->name); err = -EEXIST; goto err; } err = rxe_net_add(ibdev_name, ndev); if (err) { - rxe_dbg(exists, "failed to add %s\n", ndev->name); + rxe_err("failed to add %s\n", ndev->name); goto err; } err: diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h index 2415f3704f57..d33dd6cf83d3 100644 --- a/drivers/infiniband/sw/rxe/rxe.h +++ b/drivers/infiniband/sw/rxe/rxe.h @@ -38,7 +38,8 @@ #define RXE_ROCE_V2_SPORT (0xc000) -#define rxe_dbg(rxe, fmt, ...) ibdev_dbg(&(rxe)->ib_dev, \ +#define rxe_dbg(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__) +#define rxe_dbg_dev(rxe, fmt, ...) ibdev_dbg(&(rxe)->ib_dev, \ "%s: " fmt, __func__, ##__VA_ARGS__) #define rxe_dbg_uc(uc, fmt, ...) ibdev_dbg((uc)->ibuc.device, \ "uc#%d %s: " fmt, (uc)->elem.index, __func__, ##__VA_ARGS__) @@ -57,6 +58,48 @@ #define rxe_dbg_mw(mw, fmt, ...) ibdev_dbg((mw)->ibmw.device, \ "mw#%d %s: " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err(fmt, ...) pr_err_ratelimited("%s: " fmt "\n", __func__, \ + ##__VA_ARGS__) +#define rxe_err_dev(rxe, fmt, ...) ibdev_err_ratelimited(&(rxe)->ib_dev, \ + "%s: " fmt, __func__, ##__VA_ARGS__) +#define rxe_err_uc(uc, fmt, ...) ibdev_err_ratelimited((uc)->ibuc.device, \ + "uc#%d %s: " fmt, (uc)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_pd(pd, fmt, ...) ibdev_err_ratelimited((pd)->ibpd.device, \ + "pd#%d %s: " fmt, (pd)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_ah(ah, fmt, ...) ibdev_err_ratelimited((ah)->ibah.device, \ + "ah#%d %s: " fmt, (ah)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_srq(srq, fmt, ...) ibdev_err_ratelimited((srq)->ibsrq.device, \ + "srq#%d %s: " fmt, (srq)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_qp(qp, fmt, ...) ibdev_err_ratelimited((qp)->ibqp.device, \ + "qp#%d %s: " fmt, (qp)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_cq(cq, fmt, ...) ibdev_err_ratelimited((cq)->ibcq.device, \ + "cq#%d %s: " fmt, (cq)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_mr(mr, fmt, ...) ibdev_err_ratelimited((mr)->ibmr.device, \ + "mr#%d %s: " fmt, (mr)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_err_mw(mw, fmt, ...) ibdev_err_ratelimited((mw)->ibmw.device, \ + "mw#%d %s: " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__) + +#define rxe_info(fmt, ...) pr_info_ratelimited("%s: " fmt "\n", __func__, \ + ##__VA_ARGS__) +#define rxe_info_dev(rxe, fmt, ...) ibdev_info_ratelimited(&(rxe)->ib_dev, \ + "%s: " fmt, __func__, ##__VA_ARGS__) +#define rxe_info_uc(uc, fmt, ...) ibdev_info_ratelimited((uc)->ibuc.device, \ + "uc#%d %s: " fmt, (uc)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_pd(pd, fmt, ...) ibdev_info_ratelimited((pd)->ibpd.device, \ + "pd#%d %s: " fmt, (pd)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_ah(ah, fmt, ...) ibdev_info_ratelimited((ah)->ibah.device, \ + "ah#%d %s: " fmt, (ah)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_srq(srq, fmt, ...) ibdev_info_ratelimited((srq)->ibsrq.device, \ + "srq#%d %s: " fmt, (srq)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_qp(qp, fmt, ...) ibdev_info_ratelimited((qp)->ibqp.device, \ + "qp#%d %s: " fmt, (qp)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_cq(cq, fmt, ...) ibdev_info_ratelimited((cq)->ibcq.device, \ + "cq#%d %s: " fmt, (cq)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_mr(mr, fmt, ...) ibdev_info_ratelimited((mr)->ibmr.device, \ + "mr#%d %s: " fmt, (mr)->elem.index, __func__, ##__VA_ARGS__) +#define rxe_info_mw(mw, fmt, ...) ibdev_info_ratelimited((mw)->ibmw.device, \ + "mw#%d %s: " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__) + /* responder states */ enum resp_states { RESPST_NONE, @@ -90,7 +133,6 @@ enum resp_states { RESPST_ERR_LENGTH, RESPST_ERR_CQ_OVERFLOW, RESPST_ERROR, - RESPST_RESET, RESPST_DONE, RESPST_EXIT, }; diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index 20737fec392b..f46c5a5fd0ae 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -115,13 +115,16 @@ static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode) void retransmit_timer(struct timer_list *t) { struct rxe_qp *qp = from_timer(qp, t, retrans_timer); + unsigned long flags; rxe_dbg_qp(qp, "retransmit timer fired\n"); + spin_lock_irqsave(&qp->state_lock, flags); if (qp->valid) { qp->comp.timeout = 1; rxe_sched_task(&qp->comp.task); } + spin_unlock_irqrestore(&qp->state_lock, flags); } void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb) @@ -322,7 +325,7 @@ static inline enum comp_state check_ack(struct rxe_qp *qp, qp->comp.psn = pkt->psn; if (qp->req.wait_psn) { qp->req.wait_psn = 0; - rxe_run_task(&qp->req.task); + rxe_sched_task(&qp->req.task); } } return COMPST_ERROR_RETRY; @@ -428,6 +431,10 @@ static void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe, uwc->wc_flags = IB_WC_WITH_IMM; uwc->byte_len = wqe->dma.length; } + } else { + if (wqe->status != IB_WC_WR_FLUSH_ERR) + rxe_err_qp(qp, "non-flush error status = %d", + wqe->status); } } @@ -469,10 +476,35 @@ static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe) */ if (qp->req.wait_fence) { qp->req.wait_fence = 0; - rxe_run_task(&qp->req.task); + rxe_sched_task(&qp->req.task); } } +static void comp_check_sq_drain_done(struct rxe_qp *qp) +{ + unsigned long flags; + + spin_lock_irqsave(&qp->state_lock, flags); + if (unlikely(qp_state(qp) == IB_QPS_SQD)) { + if (qp->attr.sq_draining && qp->comp.psn == qp->req.psn) { + qp->attr.sq_draining = 0; + spin_unlock_irqrestore(&qp->state_lock, flags); + + if (qp->ibqp.event_handler) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_SQ_DRAINED; + qp->ibqp.event_handler(&ev, + qp->ibqp.qp_context); + } + return; + } + } + spin_unlock_irqrestore(&qp->state_lock, flags); +} + static inline enum comp_state complete_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt, struct rxe_send_wqe *wqe) @@ -483,31 +515,11 @@ static inline enum comp_state complete_ack(struct rxe_qp *qp, if (qp->req.need_rd_atomic) { qp->comp.timeout_retry = 0; qp->req.need_rd_atomic = 0; - rxe_run_task(&qp->req.task); + rxe_sched_task(&qp->req.task); } } - if (unlikely(qp->req.state == QP_STATE_DRAIN)) { - /* state_lock used by requester & completer */ - spin_lock_bh(&qp->state_lock); - if ((qp->req.state == QP_STATE_DRAIN) && - (qp->comp.psn == qp->req.psn)) { - qp->req.state = QP_STATE_DRAINED; - spin_unlock_bh(&qp->state_lock); - - if (qp->ibqp.event_handler) { - struct ib_event ev; - - ev.device = qp->ibqp.device; - ev.element.qp = &qp->ibqp; - ev.event = IB_EVENT_SQ_DRAINED; - qp->ibqp.event_handler(&ev, - qp->ibqp.qp_context); - } - } else { - spin_unlock_bh(&qp->state_lock); - } - } + comp_check_sq_drain_done(qp); do_complete(qp, wqe); @@ -538,25 +550,60 @@ static inline enum comp_state complete_wqe(struct rxe_qp *qp, return COMPST_GET_WQE; } -static void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify) +/* drain incoming response packet queue */ +static void drain_resp_pkts(struct rxe_qp *qp) { struct sk_buff *skb; - struct rxe_send_wqe *wqe; - struct rxe_queue *q = qp->sq.queue; while ((skb = skb_dequeue(&qp->resp_pkts))) { rxe_put(qp); kfree_skb(skb); ib_device_put(qp->ibqp.device); } +} + +/* complete send wqe with flush error */ +static int flush_send_wqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe) +{ + struct rxe_cqe cqe = {}; + struct ib_wc *wc = &cqe.ibwc; + struct ib_uverbs_wc *uwc = &cqe.uibwc; + int err; + + if (qp->is_user) { + uwc->wr_id = wqe->wr.wr_id; + uwc->status = IB_WC_WR_FLUSH_ERR; + uwc->qp_num = qp->ibqp.qp_num; + } else { + wc->wr_id = wqe->wr.wr_id; + wc->status = IB_WC_WR_FLUSH_ERR; + wc->qp = &qp->ibqp; + } + + err = rxe_cq_post(qp->scq, &cqe, 0); + if (err) + rxe_dbg_cq(qp->scq, "post cq failed, err = %d", err); + + return err; +} + +/* drain and optionally complete the send queue + * if unable to complete a wqe, i.e. cq is full, stop + * completing and flush the remaining wqes + */ +static void flush_send_queue(struct rxe_qp *qp, bool notify) +{ + struct rxe_send_wqe *wqe; + struct rxe_queue *q = qp->sq.queue; + int err; while ((wqe = queue_head(q, q->type))) { if (notify) { - wqe->status = IB_WC_WR_FLUSH_ERR; - do_complete(qp, wqe); - } else { - queue_advance_consumer(q, q->type); + err = flush_send_wqe(qp, wqe); + if (err) + notify = 0; } + queue_advance_consumer(q, q->type); } } @@ -571,25 +618,49 @@ static void free_pkt(struct rxe_pkt_info *pkt) ib_device_put(dev); } -int rxe_completer(void *arg) +/* reset the retry timer if + * - QP is type RC + * - there is a packet sent by the requester that + * might be acked (we still might get spurious + * timeouts but try to keep them as few as possible) + * - the timeout parameter is set + * - the QP is alive + */ +static void reset_retry_timer(struct rxe_qp *qp) +{ + unsigned long flags; + + if (qp_type(qp) == IB_QPT_RC && qp->qp_timeout_jiffies) { + spin_lock_irqsave(&qp->state_lock, flags); + if (qp_state(qp) >= IB_QPS_RTS && + psn_compare(qp->req.psn, qp->comp.psn) > 0) + mod_timer(&qp->retrans_timer, + jiffies + qp->qp_timeout_jiffies); + spin_unlock_irqrestore(&qp->state_lock, flags); + } +} + +int rxe_completer(struct rxe_qp *qp) { - struct rxe_qp *qp = (struct rxe_qp *)arg; struct rxe_dev *rxe = to_rdev(qp->ibqp.device); struct rxe_send_wqe *wqe = NULL; struct sk_buff *skb = NULL; struct rxe_pkt_info *pkt = NULL; enum comp_state state; int ret; + unsigned long flags; - if (!rxe_get(qp)) - return -EAGAIN; + spin_lock_irqsave(&qp->state_lock, flags); + if (!qp->valid || qp_state(qp) == IB_QPS_ERR || + qp_state(qp) == IB_QPS_RESET) { + bool notify = qp->valid && (qp_state(qp) == IB_QPS_ERR); - if (!qp->valid || qp->comp.state == QP_STATE_ERROR || - qp->comp.state == QP_STATE_RESET) { - rxe_drain_resp_pkts(qp, qp->valid && - qp->comp.state == QP_STATE_ERROR); + drain_resp_pkts(qp); + flush_send_queue(qp, notify); + spin_unlock_irqrestore(&qp->state_lock, flags); goto exit; } + spin_unlock_irqrestore(&qp->state_lock, flags); if (qp->comp.timeout) { qp->comp.timeout_retry = 1; @@ -677,20 +748,7 @@ int rxe_completer(void *arg) break; } - /* re reset the timeout counter if - * (1) QP is type RC - * (2) the QP is alive - * (3) there is a packet sent by the requester that - * might be acked (we still might get spurious - * timeouts but try to keep them as few as possible) - * (4) the timeout parameter is set - */ - if ((qp_type(qp) == IB_QPT_RC) && - (qp->req.state == QP_STATE_READY) && - (psn_compare(qp->req.psn, qp->comp.psn) > 0) && - qp->qp_timeout_jiffies) - mod_timer(&qp->retrans_timer, - jiffies + qp->qp_timeout_jiffies); + reset_retry_timer(qp); goto exit; case COMPST_ERROR_RETRY: @@ -730,7 +788,7 @@ int rxe_completer(void *arg) RXE_CNT_COMP_RETRY); qp->req.need_retry = 1; qp->comp.started_retry = 1; - rxe_run_task(&qp->req.task); + rxe_sched_task(&qp->req.task); } goto done; @@ -752,6 +810,7 @@ int rxe_completer(void *arg) */ qp->req.wait_for_rnr_timer = 1; rxe_dbg_qp(qp, "set rnr nak timer\n"); + // TODO who protects from destroy_qp?? mod_timer(&qp->rnr_nak_timer, jiffies + rnrnak_jiffies(aeth_syn(pkt) & ~AETH_TYPE_MASK)); @@ -784,7 +843,5 @@ exit: out: if (pkt) free_pkt(pkt); - rxe_put(qp); - return ret; } diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c index 1df186534639..20ff0c0c4605 100644 --- a/drivers/infiniband/sw/rxe/rxe_cq.c +++ b/drivers/infiniband/sw/rxe/rxe_cq.c @@ -14,12 +14,12 @@ int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq, int count; if (cqe <= 0) { - rxe_dbg(rxe, "cqe(%d) <= 0\n", cqe); + rxe_dbg_dev(rxe, "cqe(%d) <= 0\n", cqe); goto err1; } if (cqe > rxe->attr.max_cqe) { - rxe_dbg(rxe, "cqe(%d) > max_cqe(%d)\n", + rxe_dbg_dev(rxe, "cqe(%d) > max_cqe(%d)\n", cqe, rxe->attr.max_cqe); goto err1; } @@ -39,21 +39,6 @@ err1: return -EINVAL; } -static void rxe_send_complete(struct tasklet_struct *t) -{ - struct rxe_cq *cq = from_tasklet(cq, t, comp_task); - unsigned long flags; - - spin_lock_irqsave(&cq->cq_lock, flags); - if (cq->is_dying) { - spin_unlock_irqrestore(&cq->cq_lock, flags); - return; - } - spin_unlock_irqrestore(&cq->cq_lock, flags); - - cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); -} - int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, int comp_vector, struct ib_udata *udata, struct rxe_create_cq_resp __user *uresp) @@ -65,7 +50,7 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, cq->queue = rxe_queue_init(rxe, &cqe, sizeof(struct rxe_cqe), type); if (!cq->queue) { - rxe_dbg(rxe, "unable to create cq\n"); + rxe_dbg_dev(rxe, "unable to create cq\n"); return -ENOMEM; } @@ -79,10 +64,6 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, cq->is_user = uresp; - cq->is_dying = false; - - tasklet_setup(&cq->comp_task, rxe_send_complete); - spin_lock_init(&cq->cq_lock); cq->ibcq.cqe = cqe; return 0; @@ -103,6 +84,7 @@ int rxe_cq_resize_queue(struct rxe_cq *cq, int cqe, return err; } +/* caller holds reference to cq */ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited) { struct ib_event ev; @@ -114,6 +96,7 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited) full = queue_full(cq->queue, QUEUE_TYPE_TO_CLIENT); if (unlikely(full)) { + rxe_err_cq(cq, "queue full"); spin_unlock_irqrestore(&cq->cq_lock, flags); if (cq->ibcq.event_handler) { ev.device = cq->ibcq.device; @@ -135,21 +118,13 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited) if ((cq->notify == IB_CQ_NEXT_COMP) || (cq->notify == IB_CQ_SOLICITED && solicited)) { cq->notify = 0; - tasklet_schedule(&cq->comp_task); + + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); } return 0; } -void rxe_cq_disable(struct rxe_cq *cq) -{ - unsigned long flags; - - spin_lock_irqsave(&cq->cq_lock, flags); - cq->is_dying = true; - spin_unlock_irqrestore(&cq->cq_lock, flags); -} - void rxe_cq_cleanup(struct rxe_pool_elem *elem) { struct rxe_cq *cq = container_of(elem, typeof(*cq), elem); diff --git a/drivers/infiniband/sw/rxe/rxe_icrc.c b/drivers/infiniband/sw/rxe/rxe_icrc.c index 71bc2c189588..fdf5f08cd8f1 100644 --- a/drivers/infiniband/sw/rxe/rxe_icrc.c +++ b/drivers/infiniband/sw/rxe/rxe_icrc.c @@ -21,7 +21,7 @@ int rxe_icrc_init(struct rxe_dev *rxe) tfm = crypto_alloc_shash("crc32", 0, 0); if (IS_ERR(tfm)) { - rxe_dbg(rxe, "failed to init crc32 algorithm err: %ld\n", + rxe_dbg_dev(rxe, "failed to init crc32 algorithm err: %ld\n", PTR_ERR(tfm)); return PTR_ERR(tfm); } @@ -51,7 +51,7 @@ static __be32 rxe_crc32(struct rxe_dev *rxe, __be32 crc, void *next, size_t len) *(__be32 *)shash_desc_ctx(shash) = crc; err = crypto_shash_update(shash, next, len); if (unlikely(err)) { - rxe_dbg(rxe, "failed crc calculation, err: %d\n", err); + rxe_dbg_dev(rxe, "failed crc calculation, err: %d\n", err); return (__force __be32)crc32_le((__force u32)crc, next, len); } diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h index 1bb0cb479eb1..804b15e929dd 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -80,7 +80,6 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length); int advance_dma_data(struct rxe_dma_info *dma, unsigned int length); int rxe_invalidate_mr(struct rxe_qp *qp, u32 key); int rxe_reg_fast_mr(struct rxe_qp *qp, struct rxe_send_wqe *wqe); -int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata); void rxe_mr_cleanup(struct rxe_pool_elem *elem); /* rxe_mw.c */ @@ -171,9 +170,9 @@ void rxe_srq_cleanup(struct rxe_pool_elem *elem); void rxe_dealloc(struct ib_device *ib_dev); -int rxe_completer(void *arg); -int rxe_requester(void *arg); -int rxe_responder(void *arg); +int rxe_completer(struct rxe_qp *qp); +int rxe_requester(struct rxe_qp *qp); +int rxe_responder(struct rxe_qp *qp); /* rxe_icrc.c */ int rxe_icrc_init(struct rxe_dev *rxe); diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c index a47d72dbc537..6b7f2bd69879 100644 --- a/drivers/infiniband/sw/rxe/rxe_mmap.c +++ b/drivers/infiniband/sw/rxe/rxe_mmap.c @@ -79,7 +79,7 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) /* Don't allow a mmap larger than the object. */ if (size > ip->info.size) { - rxe_dbg(rxe, "mmap region is larger than the object!\n"); + rxe_dbg_dev(rxe, "mmap region is larger than the object!\n"); spin_unlock_bh(&rxe->pending_lock); ret = -EINVAL; goto done; @@ -87,7 +87,7 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) goto found_it; } - rxe_dbg(rxe, "unable to find pending mmap info\n"); + rxe_dbg_dev(rxe, "unable to find pending mmap info\n"); spin_unlock_bh(&rxe->pending_lock); ret = -EINVAL; goto done; @@ -98,7 +98,7 @@ found_it: ret = remap_vmalloc_range(vma, ip->obj, 0); if (ret) { - rxe_dbg(rxe, "err %d from remap_vmalloc_range\n", ret); + rxe_dbg_dev(rxe, "err %d from remap_vmalloc_range\n", ret); goto done; } diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index b10aa1580a64..0e538fafcc20 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -210,10 +210,10 @@ err1: return err; } -static int rxe_set_page(struct ib_mr *ibmr, u64 iova) +static int rxe_set_page(struct ib_mr *ibmr, u64 dma_addr) { struct rxe_mr *mr = to_rmr(ibmr); - struct page *page = virt_to_page(iova & mr->page_mask); + struct page *page = ib_virt_dma_to_page(dma_addr); bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT); int err; @@ -279,16 +279,16 @@ static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr, return 0; } -static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr, +static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 dma_addr, void *addr, unsigned int length, enum rxe_mr_copy_dir dir) { - unsigned int page_offset = iova & (PAGE_SIZE - 1); + unsigned int page_offset = dma_addr & (PAGE_SIZE - 1); unsigned int bytes; struct page *page; u8 *va; while (length) { - page = virt_to_page(iova & mr->page_mask); + page = ib_virt_dma_to_page(dma_addr); bytes = min_t(unsigned int, length, PAGE_SIZE - page_offset); va = kmap_local_page(page); @@ -300,7 +300,7 @@ static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr, kunmap_local(va); page_offset = 0; - iova += bytes; + dma_addr += bytes; addr += bytes; length -= bytes; } @@ -488,7 +488,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode, if (mr->ibmr.type == IB_MR_TYPE_DMA) { page_offset = iova & (PAGE_SIZE - 1); - page = virt_to_page(iova & PAGE_MASK); + page = ib_virt_dma_to_page(iova); } else { unsigned long index; int err; @@ -545,7 +545,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value) if (mr->ibmr.type == IB_MR_TYPE_DMA) { page_offset = iova & (PAGE_SIZE - 1); - page = virt_to_page(iova & PAGE_MASK); + page = ib_virt_dma_to_page(iova); } else { unsigned long index; int err; @@ -722,19 +722,6 @@ int rxe_reg_fast_mr(struct rxe_qp *qp, struct rxe_send_wqe *wqe) return 0; } -int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) -{ - struct rxe_mr *mr = to_rmr(ibmr); - - /* See IBA 10.6.7.2.6 */ - if (atomic_read(&mr->num_mw) > 0) - return -EINVAL; - - rxe_cleanup(mr); - kfree_rcu(mr); - return 0; -} - void rxe_mr_cleanup(struct rxe_pool_elem *elem) { struct rxe_mr *mr = container_of(elem, typeof(*mr), elem); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index e02e1624bcf4..a38fab19bed1 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -412,12 +412,16 @@ int rxe_xmit_packet(struct rxe_qp *qp, struct rxe_pkt_info *pkt, int err; int is_request = pkt->mask & RXE_REQ_MASK; struct rxe_dev *rxe = to_rdev(qp->ibqp.device); + unsigned long flags; - if ((is_request && (qp->req.state != QP_STATE_READY)) || - (!is_request && (qp->resp.state != QP_STATE_READY))) { + spin_lock_irqsave(&qp->state_lock, flags); + if ((is_request && (qp_state(qp) < IB_QPS_RTS)) || + (!is_request && (qp_state(qp) < IB_QPS_RTR))) { + spin_unlock_irqrestore(&qp->state_lock, flags); rxe_dbg_qp(qp, "Packet dropped. QP is not in ready state\n"); goto drop; } + spin_unlock_irqrestore(&qp->state_lock, flags); rxe_icrc_generate(skb, pkt); @@ -596,7 +600,7 @@ static int rxe_notify(struct notifier_block *not_blk, rxe_port_down(rxe); break; case NETDEV_CHANGEMTU: - rxe_dbg(rxe, "%s changed mtu to %d\n", ndev->name, ndev->mtu); + rxe_dbg_dev(rxe, "%s changed mtu to %d\n", ndev->name, ndev->mtu); rxe_set_mtu(rxe, ndev->mtu); break; case NETDEV_CHANGE: @@ -608,7 +612,7 @@ static int rxe_notify(struct notifier_block *not_blk, case NETDEV_CHANGENAME: case NETDEV_FEAT_CHANGE: default: - rxe_dbg(rxe, "ignoring netdev event = %ld for %s\n", + rxe_dbg_dev(rxe, "ignoring netdev event = %ld for %s\n", event, ndev->name); break; } diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index ab72db68b58f..61a2eb77d999 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -19,33 +19,33 @@ static int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap, int has_srq) { if (cap->max_send_wr > rxe->attr.max_qp_wr) { - rxe_dbg(rxe, "invalid send wr = %u > %d\n", + rxe_dbg_dev(rxe, "invalid send wr = %u > %d\n", cap->max_send_wr, rxe->attr.max_qp_wr); goto err1; } if (cap->max_send_sge > rxe->attr.max_send_sge) { - rxe_dbg(rxe, "invalid send sge = %u > %d\n", + rxe_dbg_dev(rxe, "invalid send sge = %u > %d\n", cap->max_send_sge, rxe->attr.max_send_sge); goto err1; } if (!has_srq) { if (cap->max_recv_wr > rxe->attr.max_qp_wr) { - rxe_dbg(rxe, "invalid recv wr = %u > %d\n", + rxe_dbg_dev(rxe, "invalid recv wr = %u > %d\n", cap->max_recv_wr, rxe->attr.max_qp_wr); goto err1; } if (cap->max_recv_sge > rxe->attr.max_recv_sge) { - rxe_dbg(rxe, "invalid recv sge = %u > %d\n", + rxe_dbg_dev(rxe, "invalid recv sge = %u > %d\n", cap->max_recv_sge, rxe->attr.max_recv_sge); goto err1; } } if (cap->max_inline_data > rxe->max_inline_data) { - rxe_dbg(rxe, "invalid max inline data = %u > %d\n", + rxe_dbg_dev(rxe, "invalid max inline data = %u > %d\n", cap->max_inline_data, rxe->max_inline_data); goto err1; } @@ -73,7 +73,7 @@ int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init) } if (!init->recv_cq || !init->send_cq) { - rxe_dbg(rxe, "missing cq\n"); + rxe_dbg_dev(rxe, "missing cq\n"); goto err1; } @@ -82,14 +82,14 @@ int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init) if (init->qp_type == IB_QPT_GSI) { if (!rdma_is_port_valid(&rxe->ib_dev, port_num)) { - rxe_dbg(rxe, "invalid port = %d\n", port_num); + rxe_dbg_dev(rxe, "invalid port = %d\n", port_num); goto err1; } port = &rxe->port; if (init->qp_type == IB_QPT_GSI && port->qp_gsi_index) { - rxe_dbg(rxe, "GSI QP exists for port %d\n", port_num); + rxe_dbg_dev(rxe, "GSI QP exists for port %d\n", port_num); goto err1; } } @@ -231,8 +231,6 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, qp->req.wqe_index = queue_get_producer(qp->sq.queue, QUEUE_TYPE_FROM_CLIENT); - qp->req.state = QP_STATE_RESET; - qp->comp.state = QP_STATE_RESET; qp->req.opcode = -1; qp->comp.opcode = -1; @@ -287,7 +285,6 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, qp->resp.opcode = OPCODE_NONE; qp->resp.msn = 0; - qp->resp.state = QP_STATE_RESET; return 0; } @@ -303,6 +300,7 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd, struct rxe_cq *rcq = to_rcq(init->recv_cq); struct rxe_cq *scq = to_rcq(init->send_cq); struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL; + unsigned long flags; rxe_get(pd); rxe_get(rcq); @@ -328,8 +326,10 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd, if (err) goto err2; + spin_lock_irqsave(&qp->state_lock, flags); qp->attr.qp_state = IB_QPS_RESET; qp->valid = 1; + spin_unlock_irqrestore(&qp->state_lock, flags); return 0; @@ -380,30 +380,9 @@ int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init) return 0; } -/* called by the modify qp verb, this routine checks all the parameters before - * making any changes - */ int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp, struct ib_qp_attr *attr, int mask) { - enum ib_qp_state cur_state = (mask & IB_QP_CUR_STATE) ? - attr->cur_qp_state : qp->attr.qp_state; - enum ib_qp_state new_state = (mask & IB_QP_STATE) ? - attr->qp_state : cur_state; - - if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask)) { - rxe_dbg_qp(qp, "invalid mask or state\n"); - goto err1; - } - - if (mask & IB_QP_STATE) { - if (cur_state == IB_QPS_SQD) { - if (qp->req.state == QP_STATE_DRAIN && - new_state != IB_QPS_ERR) - goto err1; - } - } - if (mask & IB_QP_PORT) { if (!rdma_is_port_valid(&rxe->ib_dev, attr->port_num)) { rxe_dbg_qp(qp, "invalid port %d\n", attr->port_num); @@ -473,29 +452,18 @@ static void rxe_qp_reset(struct rxe_qp *qp) { /* stop tasks from running */ rxe_disable_task(&qp->resp.task); + rxe_disable_task(&qp->comp.task); + rxe_disable_task(&qp->req.task); - /* stop request/comp */ - if (qp->sq.queue) { - if (qp_type(qp) == IB_QPT_RC) - rxe_disable_task(&qp->comp.task); - rxe_disable_task(&qp->req.task); - } + /* drain work and packet queuesc */ + rxe_requester(qp); + rxe_completer(qp); + rxe_responder(qp); - /* move qp to the reset state */ - qp->req.state = QP_STATE_RESET; - qp->comp.state = QP_STATE_RESET; - qp->resp.state = QP_STATE_RESET; - - /* let state machines reset themselves drain work and packet queues - * etc. - */ - __rxe_do_task(&qp->resp.task); - - if (qp->sq.queue) { - __rxe_do_task(&qp->comp.task); - __rxe_do_task(&qp->req.task); + if (qp->rq.queue) + rxe_queue_reset(qp->rq.queue); + if (qp->sq.queue) rxe_queue_reset(qp->sq.queue); - } /* cleanup attributes */ atomic_set(&qp->ssn, 0); @@ -518,54 +486,109 @@ static void rxe_qp_reset(struct rxe_qp *qp) /* reenable tasks */ rxe_enable_task(&qp->resp.task); - - if (qp->sq.queue) { - if (qp_type(qp) == IB_QPT_RC) - rxe_enable_task(&qp->comp.task); - - rxe_enable_task(&qp->req.task); - } -} - -/* drain the send queue */ -static void rxe_qp_drain(struct rxe_qp *qp) -{ - if (qp->sq.queue) { - if (qp->req.state != QP_STATE_DRAINED) { - qp->req.state = QP_STATE_DRAIN; - if (qp_type(qp) == IB_QPT_RC) - rxe_sched_task(&qp->comp.task); - else - __rxe_do_task(&qp->comp.task); - rxe_sched_task(&qp->req.task); - } - } + rxe_enable_task(&qp->comp.task); + rxe_enable_task(&qp->req.task); } /* move the qp to the error state */ void rxe_qp_error(struct rxe_qp *qp) { - qp->req.state = QP_STATE_ERROR; - qp->resp.state = QP_STATE_ERROR; - qp->comp.state = QP_STATE_ERROR; + unsigned long flags; + + spin_lock_irqsave(&qp->state_lock, flags); qp->attr.qp_state = IB_QPS_ERR; /* drain work and packet queues */ rxe_sched_task(&qp->resp.task); - - if (qp_type(qp) == IB_QPT_RC) - rxe_sched_task(&qp->comp.task); - else - __rxe_do_task(&qp->comp.task); + rxe_sched_task(&qp->comp.task); rxe_sched_task(&qp->req.task); + spin_unlock_irqrestore(&qp->state_lock, flags); } +static void rxe_qp_sqd(struct rxe_qp *qp, struct ib_qp_attr *attr, + int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&qp->state_lock, flags); + qp->attr.sq_draining = 1; + rxe_sched_task(&qp->comp.task); + rxe_sched_task(&qp->req.task); + spin_unlock_irqrestore(&qp->state_lock, flags); +} + +/* caller should hold qp->state_lock */ +static int __qp_chk_state(struct rxe_qp *qp, struct ib_qp_attr *attr, + int mask) +{ + enum ib_qp_state cur_state; + enum ib_qp_state new_state; + + cur_state = (mask & IB_QP_CUR_STATE) ? + attr->cur_qp_state : qp->attr.qp_state; + new_state = (mask & IB_QP_STATE) ? + attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask)) + return -EINVAL; + + if (mask & IB_QP_STATE && cur_state == IB_QPS_SQD) { + if (qp->attr.sq_draining && new_state != IB_QPS_ERR) + return -EINVAL; + } + + return 0; +} + +static const char *const qps2str[] = { + [IB_QPS_RESET] = "RESET", + [IB_QPS_INIT] = "INIT", + [IB_QPS_RTR] = "RTR", + [IB_QPS_RTS] = "RTS", + [IB_QPS_SQD] = "SQD", + [IB_QPS_SQE] = "SQE", + [IB_QPS_ERR] = "ERR", +}; + /* called by the modify qp verb */ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask, struct ib_udata *udata) { int err; + if (mask & IB_QP_CUR_STATE) + qp->attr.cur_qp_state = attr->qp_state; + + if (mask & IB_QP_STATE) { + unsigned long flags; + + spin_lock_irqsave(&qp->state_lock, flags); + err = __qp_chk_state(qp, attr, mask); + if (!err) { + qp->attr.qp_state = attr->qp_state; + rxe_dbg_qp(qp, "state -> %s\n", + qps2str[attr->qp_state]); + } + spin_unlock_irqrestore(&qp->state_lock, flags); + + if (err) + return err; + + switch (attr->qp_state) { + case IB_QPS_RESET: + rxe_qp_reset(qp); + break; + case IB_QPS_SQD: + rxe_qp_sqd(qp, attr, mask); + break; + case IB_QPS_ERR: + rxe_qp_error(qp); + break; + default: + break; + } + } + if (mask & IB_QP_MAX_QP_RD_ATOMIC) { int max_rd_atomic = attr->max_rd_atomic ? roundup_pow_of_two(attr->max_rd_atomic) : 0; @@ -587,9 +610,6 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask, return err; } - if (mask & IB_QP_CUR_STATE) - qp->attr.cur_qp_state = attr->qp_state; - if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY) qp->attr.en_sqd_async_notify = attr->en_sqd_async_notify; @@ -669,56 +689,14 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask, if (mask & IB_QP_DEST_QPN) qp->attr.dest_qp_num = attr->dest_qp_num; - if (mask & IB_QP_STATE) { - qp->attr.qp_state = attr->qp_state; - - switch (attr->qp_state) { - case IB_QPS_RESET: - rxe_dbg_qp(qp, "state -> RESET\n"); - rxe_qp_reset(qp); - break; - - case IB_QPS_INIT: - rxe_dbg_qp(qp, "state -> INIT\n"); - qp->req.state = QP_STATE_INIT; - qp->resp.state = QP_STATE_INIT; - qp->comp.state = QP_STATE_INIT; - break; - - case IB_QPS_RTR: - rxe_dbg_qp(qp, "state -> RTR\n"); - qp->resp.state = QP_STATE_READY; - break; - - case IB_QPS_RTS: - rxe_dbg_qp(qp, "state -> RTS\n"); - qp->req.state = QP_STATE_READY; - qp->comp.state = QP_STATE_READY; - break; - - case IB_QPS_SQD: - rxe_dbg_qp(qp, "state -> SQD\n"); - rxe_qp_drain(qp); - break; - - case IB_QPS_SQE: - rxe_dbg_qp(qp, "state -> SQE !!?\n"); - /* Not possible from modify_qp. */ - break; - - case IB_QPS_ERR: - rxe_dbg_qp(qp, "state -> ERR\n"); - rxe_qp_error(qp); - break; - } - } - return 0; } /* called by the query qp verb */ int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask) { + unsigned long flags; + *attr = qp->attr; attr->rq_psn = qp->resp.psn; @@ -736,19 +714,17 @@ int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask) rxe_av_to_attr(&qp->pri_av, &attr->ah_attr); rxe_av_to_attr(&qp->alt_av, &attr->alt_ah_attr); - if (qp->req.state == QP_STATE_DRAIN) { - attr->sq_draining = 1; - /* applications that get this state - * typically spin on it. yield the - * processor - */ + /* Applications that get this state typically spin on it. + * Yield the processor + */ + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->attr.sq_draining) { + spin_unlock_irqrestore(&qp->state_lock, flags); cond_resched(); } else { - attr->sq_draining = 0; + spin_unlock_irqrestore(&qp->state_lock, flags); } - rxe_dbg_qp(qp, "attr->sq_draining = %d\n", attr->sq_draining); - return 0; } @@ -770,27 +746,31 @@ int rxe_qp_chk_destroy(struct rxe_qp *qp) static void rxe_qp_do_cleanup(struct work_struct *work) { struct rxe_qp *qp = container_of(work, typeof(*qp), cleanup_work.work); + unsigned long flags; + spin_lock_irqsave(&qp->state_lock, flags); qp->valid = 0; + spin_unlock_irqrestore(&qp->state_lock, flags); qp->qp_timeout_jiffies = 0; - rxe_cleanup_task(&qp->resp.task); if (qp_type(qp) == IB_QPT_RC) { del_timer_sync(&qp->retrans_timer); del_timer_sync(&qp->rnr_nak_timer); } - rxe_cleanup_task(&qp->req.task); - rxe_cleanup_task(&qp->comp.task); + if (qp->resp.task.func) + rxe_cleanup_task(&qp->resp.task); + + if (qp->req.task.func) + rxe_cleanup_task(&qp->req.task); + + if (qp->comp.task.func) + rxe_cleanup_task(&qp->comp.task); /* flush out any receive wr's or pending requests */ - if (qp->req.task.func) - __rxe_do_task(&qp->req.task); - - if (qp->sq.queue) { - __rxe_do_task(&qp->comp.task); - __rxe_do_task(&qp->req.task); - } + rxe_requester(qp); + rxe_completer(qp); + rxe_responder(qp); if (qp->sq.queue) rxe_queue_cleanup(qp->sq.queue); diff --git a/drivers/infiniband/sw/rxe/rxe_queue.c b/drivers/infiniband/sw/rxe/rxe_queue.c index d6dbf5a0058d..9611ee191a46 100644 --- a/drivers/infiniband/sw/rxe/rxe_queue.c +++ b/drivers/infiniband/sw/rxe/rxe_queue.c @@ -61,11 +61,11 @@ struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem, /* num_elem == 0 is allowed, but uninteresting */ if (*num_elem < 0) - goto err1; + return NULL; q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) - goto err1; + return NULL; q->rxe = rxe; q->type = type; @@ -100,7 +100,6 @@ struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem, err2: kfree(q); -err1: return NULL; } diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c index 434a693cd4a5..5861e4244049 100644 --- a/drivers/infiniband/sw/rxe/rxe_recv.c +++ b/drivers/infiniband/sw/rxe/rxe_recv.c @@ -14,6 +14,7 @@ static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, struct rxe_qp *qp) { unsigned int pkt_type; + unsigned long flags; if (unlikely(!qp->valid)) return -EINVAL; @@ -38,12 +39,19 @@ static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, return -EINVAL; } + spin_lock_irqsave(&qp->state_lock, flags); if (pkt->mask & RXE_REQ_MASK) { - if (unlikely(qp->resp.state != QP_STATE_READY)) + if (unlikely(qp_state(qp) < IB_QPS_RTR)) { + spin_unlock_irqrestore(&qp->state_lock, flags); return -EINVAL; - } else if (unlikely(qp->req.state < QP_STATE_READY || - qp->req.state > QP_STATE_DRAINED)) - return -EINVAL; + } + } else { + if (unlikely(qp_state(qp) < IB_QPS_RTS)) { + spin_unlock_irqrestore(&qp->state_lock, flags); + return -EINVAL; + } + } + spin_unlock_irqrestore(&qp->state_lock, flags); return 0; } diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 899c8779f800..5fe7cbae3031 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -99,48 +99,50 @@ static void req_retry(struct rxe_qp *qp) void rnr_nak_timer(struct timer_list *t) { struct rxe_qp *qp = from_timer(qp, t, rnr_nak_timer); + unsigned long flags; rxe_dbg_qp(qp, "nak timer fired\n"); - /* request a send queue retry */ - qp->req.need_retry = 1; - qp->req.wait_for_rnr_timer = 0; - rxe_sched_task(&qp->req.task); + spin_lock_irqsave(&qp->state_lock, flags); + if (qp->valid) { + /* request a send queue retry */ + qp->req.need_retry = 1; + qp->req.wait_for_rnr_timer = 0; + rxe_sched_task(&qp->req.task); + } + spin_unlock_irqrestore(&qp->state_lock, flags); } -static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp) +static void req_check_sq_drain_done(struct rxe_qp *qp) { - struct rxe_send_wqe *wqe; - struct rxe_queue *q = qp->sq.queue; - unsigned int index = qp->req.wqe_index; + struct rxe_queue *q; + unsigned int index; unsigned int cons; - unsigned int prod; + struct rxe_send_wqe *wqe; + unsigned long flags; - wqe = queue_head(q, QUEUE_TYPE_FROM_CLIENT); - cons = queue_get_consumer(q, QUEUE_TYPE_FROM_CLIENT); - prod = queue_get_producer(q, QUEUE_TYPE_FROM_CLIENT); + spin_lock_irqsave(&qp->state_lock, flags); + if (qp_state(qp) == IB_QPS_SQD) { + q = qp->sq.queue; + index = qp->req.wqe_index; + cons = queue_get_consumer(q, QUEUE_TYPE_FROM_CLIENT); + wqe = queue_addr_from_index(q, cons); - if (unlikely(qp->req.state == QP_STATE_DRAIN)) { /* check to see if we are drained; * state_lock used by requester and completer */ - spin_lock_bh(&qp->state_lock); do { - if (qp->req.state != QP_STATE_DRAIN) { + if (!qp->attr.sq_draining) /* comp just finished */ - spin_unlock_bh(&qp->state_lock); break; - } if (wqe && ((index != cons) || - (wqe->state != wqe_state_posted))) { + (wqe->state != wqe_state_posted))) /* comp not done yet */ - spin_unlock_bh(&qp->state_lock); break; - } - qp->req.state = QP_STATE_DRAINED; - spin_unlock_bh(&qp->state_lock); + qp->attr.sq_draining = 0; + spin_unlock_irqrestore(&qp->state_lock, flags); if (qp->ibqp.event_handler) { struct ib_event ev; @@ -151,19 +153,44 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp) qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); } + return; } while (0); } + spin_unlock_irqrestore(&qp->state_lock, flags); +} +static struct rxe_send_wqe *__req_next_wqe(struct rxe_qp *qp) +{ + struct rxe_queue *q = qp->sq.queue; + unsigned int index = qp->req.wqe_index; + unsigned int prod; + + prod = queue_get_producer(q, QUEUE_TYPE_FROM_CLIENT); if (index == prod) return NULL; + else + return queue_addr_from_index(q, index); +} - wqe = queue_addr_from_index(q, index); +static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp) +{ + struct rxe_send_wqe *wqe; + unsigned long flags; - if (unlikely((qp->req.state == QP_STATE_DRAIN || - qp->req.state == QP_STATE_DRAINED) && - (wqe->state != wqe_state_processing))) + req_check_sq_drain_done(qp); + + wqe = __req_next_wqe(qp); + if (wqe == NULL) return NULL; + spin_lock_irqsave(&qp->state_lock, flags); + if (unlikely((qp_state(qp) == IB_QPS_SQD) && + (wqe->state != wqe_state_processing))) { + spin_unlock_irqrestore(&qp->state_lock, flags); + return NULL; + } + spin_unlock_irqrestore(&qp->state_lock, flags); + wqe->mask = wr_opcode_mask(wqe->wr.opcode, qp); return wqe; } @@ -635,9 +662,8 @@ static int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe) return 0; } -int rxe_requester(void *arg) +int rxe_requester(struct rxe_qp *qp) { - struct rxe_qp *qp = (struct rxe_qp *)arg; struct rxe_dev *rxe = to_rdev(qp->ibqp.device); struct rxe_pkt_info pkt; struct sk_buff *skb; @@ -653,25 +679,24 @@ int rxe_requester(void *arg) struct rxe_queue *q = qp->sq.queue; struct rxe_ah *ah; struct rxe_av *av; + unsigned long flags; - if (!rxe_get(qp)) - return -EAGAIN; - - if (unlikely(!qp->valid)) + spin_lock_irqsave(&qp->state_lock, flags); + if (unlikely(!qp->valid)) { + spin_unlock_irqrestore(&qp->state_lock, flags); goto exit; + } - if (unlikely(qp->req.state == QP_STATE_ERROR)) { - wqe = req_next_wqe(qp); + if (unlikely(qp_state(qp) == IB_QPS_ERR)) { + wqe = __req_next_wqe(qp); + spin_unlock_irqrestore(&qp->state_lock, flags); if (wqe) - /* - * Generate an error completion for error qp state - */ goto err; else goto exit; } - if (unlikely(qp->req.state == QP_STATE_RESET)) { + if (unlikely(qp_state(qp) == IB_QPS_RESET)) { qp->req.wqe_index = queue_get_consumer(q, QUEUE_TYPE_FROM_CLIENT); qp->req.opcode = -1; @@ -679,8 +704,10 @@ int rxe_requester(void *arg) qp->req.wait_psn = 0; qp->req.need_retry = 0; qp->req.wait_for_rnr_timer = 0; + spin_unlock_irqrestore(&qp->state_lock, flags); goto exit; } + spin_unlock_irqrestore(&qp->state_lock, flags); /* we come here if the retransmit timer has fired * or if the rnr timer has fired. If the retransmit @@ -757,7 +784,7 @@ int rxe_requester(void *arg) qp->req.wqe_index); wqe->state = wqe_state_done; wqe->status = IB_WC_SUCCESS; - rxe_run_task(&qp->comp.task); + rxe_sched_task(&qp->comp.task); goto done; } payload = mtu; @@ -840,12 +867,9 @@ err: /* update wqe_index for each wqe completion */ qp->req.wqe_index = queue_next_index(qp->sq.queue, qp->req.wqe_index); wqe->state = wqe_state_error; - qp->req.state = QP_STATE_ERROR; - rxe_run_task(&qp->comp.task); + rxe_qp_error(qp); exit: ret = -EAGAIN; out: - rxe_put(qp); - return ret; } diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 0cc1ba91d48c..1da044f6b7d4 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -42,7 +42,6 @@ static char *resp_state_name[] = { [RESPST_ERR_LENGTH] = "ERR_LENGTH", [RESPST_ERR_CQ_OVERFLOW] = "ERR_CQ_OVERFLOW", [RESPST_ERROR] = "ERROR", - [RESPST_RESET] = "RESET", [RESPST_DONE] = "DONE", [RESPST_EXIT] = "EXIT", }; @@ -69,17 +68,6 @@ static inline enum resp_states get_req(struct rxe_qp *qp, { struct sk_buff *skb; - if (qp->resp.state == QP_STATE_ERROR) { - while ((skb = skb_dequeue(&qp->req_pkts))) { - rxe_put(qp); - kfree_skb(skb); - ib_device_put(qp->ibqp.device); - } - - /* go drain recv wr queue */ - return RESPST_CHK_RESOURCE; - } - skb = skb_peek(&qp->req_pkts); if (!skb) return RESPST_EXIT; @@ -334,24 +322,6 @@ static enum resp_states check_resource(struct rxe_qp *qp, { struct rxe_srq *srq = qp->srq; - if (qp->resp.state == QP_STATE_ERROR) { - if (qp->resp.wqe) { - qp->resp.status = IB_WC_WR_FLUSH_ERR; - return RESPST_COMPLETE; - } else if (!srq) { - qp->resp.wqe = queue_head(qp->rq.queue, - QUEUE_TYPE_FROM_CLIENT); - if (qp->resp.wqe) { - qp->resp.status = IB_WC_WR_FLUSH_ERR; - return RESPST_COMPLETE; - } else { - return RESPST_EXIT; - } - } else { - return RESPST_EXIT; - } - } - if (pkt->mask & (RXE_READ_OR_ATOMIC_MASK | RXE_ATOMIC_WRITE_MASK)) { /* it is the requesters job to not send * too many read/atomic ops, we just @@ -1077,6 +1047,7 @@ static enum resp_states do_complete(struct rxe_qp *qp, struct ib_uverbs_wc *uwc = &cqe.uibwc; struct rxe_recv_wqe *wqe = qp->resp.wqe; struct rxe_dev *rxe = to_rdev(qp->ibqp.device); + unsigned long flags; if (!wqe) goto finish; @@ -1151,6 +1122,10 @@ static enum resp_states do_complete(struct rxe_qp *qp, wc->port_num = qp->attr.port_num; } + } else { + if (wc->status != IB_WC_WR_FLUSH_ERR) + rxe_err_qp(qp, "non-flush error status = %d", + wc->status); } /* have copy for srq and reference for !srq */ @@ -1163,8 +1138,13 @@ static enum resp_states do_complete(struct rxe_qp *qp, return RESPST_ERR_CQ_OVERFLOW; finish: - if (unlikely(qp->resp.state == QP_STATE_ERROR)) + spin_lock_irqsave(&qp->state_lock, flags); + if (unlikely(qp_state(qp) == IB_QPS_ERR)) { + spin_unlock_irqrestore(&qp->state_lock, flags); return RESPST_CHK_RESOURCE; + } + spin_unlock_irqrestore(&qp->state_lock, flags); + if (unlikely(!pkt)) return RESPST_DONE; if (qp_type(qp) == IB_QPT_RC) @@ -1421,49 +1401,91 @@ static enum resp_states do_class_d1e_error(struct rxe_qp *qp) } } -static void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify) +/* drain incoming request packet queue */ +static void drain_req_pkts(struct rxe_qp *qp) { struct sk_buff *skb; - struct rxe_queue *q = qp->rq.queue; while ((skb = skb_dequeue(&qp->req_pkts))) { rxe_put(qp); kfree_skb(skb); ib_device_put(qp->ibqp.device); } - - if (notify) - return; - - while (!qp->srq && q && queue_head(q, q->type)) - queue_advance_consumer(q, q->type); } -int rxe_responder(void *arg) +/* complete receive wqe with flush error */ +static int flush_recv_wqe(struct rxe_qp *qp, struct rxe_recv_wqe *wqe) +{ + struct rxe_cqe cqe = {}; + struct ib_wc *wc = &cqe.ibwc; + struct ib_uverbs_wc *uwc = &cqe.uibwc; + int err; + + if (qp->rcq->is_user) { + uwc->wr_id = wqe->wr_id; + uwc->status = IB_WC_WR_FLUSH_ERR; + uwc->qp_num = qp_num(qp); + } else { + wc->wr_id = wqe->wr_id; + wc->status = IB_WC_WR_FLUSH_ERR; + wc->qp = &qp->ibqp; + } + + err = rxe_cq_post(qp->rcq, &cqe, 0); + if (err) + rxe_dbg_cq(qp->rcq, "post cq failed err = %d", err); + + return err; +} + +/* drain and optionally complete the recive queue + * if unable to complete a wqe stop completing and + * just flush the remaining wqes + */ +static void flush_recv_queue(struct rxe_qp *qp, bool notify) +{ + struct rxe_queue *q = qp->rq.queue; + struct rxe_recv_wqe *wqe; + int err; + + if (qp->srq) + return; + + while ((wqe = queue_head(q, q->type))) { + if (notify) { + err = flush_recv_wqe(qp, wqe); + if (err) + notify = 0; + } + queue_advance_consumer(q, q->type); + } + + qp->resp.wqe = NULL; +} + +int rxe_responder(struct rxe_qp *qp) { - struct rxe_qp *qp = (struct rxe_qp *)arg; struct rxe_dev *rxe = to_rdev(qp->ibqp.device); enum resp_states state; struct rxe_pkt_info *pkt = NULL; int ret; + unsigned long flags; - if (!rxe_get(qp)) - return -EAGAIN; + spin_lock_irqsave(&qp->state_lock, flags); + if (!qp->valid || qp_state(qp) == IB_QPS_ERR || + qp_state(qp) == IB_QPS_RESET) { + bool notify = qp->valid && (qp_state(qp) == IB_QPS_ERR); + + drain_req_pkts(qp); + flush_recv_queue(qp, notify); + spin_unlock_irqrestore(&qp->state_lock, flags); + goto exit; + } + spin_unlock_irqrestore(&qp->state_lock, flags); qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED; - if (!qp->valid) - goto exit; - - switch (qp->resp.state) { - case QP_STATE_RESET: - state = RESPST_RESET; - break; - - default: - state = RESPST_GET_REQ; - break; - } + state = RESPST_GET_REQ; while (1) { rxe_dbg_qp(qp, "state = %s\n", resp_state_name[state]); @@ -1622,11 +1644,6 @@ int rxe_responder(void *arg) goto exit; - case RESPST_RESET: - rxe_drain_req_pkts(qp, false); - qp->resp.wqe = NULL; - goto exit; - case RESPST_ERROR: qp->resp.goto_error = 0; rxe_dbg_qp(qp, "moved to error state\n"); @@ -1648,6 +1665,5 @@ done: exit: ret = -EAGAIN; out: - rxe_put(qp); return ret; } diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c index 82e37a41ced4..27ca82ec0826 100644 --- a/drivers/infiniband/sw/rxe/rxe_srq.c +++ b/drivers/infiniband/sw/rxe/rxe_srq.c @@ -13,13 +13,13 @@ int rxe_srq_chk_init(struct rxe_dev *rxe, struct ib_srq_init_attr *init) struct ib_srq_attr *attr = &init->attr; if (attr->max_wr > rxe->attr.max_srq_wr) { - rxe_dbg(rxe, "max_wr(%d) > max_srq_wr(%d)\n", + rxe_dbg_dev(rxe, "max_wr(%d) > max_srq_wr(%d)\n", attr->max_wr, rxe->attr.max_srq_wr); goto err1; } if (attr->max_wr <= 0) { - rxe_dbg(rxe, "max_wr(%d) <= 0\n", attr->max_wr); + rxe_dbg_dev(rxe, "max_wr(%d) <= 0\n", attr->max_wr); goto err1; } @@ -27,7 +27,7 @@ int rxe_srq_chk_init(struct rxe_dev *rxe, struct ib_srq_init_attr *init) attr->max_wr = RXE_MIN_SRQ_WR; if (attr->max_sge > rxe->attr.max_srq_sge) { - rxe_dbg(rxe, "max_sge(%d) > max_srq_sge(%d)\n", + rxe_dbg_dev(rxe, "max_sge(%d) > max_srq_sge(%d)\n", attr->max_sge, rxe->attr.max_srq_sge); goto err1; } diff --git a/drivers/infiniband/sw/rxe/rxe_task.c b/drivers/infiniband/sw/rxe/rxe_task.c index 60b90e33a884..fb9a6bc8e620 100644 --- a/drivers/infiniband/sw/rxe/rxe_task.c +++ b/drivers/infiniband/sw/rxe/rxe_task.c @@ -6,69 +6,128 @@ #include "rxe.h" -int __rxe_do_task(struct rxe_task *task) - +/* Check if task is idle i.e. not running, not scheduled in + * tasklet queue and not draining. If so move to busy to + * reserve a slot in do_task() by setting to busy and taking + * a qp reference to cover the gap from now until the task finishes. + * state will move out of busy if task returns a non zero value + * in do_task(). If state is already busy it is raised to armed + * to indicate to do_task that additional pass should be made + * over the task. + * Context: caller should hold task->lock. + * Returns: true if state transitioned from idle to busy else false. + */ +static bool __reserve_if_idle(struct rxe_task *task) { - int ret; + WARN_ON(rxe_read(task->qp) <= 0); - while ((ret = task->func(task->arg)) == 0) - ; + if (task->tasklet.state & BIT(TASKLET_STATE_SCHED)) + return false; - task->ret = ret; + if (task->state == TASK_STATE_IDLE) { + rxe_get(task->qp); + task->state = TASK_STATE_BUSY; + task->num_sched++; + return true; + } - return ret; + if (task->state == TASK_STATE_BUSY) + task->state = TASK_STATE_ARMED; + + return false; } -/* - * this locking is due to a potential race where - * a second caller finds the task already running - * but looks just after the last call to func +/* check if task is idle or drained and not currently + * scheduled in the tasklet queue. This routine is + * called by rxe_cleanup_task or rxe_disable_task to + * see if the queue is empty. + * Context: caller should hold task->lock. + * Returns true if done else false. + */ +static bool __is_done(struct rxe_task *task) +{ + if (task->tasklet.state & BIT(TASKLET_STATE_SCHED)) + return false; + + if (task->state == TASK_STATE_IDLE || + task->state == TASK_STATE_DRAINED) { + return true; + } + + return false; +} + +/* a locked version of __is_done */ +static bool is_done(struct rxe_task *task) +{ + unsigned long flags; + int done; + + spin_lock_irqsave(&task->lock, flags); + done = __is_done(task); + spin_unlock_irqrestore(&task->lock, flags); + + return done; +} + +/* do_task is a wrapper for the three tasks (requester, + * completer, responder) and calls them in a loop until + * they return a non-zero value. It is called either + * directly by rxe_run_task or indirectly if rxe_sched_task + * schedules the task. They must call __reserve_if_idle to + * move the task to busy before calling or scheduling. + * The task can also be moved to drained or invalid + * by calls to rxe-cleanup_task or rxe_disable_task. + * In that case tasks which get here are not executed but + * just flushed. The tasks are designed to look to see if + * there is work to do and do part of it before returning + * here with a return value of zero until all the work + * has been consumed then it retuens a non-zero value. + * The number of times the task can be run is limited by + * max iterations so one task cannot hold the cpu forever. */ static void do_task(struct tasklet_struct *t) { int cont; int ret; struct rxe_task *task = from_tasklet(task, t, tasklet); - struct rxe_qp *qp = (struct rxe_qp *)task->arg; - unsigned int iterations = RXE_MAX_ITERATIONS; + unsigned int iterations; + unsigned long flags; + int resched = 0; - spin_lock_bh(&task->lock); - switch (task->state) { - case TASK_STATE_START: - task->state = TASK_STATE_BUSY; - spin_unlock_bh(&task->lock); - break; + WARN_ON(rxe_read(task->qp) <= 0); - case TASK_STATE_BUSY: - task->state = TASK_STATE_ARMED; - fallthrough; - case TASK_STATE_ARMED: - spin_unlock_bh(&task->lock); - return; - - default: - spin_unlock_bh(&task->lock); - rxe_dbg_qp(qp, "failed with bad state %d\n", task->state); + spin_lock_irqsave(&task->lock, flags); + if (task->state >= TASK_STATE_DRAINED) { + rxe_put(task->qp); + task->num_done++; + spin_unlock_irqrestore(&task->lock, flags); return; } + spin_unlock_irqrestore(&task->lock, flags); do { + iterations = RXE_MAX_ITERATIONS; cont = 0; - ret = task->func(task->arg); - spin_lock_bh(&task->lock); + do { + ret = task->func(task->qp); + } while (ret == 0 && iterations-- > 0); + + spin_lock_irqsave(&task->lock, flags); switch (task->state) { case TASK_STATE_BUSY: if (ret) { - task->state = TASK_STATE_START; - } else if (iterations--) { - cont = 1; + task->state = TASK_STATE_IDLE; } else { - /* reschedule the tasklet and exit + /* This can happen if the client + * can add work faster than the + * tasklet can finish it. + * Reschedule the tasklet and exit * the loop to give up the cpu */ - tasklet_schedule(&task->tasklet); - task->state = TASK_STATE_START; + task->state = TASK_STATE_IDLE; + resched = 1; } break; @@ -81,71 +140,158 @@ static void do_task(struct tasklet_struct *t) cont = 1; break; + case TASK_STATE_DRAINING: + if (ret) + task->state = TASK_STATE_DRAINED; + else + cont = 1; + break; + default: - rxe_dbg_qp(qp, "failed with bad state %d\n", - task->state); + WARN_ON(1); + rxe_info_qp(task->qp, "unexpected task state = %d", task->state); } - spin_unlock_bh(&task->lock); + + if (!cont) { + task->num_done++; + if (WARN_ON(task->num_done != task->num_sched)) + rxe_err_qp(task->qp, "%ld tasks scheduled, %ld tasks done", + task->num_sched, task->num_done); + } + spin_unlock_irqrestore(&task->lock, flags); } while (cont); task->ret = ret; + + if (resched) + rxe_sched_task(task); + + rxe_put(task->qp); } -int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *)) +int rxe_init_task(struct rxe_task *task, struct rxe_qp *qp, + int (*func)(struct rxe_qp *)) { - task->arg = arg; - task->func = func; - task->destroyed = false; + WARN_ON(rxe_read(qp) <= 0); + + task->qp = qp; + task->func = func; tasklet_setup(&task->tasklet, do_task); - task->state = TASK_STATE_START; + task->state = TASK_STATE_IDLE; spin_lock_init(&task->lock); return 0; } +/* rxe_cleanup_task is only called from rxe_do_qp_cleanup in + * process context. The qp is already completed with no + * remaining references. Once the queue is drained the + * task is moved to invalid and returns. The qp cleanup + * code then calls the task functions directly without + * using the task struct to drain any late arriving packets + * or work requests. + */ void rxe_cleanup_task(struct rxe_task *task) { - bool idle; + unsigned long flags; - /* - * Mark the task, then wait for it to finish. It might be - * running in a non-tasklet (direct call) context. + spin_lock_irqsave(&task->lock, flags); + if (!__is_done(task) && task->state < TASK_STATE_DRAINED) { + task->state = TASK_STATE_DRAINING; + } else { + task->state = TASK_STATE_INVALID; + spin_unlock_irqrestore(&task->lock, flags); + return; + } + spin_unlock_irqrestore(&task->lock, flags); + + /* now the task cannot be scheduled or run just wait + * for the previously scheduled tasks to finish. */ - task->destroyed = true; - - do { - spin_lock_bh(&task->lock); - idle = (task->state == TASK_STATE_START); - spin_unlock_bh(&task->lock); - } while (!idle); + while (!is_done(task)) + cond_resched(); tasklet_kill(&task->tasklet); + + spin_lock_irqsave(&task->lock, flags); + task->state = TASK_STATE_INVALID; + spin_unlock_irqrestore(&task->lock, flags); } +/* run the task inline if it is currently idle + * cannot call do_task holding the lock + */ void rxe_run_task(struct rxe_task *task) { - if (task->destroyed) - return; + unsigned long flags; + int run; - do_task(&task->tasklet); + WARN_ON(rxe_read(task->qp) <= 0); + + spin_lock_irqsave(&task->lock, flags); + run = __reserve_if_idle(task); + spin_unlock_irqrestore(&task->lock, flags); + + if (run) + do_task(&task->tasklet); } +/* schedule the task to run later as a tasklet. + * the tasklet)schedule call can be called holding + * the lock. + */ void rxe_sched_task(struct rxe_task *task) { - if (task->destroyed) - return; + unsigned long flags; - tasklet_schedule(&task->tasklet); + WARN_ON(rxe_read(task->qp) <= 0); + + spin_lock_irqsave(&task->lock, flags); + if (__reserve_if_idle(task)) + tasklet_schedule(&task->tasklet); + spin_unlock_irqrestore(&task->lock, flags); } +/* rxe_disable/enable_task are only called from + * rxe_modify_qp in process context. Task is moved + * to the drained state by do_task. + */ void rxe_disable_task(struct rxe_task *task) { + unsigned long flags; + + WARN_ON(rxe_read(task->qp) <= 0); + + spin_lock_irqsave(&task->lock, flags); + if (!__is_done(task) && task->state < TASK_STATE_DRAINED) { + task->state = TASK_STATE_DRAINING; + } else { + task->state = TASK_STATE_DRAINED; + spin_unlock_irqrestore(&task->lock, flags); + return; + } + spin_unlock_irqrestore(&task->lock, flags); + + while (!is_done(task)) + cond_resched(); + tasklet_disable(&task->tasklet); } void rxe_enable_task(struct rxe_task *task) { + unsigned long flags; + + WARN_ON(rxe_read(task->qp) <= 0); + + spin_lock_irqsave(&task->lock, flags); + if (task->state == TASK_STATE_INVALID) { + spin_unlock_irqrestore(&task->lock, flags); + return; + } + task->state = TASK_STATE_IDLE; tasklet_enable(&task->tasklet); + spin_unlock_irqrestore(&task->lock, flags); } diff --git a/drivers/infiniband/sw/rxe/rxe_task.h b/drivers/infiniband/sw/rxe/rxe_task.h index 7b88129702ac..facb7c8e3729 100644 --- a/drivers/infiniband/sw/rxe/rxe_task.h +++ b/drivers/infiniband/sw/rxe/rxe_task.h @@ -8,9 +8,12 @@ #define RXE_TASK_H enum { - TASK_STATE_START = 0, + TASK_STATE_IDLE = 0, TASK_STATE_BUSY = 1, TASK_STATE_ARMED = 2, + TASK_STATE_DRAINING = 3, + TASK_STATE_DRAINED = 4, + TASK_STATE_INVALID = 5, }; /* @@ -22,28 +25,24 @@ struct rxe_task { struct tasklet_struct tasklet; int state; spinlock_t lock; - void *arg; - int (*func)(void *arg); + struct rxe_qp *qp; + int (*func)(struct rxe_qp *qp); int ret; - bool destroyed; + long num_sched; + long num_done; }; /* * init rxe_task structure - * arg => parameter to pass to fcn + * qp => parameter to pass to func * func => function to call until it returns != 0 */ -int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *)); +int rxe_init_task(struct rxe_task *task, struct rxe_qp *qp, + int (*func)(struct rxe_qp *)); /* cleanup task */ void rxe_cleanup_task(struct rxe_task *task); -/* - * raw call to func in loop without any checking - * can call when tasklets are disabled - */ -int __rxe_do_task(struct rxe_task *task); - void rxe_run_task(struct rxe_task *task); void rxe_sched_task(struct rxe_task *task); diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index e14050a69276..4d8f6b8051ff 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -12,31 +12,48 @@ #include "rxe_queue.h" #include "rxe_hw_counters.h" -static int rxe_query_device(struct ib_device *dev, +static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr); + +/* dev */ +static int rxe_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, - struct ib_udata *uhw) + struct ib_udata *udata) { - struct rxe_dev *rxe = to_rdev(dev); + struct rxe_dev *rxe = to_rdev(ibdev); + int err; - if (uhw->inlen || uhw->outlen) - return -EINVAL; + if (udata->inlen || udata->outlen) { + rxe_dbg_dev(rxe, "malformed udata"); + err = -EINVAL; + goto err_out; + } + + memcpy(attr, &rxe->attr, sizeof(*attr)); - *attr = rxe->attr; return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static int rxe_query_port(struct ib_device *dev, +static int rxe_query_port(struct ib_device *ibdev, u32 port_num, struct ib_port_attr *attr) { - struct rxe_dev *rxe = to_rdev(dev); - int rc; + struct rxe_dev *rxe = to_rdev(ibdev); + int err, ret; - /* *attr being zeroed by the caller, avoid zeroing it here */ - *attr = rxe->port.attr; + if (port_num != 1) { + err = -EINVAL; + rxe_dbg_dev(rxe, "bad port_num = %d", port_num); + goto err_out; + } + + memcpy(attr, &rxe->port.attr, sizeof(*attr)); mutex_lock(&rxe->usdev_lock); - rc = ib_get_eth_speed(dev, port_num, &attr->active_speed, - &attr->active_width); + ret = ib_get_eth_speed(ibdev, port_num, &attr->active_speed, + &attr->active_width); if (attr->state == IB_PORT_ACTIVE) attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP; @@ -47,27 +64,45 @@ static int rxe_query_port(struct ib_device *dev, mutex_unlock(&rxe->usdev_lock); - return rc; + return ret; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static int rxe_query_pkey(struct ib_device *device, +static int rxe_query_pkey(struct ib_device *ibdev, u32 port_num, u16 index, u16 *pkey) { - if (index > 0) - return -EINVAL; + struct rxe_dev *rxe = to_rdev(ibdev); + int err; + + if (index != 0) { + err = -EINVAL; + rxe_dbg_dev(rxe, "bad pkey index = %d", index); + goto err_out; + } *pkey = IB_DEFAULT_PKEY_FULL; return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static int rxe_modify_device(struct ib_device *dev, +static int rxe_modify_device(struct ib_device *ibdev, int mask, struct ib_device_modify *attr) { - struct rxe_dev *rxe = to_rdev(dev); + struct rxe_dev *rxe = to_rdev(ibdev); + int err; if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | - IB_DEVICE_MODIFY_NODE_DESC)) - return -EOPNOTSUPP; + IB_DEVICE_MODIFY_NODE_DESC)) { + err = -EOPNOTSUPP; + rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask); + goto err_out; + } if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) rxe->attr.sys_image_guid = cpu_to_be64(attr->sys_image_guid); @@ -78,16 +113,33 @@ static int rxe_modify_device(struct ib_device *dev, } return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static int rxe_modify_port(struct ib_device *dev, - u32 port_num, int mask, struct ib_port_modify *attr) +static int rxe_modify_port(struct ib_device *ibdev, u32 port_num, + int mask, struct ib_port_modify *attr) { - struct rxe_dev *rxe = to_rdev(dev); + struct rxe_dev *rxe = to_rdev(ibdev); struct rxe_port *port; + int err; + + if (port_num != 1) { + err = -EINVAL; + rxe_dbg_dev(rxe, "bad port_num = %d", port_num); + goto err_out; + } + + //TODO is shutdown useful + if (mask & ~(IB_PORT_RESET_QKEY_CNTR)) { + err = -EOPNOTSUPP; + rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask); + goto err_out; + } port = &rxe->port; - port->attr.port_cap_flags |= attr->set_port_cap_mask; port->attr.port_cap_flags &= ~attr->clr_port_cap_mask; @@ -95,73 +147,125 @@ static int rxe_modify_port(struct ib_device *dev, port->attr.qkey_viol_cntr = 0; return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static enum rdma_link_layer rxe_get_link_layer(struct ib_device *dev, +static enum rdma_link_layer rxe_get_link_layer(struct ib_device *ibdev, u32 port_num) { + struct rxe_dev *rxe = to_rdev(ibdev); + int err; + + if (port_num != 1) { + err = -EINVAL; + rxe_dbg_dev(rxe, "bad port_num = %d", port_num); + goto err_out; + } + return IB_LINK_LAYER_ETHERNET; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } -static int rxe_alloc_ucontext(struct ib_ucontext *ibuc, struct ib_udata *udata) -{ - struct rxe_dev *rxe = to_rdev(ibuc->device); - struct rxe_ucontext *uc = to_ruc(ibuc); - - return rxe_add_to_pool(&rxe->uc_pool, uc); -} - -static void rxe_dealloc_ucontext(struct ib_ucontext *ibuc) -{ - struct rxe_ucontext *uc = to_ruc(ibuc); - - rxe_cleanup(uc); -} - -static int rxe_port_immutable(struct ib_device *dev, u32 port_num, +static int rxe_port_immutable(struct ib_device *ibdev, u32 port_num, struct ib_port_immutable *immutable) { + struct rxe_dev *rxe = to_rdev(ibdev); + struct ib_port_attr attr = {}; int err; - struct ib_port_attr attr; + + if (port_num != 1) { + err = -EINVAL; + rxe_dbg_dev(rxe, "bad port_num = %d", port_num); + goto err_out; + } + + err = ib_query_port(ibdev, port_num, &attr); + if (err) + goto err_out; immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; - - err = ib_query_port(dev, port_num, &attr); - if (err) - return err; - immutable->pkey_tbl_len = attr.pkey_tbl_len; immutable->gid_tbl_len = attr.gid_tbl_len; immutable->max_mad_size = IB_MGMT_MAD_SIZE; return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } +/* uc */ +static int rxe_alloc_ucontext(struct ib_ucontext *ibuc, struct ib_udata *udata) +{ + struct rxe_dev *rxe = to_rdev(ibuc->device); + struct rxe_ucontext *uc = to_ruc(ibuc); + int err; + + err = rxe_add_to_pool(&rxe->uc_pool, uc); + if (err) + rxe_err_dev(rxe, "unable to create uc"); + + return err; +} + +static void rxe_dealloc_ucontext(struct ib_ucontext *ibuc) +{ + struct rxe_ucontext *uc = to_ruc(ibuc); + int err; + + err = rxe_cleanup(uc); + if (err) + rxe_err_uc(uc, "cleanup failed, err = %d", err); +} + +/* pd */ static int rxe_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) { struct rxe_dev *rxe = to_rdev(ibpd->device); struct rxe_pd *pd = to_rpd(ibpd); + int err; - return rxe_add_to_pool(&rxe->pd_pool, pd); + err = rxe_add_to_pool(&rxe->pd_pool, pd); + if (err) { + rxe_dbg_dev(rxe, "unable to alloc pd"); + goto err_out; + } + + return 0; + +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } static int rxe_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) { struct rxe_pd *pd = to_rpd(ibpd); + int err; + + err = rxe_cleanup(pd); + if (err) + rxe_err_pd(pd, "cleanup failed, err = %d", err); - rxe_cleanup(pd); return 0; } +/* ah */ static int rxe_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, struct ib_udata *udata) - { struct rxe_dev *rxe = to_rdev(ibah->device); struct rxe_ah *ah = to_rah(ibah); struct rxe_create_ah_resp __user *uresp = NULL; - int err; + int err, cleanup_err; if (udata) { /* test if new user provider */ @@ -174,16 +278,18 @@ static int rxe_create_ah(struct ib_ah *ibah, err = rxe_add_to_pool_ah(&rxe->ah_pool, ah, init_attr->flags & RDMA_CREATE_AH_SLEEPABLE); - if (err) - return err; + if (err) { + rxe_dbg_dev(rxe, "unable to create ah"); + goto err_out; + } /* create index > 0 */ ah->ah_num = ah->elem.index; err = rxe_ah_chk_attr(ah, init_attr->ah_attr); if (err) { - rxe_cleanup(ah); - return err; + rxe_dbg_ah(ah, "bad attr"); + goto err_cleanup; } if (uresp) { @@ -191,8 +297,9 @@ static int rxe_create_ah(struct ib_ah *ibah, err = copy_to_user(&uresp->ah_num, &ah->ah_num, sizeof(uresp->ah_num)); if (err) { - rxe_cleanup(ah); - return -EFAULT; + err = -EFAULT; + rxe_dbg_ah(ah, "unable to copy to user"); + goto err_cleanup; } } else if (ah->is_user) { /* only if old user provider */ @@ -203,19 +310,34 @@ static int rxe_create_ah(struct ib_ah *ibah, rxe_finalize(ah); return 0; + +err_cleanup: + cleanup_err = rxe_cleanup(ah); + if (cleanup_err) + rxe_err_ah(ah, "cleanup failed, err = %d", cleanup_err); +err_out: + rxe_err_ah(ah, "returned err = %d", err); + return err; } static int rxe_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) { - int err; struct rxe_ah *ah = to_rah(ibah); + int err; err = rxe_ah_chk_attr(ah, attr); - if (err) - return err; + if (err) { + rxe_dbg_ah(ah, "bad attr"); + goto err_out; + } rxe_init_av(attr, &ah->av); + return 0; + +err_out: + rxe_err_ah(ah, "returned err = %d", err); + return err; } static int rxe_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) @@ -225,92 +347,77 @@ static int rxe_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) memset(attr, 0, sizeof(*attr)); attr->type = ibah->type; rxe_av_to_attr(&ah->av, attr); + return 0; } static int rxe_destroy_ah(struct ib_ah *ibah, u32 flags) { struct rxe_ah *ah = to_rah(ibah); + int err; - rxe_cleanup_ah(ah, flags & RDMA_DESTROY_AH_SLEEPABLE); - - return 0; -} - -static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr) -{ - int i; - u32 length; - struct rxe_recv_wqe *recv_wqe; - int num_sge = ibwr->num_sge; - int full; - - full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP); - if (unlikely(full)) - return -ENOMEM; - - if (unlikely(num_sge > rq->max_sge)) - return -EINVAL; - - length = 0; - for (i = 0; i < num_sge; i++) - length += ibwr->sg_list[i].length; - - recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_FROM_ULP); - recv_wqe->wr_id = ibwr->wr_id; - - memcpy(recv_wqe->dma.sge, ibwr->sg_list, - num_sge * sizeof(struct ib_sge)); - - recv_wqe->dma.length = length; - recv_wqe->dma.resid = length; - recv_wqe->dma.num_sge = num_sge; - recv_wqe->dma.cur_sge = 0; - recv_wqe->dma.sge_offset = 0; - - queue_advance_producer(rq->queue, QUEUE_TYPE_FROM_ULP); + err = rxe_cleanup_ah(ah, flags & RDMA_DESTROY_AH_SLEEPABLE); + if (err) + rxe_err_ah(ah, "cleanup failed, err = %d", err); return 0; } +/* srq */ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init, struct ib_udata *udata) { - int err; struct rxe_dev *rxe = to_rdev(ibsrq->device); struct rxe_pd *pd = to_rpd(ibsrq->pd); struct rxe_srq *srq = to_rsrq(ibsrq); struct rxe_create_srq_resp __user *uresp = NULL; + int err, cleanup_err; if (udata) { - if (udata->outlen < sizeof(*uresp)) - return -EINVAL; + if (udata->outlen < sizeof(*uresp)) { + err = -EINVAL; + rxe_err_dev(rxe, "malformed udata"); + goto err_out; + } uresp = udata->outbuf; } - if (init->srq_type != IB_SRQT_BASIC) - return -EOPNOTSUPP; + if (init->srq_type != IB_SRQT_BASIC) { + err = -EOPNOTSUPP; + rxe_dbg_dev(rxe, "srq type = %d, not supported", + init->srq_type); + goto err_out; + } err = rxe_srq_chk_init(rxe, init); - if (err) - return err; + if (err) { + rxe_dbg_dev(rxe, "invalid init attributes"); + goto err_out; + } err = rxe_add_to_pool(&rxe->srq_pool, srq); - if (err) - return err; + if (err) { + rxe_dbg_dev(rxe, "unable to create srq, err = %d", err); + goto err_out; + } rxe_get(pd); srq->pd = pd; err = rxe_srq_from_init(rxe, srq, init, udata, uresp); - if (err) + if (err) { + rxe_dbg_srq(srq, "create srq failed, err = %d", err); goto err_cleanup; + } return 0; err_cleanup: - rxe_cleanup(srq); - + cleanup_err = rxe_cleanup(srq); + if (cleanup_err) + rxe_err_srq(srq, "cleanup failed, err = %d", cleanup_err); +err_out: + rxe_err_dev(rxe, "returned err = %d", err); return err; } @@ -318,46 +425,64 @@ static int rxe_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, enum ib_srq_attr_mask mask, struct ib_udata *udata) { - int err; struct rxe_srq *srq = to_rsrq(ibsrq); struct rxe_dev *rxe = to_rdev(ibsrq->device); - struct rxe_modify_srq_cmd ucmd = {}; + struct rxe_modify_srq_cmd cmd = {}; + int err; if (udata) { - if (udata->inlen < sizeof(ucmd)) - return -EINVAL; + if (udata->inlen < sizeof(cmd)) { + err = -EINVAL; + rxe_dbg_srq(srq, "malformed udata"); + goto err_out; + } - err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)); - if (err) - return err; + err = ib_copy_from_udata(&cmd, udata, sizeof(cmd)); + if (err) { + err = -EFAULT; + rxe_dbg_srq(srq, "unable to read udata"); + goto err_out; + } } err = rxe_srq_chk_attr(rxe, srq, attr, mask); - if (err) - return err; + if (err) { + rxe_dbg_srq(srq, "bad init attributes"); + goto err_out; + } - return rxe_srq_from_attr(rxe, srq, attr, mask, &ucmd, udata); + err = rxe_srq_from_attr(rxe, srq, attr, mask, &cmd, udata); + if (err) { + rxe_dbg_srq(srq, "bad attr"); + goto err_out; + } + + return 0; + +err_out: + rxe_err_srq(srq, "returned err = %d", err); + return err; } static int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) { struct rxe_srq *srq = to_rsrq(ibsrq); + int err; - if (srq->error) - return -EINVAL; + if (srq->error) { + err = -EINVAL; + rxe_dbg_srq(srq, "srq in error state"); + goto err_out; + } attr->max_wr = srq->rq.queue->buf->index_mask; attr->max_sge = srq->rq.max_sge; attr->srq_limit = srq->limit; return 0; -} -static int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) -{ - struct rxe_srq *srq = to_rsrq(ibsrq); - - rxe_cleanup(srq); - return 0; +err_out: + rxe_err_srq(srq, "returned err = %d", err); + return err; } static int rxe_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, @@ -378,76 +503,116 @@ static int rxe_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, spin_unlock_irqrestore(&srq->rq.producer_lock, flags); - if (err) + if (err) { *bad_wr = wr; + rxe_err_srq(srq, "returned err = %d", err); + } return err; } +static int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) +{ + struct rxe_srq *srq = to_rsrq(ibsrq); + int err; + + err = rxe_cleanup(srq); + if (err) + rxe_err_srq(srq, "cleanup failed, err = %d", err); + + return 0; +} + +/* qp */ static int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init, struct ib_udata *udata) { - int err; struct rxe_dev *rxe = to_rdev(ibqp->device); struct rxe_pd *pd = to_rpd(ibqp->pd); struct rxe_qp *qp = to_rqp(ibqp); struct rxe_create_qp_resp __user *uresp = NULL; + int err, cleanup_err; if (udata) { - if (udata->outlen < sizeof(*uresp)) - return -EINVAL; - uresp = udata->outbuf; - } + if (udata->inlen) { + err = -EINVAL; + rxe_dbg_dev(rxe, "malformed udata, err = %d", err); + goto err_out; + } - if (init->create_flags) - return -EOPNOTSUPP; - - err = rxe_qp_chk_init(rxe, init); - if (err) - return err; - - if (udata) { - if (udata->inlen) - return -EINVAL; + if (udata->outlen < sizeof(*uresp)) { + err = -EINVAL; + rxe_dbg_dev(rxe, "malformed udata, err = %d", err); + goto err_out; + } qp->is_user = true; + uresp = udata->outbuf; } else { qp->is_user = false; } + if (init->create_flags) { + err = -EOPNOTSUPP; + rxe_dbg_dev(rxe, "unsupported create_flags, err = %d", err); + goto err_out; + } + + err = rxe_qp_chk_init(rxe, init); + if (err) { + rxe_dbg_dev(rxe, "bad init attr, err = %d", err); + goto err_out; + } + err = rxe_add_to_pool(&rxe->qp_pool, qp); - if (err) - return err; + if (err) { + rxe_dbg_dev(rxe, "unable to create qp, err = %d", err); + goto err_out; + } err = rxe_qp_from_init(rxe, qp, pd, init, uresp, ibqp->pd, udata); - if (err) - goto qp_init; + if (err) { + rxe_dbg_qp(qp, "create qp failed, err = %d", err); + goto err_cleanup; + } rxe_finalize(qp); return 0; -qp_init: - rxe_cleanup(qp); +err_cleanup: + cleanup_err = rxe_cleanup(qp); + if (cleanup_err) + rxe_err_qp(qp, "cleanup failed, err = %d", cleanup_err); +err_out: + rxe_err_dev(rxe, "returned err = %d", err); return err; } static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int mask, struct ib_udata *udata) { - int err; struct rxe_dev *rxe = to_rdev(ibqp->device); struct rxe_qp *qp = to_rqp(ibqp); + int err; - if (mask & ~IB_QP_ATTR_STANDARD_BITS) - return -EOPNOTSUPP; + if (mask & ~IB_QP_ATTR_STANDARD_BITS) { + err = -EOPNOTSUPP; + rxe_dbg_qp(qp, "unsupported mask = 0x%x, err = %d", + mask, err); + goto err_out; + } err = rxe_qp_chk_attr(rxe, qp, attr, mask); - if (err) - return err; + if (err) { + rxe_dbg_qp(qp, "bad mask/attr, err = %d", err); + goto err_out; + } err = rxe_qp_from_attr(qp, attr, mask, udata); - if (err) - return err; + if (err) { + rxe_dbg_qp(qp, "modify qp failed, err = %d", err); + goto err_out; + } if ((mask & IB_QP_AV) && (attr->ah_attr.ah_flags & IB_AH_GRH)) qp->src_port = rdma_get_udp_sport(attr->ah_attr.grh.flow_label, @@ -455,6 +620,10 @@ static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp->attr.dest_qp_num); return 0; + +err_out: + rxe_err_qp(qp, "returned err = %d", err); + return err; } static int rxe_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, @@ -471,41 +640,90 @@ static int rxe_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, static int rxe_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) { struct rxe_qp *qp = to_rqp(ibqp); - int ret; + int err; - ret = rxe_qp_chk_destroy(qp); - if (ret) - return ret; + err = rxe_qp_chk_destroy(qp); + if (err) { + rxe_dbg_qp(qp, "unable to destroy qp, err = %d", err); + goto err_out; + } + + err = rxe_cleanup(qp); + if (err) + rxe_err_qp(qp, "cleanup failed, err = %d", err); - rxe_cleanup(qp); return 0; + +err_out: + rxe_err_qp(qp, "returned err = %d", err); + return err; } +/* send wr */ + +/* sanity check incoming send work request */ static int validate_send_wr(struct rxe_qp *qp, const struct ib_send_wr *ibwr, - unsigned int mask, unsigned int length) + unsigned int *maskp, unsigned int *lengthp) { int num_sge = ibwr->num_sge; struct rxe_sq *sq = &qp->sq; + unsigned int mask = 0; + unsigned long length = 0; + int err = -EINVAL; + int i; - if (unlikely(num_sge > sq->max_sge)) - return -EINVAL; + do { + mask = wr_opcode_mask(ibwr->opcode, qp); + if (!mask) { + rxe_err_qp(qp, "bad wr opcode for qp type"); + break; + } - if (unlikely(mask & WR_ATOMIC_MASK)) { - if (length < 8) - return -EINVAL; + if (num_sge > sq->max_sge) { + rxe_err_qp(qp, "num_sge > max_sge"); + break; + } - if (atomic_wr(ibwr)->remote_addr & 0x7) - return -EINVAL; - } + length = 0; + for (i = 0; i < ibwr->num_sge; i++) + length += ibwr->sg_list[i].length; - if (unlikely((ibwr->send_flags & IB_SEND_INLINE) && - (length > sq->max_inline))) - return -EINVAL; + if (length > (1UL << 31)) { + rxe_err_qp(qp, "message length too long"); + break; + } - return 0; + if (mask & WR_ATOMIC_MASK) { + if (length != 8) { + rxe_err_qp(qp, "atomic length != 8"); + break; + } + if (atomic_wr(ibwr)->remote_addr & 0x7) { + rxe_err_qp(qp, "misaligned atomic address"); + break; + } + } + if (ibwr->send_flags & IB_SEND_INLINE) { + if (!(mask & WR_INLINE_MASK)) { + rxe_err_qp(qp, "opcode doesn't support inline data"); + break; + } + if (length > sq->max_inline) { + rxe_err_qp(qp, "inline length too big"); + break; + } + } + + err = 0; + } while (0); + + *maskp = mask; + *lengthp = (int)length; + + return err; } -static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, +static int init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, const struct ib_send_wr *ibwr) { wr->wr_id = ibwr->wr_id; @@ -521,8 +739,18 @@ static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, wr->wr.ud.ah_num = to_rah(ibah)->ah_num; if (qp_type(qp) == IB_QPT_GSI) wr->wr.ud.pkey_index = ud_wr(ibwr)->pkey_index; - if (wr->opcode == IB_WR_SEND_WITH_IMM) + + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: wr->ex.imm_data = ibwr->ex.imm_data; + break; + case IB_WR_SEND: + break; + default: + rxe_err_qp(qp, "bad wr opcode %d for UD/GSI QP", + wr->opcode); + return -EINVAL; + } } else { switch (wr->opcode) { case IB_WR_RDMA_WRITE_WITH_IMM: @@ -539,6 +767,11 @@ static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, case IB_WR_SEND_WITH_INV: wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; break; + case IB_WR_RDMA_READ_WITH_INV: + wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; + wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr; + wr->wr.rdma.rkey = rdma_wr(ibwr)->rkey; + break; case IB_WR_ATOMIC_CMP_AND_SWP: case IB_WR_ATOMIC_FETCH_AND_ADD: wr->wr.atomic.remote_addr = @@ -550,16 +783,26 @@ static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, break; case IB_WR_LOCAL_INV: wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; - break; + break; case IB_WR_REG_MR: wr->wr.reg.mr = reg_wr(ibwr)->mr; wr->wr.reg.key = reg_wr(ibwr)->key; wr->wr.reg.access = reg_wr(ibwr)->access; - break; + break; + case IB_WR_SEND: + case IB_WR_BIND_MW: + case IB_WR_FLUSH: + case IB_WR_ATOMIC_WRITE: + break; default: + rxe_err_qp(qp, "unsupported wr opcode %d", + wr->opcode); + return -EINVAL; break; } } + + return 0; } static void copy_inline_data_to_wqe(struct rxe_send_wqe *wqe, @@ -570,24 +813,27 @@ static void copy_inline_data_to_wqe(struct rxe_send_wqe *wqe, int i; for (i = 0; i < ibwr->num_sge; i++, sge++) { - memcpy(p, (void *)(uintptr_t)sge->addr, sge->length); + memcpy(p, ib_virt_dma_to_page(sge->addr), sge->length); p += sge->length; } } -static void init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr, +static int init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr, unsigned int mask, unsigned int length, struct rxe_send_wqe *wqe) { int num_sge = ibwr->num_sge; + int err; - init_send_wr(qp, &wqe->wr, ibwr); + err = init_send_wr(qp, &wqe->wr, ibwr); + if (err) + return err; /* local operation */ if (unlikely(mask & WR_LOCAL_OP_MASK)) { wqe->mask = mask; wqe->state = wqe_state_posted; - return; + return 0; } if (unlikely(ibwr->send_flags & IB_SEND_INLINE)) @@ -606,82 +852,62 @@ static void init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr, wqe->dma.sge_offset = 0; wqe->state = wqe_state_posted; wqe->ssn = atomic_add_return(1, &qp->ssn); -} - -static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr, - unsigned int mask, u32 length) -{ - int err; - struct rxe_sq *sq = &qp->sq; - struct rxe_send_wqe *send_wqe; - unsigned long flags; - int full; - - err = validate_send_wr(qp, ibwr, mask, length); - if (err) - return err; - - spin_lock_irqsave(&qp->sq.sq_lock, flags); - - full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP); - - if (unlikely(full)) { - spin_unlock_irqrestore(&qp->sq.sq_lock, flags); - return -ENOMEM; - } - - send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_FROM_ULP); - init_send_wqe(qp, ibwr, mask, length, send_wqe); - - queue_advance_producer(sq->queue, QUEUE_TYPE_FROM_ULP); - - spin_unlock_irqrestore(&qp->sq.sq_lock, flags); return 0; } -static int rxe_post_send_kernel(struct rxe_qp *qp, const struct ib_send_wr *wr, +static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr) +{ + int err; + struct rxe_sq *sq = &qp->sq; + struct rxe_send_wqe *send_wqe; + unsigned int mask; + unsigned int length; + int full; + + err = validate_send_wr(qp, ibwr, &mask, &length); + if (err) + return err; + + full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP); + if (unlikely(full)) { + rxe_err_qp(qp, "send queue full"); + return -ENOMEM; + } + + send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_FROM_ULP); + err = init_send_wqe(qp, ibwr, mask, length, send_wqe); + if (!err) + queue_advance_producer(sq->queue, QUEUE_TYPE_FROM_ULP); + + return err; +} + +static int rxe_post_send_kernel(struct rxe_qp *qp, + const struct ib_send_wr *ibwr, const struct ib_send_wr **bad_wr) { int err = 0; - unsigned int mask; - unsigned int length = 0; - int i; - struct ib_send_wr *next; - - while (wr) { - mask = wr_opcode_mask(wr->opcode, qp); - if (unlikely(!mask)) { - err = -EINVAL; - *bad_wr = wr; - break; - } - - if (unlikely((wr->send_flags & IB_SEND_INLINE) && - !(mask & WR_INLINE_MASK))) { - err = -EINVAL; - *bad_wr = wr; - break; - } - - next = wr->next; - - length = 0; - for (i = 0; i < wr->num_sge; i++) - length += wr->sg_list[i].length; - - err = post_one_send(qp, wr, mask, length); + unsigned long flags; + spin_lock_irqsave(&qp->sq.sq_lock, flags); + while (ibwr) { + err = post_one_send(qp, ibwr); if (err) { - *bad_wr = wr; + *bad_wr = ibwr; break; } - wr = next; + ibwr = ibwr->next; } + spin_unlock_irqrestore(&qp->sq.sq_lock, flags); - rxe_sched_task(&qp->req.task); - if (unlikely(qp->req.state == QP_STATE_ERROR)) + if (!err) + rxe_sched_task(&qp->req.task); + + spin_lock_irqsave(&qp->state_lock, flags); + if (qp_state(qp) == IB_QPS_ERR) rxe_sched_task(&qp->comp.task); + spin_unlock_irqrestore(&qp->state_lock, flags); return err; } @@ -690,23 +916,89 @@ static int rxe_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr) { struct rxe_qp *qp = to_rqp(ibqp); + int err; + unsigned long flags; - if (unlikely(!qp->valid)) { - *bad_wr = wr; + spin_lock_irqsave(&qp->state_lock, flags); + /* caller has already called destroy_qp */ + if (WARN_ON_ONCE(!qp->valid)) { + spin_unlock_irqrestore(&qp->state_lock, flags); + rxe_err_qp(qp, "qp has been destroyed"); return -EINVAL; } - if (unlikely(qp->req.state < QP_STATE_READY)) { + if (unlikely(qp_state(qp) < IB_QPS_RTS)) { + spin_unlock_irqrestore(&qp->state_lock, flags); *bad_wr = wr; + rxe_err_qp(qp, "qp not ready to send"); return -EINVAL; } + spin_unlock_irqrestore(&qp->state_lock, flags); if (qp->is_user) { /* Utilize process context to do protocol processing */ rxe_run_task(&qp->req.task); - return 0; - } else - return rxe_post_send_kernel(qp, wr, bad_wr); + } else { + err = rxe_post_send_kernel(qp, wr, bad_wr); + if (err) + return err; + } + + return 0; +} + +/* recv wr */ +static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr) +{ + int i; + unsigned long length; + struct rxe_recv_wqe *recv_wqe; + int num_sge = ibwr->num_sge; + int full; + int err; + + full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP); + if (unlikely(full)) { + err = -ENOMEM; + rxe_dbg("queue full"); + goto err_out; + } + + if (unlikely(num_sge > rq->max_sge)) { + err = -EINVAL; + rxe_dbg("bad num_sge > max_sge"); + goto err_out; + } + + length = 0; + for (i = 0; i < num_sge; i++) + length += ibwr->sg_list[i].length; + + /* IBA max message size is 2^31 */ + if (length >= (1UL<<31)) { + err = -EINVAL; + rxe_dbg("message length too long"); + goto err_out; + } + + recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_FROM_ULP); + + recv_wqe->wr_id = ibwr->wr_id; + recv_wqe->dma.length = length; + recv_wqe->dma.resid = length; + recv_wqe->dma.num_sge = num_sge; + recv_wqe->dma.cur_sge = 0; + recv_wqe->dma.sge_offset = 0; + memcpy(recv_wqe->dma.sge, ibwr->sg_list, + num_sge * sizeof(struct ib_sge)); + + queue_advance_producer(rq->queue, QUEUE_TYPE_FROM_ULP); + + return 0; + +err_out: + rxe_dbg("returned err = %d", err); + return err; } static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, @@ -717,13 +1009,26 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, struct rxe_rq *rq = &qp->rq; unsigned long flags; - if (unlikely((qp_state(qp) < IB_QPS_INIT) || !qp->valid)) { - *bad_wr = wr; + spin_lock_irqsave(&qp->state_lock, flags); + /* caller has already called destroy_qp */ + if (WARN_ON_ONCE(!qp->valid)) { + spin_unlock_irqrestore(&qp->state_lock, flags); + rxe_err_qp(qp, "qp has been destroyed"); return -EINVAL; } + /* see C10-97.2.1 */ + if (unlikely((qp_state(qp) < IB_QPS_INIT))) { + spin_unlock_irqrestore(&qp->state_lock, flags); + *bad_wr = wr; + rxe_dbg_qp(qp, "qp not ready to post recv"); + return -EINVAL; + } + spin_unlock_irqrestore(&qp->state_lock, flags); + if (unlikely(qp->srq)) { *bad_wr = wr; + rxe_dbg_qp(qp, "qp has srq, use post_srq_recv instead"); return -EINVAL; } @@ -740,76 +1045,102 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, spin_unlock_irqrestore(&rq->producer_lock, flags); - if (qp->resp.state == QP_STATE_ERROR) + spin_lock_irqsave(&qp->state_lock, flags); + if (qp_state(qp) == IB_QPS_ERR) rxe_sched_task(&qp->resp.task); + spin_unlock_irqrestore(&qp->state_lock, flags); return err; } +/* cq */ static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, struct ib_udata *udata) { - int err; struct ib_device *dev = ibcq->device; struct rxe_dev *rxe = to_rdev(dev); struct rxe_cq *cq = to_rcq(ibcq); struct rxe_create_cq_resp __user *uresp = NULL; + int err, cleanup_err; if (udata) { - if (udata->outlen < sizeof(*uresp)) - return -EINVAL; + if (udata->outlen < sizeof(*uresp)) { + err = -EINVAL; + rxe_dbg_dev(rxe, "malformed udata, err = %d", err); + goto err_out; + } uresp = udata->outbuf; } - if (attr->flags) - return -EOPNOTSUPP; + if (attr->flags) { + err = -EOPNOTSUPP; + rxe_dbg_dev(rxe, "bad attr->flags, err = %d", err); + goto err_out; + } err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector); - if (err) - return err; + if (err) { + rxe_dbg_dev(rxe, "bad init attributes, err = %d", err); + goto err_out; + } + + err = rxe_add_to_pool(&rxe->cq_pool, cq); + if (err) { + rxe_dbg_dev(rxe, "unable to create cq, err = %d", err); + goto err_out; + } err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector, udata, uresp); - if (err) - return err; + if (err) { + rxe_dbg_cq(cq, "create cq failed, err = %d", err); + goto err_cleanup; + } - return rxe_add_to_pool(&rxe->cq_pool, cq); -} - -static int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) -{ - struct rxe_cq *cq = to_rcq(ibcq); - - /* See IBA C11-17: The CI shall return an error if this Verb is - * invoked while a Work Queue is still associated with the CQ. - */ - if (atomic_read(&cq->num_wq)) - return -EINVAL; - - rxe_cq_disable(cq); - - rxe_cleanup(cq); return 0; + +err_cleanup: + cleanup_err = rxe_cleanup(cq); + if (cleanup_err) + rxe_err_cq(cq, "cleanup failed, err = %d", cleanup_err); +err_out: + rxe_err_dev(rxe, "returned err = %d", err); + return err; } static int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) { - int err; struct rxe_cq *cq = to_rcq(ibcq); struct rxe_dev *rxe = to_rdev(ibcq->device); struct rxe_resize_cq_resp __user *uresp = NULL; + int err; if (udata) { - if (udata->outlen < sizeof(*uresp)) - return -EINVAL; + if (udata->outlen < sizeof(*uresp)) { + err = -EINVAL; + rxe_dbg_cq(cq, "malformed udata"); + goto err_out; + } uresp = udata->outbuf; } err = rxe_cq_chk_attr(rxe, cq, cqe, 0); - if (err) - return err; + if (err) { + rxe_dbg_cq(cq, "bad attr, err = %d", err); + goto err_out; + } - return rxe_cq_resize_queue(cq, cqe, uresp, udata); + err = rxe_cq_resize_queue(cq, cqe, uresp, udata); + if (err) { + rxe_dbg_cq(cq, "resize cq failed, err = %d", err); + goto err_out; + } + + return 0; + +err_out: + rxe_err_cq(cq, "returned err = %d", err); + return err; } static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) @@ -823,7 +1154,7 @@ static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) for (i = 0; i < num_entries; i++) { cqe = queue_head(cq->queue, QUEUE_TYPE_TO_ULP); if (!cqe) - break; + break; /* queue empty */ memcpy(wc++, &cqe->ibwc, sizeof(*wc)); queue_advance_consumer(cq->queue, QUEUE_TYPE_TO_ULP); @@ -864,6 +1195,32 @@ static int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) return ret; } +static int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) +{ + struct rxe_cq *cq = to_rcq(ibcq); + int err; + + /* See IBA C11-17: The CI shall return an error if this Verb is + * invoked while a Work Queue is still associated with the CQ. + */ + if (atomic_read(&cq->num_wq)) { + err = -EINVAL; + rxe_dbg_cq(cq, "still in use"); + goto err_out; + } + + err = rxe_cleanup(cq); + if (err) + rxe_err_cq(cq, "cleanup failed, err = %d", err); + + return 0; + +err_out: + rxe_err_cq(cq, "returned err = %d", err); + return err; +} + +/* mr */ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access) { struct rxe_dev *rxe = to_rdev(ibpd->device); @@ -872,14 +1229,14 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access) int err; mr = kzalloc(sizeof(*mr), GFP_KERNEL); - if (!mr) { - err = -ENOMEM; - goto err_out; - } + if (!mr) + return ERR_PTR(-ENOMEM); err = rxe_add_to_pool(&rxe->mr_pool, mr); - if (err) + if (err) { + rxe_dbg_dev(rxe, "unable to create mr"); goto err_free; + } rxe_get(pd); mr->ibmr.pd = ibpd; @@ -891,47 +1248,49 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access) err_free: kfree(mr); -err_out: + rxe_err_pd(pd, "returned err = %d", err); return ERR_PTR(err); } -static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, - u64 start, - u64 length, - u64 iova, - int access, struct ib_udata *udata) +static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start, + u64 length, u64 iova, int access, + struct ib_udata *udata) { - int err; struct rxe_dev *rxe = to_rdev(ibpd->device); struct rxe_pd *pd = to_rpd(ibpd); struct rxe_mr *mr; + int err, cleanup_err; mr = kzalloc(sizeof(*mr), GFP_KERNEL); - if (!mr) { - err = -ENOMEM; - goto err_out; - } + if (!mr) + return ERR_PTR(-ENOMEM); err = rxe_add_to_pool(&rxe->mr_pool, mr); - if (err) + if (err) { + rxe_dbg_pd(pd, "unable to create mr"); goto err_free; + } rxe_get(pd); mr->ibmr.pd = ibpd; mr->ibmr.device = ibpd->device; err = rxe_mr_init_user(rxe, start, length, iova, access, mr); - if (err) + if (err) { + rxe_dbg_mr(mr, "reg_user_mr failed, err = %d", err); goto err_cleanup; + } rxe_finalize(mr); return &mr->ibmr; err_cleanup: - rxe_cleanup(mr); + cleanup_err = rxe_cleanup(mr); + if (cleanup_err) + rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err); err_free: kfree(mr); -err_out: + rxe_err_pd(pd, "returned err = %d", err); return ERR_PTR(err); } @@ -941,17 +1300,19 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, struct rxe_dev *rxe = to_rdev(ibpd->device); struct rxe_pd *pd = to_rpd(ibpd); struct rxe_mr *mr; - int err; + int err, cleanup_err; - if (mr_type != IB_MR_TYPE_MEM_REG) - return ERR_PTR(-EINVAL); - - mr = kzalloc(sizeof(*mr), GFP_KERNEL); - if (!mr) { - err = -ENOMEM; + if (mr_type != IB_MR_TYPE_MEM_REG) { + err = -EINVAL; + rxe_dbg_pd(pd, "mr type %d not supported, err = %d", + mr_type, err); goto err_out; } + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + err = rxe_add_to_pool(&rxe->mr_pool, mr); if (err) goto err_free; @@ -961,20 +1322,49 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, mr->ibmr.device = ibpd->device; err = rxe_mr_init_fast(max_num_sg, mr); - if (err) + if (err) { + rxe_dbg_mr(mr, "alloc_mr failed, err = %d", err); goto err_cleanup; + } rxe_finalize(mr); return &mr->ibmr; err_cleanup: - rxe_cleanup(mr); + cleanup_err = rxe_cleanup(mr); + if (cleanup_err) + rxe_err_mr(mr, "cleanup failed, err = %d", err); err_free: kfree(mr); err_out: + rxe_err_pd(pd, "returned err = %d", err); return ERR_PTR(err); } +static int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) +{ + struct rxe_mr *mr = to_rmr(ibmr); + int err, cleanup_err; + + /* See IBA 10.6.7.2.6 */ + if (atomic_read(&mr->num_mw) > 0) { + err = -EINVAL; + rxe_dbg_mr(mr, "mr has mw's bound"); + goto err_out; + } + + cleanup_err = rxe_cleanup(mr); + if (cleanup_err) + rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err); + + kfree_rcu(mr); + return 0; + +err_out: + rxe_err_mr(mr, "returned err = %d", err); + return err; +} + static ssize_t parent_show(struct device *device, struct device_attribute *attr, char *buf) { @@ -1095,7 +1485,7 @@ int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name) err = ib_register_device(dev, ibdev_name, NULL); if (err) - rxe_dbg(rxe, "failed with error %d\n", err); + rxe_dbg_dev(rxe, "failed with error %d\n", err); /* * Note that rxe may be invalid at this point if another thread diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index c269ae2a3224..26a20f088692 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -63,9 +63,7 @@ struct rxe_cq { struct rxe_queue *queue; spinlock_t cq_lock; u8 notify; - bool is_dying; bool is_user; - struct tasklet_struct comp_task; atomic_t num_wq; }; @@ -104,17 +102,7 @@ struct rxe_srq { int error; }; -enum rxe_qp_state { - QP_STATE_RESET, - QP_STATE_INIT, - QP_STATE_READY, - QP_STATE_DRAIN, /* req only */ - QP_STATE_DRAINED, /* req only */ - QP_STATE_ERROR -}; - struct rxe_req_info { - enum rxe_qp_state state; int wqe_index; u32 psn; int opcode; @@ -129,7 +117,6 @@ struct rxe_req_info { }; struct rxe_comp_info { - enum rxe_qp_state state; u32 psn; int opcode; int timeout; @@ -175,7 +162,6 @@ struct resp_res { }; struct rxe_resp_info { - enum rxe_qp_state state; u32 msn; u32 psn; u32 ack_psn; diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c index dacc174604bf..65b5cda5457b 100644 --- a/drivers/infiniband/sw/siw/siw_main.c +++ b/drivers/infiniband/sw/siw/siw_main.c @@ -437,9 +437,6 @@ static int siw_netdev_event(struct notifier_block *nb, unsigned long event, dev_dbg(&netdev->dev, "siw: event %lu\n", event); - if (dev_net(netdev) != &init_net) - return NOTIFY_OK; - base_dev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_SIW); if (!base_dev) return NOTIFY_OK; diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c index fd721cc19682..58bbf738e4e5 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -139,7 +139,7 @@ static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx, break; bytes = min(bytes, len); - if (siw_rx_kva(srx, (void *)(uintptr_t)buf_addr, bytes) == + if (siw_rx_kva(srx, ib_virt_dma_to_ptr(buf_addr), bytes) == bytes) { copied += bytes; offset += bytes; @@ -487,7 +487,7 @@ int siw_proc_send(struct siw_qp *qp) mem_p = *mem; if (mem_p->mem_obj == NULL) rv = siw_rx_kva(srx, - (void *)(uintptr_t)(sge->laddr + frx->sge_off), + ib_virt_dma_to_ptr(sge->laddr + frx->sge_off), sge_bytes); else if (!mem_p->is_pbl) rv = siw_rx_umem(srx, mem_p->umem, @@ -852,7 +852,7 @@ int siw_proc_rresp(struct siw_qp *qp) if (mem_p->mem_obj == NULL) rv = siw_rx_kva(srx, - (void *)(uintptr_t)(sge->laddr + wqe->processed), + ib_virt_dma_to_ptr(sge->laddr + wqe->processed), bytes); else if (!mem_p->is_pbl) rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed, diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 05052b49107f..4b292e0504f1 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -29,7 +29,7 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx) dma_addr_t paddr = siw_pbl_get_buffer(pbl, offset, NULL, idx); if (paddr) - return virt_to_page((void *)(uintptr_t)paddr); + return ib_virt_dma_to_page(paddr); return NULL; } @@ -56,8 +56,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr) if (!mem->mem_obj) { /* Kernel client using kva */ - memcpy(paddr, - (const void *)(uintptr_t)sge->laddr, bytes); + memcpy(paddr, ib_virt_dma_to_ptr(sge->laddr), bytes); } else if (c_tx->in_syscall) { if (copy_from_user(paddr, u64_to_user_ptr(sge->laddr), bytes)) @@ -477,7 +476,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s) * or memory region with assigned kernel buffer */ iov[seg].iov_base = - (void *)(uintptr_t)(sge->laddr + sge_off); + ib_virt_dma_to_ptr(sge->laddr + sge_off); iov[seg].iov_len = sge_len; if (do_crc) @@ -537,19 +536,13 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s) * Cast to an uintptr_t to preserve all 64 bits * in sge->laddr. */ - uintptr_t va = (uintptr_t)(sge->laddr + sge_off); + u64 va = sge->laddr + sge_off; - /* - * virt_to_page() takes a (void *) pointer - * so cast to a (void *) meaning it will be 64 - * bits on a 64 bit platform and 32 bits on a - * 32 bit platform. - */ - page_array[seg] = virt_to_page((void *)(va & PAGE_MASK)); + page_array[seg] = ib_virt_dma_to_page(va); if (do_crc) crypto_shash_update( c_tx->mpa_crc_hd, - (void *)va, + ib_virt_dma_to_ptr(va), plen); } @@ -558,7 +551,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s) data_len -= plen; fp_off = 0; - if (++seg > (int)MAX_ARRAY) { + if (++seg >= (int)MAX_ARRAY) { siw_dbg_qp(tx_qp(c_tx), "to many fragments\n"); siw_unmap_pages(iov, kmap_mask, seg-1); wqe->processed -= c_tx->bytes_unsent; diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index 906fde1a2a0d..398ec13db624 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -660,7 +660,7 @@ static int siw_copy_inline_sgl(const struct ib_send_wr *core_wr, bytes = -EINVAL; break; } - memcpy(kbuf, (void *)(uintptr_t)core_sge->addr, + memcpy(kbuf, ib_virt_dma_to_ptr(core_sge->addr), core_sge->length); kbuf += core_sge->length; @@ -1523,7 +1523,7 @@ int siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle, } siw_dbg_mem(mem, "sge[%d], size %u, addr 0x%p, total %lu\n", - i, pble->size, (void *)(uintptr_t)pble->addr, + i, pble->size, ib_virt_dma_to_ptr(pble->addr), pbl_size); } rv = ib_sg_to_pages(base_mr, sl, num_sle, sg_off, siw_set_pbl_page); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 7b83f48f60c5..39ea73f69016 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -141,10 +141,14 @@ out_err: /* creates a new tx descriptor and adds header regd buffer */ static void iser_create_send_desc(struct iser_conn *iser_conn, - struct iser_tx_desc *tx_desc) + struct iser_tx_desc *tx_desc, enum iser_desc_type type, + void (*done)(struct ib_cq *cq, struct ib_wc *wc)) { struct iser_device *device = iser_conn->ib_conn.device; + tx_desc->type = type; + tx_desc->cqe.done = done; + ib_dma_sync_single_for_cpu(device->ib_device, tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); @@ -349,9 +353,8 @@ int iser_send_command(struct iscsi_conn *conn, struct iscsi_task *task) edtl = ntohl(hdr->data_length); /* build the tx desc regd header and add it to the tx desc dto */ - tx_desc->type = ISCSI_TX_SCSI_COMMAND; - tx_desc->cqe.done = iser_cmd_comp; - iser_create_send_desc(iser_conn, tx_desc); + iser_create_send_desc(iser_conn, tx_desc, ISCSI_TX_SCSI_COMMAND, + iser_cmd_comp); if (hdr->flags & ISCSI_FLAG_CMD_READ) { data_buf = &iser_task->data[ISER_DIR_IN]; @@ -457,7 +460,6 @@ int iser_send_data_out(struct iscsi_conn *conn, struct iscsi_task *task, iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n", itt, buf_offset, data_seg_len); - err = iser_post_send(&iser_conn->ib_conn, tx_desc); if (!err) return 0; @@ -478,9 +480,8 @@ int iser_send_control(struct iscsi_conn *conn, struct iscsi_task *task) struct iser_device *device; /* build the tx desc regd header and add it to the tx desc dto */ - mdesc->type = ISCSI_TX_CONTROL; - mdesc->cqe.done = iser_ctrl_comp; - iser_create_send_desc(iser_conn, mdesc); + iser_create_send_desc(iser_conn, mdesc, ISCSI_TX_CONTROL, + iser_ctrl_comp); device = iser_conn->ib_conn.device; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 1b8eda0dae4e..95b8eebf7e04 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -37,12 +37,6 @@ #include "iscsi_iser.h" -#define ISCSI_ISER_MAX_CONN 8 -#define ISER_MAX_RX_LEN (ISER_QP_MAX_RECV_DTOS * ISCSI_ISER_MAX_CONN) -#define ISER_MAX_TX_LEN (ISER_QP_MAX_REQ_DTOS * ISCSI_ISER_MAX_CONN) -#define ISER_MAX_CQ_LEN (ISER_MAX_RX_LEN + ISER_MAX_TX_LEN + \ - ISCSI_ISER_MAX_CONN) - static void iser_qp_event_callback(struct ib_event *cause, void *context) { iser_err("qp event %s (%d)\n", diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 80abf45a197a..edb2e3a25880 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -3163,7 +3163,7 @@ static int __init rtrs_client_init(void) { rtrs_rdma_dev_pd_init(0, &dev_pd); - rtrs_clt_dev_class = class_create(THIS_MODULE, "rtrs-client"); + rtrs_clt_dev_class = class_create("rtrs-client"); if (IS_ERR(rtrs_clt_dev_class)) { pr_err("Failed to create rtrs-client dev class\n"); return PTR_ERR(rtrs_clt_dev_class); diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c index d1703e2c0b82..c38901e2c8f4 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c @@ -2253,7 +2253,7 @@ static int __init rtrs_server_init(void) err); return err; } - rtrs_dev_class = class_create(THIS_MODULE, "rtrs-server"); + rtrs_dev_class = class_create("rtrs-server"); if (IS_ERR(rtrs_dev_class)) { err = PTR_ERR(rtrs_dev_class); goto out_err; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 3446fbf5a560..0e513a7e5ac8 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -62,11 +62,6 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator"); MODULE_LICENSE("Dual BSD/GPL"); -#if !defined(CONFIG_DYNAMIC_DEBUG) -#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) -#define DYNAMIC_DEBUG_BRANCH(descriptor) false -#endif - static unsigned int srp_sg_tablesize; static unsigned int cmd_sg_entries; static unsigned int indirect_sg_entries; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 3e9343fd2d8e..c12005eab14c 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -549,6 +549,7 @@ static int srpt_format_guid(char *buf, unsigned int size, const __be64 *guid) */ static int srpt_refresh_port(struct srpt_port *sport) { + struct ib_mad_agent *mad_agent; struct ib_mad_reg_req reg_req; struct ib_port_modify port_modify; struct ib_port_attr port_attr; @@ -593,24 +594,26 @@ static int srpt_refresh_port(struct srpt_port *sport) set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask); set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask); - sport->mad_agent = ib_register_mad_agent(sport->sdev->device, - sport->port, - IB_QPT_GSI, - ®_req, 0, - srpt_mad_send_handler, - srpt_mad_recv_handler, - sport, 0); - if (IS_ERR(sport->mad_agent)) { + mad_agent = ib_register_mad_agent(sport->sdev->device, + sport->port, + IB_QPT_GSI, + ®_req, 0, + srpt_mad_send_handler, + srpt_mad_recv_handler, + sport, 0); + if (IS_ERR(mad_agent)) { pr_err("%s-%d: MAD agent registration failed (%ld). Note: this is expected if SR-IOV is enabled.\n", dev_name(&sport->sdev->device->dev), sport->port, - PTR_ERR(sport->mad_agent)); + PTR_ERR(mad_agent)); sport->mad_agent = NULL; memset(&port_modify, 0, sizeof(port_modify)); port_modify.clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP; ib_modify_port(sport->sdev->device, sport->port, 0, &port_modify); - + return 0; } + + sport->mad_agent = mad_agent; } return 0; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e2752f7364bc..735f90b74ee5 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -166,6 +166,16 @@ config INPUT_EVBUG To compile this driver as a module, choose M here: the module will be called evbug. +config INPUT_KUNIT_TEST + tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS + depends on INPUT && KUNIT=y + default KUNIT_ALL_TESTS + help + Say Y here if you want to build the KUnit tests for the input + subsystem. + + If in doubt, say "N". + config INPUT_APMPOWER tristate "Input Power Event -> APM Bridge" if EXPERT depends on INPUT && APM_EMULATION diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2266c7d010ef..c78753274921 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ +obj-$(CONFIG_INPUT_KUNIT_TEST) += tests/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 29131f1a2f06..28be88e0e96a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -126,7 +126,6 @@ static const struct xpad_device { char *name; u8 mapping; u8 xtype; - u8 packet_type; } xpad_device[] = { { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, @@ -475,6 +474,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */ + XPAD_XBOXONE_VENDOR(0x10f5), /* Turtle Beach Controllers */ XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ @@ -493,6 +493,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */ XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ + XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */ @@ -559,6 +560,9 @@ struct xboxone_init_packet { #define GIP_MOTOR_LT BIT(3) #define GIP_MOTOR_ALL (GIP_MOTOR_R | GIP_MOTOR_L | GIP_MOTOR_RT | GIP_MOTOR_LT) +#define GIP_WIRED_INTF_DATA 0 +#define GIP_WIRED_INTF_AUDIO 1 + /* * This packet is required for all Xbox One pads with 2015 * or later firmware installed (or present from the factory). @@ -1392,6 +1396,21 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) unsigned long flags; int retval; + if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) { + /* + * Explicitly disable the audio interface. This is needed + * for some controllers, such as the PowerA Enhanced Wired + * Controller for Series X|S (0x20d6:0x200e) to report the + * guide button. + */ + retval = usb_set_interface(xpad->udev, + GIP_WIRED_INTF_AUDIO, 0); + if (retval) + dev_warn(&xpad->dev->dev, + "unable to disable audio interface: %d\n", + retval); + } + spin_lock_irqsave(&xpad->odata_lock, flags); /* @@ -2003,7 +2022,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id } if (xpad->xtype == XTYPE_XBOXONE && - intf->cur_altsetting->desc.bInterfaceNumber != 0) { + intf->cur_altsetting->desc.bInterfaceNumber != GIP_WIRED_INTF_DATA) { /* * The Xbox One controller lists three interfaces all with the * same interface class, subclass and protocol. Differentiate by diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 5496482a38c1..c42f86ad0766 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -770,6 +770,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) &button->type)) button->type = EV_KEY; + fwnode_property_read_u32(child, "linux,input-value", + (u32 *)&button->value); + button->wakeup = fwnode_property_read_bool(child, "wakeup-source") || /* legacy name */ diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c index db793a550c25..02ceebad7bda 100644 --- a/drivers/input/keyboard/iqs62x-keys.c +++ b/drivers/input/keyboard/iqs62x-keys.c @@ -320,7 +320,7 @@ static int iqs62x_keys_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret); - return ret; + return 0; } static struct platform_driver iqs62x_keys_platform_driver = { diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 203310727d88..a1b037891af2 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -425,14 +425,12 @@ matrix_keypad_parse_dt(struct device *dev) return ERR_PTR(-EINVAL); } - if (of_get_property(np, "linux,no-autorepeat", NULL)) - pdata->no_autorepeat = true; + pdata->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); pdata->wakeup = of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "linux,wakeup"); /* legacy */ - if (of_get_property(np, "gpio-activelow", NULL)) - pdata->active_low = true; + pdata->active_low = of_property_read_bool(np, "gpio-activelow"); pdata->drive_inactive_cols = of_property_read_bool(np, "drive-inactive-cols"); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 4426120398b0..9f085d5679db 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -274,8 +274,7 @@ static int omap4_keypad_parse_dt(struct device *dev, if (err) return err; - if (of_get_property(np, "linux,input-no-autorepeat", NULL)) - keypad_data->no_autorepeat = true; + keypad_data->no_autorepeat = of_property_read_bool(np, "linux,input-no-autorepeat"); return 0; } diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 09e883ea1352..d85dd2489293 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -291,8 +291,7 @@ samsung_keypad_parse_dt(struct device *dev) *keymap++ = KEY(row, col, key_code); } - if (of_get_property(np, "linux,input-no-autorepeat", NULL)) - pdata->no_autorepeat = true; + pdata->no_autorepeat = of_property_read_bool(np, "linux,input-no-autorepeat"); pdata->wakeup = of_property_read_bool(np, "wakeup-source") || /* legacy name */ diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c index b6e83324f97a..0d27324af809 100644 --- a/drivers/input/keyboard/st-keyscan.c +++ b/drivers/input/keyboard/st-keyscan.c @@ -259,7 +259,7 @@ static struct platform_driver keyscan_device_driver = { .driver = { .name = "st-keyscan", .pm = pm_sleep_ptr(&keyscan_dev_pm_ops), - .of_match_table = of_match_ptr(keyscan_of_match), + .of_match_table = keyscan_of_match, } }; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index da4019cf0c83..d5a6c7d8eb25 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -504,8 +504,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop)) kbc->repeat_cnt = prop; - if (of_find_property(np, "nvidia,needs-ghost-filter", NULL)) - kbc->use_ghost_filter = true; + kbc->use_ghost_filter = of_property_present(np, "nvidia,needs-ghost-filter"); if (of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */ diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 6627e65f06e5..4e20571cb4c3 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -354,7 +354,7 @@ static struct i2c_driver tm2_touchkey_driver = { .driver = { .name = TM2_TOUCHKEY_DEV_NAME, .pm = pm_sleep_ptr(&tm2_touchkey_pm_ops), - .of_match_table = of_match_ptr(tm2_touchkey_of_match), + .of_match_table = tm2_touchkey_of_match, }, .probe_new = tm2_touchkey_probe, .id_table = tm2_touchkey_id_table, diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5c2d0c06d2a5..81a54a59e13c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -119,6 +119,17 @@ config INPUT_ATMEL_CAPTOUCH To compile this driver as a module, choose M here: the module will be called atmel_captouch. +config INPUT_BBNSM_PWRKEY + tristate "NXP BBNSM Power Key Driver" + depends on ARCH_MXC || COMPILE_TEST + depends on OF + help + This is the bbnsm powerkey driver for the NXP i.MX application + processors. + + To compile this driver as a module, choose M here; the + module will be called bbnsm_pwrkey. + config INPUT_BMA150 tristate "BMA150/SMB380 acceleration sensor support" depends on I2C diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 61949263300d..04296a4abe8e 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o +obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index e6feb73bb52b..1772846708d2 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -325,8 +325,6 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, input_dev->open = cma3000_open; input_dev->close = cma3000_close; - __set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_X, -data->g_range, data->g_range, pdata->fuzz_x, 0); input_set_abs_params(input_dev, ABS_Y, diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 199bc17ddb1d..afc0d6dc5787 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -265,7 +265,7 @@ static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) { return 0; } -static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) +static int __maybe_unused hp_sdc_rtc_proc_show(struct seq_file *m, void *v) { #define YN(bit) ("no") #define NY(bit) ("yes") diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c new file mode 100644 index 000000000000..1d99206dd3a8 --- /dev/null +++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2022 NXP. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BBNSM_CTRL 0x8 +#define BBNSM_INT_EN 0x10 +#define BBNSM_EVENTS 0x14 +#define BBNSM_PAD_CTRL 0x24 + +#define BBNSM_BTN_PRESSED BIT(7) +#define BBNSM_PWR_ON BIT(6) +#define BBNSM_BTN_OFF BIT(5) +#define BBNSM_EMG_OFF BIT(4) +#define BBNSM_PWRKEY_EVENTS (BBNSM_PWR_ON | BBNSM_BTN_OFF | BBNSM_EMG_OFF) +#define BBNSM_DP_EN BIT(24) + +#define DEBOUNCE_TIME 30 +#define REPEAT_INTERVAL 60 + +struct bbnsm_pwrkey { + struct regmap *regmap; + int irq; + int keycode; + int keystate; /* 1:pressed */ + struct timer_list check_timer; + struct input_dev *input; +}; + +static void bbnsm_pwrkey_check_for_events(struct timer_list *t) +{ + struct bbnsm_pwrkey *bbnsm = from_timer(bbnsm, t, check_timer); + struct input_dev *input = bbnsm->input; + u32 state; + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &state); + + state = state & BBNSM_BTN_PRESSED ? 1 : 0; + + /* only report new event if status changed */ + if (state ^ bbnsm->keystate) { + bbnsm->keystate = state; + input_event(input, EV_KEY, bbnsm->keycode, state); + input_sync(input); + pm_relax(bbnsm->input->dev.parent); + } + + /* repeat check if pressed long */ + if (state) + mod_timer(&bbnsm->check_timer, + jiffies + msecs_to_jiffies(REPEAT_INTERVAL)); +} + +static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev); + u32 event; + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event); + if (!(event & BBNSM_BTN_OFF)) + return IRQ_NONE; + + pm_wakeup_event(bbnsm->input->dev.parent, 0); + + mod_timer(&bbnsm->check_timer, + jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); + + /* clear PWR OFF */ + regmap_write(bbnsm->regmap, BBNSM_EVENTS, BBNSM_BTN_OFF); + + return IRQ_HANDLED; +} + +static void bbnsm_pwrkey_act(void *pdata) +{ + struct bbnsm_pwrkey *bbnsm = pdata; + + timer_shutdown_sync(&bbnsm->check_timer); +} + +static int bbnsm_pwrkey_probe(struct platform_device *pdev) +{ + struct bbnsm_pwrkey *bbnsm; + struct input_dev *input; + struct device_node *np = pdev->dev.of_node; + int error; + + bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL); + if (!bbnsm) + return -ENOMEM; + + bbnsm->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(bbnsm->regmap)) { + dev_err(&pdev->dev, "bbnsm pwerkey get regmap failed\n"); + return PTR_ERR(bbnsm->regmap); + } + + if (device_property_read_u32(&pdev->dev, "linux,code", + &bbnsm->keycode)) { + bbnsm->keycode = KEY_POWER; + dev_warn(&pdev->dev, "key code is not specified, using default KEY_POWER\n"); + } + + bbnsm->irq = platform_get_irq(pdev, 0); + if (bbnsm->irq < 0) + return -EINVAL; + + /* config the BBNSM power related register */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, BBNSM_DP_EN, BBNSM_DP_EN); + + /* clear the unexpected interrupt before driver ready */ + regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, BBNSM_PWRKEY_EVENTS, + BBNSM_PWRKEY_EVENTS); + + timer_setup(&bbnsm->check_timer, bbnsm_pwrkey_check_for_events, 0); + + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + input->name = pdev->name; + input->phys = "bbnsm-pwrkey/input0"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_KEY, bbnsm->keycode); + + /* input customer action to cancel release timer */ + error = devm_add_action(&pdev->dev, bbnsm_pwrkey_act, bbnsm); + if (error) { + dev_err(&pdev->dev, "failed to register remove action\n"); + return error; + } + + bbnsm->input = input; + platform_set_drvdata(pdev, bbnsm); + + error = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_pwrkey_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (error) { + dev_err(&pdev->dev, "interrupt not available.\n"); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + device_init_wakeup(&pdev->dev, true); + error = dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq); + if (error) + dev_warn(&pdev->dev, "irq wake enable failed.\n"); + + return 0; +} + +static const struct of_device_id bbnsm_pwrkey_ids[] = { + { .compatible = "nxp,imx93-bbnsm-pwrkey" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bbnsm_pwrkey_ids); + +static struct platform_driver bbnsm_pwrkey_driver = { + .driver = { + .name = "bbnsm_pwrkey", + .of_match_table = bbnsm_pwrkey_ids, + }, + .probe = bbnsm_pwrkey_probe, +}; +module_platform_driver(bbnsm_pwrkey_driver); + +MODULE_AUTHOR("Jacky Bai "); +MODULE_DESCRIPTION("NXP bbnsm power key Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 50a0134b6901..f2e093b0b998 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -285,7 +285,7 @@ void rmi_unregister_function(struct rmi_function *fn) } /** - * rmi_register_function_handler - register a handler for an RMI function + * __rmi_register_function_handler - register a handler for an RMI function * @handler: RMI handler that should be registered. * @owner: pointer to module that implements the handler * @mod_name: name of the module implementing the handler diff --git a/drivers/input/tests/.kunitconfig b/drivers/input/tests/.kunitconfig new file mode 100644 index 000000000000..2f5bedf8028e --- /dev/null +++ b/drivers/input/tests/.kunitconfig @@ -0,0 +1,3 @@ +CONFIG_KUNIT=y +CONFIG_INPUT=y +CONFIG_INPUT_KUNIT_TEST=y diff --git a/drivers/input/tests/Makefile b/drivers/input/tests/Makefile new file mode 100644 index 000000000000..90cf954181bc --- /dev/null +++ b/drivers/input/tests/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_INPUT_KUNIT_TEST) += input_test.o diff --git a/drivers/input/tests/input_test.c b/drivers/input/tests/input_test.c new file mode 100644 index 000000000000..e5a6c1ad2167 --- /dev/null +++ b/drivers/input/tests/input_test.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for the input core. + * + * Copyright (c) 2023 Red Hat Inc + */ + +#include +#include + +#include + +#define POLL_INTERVAL 100 + +static int input_test_init(struct kunit *test) +{ + struct input_dev *input_dev; + int ret; + + input_dev = input_allocate_device(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, input_dev); + + input_dev->name = "Test input device"; + input_dev->id.bustype = BUS_VIRTUAL; + input_dev->id.vendor = 1; + input_dev->id.product = 1; + input_dev->id.version = 1; + input_set_capability(input_dev, EV_KEY, BTN_LEFT); + input_set_capability(input_dev, EV_KEY, BTN_RIGHT); + + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + KUNIT_ASSERT_FAILURE(test, "Register device failed: %d", ret); + } + + test->priv = input_dev; + + return 0; +} + +static void input_test_exit(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + + input_unregister_device(input_dev); + input_free_device(input_dev); +} + +static void input_test_poll(struct input_dev *input) { } + +static void input_test_polling(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + + /* Must fail because a poll handler has not been set-up yet */ + KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), -EINVAL); + + KUNIT_ASSERT_EQ(test, input_setup_polling(input_dev, input_test_poll), 0); + + input_set_poll_interval(input_dev, POLL_INTERVAL); + + /* Must succeed because poll handler was set-up and poll interval set */ + KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), POLL_INTERVAL); +} + +static void input_test_timestamp(struct kunit *test) +{ + const ktime_t invalid_timestamp = ktime_set(0, 0); + struct input_dev *input_dev = test->priv; + ktime_t *timestamp, time; + + timestamp = input_get_timestamp(input_dev); + time = timestamp[INPUT_CLK_MONO]; + + /* The returned timestamp must always be valid */ + KUNIT_ASSERT_EQ(test, ktime_compare(time, invalid_timestamp), 1); + + time = ktime_get(); + input_set_timestamp(input_dev, time); + + timestamp = input_get_timestamp(input_dev); + /* The timestamp must be the same than set before */ + KUNIT_ASSERT_EQ(test, ktime_compare(timestamp[INPUT_CLK_MONO], time), 0); +} + +static void input_test_match_device_id(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + struct input_device_id id; + + /* + * Must match when the input device bus, vendor, product, version + * and events capable of handling are the same and fail to match + * otherwise. + */ + id.flags = INPUT_DEVICE_ID_MATCH_BUS; + id.bustype = BUS_VIRTUAL; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.bustype = BUS_I2C; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VENDOR; + id.vendor = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.vendor = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_PRODUCT; + id.product = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.product = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VERSION; + id.version = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.version = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_EVBIT; + __set_bit(EV_KEY, id.evbit); + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + __set_bit(EV_ABS, id.evbit); + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); +} + +static struct kunit_case input_tests[] = { + KUNIT_CASE(input_test_polling), + KUNIT_CASE(input_test_timestamp), + KUNIT_CASE(input_test_match_device_id), + { /* sentinel */ } +}; + +static struct kunit_suite input_test_suite = { + .name = "input_core", + .init = input_test_init, + .exit = input_test_exit, + .test_cases = input_tests, +}; + +kunit_test_suite(input_test_suite); + +MODULE_AUTHOR("Javier Martinez Canillas "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1a2049b336a6..143ff43c67ae 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -654,6 +654,16 @@ config TOUCHSCREEN_MTOUCH To compile this driver as a module, choose M here: the module will be called mtouch. +config TOUCHSCREEN_NOVATEK_NVT_TS + tristate "Novatek NVT-ts touchscreen support" + depends on I2C + help + Say Y here if you have a Novatek NVT-ts touchscreen. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called novatek-nvt-ts. + config TOUCHSCREEN_IMAGIS tristate "Imagis touchscreen support" depends on I2C @@ -758,6 +768,7 @@ config TOUCHSCREEN_PENMOUNT config TOUCHSCREEN_EDT_FT5X06 tristate "EDT FocalTech FT5x06 I2C Touchscreen support" depends on I2C + select REGMAP_I2C help Say Y here if you have an EDT "Polytouch" touchscreen based on the FocalTech FT5x06 family of controllers connected to diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f2fd28cc34a6..159cd5136fdb 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o +obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 35e2fe9911a4..9c84235327bf 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -511,7 +511,7 @@ static struct platform_driver iproc_ts_driver = { .probe = iproc_ts_probe, .driver = { .name = IPROC_TS_NAME, - .of_match_table = of_match_ptr(iproc_ts_of_match), + .of_match_table = iproc_ts_of_match, }, }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 2746649561c7..24ab9e9f5b21 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -3,6 +3,7 @@ * Copyright (C) 2012 Simon Budig, * Daniel Wagener (M09 firmware support) * Lothar Waßmann (DT support) + * Dario Binacchi (regmap support) */ /* @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +77,9 @@ #define EDT_DEFAULT_NUM_X 1024 #define EDT_DEFAULT_NUM_Y 1024 +#define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) +#define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) + enum edt_pmode { EDT_PMODE_NOT_SUPPORTED, EDT_PMODE_HIBERNATE, @@ -112,6 +117,8 @@ struct edt_ft5x06_ts_data { struct gpio_desc *reset_gpio; struct gpio_desc *wake_gpio; + struct regmap *regmap; + #if defined(CONFIG_DEBUG_FS) struct dentry *debug_dir; u8 *raw_buffer; @@ -128,6 +135,10 @@ struct edt_ft5x06_ts_data { int offset_y; int report_rate; int max_support_points; + int point_len; + u8 tdata_cmd; + int tdata_len; + int tdata_offset; char name[EDT_NAME_LEN]; char fw_version[EDT_NAME_LEN]; @@ -142,37 +153,10 @@ struct edt_i2c_chip_data { int max_support_points; }; -static int edt_ft5x06_ts_readwrite(struct i2c_client *client, - u16 wr_len, u8 *wr_buf, - u16 rd_len, u8 *rd_buf) -{ - struct i2c_msg wrmsg[2]; - int i = 0; - int ret; - - if (wr_len) { - wrmsg[i].addr = client->addr; - wrmsg[i].flags = 0; - wrmsg[i].len = wr_len; - wrmsg[i].buf = wr_buf; - i++; - } - if (rd_len) { - wrmsg[i].addr = client->addr; - wrmsg[i].flags = I2C_M_RD; - wrmsg[i].len = rd_len; - wrmsg[i].buf = rd_buf; - i++; - } - - ret = i2c_transfer(client->adapter, wrmsg, i); - if (ret < 0) - return ret; - if (ret != i) - return -EIO; - - return 0; -} +static const struct regmap_config edt_ft5x06_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, u8 *buf, int buflen) @@ -183,78 +167,154 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, for (i = 0; i < buflen - 1; i++) crc ^= buf[i]; - if (crc != buf[buflen-1]) { + if (crc != buf[buflen - 1]) { tsdata->crc_errors++; dev_err_ratelimited(&tsdata->client->dev, "crc error: 0x%02x expected, got 0x%02x\n", - crc, buf[buflen-1]); + crc, buf[buflen - 1]); return false; } return true; } +static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + struct i2c_msg xfer[2]; + bool reg_read = false; + u8 addr; + u8 wlen; + u8 wbuf[4], rbuf[3]; + int ret; + + addr = *((u8 *)reg_buf); + wbuf[0] = addr; + switch (addr) { + case 0xf5: + wlen = 3; + wbuf[0] = 0xf5; + wbuf[1] = 0xe; + wbuf[2] = *((u8 *)val_buf); + break; + case 0xf9: + wlen = 1; + break; + default: + wlen = 2; + reg_read = true; + wbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); + wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; + } + + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = wlen; + xfer[0].buf = wbuf; + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = reg_read ? 2 : val_size; + xfer[1].buf = reg_read ? rbuf : val_buf; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + if (ret < 0) + return ret; + + return -EIO; + } + + if (addr == 0xf9) { + u8 *buf = (u8 *)val_buf; + + if (buf[0] != 0xaa || buf[1] != 0xaa || + buf[2] != val_size) { + tsdata->header_errors++; + dev_err_ratelimited(dev, + "Unexpected header: %02x%02x%02x\n", + buf[0], buf[1], buf[2]); + return -EIO; + } + + if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size)) + return -EIO; + } else if (reg_read) { + wbuf[2] = rbuf[0]; + wbuf[3] = rbuf[1]; + if (!edt_ft5x06_ts_check_crc(tsdata, wbuf, 4)) + return -EIO; + + *((u8 *)val_buf) = rbuf[0]; + } + + return 0; +} + +static int edt_M06_i2c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + u8 addr, val; + u8 wbuf[4]; + struct i2c_msg xfer; + int ret; + + addr = *((u8 *)data); + val = *((u8 *)data + 1); + + wbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); + wbuf[2] = val; + wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2]; + + xfer.addr = i2c->addr; + xfer.flags = 0; + xfer.len = 4; + xfer.buf = wbuf; + + ret = i2c_transfer(i2c->adapter, &xfer, 1); + if (ret != 1) { + if (ret < 0) + return ret; + + return -EIO; + } + + return 0; +} + +static const struct regmap_config edt_M06_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read = edt_M06_i2c_read, + .write = edt_M06_i2c_write, +}; + static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) { struct edt_ft5x06_ts_data *tsdata = dev_id; struct device *dev = &tsdata->client->dev; - u8 cmd; u8 rdbuf[63]; int i, type, x, y, id; - int offset, tplen, datalen, crclen; int error; - switch (tsdata->version) { - case EDT_M06: - cmd = 0xf9; /* tell the controller to send touch data */ - offset = 5; /* where the actual touch data starts */ - tplen = 4; /* data comes in so called frames */ - crclen = 1; /* length of the crc data */ - break; - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - cmd = 0x0; - offset = 3; - tplen = 6; - crclen = 0; - break; - - default: - goto out; - } - memset(rdbuf, 0, sizeof(rdbuf)); - datalen = tplen * tsdata->max_support_points + offset + crclen; - - error = edt_ft5x06_ts_readwrite(tsdata->client, - sizeof(cmd), &cmd, - datalen, rdbuf); + error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, + tsdata->tdata_len); if (error) { dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error); goto out; } - /* M09/M12 does not send header or CRC */ - if (tsdata->version == EDT_M06) { - if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || - rdbuf[2] != datalen) { - tsdata->header_errors++; - dev_err_ratelimited(dev, - "Unexpected header: %02x%02x%02x!\n", - rdbuf[0], rdbuf[1], rdbuf[2]); - goto out; - } - - if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) - goto out; - } - for (i = 0; i < tsdata->max_support_points; i++) { - u8 *buf = &rdbuf[i * tplen + offset]; + u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset]; type = buf[0] >> 6; /* ignore Reserved events */ @@ -287,79 +347,6 @@ out: return IRQ_HANDLED; } -static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, - u8 addr, u8 value) -{ - u8 wrbuf[4]; - - switch (tsdata->version) { - case EDT_M06: - wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; - wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; - wrbuf[2] = value; - wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; - return edt_ft5x06_ts_readwrite(tsdata->client, 4, - wrbuf, 0, NULL); - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - wrbuf[0] = addr; - wrbuf[1] = value; - - return edt_ft5x06_ts_readwrite(tsdata->client, 2, - wrbuf, 0, NULL); - - default: - return -EINVAL; - } -} - -static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, - u8 addr) -{ - u8 wrbuf[2], rdbuf[2]; - int error; - - switch (tsdata->version) { - case EDT_M06: - wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; - wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; - wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; - - error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, - rdbuf); - if (error) - return error; - - if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { - dev_err(&tsdata->client->dev, - "crc error: 0x%02x expected, got 0x%02x\n", - wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], - rdbuf[1]); - return -EIO; - } - break; - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - wrbuf[0] = addr; - error = edt_ft5x06_ts_readwrite(tsdata->client, 1, - wrbuf, 1, rdbuf); - if (error) - return error; - break; - - default: - return -EINVAL; - } - - return rdbuf[0]; -} - struct edt_ft5x06_attribute { struct device_attribute dattr; size_t field_offset; @@ -393,7 +380,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, struct edt_ft5x06_attribute *attr = container_of(dattr, struct edt_ft5x06_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; - int val; + unsigned int val; size_t count = 0; int error = 0; u8 addr; @@ -426,9 +413,8 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, } if (addr != NO_REGISTER) { - val = edt_ft5x06_register_read(tsdata, addr); - if (val < 0) { - error = val; + error = regmap_read(tsdata->regmap, addr, &val); + if (error) { dev_err(&tsdata->client->dev, "Failed to fetch attribute %s, error %d\n", dattr->attr.name, error); @@ -501,7 +487,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, } if (addr != NO_REGISTER) { - error = edt_ft5x06_register_write(tsdata, addr, val); + error = regmap_write(tsdata->regmap, addr, val); if (error) { dev_err(&tsdata->client->dev, "Failed to update attribute %s, error: %d\n", @@ -602,24 +588,19 @@ static const struct attribute_group edt_ft5x06_attr_group = { static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; - edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, - tsdata->threshold); - edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, - tsdata->gain); + regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold); + regmap_write(regmap, reg_addr->reg_gain, tsdata->gain); if (reg_addr->reg_offset != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, - tsdata->offset); + regmap_write(regmap, reg_addr->reg_offset, tsdata->offset); if (reg_addr->reg_offset_x != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, - tsdata->offset_x); + regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x); if (reg_addr->reg_offset_y != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, - tsdata->offset_y); + regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, - tsdata->report_rate); - + regmap_write(regmap, reg_addr->reg_report_rate, + tsdata->report_rate); } #ifdef CONFIG_DEBUG_FS @@ -627,7 +608,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) { struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; - int ret; + unsigned int val; int error; if (tsdata->version != EDT_M06) { @@ -649,7 +630,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) } /* mode register is 0x3c when in the work mode */ - error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); + error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03); if (error) { dev_err(&client->dev, "failed to switch to factory mode, error %d\n", error); @@ -660,8 +641,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) do { mdelay(EDT_SWITCH_MODE_DELAY); /* mode register is 0x01 when in factory mode */ - ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE); - if (ret == 0x03) + error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE, + &val); + if (!error && val == 0x03) break; } while (--retries > 0); @@ -687,11 +669,11 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) { struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; - int ret; + unsigned int val; int error; /* mode register is 0x01 when in the factory mode */ - error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1); + error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1); if (error) { dev_err(&client->dev, "failed to switch to work mode, error: %d\n", error); @@ -703,8 +685,8 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) do { mdelay(EDT_SWITCH_MODE_DELAY); /* mode register is 0x01 when in factory mode */ - ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE); - if (ret == 0x01) + error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val); + if (!error && val == 0x01) break; } while (--retries > 0); @@ -757,15 +739,16 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, edt_ft5x06_debugfs_mode_set, "%llu\n"); static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, - char __user *buf, size_t count, loff_t *off) + char __user *buf, size_t count, + loff_t *off) { struct edt_ft5x06_ts_data *tsdata = file->private_data; struct i2c_client *client = tsdata->client; int retries = EDT_RAW_DATA_RETRIES; - int val, i, error; + unsigned int val; + int i, error; size_t read = 0; int colbytes; - char wrbuf[3]; u8 *rdbuf; if (*off < 0 || *off >= tsdata->raw_bufsize) @@ -778,29 +761,29 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, goto out; } - error = edt_ft5x06_register_write(tsdata, 0x08, 0x01); + error = regmap_write(tsdata->regmap, 0x08, 0x01); if (error) { - dev_dbg(&client->dev, + dev_err(&client->dev, "failed to write 0x08 register, error %d\n", error); goto out; } do { usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100); - val = edt_ft5x06_register_read(tsdata, 0x08); - if (val < 1) + error = regmap_read(tsdata->regmap, 0x08, &val); + if (error) { + dev_err(&client->dev, + "failed to read 0x08 register, error %d\n", + error); + goto out; + } + + if (val == 1) break; } while (--retries > 0); - if (val < 0) { - error = val; - dev_dbg(&client->dev, - "failed to read 0x08 register, error %d\n", error); - goto out; - } - if (retries == 0) { - dev_dbg(&client->dev, + dev_err(&client->dev, "timed out waiting for register to settle\n"); error = -ETIMEDOUT; goto out; @@ -809,13 +792,9 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, rdbuf = tsdata->raw_buffer; colbytes = tsdata->num_y * sizeof(u16); - wrbuf[0] = 0xf5; - wrbuf[1] = 0x0e; for (i = 0; i < tsdata->num_x; i++) { - wrbuf[2] = i; /* column index */ - error = edt_ft5x06_ts_readwrite(tsdata->client, - sizeof(wrbuf), wrbuf, - colbytes, rdbuf); + rdbuf[0] = i; /* column index */ + error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes); if (error) goto out; @@ -891,8 +870,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, * to have garbage in there */ memset(rdbuf, 0, sizeof(rdbuf)); - error = edt_ft5x06_ts_readwrite(client, 1, "\xBB", - EDT_NAME_LEN - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1); if (error) return error; @@ -914,6 +892,14 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, *p++ = '\0'; strscpy(model_name, rdbuf + 1, EDT_NAME_LEN); strscpy(fw_version, p ? p : "", EDT_NAME_LEN); + + regmap_exit(tsdata->regmap); + tsdata->regmap = regmap_init_i2c(client, + &edt_M06_i2c_regmap_config); + if (IS_ERR(tsdata->regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(tsdata->regmap); + } } else if (!strncasecmp(rdbuf, "EP0", 3)) { tsdata->version = EDT_M12; @@ -940,15 +926,13 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, */ tsdata->version = GENERIC_FT; - error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", - 2, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2); if (error) return error; strscpy(fw_version, rdbuf, 2); - error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1); if (error) return error; @@ -965,20 +949,19 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, case 0x70: /* EDT EP0700M09 */ tsdata->version = EDT_M09; snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", - rdbuf[0] >> 4, rdbuf[0] & 0x0F); + rdbuf[0] >> 4, rdbuf[0] & 0x0F); break; case 0xa1: /* EDT EP1010ML00 */ tsdata->version = EDT_M09; snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", - rdbuf[0] >> 4, rdbuf[0] & 0x0F); + rdbuf[0] >> 4, rdbuf[0] & 0x0F); break; case 0x5a: /* Solomon Goldentek Display */ snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); break; case 0x59: /* Evervision Display with FT5xx6 TS */ tsdata->version = EV_FT; - error = edt_ft5x06_ts_readwrite(client, 1, "\x53", - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1); if (error) return error; strscpy(fw_version, rdbuf, 1); @@ -1000,42 +983,40 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; u32 val; int error; error = device_property_read_u32(dev, "threshold", &val); if (!error) { - edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val); + regmap_write(regmap, reg_addr->reg_threshold, val); tsdata->threshold = val; } error = device_property_read_u32(dev, "gain", &val); if (!error) { - edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val); + regmap_write(regmap, reg_addr->reg_gain, val); tsdata->gain = val; } error = device_property_read_u32(dev, "offset", &val); if (!error) { if (reg_addr->reg_offset != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset, val); + regmap_write(regmap, reg_addr->reg_offset, val); tsdata->offset = val; } error = device_property_read_u32(dev, "offset-x", &val); if (!error) { if (reg_addr->reg_offset_x != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset_x, val); + regmap_write(regmap, reg_addr->reg_offset_x, val); tsdata->offset_x = val; } error = device_property_read_u32(dev, "offset-y", &val); if (!error) { if (reg_addr->reg_offset_y != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset_y, val); + regmap_write(regmap, reg_addr->reg_offset_y, val); tsdata->offset_y = val; } } @@ -1043,30 +1024,50 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; + unsigned int val; - tsdata->threshold = edt_ft5x06_register_read(tsdata, - reg_addr->reg_threshold); - tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); + regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold); + regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain); if (reg_addr->reg_offset != NO_REGISTER) - tsdata->offset = - edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset); if (reg_addr->reg_offset_x != NO_REGISTER) - tsdata->offset_x = edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_x); + regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x); if (reg_addr->reg_offset_y != NO_REGISTER) - tsdata->offset_y = edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_y); + regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) - tsdata->report_rate = edt_ft5x06_register_read(tsdata, - reg_addr->reg_report_rate); + regmap_read(regmap, reg_addr->reg_report_rate, + &tsdata->report_rate); tsdata->num_x = EDT_DEFAULT_NUM_X; - if (reg_addr->reg_num_x != NO_REGISTER) - tsdata->num_x = edt_ft5x06_register_read(tsdata, - reg_addr->reg_num_x); + if (reg_addr->reg_num_x != NO_REGISTER) { + if (!regmap_read(regmap, reg_addr->reg_num_x, &val)) + tsdata->num_x = val; + } tsdata->num_y = EDT_DEFAULT_NUM_Y; - if (reg_addr->reg_num_y != NO_REGISTER) - tsdata->num_y = edt_ft5x06_register_read(tsdata, - reg_addr->reg_num_y); + if (reg_addr->reg_num_y != NO_REGISTER) { + if (!regmap_read(regmap, reg_addr->reg_num_y, &val)) + tsdata->num_y = val; + } +} + +static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata) +{ + int crclen; + + if (tsdata->version == EDT_M06) { + tsdata->tdata_cmd = 0xf9; + tsdata->tdata_offset = 5; + tsdata->point_len = 4; + crclen = 1; + } else { + tsdata->tdata_cmd = 0x0; + tsdata->tdata_offset = 3; + tsdata->point_len = 6; + crclen = 0; + } + + tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points + + tsdata->tdata_offset + crclen; } static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) @@ -1136,7 +1137,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; - u8 buf[2] = { 0xfc, 0x00 }; + unsigned int val; struct input_dev *input; unsigned long irq_flags; int error; @@ -1150,6 +1151,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) return -ENOMEM; } + tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); + if (IS_ERR(tsdata->regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(tsdata->regmap); + } + chip_data = device_get_match_data(&client->dev); if (!chip_data) chip_data = (const struct edt_i2c_chip_data *)id->driver_data; @@ -1252,6 +1259,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) tsdata->client = client; tsdata->input = input; tsdata->factory_mode = false; + i2c_set_clientdata(client, tsdata); error = edt_ft5x06_ts_identify(client, tsdata); if (error) { @@ -1263,8 +1271,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) * Dummy read access. EP0700MLP1 returns bogus data on the first * register read access and ignores writes. */ - edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf); + regmap_read(tsdata->regmap, 0x00, &val); + edt_ft5x06_ts_set_tdata_parameters(tsdata); edt_ft5x06_ts_set_regs(tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); @@ -1285,9 +1294,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) if (tsdata->version == EDT_M06) tsdata->report_rate /= 10; - edt_ft5x06_register_write(tsdata, - tsdata->reg_addr.reg_report_rate, - tsdata->report_rate); + regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate, + tsdata->report_rate); } dev_dbg(&client->dev, @@ -1306,22 +1314,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) touchscreen_parse_properties(input, true, &tsdata->prop); error = input_mt_init_slots(input, tsdata->max_support_points, - INPUT_MT_DIRECT); + INPUT_MT_DIRECT); if (error) { dev_err(&client->dev, "Unable to init MT slots.\n"); return error; } - i2c_set_clientdata(client, tsdata); - irq_flags = irq_get_trigger_type(client->irq); if (irq_flags == IRQF_TRIGGER_NONE) irq_flags = IRQF_TRIGGER_FALLING; irq_flags |= IRQF_ONESHOT; error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, edt_ft5x06_ts_isr, irq_flags, - client->name, tsdata); + NULL, edt_ft5x06_ts_isr, irq_flags, + client->name, tsdata); if (error) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); return error; @@ -1351,6 +1357,7 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); edt_ft5x06_ts_teardown_debugfs(tsdata); + regmap_exit(tsdata->regmap); } static int edt_ft5x06_ts_suspend(struct device *dev) @@ -1367,8 +1374,8 @@ static int edt_ft5x06_ts_suspend(struct device *dev) return 0; /* Enter hibernate mode. */ - ret = edt_ft5x06_register_write(tsdata, PMOD_REGISTER_OPMODE, - PMOD_REGISTER_HIBERNATE); + ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE, + PMOD_REGISTER_HIBERNATE); if (ret) dev_warn(dev, "Failed to set hibernate mode\n"); @@ -1455,7 +1462,6 @@ static int edt_ft5x06_ts_resume(struct device *dev) gpiod_set_value_cansleep(wake_gpio, 1); } - return ret; } diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index bd454d93f1f7..7c7020099b0f 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -35,6 +35,7 @@ #define HIDEEP_EVENT_ADDR 0x240 /* command list */ +#define HIDEEP_WORK_MODE 0x081e #define HIDEEP_RESET_CMD 0x9800 /* event bit */ @@ -271,9 +272,14 @@ static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val) #define SW_RESET_IN_PGM(clk) \ { \ + __be32 data = cpu_to_be32(0x01); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \ - hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x01); \ + /* \ + * The first write may already cause a reset, use a raw \ + * write for the second write to avoid error logging. \ + */ \ + hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \ } #define SET_FLASH_PIO(ce) \ @@ -467,9 +473,9 @@ static int hideep_program_nvm(struct hideep_ts *ts, u32 addr = 0; int error; - error = hideep_nvm_unlock(ts); - if (error) - return error; + error = hideep_nvm_unlock(ts); + if (error) + return error; while (ucode_len > 0) { xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE); @@ -959,6 +965,21 @@ static const struct attribute_group hideep_ts_attr_group = { .attrs = hideep_ts_sysfs_entries, }; +static void hideep_set_work_mode(struct hideep_ts *ts) +{ + /* + * Reset touch report format to the native HiDeep 20 protocol if requested. + * This is necessary to make touchscreens which come up in I2C-HID mode + * work with this driver. + * + * Note this is a kernel internal device-property set by x86 platform code, + * this MUST not be used in devicetree files without first adding it to + * the DT bindings. + */ + if (device_property_read_bool(&ts->client->dev, "hideep,force-native-protocol")) + regmap_write(ts->reg, HIDEEP_WORK_MODE, 0x00); +} + static int hideep_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -982,6 +1003,8 @@ static int hideep_resume(struct device *dev) return error; } + hideep_set_work_mode(ts); + enable_irq(client->irq); return 0; @@ -1058,6 +1081,8 @@ static int hideep_probe(struct i2c_client *client) return error; } + hideep_set_work_mode(ts); + error = hideep_init_input(ts); if (error) return error; diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index acdfbdea2b6e..89b6020a9a61 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -466,7 +466,7 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) { int id; bool __always_unused hover; - bool __always_unused palm; + bool palm; bool state; u16 x, y; u8 __always_unused pressure_stage = 0; @@ -522,21 +522,21 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) if (unlikely(id < 0 || id >= MIP4_MAX_FINGERS)) { dev_err(&ts->client->dev, "Screen - invalid slot ID: %d\n", id); - } else if (state) { - /* Press or Move event */ - input_mt_slot(ts->input, id); - input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + goto out; + } + + input_mt_slot(ts->input, id); + if (input_mt_report_slot_state(ts->input, + palm ? MT_TOOL_PALM : MT_TOOL_FINGER, + state)) { input_report_abs(ts->input, ABS_MT_POSITION_X, x); input_report_abs(ts->input, ABS_MT_POSITION_Y, y); input_report_abs(ts->input, ABS_MT_PRESSURE, pressure); input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, touch_major); input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, touch_minor); - } else { - /* Release event */ - input_mt_slot(ts->input, id); - input_mt_report_slot_inactive(ts->input); } +out: input_mt_sync_frame(ts->input); } @@ -1483,6 +1483,7 @@ static int mip4_probe(struct i2c_client *client) input->keycodesize = sizeof(*ts->key_code); input->keycodemax = ts->key_num; + input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0); input_set_abs_params(input, ABS_MT_PRESSURE, diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c new file mode 100644 index 000000000000..3e551f9d31d7 --- /dev/null +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Novatek i2c touchscreen controller as found on + * the Acer Iconia One 7 B1-750 tablet. The Touchscreen controller + * model-number is unknown. Android calls this a "NVT-ts" touchscreen, + * but that may apply to other Novatek controller models too. + * + * Copyright (c) 2023 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NVT_TS_TOUCH_START 0x00 +#define NVT_TS_TOUCH_SIZE 6 + +#define NVT_TS_PARAMETERS_START 0x78 +/* These are offsets from NVT_TS_PARAMETERS_START */ +#define NVT_TS_PARAMS_WIDTH 0x04 +#define NVT_TS_PARAMS_HEIGHT 0x06 +#define NVT_TS_PARAMS_MAX_TOUCH 0x09 +#define NVT_TS_PARAMS_MAX_BUTTONS 0x0a +#define NVT_TS_PARAMS_IRQ_TYPE 0x0b +#define NVT_TS_PARAMS_WAKE_TYPE 0x0c +#define NVT_TS_PARAMS_CHIP_ID 0x0e +#define NVT_TS_PARAMS_SIZE 0x0f + +#define NVT_TS_SUPPORTED_WAKE_TYPE 0x05 +#define NVT_TS_SUPPORTED_CHIP_ID 0x05 + +#define NVT_TS_MAX_TOUCHES 10 +#define NVT_TS_MAX_SIZE 4096 + +#define NVT_TS_TOUCH_INVALID 0xff +#define NVT_TS_TOUCH_SLOT_SHIFT 3 +#define NVT_TS_TOUCH_TYPE_MASK GENMASK(2, 0) +#define NVT_TS_TOUCH_NEW 1 +#define NVT_TS_TOUCH_UPDATE 2 +#define NVT_TS_TOUCH_RELEASE 3 + +static const int nvt_ts_irq_type[4] = { + IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_LOW, + IRQF_TRIGGER_HIGH +}; + +struct nvt_ts_data { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *reset_gpio; + struct touchscreen_properties prop; + int max_touches; + u8 buf[NVT_TS_TOUCH_SIZE * NVT_TS_MAX_TOUCHES]; +}; + +static int nvt_ts_read_data(struct i2c_client *client, u8 reg, u8 *data, int count) +{ + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = count, + .buf = data, + } + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, "Error reading from 0x%02x: %d\n", reg, ret); + return (ret < 0) ? ret : -EIO; + } + + return 0; +} + +static irqreturn_t nvt_ts_irq(int irq, void *dev_id) +{ + struct nvt_ts_data *data = dev_id; + struct device *dev = &data->client->dev; + int i, error, slot, x, y; + bool active; + u8 *touch; + + error = nvt_ts_read_data(data->client, NVT_TS_TOUCH_START, data->buf, + data->max_touches * NVT_TS_TOUCH_SIZE); + if (error) + return IRQ_HANDLED; + + for (i = 0; i < data->max_touches; i++) { + touch = &data->buf[i * NVT_TS_TOUCH_SIZE]; + + if (touch[0] == NVT_TS_TOUCH_INVALID) + continue; + + slot = touch[0] >> NVT_TS_TOUCH_SLOT_SHIFT; + if (slot < 1 || slot > data->max_touches) { + dev_warn(dev, "slot %d out of range, ignoring\n", slot); + continue; + } + + switch (touch[0] & NVT_TS_TOUCH_TYPE_MASK) { + case NVT_TS_TOUCH_NEW: + case NVT_TS_TOUCH_UPDATE: + active = true; + break; + case NVT_TS_TOUCH_RELEASE: + active = false; + break; + default: + dev_warn(dev, "slot %d unknown state %d\n", slot, touch[0] & 7); + continue; + } + + slot--; + x = (touch[1] << 4) | (touch[3] >> 4); + y = (touch[2] << 4) | (touch[3] & 0x0f); + + input_mt_slot(data->input, slot); + input_mt_report_slot_state(data->input, MT_TOOL_FINGER, active); + touchscreen_report_pos(data->input, &data->prop, x, y, true); + } + + input_mt_sync_frame(data->input); + input_sync(data->input); + + return IRQ_HANDLED; +} + +static int nvt_ts_start(struct input_dev *dev) +{ + struct nvt_ts_data *data = input_get_drvdata(dev); + + enable_irq(data->client->irq); + gpiod_set_value_cansleep(data->reset_gpio, 0); + + return 0; +} + +static void nvt_ts_stop(struct input_dev *dev) +{ + struct nvt_ts_data *data = input_get_drvdata(dev); + + disable_irq(data->client->irq); + gpiod_set_value_cansleep(data->reset_gpio, 1); +} + +static int nvt_ts_suspend(struct device *dev) +{ + struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (input_device_enabled(data->input)) + nvt_ts_stop(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} + +static int nvt_ts_resume(struct device *dev) +{ + struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (input_device_enabled(data->input)) + nvt_ts_start(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(nvt_ts_pm_ops, nvt_ts_suspend, nvt_ts_resume); + +static int nvt_ts_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int error, width, height, irq_type; + struct nvt_ts_data *data; + struct input_dev *input; + + if (!client->irq) { + dev_err(dev, "Error no irq specified\n"); + return -EINVAL; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + i2c_set_clientdata(client, data); + + data->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + error = PTR_ERR_OR_ZERO(data->reset_gpio); + if (error) { + dev_err(dev, "failed to request reset GPIO: %d\n", error); + return error; + } + + /* Wait for controller to come out of reset before params read */ + msleep(100); + error = nvt_ts_read_data(data->client, NVT_TS_PARAMETERS_START, + data->buf, NVT_TS_PARAMS_SIZE); + gpiod_set_value_cansleep(data->reset_gpio, 1); /* Put back in reset */ + if (error) + return error; + + width = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_WIDTH]); + height = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_HEIGHT]); + data->max_touches = data->buf[NVT_TS_PARAMS_MAX_TOUCH]; + irq_type = data->buf[NVT_TS_PARAMS_IRQ_TYPE]; + + if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE || + data->max_touches > NVT_TS_MAX_TOUCHES || + irq_type >= ARRAY_SIZE(nvt_ts_irq_type) || + data->buf[NVT_TS_PARAMS_WAKE_TYPE] != NVT_TS_SUPPORTED_WAKE_TYPE || + data->buf[NVT_TS_PARAMS_CHIP_ID] != NVT_TS_SUPPORTED_CHIP_ID) { + dev_err(dev, "Unsupported touchscreen parameters: %*ph\n", + NVT_TS_PARAMS_SIZE, data->buf); + return -EIO; + } + + dev_dbg(dev, "Detected %dx%d touchscreen with %d max touches\n", + width, height, data->max_touches); + + if (data->buf[NVT_TS_PARAMS_MAX_BUTTONS]) + dev_warn(dev, "Touchscreen buttons are not supported\n"); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->open = nvt_ts_start; + input->close = nvt_ts_stop; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, width - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, height - 1, 0, 0); + touchscreen_parse_properties(input, true, &data->prop); + + error = input_mt_init_slots(input, data->max_touches, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + data->input = input; + input_set_drvdata(input, data); + + error = devm_request_threaded_irq(dev, client->irq, NULL, nvt_ts_irq, + IRQF_ONESHOT | IRQF_NO_AUTOEN | + nvt_ts_irq_type[irq_type], + client->name, data); + if (error) { + dev_err(dev, "failed to request irq: %d\n", error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to request irq: %d\n", error); + return error; + } + + return 0; +} + +static const struct i2c_device_id nvt_ts_i2c_id[] = { + { "NVT-ts" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id); + +static struct i2c_driver nvt_ts_driver = { + .driver = { + .name = "novatek-nvt-ts", + .pm = pm_sleep_ptr(&nvt_ts_pm_ops), + }, + .probe_new = nvt_ts_probe, + .id_table = nvt_ts_i2c_id, +}; + +module_i2c_driver(nvt_ts_driver); + +MODULE_DESCRIPTION("Novatek NVT-ts touchscreen driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index 5000f5fd9ec3..45c575df994e 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -134,7 +134,7 @@ static int rpi_ts_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; @@ -160,7 +160,6 @@ static int rpi_ts_probe(struct platform_device *pdev) touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); - rpi_firmware_put(fw); if (error || touchbuf != 0) { dev_warn(dev, "Failed to set touchbuf, %d\n", error); return error; diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 1117fba30020..577c75c83e25 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -400,7 +400,7 @@ MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); static struct platform_driver sun4i_ts_driver = { .driver = { .name = "sun4i-ts", - .of_match_table = of_match_ptr(sun4i_ts_of_match), + .of_match_table = sun4i_ts_of_match, }, .probe = sun4i_ts_probe, .remove = sun4i_ts_remove, diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 3c793fb70a0e..21916a30fb76 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -172,19 +172,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) return IRQ_HANDLED; } -static irqreturn_t tsc2007_hard_irq(int irq, void *handle) -{ - struct tsc2007 *ts = handle; - - if (tsc2007_is_pen_down(ts)) - return IRQ_WAKE_THREAD; - - if (ts->clear_penirq) - ts->clear_penirq(); - - return IRQ_HANDLED; -} - static void tsc2007_stop(struct tsc2007 *ts) { ts->stopped = true; @@ -226,7 +213,7 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct tsc2007 *ts = i2c_get_clientdata(client); - return gpiod_get_value(ts->gpiod); + return gpiod_get_value_cansleep(ts->gpiod); } static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) @@ -376,7 +363,7 @@ static int tsc2007_probe(struct i2c_client *client) } err = devm_request_threaded_irq(&client->dev, ts->irq, - tsc2007_hard_irq, tsc2007_soft_irq, + NULL, tsc2007_soft_irq, IRQF_ONESHOT, client->dev.driver->name, ts); if (err) { diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index cdf9bcd744db..b6ece47151b8 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -260,7 +260,7 @@ static int zinitix_init_regulators(struct bt541_ts_data *bt541) * so check if "vddo" is present and in that case use these names. * Else use the proper supply names on the component. */ - if (of_find_property(dev->of_node, "vddo-supply", NULL)) { + if (of_property_present(dev->of_node, "vddo-supply")) { bt541->supplies[0].supply = "vdd"; bt541->supplies[1].supply = "vddo"; } else { diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 7a24c1444ace..ec46bcb16d5e 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -451,7 +450,7 @@ struct icc_path *of_icc_get_by_index(struct device *dev, int idx) * When the consumer DT node do not have "interconnects" property * return a NULL path to skip setting constraints. */ - if (!of_find_property(np, "interconnects", NULL)) + if (!of_property_present(np, "interconnects")) return NULL; /* @@ -544,7 +543,7 @@ struct icc_path *of_icc_get(struct device *dev, const char *name) * When the consumer DT node do not have "interconnects" property * return a NULL path to skip setting constraints. */ - if (!of_find_property(np, "interconnects", NULL)) + if (!of_property_present(np, "interconnects")) return NULL; /* @@ -910,52 +909,6 @@ out: } EXPORT_SYMBOL_GPL(icc_link_create); -/** - * icc_link_destroy() - destroy a link between two nodes - * @src: pointer to source node - * @dst: pointer to destination node - * - * Return: 0 on success, or an error code otherwise - */ -int icc_link_destroy(struct icc_node *src, struct icc_node *dst) -{ - struct icc_node **new; - size_t slot; - int ret = 0; - - if (IS_ERR_OR_NULL(src)) - return -EINVAL; - - if (IS_ERR_OR_NULL(dst)) - return -EINVAL; - - mutex_lock(&icc_lock); - - for (slot = 0; slot < src->num_links; slot++) - if (src->links[slot] == dst) - break; - - if (WARN_ON(slot == src->num_links)) { - ret = -ENXIO; - goto out; - } - - src->links[slot] = src->links[--src->num_links]; - - new = krealloc(src->links, src->num_links * sizeof(*src->links), - GFP_KERNEL); - if (new) - src->links = new; - else - ret = -ENOMEM; - -out: - mutex_unlock(&icc_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(icc_link_destroy); - /** * icc_node_add() - add interconnect node to interconnect provider * @node: pointer to the interconnect node @@ -981,14 +934,17 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider) node->avg_bw = node->init_avg; node->peak_bw = node->init_peak; - if (provider->pre_aggregate) - provider->pre_aggregate(node); + if (node->avg_bw || node->peak_bw) { + if (provider->pre_aggregate) + provider->pre_aggregate(node); - if (provider->aggregate) - provider->aggregate(node, 0, node->init_avg, node->init_peak, - &node->avg_bw, &node->peak_bw); + if (provider->aggregate) + provider->aggregate(node, 0, node->init_avg, node->init_peak, + &node->avg_bw, &node->peak_bw); + if (provider->set) + provider->set(node, node); + } - provider->set(node, node); node->avg_bw = 0; node->peak_bw = 0; @@ -1081,22 +1037,6 @@ void icc_provider_deregister(struct icc_provider *provider) } EXPORT_SYMBOL_GPL(icc_provider_deregister); -int icc_provider_add(struct icc_provider *provider) -{ - icc_provider_init(provider); - - return icc_provider_register(provider); -} -EXPORT_SYMBOL_GPL(icc_provider_add); - -void icc_provider_del(struct icc_provider *provider) -{ - WARN_ON(!list_empty(&provider->nodes)); - - icc_provider_deregister(provider); -} -EXPORT_SYMBOL_GPL(icc_provider_del); - static const struct of_device_id __maybe_unused ignore_list[] = { { .compatible = "qcom,sc7180-ipa-virt" }, { .compatible = "qcom,sc8180x-ipa-virt" }, @@ -1165,7 +1105,3 @@ static int __init icc_init(void) } device_initcall(icc_init); - -MODULE_AUTHOR("Georgi Djakov "); -MODULE_DESCRIPTION("Interconnect Driver Core"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 92d65c7bda23..825b647d9169 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -83,7 +83,7 @@ config INTERCONNECT_QCOM_RPMH_POSSIBLE default INTERCONNECT_QCOM depends on QCOM_RPMH || (COMPILE_TEST && !QCOM_RPMH) depends on QCOM_COMMAND_DB || (COMPILE_TEST && !QCOM_COMMAND_DB) - depends on OF || COMPILE_TEST + depends on OF help Compile-testing RPMH drivers is possible on other platforms, but in order to avoid link failures, drivers must not be built-in diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 4180a06681b2..5341fa169dbf 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -48,6 +47,9 @@ #define NOC_QOS_MODEn_ADDR(n) (0xc + (n * 0x1000)) #define NOC_QOS_MODEn_MASK 0x3 +#define NOC_QOS_MODE_FIXED_VAL 0x0 +#define NOC_QOS_MODE_BYPASS_VAL 0x2 + static int qcom_icc_set_qnoc_qos(struct icc_node *src, u64 max_bw) { struct icc_provider *provider = src->provider; @@ -153,7 +155,7 @@ static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) struct qcom_icc_provider *qp; struct qcom_icc_node *qn; struct icc_provider *provider; - u32 mode = NOC_QOS_MODE_BYPASS; + u32 mode = NOC_QOS_MODE_BYPASS_VAL; int rc = 0; qn = src->data; @@ -167,18 +169,17 @@ static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw) return 0; } - if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID) - mode = qn->qos.qos_mode; - - if (mode == NOC_QOS_MODE_FIXED) { - dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n", - qn->name); + if (qn->qos.qos_mode == NOC_QOS_MODE_FIXED) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n", qn->name); + mode = NOC_QOS_MODE_FIXED_VAL; rc = qcom_icc_noc_set_qos_priority(qp, &qn->qos); if (rc) return rc; - } else if (mode == NOC_QOS_MODE_BYPASS) { - dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n", - qn->name); + } else if (qn->qos.qos_mode == NOC_QOS_MODE_BYPASS) { + dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n", qn->name); + mode = NOC_QOS_MODE_BYPASS_VAL; + } else { + /* How did we get here? */ } return regmap_update_bits(qp->regmap, @@ -244,7 +245,7 @@ static int __qcom_icc_set(struct icc_node *n, struct qcom_icc_node *qn, ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw); if (ret) return ret; - } else if (qn->qos.qos_mode != -1) { + } else if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID) { /* set bandwidth directly from the AP */ ret = qcom_icc_qos_set(n, sum_bw); if (ret) @@ -315,6 +316,7 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider, { struct icc_node *node; struct qcom_icc_node *qn; + u64 sum_avg[QCOM_ICC_NUM_BUCKETS]; int i; /* Initialise aggregate values */ @@ -332,7 +334,11 @@ static void qcom_icc_bus_aggregate(struct icc_provider *provider, list_for_each_entry(node, &provider->nodes, node_list) { qn = node->data; for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { - agg_avg[i] += qn->sum_avg[i]; + if (qn->channels) + sum_avg[i] = div_u64(qn->sum_avg[i], qn->channels); + else + sum_avg[i] = qn->sum_avg[i]; + agg_avg[i] += sum_avg[i]; agg_peak[i] = max_t(u64, agg_peak[i], qn->max_peak[i]); } } @@ -496,12 +502,6 @@ regmap_done: if (ret) return ret; - if (desc->has_bus_pd) { - ret = dev_pm_domain_attach(dev, true); - if (ret) - return ret; - } - provider = &qp->provider; provider->dev = dev; provider->set = qcom_icc_set; diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h index a49af844ab13..22bdb1e4bb12 100644 --- a/drivers/interconnect/qcom/icc-rpm.h +++ b/drivers/interconnect/qcom/icc-rpm.h @@ -23,12 +23,12 @@ enum qcom_icc_type { /** * struct qcom_icc_provider - Qualcomm specific interconnect provider * @provider: generic interconnect provider - * @bus_clks: the clk_bulk_data table of bus clocks * @num_clks: the total number of clk_bulk_data entries * @type: the ICC provider type - * @qos_offset: offset to QoS registers * @regmap: regmap for QoS registers read/write access + * @qos_offset: offset to QoS registers * @bus_clk_rate: bus clock rate in Hz + * @bus_clks: the clk_bulk_data table of bus clocks */ struct qcom_icc_provider { struct icc_provider provider; @@ -66,6 +66,7 @@ struct qcom_icc_qos { * @id: a unique node identifier * @links: an array of nodes where we can go next while traversing * @num_links: the total number of @links + * @channels: number of channels at this node (e.g. DDR channels) * @buswidth: width of the interconnect between a node and the bus (bytes) * @sum_avg: current sum aggregate value of all avg bw requests * @max_peak: current max aggregate value of all peak bw requests @@ -78,6 +79,7 @@ struct qcom_icc_node { u16 id; const u16 *links; u16 num_links; + u16 channels; u16 buswidth; u64 sum_avg[QCOM_ICC_NUM_BUCKETS]; u64 max_peak[QCOM_ICC_NUM_BUCKETS]; @@ -91,16 +93,17 @@ struct qcom_icc_desc { size_t num_nodes; const char * const *clocks; size_t num_clocks; - bool has_bus_pd; enum qcom_icc_type type; const struct regmap_config *regmap_cfg; unsigned int qos_offset; }; -/* Valid for both NoC and BIMC */ -#define NOC_QOS_MODE_INVALID -1 -#define NOC_QOS_MODE_FIXED 0x0 -#define NOC_QOS_MODE_BYPASS 0x2 +/* Valid for all bus types */ +enum qos_mode { + NOC_QOS_MODE_INVALID = 0, + NOC_QOS_MODE_FIXED, + NOC_QOS_MODE_BYPASS, +}; int qnoc_probe(struct platform_device *pdev); int qnoc_remove(struct platform_device *pdev); diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index 25a1a32bc611..14efd2761b7a 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -1823,7 +1823,6 @@ static const struct qcom_icc_desc msm8996_a0noc = { .num_nodes = ARRAY_SIZE(a0noc_nodes), .clocks = bus_a0noc_clocks, .num_clocks = ARRAY_SIZE(bus_a0noc_clocks), - .has_bus_pd = true, .regmap_cfg = &msm8996_a0noc_regmap_config }; diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 1bafb54f1432..a1f4f918b911 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -14,13 +14,6 @@ #include -#include "sc7180.h" -#include "sc7280.h" -#include "sc8180x.h" -#include "sdm845.h" -#include "sm8150.h" -#include "sm8250.h" - #define LUT_MAX_ENTRIES 40U #define LUT_SRC GENMASK(31, 30) #define LUT_L_VAL GENMASK(7, 0) diff --git a/drivers/interconnect/qcom/sc7180.h b/drivers/interconnect/qcom/sc7180.h index 7a2b3eb00923..2b718922c109 100644 --- a/drivers/interconnect/qcom/sc7180.h +++ b/drivers/interconnect/qcom/sc7180.h @@ -145,7 +145,5 @@ #define SC7180_SLAVE_SERVICE_SNOC 134 #define SC7180_SLAVE_QDSS_STM 135 #define SC7180_SLAVE_TCU 136 -#define SC7180_MASTER_OSM_L3_APPS 137 -#define SC7180_SLAVE_OSM_L3 138 #endif diff --git a/drivers/interconnect/qcom/sc7280.h b/drivers/interconnect/qcom/sc7280.h index 1fb9839b2c14..175e400305c5 100644 --- a/drivers/interconnect/qcom/sc7280.h +++ b/drivers/interconnect/qcom/sc7280.h @@ -150,7 +150,5 @@ #define SC7280_SLAVE_PCIE_1 139 #define SC7280_SLAVE_QDSS_STM 140 #define SC7280_SLAVE_TCU 141 -#define SC7280_MASTER_EPSS_L3_APPS 142 -#define SC7280_SLAVE_EPSS_L3 143 #endif diff --git a/drivers/interconnect/qcom/sc8180x.h b/drivers/interconnect/qcom/sc8180x.h index c138dcd350f1..f8d90598335a 100644 --- a/drivers/interconnect/qcom/sc8180x.h +++ b/drivers/interconnect/qcom/sc8180x.h @@ -168,8 +168,6 @@ #define SC8180X_SLAVE_EBI_CH0_DISPLAY 158 #define SC8180X_SLAVE_MNOC_SF_MEM_NOC_DISPLAY 159 #define SC8180X_SLAVE_MNOC_HF_MEM_NOC_DISPLAY 160 -#define SC8180X_MASTER_OSM_L3_APPS 161 -#define SC8180X_SLAVE_OSM_L3 162 #define SC8180X_MASTER_QUP_CORE_0 163 #define SC8180X_MASTER_QUP_CORE_1 164 diff --git a/drivers/interconnect/qcom/sdm845.h b/drivers/interconnect/qcom/sdm845.h index 776e9c2acb27..bc7e425ce985 100644 --- a/drivers/interconnect/qcom/sdm845.h +++ b/drivers/interconnect/qcom/sdm845.h @@ -136,7 +136,5 @@ #define SDM845_SLAVE_SERVICE_SNOC 128 #define SDM845_SLAVE_QDSS_STM 129 #define SDM845_SLAVE_TCU 130 -#define SDM845_MASTER_OSM_L3_APPS 131 -#define SDM845_SLAVE_OSM_L3 132 #endif /* __DRIVERS_INTERCONNECT_QCOM_SDM845_H__ */ diff --git a/drivers/interconnect/qcom/sm8150.h b/drivers/interconnect/qcom/sm8150.h index 023161681fb8..1d587c94eb06 100644 --- a/drivers/interconnect/qcom/sm8150.h +++ b/drivers/interconnect/qcom/sm8150.h @@ -148,7 +148,5 @@ #define SM8150_SLAVE_VSENSE_CTRL_CFG 137 #define SM8150_SNOC_CNOC_MAS 138 #define SM8150_SNOC_CNOC_SLV 139 -#define SM8150_MASTER_OSM_L3_APPS 140 -#define SM8150_SLAVE_OSM_L3 141 #endif diff --git a/drivers/interconnect/qcom/sm8250.h b/drivers/interconnect/qcom/sm8250.h index e3fc56bc7ca0..209ab195f21f 100644 --- a/drivers/interconnect/qcom/sm8250.h +++ b/drivers/interconnect/qcom/sm8250.h @@ -158,7 +158,5 @@ #define SM8250_SLAVE_VSENSE_CTRL_CFG 147 #define SM8250_SNOC_CNOC_MAS 148 #define SM8250_SNOC_CNOC_SLV 149 -#define SM8250_MASTER_EPSS_L3_APPS 150 -#define SM8250_SLAVE_EPSS_L3 151 #endif diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 889c7efd050b..4d800601e8ec 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -3,10 +3,6 @@ config IOMMU_IOVA tristate -# The IOASID library may also be used by non-IOMMU_API users -config IOASID - tristate - # IOMMU_API always gets selected by whoever wants it. config IOMMU_API bool @@ -33,7 +29,7 @@ config IOMMU_IO_PGTABLE_LPAE bool "ARMv7/v8 Long Descriptor Format" select IOMMU_IO_PGTABLE depends on ARM || ARM64 || COMPILE_TEST - depends on !GENERIC_ATOMIC64 # for cpmxchg64() + depends on !GENERIC_ATOMIC64 # for cmpxchg64() help Enable support for the ARM long descriptor pagetable format. This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page @@ -72,7 +68,7 @@ config IOMMU_IO_PGTABLE_DART bool "Apple DART Formats" select IOMMU_IO_PGTABLE depends on ARM64 || COMPILE_TEST - depends on !GENERIC_ATOMIC64 # for cpmxchg64() + depends on !GENERIC_ATOMIC64 # for cmpxchg64() help Enable support for the Apple DART pagetable formats. These include the t8020 and t6000/t8110 DART formats used in Apple M1/M2 family @@ -160,7 +156,6 @@ config IOMMU_DMA # Shared Virtual Addressing config IOMMU_SVA bool - select IOASID config FSL_PAMU bool "Freescale IOMMU support" @@ -287,6 +282,7 @@ config EXYNOS_IOMMU_DEBUG config IPMMU_VMSA bool "Renesas VMSA-compatible IPMMU" depends on ARCH_RENESAS || COMPILE_TEST + depends on ARM || ARM64 || COMPILE_TEST depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE select IOMMU_API select IOMMU_IO_PGTABLE_LPAE @@ -422,22 +418,6 @@ config S390_IOMMU help Support for the IOMMU API for s390 PCI devices. -config S390_CCW_IOMMU - bool "S390 CCW IOMMU Support" - depends on S390 && CCW || COMPILE_TEST - select IOMMU_API - help - Enables bits of IOMMU API required by VFIO. The iommu_ops - is not implemented as it is not necessary for VFIO. - -config S390_AP_IOMMU - bool "S390 AP IOMMU Support" - depends on S390 && ZCRYPT || COMPILE_TEST - select IOMMU_API - help - Enables bits of IOMMU API required by VFIO. The iommu_ops - is not implemented as it is not necessary for VFIO. - config MTK_IOMMU tristate "MediaTek IOMMU Support" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index f461d0651385..769e43d780ce 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o obj-$(CONFIG_IOMMU_IO_PGTABLE_DART) += io-pgtable-dart.o -obj-$(CONFIG_IOASID) += ioasid.o obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index c160a332ce33..9beeceb9d825 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -15,9 +15,7 @@ extern irqreturn_t amd_iommu_int_thread(int irq, void *data); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid); extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu); -extern int amd_iommu_init_devices(void); -extern void amd_iommu_uninit_devices(void); -extern void amd_iommu_init_notifier(void); +extern void amd_iommu_restart_ga_log(struct amd_iommu *iommu); extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid); #ifdef CONFIG_AMD_IOMMU_DEBUGFS @@ -34,6 +32,7 @@ extern int amd_iommu_reenable(int); extern int amd_iommu_enable_faulting(void); extern int amd_iommu_guest_ir; extern enum io_pgtable_fmt amd_iommu_pgtable; +extern int amd_iommu_gpt_level; /* IOMMUv2 specific functions */ struct iommu_domain; @@ -122,6 +121,14 @@ static inline int get_pci_sbdf_id(struct pci_dev *pdev) return PCI_SEG_DEVID_TO_SBDF(seg, devid); } +static inline void *alloc_pgtable_page(int nid, gfp_t gfp) +{ + struct page *page; + + page = alloc_pages_node(nid, gfp | __GFP_ZERO, 0); + return page ? page_address(page) : NULL; +} + extern bool translation_pre_enabled(struct amd_iommu *iommu); extern bool amd_iommu_is_attach_deferred(struct device *dev); extern int __init add_special_device(u8 type, u8 id, u32 *devid, diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 3d684190b4d5..2ddbda3a4374 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -93,6 +93,8 @@ #define FEATURE_GA (1ULL<<7) #define FEATURE_HE (1ULL<<8) #define FEATURE_PC (1ULL<<9) +#define FEATURE_GATS_SHIFT (12) +#define FEATURE_GATS_MASK (3ULL) #define FEATURE_GAM_VAPIC (1ULL<<21) #define FEATURE_GIOSUP (1ULL<<48) #define FEATURE_EPHSUP (1ULL<<50) @@ -305,6 +307,9 @@ #define PAGE_MODE_6_LEVEL 0x06 #define PAGE_MODE_7_LEVEL 0x07 +#define GUEST_PGTABLE_4_LEVEL 0x00 +#define GUEST_PGTABLE_5_LEVEL 0x01 + #define PM_LEVEL_SHIFT(x) (12 + ((x) * 9)) #define PM_LEVEL_SIZE(x) (((x) < 6) ? \ ((1ULL << PM_LEVEL_SHIFT((x))) - 1): \ @@ -398,6 +403,8 @@ #define DTE_GCR3_SHIFT_B 16 #define DTE_GCR3_SHIFT_C 43 +#define DTE_GPT_LEVEL_SHIFT 54 + #define GCR3_VALID 0x01ULL #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL) @@ -549,6 +556,7 @@ struct protection_domain { spinlock_t lock; /* mostly used to lock the page table*/ u16 id; /* the domain id written to the device table */ int glx; /* Number of levels for GCR3 table */ + int nid; /* Node ID */ u64 *gcr3_tbl; /* Guest CR3 table */ unsigned long flags; /* flags to find out type of domain */ unsigned dev_cnt; /* devices assigned to this domain */ @@ -1001,8 +1009,8 @@ struct amd_ir_data { */ struct irq_cfg *cfg; int ga_vector; - int ga_root_ptr; - int ga_tag; + u64 ga_root_ptr; + u32 ga_tag; }; struct amd_irte_ops { diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 19a46b9f7357..c2d80a4e5fb0 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -153,6 +153,8 @@ bool amd_iommu_dump; bool amd_iommu_irq_remap __read_mostly; enum io_pgtable_fmt amd_iommu_pgtable = AMD_IOMMU_V1; +/* Guest page table level */ +int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL; int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC; static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; @@ -306,6 +308,11 @@ static bool check_feature_on_all_iommus(u64 mask) return !!(amd_iommu_efr & mask); } +static inline int check_feature_gpt_level(void) +{ + return ((amd_iommu_efr >> FEATURE_GATS_SHIFT) & FEATURE_GATS_MASK); +} + /* * For IVHD type 0x11/0x40, EFR is also available via IVHD. * Default to IVHD EFR since it is available sooner @@ -751,6 +758,30 @@ void amd_iommu_restart_event_logging(struct amd_iommu *iommu) iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN); } +/* + * This function restarts event logging in case the IOMMU experienced + * an GA log overflow. + */ +void amd_iommu_restart_ga_log(struct amd_iommu *iommu) +{ + u32 status; + + status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); + if (status & MMIO_STATUS_GALOG_RUN_MASK) + return; + + pr_info_ratelimited("IOMMU GA Log restarting\n"); + + iommu_feature_disable(iommu, CONTROL_GALOG_EN); + iommu_feature_disable(iommu, CONTROL_GAINT_EN); + + writel(MMIO_STATUS_GALOG_OVERFLOW_MASK, + iommu->mmio_base + MMIO_STATUS_OFFSET); + + iommu_feature_enable(iommu, CONTROL_GAINT_EN); + iommu_feature_enable(iommu, CONTROL_GALOG_EN); +} + /* * This function resets the command buffer if the IOMMU stopped fetching * commands from it. @@ -1941,7 +1972,7 @@ static ssize_t amd_iommu_show_cap(struct device *dev, char *buf) { struct amd_iommu *iommu = dev_to_amd_iommu(dev); - return sprintf(buf, "%x\n", iommu->cap); + return sysfs_emit(buf, "%x\n", iommu->cap); } static DEVICE_ATTR(cap, S_IRUGO, amd_iommu_show_cap, NULL); @@ -1950,7 +1981,7 @@ static ssize_t amd_iommu_show_features(struct device *dev, char *buf) { struct amd_iommu *iommu = dev_to_amd_iommu(dev); - return sprintf(buf, "%llx:%llx\n", iommu->features2, iommu->features); + return sysfs_emit(buf, "%llx:%llx\n", iommu->features2, iommu->features); } static DEVICE_ATTR(features, S_IRUGO, amd_iommu_show_features, NULL); @@ -2155,8 +2186,10 @@ static void print_iommu_info(void) if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) pr_info("X2APIC enabled\n"); } - if (amd_iommu_pgtable == AMD_IOMMU_V2) - pr_info("V2 page table enabled\n"); + if (amd_iommu_pgtable == AMD_IOMMU_V2) { + pr_info("V2 page table enabled (Paging mode : %d level)\n", + amd_iommu_gpt_level); + } } static int __init amd_iommu_init_pci(void) @@ -2383,6 +2416,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu) struct irq_domain *domain; struct irq_alloc_info info; int irq, ret; + int node = dev_to_node(&iommu->dev->dev); domain = iommu_get_irqdomain(); if (!domain) @@ -2392,7 +2426,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu) info.type = X86_IRQ_ALLOC_TYPE_AMDVI; info.data = iommu; - irq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info); + irq = irq_domain_alloc_irqs(domain, 1, node, &info); if (irq < 0) { irq_domain_remove(domain); return irq; @@ -3025,6 +3059,11 @@ static int __init early_amd_iommu_init(void) if (ret) goto out; + /* 5 level guest page table */ + if (cpu_feature_enabled(X86_FEATURE_LA57) && + check_feature_gpt_level() == GUEST_PGTABLE_5_LEVEL) + amd_iommu_gpt_level = PAGE_MODE_5_LEVEL; + /* Disable any previously enabled IOMMUs */ if (!is_kdump_kernel() || amd_iommu_disabled) disable_iommus(); @@ -3556,6 +3595,11 @@ __setup("ivrs_acpihid", parse_ivrs_acpihid); bool amd_iommu_v2_supported(void) { + /* CPU page table size should match IOMMU guest page table size */ + if (cpu_feature_enabled(X86_FEATURE_LA57) && + amd_iommu_gpt_level != PAGE_MODE_5_LEVEL) + return false; + /* * Since DTE[Mode]=0 is prohibited on SNP-enabled system * (i.e. EFR[SNPSup]=1), IOMMUv2 page table cannot be used without diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c index ace0e9b8b913..1b67116882be 100644 --- a/drivers/iommu/amd/io_pgtable.c +++ b/drivers/iommu/amd/io_pgtable.c @@ -156,7 +156,7 @@ static bool increase_address_space(struct protection_domain *domain, bool ret = true; u64 *pte; - pte = (void *)get_zeroed_page(gfp); + pte = alloc_pgtable_page(domain->nid, gfp); if (!pte) return false; @@ -250,7 +250,7 @@ static u64 *alloc_pte(struct protection_domain *domain, if (!IOMMU_PTE_PRESENT(__pte) || pte_level == PAGE_MODE_NONE) { - page = (u64 *)get_zeroed_page(gfp); + page = alloc_pgtable_page(domain->nid, gfp); if (!page) return NULL; diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c index 8638ddf6fb3b..27c3015947e6 100644 --- a/drivers/iommu/amd/io_pgtable_v2.c +++ b/drivers/iommu/amd/io_pgtable_v2.c @@ -37,8 +37,7 @@ static inline int get_pgtable_level(void) { - /* 5 level page table is not supported */ - return PAGE_MODE_4_LEVEL; + return amd_iommu_gpt_level; } static inline bool is_large_pte(u64 pte) @@ -46,11 +45,6 @@ static inline bool is_large_pte(u64 pte) return (pte & IOMMU_PAGE_PSE); } -static inline void *alloc_pgtable_page(void) -{ - return (void *)get_zeroed_page(GFP_KERNEL); -} - static inline u64 set_pgtable_attr(u64 *page) { u64 prot; @@ -138,8 +132,8 @@ static void free_pgtable(u64 *pt, int level) } /* Allocate page table */ -static u64 *v2_alloc_pte(u64 *pgd, unsigned long iova, - unsigned long pg_size, bool *updated) +static u64 *v2_alloc_pte(int nid, u64 *pgd, unsigned long iova, + unsigned long pg_size, gfp_t gfp, bool *updated) { u64 *pte, *page; int level, end_level; @@ -162,7 +156,7 @@ static u64 *v2_alloc_pte(u64 *pgd, unsigned long iova, } if (!IOMMU_PTE_PRESENT(__pte)) { - page = alloc_pgtable_page(); + page = alloc_pgtable_page(nid, gfp); if (!page) return NULL; @@ -262,7 +256,8 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova, while (mapped_size < size) { map_size = get_alloc_page_size(pgsize); - pte = v2_alloc_pte(pdom->iop.pgd, iova, map_size, &updated); + pte = v2_alloc_pte(pdom->nid, pdom->iop.pgd, + iova, map_size, gfp, &updated); if (!pte) { ret = -EINVAL; goto out; @@ -383,8 +378,9 @@ static struct io_pgtable *v2_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo struct amd_io_pgtable *pgtable = io_pgtable_cfg_to_data(cfg); struct protection_domain *pdom = (struct protection_domain *)cookie; int ret; + int ias = IOMMU_IN_ADDR_BIT_SIZE; - pgtable->pgd = alloc_pgtable_page(); + pgtable->pgd = alloc_pgtable_page(pdom->nid, GFP_ATOMIC); if (!pgtable->pgd) return NULL; @@ -392,12 +388,15 @@ static struct io_pgtable *v2_alloc_pgtable(struct io_pgtable_cfg *cfg, void *coo if (ret) goto err_free_pgd; + if (get_pgtable_level() == PAGE_MODE_5_LEVEL) + ias = 57; + pgtable->iop.ops.map_pages = iommu_v2_map_pages; pgtable->iop.ops.unmap_pages = iommu_v2_unmap_pages; pgtable->iop.ops.iova_to_phys = iommu_v2_iova_to_phys; cfg->pgsize_bitmap = AMD_IOMMU_PGSIZES_V2, - cfg->ias = IOMMU_IN_ADDR_BIT_SIZE, + cfg->ias = ias, cfg->oas = IOMMU_OUT_ADDR_BIT_SIZE, cfg->tlb = &v2_flush_ops; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 5a505ba5467e..dc1ec6849775 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -845,6 +845,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { } (MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \ MMIO_STATUS_EVT_INT_MASK | \ MMIO_STATUS_PPR_INT_MASK | \ + MMIO_STATUS_GALOG_OVERFLOW_MASK | \ MMIO_STATUS_GALOG_INT_MASK) irqreturn_t amd_iommu_int_thread(int irq, void *data) @@ -868,10 +869,16 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) } #ifdef CONFIG_IRQ_REMAP - if (status & MMIO_STATUS_GALOG_INT_MASK) { + if (status & (MMIO_STATUS_GALOG_INT_MASK | + MMIO_STATUS_GALOG_OVERFLOW_MASK)) { pr_devel("Processing IOMMU GA Log\n"); iommu_poll_ga_log(iommu); } + + if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) { + pr_info_ratelimited("IOMMU GA Log overflow\n"); + amd_iommu_restart_ga_log(iommu); + } #endif if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) { @@ -1611,6 +1618,11 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 devid, tmp = DTE_GCR3_VAL_C(gcr3) << DTE_GCR3_SHIFT_C; flags |= tmp; + if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL) { + dev_table[devid].data[2] |= + ((u64)GUEST_PGTABLE_5_LEVEL << DTE_GPT_LEVEL_SHIFT); + } + if (domain->flags & PD_GIOV_MASK) pte_root |= DTE_FLAG_GIOV; } @@ -1662,14 +1674,14 @@ static void do_attach(struct iommu_dev_data *dev_data, dev_data->domain = domain; list_add(&dev_data->list, &domain->dev_list); + /* Update NUMA Node ID */ + if (domain->nid == NUMA_NO_NODE) + domain->nid = dev_to_node(dev_data->dev); + /* Do reference counting */ domain->dev_iommu[iommu->index] += 1; domain->dev_cnt += 1; - /* Override supported page sizes */ - if (domain->flags & PD_GIOV_MASK) - domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2; - /* Update device table */ set_dte_entry(iommu, dev_data->devid, domain, ats, dev_data->iommu_v2); @@ -2048,6 +2060,8 @@ static int protection_domain_init_v2(struct protection_domain *domain) domain->flags |= PD_GIOV_MASK; + domain->domain.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2; + if (domain_enable_v2(domain, 1)) { domain_id_free(domain->id); return -ENOMEM; @@ -2060,7 +2074,7 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) { struct io_pgtable_ops *pgtbl_ops; struct protection_domain *domain; - int pgtable = amd_iommu_pgtable; + int pgtable; int mode = DEFAULT_PGTABLE_LEVEL; int ret; @@ -2077,6 +2091,10 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) mode = PAGE_MODE_NONE; } else if (type == IOMMU_DOMAIN_UNMANAGED) { pgtable = AMD_IOMMU_V1; + } else if (type == IOMMU_DOMAIN_DMA || type == IOMMU_DOMAIN_DMA_FQ) { + pgtable = amd_iommu_pgtable; + } else { + return NULL; } switch (pgtable) { @@ -2097,6 +2115,8 @@ static struct protection_domain *protection_domain_alloc(unsigned int type) if (type == IOMMU_DOMAIN_IDENTITY) return domain; + domain->nid = NUMA_NO_NODE; + pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl_cfg, domain); if (!pgtbl_ops) { domain_id_free(domain->id); @@ -2109,6 +2129,15 @@ out_err: return NULL; } +static inline u64 dma_max_address(void) +{ + if (amd_iommu_pgtable == AMD_IOMMU_V1) + return ~0ULL; + + /* V2 with 4/5 level page table */ + return ((1ULL << PM_LEVEL_SHIFT(amd_iommu_gpt_level)) - 1); +} + static struct iommu_domain *amd_iommu_domain_alloc(unsigned type) { struct protection_domain *domain; @@ -2125,7 +2154,7 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type) return NULL; domain->domain.geometry.aperture_start = 0; - domain->domain.geometry.aperture_end = ~0ULL; + domain->domain.geometry.aperture_end = dma_max_address(); domain->domain.geometry.force_aperture = true; return &domain->domain; @@ -2378,7 +2407,7 @@ static void amd_iommu_iotlb_sync(struct iommu_domain *domain, unsigned long flags; spin_lock_irqsave(&dom->lock, flags); - domain_flush_pages(dom, gather->start, gather->end - gather->start, 1); + domain_flush_pages(dom, gather->start, gather->end - gather->start + 1, 1); amd_iommu_domain_flush_complete(dom); spin_unlock_irqrestore(&dom->lock, flags); } @@ -3484,8 +3513,7 @@ int amd_iommu_activate_guest_mode(void *data) struct irte_ga *entry = (struct irte_ga *) ir_data->entry; u64 valid; - if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || - !entry || entry->lo.fields_vapic.guest_mode) + if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || !entry) return 0; valid = entry->lo.fields_vapic.valid; diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 06169d36eab8..8af64b57f048 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1150,7 +1150,7 @@ err_clk_disable: return ret; } -static int apple_dart_remove(struct platform_device *pdev) +static void apple_dart_remove(struct platform_device *pdev) { struct apple_dart *dart = platform_get_drvdata(pdev); @@ -1161,8 +1161,6 @@ static int apple_dart_remove(struct platform_device *pdev) iommu_device_sysfs_remove(&dart->iommu); clk_bulk_disable_unprepare(dart->num_clks, dart->clks); - - return 0; } static const struct apple_dart_hw apple_dart_hw_t8103 = { @@ -1296,7 +1294,7 @@ static struct platform_driver apple_dart_driver = { .pm = pm_sleep_ptr(&apple_dart_pm_ops), }, .probe = apple_dart_probe, - .remove = apple_dart_remove, + .remove_new = apple_dart_remove, }; module_platform_driver(apple_dart_driver); diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index f2425b0f0cd6..3fd83fb75722 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -152,6 +152,18 @@ static void queue_inc_cons(struct arm_smmu_ll_queue *q) q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons); } +static void queue_sync_cons_ovf(struct arm_smmu_queue *q) +{ + struct arm_smmu_ll_queue *llq = &q->llq; + + if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons))) + return; + + llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) | + Q_IDX(llq, llq->cons); + queue_sync_cons_out(q); +} + static int queue_sync_prod_in(struct arm_smmu_queue *q) { u32 prod; @@ -1577,8 +1589,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) } while (!queue_empty(llq)); /* Sync our overflow flag, as we believe we're up to speed */ - llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) | - Q_IDX(llq, llq->cons); + queue_sync_cons_ovf(q); return IRQ_HANDLED; } @@ -1636,9 +1647,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) } while (!queue_empty(llq)); /* Sync our overflow flag, as we believe we're up to speed */ - llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) | - Q_IDX(llq, llq->cons); - queue_sync_cons_out(q); + queue_sync_cons_ovf(q); return IRQ_HANDLED; } @@ -2447,6 +2456,13 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) master->domain = smmu_domain; + /* + * The SMMU does not support enabling ATS with bypass. When the STE is + * in bypass (STE.Config[2:0] == 0b100), ATS Translation Requests and + * Translated transactions are denied as though ATS is disabled for the + * stream (STE.EATS == 0b00), causing F_BAD_ATS_TREQ and + * F_TRANSL_FORBIDDEN events (IHI0070Ea 5.2 Stream Table Entry). + */ if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS) master->ats_enabled = arm_smmu_ats_supported(master); @@ -3844,7 +3860,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) return 0; } -static int arm_smmu_device_remove(struct platform_device *pdev) +static void arm_smmu_device_remove(struct platform_device *pdev) { struct arm_smmu_device *smmu = platform_get_drvdata(pdev); @@ -3852,8 +3868,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev) iommu_device_sysfs_remove(&smmu->iommu); arm_smmu_device_disable(smmu); iopf_queue_free(smmu->evtq.iopf); - - return 0; } static void arm_smmu_device_shutdown(struct platform_device *pdev) @@ -3882,7 +3896,7 @@ static struct platform_driver arm_smmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_smmu_device_probe, - .remove = arm_smmu_device_remove, + .remove_new = arm_smmu_device_remove, .shutdown = arm_smmu_device_shutdown, }; module_driver(arm_smmu_driver, platform_driver_register, diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 8d772ea8a583..b574c58a3487 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -182,7 +182,7 @@ #ifdef CONFIG_CMA_ALIGNMENT #define Q_MAX_SZ_SHIFT (PAGE_SHIFT + CONFIG_CMA_ALIGNMENT) #else -#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER - 1) +#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER) #endif /* diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index d1b296b95c86..c71afda79d64 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -268,12 +268,26 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) { - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); + unsigned int last_s2cr; u32 reg; u32 smr; int i; + /* + * Some platforms support more than the Arm SMMU architected maximum of + * 128 stream matching groups. For unknown reasons, the additional + * groups don't exhibit the same behavior as the architected registers, + * so limit the groups to 128 until the behavior is fixed for the other + * groups. + */ + if (smmu->num_mapping_groups > 128) { + dev_notice(smmu->dev, "\tLimiting the stream matching groups to 128\n"); + smmu->num_mapping_groups = 128; + } + + last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); + /* * With some firmware versions writes to S2CR of type FAULT are * ignored, and writing BYPASS will end up written as FAULT in the @@ -503,6 +517,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { { .compatible = "qcom,qcm2290-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,qdu1000-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sc7180-smmu-500", .data = &qcom_smmu_500_impl0_data }, + { .compatible = "qcom,sc7180-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sc7280-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sc8180x-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sc8280xp-smmu-500", .data = &qcom_smmu_500_impl0_data }, @@ -547,5 +562,14 @@ struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) if (match) return qcom_smmu_create(smmu, match->data); + /* + * If you hit this WARN_ON() you are missing an entry in the + * qcom_smmu_impl_of_match[] table, and GPU per-process page- + * tables will be broken. + */ + WARN(of_device_is_compatible(np, "qcom,adreno-smmu"), + "Missing qcom_smmu_impl_of_match entry for: %s", + dev_name(smmu->dev)); + return smmu; } diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 2ff7a72cf377..6e0813b26fb6 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -139,7 +139,7 @@ static int arm_smmu_register_legacy_master(struct device *dev, int err; np = dev_get_dev_node(dev); - if (!np || !of_find_property(np, "#stream-id-cells", NULL)) { + if (!np || !of_property_present(np, "#stream-id-cells")) { of_node_put(np); return -ENODEV; } @@ -2195,9 +2195,6 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev) { struct arm_smmu_device *smmu = platform_get_drvdata(pdev); - if (!smmu) - return; - if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS)) dev_notice(&pdev->dev, "disabling translation\n"); @@ -2214,19 +2211,14 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev) clk_bulk_unprepare(smmu->num_clks, smmu->clks); } -static int arm_smmu_device_remove(struct platform_device *pdev) +static void arm_smmu_device_remove(struct platform_device *pdev) { struct arm_smmu_device *smmu = platform_get_drvdata(pdev); - if (!smmu) - return -ENODEV; - iommu_device_unregister(&smmu->iommu); iommu_device_sysfs_remove(&smmu->iommu); arm_smmu_device_shutdown(pdev); - - return 0; } static int __maybe_unused arm_smmu_runtime_resume(struct device *dev) @@ -2302,7 +2294,7 @@ static struct platform_driver arm_smmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_smmu_device_probe, - .remove = arm_smmu_device_remove, + .remove_new = arm_smmu_device_remove, .shutdown = arm_smmu_device_shutdown, }; module_platform_driver(arm_smmu_driver); diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index c8b70f476cd8..a503ed758ec3 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -682,7 +682,7 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) return 0; } -static int qcom_iommu_ctx_remove(struct platform_device *pdev) +static void qcom_iommu_ctx_remove(struct platform_device *pdev) { struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(pdev->dev.parent); struct qcom_iommu_ctx *ctx = platform_get_drvdata(pdev); @@ -690,8 +690,6 @@ static int qcom_iommu_ctx_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); qcom_iommu->ctxs[ctx->asid - 1] = NULL; - - return 0; } static const struct of_device_id ctx_of_match[] = { @@ -706,7 +704,7 @@ static struct platform_driver qcom_iommu_ctx_driver = { .of_match_table = ctx_of_match, }, .probe = qcom_iommu_ctx_probe, - .remove = qcom_iommu_ctx_remove, + .remove_new = qcom_iommu_ctx_remove, }; static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu) @@ -824,7 +822,7 @@ err_pm_disable: return ret; } -static int qcom_iommu_device_remove(struct platform_device *pdev) +static void qcom_iommu_device_remove(struct platform_device *pdev) { struct qcom_iommu_dev *qcom_iommu = platform_get_drvdata(pdev); @@ -832,8 +830,6 @@ static int qcom_iommu_device_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); iommu_device_sysfs_remove(&qcom_iommu->iommu); iommu_device_unregister(&qcom_iommu->iommu); - - return 0; } static int __maybe_unused qcom_iommu_resume(struct device *dev) @@ -870,7 +866,7 @@ static struct platform_driver qcom_iommu_driver = { .pm = &qcom_iommu_pm_ops, }, .probe = qcom_iommu_device_probe, - .remove = qcom_iommu_device_remove, + .remove_new = qcom_iommu_device_remove, }; static int __init qcom_iommu_init(void) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 99b2646cb5c7..7a9f0b0bddbd 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -736,7 +736,7 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev, struct page **pages; unsigned int i = 0, nid = dev_to_node(dev); - order_mask &= (2U << MAX_ORDER) - 1; + order_mask &= GENMASK(MAX_ORDER, 0); if (!order_mask) return NULL; @@ -756,7 +756,7 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev, * than a necessity, hence using __GFP_NORETRY until * falling back to minimum-order allocations. */ - for (order_mask &= (2U << __fls(count)) - 1; + for (order_mask &= GENMASK(__fls(count), 0); order_mask; order_mask &= ~order_size) { unsigned int order = __fls(order_mask); gfp_t alloc_flags = gfp; diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 1abd187c6075..c275fe71c4db 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -747,22 +747,16 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) return ret; } - data->clk = devm_clk_get(dev, "sysmmu"); - if (PTR_ERR(data->clk) == -ENOENT) - data->clk = NULL; - else if (IS_ERR(data->clk)) + data->clk = devm_clk_get_optional(dev, "sysmmu"); + if (IS_ERR(data->clk)) return PTR_ERR(data->clk); - data->aclk = devm_clk_get(dev, "aclk"); - if (PTR_ERR(data->aclk) == -ENOENT) - data->aclk = NULL; - else if (IS_ERR(data->aclk)) + data->aclk = devm_clk_get_optional(dev, "aclk"); + if (IS_ERR(data->aclk)) return PTR_ERR(data->aclk); - data->pclk = devm_clk_get(dev, "pclk"); - if (PTR_ERR(data->pclk) == -ENOENT) - data->pclk = NULL; - else if (IS_ERR(data->pclk)) + data->pclk = devm_clk_get_optional(dev, "pclk"); + if (IS_ERR(data->pclk)) return PTR_ERR(data->pclk); if (!data->clk && (!data->aclk || !data->pclk)) { @@ -770,10 +764,8 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) return -ENOSYS; } - data->clk_master = devm_clk_get(dev, "master"); - if (PTR_ERR(data->clk_master) == -ENOENT) - data->clk_master = NULL; - else if (IS_ERR(data->clk_master)) + data->clk_master = devm_clk_get_optional(dev, "master"); + if (IS_ERR(data->clk_master)) return PTR_ERR(data->clk_master); data->sysmmu = dev; diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c index 05d820fb1d0b..f37d3b044131 100644 --- a/drivers/iommu/fsl_pamu.c +++ b/drivers/iommu/fsl_pamu.c @@ -178,7 +178,7 @@ int pamu_update_paace_stash(int liodn, u32 value) } /** - * pamu_config_paace() - Sets up PPAACE entry for specified liodn + * pamu_config_ppaace() - Sets up PPAACE entry for specified liodn * * @liodn: Logical IO device number * @omi: Operation mapping index -- if ~omi == 0 then omi not defined @@ -232,7 +232,8 @@ int pamu_config_ppaace(int liodn, u32 omi, u32 stashid, int prot) /** * get_ome_index() - Returns the index in the operation mapping table * for device. - * @*omi_index: pointer for storing the index value + * @omi_index: pointer for storing the index value + * @dev: target device * */ void get_ome_index(u32 *omi_index, struct device *dev) @@ -328,7 +329,7 @@ found_cpu_node: #define QMAN_PORTAL_PAACE 2 #define BMAN_PAACE 3 -/** +/* * Setup operation mapping and stash destinations for QMAN and QMAN portal. * Memory accesses to QMAN and BMAN private memory need not be coherent, so * clear the PAACE entry coherency attribute for them. @@ -357,7 +358,7 @@ static void setup_qbman_paace(struct paace *ppaace, int paace_type) } } -/** +/* * Setup the operation mapping table for various devices. This is a static * table where each table index corresponds to a particular device. PAMU uses * this table to translate device transaction to appropriate corenet diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig index 12e1e90fdae1..2e56bd79f589 100644 --- a/drivers/iommu/intel/Kconfig +++ b/drivers/iommu/intel/Kconfig @@ -18,7 +18,6 @@ config INTEL_IOMMU select NEED_DMA_MAP_STATE select DMAR_TABLE select SWIOTLB - select IOASID select PCI_ATS select PCI_PRI select PCI_PASID diff --git a/drivers/iommu/intel/cap_audit.c b/drivers/iommu/intel/cap_audit.c index 806986696841..9862dc20b35e 100644 --- a/drivers/iommu/intel/cap_audit.c +++ b/drivers/iommu/intel/cap_audit.c @@ -54,7 +54,6 @@ static inline void check_dmar_capabilities(struct intel_iommu *a, CHECK_FEATURE_MISMATCH(a, b, ecap, slts, ECAP_SLTS_MASK); CHECK_FEATURE_MISMATCH(a, b, ecap, nwfs, ECAP_NWFS_MASK); CHECK_FEATURE_MISMATCH(a, b, ecap, slads, ECAP_SLADS_MASK); - CHECK_FEATURE_MISMATCH(a, b, ecap, vcs, ECAP_VCS_MASK); CHECK_FEATURE_MISMATCH(a, b, ecap, smts, ECAP_SMTS_MASK); CHECK_FEATURE_MISMATCH(a, b, ecap, pds, ECAP_PDS_MASK); CHECK_FEATURE_MISMATCH(a, b, ecap, dit, ECAP_DIT_MASK); @@ -101,7 +100,6 @@ static int cap_audit_hotplug(struct intel_iommu *iommu, enum cap_audit_type type CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slts, ECAP_SLTS_MASK); CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, nwfs, ECAP_NWFS_MASK); CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, slads, ECAP_SLADS_MASK); - CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, vcs, ECAP_VCS_MASK); CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, smts, ECAP_SMTS_MASK); CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, pds, ECAP_PDS_MASK); CHECK_FEATURE_MISMATCH_HOTPLUG(iommu, ecap, dit, ECAP_DIT_MASK); diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index 23828d189c2a..a3414afe11b0 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -127,8 +127,6 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) struct pci_dev *tmp; struct dmar_pci_notify_info *info; - BUG_ON(dev->is_virtfn); - /* * Ignore devices that have a domain number higher than what can * be looked up in DMAR, e.g. VMD subdevices with domain 0x10000 @@ -264,7 +262,8 @@ int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, get_device(dev)); return 1; } - BUG_ON(i >= devices_cnt); + if (WARN_ON(i >= devices_cnt)) + return -EINVAL; } return 0; @@ -993,8 +992,6 @@ static int map_iommu(struct intel_iommu *iommu, struct dmar_drhd_unit *drhd) warn_invalid_dmar(phys_addr, " returns all ones"); goto unmap; } - if (ecap_vcs(iommu->ecap)) - iommu->vccap = dmar_readq(iommu->reg + DMAR_VCCAP_REG); /* the registers might be more than one page */ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), @@ -1690,7 +1687,7 @@ static void __dmar_enable_qi(struct intel_iommu *iommu) * is present. */ if (ecap_smts(iommu->ecap)) - val |= (1 << 11) | 1; + val |= BIT_ULL(11) | BIT_ULL(0); raw_spin_lock_irqsave(&iommu->register_lock, flags); @@ -1961,7 +1958,7 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type, return 0; } - if (pasid == INVALID_IOASID) + if (pasid == IOMMU_PASID_INVALID) pr_err("[%s NO_PASID] Request device [%02x:%02x.%d] fault addr 0x%llx [fault reason 0x%02x] %s\n", type ? "DMA Read" : "DMA Write", source_id >> 8, PCI_SLOT(source_id & 0xFF), @@ -2042,7 +2039,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id) if (!ratelimited) /* Using pasid -1 if pasid is not present */ dmar_fault_do_one(iommu, type, fault_reason, - pasid_present ? pasid : INVALID_IOASID, + pasid_present ? pasid : IOMMU_PASID_INVALID, source_id, guest_addr); fault_index++; diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 7c2f4bd33582..b871a6afd803 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -876,7 +876,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, return; } /* For request-without-pasid, get the pasid from context entry */ - if (intel_iommu_sm && pasid == INVALID_IOASID) + if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID) pasid = PASID_RID2PASID; dir_index = pasid >> PASID_PDE_SHIFT; @@ -915,8 +915,6 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, int level = agaw_to_level(domain->agaw); int offset; - BUG_ON(!domain->pgd); - if (!domain_pfn_supported(domain, pfn)) /* Address beyond IOMMU's addressing capabilities. */ return NULL; @@ -1005,9 +1003,9 @@ static void dma_pte_clear_range(struct dmar_domain *domain, unsigned int large_page; struct dma_pte *first_pte, *pte; - BUG_ON(!domain_pfn_supported(domain, start_pfn)); - BUG_ON(!domain_pfn_supported(domain, last_pfn)); - BUG_ON(start_pfn > last_pfn); + if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) || + WARN_ON(start_pfn > last_pfn)) + return; /* we don't need lock here; nobody else touches the iova range */ do { @@ -1166,9 +1164,9 @@ next: static void domain_unmap(struct dmar_domain *domain, unsigned long start_pfn, unsigned long last_pfn, struct list_head *freelist) { - BUG_ON(!domain_pfn_supported(domain, start_pfn)); - BUG_ON(!domain_pfn_supported(domain, last_pfn)); - BUG_ON(start_pfn > last_pfn); + if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) || + WARN_ON(start_pfn > last_pfn)) + return; /* we don't need lock here; nobody else touches the iova range */ dma_pte_clear_level(domain, agaw_to_level(domain->agaw), @@ -1272,7 +1270,9 @@ static void __iommu_flush_context(struct intel_iommu *iommu, | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask); break; default: - BUG(); + pr_warn("%s: Unexpected context-cache invalidation type 0x%llx\n", + iommu->name, type); + return; } val |= DMA_CCMD_ICC; @@ -1308,7 +1308,9 @@ static void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, val_iva = size_order | addr; break; default: - BUG(); + pr_warn("%s: Unexpected iotlb invalidation type 0x%llx\n", + iommu->name, type); + return; } /* Note: set drain read/write */ #if 0 @@ -1406,20 +1408,6 @@ static void iommu_enable_pci_caps(struct device_domain_info *info) return; pdev = to_pci_dev(info->dev); - /* For IOMMU that supports device IOTLB throttling (DIT), we assign - * PFSID to the invalidation desc of a VF such that IOMMU HW can gauge - * queue depth at PF level. If DIT is not set, PFSID will be treated as - * reserved, which should be set to 0. - */ - if (!ecap_dit(info->iommu->ecap)) - info->pfsid = 0; - else { - struct pci_dev *pf_pdev; - - /* pdev will be returned if device is not a vf */ - pf_pdev = pci_physfn(pdev); - info->pfsid = pci_dev_id(pf_pdev); - } /* The PCIe spec, in its wisdom, declares that the behaviour of the device if you enable PASID support after ATS support is @@ -1429,16 +1417,10 @@ static void iommu_enable_pci_caps(struct device_domain_info *info) if (info->pasid_supported && !pci_enable_pasid(pdev, info->pasid_supported & ~1)) info->pasid_enabled = 1; - if (info->pri_supported && - (info->pasid_enabled ? pci_prg_resp_pasid_required(pdev) : 1) && - !pci_reset_pri(pdev) && !pci_enable_pri(pdev, PRQ_DEPTH)) - info->pri_enabled = 1; - if (info->ats_supported && pci_ats_page_aligned(pdev) && !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) { info->ats_enabled = 1; domain_update_iotlb(info->domain); - info->ats_qdep = pci_ats_queue_depth(pdev); } } @@ -1457,11 +1439,6 @@ static void iommu_disable_pci_caps(struct device_domain_info *info) domain_update_iotlb(info->domain); } - if (info->pri_enabled) { - pci_disable_pri(pdev); - info->pri_enabled = 0; - } - if (info->pasid_enabled) { pci_disable_pasid(pdev); info->pasid_enabled = 0; @@ -1508,7 +1485,8 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT; u16 did = domain_id_iommu(domain, iommu); - BUG_ON(pages == 0); + if (WARN_ON(!pages)) + return; if (ih) ih = 1 << 6; @@ -1722,9 +1700,6 @@ static void free_dmar_iommu(struct intel_iommu *iommu) if (ecap_prs(iommu->ecap)) intel_svm_finish_prq(iommu); } - if (vccap_pasid(iommu->vccap)) - ioasid_unregister_allocator(&iommu->pasid_allocator); - #endif } @@ -1895,7 +1870,7 @@ context_set_sm_rid2pasid(struct context_entry *context, unsigned long pasid) */ static inline void context_set_sm_dte(struct context_entry *context) { - context->lo |= (1 << 2); + context->lo |= BIT_ULL(2); } /* @@ -1904,7 +1879,7 @@ static inline void context_set_sm_dte(struct context_entry *context) */ static inline void context_set_sm_pre(struct context_entry *context) { - context->lo |= (1 << 4); + context->lo |= BIT_ULL(4); } /* Convert value to context PASID directory size field coding. */ @@ -1930,8 +1905,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, pr_debug("Set context mapping for %02x:%02x.%d\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - BUG_ON(!domain->pgd); - spin_lock(&iommu->lock); ret = -ENOMEM; context = iommu_context_addr(iommu, bus, devfn, 1); @@ -2183,7 +2156,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, phys_addr_t pteval; u64 attr; - BUG_ON(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1)); + if (unlikely(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1))) + return -EINVAL; if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0) return -EINVAL; @@ -2341,8 +2315,6 @@ static int domain_setup_first_level(struct intel_iommu *iommu, if (level != 4 && level != 5) return -EINVAL; - if (pasid != PASID_RID2PASID) - flags |= PASID_FLAG_SUPERVISOR_MODE; if (level == 5) flags |= PASID_FLAG_FL5LP; @@ -2797,85 +2769,6 @@ out_unmap: return ret; } -#ifdef CONFIG_INTEL_IOMMU_SVM -static ioasid_t intel_vcmd_ioasid_alloc(ioasid_t min, ioasid_t max, void *data) -{ - struct intel_iommu *iommu = data; - ioasid_t ioasid; - - if (!iommu) - return INVALID_IOASID; - /* - * VT-d virtual command interface always uses the full 20 bit - * PASID range. Host can partition guest PASID range based on - * policies but it is out of guest's control. - */ - if (min < PASID_MIN || max > intel_pasid_max_id) - return INVALID_IOASID; - - if (vcmd_alloc_pasid(iommu, &ioasid)) - return INVALID_IOASID; - - return ioasid; -} - -static void intel_vcmd_ioasid_free(ioasid_t ioasid, void *data) -{ - struct intel_iommu *iommu = data; - - if (!iommu) - return; - /* - * Sanity check the ioasid owner is done at upper layer, e.g. VFIO - * We can only free the PASID when all the devices are unbound. - */ - if (ioasid_find(NULL, ioasid, NULL)) { - pr_alert("Cannot free active IOASID %d\n", ioasid); - return; - } - vcmd_free_pasid(iommu, ioasid); -} - -static void register_pasid_allocator(struct intel_iommu *iommu) -{ - /* - * If we are running in the host, no need for custom allocator - * in that PASIDs are allocated from the host system-wide. - */ - if (!cap_caching_mode(iommu->cap)) - return; - - if (!sm_supported(iommu)) { - pr_warn("VT-d Scalable Mode not enabled, no PASID allocation\n"); - return; - } - - /* - * Register a custom PASID allocator if we are running in a guest, - * guest PASID must be obtained via virtual command interface. - * There can be multiple vIOMMUs in each guest but only one allocator - * is active. All vIOMMU allocators will eventually be calling the same - * host allocator. - */ - if (!vccap_pasid(iommu->vccap)) - return; - - pr_info("Register custom PASID allocator\n"); - iommu->pasid_allocator.alloc = intel_vcmd_ioasid_alloc; - iommu->pasid_allocator.free = intel_vcmd_ioasid_free; - iommu->pasid_allocator.pdata = (void *)iommu; - if (ioasid_register_allocator(&iommu->pasid_allocator)) { - pr_warn("Custom PASID allocator failed, scalable mode disabled\n"); - /* - * Disable scalable mode on this IOMMU if there - * is no custom allocator. Mixing SM capable vIOMMU - * and non-SM vIOMMU are not supported. - */ - intel_iommu_sm = 0; - } -} -#endif - static int __init init_dmars(void) { struct dmar_drhd_unit *drhd; @@ -2964,9 +2857,6 @@ static int __init init_dmars(void) */ for_each_active_iommu(iommu, drhd) { iommu_flush_write_buffer(iommu); -#ifdef CONFIG_INTEL_IOMMU_SVM - register_pasid_allocator(iommu); -#endif iommu_set_root_entry(iommu); } @@ -3760,8 +3650,8 @@ static ssize_t version_show(struct device *dev, { struct intel_iommu *iommu = dev_to_intel_iommu(dev); u32 ver = readl(iommu->reg + DMAR_VER_REG); - return sprintf(buf, "%d:%d\n", - DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver)); + return sysfs_emit(buf, "%d:%d\n", + DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver)); } static DEVICE_ATTR_RO(version); @@ -3769,7 +3659,7 @@ static ssize_t address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct intel_iommu *iommu = dev_to_intel_iommu(dev); - return sprintf(buf, "%llx\n", iommu->reg_phys); + return sysfs_emit(buf, "%llx\n", iommu->reg_phys); } static DEVICE_ATTR_RO(address); @@ -3777,7 +3667,7 @@ static ssize_t cap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct intel_iommu *iommu = dev_to_intel_iommu(dev); - return sprintf(buf, "%llx\n", iommu->cap); + return sysfs_emit(buf, "%llx\n", iommu->cap); } static DEVICE_ATTR_RO(cap); @@ -3785,7 +3675,7 @@ static ssize_t ecap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct intel_iommu *iommu = dev_to_intel_iommu(dev); - return sprintf(buf, "%llx\n", iommu->ecap); + return sysfs_emit(buf, "%llx\n", iommu->ecap); } static DEVICE_ATTR_RO(ecap); @@ -3793,7 +3683,7 @@ static ssize_t domains_supported_show(struct device *dev, struct device_attribute *attr, char *buf) { struct intel_iommu *iommu = dev_to_intel_iommu(dev); - return sprintf(buf, "%ld\n", cap_ndoms(iommu->cap)); + return sysfs_emit(buf, "%ld\n", cap_ndoms(iommu->cap)); } static DEVICE_ATTR_RO(domains_supported); @@ -3801,8 +3691,9 @@ static ssize_t domains_used_show(struct device *dev, struct device_attribute *attr, char *buf) { struct intel_iommu *iommu = dev_to_intel_iommu(dev); - return sprintf(buf, "%d\n", bitmap_weight(iommu->domain_ids, - cap_ndoms(iommu->cap))); + return sysfs_emit(buf, "%d\n", + bitmap_weight(iommu->domain_ids, + cap_ndoms(iommu->cap))); } static DEVICE_ATTR_RO(domains_used); @@ -4340,8 +4231,9 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain, /* Cope with horrid API which requires us to unmap more than the size argument if it happens to be a large-page mapping. */ - BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level, - GFP_ATOMIC)); + if (unlikely(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, + &level, GFP_ATOMIC))) + return 0; if (size < VTD_PAGE_SIZE << level_to_offset_bits(level)) size = VTD_PAGE_SIZE << level_to_offset_bits(level); @@ -4521,6 +4413,17 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) dmar_ats_supported(pdev, iommu)) { info->ats_supported = 1; info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev); + + /* + * For IOMMU that supports device IOTLB throttling + * (DIT), we assign PFSID to the invalidation desc + * of a VF such that IOMMU HW can gauge queue depth + * at PF level. If DIT is not set, PFSID will be + * treated as reserved, which should be set to 0. + */ + if (ecap_dit(iommu->ecap)) + info->pfsid = pci_dev_id(pci_physfn(pdev)); + info->ats_qdep = pci_ats_queue_depth(pdev); } if (sm_supported(iommu)) { if (pasid_supported(iommu)) { @@ -4638,7 +4541,6 @@ static int intel_iommu_enable_sva(struct device *dev) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct intel_iommu *iommu; - int ret; if (!info || dmar_disabled) return -EINVAL; @@ -4650,45 +4552,102 @@ static int intel_iommu_enable_sva(struct device *dev) if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE)) return -ENODEV; - if (!info->pasid_enabled || !info->pri_enabled || !info->ats_enabled) + if (!info->pasid_enabled || !info->ats_enabled) return -EINVAL; + /* + * Devices having device-specific I/O fault handling should not + * support PCI/PRI. The IOMMU side has no means to check the + * capability of device-specific IOPF. Therefore, IOMMU can only + * default that if the device driver enables SVA on a non-PRI + * device, it will handle IOPF in its own way. + */ + if (!info->pri_supported) + return 0; + + /* Devices supporting PRI should have it enabled. */ + if (!info->pri_enabled) + return -EINVAL; + + return 0; +} + +static int intel_iommu_enable_iopf(struct device *dev) +{ + struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL; + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct intel_iommu *iommu; + int ret; + + if (!pdev || !info || !info->ats_enabled || !info->pri_supported) + return -ENODEV; + + if (info->pri_enabled) + return -EBUSY; + + iommu = info->iommu; + if (!iommu) + return -EINVAL; + + /* PASID is required in PRG Response Message. */ + if (info->pasid_enabled && !pci_prg_resp_pasid_required(pdev)) + return -EINVAL; + + ret = pci_reset_pri(pdev); + if (ret) + return ret; + ret = iopf_queue_add_device(iommu->iopf_queue, dev); if (ret) return ret; ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev); if (ret) - iopf_queue_remove_device(iommu->iopf_queue, dev); + goto iopf_remove_device; + + ret = pci_enable_pri(pdev, PRQ_DEPTH); + if (ret) + goto iopf_unregister_handler; + info->pri_enabled = 1; + + return 0; + +iopf_unregister_handler: + iommu_unregister_device_fault_handler(dev); +iopf_remove_device: + iopf_queue_remove_device(iommu->iopf_queue, dev); return ret; } -static int intel_iommu_disable_sva(struct device *dev) +static int intel_iommu_disable_iopf(struct device *dev) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct intel_iommu *iommu = info->iommu; - int ret; - ret = iommu_unregister_device_fault_handler(dev); - if (ret) - return ret; + if (!info->pri_enabled) + return -EINVAL; - ret = iopf_queue_remove_device(iommu->iopf_queue, dev); - if (ret) - iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev); + /* + * PCIe spec states that by clearing PRI enable bit, the Page + * Request Interface will not issue new page requests, but has + * outstanding page requests that have been transmitted or are + * queued for transmission. This is supposed to be called after + * the device driver has stopped DMA, all PASIDs have been + * unbound and the outstanding PRQs have been drained. + */ + pci_disable_pri(to_pci_dev(dev)); + info->pri_enabled = 0; - return ret; -} + /* + * With PRI disabled and outstanding PRQs drained, unregistering + * fault handler and removing device from iopf queue should never + * fail. + */ + WARN_ON(iommu_unregister_device_fault_handler(dev)); + WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev)); -static int intel_iommu_enable_iopf(struct device *dev) -{ - struct device_domain_info *info = dev_iommu_priv_get(dev); - - if (info && info->pri_supported) - return 0; - - return -ENODEV; + return 0; } static int @@ -4711,10 +4670,10 @@ intel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat) { switch (feat) { case IOMMU_DEV_FEAT_IOPF: - return 0; + return intel_iommu_disable_iopf(dev); case IOMMU_DEV_FEAT_SVA: - return intel_iommu_disable_sva(dev); + return 0; default: return -ENODEV; diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 694ab9b7d3e9..1c5e1d88862b 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -198,7 +197,6 @@ #define ecap_flts(e) (((e) >> 47) & 0x1) #define ecap_slts(e) (((e) >> 46) & 0x1) #define ecap_slads(e) (((e) >> 45) & 0x1) -#define ecap_vcs(e) (((e) >> 44) & 0x1) #define ecap_smts(e) (((e) >> 43) & 0x1) #define ecap_dit(e) (((e) >> 41) & 0x1) #define ecap_pds(e) (((e) >> 42) & 0x1) @@ -678,7 +676,6 @@ struct intel_iommu { unsigned char prq_name[16]; /* Name for PRQ interrupt */ unsigned long prq_seq_number; struct completion prq_complete; - struct ioasid_allocator_ops pasid_allocator; /* Custom allocator for PASIDs */ #endif struct iopf_queue *iopf_queue; unsigned char iopfq_name[16]; @@ -798,18 +795,18 @@ static inline bool context_present(struct context_entry *context) return (context->lo & 1); } -extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); +struct dmar_drhd_unit *dmar_find_matched_drhd_unit(struct pci_dev *dev); -extern int dmar_enable_qi(struct intel_iommu *iommu); -extern void dmar_disable_qi(struct intel_iommu *iommu); -extern int dmar_reenable_qi(struct intel_iommu *iommu); -extern void qi_global_iec(struct intel_iommu *iommu); +int dmar_enable_qi(struct intel_iommu *iommu); +void dmar_disable_qi(struct intel_iommu *iommu); +int dmar_reenable_qi(struct intel_iommu *iommu); +void qi_global_iec(struct intel_iommu *iommu); -extern void qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, - u8 fm, u64 type); -extern void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, - unsigned int size_order, u64 type); -extern void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid, +void qi_flush_context(struct intel_iommu *iommu, u16 did, + u16 sid, u8 fm, u64 type); +void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, + unsigned int size_order, u64 type); +void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid, u16 qdep, u64 addr, unsigned mask); void qi_flush_piotlb(struct intel_iommu *iommu, u16 did, u32 pasid, u64 addr, @@ -832,7 +829,7 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc, */ #define QI_OPT_WAIT_DRAIN BIT(0) -extern int dmar_ir_support(void); +int dmar_ir_support(void); void *alloc_pgtable_page(int node, gfp_t gfp); void free_pgtable_page(void *vaddr); @@ -840,9 +837,9 @@ void iommu_flush_write_buffer(struct intel_iommu *iommu); struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn); #ifdef CONFIG_INTEL_IOMMU_SVM -extern void intel_svm_check(struct intel_iommu *iommu); -extern int intel_svm_enable_prq(struct intel_iommu *iommu); -extern int intel_svm_finish_prq(struct intel_iommu *iommu); +void intel_svm_check(struct intel_iommu *iommu); +int intel_svm_enable_prq(struct intel_iommu *iommu); +int intel_svm_finish_prq(struct intel_iommu *iommu); int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt, struct iommu_page_response *msg); struct iommu_domain *intel_svm_domain_alloc(void); @@ -889,8 +886,8 @@ extern const struct iommu_ops intel_iommu_ops; #ifdef CONFIG_INTEL_IOMMU extern int intel_iommu_sm; -extern int iommu_calculate_agaw(struct intel_iommu *iommu); -extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu); +int iommu_calculate_agaw(struct intel_iommu *iommu); +int iommu_calculate_max_sagaw(struct intel_iommu *iommu); int ecmd_submit_sync(struct intel_iommu *iommu, u8 ecmd, u64 oa, u64 ob); static inline bool ecmd_has_pmu_essential(struct intel_iommu *iommu) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index df9e261af0b5..a1b987335b31 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -548,7 +548,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) goto out_free_table; } - bitmap = bitmap_zalloc(INTR_REMAP_TABLE_ENTRIES, GFP_ATOMIC); + bitmap = bitmap_zalloc(INTR_REMAP_TABLE_ENTRIES, GFP_KERNEL); if (bitmap == NULL) { pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id); goto out_free_pages; diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index 633e0a4a01e7..c5d479770e12 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -335,15 +335,6 @@ static inline void pasid_set_fault_enable(struct pasid_entry *pe) pasid_set_bits(&pe->val[0], 1 << 1, 0); } -/* - * Setup the SRE(Supervisor Request Enable) field (Bit 128) of a - * scalable mode PASID entry. - */ -static inline void pasid_set_sre(struct pasid_entry *pe) -{ - pasid_set_bits(&pe->val[2], 1 << 0, 1); -} - /* * Setup the WPE(Write Protect Enable) field (Bit 132) of a * scalable mode PASID entry. @@ -521,23 +512,6 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu, return -EINVAL; } - if (flags & PASID_FLAG_SUPERVISOR_MODE) { -#ifdef CONFIG_X86 - unsigned long cr0 = read_cr0(); - - /* CR0.WP is normally set but just to be sure */ - if (unlikely(!(cr0 & X86_CR0_WP))) { - pr_err("No CPU write protect!\n"); - return -EINVAL; - } -#endif - if (!ecap_srs(iommu->ecap)) { - pr_err("No supervisor request support on %s\n", - iommu->name); - return -EINVAL; - } - } - if ((flags & PASID_FLAG_FL5LP) && !cap_fl5lp_support(iommu->cap)) { pr_err("No 5-level paging support for first-level on %s\n", iommu->name); @@ -560,10 +534,6 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu, /* Setup the first level page table pointer: */ pasid_set_flptr(pte, (u64)__pa(pgd)); - if (flags & PASID_FLAG_SUPERVISOR_MODE) { - pasid_set_sre(pte); - pasid_set_wpe(pte); - } if (flags & PASID_FLAG_FL5LP) pasid_set_flpm(pte, 1); @@ -658,12 +628,6 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, pasid_set_fault_enable(pte); pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); - /* - * Since it is a second level only translation setup, we should - * set SRE bit as well (addresses are expected to be GPAs). - */ - if (pasid != PASID_RID2PASID && ecap_srs(iommu->ecap)) - pasid_set_sre(pte); pasid_set_present(pte); spin_unlock(&iommu->lock); @@ -700,13 +664,6 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, pasid_set_translation_type(pte, PASID_ENTRY_PGTT_PT); pasid_set_fault_enable(pte); pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); - - /* - * We should set SRE bit as well since the addresses are expected - * to be GPAs. - */ - if (ecap_srs(iommu->ecap)) - pasid_set_sre(pte); pasid_set_present(pte); spin_unlock(&iommu->lock); diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index 20c54e50f533..d6b7d21244b1 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -41,13 +41,6 @@ #define FLPT_DEFAULT_DID 1 #define NUM_RESERVED_DID 2 -/* - * The SUPERVISOR_MODE flag indicates a first level translation which - * can be used for access to kernel addresses. It is valid only for - * access to the kernel's static 1:1 mapping of physical memory — not - * to vmalloc or even module mappings. - */ -#define PASID_FLAG_SUPERVISOR_MODE BIT(0) #define PASID_FLAG_NESTED BIT(1) #define PASID_FLAG_PAGE_SNOOP BIT(2) diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 7367f56c3bad..e95b339e9cdc 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -273,7 +272,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid, if (WARN_ON(!mutex_is_locked(&pasid_mutex))) return -EINVAL; - if (pasid == INVALID_IOASID || pasid >= PASID_MAX) + if (pasid == IOMMU_PASID_INVALID || pasid >= PASID_MAX) return -EINVAL; svm = pasid_private_find(pasid); diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c deleted file mode 100644 index a786c034907c..000000000000 --- a/drivers/iommu/ioasid.c +++ /dev/null @@ -1,422 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * I/O Address Space ID allocator. There is one global IOASID space, split into - * subsets. Users create a subset with DECLARE_IOASID_SET, then allocate and - * free IOASIDs with ioasid_alloc() and ioasid_free(). - */ -#include -#include -#include -#include -#include - -struct ioasid_data { - ioasid_t id; - struct ioasid_set *set; - void *private; - struct rcu_head rcu; -}; - -/* - * struct ioasid_allocator_data - Internal data structure to hold information - * about an allocator. There are two types of allocators: - * - * - Default allocator always has its own XArray to track the IOASIDs allocated. - * - Custom allocators may share allocation helpers with different private data. - * Custom allocators that share the same helper functions also share the same - * XArray. - * Rules: - * 1. Default allocator is always available, not dynamically registered. This is - * to prevent race conditions with early boot code that want to register - * custom allocators or allocate IOASIDs. - * 2. Custom allocators take precedence over the default allocator. - * 3. When all custom allocators sharing the same helper functions are - * unregistered (e.g. due to hotplug), all outstanding IOASIDs must be - * freed. Otherwise, outstanding IOASIDs will be lost and orphaned. - * 4. When switching between custom allocators sharing the same helper - * functions, outstanding IOASIDs are preserved. - * 5. When switching between custom allocator and default allocator, all IOASIDs - * must be freed to ensure unadulterated space for the new allocator. - * - * @ops: allocator helper functions and its data - * @list: registered custom allocators - * @slist: allocators share the same ops but different data - * @flags: attributes of the allocator - * @xa: xarray holds the IOASID space - * @rcu: used for kfree_rcu when unregistering allocator - */ -struct ioasid_allocator_data { - struct ioasid_allocator_ops *ops; - struct list_head list; - struct list_head slist; -#define IOASID_ALLOCATOR_CUSTOM BIT(0) /* Needs framework to track results */ - unsigned long flags; - struct xarray xa; - struct rcu_head rcu; -}; - -static DEFINE_SPINLOCK(ioasid_allocator_lock); -static LIST_HEAD(allocators_list); - -static ioasid_t default_alloc(ioasid_t min, ioasid_t max, void *opaque); -static void default_free(ioasid_t ioasid, void *opaque); - -static struct ioasid_allocator_ops default_ops = { - .alloc = default_alloc, - .free = default_free, -}; - -static struct ioasid_allocator_data default_allocator = { - .ops = &default_ops, - .flags = 0, - .xa = XARRAY_INIT(ioasid_xa, XA_FLAGS_ALLOC), -}; - -static struct ioasid_allocator_data *active_allocator = &default_allocator; - -static ioasid_t default_alloc(ioasid_t min, ioasid_t max, void *opaque) -{ - ioasid_t id; - - if (xa_alloc(&default_allocator.xa, &id, opaque, XA_LIMIT(min, max), GFP_ATOMIC)) { - pr_err("Failed to alloc ioasid from %d to %d\n", min, max); - return INVALID_IOASID; - } - - return id; -} - -static void default_free(ioasid_t ioasid, void *opaque) -{ - struct ioasid_data *ioasid_data; - - ioasid_data = xa_erase(&default_allocator.xa, ioasid); - kfree_rcu(ioasid_data, rcu); -} - -/* Allocate and initialize a new custom allocator with its helper functions */ -static struct ioasid_allocator_data *ioasid_alloc_allocator(struct ioasid_allocator_ops *ops) -{ - struct ioasid_allocator_data *ia_data; - - ia_data = kzalloc(sizeof(*ia_data), GFP_ATOMIC); - if (!ia_data) - return NULL; - - xa_init_flags(&ia_data->xa, XA_FLAGS_ALLOC); - INIT_LIST_HEAD(&ia_data->slist); - ia_data->flags |= IOASID_ALLOCATOR_CUSTOM; - ia_data->ops = ops; - - /* For tracking custom allocators that share the same ops */ - list_add_tail(&ops->list, &ia_data->slist); - - return ia_data; -} - -static bool use_same_ops(struct ioasid_allocator_ops *a, struct ioasid_allocator_ops *b) -{ - return (a->free == b->free) && (a->alloc == b->alloc); -} - -/** - * ioasid_register_allocator - register a custom allocator - * @ops: the custom allocator ops to be registered - * - * Custom allocators take precedence over the default xarray based allocator. - * Private data associated with the IOASID allocated by the custom allocators - * are managed by IOASID framework similar to data stored in xa by default - * allocator. - * - * There can be multiple allocators registered but only one is active. In case - * of runtime removal of a custom allocator, the next one is activated based - * on the registration ordering. - * - * Multiple allocators can share the same alloc() function, in this case the - * IOASID space is shared. - */ -int ioasid_register_allocator(struct ioasid_allocator_ops *ops) -{ - struct ioasid_allocator_data *ia_data; - struct ioasid_allocator_data *pallocator; - int ret = 0; - - spin_lock(&ioasid_allocator_lock); - - ia_data = ioasid_alloc_allocator(ops); - if (!ia_data) { - ret = -ENOMEM; - goto out_unlock; - } - - /* - * No particular preference, we activate the first one and keep - * the later registered allocators in a list in case the first one gets - * removed due to hotplug. - */ - if (list_empty(&allocators_list)) { - WARN_ON(active_allocator != &default_allocator); - /* Use this new allocator if default is not active */ - if (xa_empty(&active_allocator->xa)) { - rcu_assign_pointer(active_allocator, ia_data); - list_add_tail(&ia_data->list, &allocators_list); - goto out_unlock; - } - pr_warn("Default allocator active with outstanding IOASID\n"); - ret = -EAGAIN; - goto out_free; - } - - /* Check if the allocator is already registered */ - list_for_each_entry(pallocator, &allocators_list, list) { - if (pallocator->ops == ops) { - pr_err("IOASID allocator already registered\n"); - ret = -EEXIST; - goto out_free; - } else if (use_same_ops(pallocator->ops, ops)) { - /* - * If the new allocator shares the same ops, - * then they will share the same IOASID space. - * We should put them under the same xarray. - */ - list_add_tail(&ops->list, &pallocator->slist); - goto out_free; - } - } - list_add_tail(&ia_data->list, &allocators_list); - - spin_unlock(&ioasid_allocator_lock); - return 0; -out_free: - kfree(ia_data); -out_unlock: - spin_unlock(&ioasid_allocator_lock); - return ret; -} -EXPORT_SYMBOL_GPL(ioasid_register_allocator); - -/** - * ioasid_unregister_allocator - Remove a custom IOASID allocator ops - * @ops: the custom allocator to be removed - * - * Remove an allocator from the list, activate the next allocator in - * the order it was registered. Or revert to default allocator if all - * custom allocators are unregistered without outstanding IOASIDs. - */ -void ioasid_unregister_allocator(struct ioasid_allocator_ops *ops) -{ - struct ioasid_allocator_data *pallocator; - struct ioasid_allocator_ops *sops; - - spin_lock(&ioasid_allocator_lock); - if (list_empty(&allocators_list)) { - pr_warn("No custom IOASID allocators active!\n"); - goto exit_unlock; - } - - list_for_each_entry(pallocator, &allocators_list, list) { - if (!use_same_ops(pallocator->ops, ops)) - continue; - - if (list_is_singular(&pallocator->slist)) { - /* No shared helper functions */ - list_del(&pallocator->list); - /* - * All IOASIDs should have been freed before - * the last allocator that shares the same ops - * is unregistered. - */ - WARN_ON(!xa_empty(&pallocator->xa)); - if (list_empty(&allocators_list)) { - pr_info("No custom IOASID allocators, switch to default.\n"); - rcu_assign_pointer(active_allocator, &default_allocator); - } else if (pallocator == active_allocator) { - rcu_assign_pointer(active_allocator, - list_first_entry(&allocators_list, - struct ioasid_allocator_data, list)); - pr_info("IOASID allocator changed"); - } - kfree_rcu(pallocator, rcu); - break; - } - /* - * Find the matching shared ops to delete, - * but keep outstanding IOASIDs - */ - list_for_each_entry(sops, &pallocator->slist, list) { - if (sops == ops) { - list_del(&ops->list); - break; - } - } - break; - } - -exit_unlock: - spin_unlock(&ioasid_allocator_lock); -} -EXPORT_SYMBOL_GPL(ioasid_unregister_allocator); - -/** - * ioasid_set_data - Set private data for an allocated ioasid - * @ioasid: the ID to set data - * @data: the private data - * - * For IOASID that is already allocated, private data can be set - * via this API. Future lookup can be done via ioasid_find. - */ -int ioasid_set_data(ioasid_t ioasid, void *data) -{ - struct ioasid_data *ioasid_data; - int ret = 0; - - spin_lock(&ioasid_allocator_lock); - ioasid_data = xa_load(&active_allocator->xa, ioasid); - if (ioasid_data) - rcu_assign_pointer(ioasid_data->private, data); - else - ret = -ENOENT; - spin_unlock(&ioasid_allocator_lock); - - /* - * Wait for readers to stop accessing the old private data, so the - * caller can free it. - */ - if (!ret) - synchronize_rcu(); - - return ret; -} -EXPORT_SYMBOL_GPL(ioasid_set_data); - -/** - * ioasid_alloc - Allocate an IOASID - * @set: the IOASID set - * @min: the minimum ID (inclusive) - * @max: the maximum ID (inclusive) - * @private: data private to the caller - * - * Allocate an ID between @min and @max. The @private pointer is stored - * internally and can be retrieved with ioasid_find(). - * - * Return: the allocated ID on success, or %INVALID_IOASID on failure. - */ -ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max, - void *private) -{ - struct ioasid_data *data; - void *adata; - ioasid_t id; - - data = kzalloc(sizeof(*data), GFP_ATOMIC); - if (!data) - return INVALID_IOASID; - - data->set = set; - data->private = private; - - /* - * Custom allocator needs allocator data to perform platform specific - * operations. - */ - spin_lock(&ioasid_allocator_lock); - adata = active_allocator->flags & IOASID_ALLOCATOR_CUSTOM ? active_allocator->ops->pdata : data; - id = active_allocator->ops->alloc(min, max, adata); - if (id == INVALID_IOASID) { - pr_err("Failed ASID allocation %lu\n", active_allocator->flags); - goto exit_free; - } - - if ((active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) && - xa_alloc(&active_allocator->xa, &id, data, XA_LIMIT(id, id), GFP_ATOMIC)) { - /* Custom allocator needs framework to store and track allocation results */ - pr_err("Failed to alloc ioasid from %d\n", id); - active_allocator->ops->free(id, active_allocator->ops->pdata); - goto exit_free; - } - data->id = id; - - spin_unlock(&ioasid_allocator_lock); - return id; -exit_free: - spin_unlock(&ioasid_allocator_lock); - kfree(data); - return INVALID_IOASID; -} -EXPORT_SYMBOL_GPL(ioasid_alloc); - -/** - * ioasid_free - Free an ioasid - * @ioasid: the ID to remove - */ -void ioasid_free(ioasid_t ioasid) -{ - struct ioasid_data *ioasid_data; - - spin_lock(&ioasid_allocator_lock); - ioasid_data = xa_load(&active_allocator->xa, ioasid); - if (!ioasid_data) { - pr_err("Trying to free unknown IOASID %u\n", ioasid); - goto exit_unlock; - } - - active_allocator->ops->free(ioasid, active_allocator->ops->pdata); - /* Custom allocator needs additional steps to free the xa element */ - if (active_allocator->flags & IOASID_ALLOCATOR_CUSTOM) { - ioasid_data = xa_erase(&active_allocator->xa, ioasid); - kfree_rcu(ioasid_data, rcu); - } - -exit_unlock: - spin_unlock(&ioasid_allocator_lock); -} -EXPORT_SYMBOL_GPL(ioasid_free); - -/** - * ioasid_find - Find IOASID data - * @set: the IOASID set - * @ioasid: the IOASID to find - * @getter: function to call on the found object - * - * The optional getter function allows to take a reference to the found object - * under the rcu lock. The function can also check if the object is still valid: - * if @getter returns false, then the object is invalid and NULL is returned. - * - * If the IOASID exists, return the private pointer passed to ioasid_alloc. - * Private data can be NULL if not set. Return an error if the IOASID is not - * found, or if @set is not NULL and the IOASID does not belong to the set. - */ -void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid, - bool (*getter)(void *)) -{ - void *priv; - struct ioasid_data *ioasid_data; - struct ioasid_allocator_data *idata; - - rcu_read_lock(); - idata = rcu_dereference(active_allocator); - ioasid_data = xa_load(&idata->xa, ioasid); - if (!ioasid_data) { - priv = ERR_PTR(-ENOENT); - goto unlock; - } - if (set && ioasid_data->set != set) { - /* data found but does not belong to the set */ - priv = ERR_PTR(-EACCES); - goto unlock; - } - /* Now IOASID and its set is verified, we can return the private data */ - priv = rcu_dereference(ioasid_data->private); - if (getter && !getter(priv)) - priv = NULL; -unlock: - rcu_read_unlock(); - - return priv; -} -EXPORT_SYMBOL_GPL(ioasid_find); - -MODULE_AUTHOR("Jean-Philippe Brucker "); -MODULE_AUTHOR("Jacob Pan "); -MODULE_DESCRIPTION("IO Address Space ID (IOASID) allocator"); -MODULE_LICENSE("GPL"); diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index 24bf9b2b58aa..9821bc44f5ac 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -2,6 +2,7 @@ /* * Helpers for IOMMU drivers implementing SVA */ +#include #include #include #include @@ -9,67 +10,38 @@ #include "iommu-sva.h" static DEFINE_MUTEX(iommu_sva_lock); -static DECLARE_IOASID_SET(iommu_sva_pasid); +static DEFINE_IDA(iommu_global_pasid_ida); -/** - * iommu_sva_alloc_pasid - Allocate a PASID for the mm - * @mm: the mm - * @min: minimum PASID value (inclusive) - * @max: maximum PASID value (inclusive) - * - * Try to allocate a PASID for this mm, or take a reference to the existing one - * provided it fits within the [@min, @max] range. On success the PASID is - * available in mm->pasid and will be available for the lifetime of the mm. - * - * Returns 0 on success and < 0 on error. - */ -int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max) +/* Allocate a PASID for the mm within range (inclusive) */ +static int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max) { int ret = 0; - ioasid_t pasid; - if (min == INVALID_IOASID || max == INVALID_IOASID || + if (min == IOMMU_PASID_INVALID || + max == IOMMU_PASID_INVALID || min == 0 || max < min) return -EINVAL; + if (!arch_pgtable_dma_compat(mm)) + return -EBUSY; + mutex_lock(&iommu_sva_lock); /* Is a PASID already associated with this mm? */ - if (pasid_valid(mm->pasid)) { - if (mm->pasid < min || mm->pasid >= max) + if (mm_valid_pasid(mm)) { + if (mm->pasid < min || mm->pasid > max) ret = -EOVERFLOW; goto out; } - pasid = ioasid_alloc(&iommu_sva_pasid, min, max, mm); - if (!pasid_valid(pasid)) - ret = -ENOMEM; - else - mm_pasid_set(mm, pasid); + ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL); + if (ret < min) + goto out; + mm->pasid = ret; + ret = 0; out: mutex_unlock(&iommu_sva_lock); return ret; } -EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid); - -/* ioasid_find getter() requires a void * argument */ -static bool __mmget_not_zero(void *mm) -{ - return mmget_not_zero(mm); -} - -/** - * iommu_sva_find() - Find mm associated to the given PASID - * @pasid: Process Address Space ID assigned to the mm - * - * On success a reference to the mm is taken, and must be released with mmput(). - * - * Returns the mm corresponding to this PASID, or an error if not found. - */ -struct mm_struct *iommu_sva_find(ioasid_t pasid) -{ - return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero); -} -EXPORT_SYMBOL_GPL(iommu_sva_find); /** * iommu_sva_bind_device() - Bind a process address space to a device @@ -238,3 +210,11 @@ out_put_mm: return status; } + +void mm_pasid_drop(struct mm_struct *mm) +{ + if (likely(!mm_valid_pasid(mm))) + return; + + ida_free(&iommu_global_pasid_ida, mm->pasid); +} diff --git a/drivers/iommu/iommu-sva.h b/drivers/iommu/iommu-sva.h index 7215a761b962..54946b5a7caf 100644 --- a/drivers/iommu/iommu-sva.h +++ b/drivers/iommu/iommu-sva.h @@ -5,12 +5,8 @@ #ifndef _IOMMU_SVA_H #define _IOMMU_SVA_H -#include #include -int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max); -struct mm_struct *iommu_sva_find(ioasid_t pasid); - /* I/O Page fault */ struct device; struct iommu_fault; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 10db680acaed..f1dcfa3f1a1b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -87,9 +88,10 @@ static const char * const iommu_group_resv_type_string[] = { static int iommu_bus_notifier(struct notifier_block *nb, unsigned long action, void *data); +static void iommu_release_device(struct device *dev); static int iommu_alloc_default_domain(struct iommu_group *group, struct device *dev); -static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, +static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, unsigned type); static int __iommu_attach_device(struct iommu_domain *domain, struct device *dev); @@ -129,6 +131,9 @@ static struct bus_type * const iommu_buses[] = { #ifdef CONFIG_TEGRA_HOST1X_CONTEXT_BUS &host1x_context_device_bus_type, #endif +#ifdef CONFIG_CDX_BUS + &cdx_bus_type, +#endif }; /* @@ -453,20 +458,86 @@ err_out: } -void iommu_release_device(struct device *dev) +/* + * Remove a device from a group's device list and return the group device + * if successful. + */ +static struct group_device * +__iommu_group_remove_device(struct iommu_group *group, struct device *dev) { + struct group_device *device; + + lockdep_assert_held(&group->mutex); + list_for_each_entry(device, &group->devices, list) { + if (device->dev == dev) { + list_del(&device->list); + return device; + } + } + + return NULL; +} + +/* + * Release a device from its group and decrements the iommu group reference + * count. + */ +static void __iommu_group_release_device(struct iommu_group *group, + struct group_device *grp_dev) +{ + struct device *dev = grp_dev->dev; + + sysfs_remove_link(group->devices_kobj, grp_dev->name); + sysfs_remove_link(&dev->kobj, "iommu_group"); + + trace_remove_device_from_group(group->id, dev); + + kfree(grp_dev->name); + kfree(grp_dev); + dev->iommu_group = NULL; + kobject_put(group->devices_kobj); +} + +static void iommu_release_device(struct device *dev) +{ + struct iommu_group *group = dev->iommu_group; + struct group_device *device; const struct iommu_ops *ops; - if (!dev->iommu) + if (!dev->iommu || !group) return; iommu_device_unlink(dev->iommu->iommu_dev, dev); + mutex_lock(&group->mutex); + device = __iommu_group_remove_device(group, dev); + + /* + * If the group has become empty then ownership must have been released, + * and the current domain must be set back to NULL or the default + * domain. + */ + if (list_empty(&group->devices)) + WARN_ON(group->owner_cnt || + group->domain != group->default_domain); + + /* + * release_device() must stop using any attached domain on the device. + * If there are still other devices in the group they are not effected + * by this callback. + * + * The IOMMU driver must set the device to either an identity or + * blocking translation and stop using any domain pointer, as it is + * going to be freed. + */ ops = dev_iommu_ops(dev); if (ops->release_device) ops->release_device(dev); + mutex_unlock(&group->mutex); + + if (device) + __iommu_group_release_device(group, device); - iommu_group_remove_device(dev); module_put(ops->owner); dev_iommu_free(dev); } @@ -550,7 +621,7 @@ static void iommu_group_remove_file(struct iommu_group *group, static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf) { - return sprintf(buf, "%s\n", group->name); + return sysfs_emit(buf, "%s\n", group->name); } /** @@ -663,52 +734,51 @@ static ssize_t iommu_group_show_resv_regions(struct iommu_group *group, { struct iommu_resv_region *region, *next; struct list_head group_resv_regions; - char *str = buf; + int offset = 0; INIT_LIST_HEAD(&group_resv_regions); iommu_get_group_resv_regions(group, &group_resv_regions); list_for_each_entry_safe(region, next, &group_resv_regions, list) { - str += sprintf(str, "0x%016llx 0x%016llx %s\n", - (long long int)region->start, - (long long int)(region->start + - region->length - 1), - iommu_group_resv_type_string[region->type]); + offset += sysfs_emit_at(buf, offset, "0x%016llx 0x%016llx %s\n", + (long long)region->start, + (long long)(region->start + + region->length - 1), + iommu_group_resv_type_string[region->type]); kfree(region); } - return (str - buf); + return offset; } static ssize_t iommu_group_show_type(struct iommu_group *group, char *buf) { - char *type = "unknown\n"; + char *type = "unknown"; mutex_lock(&group->mutex); if (group->default_domain) { switch (group->default_domain->type) { case IOMMU_DOMAIN_BLOCKED: - type = "blocked\n"; + type = "blocked"; break; case IOMMU_DOMAIN_IDENTITY: - type = "identity\n"; + type = "identity"; break; case IOMMU_DOMAIN_UNMANAGED: - type = "unmanaged\n"; + type = "unmanaged"; break; case IOMMU_DOMAIN_DMA: - type = "DMA\n"; + type = "DMA"; break; case IOMMU_DOMAIN_DMA_FQ: - type = "DMA-FQ\n"; + type = "DMA-FQ"; break; } } mutex_unlock(&group->mutex); - strcpy(buf, type); - return strlen(type); + return sysfs_emit(buf, "%s\n", type); } static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); @@ -739,7 +809,7 @@ static void iommu_group_release(struct kobject *kobj) kfree(group); } -static struct kobj_type iommu_group_ktype = { +static const struct kobj_type iommu_group_ktype = { .sysfs_ops = &iommu_group_sysfs_ops, .release = iommu_group_release, }; @@ -816,35 +886,6 @@ struct iommu_group *iommu_group_alloc(void) } EXPORT_SYMBOL_GPL(iommu_group_alloc); -struct iommu_group *iommu_group_get_by_id(int id) -{ - struct kobject *group_kobj; - struct iommu_group *group; - const char *name; - - if (!iommu_group_kset) - return NULL; - - name = kasprintf(GFP_KERNEL, "%d", id); - if (!name) - return NULL; - - group_kobj = kset_find_obj(iommu_group_kset, name); - kfree(name); - - if (!group_kobj) - return NULL; - - group = container_of(group_kobj, struct iommu_group, kobj); - BUG_ON(group->id != id); - - kobject_get(group->devices_kobj); - kobject_put(&group->kobj); - - return group; -} -EXPORT_SYMBOL_GPL(iommu_group_get_by_id); - /** * iommu_group_get_iommudata - retrieve iommu_data registered for a group * @group: the group @@ -1068,7 +1109,7 @@ EXPORT_SYMBOL_GPL(iommu_group_add_device); void iommu_group_remove_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; - struct group_device *tmp_device, *device = NULL; + struct group_device *device; if (!group) return; @@ -1076,27 +1117,11 @@ void iommu_group_remove_device(struct device *dev) dev_info(dev, "Removing from iommu group %d\n", group->id); mutex_lock(&group->mutex); - list_for_each_entry(tmp_device, &group->devices, list) { - if (tmp_device->dev == dev) { - device = tmp_device; - list_del(&device->list); - break; - } - } + device = __iommu_group_remove_device(group, dev); mutex_unlock(&group->mutex); - if (!device) - return; - - sysfs_remove_link(group->devices_kobj, device->name); - sysfs_remove_link(&dev->kobj, "iommu_group"); - - trace_remove_device_from_group(group->id, dev); - - kfree(device->name); - kfree(device); - dev->iommu_group = NULL; - kobject_put(group->devices_kobj); + if (device) + __iommu_group_release_device(group, device); } EXPORT_SYMBOL_GPL(iommu_group_remove_device); @@ -1631,7 +1656,7 @@ static int iommu_get_def_domain_type(struct device *dev) return 0; } -static int iommu_group_alloc_default_domain(struct bus_type *bus, +static int iommu_group_alloc_default_domain(const struct bus_type *bus, struct iommu_group *group, unsigned int type) { @@ -1777,7 +1802,7 @@ static int probe_get_default_domain_type(struct device *dev, void *data) return 0; } -static void probe_alloc_default_domain(struct bus_type *bus, +static void probe_alloc_default_domain(const struct bus_type *bus, struct iommu_group *group) { struct __group_domain_type gtype; @@ -1832,7 +1857,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group) iommu_do_create_direct_mappings); } -int bus_iommu_probe(struct bus_type *bus) +int bus_iommu_probe(const struct bus_type *bus) { struct iommu_group *group, *next; LIST_HEAD(group_list); @@ -1876,7 +1901,7 @@ int bus_iommu_probe(struct bus_type *bus) return ret; } -bool iommu_present(struct bus_type *bus) +bool iommu_present(const struct bus_type *bus) { return bus->iommu_ops != NULL; } @@ -1951,7 +1976,7 @@ void iommu_set_fault_handler(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_set_fault_handler); -static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, +static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, unsigned type) { struct iommu_domain *domain; @@ -1964,8 +1989,13 @@ static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, return NULL; domain->type = type; - /* Assume all sizes by default; the driver may override this later */ - domain->pgsize_bitmap = bus->iommu_ops->pgsize_bitmap; + /* + * If not already set, assume all sizes by default; the driver + * may override this later + */ + if (!domain->pgsize_bitmap) + domain->pgsize_bitmap = bus->iommu_ops->pgsize_bitmap; + if (!domain->ops) domain->ops = bus->iommu_ops->default_domain_ops; @@ -1976,7 +2006,7 @@ static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, return domain; } -struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) +struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus) { return __iommu_domain_alloc(bus, IOMMU_DOMAIN_UNMANAGED); } @@ -2817,11 +2847,10 @@ int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat) EXPORT_SYMBOL_GPL(iommu_dev_disable_feature); /* - * Changes the default domain of an iommu group that has *only* one device + * Changes the default domain of an iommu group * * @group: The group for which the default domain should be changed - * @prev_dev: The device in the group (this is used to make sure that the device - * hasn't changed after the caller has called this function) + * @dev: The first device in the group * @type: The type of the new default domain that gets associated with the group * * Returns 0 on success and error code on failure @@ -2832,124 +2861,63 @@ EXPORT_SYMBOL_GPL(iommu_dev_disable_feature); * Please take a closer look if intended to use for other purposes. */ static int iommu_change_dev_def_domain(struct iommu_group *group, - struct device *prev_dev, int type) + struct device *dev, int type) { + struct __group_domain_type gtype = {NULL, 0}; struct iommu_domain *prev_dom; - struct group_device *grp_dev; - int ret, dev_def_dom; - struct device *dev; + int ret; - mutex_lock(&group->mutex); - - if (group->default_domain != group->domain) { - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); - ret = -EBUSY; - goto out; - } - - /* - * iommu group wasn't locked while acquiring device lock in - * iommu_group_store_type(). So, make sure that the device count hasn't - * changed while acquiring device lock. - * - * Changing default domain of an iommu group with two or more devices - * isn't supported because there could be a potential deadlock. Consider - * the following scenario. T1 is trying to acquire device locks of all - * the devices in the group and before it could acquire all of them, - * there could be another thread T2 (from different sub-system and use - * case) that has already acquired some of the device locks and might be - * waiting for T1 to release other device locks. - */ - if (iommu_group_device_count(group) != 1) { - dev_err_ratelimited(prev_dev, "Cannot change default domain: Group has more than one device\n"); - ret = -EINVAL; - goto out; - } - - /* Since group has only one device */ - grp_dev = list_first_entry(&group->devices, struct group_device, list); - dev = grp_dev->dev; - - if (prev_dev != dev) { - dev_err_ratelimited(prev_dev, "Cannot change default domain: Device has been changed\n"); - ret = -EBUSY; - goto out; - } + lockdep_assert_held(&group->mutex); prev_dom = group->default_domain; - if (!prev_dom) { - ret = -EINVAL; - goto out; - } - - dev_def_dom = iommu_get_def_domain_type(dev); + __iommu_group_for_each_dev(group, >ype, + probe_get_default_domain_type); if (!type) { /* * If the user hasn't requested any specific type of domain and * if the device supports both the domains, then default to the * domain the device was booted with */ - type = dev_def_dom ? : iommu_def_domain_type; - } else if (dev_def_dom && type != dev_def_dom) { - dev_err_ratelimited(prev_dev, "Device cannot be in %s domain\n", + type = gtype.type ? : iommu_def_domain_type; + } else if (gtype.type && type != gtype.type) { + dev_err_ratelimited(dev, "Device cannot be in %s domain\n", iommu_domain_type_str(type)); - ret = -EINVAL; - goto out; + return -EINVAL; } /* * Switch to a new domain only if the requested domain type is different * from the existing default domain type */ - if (prev_dom->type == type) { - ret = 0; - goto out; - } + if (prev_dom->type == type) + return 0; - /* We can bring up a flush queue without tearing down the domain */ - if (type == IOMMU_DOMAIN_DMA_FQ && prev_dom->type == IOMMU_DOMAIN_DMA) { - ret = iommu_dma_init_fq(prev_dom); - if (!ret) - prev_dom->type = IOMMU_DOMAIN_DMA_FQ; - goto out; - } + group->default_domain = NULL; + group->domain = NULL; /* Sets group->default_domain to the newly allocated domain */ ret = iommu_group_alloc_default_domain(dev->bus, group, type); if (ret) - goto out; + goto restore_old_domain; - ret = iommu_create_device_direct_mappings(group, dev); + ret = iommu_group_create_direct_mappings(group); if (ret) goto free_new_domain; - ret = __iommu_attach_device(group->default_domain, dev); + ret = __iommu_attach_group(group->default_domain, group); if (ret) goto free_new_domain; - group->domain = group->default_domain; - - /* - * Release the mutex here because ops->probe_finalize() call-back of - * some vendor IOMMU drivers calls arm_iommu_attach_device() which - * in-turn might call back into IOMMU core code, where it tries to take - * group->mutex, resulting in a deadlock. - */ - mutex_unlock(&group->mutex); - - /* Make sure dma_ops is appropriatley set */ - iommu_group_do_probe_finalize(dev, group->default_domain); iommu_domain_free(prev_dom); + return 0; free_new_domain: iommu_domain_free(group->default_domain); +restore_old_domain: group->default_domain = prev_dom; group->domain = prev_dom; -out: - mutex_unlock(&group->mutex); - return ret; } @@ -2959,7 +2927,7 @@ out: * transition. Return failure if this isn't met. * * We need to consider the race between this and the device release path. - * device_lock(dev) is used here to guarantee that the device release path + * group->mutex is used here to guarantee that the device release path * will not be entered at the same time. */ static ssize_t iommu_group_store_type(struct iommu_group *group, @@ -2986,67 +2954,42 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, else return -EINVAL; - /* - * Lock/Unlock the group mutex here before device lock to - * 1. Make sure that the iommu group has only one device (this is a - * prerequisite for step 2) - * 2. Get struct *dev which is needed to lock device - */ mutex_lock(&group->mutex); - if (iommu_group_device_count(group) != 1) { + /* We can bring up a flush queue without tearing down the domain. */ + if (req_type == IOMMU_DOMAIN_DMA_FQ && + group->default_domain->type == IOMMU_DOMAIN_DMA) { + ret = iommu_dma_init_fq(group->default_domain); + if (!ret) + group->default_domain->type = IOMMU_DOMAIN_DMA_FQ; mutex_unlock(&group->mutex); - pr_err_ratelimited("Cannot change default domain: Group has more than one device\n"); - return -EINVAL; + + return ret ?: count; + } + + /* Otherwise, ensure that device exists and no driver is bound. */ + if (list_empty(&group->devices) || group->owner_cnt) { + mutex_unlock(&group->mutex); + return -EPERM; } - /* Since group has only one device */ grp_dev = list_first_entry(&group->devices, struct group_device, list); dev = grp_dev->dev; - get_device(dev); + + ret = iommu_change_dev_def_domain(group, dev, req_type); /* - * Don't hold the group mutex because taking group mutex first and then - * the device lock could potentially cause a deadlock as below. Assume - * two threads T1 and T2. T1 is trying to change default domain of an - * iommu group and T2 is trying to hot unplug a device or release [1] VF - * of a PCIe device which is in the same iommu group. T1 takes group - * mutex and before it could take device lock assume T2 has taken device - * lock and is yet to take group mutex. Now, both the threads will be - * waiting for the other thread to release lock. Below, lock order was - * suggested. - * device_lock(dev); - * mutex_lock(&group->mutex); - * iommu_change_dev_def_domain(); - * mutex_unlock(&group->mutex); - * device_unlock(dev); - * - * [1] Typical device release path - * device_lock() from device/driver core code - * -> bus_notifier() - * -> iommu_bus_notifier() - * -> iommu_release_device() - * -> ops->release_device() vendor driver calls back iommu core code - * -> mutex_lock() from iommu core code + * Release the mutex here because ops->probe_finalize() call-back of + * some vendor IOMMU drivers calls arm_iommu_attach_device() which + * in-turn might call back into IOMMU core code, where it tries to take + * group->mutex, resulting in a deadlock. */ mutex_unlock(&group->mutex); - /* Check if the device in the group still has a driver bound to it */ - device_lock(dev); - if (device_is_bound(dev) && !(req_type == IOMMU_DOMAIN_DMA_FQ && - group->default_domain->type == IOMMU_DOMAIN_DMA)) { - pr_err_ratelimited("Device is still bound to driver\n"); - ret = -EBUSY; - goto out; - } + /* Make sure dma_ops is appropriatley set */ + if (!ret) + __iommu_group_dma_finalize(group); - ret = iommu_change_dev_def_domain(group, dev, req_type); - ret = ret ?: count; - -out: - device_unlock(dev); - put_device(dev); - - return ret; + return ret ?: count; } static bool iommu_is_default_domain(struct iommu_group *group) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index bdf1a4e5eae0..9f64c5c9f5b9 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -30,7 +30,6 @@ #define arm_iommu_create_mapping(...) NULL #define arm_iommu_attach_device(...) -ENODEV #define arm_iommu_release_mapping(...) do {} while (0) -#define arm_iommu_detach_device(...) do {} while (0) #endif #define IPMMU_CTX_MAX 16U @@ -697,7 +696,6 @@ static const struct soc_device_attribute soc_needs_opt_in[] = { static const struct soc_device_attribute soc_denylist[] = { { .soc_id = "r8a774a1", }, - { .soc_id = "r8a7795", .revision = "ES1.*" }, { .soc_id = "r8a7795", .revision = "ES2.*" }, { .soc_id = "r8a7796", }, { /* sentinel */ } @@ -820,7 +818,18 @@ static void ipmmu_probe_finalize(struct device *dev) static void ipmmu_release_device(struct device *dev) { - arm_iommu_detach_device(dev); + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); + unsigned int i; + + for (i = 0; i < fwspec->num_ids; ++i) { + unsigned int utlb = fwspec->ids[i]; + + ipmmu_imuctr_write(mmu, utlb, 0); + mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID; + } + + arm_iommu_release_mapping(mmu->mapping); } static struct iommu_group *ipmmu_find_group(struct device *dev) @@ -1014,7 +1023,7 @@ static int ipmmu_probe(struct platform_device *pdev) * the lack of has_cache_leaf_nodes flag or renesas,ipmmu-main property. */ if (!mmu->features->has_cache_leaf_nodes || - !of_find_property(pdev->dev.of_node, "renesas,ipmmu-main", NULL)) + !of_property_present(pdev->dev.of_node, "renesas,ipmmu-main")) mmu->root = mmu; else mmu->root = ipmmu_find_root(); @@ -1073,7 +1082,7 @@ static int ipmmu_probe(struct platform_device *pdev) return 0; } -static int ipmmu_remove(struct platform_device *pdev) +static void ipmmu_remove(struct platform_device *pdev) { struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev); @@ -1083,8 +1092,6 @@ static int ipmmu_remove(struct platform_device *pdev) arm_iommu_release_mapping(mmu->mapping); ipmmu_device_reset(mmu); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1131,6 +1138,6 @@ static struct platform_driver ipmmu_driver = { .pm = DEV_PM_OPS, }, .probe = ipmmu_probe, - .remove = ipmmu_remove, + .remove_new = ipmmu_remove, }; builtin_platform_driver(ipmmu_driver); diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 454f6331c889..79d89bad5132 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -811,13 +811,12 @@ static const struct of_device_id msm_iommu_dt_match[] = { {} }; -static int msm_iommu_remove(struct platform_device *pdev) +static void msm_iommu_remove(struct platform_device *pdev) { struct msm_iommu_dev *iommu = platform_get_drvdata(pdev); clk_unprepare(iommu->clk); clk_unprepare(iommu->pclk); - return 0; } static struct platform_driver msm_iommu_driver = { @@ -826,6 +825,6 @@ static struct platform_driver msm_iommu_driver = { .of_match_table = msm_iommu_dt_match, }, .probe = msm_iommu_probe, - .remove = msm_iommu_remove, + .remove_new = msm_iommu_remove, }; builtin_platform_driver(msm_iommu_driver); diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index d5a4955910ff..e93906d6e112 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -197,12 +196,42 @@ struct mtk_iommu_plat_data { char *pericfg_comp_str; struct list_head *hw_list; - unsigned int iova_region_nr; - const struct mtk_iommu_iova_region *iova_region; - u8 banks_num; - bool banks_enable[MTK_IOMMU_BANK_MAX]; - unsigned int banks_portmsk[MTK_IOMMU_BANK_MAX]; + /* + * The IOMMU HW may support 16GB iova. In order to balance the IOVA ranges, + * different masters will be put in different iova ranges, for example vcodec + * is in 4G-8G and cam is in 8G-12G. Meanwhile, some masters may have the + * special IOVA range requirement, like CCU can only support the address + * 0x40000000-0x44000000. + * Here list the iova ranges this SoC supports and which larbs/ports are in + * which region. + * + * 16GB iova all use one pgtable, but each a region is a iommu group. + */ + struct { + unsigned int iova_region_nr; + const struct mtk_iommu_iova_region *iova_region; + /* + * Indicate the correspondance between larbs, ports and regions. + * + * The index is the same as iova_region and larb port numbers are + * described as bit positions. + * For example, storing BIT(0) at index 2,1 means "larb 1, port0 is in region 2". + * [2] = { [1] = BIT(0) } + */ + const u32 (*iova_region_larb_msk)[MTK_LARB_NR_MAX]; + }; + + /* + * The IOMMU HW may have 5 banks. Each bank has a independent pgtable. + * Here list how many banks this SoC supports/enables and which ports are in which bank. + */ + struct { + u8 banks_num; + bool banks_enable[MTK_IOMMU_BANK_MAX]; + unsigned int banks_portmsk[MTK_IOMMU_BANK_MAX]; + }; + unsigned char larbid_remap[MTK_LARB_COM_MAX][MTK_LARB_SUBCOM_MAX]; }; @@ -303,16 +332,23 @@ static LIST_HEAD(m4ulist); /* List all the M4U HWs */ #define for_each_m4u(data, head) list_for_each_entry(data, head, list) +#define MTK_IOMMU_IOVA_SZ_4G (SZ_4G - SZ_8M) /* 8M as gap */ + static const struct mtk_iommu_iova_region single_domain[] = { - {.iova_base = 0, .size = SZ_4G}, + {.iova_base = 0, .size = MTK_IOMMU_IOVA_SZ_4G}, }; -static const struct mtk_iommu_iova_region mt8192_multi_dom[] = { - { .iova_base = 0x0, .size = SZ_4G}, /* 0 ~ 4G */ +#define MT8192_MULTI_REGION_NR_MAX 6 + +#define MT8192_MULTI_REGION_NR (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) ? \ + MT8192_MULTI_REGION_NR_MAX : 1) + +static const struct mtk_iommu_iova_region mt8192_multi_dom[MT8192_MULTI_REGION_NR] = { + { .iova_base = 0x0, .size = MTK_IOMMU_IOVA_SZ_4G}, /* 0 ~ 4G, */ #if IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) - { .iova_base = SZ_4G, .size = SZ_4G}, /* 4G ~ 8G */ - { .iova_base = SZ_4G * 2, .size = SZ_4G}, /* 8G ~ 12G */ - { .iova_base = SZ_4G * 3, .size = SZ_4G}, /* 12G ~ 16G */ + { .iova_base = SZ_4G, .size = MTK_IOMMU_IOVA_SZ_4G}, /* 4G ~ 8G */ + { .iova_base = SZ_4G * 2, .size = MTK_IOMMU_IOVA_SZ_4G}, /* 8G ~ 12G */ + { .iova_base = SZ_4G * 3, .size = MTK_IOMMU_IOVA_SZ_4G}, /* 12G ~ 16G */ { .iova_base = 0x240000000ULL, .size = 0x4000000}, /* CCU0 */ { .iova_base = 0x244000000ULL, .size = 0x4000000}, /* CCU1 */ @@ -508,30 +544,29 @@ static unsigned int mtk_iommu_get_bank_id(struct device *dev, static int mtk_iommu_get_iova_region_id(struct device *dev, const struct mtk_iommu_plat_data *plat_data) { - const struct mtk_iommu_iova_region *rgn = plat_data->iova_region; - const struct bus_dma_region *dma_rgn = dev->dma_range_map; - int i, candidate = -1; - dma_addr_t dma_end; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + unsigned int portidmsk = 0, larbid; + const u32 *rgn_larb_msk; + int i; - if (!dma_rgn || plat_data->iova_region_nr == 1) + if (plat_data->iova_region_nr == 1) return 0; - dma_end = dma_rgn->dma_start + dma_rgn->size - 1; - for (i = 0; i < plat_data->iova_region_nr; i++, rgn++) { - /* Best fit. */ - if (dma_rgn->dma_start == rgn->iova_base && - dma_end == rgn->iova_base + rgn->size - 1) + larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); + for (i = 0; i < fwspec->num_ids; i++) + portidmsk |= BIT(MTK_M4U_TO_PORT(fwspec->ids[i])); + + for (i = 0; i < plat_data->iova_region_nr; i++) { + rgn_larb_msk = plat_data->iova_region_larb_msk[i]; + if (!rgn_larb_msk) + continue; + + if ((rgn_larb_msk[larbid] & portidmsk) == portidmsk) return i; - /* ok if it is inside this region. */ - if (dma_rgn->dma_start >= rgn->iova_base && - dma_end < rgn->iova_base + rgn->size) - candidate = i; } - if (candidate >= 0) - return candidate; - dev_err(dev, "Can NOT find the iommu domain id(%pad 0x%llx).\n", - &dma_rgn->dma_start, dma_rgn->size); + dev_err(dev, "Can NOT find the region for larb(%d-%x).\n", + larbid, portidmsk); return -EINVAL; } @@ -703,6 +738,14 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, } mutex_unlock(&data->mutex); + if (region_id > 0) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34)); + if (ret) { + dev_err(m4udev, "Failed to set dma_mask for %s(%d).\n", dev_name(dev), ret); + return ret; + } + } + return mtk_iommu_config(data, dev, true, region_id); err_unlock: @@ -738,7 +781,8 @@ static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); - mtk_iommu_tlb_flush_all(dom->bank->parent_data); + if (dom->bank) + mtk_iommu_tlb_flush_all(dom->bank->parent_data); } static void mtk_iommu_iotlb_sync(struct iommu_domain *domain, @@ -1258,6 +1302,14 @@ static int mtk_iommu_probe(struct platform_device *pdev) return PTR_ERR(data->bclk); } + if (MTK_IOMMU_HAS_FLAG(data->plat_data, PGTABLE_PA_35_EN)) { + ret = dma_set_mask(dev, DMA_BIT_MASK(35)); + if (ret) { + dev_err(dev, "Failed to set dma_mask 35.\n"); + return ret; + } + } + pm_runtime_enable(dev); if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { @@ -1316,7 +1368,7 @@ out_runtime_disable: return ret; } -static int mtk_iommu_remove(struct platform_device *pdev) +static void mtk_iommu_remove(struct platform_device *pdev) { struct mtk_iommu_data *data = platform_get_drvdata(pdev); struct mtk_iommu_bank_data *bank; @@ -1338,7 +1390,6 @@ static int mtk_iommu_remove(struct platform_device *pdev) continue; devm_free_irq(&pdev->dev, bank->irq, bank); } - return 0; } static int __maybe_unused mtk_iommu_runtime_suspend(struct device *dev) @@ -1492,6 +1543,18 @@ static const struct mtk_iommu_plat_data mt8183_data = { .larbid_remap = {{0}, {4}, {5}, {6}, {7}, {2}, {3}, {1}}, }; +static const unsigned int mt8186_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK_LARB_NR_MAX] = { + [0] = {~0, ~0, ~0}, /* Region0: all ports for larb0/1/2 */ + [1] = {0, 0, 0, 0, ~0, 0, 0, ~0}, /* Region1: larb4/7 */ + [2] = {0, 0, 0, 0, 0, 0, 0, 0, /* Region2: larb8/9/11/13/16/17/19/20 */ + ~0, ~0, 0, ~0, 0, ~(u32)(BIT(9) | BIT(10)), 0, 0, + /* larb13: the other ports except port9/10 */ + ~0, ~0, 0, ~0, ~0}, + [3] = {0}, + [4] = {[13] = BIT(9) | BIT(10)}, /* larb13 port9/10 */ + [5] = {[14] = ~0}, /* larb14 */ +}; + static const struct mtk_iommu_plat_data mt8186_data_mm = { .m4u_plat = M4U_MT8186, .flags = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN | @@ -1504,6 +1567,18 @@ static const struct mtk_iommu_plat_data mt8186_data_mm = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8186_larb_region_msk, +}; + +static const unsigned int mt8192_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK_LARB_NR_MAX] = { + [0] = {~0, ~0}, /* Region0: larb0/1 */ + [1] = {0, 0, 0, 0, ~0, ~0, 0, ~0}, /* Region1: larb4/5/7 */ + [2] = {0, 0, ~0, 0, 0, 0, 0, 0, /* Region2: larb2/9/11/13/14/16/17/18/19/20 */ + 0, ~0, 0, ~0, 0, ~(u32)(BIT(9) | BIT(10)), ~(u32)(BIT(4) | BIT(5)), 0, + ~0, ~0, ~0, ~0, ~0}, + [3] = {0}, + [4] = {[13] = BIT(9) | BIT(10)}, /* larb13 port9/10 */ + [5] = {[14] = BIT(4) | BIT(5)}, /* larb14 port4/5 */ }; static const struct mtk_iommu_plat_data mt8192_data = { @@ -1515,6 +1590,7 @@ static const struct mtk_iommu_plat_data mt8192_data = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8192_larb_region_msk, .larbid_remap = {{0}, {1}, {4, 5}, {7}, {2}, {9, 11, 19, 20}, {0, 14, 16}, {0, 13, 18, 17}}, }; @@ -1534,6 +1610,21 @@ static const struct mtk_iommu_plat_data mt8195_data_infra = { .iova_region_nr = ARRAY_SIZE(single_domain), }; +static const unsigned int mt8195_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK_LARB_NR_MAX] = { + [0] = {~0, ~0, ~0, ~0}, /* Region0: all ports for larb0/1/2/3 */ + [1] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, ~0, ~0, ~0, ~0, ~0, /* Region1: larb19/20/21/22/23/24 */ + ~0}, + [2] = {0, 0, 0, 0, ~0, ~0, ~0, ~0, /* Region2: the other larbs. */ + ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + ~0, ~0, 0, 0, 0, 0, 0, 0, + 0, ~0, ~0, ~0, ~0}, + [3] = {0}, + [4] = {[18] = BIT(0) | BIT(1)}, /* Only larb18 port0/1 */ + [5] = {[18] = BIT(2) | BIT(3)}, /* Only larb18 port2/3 */ +}; + static const struct mtk_iommu_plat_data mt8195_data_vdo = { .m4u_plat = M4U_MT8195, .flags = HAS_BCLK | HAS_SUB_COMM_2BITS | OUT_ORDER_WR_EN | @@ -1544,6 +1635,7 @@ static const struct mtk_iommu_plat_data mt8195_data_vdo = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8195_larb_region_msk, .larbid_remap = {{2, 0}, {21}, {24}, {7}, {19}, {9, 10, 11}, {13, 17, 15/* 17b */, 25}, {5}}, }; @@ -1558,6 +1650,7 @@ static const struct mtk_iommu_plat_data mt8195_data_vpp = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8195_larb_region_msk, .larbid_remap = {{1}, {3}, {22, MTK_INVALID_LARBID, MTK_INVALID_LARBID, MTK_INVALID_LARBID, 23}, {8}, {20}, {12}, @@ -1595,7 +1688,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = { static struct platform_driver mtk_iommu_driver = { .probe = mtk_iommu_probe, - .remove = mtk_iommu_remove, + .remove_new = mtk_iommu_remove, .driver = { .name = "mtk-iommu", .of_match_table = mtk_iommu_of_ids, diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 43e4c8f89e23..8a0a5e5d049f 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -703,7 +703,7 @@ out_clk_unprepare: return ret; } -static int mtk_iommu_v1_remove(struct platform_device *pdev) +static void mtk_iommu_v1_remove(struct platform_device *pdev) { struct mtk_iommu_v1_data *data = platform_get_drvdata(pdev); @@ -713,7 +713,6 @@ static int mtk_iommu_v1_remove(struct platform_device *pdev) clk_disable_unprepare(data->bclk); devm_free_irq(&pdev->dev, data->irq, data); component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops); - return 0; } static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev) @@ -752,7 +751,7 @@ static const struct dev_pm_ops mtk_iommu_v1_pm_ops = { static struct platform_driver mtk_iommu_v1_driver = { .probe = mtk_iommu_v1_probe, - .remove = mtk_iommu_v1_remove, + .remove_new = mtk_iommu_v1_remove, .driver = { .name = "mtk-iommu-v1", .of_match_table = mtk_iommu_v1_of_ids, diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 3ab078112a7c..537e402f9bba 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1191,7 +1191,7 @@ static int omap_iommu_probe(struct platform_device *pdev) return err; if (obj->nr_tlb_entries != 32 && obj->nr_tlb_entries != 8) return -EINVAL; - if (of_find_property(of, "ti,iommu-bus-err-back", NULL)) + if (of_property_read_bool(of, "ti,iommu-bus-err-back")) obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN; obj->dev = &pdev->dev; @@ -1257,7 +1257,7 @@ out_group: return err; } -static int omap_iommu_remove(struct platform_device *pdev) +static void omap_iommu_remove(struct platform_device *pdev) { struct omap_iommu *obj = platform_get_drvdata(pdev); @@ -1274,7 +1274,6 @@ static int omap_iommu_remove(struct platform_device *pdev) pm_runtime_disable(obj->dev); dev_info(&pdev->dev, "%s removed\n", obj->name); - return 0; } static const struct dev_pm_ops omap_iommu_pm_ops = { @@ -1295,7 +1294,7 @@ static const struct of_device_id omap_iommu_of_match[] = { static struct platform_driver omap_iommu_driver = { .probe = omap_iommu_probe, - .remove = omap_iommu_remove, + .remove_new = omap_iommu_remove, .driver = { .name = "omap-iommu", .pm = &omap_iommu_pm_ops, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index f30db22ea5d7..4054030c3237 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -124,6 +124,7 @@ struct rk_iommudata { static struct device *dma_dev; static const struct rk_iommu_ops *rk_ops; +static struct iommu_domain rk_identity_domain; static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma, unsigned int count) @@ -646,7 +647,7 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id) * Ignore the return code, though, since we always zap cache * and clear the page fault anyway. */ - if (iommu->domain) + if (iommu->domain != &rk_identity_domain) report_iommu_fault(iommu->domain, iommu->dev, iova, flags); else @@ -980,26 +981,27 @@ out_disable_clocks: return ret; } -static void rk_iommu_detach_device(struct iommu_domain *domain, - struct device *dev) +static int rk_iommu_identity_attach(struct iommu_domain *identity_domain, + struct device *dev) { struct rk_iommu *iommu; - struct rk_iommu_domain *rk_domain = to_rk_domain(domain); + struct rk_iommu_domain *rk_domain; unsigned long flags; int ret; /* Allow 'virtual devices' (eg drm) to detach from domain */ iommu = rk_iommu_from_dev(dev); if (!iommu) - return; + return -ENODEV; + + rk_domain = to_rk_domain(iommu->domain); dev_dbg(dev, "Detaching from iommu domain\n"); - /* iommu already detached */ - if (iommu->domain != domain) - return; + if (iommu->domain == identity_domain) + return 0; - iommu->domain = NULL; + iommu->domain = identity_domain; spin_lock_irqsave(&rk_domain->iommus_lock, flags); list_del_init(&iommu->node); @@ -1011,8 +1013,31 @@ static void rk_iommu_detach_device(struct iommu_domain *domain, rk_iommu_disable(iommu); pm_runtime_put(iommu->dev); } + + return 0; } +static void rk_iommu_identity_free(struct iommu_domain *domain) +{ +} + +static struct iommu_domain_ops rk_identity_ops = { + .attach_dev = rk_iommu_identity_attach, + .free = rk_iommu_identity_free, +}; + +static struct iommu_domain rk_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &rk_identity_ops, +}; + +#ifdef CONFIG_ARM +static void rk_iommu_set_platform_dma(struct device *dev) +{ + WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev)); +} +#endif + static int rk_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { @@ -1035,8 +1060,9 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, if (iommu->domain == domain) return 0; - if (iommu->domain) - rk_iommu_detach_device(iommu->domain, dev); + ret = rk_iommu_identity_attach(&rk_identity_domain, dev); + if (ret) + return ret; iommu->domain = domain; @@ -1050,7 +1076,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain, ret = rk_iommu_enable(iommu); if (ret) - rk_iommu_detach_device(iommu->domain, dev); + WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev)); pm_runtime_put(iommu->dev); @@ -1061,6 +1087,9 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) { struct rk_iommu_domain *rk_domain; + if (type == IOMMU_DOMAIN_IDENTITY) + return &rk_identity_domain; + if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) return NULL; @@ -1176,6 +1205,7 @@ static int rk_iommu_of_xlate(struct device *dev, iommu_dev = of_find_device_by_node(args->np); data->iommu = platform_get_drvdata(iommu_dev); + data->iommu->domain = &rk_identity_domain; dev_iommu_priv_set(dev, data); platform_device_put(iommu_dev); @@ -1188,6 +1218,9 @@ static const struct iommu_ops rk_iommu_ops = { .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device, .device_group = rk_iommu_device_group, +#ifdef CONFIG_ARM + .set_platform_dma_ops = rk_iommu_set_platform_dma, +#endif .pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP, .of_xlate = rk_iommu_of_xlate, .default_domain_ops = &(const struct iommu_domain_ops) { @@ -1302,20 +1335,22 @@ static int rk_iommu_probe(struct platform_device *pdev) for (i = 0; i < iommu->num_irq; i++) { int irq = platform_get_irq(pdev, i); - if (irq < 0) - return irq; + if (irq < 0) { + err = irq; + goto err_pm_disable; + } err = devm_request_irq(iommu->dev, irq, rk_iommu_irq, IRQF_SHARED, dev_name(dev), iommu); - if (err) { - pm_runtime_disable(dev); - goto err_remove_sysfs; - } + if (err) + goto err_pm_disable; } dma_set_mask_and_coherent(dev, rk_ops->dma_bit_mask); return 0; +err_pm_disable: + pm_runtime_disable(dev); err_remove_sysfs: iommu_device_sysfs_remove(&iommu->iommu); err_put_group: @@ -1343,7 +1378,7 @@ static int __maybe_unused rk_iommu_suspend(struct device *dev) { struct rk_iommu *iommu = dev_get_drvdata(dev); - if (!iommu->domain) + if (iommu->domain == &rk_identity_domain) return 0; rk_iommu_disable(iommu); @@ -1354,7 +1389,7 @@ static int __maybe_unused rk_iommu_resume(struct device *dev) { struct rk_iommu *iommu = dev_get_drvdata(dev); - if (!iommu->domain) + if (iommu->domain == &rk_identity_domain) return 0; return rk_iommu_enable(iommu); diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index ae94d74b73f4..39e34fdeccda 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -62,6 +62,7 @@ enum sprd_iommu_version { * @eb: gate clock which controls IOMMU access */ struct sprd_iommu_device { + struct sprd_iommu_domain *dom; enum sprd_iommu_version ver; u32 *prot_page_va; dma_addr_t prot_page_pa; @@ -151,13 +152,6 @@ static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type) return &dom->domain; } -static void sprd_iommu_domain_free(struct iommu_domain *domain) -{ - struct sprd_iommu_domain *dom = to_sprd_domain(domain); - - kfree(dom); -} - static void sprd_iommu_first_vpn(struct sprd_iommu_domain *dom) { struct sprd_iommu_device *sdev = dom->sdev; @@ -230,6 +224,28 @@ static void sprd_iommu_hw_en(struct sprd_iommu_device *sdev, bool en) sprd_iommu_update_bits(sdev, reg_cfg, mask, 0, val); } +static void sprd_iommu_cleanup(struct sprd_iommu_domain *dom) +{ + size_t pgt_size; + + /* Nothing need to do if the domain hasn't been attached */ + if (!dom->sdev) + return; + + pgt_size = sprd_iommu_pgt_size(&dom->domain); + dma_free_coherent(dom->sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa); + dom->sdev = NULL; + sprd_iommu_hw_en(dom->sdev, false); +} + +static void sprd_iommu_domain_free(struct iommu_domain *domain) +{ + struct sprd_iommu_domain *dom = to_sprd_domain(domain); + + sprd_iommu_cleanup(dom); + kfree(dom); +} + static int sprd_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { @@ -237,15 +253,27 @@ static int sprd_iommu_attach_device(struct iommu_domain *domain, struct sprd_iommu_domain *dom = to_sprd_domain(domain); size_t pgt_size = sprd_iommu_pgt_size(domain); - if (dom->sdev) - return -EINVAL; + /* The device is attached to this domain */ + if (sdev->dom == dom) + return 0; - dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, GFP_KERNEL); - if (!dom->pgt_va) - return -ENOMEM; + /* The first time that domain is attaching to a device */ + if (!dom->pgt_va) { + dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, GFP_KERNEL); + if (!dom->pgt_va) + return -ENOMEM; - dom->sdev = sdev; + dom->sdev = sdev; + } + sdev->dom = dom; + + /* + * One sprd IOMMU serves one client device only, disabled it before + * configure mapping table to avoid access conflict in case other + * mapping table is stored in. + */ + sprd_iommu_hw_en(sdev, false); sprd_iommu_first_ppn(dom); sprd_iommu_first_vpn(dom); sprd_iommu_vpn_range(dom); @@ -507,7 +535,7 @@ free_page: return ret; } -static int sprd_iommu_remove(struct platform_device *pdev) +static void sprd_iommu_remove(struct platform_device *pdev) { struct sprd_iommu_device *sdev = platform_get_drvdata(pdev); @@ -519,8 +547,6 @@ static int sprd_iommu_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); iommu_device_sysfs_remove(&sdev->iommu); iommu_device_unregister(&sdev->iommu); - - return 0; } static struct platform_driver sprd_iommu_driver = { @@ -530,7 +556,7 @@ static struct platform_driver sprd_iommu_driver = { .suppress_bind_attrs = true, }, .probe = sprd_iommu_probe, - .remove = sprd_iommu_remove, + .remove_new = sprd_iommu_remove, }; module_platform_driver(sprd_iommu_driver); diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c index 2d993d0cea7d..74c5cb93e900 100644 --- a/drivers/iommu/sun50i-iommu.c +++ b/drivers/iommu/sun50i-iommu.c @@ -1076,4 +1076,3 @@ builtin_platform_driver_probe(sun50i_iommu_driver, sun50i_iommu_probe); MODULE_DESCRIPTION("Allwinner H6 IOMMU driver"); MODULE_AUTHOR("Maxime Ripard "); MODULE_AUTHOR("zhuxianbin "); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c index 886de028a901..dfb761e86c9c 100644 --- a/drivers/irqchip/irq-al-fic.c +++ b/drivers/irqchip/irq-al-fic.c @@ -26,7 +26,6 @@ MODULE_AUTHOR("Talel Shenhar"); MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver"); -MODULE_LICENSE("GPL v2"); enum al_fic_state { AL_FIC_UNCONFIGURED = 0, diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index a610821c8ff2..afd6a1841715 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -16,7 +16,13 @@ void gic_enable_of_quirks(const struct device_node *np, const struct gic_quirk *quirks, void *data) { for (; quirks->desc; quirks++) { - if (!of_device_is_compatible(np, quirks->compatible)) + if (!quirks->compatible && !quirks->property) + continue; + if (quirks->compatible && + !of_device_is_compatible(np, quirks->compatible)) + continue; + if (quirks->property && + !of_property_read_bool(np, quirks->property)) continue; if (quirks->init(data)) pr_info("GIC: enabling workaround for %s\n", @@ -28,7 +34,7 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data) { for (; quirks->desc; quirks++) { - if (quirks->compatible) + if (quirks->compatible || quirks->property) continue; if (quirks->iidr != (quirks->mask & iidr)) continue; diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index 27e3d4ed4f32..3db4592cda1c 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -13,6 +13,7 @@ struct gic_quirk { const char *desc; const char *compatible; + const char *property; bool (*init)(void *data); u32 iidr; u32 mask; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index fa4641a5dfd8..0ec2b1e1df75 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2445,8 +2445,8 @@ static bool its_parse_indirect_baser(struct its_node *its, * feature is not supported by hardware. */ new_order = max_t(u32, get_order(esz << ids), new_order); - if (new_order >= MAX_ORDER) { - new_order = MAX_ORDER - 1; + if (new_order > MAX_ORDER) { + new_order = MAX_ORDER; ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); pr_warn("ITS@%pa: %s Table too large, reduce ids %llu->%u\n", &its->phys_base, its_base_type_string[type], diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 6fcee221f201..a605aa79435a 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -39,6 +39,7 @@ #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) +#define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) @@ -1720,6 +1721,15 @@ static bool gic_enable_quirk_msm8996(void *data) return true; } +static bool gic_enable_quirk_mtk_gicr(void *data) +{ + struct gic_chip_data *d = data; + + d->flags |= FLAGS_WORKAROUND_MTK_GICR_SAVE; + + return true; +} + static bool gic_enable_quirk_cavium_38539(void *data) { struct gic_chip_data *d = data; @@ -1792,6 +1802,11 @@ static const struct gic_quirk gic_quirks[] = { .compatible = "qcom,msm8996-gic-v3", .init = gic_enable_quirk_msm8996, }, + { + .desc = "GICv3: Mediatek Chromebook GICR save problem", + .property = "mediatek,broken-save-restore-fw", + .init = gic_enable_quirk_mtk_gicr, + }, { .desc = "GICv3: HIP06 erratum 161010803", .iidr = 0x0204043b, @@ -1834,6 +1849,11 @@ static void gic_enable_nmi_support(void) if (!gic_prio_masking_enabled()) return; + if (gic_data.flags & FLAGS_WORKAROUND_MTK_GICR_SAVE) { + pr_warn("Skipping NMI enable due to firmware issues\n"); + return; + } + ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL); if (!ppi_nmi_refs) return; diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 527c90e0920e..f5ba3f9f8415 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -430,4 +430,3 @@ module_platform_driver(ls_scfg_msi_driver); MODULE_AUTHOR("Minghuan Lian "); MODULE_DESCRIPTION("Freescale Layerscape SCFG MSI controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index f3faf5c99770..5101a3fb11df 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -240,23 +240,27 @@ static int mbigen_of_create_domain(struct platform_device *pdev, struct irq_domain *domain; struct device_node *np; u32 num_pins; + int ret = 0; + + parent = bus_get_dev_root(&platform_bus_type); + if (!parent) + return -ENODEV; for_each_child_of_node(pdev->dev.of_node, np) { if (!of_property_read_bool(np, "interrupt-controller")) continue; - parent = platform_bus_type.dev_root; child = of_platform_device_create(np, NULL, parent); if (!child) { - of_node_put(np); - return -ENOMEM; + ret = -ENOMEM; + break; } if (of_property_read_u32(child->dev.of_node, "num-pins", &num_pins) < 0) { dev_err(&pdev->dev, "No num-pins property\n"); - of_node_put(np); - return -EINVAL; + ret = -EINVAL; + break; } domain = platform_msi_create_device_domain(&child->dev, num_pins, @@ -264,12 +268,16 @@ static int mbigen_of_create_domain(struct platform_device *pdev, &mbigen_domain_ops, mgn_chip); if (!domain) { - of_node_put(np); - return -ENOMEM; + ret = -ENOMEM; + break; } } - return 0; + put_device(parent); + if (ret) + of_node_put(np); + + return ret; } #ifdef CONFIG_ACPI @@ -389,5 +397,4 @@ module_platform_driver(mbigen_platform_driver); MODULE_AUTHOR("Jun Ma "); MODULE_AUTHOR("Yun Wu "); -MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("HiSilicon MBI Generator driver"); diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index c726a19837d2..5dcd94c000a2 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -276,5 +276,4 @@ IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_init) IRQCHIP_PLATFORM_DRIVER_END(mchp_eic) MODULE_DESCRIPTION("Microchip External Interrupt Controller"); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Claudiu Beznea "); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 2aaa9aad3e87..7da18ef95211 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -150,7 +150,7 @@ static const struct meson_gpio_irq_params s4_params = { INIT_MESON_S4_COMMON_DATA(82) }; -static const struct of_device_id meson_irq_gpio_matches[] = { +static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = { { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 1a6a7a672ad7..6d5ecc10a870 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -50,11 +50,10 @@ void __iomem *mips_gic_base; static DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks); -static DEFINE_SPINLOCK(gic_lock); +static DEFINE_RAW_SPINLOCK(gic_lock); static struct irq_domain *gic_irq_domain; static int gic_shared_intrs; static unsigned int gic_cpu_pin; -static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; #ifdef CONFIG_GENERIC_IRQ_IPI @@ -211,7 +210,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) irq = GIC_HWIRQ_TO_SHARED(d->hwirq); - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_FALLING: pol = GIC_POL_FALLING_EDGE; @@ -251,7 +250,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) else irq_set_chip_handler_name_locked(d, &gic_level_irq_controller, handle_level_irq, NULL); - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); return 0; } @@ -269,7 +268,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, return -EINVAL; /* Assumption : cpumask refers to a single CPU */ - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); /* Re-route this IRQ */ write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu))); @@ -280,7 +279,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); irq_data_update_effective_affinity(d, cpumask_of(cpu)); - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); return IRQ_SET_MASK_OK; } @@ -358,12 +357,12 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) cd = irq_data_get_irq_chip_data(d); cd->mask = false; - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); write_gic_vo_rmask(BIT(intr)); } - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); } static void gic_unmask_local_irq_all_vpes(struct irq_data *d) @@ -376,12 +375,12 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) cd = irq_data_get_irq_chip_data(d); cd->mask = true; - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); write_gic_vo_smask(BIT(intr)); } - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); } static void gic_all_vpes_irq_cpu_online(void) @@ -394,19 +393,21 @@ static void gic_all_vpes_irq_cpu_online(void) unsigned long flags; int i; - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < ARRAY_SIZE(local_intrs); i++) { unsigned int intr = local_intrs[i]; struct gic_all_vpes_chip_data *cd; + if (!gic_local_irq_is_routable(intr)) + continue; cd = &gic_all_vpes_chip_data[intr]; write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map); if (cd->mask) write_gic_vl_smask(BIT(intr)); } - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); } static struct irq_chip gic_all_vpes_local_irq_controller = { @@ -436,11 +437,11 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, data = irq_get_irq_data(virq); - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); irq_data_update_effective_affinity(data, cpumask_of(cpu)); - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); return 0; } @@ -499,9 +500,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, */ switch (intr) { case GIC_LOCAL_INT_TIMER: - /* CONFIG_MIPS_CMP workaround (see __gic_init) */ - map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin; - fallthrough; case GIC_LOCAL_INT_PERFCTR: case GIC_LOCAL_INT_FDC: /* @@ -535,12 +533,12 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, if (!gic_local_irq_is_routable(intr)) return -EPERM; - spin_lock_irqsave(&gic_lock, flags); + raw_spin_lock_irqsave(&gic_lock, flags); for_each_online_cpu(cpu) { write_gic_vl_other(mips_cm_vp_id(cpu)); write_gic_vo_map(mips_gic_vx_map_reg(intr), map); } - spin_unlock_irqrestore(&gic_lock, flags); + raw_spin_unlock_irqrestore(&gic_lock, flags); return 0; } @@ -795,34 +793,12 @@ static int __init gic_of_init(struct device_node *node, if (cpu_has_veic) { /* Always use vector 1 in EIC mode */ gic_cpu_pin = 0; - timer_cpu_pin = gic_cpu_pin; set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, __gic_irq_dispatch); } else { gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, gic_irq_dispatch); - /* - * With the CMP implementation of SMP (deprecated), other CPUs - * are started by the bootloader and put into a timer based - * waiting poll loop. We must not re-route those CPU's local - * timer interrupts as the wait instruction will never finish, - * so just handle whatever CPU interrupt it is routed to by - * default. - * - * This workaround should be removed when CMP support is - * dropped. - */ - if (IS_ENABLED(CONFIG_MIPS_CMP) && - gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { - timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP; - irq_set_chained_handler(MIPS_CPU_IRQ_BASE + - GIC_CPU_PIN_OFFSET + - timer_cpu_pin, - gic_irq_dispatch); - } else { - timer_cpu_pin = gic_cpu_pin; - } } gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index e83756aca14e..26e4c17a7bf2 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -608,4 +608,3 @@ module_exit(intc_irqpin_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 1ee5e9941f67..49b446b396f9 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -270,4 +270,3 @@ module_exit(irqc_exit); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("Renesas IRQC Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c index 72c06e883d1c..e4c99c2e0373 100644 --- a/drivers/irqchip/irq-renesas-rza1.c +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -281,4 +281,3 @@ module_exit(rza1_irqc_exit); MODULE_AUTHOR("Geert Uytterhoeven "); MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 25fd8ee66565..4bbfa2b0a4df 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -390,4 +390,3 @@ IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init) IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc) MODULE_AUTHOR("Lad Prabhakar "); MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c index f2172240172c..e50f9eaba4cd 100644 --- a/drivers/irqchip/irq-sl28cpld.c +++ b/drivers/irqchip/irq-sl28cpld.c @@ -92,4 +92,3 @@ module_platform_driver(sl28cpld_intc_driver); MODULE_DESCRIPTION("sl28cpld Interrupt Controller Driver"); MODULE_AUTHOR("Michael Walle "); -MODULE_LICENSE("GPL"); diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index a6ecc53d055c..7133f9fa6fd9 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -743,4 +743,3 @@ module_platform_driver(ti_sci_inta_irq_domain_driver); MODULE_AUTHOR("Lokesh Vutla "); MODULE_DESCRIPTION("K3 Interrupt Aggregator driver over TI SCI protocol"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c index 020ddf29efb8..1186f1e431a3 100644 --- a/drivers/irqchip/irq-ti-sci-intr.c +++ b/drivers/irqchip/irq-ti-sci-intr.c @@ -303,4 +303,3 @@ module_platform_driver(ti_sci_intr_irq_domain_driver); MODULE_AUTHOR("Lokesh Vutla "); MODULE_DESCRIPTION("K3 Interrupt Router driver over TI SCI protocol"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 0f00be62438d..45a4043c5042 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1393,7 +1393,7 @@ static int __init capi_init(void) kcapi_exit(); return major_ret; } - capi_class = class_create(THIS_MODULE, "capi"); + capi_class = class_create("capi"); if (IS_ERR(capi_class)) { unregister_chrdev(capi_major, "capi20"); kcapi_exit(); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 9120be590325..ab8513a7acd5 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -152,18 +152,11 @@ static int mISDN_uevent(const struct device *dev, struct kobj_uevent_env *env) return 0; } -static void mISDN_class_release(struct class *cls) -{ - /* do nothing, it's static */ -} - static struct class mISDN_class = { .name = "mISDN", - .owner = THIS_MODULE, .dev_uevent = mISDN_uevent, .dev_groups = mISDN_groups, .dev_release = mISDN_dev_release, - .class_release = mISDN_class_release, }; static int diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 6d2088fbaf69..357b87592eb4 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -141,17 +141,6 @@ /*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */ /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ -static inline int -count_list_member(struct list_head *head) -{ - int cnt = 0; - struct list_head *m; - - list_for_each(m, head) - cnt++; - return cnt; -} - /* * debug cmx memory structure */ @@ -1672,7 +1661,7 @@ dsp_cmx_send(void *arg) mustmix = 0; members = 0; if (conf) { - members = count_list_member(&conf->mlist); + members = list_count_nodes(&conf->mlist); #ifdef CMX_CONF_DEBUG if (conf->software && members > 1) #else @@ -1695,7 +1684,7 @@ dsp_cmx_send(void *arg) /* loop all members that require conference mixing */ list_for_each_entry(conf, &conf_ilist, list) { /* count members and check hardware */ - members = count_list_member(&conf->mlist); + members = list_count_nodes(&conf->mlist); #ifdef CMX_CONF_DEBUG if (conf->software && members > 1) { #else diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index cfbcd9e973c2..09b72f14d4b7 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -131,7 +131,7 @@ EXPORT_SYMBOL(mISDN_dsp_element_unregister); int dsp_pipeline_module_init(void) { - elements_class = class_create(THIS_MODULE, "dsp_pipeline"); + elements_class = class_create("dsp_pipeline"); if (IS_ERR(elements_class)) return PTR_ERR(elements_class); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9dbce09eabac..2c5fdf848210 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -551,6 +551,20 @@ config LEDS_REGULATOR help This option enables support for regulator driven LEDs. +config LEDS_BD2606MVV + tristate "LED driver for BD2606MVV" + depends on LEDS_CLASS + depends on I2C + select REGMAP_I2C + help + This option enables support for BD2606MVV LED driver chips + accessed via the I2C bus. It supports setting brightness, with + the limitiation that there are groups of two channels sharing + a brightness setting, but not the on/off setting. + + To compile this driver as a module, choose M here: the module will + be called leds-bd2606mvv. + config LEDS_BD2802 tristate "LED driver for BD2802 RGB LED" depends on LEDS_CLASS @@ -795,7 +809,7 @@ config LEDS_SPI_BYTE config LEDS_TI_LMU_COMMON tristate "LED driver for TI LMU" depends on LEDS_CLASS - depends on REGMAP + select REGMAP help Say Y to enable the LED driver for TI LMU devices. This supports common features between the TI LM3532, LM3631, LM3632, diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index d30395d11fd8..c07d1512c745 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o obj-$(CONFIG_LEDS_AW2013) += leds-aw2013.o obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o +obj-$(CONFIG_LEDS_BD2606MVV) += leds-bd2606mvv.o obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index d3eb689b193c..4ed2efc65434 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -61,6 +61,34 @@ config LEDS_MT6360 Independent current sources supply for each flash LED support torch and strobe mode. +config LEDS_MT6370_FLASH + tristate "Flash LED Support for MediaTek MT6370 PMIC" + depends on LEDS_CLASS + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS + depends on MFD_MT6370 + help + Support 2 channels and torch/strobe mode. + Say Y here to enable support for + MT6370_FLASH_LED device. + + This driver can also be built as a module. If so, the module + will be called "leds-mt6370-flash". + +config LEDS_QCOM_FLASH + tristate "LED support for flash module inside Qualcomm Technologies, Inc. PMIC" + depends on MFD_SPMI_PMIC || COMPILE_TEST + depends on LEDS_CLASS && OF + depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS + select REGMAP + help + This option enables support for the flash module found in Qualcomm + Technologies, Inc. PMICs. The flash module can have 3 or 4 flash LED + channels and each channel is programmable to support up to 1.5 A full + scale current. It also supports connecting two channels' output together + to supply one LED component to achieve current up to 2 A. In such case, + the total LED current will be split symmetrically on each channel and + they will be enabled/disabled at the same time. + config LEDS_RT4505 tristate "LED support for RT4505 flashlight controller" depends on I2C && OF diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile index 0acbddc0b91b..91d60a4b7952 100644 --- a/drivers/leds/flash/Makefile +++ b/drivers/leds/flash/Makefile @@ -1,11 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_LEDS_MT6360) += leds-mt6360.o +obj-$(CONFIG_LEDS_MT6370_FLASH) += leds-mt6370-flash.o obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o +obj-$(CONFIG_LEDS_QCOM_FLASH) += leds-qcom-flash.o obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c new file mode 100644 index 000000000000..931067c8a75f --- /dev/null +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Richtek Technology Corp. + * + * Authors: + * Alice Chen + * ChiYuan Huang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum { + MT6370_LED_FLASH1 = 0, + MT6370_LED_FLASH2, + MT6370_MAX_LEDS +}; + +/* Virtual definition for multicolor */ + +#define MT6370_REG_FLEDEN 0x17E +#define MT6370_REG_STRBTO 0x173 +#define MT6370_REG_CHGSTAT2 0x1D1 +#define MT6370_REG_FLEDSTAT1 0x1D9 +#define MT6370_REG_FLEDISTRB(_id) (0x174 + 4 * (_id)) +#define MT6370_REG_FLEDITOR(_id) (0x175 + 4 * (_id)) +#define MT6370_ITORCH_MASK GENMASK(4, 0) +#define MT6370_ISTROBE_MASK GENMASK(6, 0) +#define MT6370_STRBTO_MASK GENMASK(6, 0) +#define MT6370_TORCHEN_MASK BIT(3) +#define MT6370_STROBEN_MASK BIT(2) +#define MT6370_FLCSEN_MASK(_id) BIT(MT6370_LED_FLASH2 - (_id)) +#define MT6370_FLCSEN_MASK_ALL GENMASK(1, 0) +#define MT6370_FLEDCHGVINOVP_MASK BIT(3) +#define MT6370_FLED1STRBTO_MASK BIT(11) +#define MT6370_FLED2STRBTO_MASK BIT(10) +#define MT6370_FLED1STRB_MASK BIT(9) +#define MT6370_FLED2STRB_MASK BIT(8) +#define MT6370_FLED1SHORT_MASK BIT(7) +#define MT6370_FLED2SHORT_MASK BIT(6) +#define MT6370_FLEDLVF_MASK BIT(3) + +#define MT6370_LED_JOINT 2 +#define MT6370_RANGE_FLED_REG 4 +#define MT6370_ITORCH_MIN_uA 25000 +#define MT6370_ITORCH_STEP_uA 12500 +#define MT6370_ITORCH_MAX_uA 400000 +#define MT6370_ITORCH_DOUBLE_MAX_uA 800000 +#define MT6370_ISTRB_MIN_uA 50000 +#define MT6370_ISTRB_STEP_uA 12500 +#define MT6370_ISTRB_MAX_uA 1500000 +#define MT6370_ISTRB_DOUBLE_MAX_uA 3000000 +#define MT6370_STRBTO_MIN_US 64000 +#define MT6370_STRBTO_STEP_US 32000 +#define MT6370_STRBTO_MAX_US 2432000 + +#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member) + +struct mt6370_led { + struct led_classdev_flash flash; + struct v4l2_flash *v4l2_flash; + struct mt6370_priv *priv; + u8 led_no; +}; + +struct mt6370_priv { + struct regmap *regmap; + struct mutex lock; + unsigned int fled_strobe_used; + unsigned int fled_torch_used; + unsigned int leds_active; + unsigned int leds_count; + struct mt6370_led leds[]; +}; + +static int mt6370_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness level) +{ + struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev); + struct mt6370_priv *priv = led->priv; + u32 led_enable_mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask; + u32 val = level ? led_enable_mask : 0; + u32 curr; + int ret, i; + + mutex_lock(&priv->lock); + + /* + * There is only one set of flash control logic, and this flag is used to check if 'strobe' + * is currently being used. + */ + if (priv->fled_strobe_used) { + dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", priv->fled_strobe_used); + ret = -EBUSY; + goto unlock; + } + + if (level) + curr = priv->fled_torch_used | BIT(led->led_no); + else + curr = priv->fled_torch_used & ~BIT(led->led_no); + + if (curr) + val |= MT6370_TORCHEN_MASK; + + if (level) { + level -= 1; + if (led->led_no == MT6370_LED_JOINT) { + u32 flevel[MT6370_MAX_LEDS]; + + /* + * There're two flash channels in MT6370. If joint flash output is used, + * torch current will be averaged output from both channels. + */ + flevel[0] = level / 2; + flevel[1] = level - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDITOR(i), + MT6370_ITORCH_MASK, flevel[i]); + if (ret) + goto unlock; + } + } else { + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDITOR(led->led_no), + MT6370_ITORCH_MASK, level); + if (ret) + goto unlock; + } + } + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, val); + if (ret) + goto unlock; + + priv->fled_torch_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness) +{ + /* + * Because of the current spikes when turning on the flash, the brightness should be kept + * by the LED framework. This empty function is used to prevent checking failure when + * led_classdev_flash registers ops. + */ + return 0; +} + +static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *setting = &fl_cdev->brightness; + u32 val = (brightness - setting->min) / setting->step; + int ret, i; + + if (led->led_no == MT6370_LED_JOINT) { + u32 flevel[MT6370_MAX_LEDS]; + + /* + * There're two flash channels in MT6370. If joint flash output is used, storbe + * current will be averaged output from both channels. + */ + flevel[0] = val / 2; + flevel[1] = val - flevel[0]; + for (i = 0; i < MT6370_MAX_LEDS; i++) { + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDISTRB(i), + MT6370_ISTROBE_MASK, flevel[i]); + if (ret) + break; + } + } else { + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDISTRB(led->led_no), + MT6370_ISTROBE_MASK, val); + } + + return ret; +} + +static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev = &fl_cdev->led_cdev; + struct led_flash_setting *s = &fl_cdev->brightness; + u32 led_enable_mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask; + u32 val = state ? led_enable_mask : 0; + u32 curr; + int ret; + + mutex_lock(&priv->lock); + + /* + * There is only one set of flash control logic, and this flag is used to check if 'torch' + * is currently being used. + */ + if (priv->fled_torch_used) { + dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", priv->fled_torch_used); + ret = -EBUSY; + goto unlock; + } + + if (state) + curr = priv->fled_strobe_used | BIT(led->led_no); + else + curr = priv->fled_strobe_used & ~BIT(led->led_no); + + if (curr) + val |= MT6370_STROBEN_MASK; + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, val); + if (ret) { + dev_err(lcdev->dev, "[%d] control current source %d fail\n", led->led_no, state); + goto unlock; + } + + /* + * If the flash needs to turn on, configure the flash current to ramp up to the setting + * value. Otherwise, always revert to the minimum one. + */ + ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min); + if (ret) { + dev_err(lcdev->dev, "[%d] Failed to set brightness\n", led->led_no); + goto unlock; + } + + /* + * For the flash to turn on/off, we must wait for HW ramping up/down time 5ms/500us to + * prevent the unexpected problem. + */ + if (!priv->fled_strobe_used && curr) + usleep_range(5000, 6000); + else if (priv->fled_strobe_used && !curr) + usleep_range(500, 600); + + priv->fled_strobe_used = curr; + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + + mutex_lock(&priv->lock); + *state = !!(priv->fled_strobe_used & BIT(led->led_no)); + mutex_unlock(&priv->lock); + + return 0; +} + +static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s = &fl_cdev->timeout; + u32 val = (timeout - s->min) / s->step; + + return regmap_update_bits(priv->regmap, MT6370_REG_STRBTO, MT6370_STRBTO_MASK, val); +} + +static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault) +{ + struct mt6370_led *led = to_mt6370_led(fl_cdev, flash); + struct mt6370_priv *priv = led->priv; + u16 fled_stat; + unsigned int chg_stat, strobe_timeout_mask, fled_short_mask; + u32 rfault = 0; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat); + if (ret) + return ret; + + ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat, sizeof(fled_stat)); + if (ret) + return ret; + + switch (led->led_no) { + case MT6370_LED_FLASH1: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK; + break; + + case MT6370_LED_FLASH2: + strobe_timeout_mask = MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED2SHORT_MASK; + break; + + case MT6370_LED_JOINT: + strobe_timeout_mask = MT6370_FLED1STRBTO_MASK | MT6370_FLED2STRBTO_MASK; + fled_short_mask = MT6370_FLED1SHORT_MASK | MT6370_FLED2SHORT_MASK; + break; + default: + return -EINVAL; + } + + if (chg_stat & MT6370_FLEDCHGVINOVP_MASK) + rfault |= LED_FAULT_INPUT_VOLTAGE; + + if (fled_stat & strobe_timeout_mask) + rfault |= LED_FAULT_TIMEOUT; + + if (fled_stat & fled_short_mask) + rfault |= LED_FAULT_SHORT_CIRCUIT; + + if (fled_stat & MT6370_FLEDLVF_MASK) + rfault |= LED_FAULT_UNDER_VOLTAGE; + + *fault = rfault; + return ret; +} + +static const struct led_flash_ops mt6370_flash_ops = { + .flash_brightness_set = mt6370_flash_brightness_set, + .strobe_set = mt6370_strobe_set, + .strobe_get = mt6370_strobe_get, + .timeout_set = mt6370_timeout_set, + .fault_get = mt6370_fault_get, +}; + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, + bool enable) +{ + struct led_classdev_flash *flash = v4l2_flash->fled_cdev; + struct mt6370_led *led = to_mt6370_led(flash, flash); + struct mt6370_priv *priv = led->priv; + u32 mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL : + MT6370_FLCSEN_MASK(led->led_no); + u32 val = enable ? mask : 0; + int ret; + + mutex_lock(&priv->lock); + + ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val); + if (ret) + goto unlock; + + if (enable) + priv->fled_strobe_used |= BIT(led->led_no); + else + priv->fled_strobe_used &= ~BIT(led->led_no); + +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static const struct v4l2_flash_ops v4l2_flash_ops = { + .external_strobe_set = mt6370_flash_external_strobe_set, +}; + +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, struct v4l2_flash_config *cfg) +{ + struct led_classdev *lcdev; + struct led_flash_setting *s = &cfg->intensity; + + lcdev = &led->flash.led_cdev; + + s->min = MT6370_ITORCH_MIN_uA; + s->step = MT6370_ITORCH_STEP_uA; + s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step; + + cfg->has_external_strobe = 1; + strscpy(cfg->dev_name, dev_name(lcdev->dev), sizeof(cfg->dev_name)); + + cfg->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT | + LED_FAULT_INPUT_VOLTAGE | LED_FAULT_UNDER_VOLTAGE; +} +#else +static const struct v4l2_flash_ops v4l2_flash_ops; +static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, struct v4l2_flash_config *cfg) +{ +} +#endif + +static void mt6370_v4l2_flash_release(void *v4l2_flash) +{ + v4l2_flash_release(v4l2_flash); +} + +static int mt6370_led_register(struct device *parent, struct mt6370_led *led, + struct fwnode_handle *fwnode) +{ + struct led_init_data init_data = { .fwnode = fwnode }; + struct v4l2_flash_config v4l2_config = {}; + int ret; + + ret = devm_led_classdev_flash_register_ext(parent, &led->flash, &init_data); + if (ret) + return dev_err_probe(parent, ret, "Couldn't register flash %d\n", led->led_no); + + mt6370_init_v4l2_flash_config(led, &v4l2_config); + led->v4l2_flash = v4l2_flash_init(parent, fwnode, &led->flash, &v4l2_flash_ops, + &v4l2_config); + if (IS_ERR(led->v4l2_flash)) + return dev_err_probe(parent, PTR_ERR(led->v4l2_flash), + "Failed to register %d v4l2 sd\n", led->led_no); + + return devm_add_action_or_reset(parent, mt6370_v4l2_flash_release, led->v4l2_flash); +} + +static u32 mt6370_clamp(u32 val, u32 min, u32 max, u32 step) +{ + u32 retval; + + retval = clamp_val(val, min, max); + if (step > 1) + retval = rounddown(retval - min, step) + min; + + return retval; +} + +static int mt6370_init_flash_properties(struct device *dev, struct mt6370_led *led, + struct fwnode_handle *fwnode) +{ + struct led_classdev_flash *flash = &led->flash; + struct led_classdev *lcdev = &flash->led_cdev; + struct mt6370_priv *priv = led->priv; + struct led_flash_setting *s; + u32 sources[MT6370_MAX_LEDS]; + u32 max_ua, val; + int i, ret, num; + + num = fwnode_property_count_u32(fwnode, "led-sources"); + if (num < 1) + return dev_err_probe(dev, -EINVAL, + "Not specified or wrong number of led-sources\n"); + + ret = fwnode_property_read_u32_array(fwnode, "led-sources", sources, num); + if (ret) + return ret; + + for (i = 0; i < num; i++) { + if (sources[i] >= MT6370_MAX_LEDS) + return -EINVAL; + if (priv->leds_active & BIT(sources[i])) + return -EINVAL; + priv->leds_active |= BIT(sources[i]); + } + + /* If both channels are specified in 'led-sources', joint flash output mode is used */ + led->led_no = num == 2 ? MT6370_LED_JOINT : sources[0]; + + max_ua = num == 2 ? MT6370_ITORCH_DOUBLE_MAX_uA : MT6370_ITORCH_MAX_uA; + val = MT6370_ITORCH_MIN_uA; + ret = fwnode_property_read_u32(fwnode, "led-max-microamp", &val); + if (!ret) + val = mt6370_clamp(val, MT6370_ITORCH_MIN_uA, max_ua, MT6370_ITORCH_STEP_uA); + + lcdev->max_brightness = (val - MT6370_ITORCH_MIN_uA) / MT6370_ITORCH_STEP_uA + 1; + lcdev->brightness_set_blocking = mt6370_torch_brightness_set; + lcdev->flags |= LED_DEV_CAP_FLASH; + + max_ua = num == 2 ? MT6370_ISTRB_DOUBLE_MAX_uA : MT6370_ISTRB_MAX_uA; + val = MT6370_ISTRB_MIN_uA; + ret = fwnode_property_read_u32(fwnode, "flash-max-microamp", &val); + if (!ret) + val = mt6370_clamp(val, MT6370_ISTRB_MIN_uA, max_ua, MT6370_ISTRB_STEP_uA); + + s = &flash->brightness; + s->min = MT6370_ISTRB_MIN_uA; + s->step = MT6370_ISTRB_STEP_uA; + s->val = s->max = val; + + /* Always configure to the minimum level when off to prevent flash current spikes. */ + ret = _mt6370_flash_brightness_set(flash, s->min); + if (ret) + return ret; + + val = MT6370_STRBTO_MIN_US; + ret = fwnode_property_read_u32(fwnode, "flash-max-timeout-us", &val); + if (!ret) + val = mt6370_clamp(val, MT6370_STRBTO_MIN_US, MT6370_STRBTO_MAX_US, + MT6370_STRBTO_STEP_US); + + s = &flash->timeout; + s->min = MT6370_STRBTO_MIN_US; + s->step = MT6370_STRBTO_STEP_US; + s->val = s->max = val; + + flash->ops = &mt6370_flash_ops; + + return 0; +} + +static int mt6370_led_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + int i = 0, ret; + + count = device_get_child_node_count(dev); + if (!count || count > MT6370_MAX_LEDS) + return dev_err_probe(dev, -EINVAL, + "No child node or node count over max led number %zu\n", count); + + priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n"); + + device_for_each_child_node(dev, child) { + struct mt6370_led *led = priv->leds + i; + + led->priv = priv; + + ret = mt6370_init_flash_properties(dev, led, child); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + ret = mt6370_led_register(dev, led, child); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + i++; + } + + return 0; +} + +static const struct of_device_id mt6370_led_of_id[] = { + { .compatible = "mediatek,mt6370-flashlight" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_led_of_id); + +static struct platform_driver mt6370_led_driver = { + .driver = { + .name = "mt6370-flashlight", + .of_match_table = mt6370_led_of_id, + }, + .probe = mt6370_led_probe, +}; +module_platform_driver(mt6370_led_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MT6370 FLASH LED Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c new file mode 100644 index 000000000000..90a24fa25a49 --- /dev/null +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -0,0 +1,773 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* registers definitions */ +#define FLASH_TYPE_REG 0x04 +#define FLASH_TYPE_VAL 0x18 + +#define FLASH_SUBTYPE_REG 0x05 +#define FLASH_SUBTYPE_3CH_VAL 0x04 +#define FLASH_SUBTYPE_4CH_VAL 0x07 + +#define FLASH_STS_3CH_OTST1 BIT(0) +#define FLASH_STS_3CH_OTST2 BIT(1) +#define FLASH_STS_3CH_OTST3 BIT(2) +#define FLASH_STS_3CH_BOB_THM_OVERLOAD BIT(3) +#define FLASH_STS_3CH_VPH_DROOP BIT(4) +#define FLASH_STS_3CH_BOB_ILIM_S1 BIT(5) +#define FLASH_STS_3CH_BOB_ILIM_S2 BIT(6) +#define FLASH_STS_3CH_BCL_IBAT BIT(7) + +#define FLASH_STS_4CH_VPH_LOW BIT(0) +#define FLASH_STS_4CH_BCL_IBAT BIT(1) +#define FLASH_STS_4CH_BOB_ILIM_S1 BIT(2) +#define FLASH_STS_4CH_BOB_ILIM_S2 BIT(3) +#define FLASH_STS_4CH_OTST2 BIT(4) +#define FLASH_STS_4CH_OTST1 BIT(5) +#define FLASH_STS_4CHG_BOB_THM_OVERLOAD BIT(6) + +#define FLASH_TIMER_EN_BIT BIT(7) +#define FLASH_TIMER_VAL_MASK GENMASK(6, 0) +#define FLASH_TIMER_STEP_MS 10 + +#define FLASH_STROBE_HW_SW_SEL_BIT BIT(2) +#define SW_STROBE_VAL 0 +#define HW_STROBE_VAL 1 +#define FLASH_HW_STROBE_TRIGGER_SEL_BIT BIT(1) +#define STROBE_LEVEL_TRIGGER_VAL 0 +#define STROBE_EDGE_TRIGGER_VAL 1 +#define FLASH_STROBE_POLARITY_BIT BIT(0) +#define STROBE_ACTIVE_HIGH_VAL 1 + +#define FLASH_IRES_MASK_4CH BIT(0) +#define FLASH_IRES_MASK_3CH GENMASK(1, 0) +#define FLASH_IRES_12P5MA_VAL 0 +#define FLASH_IRES_5MA_VAL_4CH 1 +#define FLASH_IRES_5MA_VAL_3CH 3 + +/* constants */ +#define FLASH_CURRENT_MAX_UA 1500000 +#define TORCH_CURRENT_MAX_UA 500000 +#define FLASH_TOTAL_CURRENT_MAX_UA 2000000 +#define FLASH_CURRENT_DEFAULT_UA 1000000 +#define TORCH_CURRENT_DEFAULT_UA 200000 + +#define TORCH_IRES_UA 5000 +#define FLASH_IRES_UA 12500 + +#define FLASH_TIMEOUT_MAX_US 1280000 +#define FLASH_TIMEOUT_STEP_US 10000 + +#define UA_PER_MA 1000 + +enum hw_type { + QCOM_MVFLASH_3CH, + QCOM_MVFLASH_4CH, +}; + +enum led_mode { + FLASH_MODE, + TORCH_MODE, +}; + +enum led_strobe { + SW_STROBE, + HW_STROBE, +}; + +enum { + REG_STATUS1, + REG_STATUS2, + REG_STATUS3, + REG_CHAN_TIMER, + REG_ITARGET, + REG_MODULE_EN, + REG_IRESOLUTION, + REG_CHAN_STROBE, + REG_CHAN_EN, + REG_MAX_COUNT, +}; + +static struct reg_field mvflash_3ch_regs[REG_MAX_COUNT] = { + REG_FIELD(0x08, 0, 7), /* status1 */ + REG_FIELD(0x09, 0, 7), /* status2 */ + REG_FIELD(0x0a, 0, 7), /* status3 */ + REG_FIELD_ID(0x40, 0, 7, 3, 1), /* chan_timer */ + REG_FIELD_ID(0x43, 0, 6, 3, 1), /* itarget */ + REG_FIELD(0x46, 7, 7), /* module_en */ + REG_FIELD(0x47, 0, 5), /* iresolution */ + REG_FIELD_ID(0x49, 0, 2, 3, 1), /* chan_strobe */ + REG_FIELD(0x4c, 0, 2), /* chan_en */ +}; + +static struct reg_field mvflash_4ch_regs[REG_MAX_COUNT] = { + REG_FIELD(0x06, 0, 7), /* status1 */ + REG_FIELD(0x07, 0, 6), /* status2 */ + REG_FIELD(0x09, 0, 7), /* status3 */ + REG_FIELD_ID(0x3e, 0, 7, 4, 1), /* chan_timer */ + REG_FIELD_ID(0x42, 0, 6, 4, 1), /* itarget */ + REG_FIELD(0x46, 7, 7), /* module_en */ + REG_FIELD(0x49, 0, 3), /* iresolution */ + REG_FIELD_ID(0x4a, 0, 6, 4, 1), /* chan_strobe */ + REG_FIELD(0x4e, 0, 3), /* chan_en */ +}; + +struct qcom_flash_data { + struct v4l2_flash **v4l2_flash; + struct regmap_field *r_fields[REG_MAX_COUNT]; + struct mutex lock; + enum hw_type hw_type; + u8 leds_count; + u8 max_channels; + u8 chan_en_bits; +}; + +struct qcom_flash_led { + struct qcom_flash_data *flash_data; + struct led_classdev_flash flash; + u32 max_flash_current_ma; + u32 max_torch_current_ma; + u32 max_timeout_ms; + u32 flash_current_ma; + u32 flash_timeout_ms; + u8 *chan_id; + u8 chan_count; + bool enabled; +}; + +static int set_flash_module_en(struct qcom_flash_led *led, bool en) +{ + struct qcom_flash_data *flash_data = led->flash_data; + u8 led_mask = 0, enable; + int i, rc; + + for (i = 0; i < led->chan_count; i++) + led_mask |= BIT(led->chan_id[i]); + + mutex_lock(&flash_data->lock); + if (en) + flash_data->chan_en_bits |= led_mask; + else + flash_data->chan_en_bits &= ~led_mask; + + enable = !!flash_data->chan_en_bits; + rc = regmap_field_write(flash_data->r_fields[REG_MODULE_EN], enable); + if (rc) + dev_err(led->flash.led_cdev.dev, "write module_en failed, rc=%d\n", rc); + mutex_unlock(&flash_data->lock); + + return rc; +} + +static int set_flash_current(struct qcom_flash_led *led, u32 current_ma, enum led_mode mode) +{ + struct qcom_flash_data *flash_data = led->flash_data; + u32 itarg_ua, ires_ua; + u8 shift, ires_mask = 0, ires_val = 0, chan_id; + int i, rc; + + /* + * Split the current across the channels and set the + * IRESOLUTION and ITARGET registers accordingly. + */ + itarg_ua = (current_ma * UA_PER_MA) / led->chan_count + 1; + ires_ua = (mode == FLASH_MODE) ? FLASH_IRES_UA : TORCH_IRES_UA; + + for (i = 0; i < led->chan_count; i++) { + u8 itarget = 0; + + if (itarg_ua > ires_ua) + itarget = itarg_ua / ires_ua - 1; + + chan_id = led->chan_id[i]; + + rc = regmap_fields_write(flash_data->r_fields[REG_ITARGET], chan_id, itarget); + if (rc) + return rc; + + if (flash_data->hw_type == QCOM_MVFLASH_3CH) { + shift = chan_id * 2; + ires_mask |= FLASH_IRES_MASK_3CH << shift; + ires_val |= ((mode == FLASH_MODE) ? + (FLASH_IRES_12P5MA_VAL << shift) : + (FLASH_IRES_5MA_VAL_3CH << shift)); + } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { + shift = chan_id; + ires_mask |= FLASH_IRES_MASK_4CH << shift; + ires_val |= ((mode == FLASH_MODE) ? + (FLASH_IRES_12P5MA_VAL << shift) : + (FLASH_IRES_5MA_VAL_4CH << shift)); + } else { + dev_err(led->flash.led_cdev.dev, + "HW type %d is not supported\n", flash_data->hw_type); + return -EOPNOTSUPP; + } + } + + return regmap_field_update_bits(flash_data->r_fields[REG_IRESOLUTION], ires_mask, ires_val); +} + +static int set_flash_timeout(struct qcom_flash_led *led, u32 timeout_ms) +{ + struct qcom_flash_data *flash_data = led->flash_data; + u8 timer, chan_id; + int rc, i; + + /* set SAFETY_TIMER for all the channels connected to the same LED */ + timeout_ms = min_t(u32, timeout_ms, led->max_timeout_ms); + + for (i = 0; i < led->chan_count; i++) { + chan_id = led->chan_id[i]; + + timer = timeout_ms / FLASH_TIMER_STEP_MS; + timer = clamp_t(u8, timer, 0, FLASH_TIMER_VAL_MASK); + + if (timeout_ms) + timer |= FLASH_TIMER_EN_BIT; + + rc = regmap_fields_write(flash_data->r_fields[REG_CHAN_TIMER], chan_id, timer); + if (rc) + return rc; + } + + return 0; +} + +static int set_flash_strobe(struct qcom_flash_led *led, enum led_strobe strobe, bool state) +{ + struct qcom_flash_data *flash_data = led->flash_data; + u8 strobe_sel, chan_en, chan_id, chan_mask = 0; + int rc, i; + + /* Set SW strobe config for all channels connected to the LED */ + for (i = 0; i < led->chan_count; i++) { + chan_id = led->chan_id[i]; + + if (strobe == SW_STROBE) + strobe_sel = FIELD_PREP(FLASH_STROBE_HW_SW_SEL_BIT, SW_STROBE_VAL); + else + strobe_sel = FIELD_PREP(FLASH_STROBE_HW_SW_SEL_BIT, HW_STROBE_VAL); + + strobe_sel |= + FIELD_PREP(FLASH_HW_STROBE_TRIGGER_SEL_BIT, STROBE_LEVEL_TRIGGER_VAL) | + FIELD_PREP(FLASH_STROBE_POLARITY_BIT, STROBE_ACTIVE_HIGH_VAL); + + rc = regmap_fields_write( + flash_data->r_fields[REG_CHAN_STROBE], chan_id, strobe_sel); + if (rc) + return rc; + + chan_mask |= BIT(chan_id); + } + + /* Enable/disable flash channels */ + chan_en = state ? chan_mask : 0; + rc = regmap_field_update_bits(flash_data->r_fields[REG_CHAN_EN], chan_mask, chan_en); + if (rc) + return rc; + + led->enabled = state; + return 0; +} + +static inline struct qcom_flash_led *flcdev_to_qcom_fled(struct led_classdev_flash *flcdev) +{ + return container_of(flcdev, struct qcom_flash_led, flash); +} + +static int qcom_flash_brightness_set(struct led_classdev_flash *fled_cdev, u32 brightness) +{ + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + + led->flash_current_ma = min_t(u32, led->max_flash_current_ma, brightness / UA_PER_MA); + return 0; +} + +static int qcom_flash_timeout_set(struct led_classdev_flash *fled_cdev, u32 timeout) +{ + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + + led->flash_timeout_ms = timeout / USEC_PER_MSEC; + return 0; +} + +static int qcom_flash_strobe_set(struct led_classdev_flash *fled_cdev, bool state) +{ + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + int rc; + + rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE); + if (rc) + return rc; + + rc = set_flash_timeout(led, led->flash_timeout_ms); + if (rc) + return rc; + + rc = set_flash_module_en(led, state); + if (rc) + return rc; + + return set_flash_strobe(led, SW_STROBE, state); +} + +static int qcom_flash_strobe_get(struct led_classdev_flash *fled_cdev, bool *state) +{ + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + + *state = led->enabled; + return 0; +} + +static int qcom_flash_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault) +{ + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + struct qcom_flash_data *flash_data = led->flash_data; + u8 shift, chan_id, chan_mask = 0; + u8 ot_mask = 0, oc_mask = 0, uv_mask = 0; + u32 val, fault_sts = 0; + int i, rc; + + rc = regmap_field_read(flash_data->r_fields[REG_STATUS1], &val); + if (rc) + return rc; + + for (i = 0; i < led->chan_count; i++) { + chan_id = led->chan_id[i]; + shift = chan_id * 2; + + if (val & BIT(shift)) + fault_sts |= LED_FAULT_SHORT_CIRCUIT; + + chan_mask |= BIT(chan_id); + } + + rc = regmap_field_read(flash_data->r_fields[REG_STATUS2], &val); + if (rc) + return rc; + + if (flash_data->hw_type == QCOM_MVFLASH_3CH) { + ot_mask = FLASH_STS_3CH_OTST1 | + FLASH_STS_3CH_OTST2 | + FLASH_STS_3CH_OTST3 | + FLASH_STS_3CH_BOB_THM_OVERLOAD; + oc_mask = FLASH_STS_3CH_BOB_ILIM_S1 | + FLASH_STS_3CH_BOB_ILIM_S2 | + FLASH_STS_3CH_BCL_IBAT; + uv_mask = FLASH_STS_3CH_VPH_DROOP; + } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { + ot_mask = FLASH_STS_4CH_OTST2 | + FLASH_STS_4CH_OTST1 | + FLASH_STS_4CHG_BOB_THM_OVERLOAD; + oc_mask = FLASH_STS_4CH_BCL_IBAT | + FLASH_STS_4CH_BOB_ILIM_S1 | + FLASH_STS_4CH_BOB_ILIM_S2; + uv_mask = FLASH_STS_4CH_VPH_LOW; + } + + if (val & ot_mask) + fault_sts |= LED_FAULT_OVER_TEMPERATURE; + + if (val & oc_mask) + fault_sts |= LED_FAULT_OVER_CURRENT; + + if (val & uv_mask) + fault_sts |= LED_FAULT_INPUT_VOLTAGE; + + rc = regmap_field_read(flash_data->r_fields[REG_STATUS3], &val); + if (rc) + return rc; + + if (flash_data->hw_type == QCOM_MVFLASH_3CH) { + if (val & chan_mask) + fault_sts |= LED_FAULT_TIMEOUT; + } else if (flash_data->hw_type == QCOM_MVFLASH_4CH) { + for (i = 0; i < led->chan_count; i++) { + chan_id = led->chan_id[i]; + shift = chan_id * 2; + + if (val & BIT(shift)) + fault_sts |= LED_FAULT_TIMEOUT; + } + } + + *fault = fault_sts; + return 0; +} + +static int qcom_flash_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + u32 current_ma = brightness * led->max_torch_current_ma / LED_FULL; + bool enable = !!brightness; + int rc; + + rc = set_flash_current(led, current_ma, TORCH_MODE); + if (rc) + return rc; + + /* Disable flash timeout for torch LED */ + rc = set_flash_timeout(led, 0); + if (rc) + return rc; + + rc = set_flash_module_en(led, enable); + if (rc) + return rc; + + return set_flash_strobe(led, SW_STROBE, enable); +} + +static const struct led_flash_ops qcom_flash_ops = { + .flash_brightness_set = qcom_flash_brightness_set, + .strobe_set = qcom_flash_strobe_set, + .strobe_get = qcom_flash_strobe_get, + .timeout_set = qcom_flash_timeout_set, + .fault_get = qcom_flash_fault_get, +}; + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +static int qcom_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, bool enable) +{ + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + int rc; + + rc = set_flash_module_en(led, enable); + if (rc) + return rc; + + if (enable) + return set_flash_strobe(led, HW_STROBE, true); + else + return set_flash_strobe(led, SW_STROBE, false); +} + +static enum led_brightness +qcom_flash_intensity_to_led_brightness(struct v4l2_flash *v4l2_flash, s32 intensity) +{ + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + u32 current_ma = intensity / UA_PER_MA; + + current_ma = min_t(u32, current_ma, led->max_torch_current_ma); + if (!current_ma) + return LED_OFF; + + return (current_ma * LED_FULL) / led->max_torch_current_ma; +} + +static s32 qcom_flash_brightness_to_led_intensity(struct v4l2_flash *v4l2_flash, + enum led_brightness brightness) +{ + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; + struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); + + return (brightness * led->max_torch_current_ma * UA_PER_MA) / LED_FULL; +} + +static const struct v4l2_flash_ops qcom_v4l2_flash_ops = { + .external_strobe_set = qcom_flash_external_strobe_set, + .intensity_to_led_brightness = qcom_flash_intensity_to_led_brightness, + .led_brightness_to_intensity = qcom_flash_brightness_to_led_intensity, +}; + +static int +qcom_flash_v4l2_init(struct device *dev, struct qcom_flash_led *led, struct fwnode_handle *fwnode) +{ + struct qcom_flash_data *flash_data = led->flash_data; + struct v4l2_flash_config v4l2_cfg = { 0 }; + struct led_flash_setting *intensity = &v4l2_cfg.intensity; + + if (!(led->flash.led_cdev.flags & LED_DEV_CAP_FLASH)) + return 0; + + intensity->min = intensity->step = TORCH_IRES_UA * led->chan_count; + intensity->max = led->max_torch_current_ma * UA_PER_MA; + intensity->val = min_t(u32, intensity->max, TORCH_CURRENT_DEFAULT_UA); + + strscpy(v4l2_cfg.dev_name, led->flash.led_cdev.dev->kobj.name, + sizeof(v4l2_cfg.dev_name)); + + v4l2_cfg.has_external_strobe = true; + v4l2_cfg.flash_faults = LED_FAULT_INPUT_VOLTAGE | + LED_FAULT_OVER_CURRENT | + LED_FAULT_SHORT_CIRCUIT | + LED_FAULT_OVER_TEMPERATURE | + LED_FAULT_TIMEOUT; + + flash_data->v4l2_flash[flash_data->leds_count] = + v4l2_flash_init(dev, fwnode, &led->flash, &qcom_v4l2_flash_ops, &v4l2_cfg); + return PTR_ERR_OR_ZERO(flash_data->v4l2_flash); +} +# else +static int +qcom_flash_v4l2_init(struct device *dev, struct qcom_flash_led *led, struct fwnode_handle *fwnode) +{ + return 0; +} +#endif + +static int qcom_flash_register_led_device(struct device *dev, + struct fwnode_handle *node, struct qcom_flash_led *led) +{ + struct qcom_flash_data *flash_data = led->flash_data; + struct led_init_data init_data; + struct led_classdev_flash *flash = &led->flash; + struct led_flash_setting *brightness, *timeout; + u32 count, current_ua, timeout_us; + u32 channels[4]; + int i, rc; + + count = fwnode_property_count_u32(node, "led-sources"); + if (count <= 0) { + dev_err(dev, "No led-sources specified\n"); + return -ENODEV; + } + + if (count > flash_data->max_channels) { + dev_err(dev, "led-sources count %u exceeds maximum channel count %u\n", + count, flash_data->max_channels); + return -EINVAL; + } + + rc = fwnode_property_read_u32_array(node, "led-sources", channels, count); + if (rc < 0) { + dev_err(dev, "Failed to read led-sources property, rc=%d\n", rc); + return rc; + } + + led->chan_count = count; + led->chan_id = devm_kcalloc(dev, count, sizeof(u8), GFP_KERNEL); + if (!led->chan_id) + return -ENOMEM; + + for (i = 0; i < count; i++) { + if ((channels[i] == 0) || (channels[i] > flash_data->max_channels)) { + dev_err(dev, "led-source out of HW support range [1-%u]\n", + flash_data->max_channels); + return -EINVAL; + } + + /* Make chan_id indexing from 0 */ + led->chan_id[i] = channels[i] - 1; + } + + rc = fwnode_property_read_u32(node, "led-max-microamp", ¤t_ua); + if (rc < 0) { + dev_err(dev, "Failed to read led-max-microamp property, rc=%d\n", rc); + return rc; + } + + if (current_ua == 0) { + dev_err(dev, "led-max-microamp shouldn't be 0\n"); + return -EINVAL; + } + + current_ua = min_t(u32, current_ua, TORCH_CURRENT_MAX_UA * led->chan_count); + led->max_torch_current_ma = current_ua / UA_PER_MA; + + if (fwnode_property_present(node, "flash-max-microamp")) { + flash->led_cdev.flags |= LED_DEV_CAP_FLASH; + + rc = fwnode_property_read_u32(node, "flash-max-microamp", ¤t_ua); + if (rc < 0) { + dev_err(dev, "Failed to read flash-max-microamp property, rc=%d\n", + rc); + return rc; + } + + current_ua = min_t(u32, current_ua, FLASH_CURRENT_MAX_UA * led->chan_count); + current_ua = min_t(u32, current_ua, FLASH_TOTAL_CURRENT_MAX_UA); + + /* Initialize flash class LED device brightness settings */ + brightness = &flash->brightness; + brightness->min = brightness->step = FLASH_IRES_UA * led->chan_count; + brightness->max = current_ua; + brightness->val = min_t(u32, current_ua, FLASH_CURRENT_DEFAULT_UA); + + led->max_flash_current_ma = current_ua / UA_PER_MA; + led->flash_current_ma = brightness->val / UA_PER_MA; + + rc = fwnode_property_read_u32(node, "flash-max-timeout-us", &timeout_us); + if (rc < 0) { + dev_err(dev, "Failed to read flash-max-timeout-us property, rc=%d\n", + rc); + return rc; + } + + timeout_us = min_t(u32, timeout_us, FLASH_TIMEOUT_MAX_US); + + /* Initialize flash class LED device timeout settings */ + timeout = &flash->timeout; + timeout->min = timeout->step = FLASH_TIMEOUT_STEP_US; + timeout->val = timeout->max = timeout_us; + + led->max_timeout_ms = led->flash_timeout_ms = timeout_us / USEC_PER_MSEC; + + flash->ops = &qcom_flash_ops; + } + + flash->led_cdev.brightness_set_blocking = qcom_flash_led_brightness_set; + + init_data.fwnode = node; + init_data.devicename = NULL; + init_data.default_label = NULL; + init_data.devname_mandatory = false; + + rc = devm_led_classdev_flash_register_ext(dev, flash, &init_data); + if (rc < 0) { + dev_err(dev, "Register flash LED classdev failed, rc=%d\n", rc); + return rc; + } + + return qcom_flash_v4l2_init(dev, led, node); +} + +static int qcom_flash_led_probe(struct platform_device *pdev) +{ + struct qcom_flash_data *flash_data; + struct qcom_flash_led *led; + struct fwnode_handle *child; + struct device *dev = &pdev->dev; + struct regmap *regmap; + struct reg_field *regs; + int count, i, rc; + u32 val, reg_base; + + flash_data = devm_kzalloc(dev, sizeof(*flash_data), GFP_KERNEL); + if (!flash_data) + return -ENOMEM; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) { + dev_err(dev, "Failed to get parent regmap\n"); + return -EINVAL; + } + + rc = fwnode_property_read_u32(dev->fwnode, "reg", ®_base); + if (rc < 0) { + dev_err(dev, "Failed to get register base address, rc=%d\n", rc); + return rc; + } + + rc = regmap_read(regmap, reg_base + FLASH_TYPE_REG, &val); + if (rc < 0) { + dev_err(dev, "Read flash LED module type failed, rc=%d\n", rc); + return rc; + } + + if (val != FLASH_TYPE_VAL) { + dev_err(dev, "type %#x is not a flash LED module\n", val); + return -ENODEV; + } + + rc = regmap_read(regmap, reg_base + FLASH_SUBTYPE_REG, &val); + if (rc < 0) { + dev_err(dev, "Read flash LED module subtype failed, rc=%d\n", rc); + return rc; + } + + if (val == FLASH_SUBTYPE_3CH_VAL) { + flash_data->hw_type = QCOM_MVFLASH_3CH; + flash_data->max_channels = 3; + regs = mvflash_3ch_regs; + } else if (val == FLASH_SUBTYPE_4CH_VAL) { + flash_data->hw_type = QCOM_MVFLASH_4CH; + flash_data->max_channels = 4; + regs = mvflash_4ch_regs; + } else { + dev_err(dev, "flash LED subtype %#x is not yet supported\n", val); + return -ENODEV; + } + + for (i = 0; i < REG_MAX_COUNT; i++) + regs[i].reg += reg_base; + + rc = devm_regmap_field_bulk_alloc(dev, regmap, flash_data->r_fields, regs, REG_MAX_COUNT); + if (rc < 0) { + dev_err(dev, "Failed to allocate regmap field, rc=%d\n", rc); + return rc; + } + + platform_set_drvdata(pdev, flash_data); + mutex_init(&flash_data->lock); + + count = device_get_child_node_count(dev); + if (count == 0 || count > flash_data->max_channels) { + dev_err(dev, "No child or child count exceeds %d\n", flash_data->max_channels); + return -EINVAL; + } + + flash_data->v4l2_flash = devm_kcalloc(dev, count, + sizeof(*flash_data->v4l2_flash), GFP_KERNEL); + if (!flash_data->v4l2_flash) + return -ENOMEM; + + device_for_each_child_node(dev, child) { + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); + if (!led) { + rc = -ENOMEM; + goto release; + } + + led->flash_data = flash_data; + rc = qcom_flash_register_led_device(dev, child, led); + if (rc < 0) + goto release; + + flash_data->leds_count++; + } + + return 0; + +release: + while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) + v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); + return rc; +} + +static int qcom_flash_led_remove(struct platform_device *pdev) +{ + struct qcom_flash_data *flash_data = platform_get_drvdata(pdev); + + while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) + v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); + + mutex_destroy(&flash_data->lock); + return 0; +} + +static const struct of_device_id qcom_flash_led_match_table[] = { + { .compatible = "qcom,spmi-flash-led" }, + { } +}; + +MODULE_DEVICE_TABLE(of, qcom_flash_led_match_table); +static struct platform_driver qcom_flash_led_driver = { + .driver = { + .name = "leds-qcom-flash", + .of_match_table = qcom_flash_led_match_table, + }, + .probe = qcom_flash_led_probe, + .remove = qcom_flash_led_remove, +}; + +module_platform_driver(qcom_flash_led_driver); + +MODULE_DESCRIPTION("QCOM Flash LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index a6b3adcd044a..9255bc11f99d 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -626,7 +626,7 @@ EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); static int __init leds_init(void) { - leds_class = class_create(THIS_MODULE, "leds"); + leds_class = class_create("leds"); if (IS_ERR(leds_class)) return PTR_ERR(leds_class); leds_class->pm = &leds_class_dev_pm_ops; diff --git a/drivers/leds/leds-bd2606mvv.c b/drivers/leds/leds-bd2606mvv.c new file mode 100644 index 000000000000..76f9d4d70f9a --- /dev/null +++ b/drivers/leds/leds-bd2606mvv.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Andreas Kemnade + * + * Datasheet: + * https://fscdn.rohm.com/en/products/databook/datasheet/ic/power/led_driver/bd2606mvv_1-e.pdf + * + * If LED brightness cannot be controlled independently due to shared + * brightness registers, max_brightness is set to 1 and only on/off + * is possible for the affected LED pair. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define BD2606_MAX_LEDS 6 +#define BD2606_MAX_BRIGHTNESS 63 +#define BD2606_REG_PWRCNT 3 +#define ldev_to_led(c) container_of(c, struct bd2606mvv_led, ldev) + +struct bd2606mvv_led { + unsigned int led_no; + struct led_classdev ldev; + struct bd2606mvv_priv *priv; +}; + +struct bd2606mvv_priv { + struct bd2606mvv_led leds[BD2606_MAX_LEDS]; + struct regmap *regmap; +}; + +static int +bd2606mvv_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct bd2606mvv_led *led = ldev_to_led(led_cdev); + struct bd2606mvv_priv *priv = led->priv; + int err; + + if (brightness == 0) + return regmap_update_bits(priv->regmap, + BD2606_REG_PWRCNT, + 1 << led->led_no, + 0); + + /* shared brightness register */ + err = regmap_write(priv->regmap, led->led_no / 2, + led_cdev->max_brightness == 1 ? + BD2606_MAX_BRIGHTNESS : brightness); + if (err) + return err; + + return regmap_update_bits(priv->regmap, + BD2606_REG_PWRCNT, + 1 << led->led_no, + 1 << led->led_no); +} + +static const struct regmap_config bd2606mvv_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x3, +}; + +static int bd2606mvv_probe(struct i2c_client *client) +{ + struct fwnode_handle *np, *child; + struct device *dev = &client->dev; + struct bd2606mvv_priv *priv; + struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 }; + int active_pairs[BD2606_MAX_LEDS / 2] = { 0 }; + int err, reg; + int i; + + np = dev_fwnode(dev); + if (!np) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(client, &bd2606mvv_regmap); + if (IS_ERR(priv->regmap)) { + err = PTR_ERR(priv->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", err); + return err; + } + + i2c_set_clientdata(client, priv); + + fwnode_for_each_available_child_node(np, child) { + struct bd2606mvv_led *led; + + err = fwnode_property_read_u32(child, "reg", ®); + if (err) { + fwnode_handle_put(child); + return err; + } + if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) { + fwnode_handle_put(child); + return -EINVAL; + } + led = &priv->leds[reg]; + led_fwnodes[reg] = child; + active_pairs[reg / 2]++; + led->priv = priv; + led->led_no = reg; + led->ldev.brightness_set_blocking = bd2606mvv_brightness_set; + led->ldev.max_brightness = BD2606_MAX_BRIGHTNESS; + } + + for (i = 0; i < BD2606_MAX_LEDS; i++) { + struct led_init_data init_data = {}; + + if (!led_fwnodes[i]) + continue; + + init_data.fwnode = led_fwnodes[i]; + /* Check whether brightness can be independently adjusted. */ + if (active_pairs[i / 2] == 2) + priv->leds[i].ldev.max_brightness = 1; + + err = devm_led_classdev_register_ext(dev, + &priv->leds[i].ldev, + &init_data); + if (err < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, err, + "couldn't register LED %s\n", + priv->leds[i].ldev.name); + } + } + return 0; +} + +static const struct of_device_id __maybe_unused of_bd2606mvv_leds_match[] = { + { .compatible = "rohm,bd2606mvv", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_bd2606mvv_leds_match); + +static struct i2c_driver bd2606mvv_driver = { + .driver = { + .name = "leds-bd2606mvv", + .of_match_table = of_match_ptr(of_bd2606mvv_leds_match), + }, + .probe_new = bd2606mvv_probe, +}; + +module_i2c_driver(bd2606mvv_driver); + +MODULE_AUTHOR("Andreas Kemnade "); +MODULE_DESCRIPTION("BD2606 LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index b66ed5ac1aa5..221b386443bc 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -250,8 +249,7 @@ static int lp8860_init(struct lp8860_led *led) } } - if (led->enable_gpio) - gpiod_direction_output(led->enable_gpio, 1); + gpiod_direction_output(led->enable_gpio, 1); ret = lp8860_fault_check(led); if (ret) @@ -294,8 +292,7 @@ static int lp8860_init(struct lp8860_led *led) out: if (ret) - if (led->enable_gpio) - gpiod_direction_output(led->enable_gpio, 0); + gpiod_direction_output(led->enable_gpio, 0); if (led->regulator) { ret = regulator_disable(led->regulator); @@ -449,8 +446,7 @@ static void lp8860_remove(struct i2c_client *client) struct lp8860_led *led = i2c_get_clientdata(client); int ret; - if (led->enable_gpio) - gpiod_direction_output(led->enable_gpio, 0); + gpiod_direction_output(led->enable_gpio, 0); if (led->regulator) { ret = regulator_disable(led->regulator); diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 07dd12686a69..634cabd5bb79 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -691,8 +691,9 @@ tca6507_led_dt_init(struct device *dev) if (fwnode_property_read_string(child, "label", &led.name)) led.name = fwnode_get_name(child); - fwnode_property_read_string(child, "linux,default-trigger", - &led.default_trigger); + if (fwnode_property_read_string(child, "linux,default-trigger", + &led.default_trigger)) + led.default_trigger = NULL; led.flags = 0; if (fwnode_device_is_compatible(child, "gpio")) diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index ec25e0c16bea..7e31db50036f 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -135,7 +135,7 @@ static const struct regmap_config tlc591xx_regmap = { .max_register = 0x1e, }; -static const struct of_device_id of_tlc591xx_leds_match[] = { +static const struct of_device_id of_tlc591xx_leds_match[] __maybe_unused = { { .compatible = "ti,tlc59116", .data = &tlc59116 }, { .compatible = "ti,tlc59108", diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig index 204cf470beae..360c8679c6e2 100644 --- a/drivers/leds/rgb/Kconfig +++ b/drivers/leds/rgb/Kconfig @@ -26,4 +26,17 @@ config LEDS_QCOM_LPG If compiled as a module, the module will be named leds-qcom-lpg. +config LEDS_MT6370_RGB + tristate "LED Support for MediaTek MT6370 PMIC" + depends on MFD_MT6370 + select LINEAR_RANGES + help + Say Y here to enable support for MT6370_RGB LED device. + In MT6370, there are four channel current-sink LED drivers that + support hardware pattern for constant current, PWM, and breath mode. + Isink4 channel can also be used as a CHG_VIN power good indicator. + + This driver can also be built as a module. If so, the module + will be called "leds-mt6370-rgb". + endif # LEDS_CLASS_MULTICOLOR diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile index 0675bc0f6e18..8c01daf63f61 100644 --- a/drivers/leds/rgb/Makefile +++ b/drivers/leds/rgb/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o +obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c new file mode 100644 index 000000000000..bb62431efe83 --- /dev/null +++ b/drivers/leds/rgb/leds-mt6370-rgb.c @@ -0,0 +1,1011 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Richtek Technology Corp. + * + * Authors: + * ChiYuan Huang + * Alice Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum { + MT6370_LED_ISNK1 = 0, + MT6370_LED_ISNK2, + MT6370_LED_ISNK3, + MT6370_LED_ISNK4, + MT6370_MAX_LEDS +}; + +enum mt6370_led_mode { + MT6370_LED_PWM_MODE = 0, + MT6370_LED_BREATH_MODE, + MT6370_LED_REG_MODE, + MT6370_LED_MAX_MODE +}; + +enum mt6370_led_field { + F_RGB_EN = 0, + F_CHGIND_EN, + F_LED1_CURR, + F_LED2_CURR, + F_LED3_CURR, + F_LED4_CURR, + F_LED1_MODE, + F_LED2_MODE, + F_LED3_MODE, + F_LED4_MODE, + F_LED1_DUTY, + F_LED2_DUTY, + F_LED3_DUTY, + F_LED4_DUTY, + F_LED1_FREQ, + F_LED2_FREQ, + F_LED3_FREQ, + F_LED4_FREQ, + F_MAX_FIELDS +}; + +enum mt6370_led_ranges { + R_LED123_CURR = 0, + R_LED4_CURR, + R_LED_TRFON, + R_LED_TOFF, + R_MAX_RANGES +}; + +enum mt6370_pattern { + P_LED_TR1 = 0, + P_LED_TR2, + P_LED_TF1, + P_LED_TF2, + P_LED_TON, + P_LED_TOFF, + P_MAX_PATTERNS +}; + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_RGB1_DIM 0x182 +#define MT6370_REG_RGB2_DIM 0x183 +#define MT6370_REG_RGB3_DIM 0x184 +#define MT6370_REG_RGB_EN 0x185 +#define MT6370_REG_RGB1_ISNK 0x186 +#define MT6370_REG_RGB2_ISNK 0x187 +#define MT6370_REG_RGB3_ISNK 0x188 +#define MT6370_REG_RGB1_TR 0x189 +#define MT6370_REG_RGB_CHRIND_DIM 0x192 +#define MT6370_REG_RGB_CHRIND_CTRL 0x193 +#define MT6370_REG_RGB_CHRIND_TR 0x194 + +#define MT6372_REG_RGB_EN 0x182 +#define MT6372_REG_RGB1_ISNK 0x183 +#define MT6372_REG_RGB2_ISNK 0x184 +#define MT6372_REG_RGB3_ISNK 0x185 +#define MT6372_REG_RGB4_ISNK 0x186 +#define MT6372_REG_RGB1_DIM 0x187 +#define MT6372_REG_RGB2_DIM 0x188 +#define MT6372_REG_RGB3_DIM 0x189 +#define MT6372_REG_RGB4_DIM 0x18A +#define MT6372_REG_RGB12_FREQ 0x18B +#define MT6372_REG_RGB34_FREQ 0x18C +#define MT6372_REG_RGB1_TR 0x18D + +#define MT6370_VENDOR_ID_MASK GENMASK(7, 4) +#define MT6372_VENDOR_ID 0x9 +#define MT6372C_VENDOR_ID 0xb +#define MT6370_CHEN_BIT(id) BIT(MT6370_LED_ISNK4 - id) +#define MT6370_VIRTUAL_MULTICOLOR 5 +#define MC_CHANNEL_NUM 3 +#define MT6370_PWM_DUTY (BIT(5) - 1) +#define MT6372_PWM_DUTY (BIT(8) - 1) + +struct mt6370_led { + /* + * If the color of the LED in DT is set to + * - 'LED_COLOR_ID_RGB' + * - 'LED_COLOR_ID_MULTI' + * The member 'index' of this struct will be set to + * 'MT6370_VIRTUAL_MULTICOLOR'. + * If so, this LED will choose 'struct led_classdev_mc mc' to use. + * Instead, if the member 'index' of this struct is set to + * 'MT6370_LED_ISNK1' ~ 'MT6370_LED_ISNK4', then this LED will choose + * 'struct led_classdev isink' to use. + */ + union { + struct led_classdev isink; + struct led_classdev_mc mc; + }; + struct mt6370_priv *priv; + enum led_default_state default_state; + u32 index; +}; + +struct mt6370_pdata { + const unsigned int *tfreq; + unsigned int tfreq_len; + u16 reg_rgb1_tr; + s16 reg_rgb_chrind_tr; + u8 pwm_duty; +}; + +struct mt6370_priv { + /* Per LED access lock */ + struct mutex lock; + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + const struct reg_field *reg_fields; + const struct linear_range *ranges; + struct reg_cfg *reg_cfgs; + const struct mt6370_pdata *pdata; + unsigned int leds_count; + unsigned int leds_active; + struct mt6370_led leds[]; +}; + +static const struct reg_field common_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6370_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7), + [F_LED1_CURR] = REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2), + [F_LED2_CURR] = REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2), + [F_LED3_CURR] = REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2), + [F_LED4_CURR] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1), + [F_LED1_MODE] = REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6), + [F_LED2_MODE] = REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6), + [F_LED3_MODE] = REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6), + [F_LED4_MODE] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6), + [F_LED1_DUTY] = REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4), + [F_LED2_DUTY] = REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4), + [F_LED3_DUTY] = REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4), + [F_LED4_DUTY] = REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4), + [F_LED1_FREQ] = REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5), + [F_LED2_FREQ] = REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5), + [F_LED3_FREQ] = REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5), + [F_LED4_FREQ] = REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4), +}; + +static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = { + [F_RGB_EN] = REG_FIELD(MT6372_REG_RGB_EN, 4, 7), + [F_CHGIND_EN] = REG_FIELD(MT6372_REG_RGB_EN, 3, 3), + [F_LED1_CURR] = REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3), + [F_LED2_CURR] = REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3), + [F_LED3_CURR] = REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3), + [F_LED4_CURR] = REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3), + [F_LED1_MODE] = REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7), + [F_LED2_MODE] = REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7), + [F_LED3_MODE] = REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7), + [F_LED4_MODE] = REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7), + [F_LED1_DUTY] = REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7), + [F_LED2_DUTY] = REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7), + [F_LED3_DUTY] = REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7), + [F_LED4_DUTY] = REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7), + [F_LED1_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7), + [F_LED2_FREQ] = REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4), + [F_LED3_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7), + [F_LED4_FREQ] = REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4), +}; + +/* Current unit: microamp, time unit: millisecond */ +static const struct linear_range common_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 4000, 1, 6, 4000 }, + [R_LED4_CURR] = { 2000, 1, 3, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 200 }, + [R_LED_TOFF] = { 250, 0, 15, 400 }, +}; + +static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = { + [R_LED123_CURR] = { 2000, 1, 14, 2000 }, + [R_LED4_CURR] = { 2000, 1, 14, 2000 }, + [R_LED_TRFON] = { 125, 0, 15, 250 }, + [R_LED_TOFF] = { 250, 0, 15, 500 }, +}; + +static const unsigned int common_tfreqs[] = { + 10000, 5000, 2000, 1000, 500, 200, 5, 1, +}; + +static const unsigned int mt6372_tfreqs[] = { + 8000, 4000, 2000, 1000, 500, 250, 8, 4, +}; + +static const struct mt6370_pdata common_pdata = { + .tfreq = common_tfreqs, + .tfreq_len = ARRAY_SIZE(common_tfreqs), + .pwm_duty = MT6370_PWM_DUTY, + .reg_rgb1_tr = MT6370_REG_RGB1_TR, + .reg_rgb_chrind_tr = MT6370_REG_RGB_CHRIND_TR, +}; + +static const struct mt6370_pdata mt6372_pdata = { + .tfreq = mt6372_tfreqs, + .tfreq_len = ARRAY_SIZE(mt6372_tfreqs), + .pwm_duty = MT6372_PWM_DUTY, + .reg_rgb1_tr = MT6372_REG_RGB1_TR, + .reg_rgb_chrind_tr = -1, +}; + +static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no) +{ + switch (led_no) { + case MT6370_LED_ISNK1: + return F_LED1_CURR; + case MT6370_LED_ISNK2: + return F_LED2_CURR; + case MT6370_LED_ISNK3: + return F_LED3_CURR; + default: + return F_LED4_CURR; + } +} + +static int mt6370_set_led_brightness(struct mt6370_priv *priv, unsigned int led_no, + unsigned int level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_write(priv->fields[sel_field], level); +} + +static int mt6370_get_led_brightness(struct mt6370_priv *priv, unsigned int led_no, + unsigned int *level) +{ + enum mt6370_led_field sel_field; + + sel_field = mt6370_get_led_current_field(led_no); + + return regmap_field_read(priv->fields[sel_field], level); +} + +static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no, unsigned int ton, + unsigned int toff) +{ + const struct mt6370_pdata *pdata = priv->pdata; + enum mt6370_led_field sel_field; + unsigned int divisor, ratio; + + divisor = pdata->pwm_duty; + ratio = ton * divisor / (ton + toff); + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_DUTY; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_DUTY; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_DUTY; + break; + default: + sel_field = F_LED4_DUTY; + break; + } + + return regmap_field_write(priv->fields[sel_field], ratio); +} + +static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no, unsigned int ton, + unsigned int toff) +{ + const struct mt6370_pdata *pdata = priv->pdata; + enum mt6370_led_field sel_field; + unsigned int tfreq_len = pdata->tfreq_len; + unsigned int tsum, sel; + + tsum = ton + toff; + + if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1]) + return -EOPNOTSUPP; + + sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len); + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_FREQ; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_FREQ; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_FREQ; + break; + default: + sel_field = F_LED4_FREQ; + break; + } + + return regmap_field_write(priv->fields[sel_field], sel); +} + +static void mt6370_get_breath_reg_base(struct mt6370_priv *priv, unsigned int led_no, + unsigned int *base) +{ + const struct mt6370_pdata *pdata = priv->pdata; + + if (pdata->reg_rgb_chrind_tr < 0) { + *base = pdata->reg_rgb1_tr + led_no * 3; + return; + } + + switch (led_no) { + case MT6370_LED_ISNK1: + case MT6370_LED_ISNK2: + case MT6370_LED_ISNK3: + *base = pdata->reg_rgb1_tr + led_no * 3; + break; + default: + *base = pdata->reg_rgb_chrind_tr; + break; + } +} + +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv, struct led_pattern *pattern, u32 len, + u8 *pattern_val, u32 val_len) +{ + enum mt6370_led_ranges sel_range; + struct led_pattern *curr; + unsigned int sel; + u32 val = 0; + int i; + + if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2) + return -EINVAL; + + /* + * Pattern list + * tr1: byte 0, b'[7:4] + * tr2: byte 0, b'[3:0] + * tf1: byte 1, b'[7:4] + * tf2: byte 1, b'[3:0] + * ton: byte 2, b'[7:4] + * toff: byte 2, b'[3:0] + */ + for (i = 0; i < P_MAX_PATTERNS; i++) { + curr = pattern + i; + + sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON; + + linear_range_get_selector_within(priv->ranges + sel_range, curr->delta_t, &sel); + + if (i % 2) { + val |= sel; + } else { + val <<= 8; + val |= sel << 4; + } + } + + put_unaligned_be24(val, pattern_val); + + return 0; +} + +static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no, + enum mt6370_led_mode mode) +{ + enum mt6370_led_field sel_field; + + switch (led_no) { + case MT6370_LED_ISNK1: + sel_field = F_LED1_MODE; + break; + case MT6370_LED_ISNK2: + sel_field = F_LED2_MODE; + break; + case MT6370_LED_ISNK3: + sel_field = F_LED3_MODE; + break; + default: + sel_field = F_LED4_MODE; + break; + } + + return regmap_field_write(priv->fields[sel_field], mode); +} + +static int mt6370_mc_brightness_set(struct led_classdev *lcdev, enum led_brightness level) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + led_mc_calc_color_components(mccdev, level); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out_unlock; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + u32 brightness; + + subled = mccdev->subled_info + i; + brightness = min(subled->brightness, lcdev->max_brightness); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + if (level == 0) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); + if (ret) + goto out_unlock; + + continue; + } + + if (brightness == 0) { + enable &= ~MT6370_CHEN_BIT(subled->channel); + continue; + } + + enable |= MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_brightness(priv, subled->channel, brightness); + if (ret) + goto out_unlock; + } + + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out_unlock; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_blink_set(struct led_classdev *lcdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int enable, disable; + int i, ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out_unlock; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = mt6370_set_led_duty(priv, subled->channel, *delay_on, *delay_off); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_freq(priv, subled->channel, *delay_on, *delay_off); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_PWM_MODE); + if (ret) + goto out_unlock; + } + + /* Toggle to make pattern timing the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out_unlock; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_mc_pattern_set(struct led_classdev *lcdev, struct led_pattern *pattern, u32 len, + int repeat) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + unsigned int reg_base, enable, disable; + u8 params[P_MAX_PATTERNS / 2]; + int i, ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, sizeof(params)); + if (ret) + goto out_unlock; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out_unlock; + + disable = enable; + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + mt6370_get_breath_reg_base(priv, subled->channel, ®_base); + disable &= ~MT6370_CHEN_BIT(subled->channel); + + ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_BREATH_MODE); + if (ret) + goto out_unlock; + } + + /* Toggle to make pattern timing be the same */ + ret = regmap_field_write(priv->fields[F_RGB_EN], disable); + if (ret) + goto out_unlock; + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev) +{ + struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev); + struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); + struct mt6370_priv *priv = led->priv; + struct mc_subled *subled; + int i, ret; + + mutex_lock(&led->priv->lock); + + for (i = 0; i < mccdev->num_colors; i++) { + subled = mccdev->subled_info + i; + + ret = mt6370_set_led_mode(priv, subled->channel, MT6370_LED_REG_MODE); + if (ret) + break; + } + + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_isnk_brightness_set(struct led_classdev *lcdev, + enum led_brightness level) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int enable; + int ret; + + mutex_lock(&priv->lock); + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + goto out_unlock; + + if (level == 0) { + enable &= ~MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); + if (ret) + goto out_unlock; + } else { + enable |= MT6370_CHEN_BIT(led->index); + + ret = mt6370_set_led_brightness(priv, led->index, level); + if (ret) + goto out_unlock; + } + + ret = regmap_field_write(priv->fields[F_RGB_EN], enable); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_blink_set(struct led_classdev *lcdev, unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&priv->lock); + + if (!*delay_on && !*delay_off) + *delay_on = *delay_off = 500; + + ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static int mt6370_isnk_pattern_set(struct led_classdev *lcdev, struct led_pattern *pattern, u32 len, + int repeat) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + unsigned int reg_base; + u8 params[P_MAX_PATTERNS / 2]; + int ret; + + mutex_lock(&priv->lock); + + ret = mt6370_gen_breath_pattern(priv, pattern, len, params, sizeof(params)); + if (ret) + goto out_unlock; + + mt6370_get_breath_reg_base(priv, led->index, ®_base); + + ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params)); + if (ret) + goto out_unlock; + + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE); + +out_unlock: + mutex_unlock(&priv->lock); + + return ret; +} + +static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev) +{ + struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink); + struct mt6370_priv *priv = led->priv; + int ret; + + mutex_lock(&led->priv->lock); + ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE); + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int mt6370_assign_multicolor_info(struct device *dev, struct mt6370_led *led, + struct fwnode_handle *fwnode) +{ + struct mt6370_priv *priv = led->priv; + struct fwnode_handle *child; + struct mc_subled *sub_led; + u32 num_color = 0; + int ret; + + sub_led = devm_kcalloc(dev, MC_CHANNEL_NUM, sizeof(*sub_led), GFP_KERNEL); + if (!sub_led) + return -ENOMEM; + + fwnode_for_each_child_node(fwnode, child) { + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg > MT6370_LED_ISNK3 || priv->leds_active & BIT(reg)) { + fwnode_handle_put(child); + return -EINVAL; + } + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, "LED %d, no color specified\n", led->index); + } + + priv->leds_active |= BIT(reg); + sub_led[num_color].color_index = color; + sub_led[num_color].channel = reg; + sub_led[num_color].intensity = 0; + num_color++; + } + + if (num_color < 2) + return dev_err_probe(dev, -EINVAL, + "Multicolor must include 2 or more LED channels\n"); + + led->mc.num_colors = num_color; + led->mc.subled_info = sub_led; + + return 0; +} + +static int mt6370_init_led_properties(struct device *dev, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + struct led_classdev *lcdev; + enum mt6370_led_ranges sel_range; + u32 max_uA, max_level; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) { + ret = mt6370_assign_multicolor_info(dev, led, init_data->fwnode); + if (ret) + return ret; + + lcdev = &led->mc.led_cdev; + lcdev->brightness_set_blocking = mt6370_mc_brightness_set; + lcdev->blink_set = mt6370_mc_blink_set; + lcdev->pattern_set = mt6370_mc_pattern_set; + lcdev->pattern_clear = mt6370_mc_pattern_clear; + } else { + lcdev = &led->isink; + lcdev->brightness_set_blocking = mt6370_isnk_brightness_set; + lcdev->blink_set = mt6370_isnk_blink_set; + lcdev->pattern_set = mt6370_isnk_pattern_set; + lcdev->pattern_clear = mt6370_isnk_pattern_clear; + } + + ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &max_uA); + if (ret) { + dev_warn(dev, "Not specified led-max-microamp, config to the minimum\n"); + max_uA = 0; + } + + if (led->index == MT6370_LED_ISNK4) + sel_range = R_LED4_CURR; + else + sel_range = R_LED123_CURR; + + linear_range_get_selector_within(priv->ranges + sel_range, max_uA, &max_level); + + lcdev->max_brightness = max_level; + + led->default_state = led_init_default_state_get(init_data->fwnode); + + return 0; +} + +static int mt6370_isnk_init_default_state(struct mt6370_led *led) +{ + struct mt6370_priv *priv = led->priv; + unsigned int enable, level; + int ret; + + ret = mt6370_get_led_brightness(priv, led->index, &level); + if (ret) + return ret; + + ret = regmap_field_read(priv->fields[F_RGB_EN], &enable); + if (ret) + return ret; + + if (!(enable & MT6370_CHEN_BIT(led->index))) + level = 0; + + switch (led->default_state) { + case LEDS_DEFSTATE_ON: + led->isink.brightness = led->isink.max_brightness; + break; + case LEDS_DEFSTATE_KEEP: + led->isink.brightness = min(level, led->isink.max_brightness); + break; + default: + led->isink.brightness = 0; + break; + } + + return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness); +} + +static int mt6370_multicolor_led_register(struct device *dev, struct mt6370_led *led, + struct led_init_data *init_data) +{ + int ret; + + ret = mt6370_mc_brightness_set(&led->mc.led_cdev, 0); + if (ret) + return dev_err_probe(dev, ret, "Couldn't set multicolor brightness\n"); + + ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc, init_data); + if (ret) + return dev_err_probe(dev, ret, "Couldn't register multicolor\n"); + + return 0; +} + +static int mt6370_led_register(struct device *dev, struct mt6370_led *led, + struct led_init_data *init_data) +{ + struct mt6370_priv *priv = led->priv; + int ret; + + if (led->index == MT6370_VIRTUAL_MULTICOLOR) + return mt6370_multicolor_led_register(dev, led, init_data); + + /* If ISNK4 is declared, change its mode from HW auto to SW control */ + if (led->index == MT6370_LED_ISNK4) { + ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1); + if (ret) + return dev_err_probe(dev, ret, "Failed to set CHRIND to SW\n"); + } + + ret = mt6370_isnk_init_default_state(led); + if (ret) + return dev_err_probe(dev, ret, "Failed to init %d isnk state\n", led->index); + + ret = devm_led_classdev_register_ext(dev, &led->isink, init_data); + if (ret) + return dev_err_probe(dev, ret, "Couldn't register isink %d\n", led->index); + + return 0; +} + +static int mt6370_check_vendor_info(struct mt6370_priv *priv) +{ + unsigned int devinfo, vid; + int ret; + + ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + vid = FIELD_GET(MT6370_VENDOR_ID_MASK, devinfo); + if (vid == MT6372_VENDOR_ID || vid == MT6372C_VENDOR_ID) { + priv->reg_fields = mt6372_reg_fields; + priv->ranges = mt6372_led_ranges; + priv->pdata = &mt6372_pdata; + } else { + /* Common for MT6370/71 */ + priv->reg_fields = common_reg_fields; + priv->ranges = common_led_ranges; + priv->pdata = &common_pdata; + } + + return 0; +} + +static int mt6370_leds_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mt6370_priv *priv; + struct fwnode_handle *child; + size_t count; + unsigned int i = 0; + int ret; + + count = device_get_child_node_count(dev); + if (!count || count > MT6370_MAX_LEDS) + return dev_err_probe(dev, -EINVAL, + "No child node or node count over max LED number %zu\n", + count); + + priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->leds_count = count; + mutex_init(&priv->lock); + + priv->regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->regmap) + return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n"); + + ret = mt6370_check_vendor_info(priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to check vendor info\n"); + + ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields, priv->reg_fields, + F_MAX_FIELDS); + if (ret) + return dev_err_probe(dev, ret, "Failed to allocate regmap field\n"); + + device_for_each_child_node(dev, child) { + struct mt6370_led *led = priv->leds + i++; + struct led_init_data init_data = { .fwnode = child }; + u32 reg, color; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + dev_err(dev, "Failed to parse reg property\n"); + goto fwnode_release; + } + + if (reg >= MT6370_MAX_LEDS) { + ret = -EINVAL; + dev_err(dev, "Error reg property number\n"); + goto fwnode_release; + } + + ret = fwnode_property_read_u32(child, "color", &color); + if (ret) { + dev_err(dev, "Failed to parse color property\n"); + goto fwnode_release; + } + + if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI) + reg = MT6370_VIRTUAL_MULTICOLOR; + + if (priv->leds_active & BIT(reg)) { + ret = -EINVAL; + dev_err(dev, "Duplicate reg property\n"); + goto fwnode_release; + } + + priv->leds_active |= BIT(reg); + + led->index = reg; + led->priv = priv; + + ret = mt6370_init_led_properties(dev, led, &init_data); + if (ret) + goto fwnode_release; + + ret = mt6370_led_register(dev, led, &init_data); + if (ret) + goto fwnode_release; + } + + return 0; + +fwnode_release: + fwnode_handle_put(child); + return ret; +} + +static const struct of_device_id mt6370_rgbled_device_table[] = { + { .compatible = "mediatek,mt6370-indicator" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table); + +static struct platform_driver mt6370_rgbled_driver = { + .driver = { + .name = "mt6370-indicator", + .of_match_table = mt6370_rgbled_device_table, + }, + .probe = mt6370_leds_probe, +}; +module_platform_driver(mt6370_rgbled_driver); + +MODULE_AUTHOR("Alice Chen "); +MODULE_AUTHOR("ChiYuan Huang "); +MODULE_DESCRIPTION("MediaTek MT6370 RGB LED Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c index da9d2218ae18..46cd062b8b24 100644 --- a/drivers/leds/rgb/leds-pwm-multicolor.c +++ b/drivers/leds/rgb/leds-pwm-multicolor.c @@ -158,8 +158,8 @@ static int led_pwm_mc_probe(struct platform_device *pdev) ret = led_pwm_mc_set(cdev, cdev->brightness); if (ret) return dev_err_probe(&pdev->dev, ret, - "failed to set led PWM value for %s: %d", - cdev->name, ret); + "failed to set led PWM value for %s\n", + cdev->name); platform_set_drvdata(pdev, priv); return 0; diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 67f48f222109..1c849814a491 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2017-2022 Linaro Ltd * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -17,10 +18,13 @@ #define LPG_SUBTYPE_REG 0x05 #define LPG_SUBTYPE_LPG 0x2 #define LPG_SUBTYPE_PWM 0xb +#define LPG_SUBTYPE_HI_RES_PWM 0xc #define LPG_SUBTYPE_LPG_LITE 0x11 #define LPG_PATTERN_CONFIG_REG 0x40 #define LPG_SIZE_CLK_REG 0x41 #define PWM_CLK_SELECT_MASK GENMASK(1, 0) +#define PWM_CLK_SELECT_HI_RES_MASK GENMASK(2, 0) +#define PWM_SIZE_HI_RES_MASK GENMASK(6, 4) #define LPG_PREDIV_CLK_REG 0x42 #define PWM_FREQ_PRE_DIV_MASK GENMASK(6, 5) #define PWM_FREQ_EXP_MASK GENMASK(2, 0) @@ -43,8 +47,10 @@ #define LPG_LUT_REG(x) (0x40 + (x) * 2) #define RAMP_CONTROL_REG 0xc8 -#define LPG_RESOLUTION 512 +#define LPG_RESOLUTION_9BIT BIT(9) +#define LPG_RESOLUTION_15BIT BIT(15) #define LPG_MAX_M 7 +#define LPG_MAX_PREDIV 6 struct lpg_channel; struct lpg_data; @@ -106,6 +112,7 @@ struct lpg { * @clk_sel: reference clock frequency selector * @pre_div_sel: divider selector of the reference clock * @pre_div_exp: exponential divider of the reference clock + * @pwm_resolution_sel: pwm resolution selector * @ramp_enabled: duty cycle is driven by iterating over lookup table * @ramp_ping_pong: reverse through pattern, rather than wrapping to start * @ramp_oneshot: perform only a single pass over the pattern @@ -138,6 +145,7 @@ struct lpg_channel { unsigned int clk_sel; unsigned int pre_div_sel; unsigned int pre_div_exp; + unsigned int pwm_resolution_sel; bool ramp_enabled; bool ramp_ping_pong; @@ -253,17 +261,24 @@ static int lpg_lut_sync(struct lpg *lpg, unsigned int mask) } static const unsigned int lpg_clk_rates[] = {0, 1024, 32768, 19200000}; +static const unsigned int lpg_clk_rates_hi_res[] = {0, 1024, 32768, 19200000, 76800000}; static const unsigned int lpg_pre_divs[] = {1, 3, 5, 6}; +static const unsigned int lpg_pwm_resolution[] = {9}; +static const unsigned int lpg_pwm_resolution_hi_res[] = {8, 9, 10, 11, 12, 13, 14, 15}; static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period) { - unsigned int clk_sel, best_clk = 0; + unsigned int i, pwm_resolution_count, best_pwm_resolution_sel = 0; + const unsigned int *clk_rate_arr, *pwm_resolution_arr; + unsigned int clk_sel, clk_len, best_clk = 0; unsigned int div, best_div = 0; unsigned int m, best_m = 0; + unsigned int resolution; unsigned int error; unsigned int best_err = UINT_MAX; + u64 max_period, min_period; u64 best_period = 0; - u64 max_period; + u64 max_res; /* * The PWM period is determined by: @@ -272,73 +287,107 @@ static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period) * period = -------------------------- * refclk * - * With resolution fixed at 2^9 bits, pre_div = {1, 3, 5, 6} and + * Resolution = 2^9 bits for PWM or + * 2^{8, 9, 10, 11, 12, 13, 14, 15} bits for high resolution PWM + * pre_div = {1, 3, 5, 6} and * M = [0..7]. * - * This allows for periods between 27uS and 384s, as the PWM framework - * wants a period of equal or lower length than requested, reject - * anything below 27uS. + * This allows for periods between 27uS and 384s for PWM channels and periods between + * 3uS and 24576s for high resolution PWMs. + * The PWM framework wants a period of equal or lower length than requested, + * reject anything below minimum period. */ - if (period <= (u64)NSEC_PER_SEC * LPG_RESOLUTION / 19200000) + + if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { + clk_rate_arr = lpg_clk_rates_hi_res; + clk_len = ARRAY_SIZE(lpg_clk_rates_hi_res); + pwm_resolution_arr = lpg_pwm_resolution_hi_res; + pwm_resolution_count = ARRAY_SIZE(lpg_pwm_resolution_hi_res); + max_res = LPG_RESOLUTION_15BIT; + } else { + clk_rate_arr = lpg_clk_rates; + clk_len = ARRAY_SIZE(lpg_clk_rates); + pwm_resolution_arr = lpg_pwm_resolution; + pwm_resolution_count = ARRAY_SIZE(lpg_pwm_resolution); + max_res = LPG_RESOLUTION_9BIT; + } + + min_period = div64_u64((u64)NSEC_PER_SEC * (1 << pwm_resolution_arr[0]), + clk_rate_arr[clk_len - 1]); + if (period <= min_period) return -EINVAL; /* Limit period to largest possible value, to avoid overflows */ - max_period = (u64)NSEC_PER_SEC * LPG_RESOLUTION * 6 * (1 << LPG_MAX_M) / 1024; + max_period = div64_u64((u64)NSEC_PER_SEC * max_res * LPG_MAX_PREDIV * (1 << LPG_MAX_M), + 1024); if (period > max_period) period = max_period; /* - * Search for the pre_div, refclk and M by solving the rewritten formula - * for each refclk and pre_div value: + * Search for the pre_div, refclk, resolution and M by solving the rewritten formula + * for each refclk, resolution and pre_div value: * * period * refclk * M = log2 ------------------------------------- * NSEC_PER_SEC * pre_div * resolution */ - for (clk_sel = 1; clk_sel < ARRAY_SIZE(lpg_clk_rates); clk_sel++) { - u64 numerator = period * lpg_clk_rates[clk_sel]; - for (div = 0; div < ARRAY_SIZE(lpg_pre_divs); div++) { - u64 denominator = (u64)NSEC_PER_SEC * lpg_pre_divs[div] * LPG_RESOLUTION; - u64 actual; - u64 ratio; + for (i = 0; i < pwm_resolution_count; i++) { + resolution = 1 << pwm_resolution_arr[i]; + for (clk_sel = 1; clk_sel < clk_len; clk_sel++) { + u64 numerator = period * clk_rate_arr[clk_sel]; - if (numerator < denominator) - continue; + for (div = 0; div < ARRAY_SIZE(lpg_pre_divs); div++) { + u64 denominator = (u64)NSEC_PER_SEC * lpg_pre_divs[div] * + resolution; + u64 actual; + u64 ratio; - ratio = div64_u64(numerator, denominator); - m = ilog2(ratio); - if (m > LPG_MAX_M) - m = LPG_MAX_M; + if (numerator < denominator) + continue; - actual = DIV_ROUND_UP_ULL(denominator * (1 << m), lpg_clk_rates[clk_sel]); + ratio = div64_u64(numerator, denominator); + m = ilog2(ratio); + if (m > LPG_MAX_M) + m = LPG_MAX_M; - error = period - actual; - if (error < best_err) { - best_err = error; - - best_div = div; - best_m = m; - best_clk = clk_sel; - best_period = actual; + actual = DIV_ROUND_UP_ULL(denominator * (1 << m), + clk_rate_arr[clk_sel]); + error = period - actual; + if (error < best_err) { + best_err = error; + best_div = div; + best_m = m; + best_clk = clk_sel; + best_period = actual; + best_pwm_resolution_sel = i; + } } } } - chan->clk_sel = best_clk; chan->pre_div_sel = best_div; chan->pre_div_exp = best_m; chan->period = best_period; - + chan->pwm_resolution_sel = best_pwm_resolution_sel; return 0; } static void lpg_calc_duty(struct lpg_channel *chan, uint64_t duty) { - unsigned int max = LPG_RESOLUTION - 1; + unsigned int max; unsigned int val; + unsigned int clk_rate; - val = div64_u64(duty * lpg_clk_rates[chan->clk_sel], + if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { + max = LPG_RESOLUTION_15BIT - 1; + clk_rate = lpg_clk_rates_hi_res[chan->clk_sel]; + } else { + max = LPG_RESOLUTION_9BIT - 1; + clk_rate = lpg_clk_rates[chan->clk_sel]; + } + + val = div64_u64(duty * clk_rate, (u64)NSEC_PER_SEC * lpg_pre_divs[chan->pre_div_sel] * (1 << chan->pre_div_exp)); chan->pwm_value = min(val, max); @@ -354,7 +403,7 @@ static void lpg_apply_freq(struct lpg_channel *chan) val = chan->clk_sel; - /* Specify 9bit resolution, based on the subtype of the channel */ + /* Specify resolution, based on the subtype of the channel */ switch (chan->subtype) { case LPG_SUBTYPE_LPG: val |= GENMASK(5, 4); @@ -362,6 +411,9 @@ static void lpg_apply_freq(struct lpg_channel *chan) case LPG_SUBTYPE_PWM: val |= BIT(2); break; + case LPG_SUBTYPE_HI_RES_PWM: + val |= FIELD_PREP(PWM_SIZE_HI_RES_MASK, chan->pwm_resolution_sel); + break; case LPG_SUBTYPE_LPG_LITE: default: val |= BIT(4); @@ -670,7 +722,7 @@ static int lpg_blink_set(struct lpg_led *led, triled_set(lpg, triled_mask, triled_mask); chan = led->channels[0]; - duty = div_u64(chan->pwm_value * chan->period, LPG_RESOLUTION); + duty = div_u64(chan->pwm_value * chan->period, LPG_RESOLUTION_9BIT); *delay_on = div_u64(duty, NSEC_PER_MSEC); *delay_off = div_u64(chan->period - duty, NSEC_PER_MSEC); @@ -977,6 +1029,7 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, { struct lpg *lpg = container_of(chip, struct lpg, pwm); struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; + unsigned int resolution; unsigned int pre_div; unsigned int refclk; unsigned int val; @@ -988,7 +1041,14 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) return ret; - refclk = lpg_clk_rates[val & PWM_CLK_SELECT_MASK]; + if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { + refclk = lpg_clk_rates_hi_res[FIELD_GET(PWM_CLK_SELECT_HI_RES_MASK, val)]; + resolution = lpg_pwm_resolution_hi_res[FIELD_GET(PWM_SIZE_HI_RES_MASK, val)]; + } else { + refclk = lpg_clk_rates[FIELD_GET(PWM_CLK_SELECT_MASK, val)]; + resolution = 9; + } + if (refclk) { ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); if (ret) @@ -1001,7 +1061,8 @@ static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) return ret; - state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * LPG_RESOLUTION * pre_div * (1 << m), refclk); + state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * (1 << resolution) * + pre_div * (1 << m), refclk); state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); } else { state->period = 0; @@ -1149,7 +1210,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) } cdev->default_trigger = of_get_property(np, "linux,default-trigger", NULL); - cdev->max_brightness = LPG_RESOLUTION - 1; + cdev->max_brightness = LPG_RESOLUTION_9BIT - 1; if (!of_property_read_string(np, "default-state", &state) && !strcmp(state, "on")) @@ -1429,6 +1490,14 @@ static const struct lpg_data pm8350c_pwm_data = { }, }; +static const struct lpg_data pmk8550_pwm_data = { + .num_channels = 2, + .channels = (const struct lpg_channel_data[]) { + { .base = 0xe800 }, + { .base = 0xe900 }, + }, +}; + static const struct of_device_id lpg_of_table[] = { { .compatible = "qcom,pm8150b-lpg", .data = &pm8150b_lpg_data }, { .compatible = "qcom,pm8150l-lpg", .data = &pm8150l_lpg_data }, @@ -1439,6 +1508,7 @@ static const struct of_device_id lpg_of_table[] = { { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data }, + { .compatible = "qcom,pmk8550-pwm", .data = &pmk8550_pwm_data }, {} }; MODULE_DEVICE_TABLE(of, lpg_of_table); diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index dc6816d36d06..2a57328eca20 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -83,6 +83,7 @@ config LEDS_TRIGGER_ACTIVITY config LEDS_TRIGGER_GPIO tristate "LED GPIO Trigger" depends on GPIOLIB || COMPILE_TEST + depends on BROKEN help This allows LEDs to be controlled by gpio events. It's good when using gpios as switches and triggering the needed LEDs diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 539a2ed4e13d..a0e717a986dc 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -86,6 +86,7 @@ config ADB_PMU_LED config ADB_PMU_LED_DISK bool "Use front LED as DISK LED by default" + depends on ATA depends on ADB_PMU_LED depends on LEDS_CLASS select LEDS_TRIGGERS diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 23bd0c77ac1a..057b0221f695 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -80,7 +80,7 @@ static struct adb_driver *adb_controller; BLOCKING_NOTIFIER_HEAD(adb_client_list); static int adb_got_sleep; static int adb_inited; -static DEFINE_SEMAPHORE(adb_probe_mutex); +static DEFINE_SEMAPHORE(adb_probe_mutex, 1); static int sleepy_trackpad; static int autopoll_devs; int __adb_probe_sync; @@ -888,7 +888,7 @@ adbdev_init(void) return; } - adb_dev_class = class_create(THIS_MODULE, "adb"); + adb_dev_class = class_create("adb"); if (IS_ERR(adb_dev_class)) return; device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index c28893e41a8b..40240bce77b0 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -387,7 +387,7 @@ static int rackmeter_probe(struct macio_dev* mdev, if (of_node_name_eq(np, "lightshow")) break; if (of_node_name_eq(np, "sound") && - of_get_property(np, "virtual", NULL) != NULL) + of_property_present(np, "virtual")) break; } if (np == NULL) { diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 8f5db9093c9a..384b87d661e1 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -483,7 +483,7 @@ static int probe_thermostat(struct i2c_client *client) if (vers != 1) return -ENXIO; - if (of_get_property(np, "hwsensor-location", NULL)) { + if (of_property_present(np, "hwsensor-location")) { for (i = 0; i < 3; i++) { sensor_location[i] = of_get_property(np, "hwsensor-location", NULL) + offset; diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index ebc4256a9e4a..089f2743a070 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -171,6 +171,7 @@ static void wf_sat_release(struct kref *ref) if (sat->nr >= 0) sats[sat->nr] = NULL; + of_node_put(sat->node); kfree(sat); } diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 1495965bc394..bc2e265cb02d 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -176,7 +176,7 @@ config MAILBOX_TEST config POLARFIRE_SOC_MAILBOX tristate "PolarFire SoC (MPFS) Mailbox" depends on HAS_IOMEM - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST help This driver adds support for the PolarFire SoC (MPFS) mailbox controller. @@ -259,7 +259,7 @@ config MTK_CMDQ_MBOX during the vblank. config ZYNQMP_IPI_MBOX - bool "Xilinx ZynqMP IPI Mailbox" + tristate "Xilinx ZynqMP IPI Mailbox" depends on ARCH_ZYNQMP && OF help Say yes here to add support for Xilinx IPI mailbox driver. diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 8d3a4c1fe761..8c95e3ce295f 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -1635,7 +1635,7 @@ static struct platform_driver pdc_mbox_driver = { .remove = pdc_remove, .driver = { .name = "brcm-iproc-pdc-mbox", - .of_match_table = of_match_ptr(pdc_mbox_of_match), + .of_match_table = pdc_mbox_of_match, }, }; module_platform_driver(pdc_mbox_driver); diff --git a/drivers/mailbox/hi6220-mailbox.c b/drivers/mailbox/hi6220-mailbox.c index fca61f5312d9..1c73c63598f5 100644 --- a/drivers/mailbox/hi6220-mailbox.c +++ b/drivers/mailbox/hi6220-mailbox.c @@ -325,10 +325,7 @@ static int hi6220_mbox_probe(struct platform_device *pdev) writel(~0x0, ACK_INT_CLR_REG(mbox->ipc)); /* use interrupt for tx's ack */ - if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL)) - mbox->tx_irq_mode = false; - else - mbox->tx_irq_mode = true; + mbox->tx_irq_mode = !of_property_read_bool(node, "hi6220,mbox-tx-noirq"); if (mbox->tx_irq_mode) mbox->controller.txdone_irq = true; diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 4555d678fadd..fc6a12a51b40 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -38,6 +40,7 @@ struct mbox_test_device { char *signal; char *message; spinlock_t lock; + struct mutex mutex; wait_queue_head_t waitq; struct fasync_struct *async_queue; struct dentry *root_debugfs_dir; @@ -95,6 +98,7 @@ static ssize_t mbox_test_message_write(struct file *filp, size_t count, loff_t *ppos) { struct mbox_test_device *tdev = filp->private_data; + char *message; void *data; int ret; @@ -110,10 +114,13 @@ static ssize_t mbox_test_message_write(struct file *filp, return -EINVAL; } - tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); - if (!tdev->message) + message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); + if (!message) return -ENOMEM; + mutex_lock(&tdev->mutex); + + tdev->message = message; ret = copy_from_user(tdev->message, userbuf, count); if (ret) { ret = -EFAULT; @@ -144,6 +151,8 @@ out: kfree(tdev->message); tdev->signal = NULL; + mutex_unlock(&tdev->mutex); + return ret < 0 ? ret : count; } @@ -392,6 +401,7 @@ static int mbox_test_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tdev); spin_lock_init(&tdev->lock); + mutex_init(&tdev->mutex); if (tdev->rx_channel) { tdev->rx_buffer = devm_kzalloc(&pdev->dev, diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 4229b9b5da98..adf36c05fa43 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -317,6 +317,71 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout) } EXPORT_SYMBOL_GPL(mbox_flush); +static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) +{ + struct device *dev = cl->dev; + unsigned long flags; + int ret; + + if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) { + dev_dbg(dev, "%s: mailbox not free\n", __func__); + return -EBUSY; + } + + spin_lock_irqsave(&chan->lock, flags); + chan->msg_free = 0; + chan->msg_count = 0; + chan->active_req = NULL; + chan->cl = cl; + init_completion(&chan->tx_complete); + + if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) + chan->txdone_method = TXDONE_BY_ACK; + + spin_unlock_irqrestore(&chan->lock, flags); + + if (chan->mbox->ops->startup) { + ret = chan->mbox->ops->startup(chan); + + if (ret) { + dev_err(dev, "Unable to startup the chan (%d)\n", ret); + mbox_free_channel(chan); + return ret; + } + } + + return 0; +} + +/** + * mbox_bind_client - Request a mailbox channel. + * @chan: The mailbox channel to bind the client to. + * @cl: Identity of the client requesting the channel. + * + * The Client specifies its requirements and capabilities while asking for + * a mailbox channel. It can't be called from atomic context. + * The channel is exclusively allocated and can't be used by another + * client before the owner calls mbox_free_channel. + * After assignment, any packet received on this channel will be + * handed over to the client via the 'rx_callback'. + * The framework holds reference to the client, so the mbox_client + * structure shouldn't be modified until the mbox_free_channel returns. + * + * Return: 0 if the channel was assigned to the client successfully. + * <0 for request failure. + */ +int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) +{ + int ret; + + mutex_lock(&con_mutex); + ret = __mbox_bind_client(chan, cl); + mutex_unlock(&con_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mbox_bind_client); + /** * mbox_request_channel - Request a mailbox channel. * @cl: Identity of the client requesting the channel. @@ -340,7 +405,6 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) struct mbox_controller *mbox; struct of_phandle_args spec; struct mbox_chan *chan; - unsigned long flags; int ret; if (!dev || !dev->of_node) { @@ -372,33 +436,9 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) return chan; } - if (chan->cl || !try_module_get(mbox->dev->driver->owner)) { - dev_dbg(dev, "%s: mailbox not free\n", __func__); - mutex_unlock(&con_mutex); - return ERR_PTR(-EBUSY); - } - - spin_lock_irqsave(&chan->lock, flags); - chan->msg_free = 0; - chan->msg_count = 0; - chan->active_req = NULL; - chan->cl = cl; - init_completion(&chan->tx_complete); - - if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) - chan->txdone_method = TXDONE_BY_ACK; - - spin_unlock_irqrestore(&chan->lock, flags); - - if (chan->mbox->ops->startup) { - ret = chan->mbox->ops->startup(chan); - - if (ret) { - dev_err(dev, "Unable to startup the chan (%d)\n", ret); - mbox_free_channel(chan); - chan = ERR_PTR(ret); - } - } + ret = __mbox_bind_client(chan, cl); + if (ret) + chan = ERR_PTR(ret); mutex_unlock(&con_mutex); return chan; diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index 098c82d87137..fa2ce3246b70 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -417,8 +417,6 @@ struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl, struct device *dev = cl->dev; struct omap_mbox *mbox = NULL; struct omap_mbox_device *mdev; - struct mbox_chan *chan; - unsigned long flags; int ret; if (!dev) @@ -441,23 +439,11 @@ struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl, if (!mbox || !mbox->chan) return ERR_PTR(-ENOENT); - chan = mbox->chan; - spin_lock_irqsave(&chan->lock, flags); - chan->msg_free = 0; - chan->msg_count = 0; - chan->active_req = NULL; - chan->cl = cl; - init_completion(&chan->tx_complete); - spin_unlock_irqrestore(&chan->lock, flags); + ret = mbox_bind_client(mbox->chan, cl); + if (ret) + return ERR_PTR(ret); - ret = chan->mbox->ops->startup(chan); - if (ret) { - pr_err("Unable to startup the chan (%d)\n", ret); - mbox_free_channel(chan); - chan = ERR_PTR(ret); - } - - return chan; + return mbox->chan; } EXPORT_SYMBOL(omap_mbox_request_channel); @@ -763,8 +749,7 @@ static int omap_mbox_probe(struct platform_device *pdev) finfo->name = child->name; - if (of_find_property(child, "ti,mbox-send-noirq", NULL)) - finfo->send_no_irq = true; + finfo->send_no_irq = of_property_read_bool(child, "ti,mbox-send-noirq"); if (finfo->tx_id >= num_fifos || finfo->rx_id >= num_fifos || finfo->tx_usr >= num_users || finfo->rx_usr >= num_users) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 105d46c9801b..a44d4b3e5beb 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -282,8 +282,7 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) { struct pcc_chan_info *pchan; struct mbox_chan *chan; - struct device *dev; - unsigned long flags; + int rc; if (subspace_id < 0 || subspace_id >= pcc_chan_count) return ERR_PTR(-ENOENT); @@ -294,32 +293,10 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id) pr_err("Channel not found for idx: %d\n", subspace_id); return ERR_PTR(-EBUSY); } - dev = chan->mbox->dev; - spin_lock_irqsave(&chan->lock, flags); - chan->msg_free = 0; - chan->msg_count = 0; - chan->active_req = NULL; - chan->cl = cl; - init_completion(&chan->tx_complete); - - if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) - chan->txdone_method = TXDONE_BY_ACK; - - spin_unlock_irqrestore(&chan->lock, flags); - - if (pchan->plat_irq > 0) { - int rc; - - rc = devm_request_irq(dev, pchan->plat_irq, pcc_mbox_irq, 0, - MBOX_IRQ_NAME, chan); - if (unlikely(rc)) { - dev_err(dev, "failed to register PCC interrupt %d\n", - pchan->plat_irq); - pcc_mbox_free_channel(&pchan->chan); - return ERR_PTR(rc); - } - } + rc = mbox_bind_client(chan, cl); + if (rc) + return ERR_PTR(rc); return &pchan->chan; } @@ -333,23 +310,12 @@ EXPORT_SYMBOL_GPL(pcc_mbox_request_channel); */ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) { - struct pcc_chan_info *pchan_info = to_pcc_chan_info(pchan); struct mbox_chan *chan = pchan->mchan; - unsigned long flags; if (!chan || !chan->cl) return; - if (pchan_info->plat_irq > 0) - devm_free_irq(chan->mbox->dev, pchan_info->plat_irq, chan); - - spin_lock_irqsave(&chan->lock, flags); - chan->cl = NULL; - chan->active_req = NULL; - if (chan->txdone_method == TXDONE_BY_ACK) - chan->txdone_method = TXDONE_BY_POLL; - - spin_unlock_irqrestore(&chan->lock, flags); + mbox_free_channel(chan); } EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); @@ -377,8 +343,48 @@ static int pcc_send_data(struct mbox_chan *chan, void *data) return pcc_chan_reg_read_modify_write(&pchan->db); } +/** + * pcc_startup - Called from Mailbox Controller code. Used here + * to request the interrupt. + * @chan: Pointer to Mailbox channel to startup. + * + * Return: Err if something failed else 0 for success. + */ +static int pcc_startup(struct mbox_chan *chan) +{ + struct pcc_chan_info *pchan = chan->con_priv; + int rc; + + if (pchan->plat_irq > 0) { + rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq, 0, + MBOX_IRQ_NAME, chan); + if (unlikely(rc)) { + dev_err(chan->mbox->dev, "failed to register PCC interrupt %d\n", + pchan->plat_irq); + return rc; + } + } + + return 0; +} + +/** + * pcc_shutdown - Called from Mailbox Controller code. Used here + * to free the interrupt. + * @chan: Pointer to Mailbox channel to shutdown. + */ +static void pcc_shutdown(struct mbox_chan *chan) +{ + struct pcc_chan_info *pchan = chan->con_priv; + + if (pchan->plat_irq > 0) + devm_free_irq(chan->mbox->dev, pchan->plat_irq, chan); +} + static const struct mbox_chan_ops pcc_chan_ops = { .send_data = pcc_send_data, + .startup = pcc_startup, + .shutdown = pcc_shutdown, }; /** diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index 6bbf87c6d60b..002a135ee868 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -141,9 +141,7 @@ static int qcom_apcs_ipc_remove(struct platform_device *pdev) /* .data is the offset of the ipc register within the global block */ static const struct of_device_id qcom_apcs_ipc_of_match[] = { - { .compatible = "qcom,ipq5332-apcs-apps-global", .data = &ipq6018_apcs_data }, { .compatible = "qcom,ipq6018-apcs-apps-global", .data = &ipq6018_apcs_data }, - { .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq6018_apcs_data }, { .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data }, { .compatible = "qcom,msm8939-apcs-kpss-global", .data = &msm8916_apcs_data }, { .compatible = "qcom,msm8953-apcs-kpss-global", .data = &msm8994_apcs_data }, @@ -153,15 +151,18 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = { { .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,qcm2290-apcs-hmss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,qcs404-apcs-apps-global", .data = &msm8916_apcs_data }, - { .compatible = "qcom,sc7180-apss-shared", .data = &apps_shared_apcs_data }, - { .compatible = "qcom,sc8180x-apss-shared", .data = &apps_shared_apcs_data }, { .compatible = "qcom,sdm660-apcs-hmss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,sdm845-apss-shared", .data = &apps_shared_apcs_data }, { .compatible = "qcom,sm4250-apcs-hmss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,sm6125-apcs-hmss-global", .data = &msm8994_apcs_data }, - { .compatible = "qcom,sm8150-apss-shared", .data = &apps_shared_apcs_data }, { .compatible = "qcom,sm6115-apcs-hmss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,sdx55-apcs-gcc", .data = &sdx55_apcs_data }, + /* Do not add any more entries using existing driver data */ + { .compatible = "qcom,ipq5332-apcs-apps-global", .data = &ipq6018_apcs_data }, + { .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq6018_apcs_data }, + { .compatible = "qcom,sc7180-apss-shared", .data = &apps_shared_apcs_data }, + { .compatible = "qcom,sc8180x-apss-shared", .data = &apps_shared_apcs_data }, + { .compatible = "qcom,sm8150-apss-shared", .data = &apps_shared_apcs_data }, {} }; MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match); diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index e02d3c9e3693..116286ecc5a0 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -248,13 +248,12 @@ static struct platform_driver rockchip_mbox_driver = { .probe = rockchip_mbox_probe, .driver = { .name = "rockchip-mailbox", - .of_match_table = of_match_ptr(rockchip_mbox_of_match), + .of_match_table = rockchip_mbox_of_match, }, }; module_platform_driver(rockchip_mbox_driver); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Rockchip mailbox: communicate between CPU cores and MCU"); MODULE_AUTHOR("Addy Ke "); MODULE_AUTHOR("Caesar Wang "); diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c index 53decd89876e..a851e0236464 100644 --- a/drivers/mcb/mcb-lpc.c +++ b/drivers/mcb/mcb-lpc.c @@ -23,7 +23,7 @@ static int mcb_lpc_probe(struct platform_device *pdev) { struct resource *res; struct priv *priv; - int ret = 0; + int ret = 0, table_size; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -58,16 +58,43 @@ static int mcb_lpc_probe(struct platform_device *pdev) ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base); if (ret < 0) { - mcb_release_bus(priv->bus); - return ret; + goto out_mcb_bus; } - dev_dbg(&pdev->dev, "Found %d cells\n", ret); + table_size = ret; + + if (table_size < CHAM_HEADER_SIZE) { + /* Release the previous resources */ + devm_iounmap(&pdev->dev, priv->base); + devm_release_mem_region(&pdev->dev, priv->mem->start, resource_size(priv->mem)); + + /* Then, allocate it again with the actual chameleon table size */ + res = devm_request_mem_region(&pdev->dev, priv->mem->start, + table_size, + KBUILD_MODNAME); + if (!res) { + dev_err(&pdev->dev, "Failed to request PCI memory\n"); + ret = -EBUSY; + goto out_mcb_bus; + } + + priv->base = devm_ioremap(&pdev->dev, priv->mem->start, table_size); + if (!priv->base) { + dev_err(&pdev->dev, "Cannot ioremap\n"); + ret = -ENOMEM; + goto out_mcb_bus; + } + + platform_set_drvdata(pdev, priv); + } mcb_bus_add_devices(priv->bus); return 0; +out_mcb_bus: + mcb_release_bus(priv->bus); + return ret; } static int mcb_lpc_remove(struct platform_device *pdev) diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index aa6938da0db8..2aef990f379f 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c @@ -130,7 +130,7 @@ static void chameleon_parse_bar(void __iomem *base, } } -static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase, +static int chameleon_get_bar(void __iomem **base, phys_addr_t mapbase, struct chameleon_bar **cb) { struct chameleon_bar *c; @@ -179,12 +179,13 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, { struct chameleon_fpga_header *header; struct chameleon_bar *cb; - char __iomem *p = base; + void __iomem *p = base; int num_cells = 0; uint32_t dtype; int bar_count; int ret; u32 hsize; + u32 table_size; hsize = sizeof(struct chameleon_fpga_header); @@ -239,12 +240,16 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, num_cells++; } - if (num_cells == 0) - num_cells = -EINVAL; + if (num_cells == 0) { + ret = -EINVAL; + goto free_bar; + } + table_size = p - base; + pr_debug("%d cell(s) found. Chameleon table size: 0x%04x bytes\n", num_cells, table_size); kfree(cb); kfree(header); - return num_cells; + return table_size; free_bar: kfree(cb); diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index dc88232d9af8..53d9202ff9a7 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c @@ -31,7 +31,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct resource *res; struct priv *priv; - int ret; + int ret, table_size; unsigned long flags; priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL); @@ -90,7 +90,30 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret < 0) goto out_mcb_bus; - dev_dbg(&pdev->dev, "Found %d cells\n", ret); + table_size = ret; + + if (table_size < CHAM_HEADER_SIZE) { + /* Release the previous resources */ + devm_iounmap(&pdev->dev, priv->base); + devm_release_mem_region(&pdev->dev, priv->mapbase, CHAM_HEADER_SIZE); + + /* Then, allocate it again with the actual chameleon table size */ + res = devm_request_mem_region(&pdev->dev, priv->mapbase, + table_size, + KBUILD_MODNAME); + if (!res) { + dev_err(&pdev->dev, "Failed to request PCI memory\n"); + ret = -EBUSY; + goto out_mcb_bus; + } + + priv->base = devm_ioremap(&pdev->dev, priv->mapbase, table_size); + if (!priv->base) { + dev_err(&pdev->dev, "Cannot ioremap\n"); + ret = -ENOMEM; + goto out_mcb_bus; + } + } mcb_bus_add_devices(priv->bus); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index ba3909bb6bea..7e9d19fd21dd 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -971,7 +971,6 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size, } blk_queue_flag_set(QUEUE_FLAG_NONROT, d->disk->queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, d->disk->queue); blk_queue_write_cache(q, true, true); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 8a448185662c..eea977662e81 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1134,7 +1134,7 @@ static void __cache_size_refresh(void) * If the allocation may fail we use __get_free_pages. Memory fragmentation * won't have a fatal effect here, but it just causes flushes of some other * buffers and more I/O will be performed. Don't use __get_free_pages if it - * always fails (i.e. order >= MAX_ORDER). + * always fails (i.e. order > MAX_ORDER). * * If the allocation shouldn't fail we use __vmalloc. This is only for the * initial reserve allocation, so there's no risk of wasting all vmalloc diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index acffed750e3e..9e0c69958587 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -1828,7 +1828,7 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) * Replacement block manager (new_bm) is created and old_bm destroyed outside of * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of * shrinker associated with the block manager's bufio client vs cmd root_lock). - * - must take shrinker_rwsem without holding cmd->root_lock + * - must take shrinker_mutex without holding cmd->root_lock */ new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, CACHE_MAX_CONCURRENT_LOCKS); diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index fd464fb024c3..9f5cb52c5763 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1887,7 +1887,7 @@ int dm_pool_abort_metadata(struct dm_pool_metadata *pmd) * Replacement block manager (new_bm) is created and old_bm destroyed outside of * pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of * shrinker associated with the block manager's bufio client vs pmd root_lock). - * - must take shrinker_rwsem without holding pmd->root_lock + * - must take shrinker_mutex without holding pmd->root_lock */ new_bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT, THIN_MAX_CONCURRENT_LOCKS); diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 920bb68156d2..bc8d7565171d 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -219,7 +219,7 @@ static unsigned int optimal_io_size(struct block_device *bdev, } static unsigned int bitmap_io_size(unsigned int io_size, unsigned int opt_size, - sector_t start, sector_t boundary) + loff_t start, loff_t boundary) { if (io_size != opt_size && start + opt_size / SECTOR_SIZE <= boundary) @@ -237,8 +237,8 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap, struct block_device *bdev; struct mddev *mddev = bitmap->mddev; struct bitmap_storage *store = &bitmap->storage; - sector_t offset = mddev->bitmap_info.offset; - sector_t ps, sboff, doff; + loff_t sboff, offset = mddev->bitmap_info.offset; + sector_t ps, doff; unsigned int size = PAGE_SIZE; unsigned int opt_size = PAGE_SIZE; diff --git a/drivers/md/md.c b/drivers/md/md.c index 2003cf86fb8d..8e344b4b3444 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -322,26 +322,6 @@ static struct ctl_table raid_table[] = { { } }; -static struct ctl_table raid_dir_table[] = { - { - .procname = "raid", - .maxlen = 0, - .mode = S_IRUGO|S_IXUGO, - .child = raid_table, - }, - { } -}; - -static struct ctl_table raid_root_table[] = { - { - .procname = "dev", - .maxlen = 0, - .mode = 0555, - .child = raid_dir_table, - }, - { } -}; - static int start_readonly; /* @@ -9653,7 +9633,7 @@ static int __init md_init(void) mdp_major = ret; register_reboot_notifier(&md_notifier); - raid_table_header = register_sysctl_table(raid_root_table); + raid_table_header = register_sysctl("dev/raid", raid_table); md_geninit(); return 0; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 812a12e3e41a..9ea285fbc4a6 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5516,7 +5516,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) sector = raid5_compute_sector(conf, raid_bio->bi_iter.bi_sector, 0, &dd_idx, NULL); - end_sector = bio_end_sector(raid_bio); + end_sector = sector + bio_sectors(raid_bio); rcu_read_lock(); if (r5c_big_stripe_cached(conf, sector)) @@ -6079,6 +6079,38 @@ out_release: return ret; } +/* + * If the bio covers multiple data disks, find sector within the bio that has + * the lowest chunk offset in the first chunk. + */ +static sector_t raid5_bio_lowest_chunk_sector(struct r5conf *conf, + struct bio *bi) +{ + int sectors_per_chunk = conf->chunk_sectors; + int raid_disks = conf->raid_disks; + int dd_idx; + struct stripe_head sh; + unsigned int chunk_offset; + sector_t r_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1); + sector_t sector; + + /* We pass in fake stripe_head to get back parity disk numbers */ + sector = raid5_compute_sector(conf, r_sector, 0, &dd_idx, &sh); + chunk_offset = sector_div(sector, sectors_per_chunk); + if (sectors_per_chunk - chunk_offset >= bio_sectors(bi)) + return r_sector; + /* + * Bio crosses to the next data disk. Check whether it's in the same + * chunk. + */ + dd_idx++; + while (dd_idx == sh.pd_idx || dd_idx == sh.qd_idx) + dd_idx++; + if (dd_idx >= raid_disks) + return r_sector; + return r_sector + sectors_per_chunk - chunk_offset; +} + static bool raid5_make_request(struct mddev *mddev, struct bio * bi) { DEFINE_WAIT_FUNC(wait, woken_wake_function); @@ -6150,6 +6182,17 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) } md_account_bio(mddev, &bi); + /* + * Lets start with the stripe with the lowest chunk offset in the first + * chunk. That has the best chances of creating IOs adjacent to + * previous IOs in case of sequential IO and thus creates the most + * sequential IO pattern. We don't bother with the optimization when + * reshaping as the performance benefit is not worth the complexity. + */ + if (likely(conf->reshape_progress == MaxSector)) + logical_sector = raid5_bio_lowest_chunk_sector(conf, bi); + s = (logical_sector - ctx.first_sector) >> RAID5_STRIPE_SHIFT(conf); + add_wait_queue(&conf->wait_for_overlap, &wait); while (1) { res = make_stripe_request(mddev, conf, &ctx, logical_sector, @@ -6178,7 +6221,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) continue; } - s = find_first_bit(ctx.sectors_to_do, stripe_cnt); + s = find_next_bit_wrap(ctx.sectors_to_do, stripe_cnt, s); if (s == stripe_cnt) break; diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 769ea6b2e1d0..241b1621b197 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -1091,7 +1091,8 @@ void cec_received_msg_ts(struct cec_adapter *adap, mutex_lock(&adap->lock); dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); - adap->last_initiator = 0xff; + if (!adap->transmit_in_progress) + adap->last_initiator = 0xff; /* Check if this message was for us (directed or broadcast). */ if (!cec_msg_is_broadcast(msg)) { @@ -1585,7 +1586,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) * * This function is called with adap->lock held. */ -static int cec_adap_enable(struct cec_adapter *adap) +int cec_adap_enable(struct cec_adapter *adap) { bool enable; int ret = 0; @@ -1595,6 +1596,9 @@ static int cec_adap_enable(struct cec_adapter *adap) if (adap->needs_hpd) enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID; + if (adap->devnode.unregistered) + enable = false; + if (enable == adap->is_enabled) return 0; diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index af358e901b5f..7e153c5cad04 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -191,6 +191,8 @@ static void cec_devnode_unregister(struct cec_adapter *adap) mutex_lock(&adap->lock); __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); __cec_s_log_addrs(adap, NULL, false); + // Disable the adapter (since adap->devnode.unregistered is true) + cec_adap_enable(adap); mutex_unlock(&adap->lock); cdev_device_del(&devnode->cdev, &devnode->dev); diff --git a/drivers/media/cec/core/cec-priv.h b/drivers/media/cec/core/cec-priv.h index b78df931aa74..ed1f8c67626b 100644 --- a/drivers/media/cec/core/cec-priv.h +++ b/drivers/media/cec/core/cec-priv.h @@ -47,6 +47,7 @@ int cec_monitor_pin_cnt_inc(struct cec_adapter *adap); void cec_monitor_pin_cnt_dec(struct cec_adapter *adap); int cec_adap_status(struct seq_file *file, void *priv); int cec_thread_func(void *_adap); +int cec_adap_enable(struct cec_adapter *adap); void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); int __cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs, bool block); diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index c2d2792227f8..baf64540dc00 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -151,6 +151,12 @@ struct dvb_ca_private { /* mutex serializing ioctls */ struct mutex ioctl_mutex; + + /* A mutex used when a device is disconnected */ + struct mutex remove_mutex; + + /* Whether the device is disconnected */ + int exit; }; static void dvb_ca_private_free(struct dvb_ca_private *ca) @@ -187,7 +193,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount); static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, - u8 *ebuf, int ecount); + u8 *ebuf, int ecount, int size_write_flag); /** * findstr - Safely find needle in haystack. @@ -370,7 +376,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10); if (ret) return ret; - ret = dvb_ca_en50221_write_data(ca, slot, buf, 2); + ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW); if (ret != 2) return -EIO; ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); @@ -778,11 +784,13 @@ exit: * @buf: The data in this buffer is treated as a complete link-level packet to * be written. * @bytes_write: Size of ebuf. + * @size_write_flag: A flag on Command Register which says whether the link size + * information will be writen or not. * * return: Number of bytes written, or < 0 on error. */ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, - u8 *buf, int bytes_write) + u8 *buf, int bytes_write, int size_write_flag) { struct dvb_ca_slot *sl = &ca->slot_info[slot]; int status; @@ -817,7 +825,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, /* OK, set HC bit */ status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, - IRQEN | CMDREG_HC); + IRQEN | CMDREG_HC | size_write_flag); if (status) goto exit; @@ -1508,7 +1516,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, mutex_lock(&sl->slot_lock); status = dvb_ca_en50221_write_data(ca, slot, fragbuf, - fraglen + 2); + fraglen + 2, 0); mutex_unlock(&sl->slot_lock); if (status == (fraglen + 2)) { written = 1; @@ -1709,12 +1717,22 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) dprintk("%s\n", __func__); - if (!try_module_get(ca->pub->owner)) + mutex_lock(&ca->remove_mutex); + + if (ca->exit) { + mutex_unlock(&ca->remove_mutex); + return -ENODEV; + } + + if (!try_module_get(ca->pub->owner)) { + mutex_unlock(&ca->remove_mutex); return -EIO; + } err = dvb_generic_open(inode, file); if (err < 0) { module_put(ca->pub->owner); + mutex_unlock(&ca->remove_mutex); return err; } @@ -1739,6 +1757,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) dvb_ca_private_get(ca); + mutex_unlock(&ca->remove_mutex); return 0; } @@ -1758,6 +1777,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) dprintk("%s\n", __func__); + mutex_lock(&ca->remove_mutex); + /* mark the CA device as closed */ ca->open = 0; dvb_ca_en50221_thread_update_delay(ca); @@ -1768,6 +1789,13 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) dvb_ca_private_put(ca); + if (dvbdev->users == 1 && ca->exit == 1) { + mutex_unlock(&ca->remove_mutex); + wake_up(&dvbdev->wait_queue); + } else { + mutex_unlock(&ca->remove_mutex); + } + return err; } @@ -1891,6 +1919,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, } mutex_init(&ca->ioctl_mutex); + mutex_init(&ca->remove_mutex); if (signal_pending(current)) { ret = -EINTR; @@ -1933,6 +1962,14 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) dprintk("%s\n", __func__); + mutex_lock(&ca->remove_mutex); + ca->exit = 1; + mutex_unlock(&ca->remove_mutex); + + if (ca->dvbdev->users < 1) + wait_event(ca->dvbdev->wait_queue, + ca->dvbdev->users == 1); + /* shutdown the thread if there was one */ kthread_stop(ca->thread); diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 398c86279b5b..7c4d86bfdd6c 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -115,12 +115,12 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; if (!ccok) { set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); dprintk_sect_loss("missed packet: %d instead of %d!\n", cc, (feed->cc + 1) & 0x0f); } + feed->cc = cc; if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; @@ -300,7 +300,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; - feed->cc = cc; if (buf[3] & 0x20) { /* adaption field present, check for discontinuity_indicator */ @@ -336,6 +335,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, feed->pusi_seen = false; dvb_dmx_swfilter_section_new(feed); } + feed->cc = cc; if (buf[1] & 0x40) { /* PUSI=1 (is set), section boundary is here */ diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index cc0a789f09ae..bc6950a5740f 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -293,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, } if (events->eventw == events->eventr) { - int ret; + struct wait_queue_entry wait; + int ret = 0; if (flags & O_NONBLOCK) return -EWOULDBLOCK; - ret = wait_event_interruptible(events->wait_queue, - dvb_frontend_test_event(fepriv, events)); - + init_waitqueue_entry(&wait, current); + add_wait_queue(&events->wait_queue, &wait); + while (!dvb_frontend_test_event(fepriv, events)) { + wait_woken(&wait, TASK_INTERRUPTIBLE, 0); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + remove_wait_queue(&events->wait_queue, &wait); if (ret < 0) return ret; } @@ -809,15 +817,26 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) dev_dbg(fe->dvb->device, "%s:\n", __func__); + mutex_lock(&fe->remove_mutex); + if (fe->exit != DVB_FE_DEVICE_REMOVED) fe->exit = DVB_FE_NORMAL_EXIT; mb(); - if (!fepriv->thread) + if (!fepriv->thread) { + mutex_unlock(&fe->remove_mutex); return; + } kthread_stop(fepriv->thread); + mutex_unlock(&fe->remove_mutex); + + if (fepriv->dvbdev->users < -1) { + wait_event(fepriv->dvbdev->wait_queue, + fepriv->dvbdev->users == -1); + } + sema_init(&fepriv->sem, 1); fepriv->state = FESTATE_IDLE; @@ -2761,9 +2780,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) struct dvb_adapter *adapter = fe->dvb; int ret; + mutex_lock(&fe->remove_mutex); + dev_dbg(fe->dvb->device, "%s:\n", __func__); - if (fe->exit == DVB_FE_DEVICE_REMOVED) - return -ENODEV; + if (fe->exit == DVB_FE_DEVICE_REMOVED) { + ret = -ENODEV; + goto err_remove_mutex; + } if (adapter->mfe_shared == 2) { mutex_lock(&adapter->mfe_lock); @@ -2771,7 +2794,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) if (adapter->mfe_dvbdev && !adapter->mfe_dvbdev->writers) { mutex_unlock(&adapter->mfe_lock); - return -EBUSY; + ret = -EBUSY; + goto err_remove_mutex; } adapter->mfe_dvbdev = dvbdev; } @@ -2794,8 +2818,10 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) while (mferetry-- && (mfedev->users != -1 || mfepriv->thread)) { if (msleep_interruptible(500)) { - if (signal_pending(current)) - return -EINTR; + if (signal_pending(current)) { + ret = -EINTR; + goto err_remove_mutex; + } } } @@ -2807,7 +2833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) if (mfedev->users != -1 || mfepriv->thread) { mutex_unlock(&adapter->mfe_lock); - return -EBUSY; + ret = -EBUSY; + goto err_remove_mutex; } adapter->mfe_dvbdev = dvbdev; } @@ -2866,6 +2893,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) if (adapter->mfe_shared) mutex_unlock(&adapter->mfe_lock); + + mutex_unlock(&fe->remove_mutex); return ret; err3: @@ -2887,6 +2916,9 @@ err1: err0: if (adapter->mfe_shared) mutex_unlock(&adapter->mfe_lock); + +err_remove_mutex: + mutex_unlock(&fe->remove_mutex); return ret; } @@ -2897,6 +2929,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) struct dvb_frontend_private *fepriv = fe->frontend_priv; int ret; + mutex_lock(&fe->remove_mutex); + dev_dbg(fe->dvb->device, "%s:\n", __func__); if ((file->f_flags & O_ACCMODE) != O_RDONLY) { @@ -2918,10 +2952,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) } mutex_unlock(&fe->dvb->mdev_lock); #endif - if (fe->exit != DVB_FE_NO_EXIT) - wake_up(&dvbdev->wait_queue); if (fe->ops.ts_bus_ctrl) fe->ops.ts_bus_ctrl(fe, 0); + + if (fe->exit != DVB_FE_NO_EXIT) { + mutex_unlock(&fe->remove_mutex); + wake_up(&dvbdev->wait_queue); + } else { + mutex_unlock(&fe->remove_mutex); + } + + } else { + mutex_unlock(&fe->remove_mutex); } dvb_frontend_put(fe); @@ -3022,6 +3064,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, fepriv = fe->frontend_priv; kref_init(&fe->refcount); + mutex_init(&fe->remove_mutex); /* * After initialization, there need to be two references: one diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 8a2febf33ce2..8bb8dd34c223 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1564,15 +1564,43 @@ static long dvb_net_ioctl(struct file *file, return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); } +static int locked_dvb_net_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_net *dvbnet = dvbdev->priv; + int ret; + + if (mutex_lock_interruptible(&dvbnet->remove_mutex)) + return -ERESTARTSYS; + + if (dvbnet->exit) { + mutex_unlock(&dvbnet->remove_mutex); + return -ENODEV; + } + + ret = dvb_generic_open(inode, file); + + mutex_unlock(&dvbnet->remove_mutex); + + return ret; +} + static int dvb_net_close(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; + mutex_lock(&dvbnet->remove_mutex); + dvb_generic_release(inode, file); - if(dvbdev->users == 1 && dvbnet->exit == 1) + if (dvbdev->users == 1 && dvbnet->exit == 1) { + mutex_unlock(&dvbnet->remove_mutex); wake_up(&dvbdev->wait_queue); + } else { + mutex_unlock(&dvbnet->remove_mutex); + } + return 0; } @@ -1580,7 +1608,7 @@ static int dvb_net_close(struct inode *inode, struct file *file) static const struct file_operations dvb_net_fops = { .owner = THIS_MODULE, .unlocked_ioctl = dvb_net_ioctl, - .open = dvb_generic_open, + .open = locked_dvb_net_open, .release = dvb_net_close, .llseek = noop_llseek, }; @@ -1599,10 +1627,13 @@ void dvb_net_release (struct dvb_net *dvbnet) { int i; + mutex_lock(&dvbnet->remove_mutex); dvbnet->exit = 1; + mutex_unlock(&dvbnet->remove_mutex); + if (dvbnet->dvbdev->users < 1) wait_event(dvbnet->dvbdev->wait_queue, - dvbnet->dvbdev->users==1); + dvbnet->dvbdev->users == 1); dvb_unregister_device(dvbnet->dvbdev); @@ -1621,6 +1652,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, int i; mutex_init(&dvbnet->ioctl_mutex); + mutex_init(&dvbnet->remove_mutex); dvbnet->demux = dmx; for (i=0; i static DEFINE_MUTEX(dvbdev_mutex); +static LIST_HEAD(dvbdevfops_list); static int dvbdev_debug; module_param(dvbdev_debug, int, 0644); @@ -453,14 +454,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, enum dvb_device_type type, int demux_sink_pads) { struct dvb_device *dvbdev; - struct file_operations *dvbdevfops; + struct file_operations *dvbdevfops = NULL; + struct dvbdevfops_node *node = NULL, *new_node = NULL; struct device *clsdev; int minor; int id, ret; mutex_lock(&dvbdev_register_lock); - if ((id = dvbdev_get_free_id (adap, type)) < 0){ + if ((id = dvbdev_get_free_id (adap, type)) < 0) { mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; pr_err("%s: couldn't find free device id\n", __func__); @@ -468,18 +470,45 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL); - if (!dvbdev){ mutex_unlock(&dvbdev_register_lock); return -ENOMEM; } - dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); + /* + * When a device of the same type is probe()d more than once, + * the first allocated fops are used. This prevents memory leaks + * that can occur when the same device is probe()d repeatedly. + */ + list_for_each_entry(node, &dvbdevfops_list, list_head) { + if (node->fops->owner == adap->module && + node->type == type && + node->template == template) { + dvbdevfops = node->fops; + break; + } + } - if (!dvbdevfops){ - kfree (dvbdev); - mutex_unlock(&dvbdev_register_lock); - return -ENOMEM; + if (dvbdevfops == NULL) { + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); + if (!dvbdevfops) { + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } + + new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL); + if (!new_node) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } + + new_node->fops = dvbdevfops; + new_node->type = type; + new_node->template = template; + list_add_tail (&new_node->list_head, &dvbdevfops_list); } memcpy(dvbdev, template, sizeof(struct dvb_device)); @@ -490,20 +519,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvbdev->priv = priv; dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); - dvbdevfops->owner = adap->module; - list_add_tail (&dvbdev->list_head, &adap->device_list); - down_write(&minor_rwsem); #ifdef CONFIG_DVB_DYNAMIC_MINORS for (minor = 0; minor < MAX_DVB_MINORS; minor++) if (dvb_minors[minor] == NULL) break; - if (minor == MAX_DVB_MINORS) { + if (new_node) { + list_del (&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } list_del (&dvbdev->list_head); - kfree(dvbdevfops); kfree(dvbdev); up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); @@ -512,41 +541,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, #else minor = nums2minor(adap->num, type, id); #endif - dvbdev->minor = minor; dvb_minors[minor] = dvb_device_get(dvbdev); up_write(&minor_rwsem); - ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads); if (ret) { pr_err("%s: dvb_register_media_device failed to create the mediagraph\n", __func__); - + if (new_node) { + list_del (&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } dvb_media_device_free(dvbdev); list_del (&dvbdev->list_head); - kfree(dvbdevfops); kfree(dvbdev); mutex_unlock(&dvbdev_register_lock); return ret; } - mutex_unlock(&dvbdev_register_lock); - clsdev = device_create(dvb_class, adap->device, MKDEV(DVB_MAJOR, minor), dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + if (new_node) { + list_del (&new_node->list_head); + kfree(dvbdevfops); + kfree(new_node); + } dvb_media_device_free(dvbdev); list_del (&dvbdev->list_head); - kfree(dvbdevfops); kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); return PTR_ERR(clsdev); } + dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); + mutex_unlock(&dvbdev_register_lock); return 0; } EXPORT_SYMBOL(dvb_register_device); @@ -575,7 +610,6 @@ static void dvb_free_device(struct kref *ref) { struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref); - kfree (dvbdev->fops); kfree (dvbdev); } @@ -1063,7 +1097,7 @@ static int __init init_dvbdev(void) goto error; } - dvb_class = class_create(THIS_MODULE, "dvb"); + dvb_class = class_create("dvb"); if (IS_ERR(dvb_class)) { retval = PTR_ERR(dvb_class); goto error; @@ -1081,9 +1115,17 @@ error: static void __exit exit_dvbdev(void) { + struct dvbdevfops_node *node, *next; + class_destroy(dvb_class); cdev_del(&dvb_device_cdev); unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); + + list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) { + list_del (&node->list_head); + kfree(node->fops); + kfree(node); + } } subsys_initcall(init_dvbdev); diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 1f1753f2ab1a..0782f8377eb2 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(i2c, mn88443x_i2c_id); static struct i2c_driver mn88443x_driver = { .driver = { .name = "mn88443x", - .of_match_table = of_match_ptr(mn88443x_of_match), + .of_match_table = mn88443x_of_match, }, .probe_new = mn88443x_probe, .remove = mn88443x_remove, diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index ee8087f29b2c..40e6c873c36d 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -3117,7 +3117,6 @@ static struct device_attribute ddb_attrs_fanspeed[] = { static struct class ddb_class = { .name = "ddbridge", - .owner = THIS_MODULE, .devnode = ddb_devnode, }; diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 8287851b5ffd..d85bfbb77a25 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -697,7 +697,7 @@ static void netup_unidvb_dma_fini(struct netup_unidvb_dev *ndev, int num) netup_unidvb_dma_enable(dma, 0); msleep(50); cancel_work_sync(&dma->work); - del_timer(&dma->timeout); + del_timer_sync(&dma->timeout); } static int netup_unidvb_dma_setup(struct netup_unidvb_dev *ndev) @@ -887,12 +887,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, ndev->lmmio0, (u32)pci_resource_len(pci_dev, 0), ndev->lmmio1, (u32)pci_resource_len(pci_dev, 1), pci_dev->irq); - if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED, - "netup_unidvb", pci_dev) < 0) { - dev_err(&pci_dev->dev, - "%s(): can't get IRQ %d\n", __func__, pci_dev->irq); - goto irq_request_err; - } + ndev->dma_size = 2 * 188 * NETUP_DMA_BLOCKS_COUNT * NETUP_DMA_PACKETS_COUNT; ndev->dma_virt = dma_alloc_coherent(&pci_dev->dev, @@ -933,6 +928,14 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, dev_err(&pci_dev->dev, "netup_unidvb: DMA setup failed\n"); goto dma_setup_err; } + + if (request_irq(pci_dev->irq, netup_unidvb_isr, IRQF_SHARED, + "netup_unidvb", pci_dev) < 0) { + dev_err(&pci_dev->dev, + "%s(): can't get IRQ %d\n", __func__, pci_dev->irq); + goto dma_setup_err; + } + dev_info(&pci_dev->dev, "netup_unidvb: device has been initialized\n"); return 0; @@ -951,8 +954,6 @@ spi_setup_err: dma_free_coherent(&pci_dev->dev, ndev->dma_size, ndev->dma_virt, ndev->dma_phys); dma_alloc_err: - free_irq(pci_dev->irq, pci_dev); -irq_request_err: iounmap(ndev->lmmio1); pci_bar1_error: iounmap(ndev->lmmio0); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 6c7c5f3648df..0051f372a66c 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1782,9 +1782,6 @@ static int mtk_jpeg_probe(struct platform_device *pdev) jpeg->vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - if (of_property_present(pdev->dev.of_node, "dma-ranges")) - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); - ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 75c92e282fa2..19a4a085f73a 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1035,7 +1035,6 @@ static int mdp_comp_sub_create(struct mdp_dev *mdp) { struct device *dev = &mdp->pdev->dev; struct device_node *node, *parent; - const struct mtk_mdp_driver_data *data = mdp->mdp_data; parent = dev->of_node->parent; @@ -1045,7 +1044,7 @@ static int mdp_comp_sub_create(struct mdp_dev *mdp) int id, alias_id; struct mdp_comp *comp; - of_id = of_match_node(data->mdp_sub_comp_dt_ids, node); + of_id = of_match_node(mdp->mdp_data->mdp_sub_comp_dt_ids, node); if (!of_id) continue; if (!of_device_is_available(node)) { diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index 9ba5dc5df648..9c652beb3f19 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -321,14 +321,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } } - if (of_property_present(pdev->dev.of_node, "dma-ranges")) { - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); - if (ret) { - mtk_v4l2_err("Failed to set mask"); - goto err_core_workq; - } - } - for (i = 0; i < MTK_VDEC_HW_MAX; i++) mutex_init(&dev->dec_mutex[i]); mutex_init(&dev->dev_mutex); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c index 29991551cf61..0fbd030026c7 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c @@ -584,6 +584,9 @@ static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED)) { for (i = 0; i < num_supported_formats; i++) { + if (mtk_video_formats[i].type != MTK_FMT_DEC) + continue; + mtk_video_formats[i].frmsize.max_width = VCODEC_DEC_4K_CODED_WIDTH; mtk_video_formats[i].frmsize.max_height = diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c index 755f567b9e54..168004a08888 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c @@ -352,9 +352,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_event_workq; } - if (of_property_present(pdev->dev.of_node, "dma-ranges")) - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); - ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1); if (ret) { mtk_v4l2_err("Failed to register video device"); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index 238521622b75..253e77189b69 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -378,8 +378,8 @@ static int mxc_isi_runtime_resume(struct device *dev) } static const struct dev_pm_ops mxc_isi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mxc_isi_pm_suspend, mxc_isi_pm_resume) - SET_RUNTIME_PM_OPS(mxc_isi_runtime_suspend, mxc_isi_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mxc_isi_pm_suspend, mxc_isi_pm_resume) + RUNTIME_PM_OPS(mxc_isi_runtime_suspend, mxc_isi_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- @@ -528,7 +528,7 @@ static struct platform_driver mxc_isi_driver = { .driver = { .of_match_table = mxc_isi_of_match, .name = MXC_ISI_DRIVER_NAME, - .pm = &mxc_isi_pm_ops, + .pm = pm_ptr(&mxc_isi_pm_ops), } }; module_platform_driver(mxc_isi_driver); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c index db538f3d88ec..19e80b95ffea 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c @@ -29,11 +29,10 @@ static inline void mxc_isi_write(struct mxc_isi_pipe *pipe, u32 reg, u32 val) void mxc_isi_channel_set_inbuf(struct mxc_isi_pipe *pipe, dma_addr_t dma_addr) { - mxc_isi_write(pipe, CHNL_IN_BUF_ADDR, dma_addr); -#if CONFIG_ARCH_DMA_ADDR_T_64BIT + mxc_isi_write(pipe, CHNL_IN_BUF_ADDR, lower_32_bits(dma_addr)); if (pipe->isi->pdata->has_36bit_dma) - mxc_isi_write(pipe, CHNL_IN_BUF_XTND_ADDR, dma_addr >> 32); -#endif + mxc_isi_write(pipe, CHNL_IN_BUF_XTND_ADDR, + upper_32_bits(dma_addr)); } void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe, @@ -45,34 +44,36 @@ void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe, val = mxc_isi_read(pipe, CHNL_OUT_BUF_CTRL); if (buf_id == MXC_ISI_BUF1) { - mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_Y, dma_addrs[0]); - mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_U, dma_addrs[1]); - mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_V, dma_addrs[2]); -#if CONFIG_ARCH_DMA_ADDR_T_64BIT + mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_Y, + lower_32_bits(dma_addrs[0])); + mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_U, + lower_32_bits(dma_addrs[1])); + mxc_isi_write(pipe, CHNL_OUT_BUF1_ADDR_V, + lower_32_bits(dma_addrs[2])); if (pipe->isi->pdata->has_36bit_dma) { mxc_isi_write(pipe, CHNL_Y_BUF1_XTND_ADDR, - dma_addrs[0] >> 32); + upper_32_bits(dma_addrs[0])); mxc_isi_write(pipe, CHNL_U_BUF1_XTND_ADDR, - dma_addrs[1] >> 32); + upper_32_bits(dma_addrs[1])); mxc_isi_write(pipe, CHNL_V_BUF1_XTND_ADDR, - dma_addrs[2] >> 32); + upper_32_bits(dma_addrs[2])); } -#endif val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR; } else { - mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_Y, dma_addrs[0]); - mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_U, dma_addrs[1]); - mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_V, dma_addrs[2]); -#if CONFIG_ARCH_DMA_ADDR_T_64BIT + mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_Y, + lower_32_bits(dma_addrs[0])); + mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_U, + lower_32_bits(dma_addrs[1])); + mxc_isi_write(pipe, CHNL_OUT_BUF2_ADDR_V, + lower_32_bits(dma_addrs[2])); if (pipe->isi->pdata->has_36bit_dma) { mxc_isi_write(pipe, CHNL_Y_BUF2_XTND_ADDR, - dma_addrs[0] >> 32); + upper_32_bits(dma_addrs[0])); mxc_isi_write(pipe, CHNL_U_BUF2_XTND_ADDR, - dma_addrs[1] >> 32); + upper_32_bits(dma_addrs[1])); mxc_isi_write(pipe, CHNL_V_BUF2_XTND_ADDR, - dma_addrs[2] >> 32); + upper_32_bits(dma_addrs[2])); } -#endif val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR; } diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 898f32177b12..8640db306026 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -353,7 +353,6 @@ static int video_get_subdev_format(struct camss_video *video, if (subdev == NULL) return -EPIPE; - memset(&fmt, 0, sizeof(fmt)); fmt.pad = pad; ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 98bfd445a649..2a77353f10b5 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -728,11 +728,9 @@ static int rvin_setup(struct rvin_dev *vin) case V4L2_FIELD_SEQ_TB: case V4L2_FIELD_SEQ_BT: case V4L2_FIELD_NONE: - vnmc = VNMC_IM_ODD_EVEN; - progressive = true; - break; case V4L2_FIELD_ALTERNATE: vnmc = VNMC_IM_ODD_EVEN; + progressive = true; break; default: vnmc = VNMC_IM_ODD; @@ -1312,12 +1310,23 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, } if (rvin_scaler_needed(vin)) { + /* Gen3 can't scale NV12 */ + if (vin->info->model == RCAR_GEN3 && + vin->format.pixelformat == V4L2_PIX_FMT_NV12) + return -EPIPE; + if (!vin->scaler) return -EPIPE; } else { - if (fmt.format.width != vin->format.width || - fmt.format.height != vin->format.height) - return -EPIPE; + if (vin->format.pixelformat == V4L2_PIX_FMT_NV12) { + if (ALIGN(fmt.format.width, 32) != vin->format.width || + ALIGN(fmt.format.height, 32) != vin->format.height) + return -EPIPE; + } else { + if (fmt.format.width != vin->format.width || + fmt.format.height != vin->format.height) + return -EPIPE; + } } if (fmt.format.code != vin->mbus_code) diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 835518534e3b..61cfaaf4e927 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -397,10 +397,12 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth) if (!raw_vpu_fmt) return -EINVAL; - if (ctx->is_encoder) + if (ctx->is_encoder) { encoded_fmt = &ctx->dst_fmt; - else + ctx->vpu_src_fmt = raw_vpu_fmt; + } else { encoded_fmt = &ctx->src_fmt; + } hantro_reset_fmt(&raw_fmt, raw_vpu_fmt); raw_fmt.width = encoded_fmt->width; diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c index 8230da828d0e..127a3be0e0f0 100644 --- a/drivers/media/radio/radio-shark.c +++ b/drivers/media/radio/radio-shark.c @@ -316,6 +316,16 @@ static int usb_shark_probe(struct usb_interface *intf, { struct shark_device *shark; int retval = -ENOMEM; + static const u8 ep_addresses[] = { + SHARK_IN_EP | USB_DIR_IN, + SHARK_OUT_EP | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_int_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid radioSHARK device\n"); + return -EINVAL; + } shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); if (!shark) diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c index d150f12382c6..f1c5c0a6a335 100644 --- a/drivers/media/radio/radio-shark2.c +++ b/drivers/media/radio/radio-shark2.c @@ -282,6 +282,16 @@ static int usb_shark_probe(struct usb_interface *intf, { struct shark_device *shark; int retval = -ENOMEM; + static const u8 ep_addresses[] = { + SHARK_IN_EP | USB_DIR_IN, + SHARK_OUT_EP | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_int_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid radioSHARK2 device\n"); + return -EINVAL; + } shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); if (!shark) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 25ab61dae126..043d23aaa3cb 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -785,7 +785,7 @@ int __init lirc_dev_init(void) { int retval; - lirc_class = class_create(THIS_MODULE, "lirc"); + lirc_class = class_create("lirc"); if (IS_ERR(lirc_class)) { pr_err("class_create failed\n"); return PTR_ERR(lirc_class); diff --git a/drivers/media/usb/dvb-usb-v2/ce6230.c b/drivers/media/usb/dvb-usb-v2/ce6230.c index 44540de1a206..d3b5cb4a24da 100644 --- a/drivers/media/usb/dvb-usb-v2/ce6230.c +++ b/drivers/media/usb/dvb-usb-v2/ce6230.c @@ -101,6 +101,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (msg[i].addr == ce6230_zl10353_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = DEMOD_READ; req.value = msg[i].addr >> 1; req.index = msg[i].buf[0]; @@ -117,6 +121,10 @@ static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, } else { if (msg[i].addr == ce6230_zl10353_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = DEMOD_WRITE; req.value = msg[i].addr >> 1; req.index = msg[i].buf[0]; diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c index 7ed0ab9e429b..0e4773fc025c 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -115,6 +115,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], while (i < num) { if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { if (msg[i].addr == ec168_ec100_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = READ_DEMOD; req.value = 0; req.index = 0xff00 + msg[i].buf[0]; /* reg */ @@ -131,6 +135,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } } else { if (msg[i].addr == ec168_ec100_config.demod_address) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = WRITE_DEMOD; req.value = msg[i].buf[1]; /* val */ req.index = 0xff00 + msg[i].buf[0]; /* reg */ @@ -139,6 +147,10 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = ec168_ctrl_msg(d, &req); i += 1; } else { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } req.cmd = WRITE_I2C; req.value = msg[i].buf[0]; /* val */ req.index = 0x0100 + msg[i].addr; /* I2C addr */ diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 795a012d4020..f7884bb56fcc 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -176,6 +176,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1 || msg[1].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { /* return demod page from driver cache */ @@ -189,6 +193,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if (msg[0].len < 2) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_RD; @@ -217,8 +225,16 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = -EOPNOTSUPP; goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { + if (msg[0].len < 2) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* save demod page for later demod access */ dev->page = msg[0].buf[1]; ret = 0; @@ -231,6 +247,10 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = rtl28xxu_ctrl_msg(d, &req); } } else if ((msg[0].len < 23) && (!dev->new_i2c_write)) { + if (msg[0].len < 1) { + ret = -EOPNOTSUPP; + goto err_mutex_unlock; + } /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.index = CMD_I2C_WR; diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 7d78ee09be5e..a31c6f82f4e9 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -988,6 +988,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n /* write/read request */ if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) { req = 0xB9; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); value = msg[i].addr + (msg[i].len << 8); length = msg[i + 1].len + 6; @@ -1001,6 +1005,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n /* demod 16bit addr */ req = 0xBD; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff)); value = msg[i].addr + (2 << 8); length = msg[i].len - 2; @@ -1026,6 +1034,10 @@ static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int n } else { req = 0xBD; + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } index = msg[i].buf[0] & 0x00FF; value = msg[i].addr + (1 << 8); length = msg[i].len - 1; diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 2756815a780b..32134be16914 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -63,6 +63,10 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num warn("more than 2 i2c messages at a time is not handled yet. TODO."); for (i = 0; i < num; i++) { + if (msg[i].len < 1) { + i = -EOPNOTSUPP; + break; + } /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 0ca764282c76..8747960e6146 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -946,7 +946,7 @@ static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) for (i = 0; i < 6; i++) { obuf[1] = 0xf0 + i; if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) - break; + return -1; else mac[i] = ibuf[0]; } diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 9501b10b31aa..0df10270dbdf 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -37,6 +37,7 @@ config VIDEO_PVRUSB2_DVB bool "pvrusb2 ATSC/DVB support" default y depends on VIDEO_PVRUSB2 && DVB_CORE + depends on VIDEO_PVRUSB2=m || DVB_CORE=y select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c index ce4d566e4e5a..721dafd2c14b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-main.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c @@ -16,9 +16,7 @@ #include "pvrusb2-context.h" #include "pvrusb2-debug.h" #include "pvrusb2-v4l2.h" -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS #include "pvrusb2-sysfs.h" -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ #define DRIVER_AUTHOR "Mike Isely " #define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner" @@ -36,10 +34,6 @@ int pvrusb2_debug = DEFAULT_DEBUG_MASK; module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Debug trace mask"); -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS -static struct pvr2_sysfs_class *class_ptr = NULL; -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - static void pvr_setup_attach(struct pvr2_context *pvr) { /* Create association with v4l layer */ @@ -48,9 +42,7 @@ static void pvr_setup_attach(struct pvr2_context *pvr) /* Create association with dvb layer */ pvr2_dvb_create(pvr); #endif -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_create(pvr,class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_create(pvr); } static int pvr_probe(struct usb_interface *intf, @@ -115,9 +107,7 @@ static int __init pvr_init(void) return ret; } -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - class_ptr = pvr2_sysfs_class_create(); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_class_create(); ret = usb_register(&pvr_driver); @@ -141,9 +131,7 @@ static void __exit pvr_exit(void) pvr2_context_global_done(); -#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS - pvr2_sysfs_class_destroy(class_ptr); -#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ + pvr2_sysfs_class_destroy(); pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete"); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 3e42e209be37..a8c0b513e58e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -66,10 +66,6 @@ struct pvr2_sysfs_ctl_item { char name[80]; }; -struct pvr2_sysfs_class { - struct class class; -}; - static ssize_t show_name(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -487,15 +483,6 @@ static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) } -static void pvr2_sysfs_class_release(struct class *class) -{ - struct pvr2_sysfs_class *clp; - clp = container_of(class,struct pvr2_sysfs_class,class); - pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); - kfree(clp); -} - - static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); @@ -503,6 +490,12 @@ static void pvr2_sysfs_release(struct device *class_dev) } +static struct class pvr2_class = { + .name = "pvrusb2", + .dev_release = pvr2_sysfs_release, +}; + + static void class_dev_destroy(struct pvr2_sysfs *sfp) { struct device *dev; @@ -614,8 +607,7 @@ static ssize_t unit_number_show(struct device *class_dev, } -static void class_dev_create(struct pvr2_sysfs *sfp, - struct pvr2_sysfs_class *class_ptr) +static void class_dev_create(struct pvr2_sysfs *sfp) { struct usb_device *usb_dev; struct device *class_dev; @@ -628,7 +620,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); - class_dev->class = &class_ptr->class; + class_dev->class = &pvr2_class; dev_set_name(class_dev, "%s", pvr2_hdw_get_device_identifier(sfp->channel.hdw)); @@ -753,47 +745,30 @@ static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) } -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, - struct pvr2_sysfs_class *class_ptr) +void pvr2_sysfs_create(struct pvr2_context *mp) { struct pvr2_sysfs *sfp; sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); - if (!sfp) return sfp; + if (!sfp) + return; pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); pvr2_channel_init(&sfp->channel,mp); sfp->channel.check_func = pvr2_sysfs_internal_check; - class_dev_create(sfp,class_ptr); - return sfp; + class_dev_create(sfp); } - -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) +void pvr2_sysfs_class_create(void) { - struct pvr2_sysfs_class *clp; - clp = kzalloc(sizeof(*clp),GFP_KERNEL); - if (!clp) return clp; - pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", - clp); - clp->class.name = "pvrusb2"; - clp->class.class_release = pvr2_sysfs_class_release; - clp->class.dev_release = pvr2_sysfs_release; - if (class_register(&clp->class)) { - pvr2_sysfs_trace( - "Registration failed for pvr2_sysfs_class id=%p",clp); - kfree(clp); - clp = NULL; - } - return clp; + if (class_register(&pvr2_class)) + pvr2_sysfs_trace("Registration failed for pvr2_sysfs_class"); } -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) +void pvr2_sysfs_class_destroy(void) { - pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); - if (clp) - class_unregister(&clp->class); + class_unregister(&pvr2_class); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h index ac580ff39b5f..375a5372e95c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h @@ -10,13 +10,15 @@ #include #include "pvrusb2-context.h" -struct pvr2_sysfs; -struct pvr2_sysfs_class; +#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS +void pvr2_sysfs_class_create(void); +void pvr2_sysfs_class_destroy(void); +void pvr2_sysfs_create(struct pvr2_context *mp); +#else +static inline void pvr2_sysfs_class_create(void) { } +static inline void pvr2_sysfs_class_destroy(void) { } +static inline void pvr2_sysfs_create(struct pvr2_context *mp) { } +#endif -struct pvr2_sysfs_class *pvr2_sysfs_class_create(void); -void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *); - -struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, - struct pvr2_sysfs_class *); #endif /* __PVRUSB2_SYSFS_H */ diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 38822cedd93a..c4474d4c44e2 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1544,8 +1544,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) dvb_dmx_release(&dec->demux); if (dec->fe) { dvb_unregister_frontend(dec->fe); - if (dec->fe->ops.release) - dec->fe->ops.release(dec->fe); + dvb_frontend_detach(dec->fe); } dvb_unregister_adapter(&dec->adapter); } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 7aefa76a42b3..d631ce4f9f7b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -251,14 +251,17 @@ static int uvc_parse_format(struct uvc_device *dev, /* Find the format descriptor from its GUID. */ fmtdesc = uvc_format_by_guid(&buffer[5]); - if (fmtdesc != NULL) { - format->fcc = fmtdesc->fcc; - } else { + if (!fmtdesc) { + /* + * Unknown video formats are not fatal errors, the + * caller will skip this descriptor. + */ dev_info(&streaming->intf->dev, "Unknown video format %pUl\n", &buffer[5]); - format->fcc = 0; + return 0; } + format->fcc = fmtdesc->fcc; format->bpp = buffer[21]; /* @@ -675,7 +678,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, interval = (u32 *)&frame[nframes]; streaming->format = format; - streaming->nformats = nformats; + streaming->nformats = 0; /* Parse the format descriptors. */ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) { @@ -689,7 +692,10 @@ static int uvc_parse_streaming(struct uvc_device *dev, &interval, buffer, buflen); if (ret < 0) goto error; + if (!ret) + break; + streaming->nformats++; frame += format->nframes; format++; diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index bf0c18100664..22fe08fce0a9 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -314,8 +314,7 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, { struct fwnode_handle *endpoint; - if (!(sink->flags & MEDIA_PAD_FL_SINK) || - !is_media_entity_v4l2_subdev(sink->entity)) + if (!(sink->flags & MEDIA_PAD_FL_SINK)) return -EINVAL; fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) { diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 9b3ba2df71c7..4f0afce8428d 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6935,7 +6935,7 @@ EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); * @ioc: Pointer to MPT_ADAPTER structure * **/ -void +void __noreturn mpt_halt_firmware(MPT_ADAPTER *ioc) { u32 ioc_raw_state; diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index e0ba783de368..8031173c3655 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -944,7 +944,7 @@ extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num); extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); -extern void mpt_halt_firmware(MPT_ADAPTER *ioc); +extern void __noreturn mpt_halt_firmware(MPT_ADAPTER *ioc); /* diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 6ba7169cb953..aabac37c3502 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1117,8 +1117,7 @@ static int pm860x_dt_init(struct device_node *np, { int ret; - if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) - pdata->irq_mode = 1; + pdata->irq_mode = of_property_read_bool(np, "marvell,88pm860x-irq-read-clr"); ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", &pdata->companion_addr); if (ret) { @@ -1276,4 +1275,3 @@ module_exit(pm860x_i2c_exit); MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); MODULE_AUTHOR("Haojian Zhuang "); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fcc141e067b9..e90463c4441c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -266,6 +266,16 @@ config MFD_MADERA_SPI Support for the Cirrus Logic Madera platform audio SoC core functionality controlled via SPI. +config MFD_MAX597X + tristate "Maxim 597x power switch and monitor" + depends on (I2C && OF) + select MFD_SIMPLE_MFD_I2C + help + This driver controls a Maxim 5970/5978 switch via I2C bus. + The MAX5970/5978 is a smart switch with no output regulation, but + fault protection and voltage and current monitoring capabilities. + Also it supports upto 4 indication leds. + config MFD_CS47L15 bool "Cirrus Logic CS47L15" select PINCTRL_CS47L15 @@ -353,9 +363,6 @@ config MFD_DA9055 Additional drivers must be enabled in order to use the functionality of the device. - This driver can be built as a module. If built as a module it will be - called "da9055" - config MFD_DA9062 tristate "Dialog Semiconductor DA9062/61 PMIC Support" select MFD_CORE @@ -1308,6 +1315,16 @@ config MFD_SC27XX_PMIC This driver provides common support for accessing the SC27xx PMICs, and it also adds the irq_chip parts for handling the PMIC chip events. +config RZ_MTU3 + bool "Renesas RZ/G2L MTU3a core driver" + depends on (ARCH_RZG2L && OF) || COMPILE_TEST + help + Select this option to enable Renesas RZ/G2L MTU3a core driver for + the Multi-Function Timer Pulse Unit 3 (MTU3a) hardware available + on SoCs from Renesas. The core driver shares the clk and channel + register access for the other child devices like Counter, PWM, + Clock Source, and Clock event. + config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" depends on ARCH_U8500 || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2f6c89d1e277..1d2392f06f78 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -174,6 +174,7 @@ pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o +obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 5d3715a28b28..af205813b281 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -198,4 +198,3 @@ module_exit(altr_sysmgr_exit); MODULE_AUTHOR("Thor Thayer <>"); MODULE_DESCRIPTION("SOCFPGA System Manager driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index b2301586adbc..43e393c8608d 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -112,6 +112,7 @@ static const struct of_device_id arizona_i2c_of_match[] = { { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, {}, }; +MODULE_DEVICE_TABLE(of, arizona_i2c_of_match); #endif static struct i2c_driver arizona_i2c_driver = { diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index da05b966d48c..02cf4f3e91d7 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -277,6 +277,7 @@ static const struct of_device_id arizona_spi_of_match[] = { { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, {}, }; +MODULE_DEVICE_TABLE(of, arizona_spi_of_match); #endif static struct spi_driver arizona_spi_driver = { diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c index 19e248ed7966..8e1491167160 100644 --- a/drivers/mfd/atc260x-i2c.c +++ b/drivers/mfd/atc260x-i2c.c @@ -51,7 +51,7 @@ MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match); static struct i2c_driver atc260x_i2c_driver = { .driver = { .name = "atc260x", - .of_match_table = of_match_ptr(atc260x_i2c_of_match), + .of_match_table = atc260x_i2c_of_match, }, .probe_new = atc260x_i2c_probe, }; diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index 33caa4fba6af..b52f7ffdad35 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -37,7 +37,6 @@ struct atmel_flexcom { static int atmel_flexcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *res; struct atmel_flexcom *ddata; int err; @@ -55,8 +54,7 @@ static int atmel_flexcom_probe(struct platform_device *pdev) ddata->opmode > ATMEL_FLEXCOM_MODE_TWI) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ddata->base = devm_ioremap_resource(&pdev->dev, res); + ddata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(ddata->base)) return PTR_ERR(ddata->base); diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index f3bad2b52f17..e560066e5885 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -323,7 +323,7 @@ static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { .timing_regs_offset = 0x700, }; -static const struct of_device_id atmel_smc_ids[] = { +static const struct of_device_id atmel_smc_ids[] __maybe_unused = { { .compatible = "atmel,at91sam9260-smc", .data = NULL }, { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index f49fbd307958..b4f5cb457117 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, + { .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID }, { }, }; MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); @@ -78,6 +79,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = { { "axp223", 0 }, { "axp803", 0 }, { "axp806", 0 }, + { "axp15060", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 01a6bbb6d266..72b87aae60cc 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -43,6 +43,7 @@ static const char * const axp20x_model_names[] = { "AXP806", "AXP809", "AXP813", + "AXP15060", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -119,6 +120,7 @@ static const struct regmap_access_table axp22x_volatile_table = { /* AXP288 ranges are shared with the AXP803, as they cover the same range */ static const struct regmap_range axp288_writeable_ranges[] = { + regmap_reg_range(AXP288_POWER_REASON, AXP288_POWER_REASON), regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), }; @@ -168,6 +170,31 @@ static const struct regmap_access_table axp806_volatile_table = { .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges), }; +static const struct regmap_range axp15060_writeable_ranges[] = { + regmap_reg_range(AXP15060_PWR_OUT_CTRL1, AXP15060_DCDC_MODE_CTRL2), + regmap_reg_range(AXP15060_OUTPUT_MONITOR_DISCHARGE, AXP15060_CPUSLDO_V_CTRL), + regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), + regmap_reg_range(AXP15060_PEK_KEY, AXP15060_PEK_KEY), + regmap_reg_range(AXP15060_IRQ1_EN, AXP15060_IRQ2_EN), + regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), +}; + +static const struct regmap_range axp15060_volatile_ranges[] = { + regmap_reg_range(AXP15060_STARTUP_SRC, AXP15060_STARTUP_SRC), + regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ), + regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE), +}; + +static const struct regmap_access_table axp15060_writeable_table = { + .yes_ranges = axp15060_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp15060_writeable_ranges), +}; + +static const struct regmap_access_table axp15060_volatile_table = { + .yes_ranges = axp15060_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp15060_volatile_ranges), +}; + static const struct resource axp152_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"), DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), @@ -236,6 +263,11 @@ static const struct resource axp809_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static const struct resource axp15060_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_FAL_EDGE, "PEK_DBF"), +}; + static const struct regmap_config axp152_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -281,6 +313,15 @@ static const struct regmap_config axp806_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static const struct regmap_config axp15060_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp15060_writeable_table, + .volatile_table = &axp15060_volatile_table, + .max_register = AXP15060_IRQ2_STATE, + .cache_type = REGCACHE_RBTREE, +}; + #define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \ [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } @@ -502,6 +543,23 @@ static const struct regmap_irq axp809_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0), }; +static const struct regmap_irq axp15060_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV1, 0, 0), + INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV2, 0, 1), + INIT_REGMAP_IRQ(AXP15060, DCDC1_V_LOW, 0, 2), + INIT_REGMAP_IRQ(AXP15060, DCDC2_V_LOW, 0, 3), + INIT_REGMAP_IRQ(AXP15060, DCDC3_V_LOW, 0, 4), + INIT_REGMAP_IRQ(AXP15060, DCDC4_V_LOW, 0, 5), + INIT_REGMAP_IRQ(AXP15060, DCDC5_V_LOW, 0, 6), + INIT_REGMAP_IRQ(AXP15060, DCDC6_V_LOW, 0, 7), + INIT_REGMAP_IRQ(AXP15060, PEK_LONG, 1, 0), + INIT_REGMAP_IRQ(AXP15060, PEK_SHORT, 1, 1), + INIT_REGMAP_IRQ(AXP15060, GPIO1_INPUT, 1, 2), + INIT_REGMAP_IRQ(AXP15060, PEK_FAL_EDGE, 1, 3), + INIT_REGMAP_IRQ(AXP15060, PEK_RIS_EDGE, 1, 4), + INIT_REGMAP_IRQ(AXP15060, GPIO2_INPUT, 1, 5), +}; + static const struct regmap_irq_chip axp152_regmap_irq_chip = { .name = "axp152_irq_chip", .status_base = AXP152_IRQ1_STATE, @@ -581,6 +639,17 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = { .num_regs = 5, }; +static const struct regmap_irq_chip axp15060_regmap_irq_chip = { + .name = "axp15060", + .status_base = AXP15060_IRQ1_STATE, + .ack_base = AXP15060_IRQ1_STATE, + .unmask_base = AXP15060_IRQ1_EN, + .init_ack_masked = true, + .irqs = axp15060_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp15060_regmap_irqs), + .num_regs = 2, +}; + static const struct mfd_cell axp20x_cells[] = { { .name = "axp20x-gpio", @@ -825,6 +894,23 @@ static const struct mfd_cell axp813_cells[] = { }, }; +static const struct mfd_cell axp15060_cells[] = { + { + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp15060_pek_resources), + .resources = axp15060_pek_resources, + }, { + .name = "axp20x-regulator", + }, +}; + +/* For boards that don't have IRQ line connected to SOC. */ +static const struct mfd_cell axp_regulator_only_cells[] = { + { + .name = "axp20x-regulator", + }, +}; + static int axp20x_power_off(struct sys_off_data *data) { struct axp20x_dev *axp20x = data->cb_data; @@ -934,6 +1020,28 @@ int axp20x_match_device(struct axp20x_dev *axp20x) */ axp20x->regmap_irq_chip = &axp803_regmap_irq_chip; break; + case AXP15060_ID: + /* + * Don't register the power key part if there is no interrupt + * line. + * + * Since most use cases of AXP PMICs are Allwinner SOCs, board + * designers follow Allwinner's reference design and connects + * IRQ line to SOC, there's no need for those variants to deal + * with cases that IRQ isn't connected. However, AXP15660 is + * used by some other vendors' SOCs that didn't connect IRQ + * line, we need to deal with this case. + */ + if (axp20x->irq > 0) { + axp20x->nr_cells = ARRAY_SIZE(axp15060_cells); + axp20x->cells = axp15060_cells; + } else { + axp20x->nr_cells = ARRAY_SIZE(axp_regulator_only_cells); + axp20x->cells = axp_regulator_only_cells; + } + axp20x->regmap_cfg = &axp15060_regmap_config; + axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip; + break; default: dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); return -EINVAL; diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c index 49cd1f03884a..3cb2b9423121 100644 --- a/drivers/mfd/bcm2835-pm.c +++ b/drivers/mfd/bcm2835-pm.c @@ -28,7 +28,7 @@ static const struct mfd_cell bcm2835_power_devs[] = { static int bcm2835_pm_get_pdata(struct platform_device *pdev, struct bcm2835_pm *pm) { - if (of_find_property(pm->dev->of_node, "reg-names", NULL)) { + if (of_property_present(pm->dev->of_node, "reg-names")) { struct resource *res; pm->base = devm_platform_ioremap_resource_byname(pdev, "pm"); @@ -123,4 +123,3 @@ module_platform_driver(bcm2835_pm_driver); MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 02d4271dfe06..92f4dfccc3cc 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -20,7 +20,6 @@ #define DRV_NAME "cros-ec-dev" static struct class cros_class = { - .owner = THIS_MODULE, .name = "chromeos", }; diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 44a25d642ce9..6570b33a5a77 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -563,4 +563,3 @@ module_exit(da903x_exit); MODULE_DESCRIPTION("PMIC Driver for Dialog Semiconductor DA9034"); MODULE_AUTHOR("Eric Miao "); MODULE_AUTHOR("Mike Rapoport "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 8b42d2f7024f..150448cd2eb0 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -653,4 +653,3 @@ void da9052_device_exit(struct da9052 *da9052) MODULE_AUTHOR("David Dajun Chen "); MODULE_DESCRIPTION("DA9052 MFD Core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index ecb8077cdaaf..03db7a2ccf7a 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -209,4 +209,3 @@ module_exit(da9052_i2c_exit); MODULE_AUTHOR("David Dajun Chen "); MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index b79a57b45c1e..be5f2b34e18a 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -102,4 +102,3 @@ module_exit(da9052_spi_exit); MODULE_AUTHOR("David Dajun Chen "); MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index c3bcbd8905c6..768302e05baa 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -398,5 +398,4 @@ void da9055_device_exit(struct da9055 *da9055) } MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Dajun Chen "); diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 702abff506a1..537fd5de3e6d 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -97,4 +97,3 @@ module_exit(da9055_i2c_exit); MODULE_AUTHOR("David Dajun Chen "); MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 40cde51e5719..d073d5f106ec 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -181,35 +181,25 @@ static const struct resource da9061_onkey_resources[] = { DEFINE_RES_IRQ_NAMED(DA9061_IRQ_ONKEY, "ONKEY"), }; -static const struct mfd_cell da9061_devs[] = { - { - .name = "da9061-core", - .num_resources = ARRAY_SIZE(da9061_core_resources), - .resources = da9061_core_resources, - }, - { - .name = "da9062-regulators", - .num_resources = ARRAY_SIZE(da9061_regulators_resources), - .resources = da9061_regulators_resources, - }, - { - .name = "da9061-watchdog", - .num_resources = ARRAY_SIZE(da9061_wdt_resources), - .resources = da9061_wdt_resources, - .of_compatible = "dlg,da9061-watchdog", - }, - { - .name = "da9061-thermal", - .num_resources = ARRAY_SIZE(da9061_thermal_resources), - .resources = da9061_thermal_resources, - .of_compatible = "dlg,da9061-thermal", - }, - { - .name = "da9061-onkey", - .num_resources = ARRAY_SIZE(da9061_onkey_resources), - .resources = da9061_onkey_resources, - .of_compatible = "dlg,da9061-onkey", - }, +static const struct mfd_cell da9061_devs_irq[] = { + MFD_CELL_OF("da9061-core", da9061_core_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-regulators", da9061_regulators_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9061-watchdog", da9061_wdt_resources, NULL, 0, 0, + "dlg,da9061-watchdog"), + MFD_CELL_OF("da9061-thermal", da9061_thermal_resources, NULL, 0, 0, + "dlg,da9061-thermal"), + MFD_CELL_OF("da9061-onkey", da9061_onkey_resources, NULL, 0, 0, + "dlg,da9061-onkey"), +}; + +static const struct mfd_cell da9061_devs_noirq[] = { + MFD_CELL_OF("da9061-core", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-regulators", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9061-watchdog", NULL, NULL, 0, 0, "dlg,da9061-watchdog"), + MFD_CELL_OF("da9061-thermal", NULL, NULL, 0, 0, "dlg,da9061-thermal"), + MFD_CELL_OF("da9061-onkey", NULL, NULL, 0, 0, "dlg,da9061-onkey"), }; static const struct resource da9062_core_resources[] = { @@ -245,47 +235,31 @@ static const struct resource da9062_gpio_resources[] = { DEFINE_RES_NAMED(DA9062_IRQ_GPI4, 1, "GPI4", IORESOURCE_IRQ), }; -static const struct mfd_cell da9062_devs[] = { - { - .name = "da9062-core", - .num_resources = ARRAY_SIZE(da9062_core_resources), - .resources = da9062_core_resources, - }, - { - .name = "da9062-regulators", - .num_resources = ARRAY_SIZE(da9062_regulators_resources), - .resources = da9062_regulators_resources, - }, - { - .name = "da9062-watchdog", - .num_resources = ARRAY_SIZE(da9062_wdt_resources), - .resources = da9062_wdt_resources, - .of_compatible = "dlg,da9062-watchdog", - }, - { - .name = "da9062-thermal", - .num_resources = ARRAY_SIZE(da9062_thermal_resources), - .resources = da9062_thermal_resources, - .of_compatible = "dlg,da9062-thermal", - }, - { - .name = "da9062-rtc", - .num_resources = ARRAY_SIZE(da9062_rtc_resources), - .resources = da9062_rtc_resources, - .of_compatible = "dlg,da9062-rtc", - }, - { - .name = "da9062-onkey", - .num_resources = ARRAY_SIZE(da9062_onkey_resources), - .resources = da9062_onkey_resources, - .of_compatible = "dlg,da9062-onkey", - }, - { - .name = "da9062-gpio", - .num_resources = ARRAY_SIZE(da9062_gpio_resources), - .resources = da9062_gpio_resources, - .of_compatible = "dlg,da9062-gpio", - }, +static const struct mfd_cell da9062_devs_irq[] = { + MFD_CELL_OF("da9062-core", da9062_core_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-regulators", da9062_regulators_resources, NULL, 0, 0, + NULL), + MFD_CELL_OF("da9062-watchdog", da9062_wdt_resources, NULL, 0, 0, + "dlg,da9062-watchdog"), + MFD_CELL_OF("da9062-thermal", da9062_thermal_resources, NULL, 0, 0, + "dlg,da9062-thermal"), + MFD_CELL_OF("da9062-rtc", da9062_rtc_resources, NULL, 0, 0, + "dlg,da9062-rtc"), + MFD_CELL_OF("da9062-onkey", da9062_onkey_resources, NULL, 0, 0, + "dlg,da9062-onkey"), + MFD_CELL_OF("da9062-gpio", da9062_gpio_resources, NULL, 0, 0, + "dlg,da9062-gpio"), +}; + +static const struct mfd_cell da9062_devs_noirq[] = { + MFD_CELL_OF("da9062-core", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-regulators", NULL, NULL, 0, 0, NULL), + MFD_CELL_OF("da9062-watchdog", NULL, NULL, 0, 0, "dlg,da9062-watchdog"), + MFD_CELL_OF("da9062-thermal", NULL, NULL, 0, 0, "dlg,da9062-thermal"), + MFD_CELL_OF("da9062-rtc", NULL, NULL, 0, 0, "dlg,da9062-rtc"), + MFD_CELL_OF("da9062-onkey", NULL, NULL, 0, 0, "dlg,da9062-onkey"), + MFD_CELL_OF("da9062-gpio", NULL, NULL, 0, 0, "dlg,da9062-gpio"), }; static int da9062_clear_fault_log(struct da9062 *chip) @@ -625,7 +599,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c) { const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct da9062 *chip; - unsigned int irq_base; + unsigned int irq_base = 0; const struct mfd_cell *cell; const struct regmap_irq_chip *irq_chip; const struct regmap_config *config; @@ -645,22 +619,16 @@ static int da9062_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, chip); chip->dev = &i2c->dev; - if (!i2c->irq) { - dev_err(chip->dev, "No IRQ configured\n"); - return -EINVAL; - } - + /* Start with a base configuration without IRQ */ switch (chip->chip_type) { case COMPAT_TYPE_DA9061: - cell = da9061_devs; - cell_num = ARRAY_SIZE(da9061_devs); - irq_chip = &da9061_irq_chip; + cell = da9061_devs_noirq; + cell_num = ARRAY_SIZE(da9061_devs_noirq); config = &da9061_regmap_config; break; case COMPAT_TYPE_DA9062: - cell = da9062_devs; - cell_num = ARRAY_SIZE(da9062_devs); - irq_chip = &da9062_irq_chip; + cell = da9062_devs_noirq; + cell_num = ARRAY_SIZE(da9062_devs_noirq); config = &da9062_regmap_config; break; default: @@ -695,29 +663,43 @@ static int da9062_i2c_probe(struct i2c_client *i2c) if (ret) return ret; - ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type); - if (ret < 0) { - dev_err(chip->dev, "Failed to configure IRQ type\n"); - return ret; - } + /* If IRQ is available, reconfigure it accordingly */ + if (i2c->irq) { + if (chip->chip_type == COMPAT_TYPE_DA9061) { + cell = da9061_devs_irq; + cell_num = ARRAY_SIZE(da9061_devs_irq); + irq_chip = &da9061_irq_chip; + } else { + cell = da9062_devs_irq; + cell_num = ARRAY_SIZE(da9062_devs_irq); + irq_chip = &da9062_irq_chip; + } - ret = regmap_add_irq_chip(chip->regmap, i2c->irq, - trigger_type | IRQF_SHARED | IRQF_ONESHOT, - -1, irq_chip, &chip->regmap_irq); - if (ret) { - dev_err(chip->dev, "Failed to request IRQ %d: %d\n", - i2c->irq, ret); - return ret; - } + ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type); + if (ret < 0) { + dev_err(chip->dev, "Failed to configure IRQ type\n"); + return ret; + } - irq_base = regmap_irq_chip_get_base(chip->regmap_irq); + ret = regmap_add_irq_chip(chip->regmap, i2c->irq, + trigger_type | IRQF_SHARED | IRQF_ONESHOT, + -1, irq_chip, &chip->regmap_irq); + if (ret) { + dev_err(chip->dev, "Failed to request IRQ %d: %d\n", + i2c->irq, ret); + return ret; + } + + irq_base = regmap_irq_chip_get_base(chip->regmap_irq); + } ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell, cell_num, NULL, irq_base, NULL); if (ret) { dev_err(chip->dev, "Cannot register child devices\n"); - regmap_del_irq_chip(i2c->irq, chip->regmap_irq); + if (i2c->irq) + regmap_del_irq_chip(i2c->irq, chip->regmap_irq); return ret; } diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index 6cd0b0c752d6..c3149729cec2 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -827,6 +827,7 @@ out_stop_rx: dln2_stop_rx_urbs(dln2); out_free: + usb_put_dev(dln2->usb_dev); dln2_free(dln2); return ret; diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 3d5ce18aa9ae..8d006f6be48c 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -528,7 +528,6 @@ static void __exit ezx_pcap_exit(void) subsys_initcall(ezx_pcap_init); module_exit(ezx_pcap_exit); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); MODULE_DESCRIPTION("Motorola PCAP2 ASIC Driver"); MODULE_ALIAS("spi:ezx-pcap"); diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c index eba88b80d969..cb5cf4a81c06 100644 --- a/drivers/mfd/hi6421-pmic-core.c +++ b/drivers/mfd/hi6421-pmic-core.c @@ -50,7 +50,6 @@ MODULE_DEVICE_TABLE(of, of_hi6421_pmic_match); static int hi6421_pmic_probe(struct platform_device *pdev) { struct hi6421_pmic *pmic; - struct resource *res; const struct of_device_id *id; const struct mfd_cell *subdevs; enum hi6421_type type; @@ -66,8 +65,7 @@ static int hi6421_pmic_probe(struct platform_device *pdev) if (!pmic) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index dde31c50a632..699f44ffff0e 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -447,6 +447,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x7e79), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e7a), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e7b), (kernel_ulong_t)&bxt_i2c_info }, + /* MTP-S */ + { PCI_VDEVICE(INTEL, 0x7f28), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f29), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f4c), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4d), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4e), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f4f), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f5c), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f5d), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f7a), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7f7b), (kernel_ulong_t)&bxt_i2c_info }, /* LKF */ { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index d53dae255490..871776d511e3 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -159,11 +159,19 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), }, }, { - /* Lenovo Yoga Book X90F / X91F / X91L */ + /* Lenovo Yoga Book X90F / X90L */ .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, .matches = { - /* Non exact match to match all versions */ - DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), + }, + }, { + /* Lenovo Yoga Book X91F / X91L */ + .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, + .matches = { + /* Non exact match to match F + L versions */ + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), }, }, { /* Lenovo Yoga Tab 3 Pro YT3-X90F */ diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index b1548a933dc3..b745ace46e5b 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -271,6 +271,5 @@ static struct i2c_driver crystal_cove_i2c_driver = { module_i2c_driver(crystal_cove_i2c_driver); MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC"); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yang, Bin "); MODULE_AUTHOR("Zhu, Lejun "); diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index 4cd5ecc72211..6d3968458e81 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -381,7 +381,6 @@ static int __maybe_unused micro_resume(struct device *dev) static int __init micro_probe(struct platform_device *pdev) { struct ipaq_micro *micro; - struct resource *res; int ret; int irq; @@ -391,8 +390,7 @@ static int __init micro_probe(struct platform_device *pdev) micro->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - micro->base = devm_ioremap_resource(&pdev->dev, res); + micro->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(micro->base)) return PTR_ERR(micro->base); diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c index 7338cc16f327..1c807c0e6d25 100644 --- a/drivers/mfd/khadas-mcu.c +++ b/drivers/mfd/khadas-mcu.c @@ -112,7 +112,7 @@ static int khadas_mcu_probe(struct i2c_client *client) if (ret) return ret; - if (of_find_property(dev->of_node, "#cooling-cells", NULL)) + if (of_property_present(dev->of_node, "#cooling-cells")) return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, khadas_mcu_fan_cells, ARRAY_SIZE(khadas_mcu_fan_cells), diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index fe809b64147e..18583addaae2 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -244,4 +244,3 @@ module_exit(lp8788_exit); MODULE_DESCRIPTION("TI LP8788 MFD Driver"); MODULE_AUTHOR("Milo Kim"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 16d1861e9682..695d50b3bac6 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -33,32 +33,6 @@ static struct device_type mfd_dev_type = { .name = "mfd_device", }; -int mfd_cell_enable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->enable) { - dev_dbg(&pdev->dev, "No .enable() call-back registered\n"); - return 0; - } - - return cell->enable(pdev); -} -EXPORT_SYMBOL(mfd_cell_enable); - -int mfd_cell_disable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->disable) { - dev_dbg(&pdev->dev, "No .disable() call-back registered\n"); - return 0; - } - - return cell->disable(pdev); -} -EXPORT_SYMBOL(mfd_cell_disable); - #if IS_ENABLED(CONFIG_ACPI) struct match_ids_walk_data { struct acpi_device_id *ids; diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c index 2d1349a10ca9..94f82677675b 100644 --- a/drivers/mfd/ocelot-spi.c +++ b/drivers/mfd/ocelot-spi.c @@ -130,6 +130,7 @@ static const struct regmap_config ocelot_spi_regmap_config = { .write_flag_mask = 0x80, + .use_single_read = true, .use_single_write = true, .can_multi_write = false, diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 787d2ae86375..7f5775109593 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -853,7 +853,6 @@ static struct platform_driver usbhs_omap_driver = { MODULE_AUTHOR("Keshava Munegowda "); MODULE_AUTHOR("Roger Quadros "); MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); static int omap_usbhs_drvinit(void) diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 080d7970a377..69cbc2097911 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -125,11 +125,6 @@ static inline void usbtll_writeb(void __iomem *base, u32 reg, u8 val) writeb_relaxed(val, base + reg); } -static inline u8 usbtll_readb(void __iomem *base, u32 reg) -{ - return readb_relaxed(base + reg); -} - /*-------------------------------------------------------------------------*/ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) @@ -450,7 +445,6 @@ EXPORT_SYMBOL_GPL(omap_tll_disable); MODULE_AUTHOR("Keshava Munegowda "); MODULE_AUTHOR("Roger Quadros "); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); static int __init omap_usbtll_drvinit(void) diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c index 9f3c4a01b4c1..837246aab4ac 100644 --- a/drivers/mfd/qcom-pm8008.c +++ b/drivers/mfd/qcom-pm8008.c @@ -44,37 +44,16 @@ enum { #define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE #define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE -#define PM8008_STATUS_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_STS_OFFSET) -#define PM8008_MASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_SET_OFFSET) -#define PM8008_UNMASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_CLR_OFFSET) -#define PM8008_TYPE_BASE (PM8008_PERIPH_0_BASE | INT_SET_TYPE_OFFSET) -#define PM8008_ACK_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_CLR_OFFSET) -#define PM8008_POLARITY_HI_BASE (PM8008_PERIPH_0_BASE | INT_POL_HIGH_OFFSET) -#define PM8008_POLARITY_LO_BASE (PM8008_PERIPH_0_BASE | INT_POL_LOW_OFFSET) - -#define PM8008_PERIPH_OFFSET(paddr) (paddr - PM8008_PERIPH_0_BASE) - -static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)}; -static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)}; -static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)}; -static unsigned int p3_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_3_BASE)}; - -static struct regmap_irq_sub_irq_map pm8008_sub_reg_offsets[] = { - REGMAP_IRQ_MAIN_REG_OFFSET(p0_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p1_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p2_offs), - REGMAP_IRQ_MAIN_REG_OFFSET(p3_offs), -}; - -static unsigned int pm8008_virt_regs[] = { - PM8008_POLARITY_HI_BASE, - PM8008_POLARITY_LO_BASE, -}; - enum { + SET_TYPE_INDEX, POLARITY_HI_INDEX, POLARITY_LO_INDEX, - PM8008_NUM_VIRT_REGS, +}; + +static unsigned int pm8008_config_regs[] = { + INT_SET_TYPE_OFFSET, + INT_POL_HIGH_OFFSET, + INT_POL_LOW_OFFSET, }; static struct regmap_irq pm8008_irqs[] = { @@ -88,32 +67,54 @@ static struct regmap_irq pm8008_irqs[] = { REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)), }; -static int pm8008_set_type_virt(unsigned int **virt_buf, - unsigned int type, unsigned long hwirq, - int reg) +static const unsigned int pm8008_periph_base[] = { + PM8008_PERIPH_0_BASE, + PM8008_PERIPH_1_BASE, + PM8008_PERIPH_2_BASE, + PM8008_PERIPH_3_BASE, +}; + +static unsigned int pm8008_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + /* Simple linear addressing for the main status register */ + if (base == I2C_INTR_STATUS_BASE) + return base + index; + + return pm8008_periph_base[index] + base; +} + +static int pm8008_set_type_config(unsigned int **buf, unsigned int type, + const struct regmap_irq *irq_data, int idx, + void *irq_drv_data) { switch (type) { case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - virt_buf[POLARITY_HI_INDEX][reg] &= ~pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] &= ~irq_data->mask; + buf[POLARITY_LO_INDEX][idx] |= irq_data->mask; break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] &= ~pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] |= irq_data->mask; + buf[POLARITY_LO_INDEX][idx] &= ~irq_data->mask; break; case IRQ_TYPE_EDGE_BOTH: - virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask; - virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask; + buf[POLARITY_HI_INDEX][idx] |= irq_data->mask; + buf[POLARITY_LO_INDEX][idx] |= irq_data->mask; break; default: return -EINVAL; } + if (type & IRQ_TYPE_EDGE_BOTH) + buf[SET_TYPE_INDEX][idx] |= irq_data->mask; + else + buf[SET_TYPE_INDEX][idx] &= ~irq_data->mask; + return 0; } @@ -121,20 +122,19 @@ static struct regmap_irq_chip pm8008_irq_chip = { .name = "pm8008_irq", .main_status = I2C_INTR_STATUS_BASE, .num_main_regs = 1, - .num_virt_regs = PM8008_NUM_VIRT_REGS, .irqs = pm8008_irqs, .num_irqs = ARRAY_SIZE(pm8008_irqs), .num_regs = PM8008_NUM_PERIPHS, - .not_fixed_stride = true, - .sub_reg_offsets = pm8008_sub_reg_offsets, - .set_type_virt = pm8008_set_type_virt, - .status_base = PM8008_STATUS_BASE, - .mask_base = PM8008_MASK_BASE, - .unmask_base = PM8008_UNMASK_BASE, - .type_base = PM8008_TYPE_BASE, - .ack_base = PM8008_ACK_BASE, - .virt_reg_base = pm8008_virt_regs, - .num_type_reg = PM8008_NUM_PERIPHS, + .status_base = INT_LATCHED_STS_OFFSET, + .mask_base = INT_EN_CLR_OFFSET, + .unmask_base = INT_EN_SET_OFFSET, + .mask_unmask_non_inverted = true, + .ack_base = INT_LATCHED_CLR_OFFSET, + .config_base = pm8008_config_regs, + .num_config_bases = ARRAY_SIZE(pm8008_config_regs), + .num_config_regs = PM8008_NUM_PERIPHS, + .set_type_config = pm8008_set_type_config, + .get_irq_reg = pm8008_get_irq_reg, }; static struct regmap_config qcom_mfd_regmap_cfg = { @@ -143,30 +143,6 @@ static struct regmap_config qcom_mfd_regmap_cfg = { .max_register = 0xFFFF, }; -static int pm8008_init(struct regmap *regmap) -{ - int rc; - - /* - * Set TEMP_ALARM peripheral's TYPE so that the regmap-irq framework - * reads this as the default value instead of zero, the HW default. - * This is required to enable the writing of TYPE registers in - * regmap_irq_sync_unlock(). - */ - rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - if (rc) - return rc; - - /* Do the same for GPIO1 and GPIO2 peripherals */ - rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - if (rc) - return rc; - - rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); - - return rc; -} - static int pm8008_probe_irq_peripherals(struct device *dev, struct regmap *regmap, int client_irq) @@ -175,20 +151,10 @@ static int pm8008_probe_irq_peripherals(struct device *dev, struct regmap_irq_type *type; struct regmap_irq_chip_data *irq_data; - rc = pm8008_init(regmap); - if (rc) { - dev_err(dev, "Init failed: %d\n", rc); - return rc; - } - for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) { type = &pm8008_irqs[i].type; - type->type_reg_offset = pm8008_irqs[i].reg_offset; - type->type_rising_val = pm8008_irqs[i].mask; - type->type_falling_val = pm8008_irqs[i].mask; - type->type_level_high_val = 0; - type->type_level_low_val = 0; + type->type_reg_offset = pm8008_irqs[i].reg_offset; if (type->type_reg_offset == PM8008_MISC) type->types_supported = IRQ_TYPE_EDGE_RISING; diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c index 8fea0e511550..086611322874 100644 --- a/drivers/mfd/qcom_rpm.c +++ b/drivers/mfd/qcom_rpm.c @@ -530,7 +530,6 @@ static int qcom_rpm_probe(struct platform_device *pdev) { const struct of_device_id *match; struct device_node *syscon_np; - struct resource *res; struct qcom_rpm *rpm; u32 fw_version[3]; int irq_wakeup; @@ -576,8 +575,7 @@ static int qcom_rpm_probe(struct platform_device *pdev) return -ENODEV; rpm->data = match->data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rpm->status_regs = devm_ioremap_resource(&pdev->dev, res); + rpm->status_regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(rpm->status_regs)) return PTR_ERR(rpm->status_regs); rpm->ctrl_regs = rpm->status_regs + 0x400; diff --git a/drivers/mfd/rsmu.h b/drivers/mfd/rsmu.h index bb88597d189f..1bb04cafa45d 100644 --- a/drivers/mfd/rsmu.h +++ b/drivers/mfd/rsmu.h @@ -10,6 +10,8 @@ #include +#define RSMU_CM_SCSR_BASE 0x20100000 + int rsmu_core_init(struct rsmu_ddata *rsmu); void rsmu_core_exit(struct rsmu_ddata *rsmu); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index 15d25b081434..807c32101460 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -18,11 +18,12 @@ #include "rsmu.h" /* - * 16-bit register address: the lower 8 bits of the register address come - * from the offset addr byte and the upper 8 bits come from the page register. + * 32-bit register address: the lower 8 bits of the register address come + * from the offset addr byte and the upper 24 bits come from the page register. */ -#define RSMU_CM_PAGE_ADDR 0xFD -#define RSMU_CM_PAGE_WINDOW 256 +#define RSMU_CM_PAGE_ADDR 0xFC +#define RSMU_CM_PAGE_MASK 0xFFFFFF00 +#define RSMU_CM_ADDRESS_MASK 0x000000FF /* * 15-bit register address: the lower 7 bits of the register address come @@ -31,18 +32,6 @@ #define RSMU_SABRE_PAGE_ADDR 0x7F #define RSMU_SABRE_PAGE_WINDOW 128 -static const struct regmap_range_cfg rsmu_cm_range_cfg[] = { - { - .range_min = 0, - .range_max = 0xD000, - .selector_reg = RSMU_CM_PAGE_ADDR, - .selector_mask = 0xFF, - .selector_shift = 0, - .window_start = 0, - .window_len = RSMU_CM_PAGE_WINDOW, - } -}; - static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { { .range_min = 0, @@ -55,16 +44,6 @@ static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { } }; -static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case RSMU_CM_PAGE_ADDR: - return false; - default: - return true; - } -} - static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -75,15 +54,131 @@ static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) } } +static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + struct i2c_msg msg[2]; + int cnt; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = bytes; + msg[1].buf = buf; + + cnt = i2c_transfer(client->adapter, msg, 2); + + if (cnt < 0) { + dev_err(rsmu->dev, "i2c_transfer failed at addr: %04x!", reg); + return cnt; + } else if (cnt != 2) { + dev_err(rsmu->dev, + "i2c_transfer sent only %d of 2 messages", cnt); + return -EIO; + } + + return 0; +} + +static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + u8 msg[RSMU_MAX_WRITE_COUNT + 1]; /* 1 Byte added for the device register */ + int cnt; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; + + msg[0] = reg; + memcpy(&msg[1], buf, bytes); + + cnt = i2c_master_send(client, msg, bytes + 1); + + if (cnt < 0) { + dev_err(&client->dev, + "i2c_master_send failed at addr: %04x!", reg); + return cnt; + } + + return 0; +} + +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) +{ + u32 page = reg & RSMU_CM_PAGE_MASK; + u8 buf[4]; + int err; + + /* Do not modify offset register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; + + /* Simply return if we are on the same page */ + if (rsmu->page == page) + return 0; + + buf[0] = 0x0; + buf[1] = (u8)((page >> 8) & 0xFF); + buf[2] = (u8)((page >> 16) & 0xFF); + buf[3] = (u8)((page >> 24) & 0xFF); + + err = rsmu_write_device(rsmu, RSMU_CM_PAGE_ADDR, buf, sizeof(buf)); + if (err) + dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page); + else + /* Remember the last page */ + rsmu->page = page; + + return err; +} + +static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_read_device(rsmu, addr, (u8 *)val, 1); + if (err) + dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); + + return err; +} + +static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + u8 data = (u8)val; + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_write_device(rsmu, addr, &data, 1); + if (err) + dev_err(rsmu->dev, + "Failed to write offset address 0x%x\n", addr); + + return err; +} + static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 8, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, - .ranges = rsmu_cm_range_cfg, - .num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg), - .volatile_reg = rsmu_cm_volatile_reg, - .cache_type = REGCACHE_RBTREE, - .can_multi_write = true, + .max_register = 0x20120000, + .reg_read = rsmu_reg_read, + .reg_write = rsmu_reg_write, + .cache_type = REGCACHE_NONE, }; static const struct regmap_config rsmu_sabre_regmap_config = { @@ -101,7 +196,7 @@ static const struct regmap_config rsmu_sl_regmap_config = { .reg_bits = 16, .val_bits = 8, .reg_format_endian = REGMAP_ENDIAN_BIG, - .max_register = 0x339, + .max_register = 0x340, .cache_type = REGCACHE_NONE, .can_multi_write = true, }; @@ -136,7 +231,11 @@ static int rsmu_i2c_probe(struct i2c_client *client) dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); return -ENODEV; } - rsmu->regmap = devm_regmap_init_i2c(client, cfg); + + if (rsmu->type == RSMU_CM) + rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg); + else + rsmu->regmap = devm_regmap_init_i2c(client, cfg); if (IS_ERR(rsmu->regmap)) { ret = PTR_ERR(rsmu->regmap); dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index d2f3d8f1e05a..a4a595bb8d0d 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -19,19 +19,21 @@ #define RSMU_CM_PAGE_ADDR 0x7C #define RSMU_SABRE_PAGE_ADDR 0x7F -#define RSMU_HIGHER_ADDR_MASK 0xFF80 -#define RSMU_HIGHER_ADDR_SHIFT 7 -#define RSMU_LOWER_ADDR_MASK 0x7F +#define RSMU_PAGE_MASK 0xFFFFFF80 +#define RSMU_ADDR_MASK 0x7F static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) { struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; - u8 rsp[256] = {0}; + u8 cmd[RSMU_MAX_READ_COUNT + 1] = {0}; + u8 rsp[RSMU_MAX_READ_COUNT + 1] = {0}; int ret; + if (bytes > RSMU_MAX_READ_COUNT) + return -EINVAL; + cmd[0] = reg | 0x80; xfer.rx_buf = rsp; xfer.len = bytes + 1; @@ -66,7 +68,10 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; + u8 cmd[RSMU_MAX_WRITE_COUNT + 1] = {0}; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; cmd[0] = reg; memcpy(&cmd[1], buf, bytes); @@ -86,26 +91,35 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes * 16-bit register address: the lower 7 bits of the register address come * from the offset addr byte and the upper 9 bits come from the page register. */ -static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) { u8 page_reg; - u8 buf[2]; + u8 buf[4]; u16 bytes; - u16 page; + u32 page; int err; switch (rsmu->type) { case RSMU_CM: + /* Do not modify page register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; page_reg = RSMU_CM_PAGE_ADDR; - page = reg & RSMU_HIGHER_ADDR_MASK; + page = reg & RSMU_PAGE_MASK; buf[0] = (u8)(page & 0xff); buf[1] = (u8)((page >> 8) & 0xff); - bytes = 2; + buf[2] = (u8)((page >> 16) & 0xff); + buf[3] = (u8)((page >> 24) & 0xff); + bytes = 4; break; case RSMU_SABRE: + /* Do not modify page register if reg is page register itself */ + if ((reg & RSMU_ADDR_MASK) == RSMU_ADDR_MASK) + return 0; page_reg = RSMU_SABRE_PAGE_ADDR; - page = reg >> RSMU_HIGHER_ADDR_SHIFT; - buf[0] = (u8)(page & 0xff); + page = reg & RSMU_PAGE_MASK; + /* The three page bits are located in the single Page Register */ + buf[0] = (u8)((page >> 7) & 0x7); bytes = 1; break; default: @@ -130,7 +144,7 @@ static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) { struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); int err; err = rsmu_write_page_register(rsmu, reg); @@ -147,7 +161,7 @@ static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) { struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); u8 data = (u8)val; int err; @@ -164,9 +178,9 @@ static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) } static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 16, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, + .max_register = 0x20120000, .reg_read = rsmu_reg_read, .reg_write = rsmu_reg_write, .cache_type = REGCACHE_NONE, diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c new file mode 100644 index 000000000000..04006f4aa702 --- /dev/null +++ b/drivers/mfd/rz-mtu3.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rz-mtu3.h" + +struct rz_mtu3_priv { + void __iomem *mmio; + struct reset_control *rstc; + raw_spinlock_t lock; +}; + +/******* MTU3 registers (original offset is +0x1200) *******/ +static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = { + [RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126), + [RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182), + [RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202), + [RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038), + [RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039), + [RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6), + [RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838), + [RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839), + [RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403) +}; + +static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = { + [RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122), + [RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a), + [RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a), + [RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072), + [RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a), + [RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2), + [RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872), + [RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a) +}; + +static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = { + [RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8), + [RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418) +}; + +static bool rz_mtu3_is_16bit_shared_reg(u16 offset) +{ + return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB || + offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB || + offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB || + offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB); +} + +u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + return readw(priv->mmio + offset); + else + return readb(priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read); + +u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + + return readb(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read); + +u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + + return readw(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read); + +u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + + return readl(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read); + +void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + writeb(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write); + +void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + writew(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write); + +void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + writel(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write); + +void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + writew(value, priv->mmio + offset); + else + writeb((u8)value, priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write); + +void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset, + u16 pos, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long tmdr, flags; + + raw_spin_lock_irqsave(&priv->lock, flags); + tmdr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(pos, &tmdr, !!val); + rz_mtu3_shared_reg_write(ch, offset, tmdr); + raw_spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit); + +static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch) +{ + u16 offset; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_3: + case RZ_MTU3_CHAN_4: + case RZ_MTU3_CHAN_8: + offset = RZ_MTU3_TSTRA; + break; + case RZ_MTU3_CHAN_5: + offset = RZ_MTU3_TSTR; + break; + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + offset = RZ_MTU3_TSTRB; + break; + default: + offset = 0; + break; + } + + return offset; +} + +static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch) +{ + u8 bitpos; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + bitpos = ch->channel_number; + break; + case RZ_MTU3_CHAN_3: + bitpos = 6; + break; + case RZ_MTU3_CHAN_4: + bitpos = 7; + break; + case RZ_MTU3_CHAN_5: + bitpos = 2; + break; + case RZ_MTU3_CHAN_8: + bitpos = 3; + break; + default: + bitpos = 0; + break; + } + + return bitpos; +} + +static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(bitpos, &tstr, start); + rz_mtu3_shared_reg_write(ch, offset, tstr); + + raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + bool ret = false; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + ret = tstr & BIT(bitpos); + + raw_spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled); + +int rz_mtu3_enable(struct rz_mtu3_channel *ch) +{ + /* enable channel */ + rz_mtu3_start_stop_ch(ch, true); + + return 0; +} +EXPORT_SYMBOL_GPL(rz_mtu3_enable); + +void rz_mtu3_disable(struct rz_mtu3_channel *ch) +{ + /* disable channel */ + rz_mtu3_start_stop_ch(ch, false); +} +EXPORT_SYMBOL_GPL(rz_mtu3_disable); + +static void rz_mtu3_reset_assert(void *data) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(data); + struct rz_mtu3_priv *priv = mtu->priv_data; + + mfd_remove_devices(data); + reset_control_assert(priv->rstc); +} + +static const struct mfd_cell rz_mtu3_devs[] = { + { + .name = "rz-mtu3-counter", + }, + { + .name = "pwm-rz-mtu3", + }, +}; + +static int rz_mtu3_probe(struct platform_device *pdev) +{ + struct rz_mtu3_priv *priv; + struct rz_mtu3 *ddata; + unsigned int i; + int ret; + + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!ddata->priv_data) + return -ENOMEM; + + priv = ddata->priv_data; + + priv->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio)) + return PTR_ERR(priv->mmio); + + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + + ddata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); + + reset_control_deassert(priv->rstc); + raw_spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, ddata); + + for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) { + ddata->channels[i].channel_number = i; + ddata->channels[i].is_busy = false; + mutex_init(&ddata->channels[i].lock); + } + + ret = mfd_add_devices(&pdev->dev, 0, rz_mtu3_devs, + ARRAY_SIZE(rz_mtu3_devs), NULL, 0, NULL); + if (ret < 0) + goto err_assert; + + return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert, + &pdev->dev); + +err_assert: + reset_control_assert(priv->rstc); + return ret; +} + +static const struct of_device_id rz_mtu3_of_match[] = { + { .compatible = "renesas,rz-mtu3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rz_mtu3_of_match); + +static struct platform_driver rz_mtu3_driver = { + .probe = rz_mtu3_probe, + .driver = { + .name = "rz-mtu3", + .of_match_table = rz_mtu3_of_match, + }, +}; +module_platform_driver(rz_mtu3_driver); + +MODULE_AUTHOR("Biju Das "); +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rz-mtu3.h b/drivers/mfd/rz-mtu3.h new file mode 100644 index 000000000000..51a1298b0613 --- /dev/null +++ b/drivers/mfd/rz-mtu3.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MFD internals for Renesas RZ/G2L MTU3 Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#ifndef RZ_MTU3_MFD_H +#define RZ_MTU3_MFD_H + +#define MTU_8BIT_CH_0(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } + +#define MTU_8BIT_CH_1_2(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tior) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIOR] = _tior \ + } \ + +#define MTU_8BIT_CH_3_4_6_7(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } \ + +#define MTU_8BIT_CH_5(_tier, _nfcr, _tstr, _tcntcmpclr, _tcru, _tcr2u, _tioru, \ + _tcrv, _tcr2v, _tiorv, _tcrw, _tcr2w, _tiorw) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSTR] = _tstr, \ + [RZ_MTU3_TCNTCMPCLR] = _tcntcmpclr, \ + [RZ_MTU3_TCRU] = _tcru, \ + [RZ_MTU3_TCR2U] = _tcr2u, \ + [RZ_MTU3_TIORU] = _tioru, \ + [RZ_MTU3_TCRV] = _tcrv, \ + [RZ_MTU3_TCR2V] = _tcr2v, \ + [RZ_MTU3_TIORV] = _tiorv, \ + [RZ_MTU3_TCRW] = _tcrw, \ + [RZ_MTU3_TCR2W] = _tcr2w, \ + [RZ_MTU3_TIORW] = _tiorw \ + } \ + +#define MTU_8BIT_CH_8(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl \ + } \ + +#define MTU_16BIT_CH_0(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf \ + } + +#define MTU_16BIT_CH_1_2(_tcnt, _tgra, _tgrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb \ + } + +#define MTU_16BIT_CH_3_6(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre \ + } + +#define MTU_16BIT_CH_4_7(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf, \ + _tadcr, _tadcora, _tadcorb, _tadcobra, _tadcobrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf, \ + [RZ_MTU3_TADCR] = _tadcr, \ + [RZ_MTU3_TADCORA] = _tadcora, \ + [RZ_MTU3_TADCORB] = _tadcorb, \ + [RZ_MTU3_TADCOBRA] = _tadcobra, \ + [RZ_MTU3_TADCOBRB] = _tadcobrb \ + } + +#define MTU_16BIT_CH_5(_tcntu, _tgru, _tcntv, _tgrv, _tcntw, _tgrw) \ + { \ + [RZ_MTU3_TCNTU] = _tcntu, \ + [RZ_MTU3_TGRU] = _tgru, \ + [RZ_MTU3_TCNTV] = _tcntv, \ + [RZ_MTU3_TGRV] = _tgrv, \ + [RZ_MTU3_TCNTW] = _tcntw, \ + [RZ_MTU3_TGRW] = _tgrw \ + } + +#define MTU_32BIT_CH_1(_tcntlw, _tgralw, _tgrblw) \ + { \ + [RZ_MTU3_TCNTLW] = _tcntlw, \ + [RZ_MTU3_TGRALW] = _tgralw, \ + [RZ_MTU3_TGRBLW] = _tgrblw \ + } + +#define MTU_32BIT_CH_8(_tcnt, _tgra, _tgrb, _tgrc, _tgrd) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd \ + } + +#endif diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index b03edda56009..c2d0ed496959 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -24,22 +24,9 @@ #include #include #include -#include #include #include -static const struct mfd_cell s5m8751_devs[] = { - { .name = "s5m8751-pmic", }, - { .name = "s5m-charger", }, - { .name = "s5m8751-codec", }, -}; - -static const struct mfd_cell s5m8763_devs[] = { - { .name = "s5m8763-pmic", }, - { .name = "s5m-rtc", }, - { .name = "s5m-charger", }, -}; - static const struct mfd_cell s5m8767_devs[] = { { .name = "s5m8767-pmic", }, { .name = "s5m-rtc", }, @@ -158,19 +145,6 @@ static bool s2mpu02_volatile(struct device *dev, unsigned int reg) } } -static bool s5m8763_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S5M8763_REG_IRQM1: - case S5M8763_REG_IRQM2: - case S5M8763_REG_IRQM3: - case S5M8763_REG_IRQM4: - return false; - default: - return true; - } -} - static const struct regmap_config sec_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -230,15 +204,6 @@ static const struct regmap_config s2mpu02_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config s5m8763_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S5M8763_REG_LBCNFG2, - .volatile_reg = s5m8763_volatile, - .cache_type = REGCACHE_FLAT, -}; - static const struct regmap_config s5m8767_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -348,9 +313,6 @@ static int sec_pmic_probe(struct i2c_client *i2c) case S2MPS15X: regmap = &s2mps15_regmap_config; break; - case S5M8763X: - regmap = &s5m8763_regmap_config; - break; case S5M8767X: regmap = &s5m8767_regmap_config; break; @@ -375,14 +337,6 @@ static int sec_pmic_probe(struct i2c_client *i2c) pm_runtime_set_active(sec_pmic->dev); switch (sec_pmic->device_type) { - case S5M8751X: - sec_devs = s5m8751_devs; - num_sec_devs = ARRAY_SIZE(s5m8751_devs); - break; - case S5M8763X: - sec_devs = s5m8763_devs; - num_sec_devs = ARRAY_SIZE(s5m8763_devs); - break; case S5M8767X: sec_devs = s5m8767_devs; num_sec_devs = ARRAY_SIZE(s5m8767_devs); diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index f5f59fdc72fe..e191aeb0c07c 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include static const struct regmap_irq s2mps11_irqs[] = { @@ -297,81 +296,6 @@ static const struct regmap_irq s5m8767_irqs[] = { }, }; -static const struct regmap_irq s5m8763_irqs[] = { - [S5M8763_IRQ_DCINF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_DCINF_MASK, - }, - [S5M8763_IRQ_DCINR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_DCINR_MASK, - }, - [S5M8763_IRQ_JIGF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_JIGF_MASK, - }, - [S5M8763_IRQ_JIGR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_JIGR_MASK, - }, - [S5M8763_IRQ_PWRONF] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_PWRONF_MASK, - }, - [S5M8763_IRQ_PWRONR] = { - .reg_offset = 0, - .mask = S5M8763_IRQ_PWRONR_MASK, - }, - [S5M8763_IRQ_WTSREVNT] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_WTSREVNT_MASK, - }, - [S5M8763_IRQ_SMPLEVNT] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_SMPLEVNT_MASK, - }, - [S5M8763_IRQ_ALARM1] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_ALARM1_MASK, - }, - [S5M8763_IRQ_ALARM0] = { - .reg_offset = 1, - .mask = S5M8763_IRQ_ALARM0_MASK, - }, - [S5M8763_IRQ_ONKEY1S] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_ONKEY1S_MASK, - }, - [S5M8763_IRQ_TOPOFFR] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_TOPOFFR_MASK, - }, - [S5M8763_IRQ_DCINOVPR] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_DCINOVPR_MASK, - }, - [S5M8763_IRQ_CHGRSTF] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_CHGRSTF_MASK, - }, - [S5M8763_IRQ_DONER] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_DONER_MASK, - }, - [S5M8763_IRQ_CHGFAULT] = { - .reg_offset = 2, - .mask = S5M8763_IRQ_CHGFAULT_MASK, - }, - [S5M8763_IRQ_LOBAT1] = { - .reg_offset = 3, - .mask = S5M8763_IRQ_LOBAT1_MASK, - }, - [S5M8763_IRQ_LOBAT2] = { - .reg_offset = 3, - .mask = S5M8763_IRQ_LOBAT2_MASK, - }, -}; - static const struct regmap_irq_chip s2mps11_irq_chip = { .name = "s2mps11", .irqs = s2mps11_irqs, @@ -425,16 +349,6 @@ static const struct regmap_irq_chip s5m8767_irq_chip = { .ack_base = S5M8767_REG_INT1, }; -static const struct regmap_irq_chip s5m8763_irq_chip = { - .name = "s5m8763", - .irqs = s5m8763_irqs, - .num_irqs = ARRAY_SIZE(s5m8763_irqs), - .num_regs = 4, - .status_base = S5M8763_REG_IRQ1, - .mask_base = S5M8763_REG_IRQM1, - .ack_base = S5M8763_REG_IRQ1, -}; - int sec_irq_init(struct sec_pmic_dev *sec_pmic) { int ret = 0; @@ -448,9 +362,6 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) } switch (type) { - case S5M8763X: - sec_irq_chip = &s5m8763_irq_chip; - break; case S5M8767X: sec_irq_chip = &s5m8767_irq_chip; break; diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c index f32f1fb93e37..c9a0ec084aa8 100644 --- a/drivers/mfd/si476x-cmd.c +++ b/drivers/mfd/si476x-cmd.c @@ -251,7 +251,7 @@ static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) * @usecs: amount of time to wait before reading the response (in * usecs) * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ static int si476x_core_send_command(struct si476x_core *core, @@ -398,7 +398,7 @@ static int si476x_cmd_tune_seek_freq(struct si476x_core *core, * The command requests the firmware and patch version for currently * loaded firmware (dependent on the function of the device FM/AM/WB) * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ int si476x_core_cmd_func_info(struct si476x_core *core, @@ -429,7 +429,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); * @property: property address * @value: property value * - * Function returns 0 on succsess and negative error code on + * Function returns 0 on success and negative error code on * failure */ int si476x_core_cmd_set_property(struct si476x_core *core, @@ -545,13 +545,13 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); * SI476X_IQCLK_NOOP - do not modify the behaviour * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown - * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace + * SI476X_IQCLK_IQ - set pin to be a part of I/Q interface * in master mode * @iqfs: - IQFS pin function configuration: * SI476X_IQFS_NOOP - do not modify the behaviour * SI476X_IQFS_TRISTATE - put the pin in tristate condition, * enable 1MOhm pulldown - * SI476X_IQFS_IQ - set pin to be a part of I/Q interace + * SI476X_IQFS_IQ - set pin to be a part of I/Q interface * in master mode * @iout: - IOUT pin function configuration: * SI476X_IOUT_NOOP - do not modify the behaviour @@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); /** * si476x_core_cmd_ic_link_gpo_ctl_pin_cfg - send - * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device + * 'IC_LINK_GPIO_CTL_PIN_CFG' command to the device * @core: - device to send the command to * @icin: - ICIN pin function configuration: * SI476X_ICIN_NOOP - do not modify the behaviour @@ -1014,7 +1014,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); * NOTE caller must hold core lock * * Function returns the value of the status bit in case of success and - * negative error code in case of failre. + * negative error code in case of failure. */ int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) { diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index e31f13fd6a79..20782b4dd172 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -72,9 +72,22 @@ static const struct simple_mfd_data silergy_sy7636a = { .mfd_cell_size = ARRAY_SIZE(sy7636a_cells), }; +static const struct mfd_cell max597x_cells[] = { + { .name = "max597x-regulator", }, + { .name = "max597x-iio", }, + { .name = "max597x-led", }, +}; + +static const struct simple_mfd_data maxim_max597x = { + .mfd_cell = max597x_cells, + .mfd_cell_size = ARRAY_SIZE(max597x_cells), +}; + static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max597x}, + { .compatible = "maxim,max5978", .data = &maxim_max597x}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c index 94f60df0decd..dee89db3471d 100644 --- a/drivers/mfd/ssbi.c +++ b/drivers/mfd/ssbi.c @@ -262,7 +262,6 @@ EXPORT_SYMBOL_GPL(ssbi_write); static int ssbi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *mem_res; struct ssbi *ssbi; const char *type; @@ -270,8 +269,7 @@ static int ssbi_probe(struct platform_device *pdev) if (!ssbi) return -ENOMEM; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ssbi->base = devm_ioremap_resource(&pdev->dev, mem_res); + ssbi->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(ssbi->base)) return PTR_ERR(ssbi->base); diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index d4944fc1feb1..7998e0db1e15 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -135,6 +135,5 @@ static void __exit stmpe_exit(void) } module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver"); MODULE_AUTHOR("Rabin Vincent "); diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index e9cbf33502b3..792236f56399 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -154,6 +154,5 @@ static void __exit stmpe_exit(void) } module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); MODULE_AUTHOR("Viresh Kumar "); diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index c304d20bb988..a92301dfc712 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1378,7 +1378,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) stmpe_of_probe(pdata, np); - if (of_find_property(np, "interrupts", NULL) == NULL) + if (!of_property_present(np, "interrupts")) ci->irq = -1; stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c index edc180d83a4b..d1cbea27b136 100644 --- a/drivers/mfd/sun4i-gpadc.c +++ b/drivers/mfd/sun4i-gpadc.c @@ -93,7 +93,6 @@ MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match); static int sun4i_gpadc_probe(struct platform_device *pdev) { struct sun4i_gpadc_dev *dev; - struct resource *mem; const struct of_device_id *of_id; const struct mfd_cell *cells; unsigned int irq, size; @@ -124,8 +123,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(&pdev->dev, mem); + dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 1f6e0d682cd9..cbfe19d1b145 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -502,6 +502,5 @@ static void __exit tc3589x_exit(void) } module_exit(tc3589x_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("TC3589x MFD core driver"); MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 2d947f3f606a..90e23232b6b0 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -638,4 +638,3 @@ module_exit(tps6586x_exit); MODULE_DESCRIPTION("TPS6586X core driver"); MODULE_AUTHOR("Mike Rapoport "); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c index 7ae906ff8e35..fac02875fe7d 100644 --- a/drivers/mfd/tqmx86.c +++ b/drivers/mfd/tqmx86.c @@ -16,8 +16,8 @@ #include #include -#define TQMX86_IOBASE 0x160 -#define TQMX86_IOSIZE 0x3f +#define TQMX86_IOBASE 0x180 +#define TQMX86_IOSIZE 0x20 #define TQMX86_IOBASE_I2C 0x1a0 #define TQMX86_IOSIZE_I2C 0xa #define TQMX86_IOBASE_WATCHDOG 0x18b @@ -25,14 +25,14 @@ #define TQMX86_IOBASE_GPIO 0x18d #define TQMX86_IOSIZE_GPIO 0x4 -#define TQMX86_REG_BOARD_ID 0x20 +#define TQMX86_REG_BOARD_ID 0x00 #define TQMX86_REG_BOARD_ID_E38M 1 #define TQMX86_REG_BOARD_ID_50UC 2 #define TQMX86_REG_BOARD_ID_E38C 3 #define TQMX86_REG_BOARD_ID_60EB 4 -#define TQMX86_REG_BOARD_ID_E39M 5 -#define TQMX86_REG_BOARD_ID_E39C 6 -#define TQMX86_REG_BOARD_ID_E39x 7 +#define TQMX86_REG_BOARD_ID_E39MS 5 +#define TQMX86_REG_BOARD_ID_E39C1 6 +#define TQMX86_REG_BOARD_ID_E39C2 7 #define TQMX86_REG_BOARD_ID_70EB 8 #define TQMX86_REG_BOARD_ID_80UC 9 #define TQMX86_REG_BOARD_ID_110EB 11 @@ -40,18 +40,18 @@ #define TQMX86_REG_BOARD_ID_E40S 13 #define TQMX86_REG_BOARD_ID_E40C1 14 #define TQMX86_REG_BOARD_ID_E40C2 15 -#define TQMX86_REG_BOARD_REV 0x21 -#define TQMX86_REG_IO_EXT_INT 0x26 +#define TQMX86_REG_BOARD_REV 0x01 +#define TQMX86_REG_IO_EXT_INT 0x06 #define TQMX86_REG_IO_EXT_INT_NONE 0 #define TQMX86_REG_IO_EXT_INT_7 1 #define TQMX86_REG_IO_EXT_INT_9 2 #define TQMX86_REG_IO_EXT_INT_12 3 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 +#define TQMX86_REG_SAUC 0x17 -#define TQMX86_REG_I2C_DETECT 0x47 +#define TQMX86_REG_I2C_DETECT 0x1a7 #define TQMX86_REG_I2C_DETECT_SOFT 0xa5 -#define TQMX86_REG_I2C_INT_EN 0x49 static uint gpio_irq; module_param(gpio_irq, uint, 0); @@ -111,7 +111,7 @@ static const struct mfd_cell tqmx86_devs[] = { }, }; -static const char *tqmx86_board_id_to_name(u8 board_id) +static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) { switch (board_id) { case TQMX86_REG_BOARD_ID_E38M: @@ -122,12 +122,12 @@ static const char *tqmx86_board_id_to_name(u8 board_id) return "TQMxE38C"; case TQMX86_REG_BOARD_ID_60EB: return "TQMx60EB"; - case TQMX86_REG_BOARD_ID_E39M: - return "TQMxE39M"; - case TQMX86_REG_BOARD_ID_E39C: - return "TQMxE39C"; - case TQMX86_REG_BOARD_ID_E39x: - return "TQMxE39x"; + case TQMX86_REG_BOARD_ID_E39MS: + return (sauc == 0xff) ? "TQMxE39M" : "TQMxE39S"; + case TQMX86_REG_BOARD_ID_E39C1: + return "TQMxE39C1"; + case TQMX86_REG_BOARD_ID_E39C2: + return "TQMxE39C2"; case TQMX86_REG_BOARD_ID_70EB: return "TQMx70EB"; case TQMX86_REG_BOARD_ID_80UC: @@ -160,9 +160,9 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) case TQMX86_REG_BOARD_ID_E40C1: case TQMX86_REG_BOARD_ID_E40C2: return 24000; - case TQMX86_REG_BOARD_ID_E39M: - case TQMX86_REG_BOARD_ID_E39C: - case TQMX86_REG_BOARD_ID_E39x: + case TQMX86_REG_BOARD_ID_E39MS: + case TQMX86_REG_BOARD_ID_E39C1: + case TQMX86_REG_BOARD_ID_E39C2: return 25000; case TQMX86_REG_BOARD_ID_E38M: case TQMX86_REG_BOARD_ID_E38C: @@ -176,7 +176,7 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) static int tqmx86_probe(struct platform_device *pdev) { - u8 board_id, rev, i2c_det, io_ext_int_val; + u8 board_id, sauc, rev, i2c_det, io_ext_int_val; struct device *dev = &pdev->dev; u8 gpio_irq_cfg, readback; const char *board_name; @@ -206,14 +206,20 @@ static int tqmx86_probe(struct platform_device *pdev) return -ENOMEM; board_id = ioread8(io_base + TQMX86_REG_BOARD_ID); - board_name = tqmx86_board_id_to_name(board_id); + sauc = ioread8(io_base + TQMX86_REG_SAUC); + board_name = tqmx86_board_id_to_name(board_id, sauc); rev = ioread8(io_base + TQMX86_REG_BOARD_REV); dev_info(dev, "Found %s - Board ID %d, PCB Revision %d, PLD Revision %d\n", board_name, board_id, rev >> 4, rev & 0xf); - i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT); + /* + * The I2C_DETECT register is in the range assigned to the I2C driver + * later, so we don't extend TQMX86_IOSIZE. Use inb() for this one-off + * access instead of ioport_map + unmap. + */ + i2c_det = inb(TQMX86_REG_I2C_DETECT); if (gpio_irq_cfg) { io_ext_int_val = diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e2d9a93be43b..e801b7ce010f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -594,71 +594,6 @@ int twl_get_hfclk_rate(void) } EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); -static struct device * -add_numbered_child(unsigned mod_no, const char *name, int num, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - struct platform_device *pdev; - struct twl_client *twl; - int status, sid; - - if (unlikely(mod_no >= twl_get_last_module())) { - pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); - return ERR_PTR(-EPERM); - } - sid = twl_priv->twl_map[mod_no].sid; - twl = &twl_priv->twl_modules[sid]; - - pdev = platform_device_alloc(name, num); - if (!pdev) - return ERR_PTR(-ENOMEM); - - pdev->dev.parent = &twl->client->dev; - - if (pdata) { - status = platform_device_add_data(pdev, pdata, pdata_len); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add platform_data\n"); - goto put_device; - } - } - - if (irq0) { - struct resource r[2] = { - { .start = irq0, .flags = IORESOURCE_IRQ, }, - { .start = irq1, .flags = IORESOURCE_IRQ, }, - }; - - status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add irqs\n"); - goto put_device; - } - } - - status = platform_device_add(pdev); - if (status) - goto put_device; - - device_init_wakeup(&pdev->dev, can_wakeup); - - return &pdev->dev; - -put_device: - platform_device_put(pdev); - dev_err(&twl->client->dev, "failed to add device %s\n", name); - return ERR_PTR(status); -} - -static inline struct device *add_child(unsigned mod_no, const char *name, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - return add_numbered_child(mod_no, name, -1, pdata, pdata_len, - can_wakeup, irq0, irq1); -} - /*----------------------------------------------------------------------*/ /* diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 4536d829b43e..88002f8941e5 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -285,5 +285,4 @@ module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi "); MODULE_DESCRIPTION("TWL4030 audio block MFD driver"); -MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:twl4030-audio"); diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index fc97fa5a2d0c..e982119bbefa 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -839,4 +839,3 @@ module_i2c_driver(twl6040_driver); MODULE_DESCRIPTION("TWL6040 MFD"); MODULE_AUTHOR("Misael Lopez Cruz "); MODULE_AUTHOR("Jorge Eduardo Candelaria "); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index a89221bffde5..c419ab0c0eae 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -279,20 +279,11 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, ARRAY_SIZE(pdata->micbias)); - pdata->lineout1_diff = true; - pdata->lineout2_diff = true; - if (of_find_property(np, "wlf,lineout1-se", NULL)) - pdata->lineout1_diff = false; - if (of_find_property(np, "wlf,lineout2-se", NULL)) - pdata->lineout2_diff = false; - - if (of_find_property(np, "wlf,lineout1-feedback", NULL)) - pdata->lineout1fb = true; - if (of_find_property(np, "wlf,lineout2-feedback", NULL)) - pdata->lineout2fb = true; - - if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) - pdata->lineout2fb = true; + pdata->lineout1_diff = !of_property_read_bool(np, "wlf,lineout1-se"); + pdata->lineout2_diff = !of_property_read_bool(np, "wlf,lineout2-se"); + pdata->lineout1fb = of_property_read_bool(np, "wlf,lineout1-feedback"); + pdata->lineout2fb = of_property_read_bool(np, "wlf,lineout2-feedback") || + of_property_read_bool(np, "wlf,ldoena-always-driven"); pdata->spkmode_pu = of_property_read_bool(np, "wlf,spkmode-pu"); diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c index fb9a1b49ff6d..f574c83b82cf 100644 --- a/drivers/misc/c2port/core.c +++ b/drivers/misc/c2port/core.c @@ -977,7 +977,7 @@ static int __init c2port_init(void) printk(KERN_INFO "Silicon Labs C2 port support v. " DRIVER_VERSION " - (C) 2007 Rodolfo Giometti\n"); - c2port_class = class_create(THIS_MODULE, "c2port"); + c2port_class = class_create("c2port"); if (IS_ERR(c2port_class)) { printk(KERN_ERR "c2port: failed to allocate class\n"); return PTR_ERR(c2port_class); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index 9080f9f150a2..0142c4bf4f42 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -95,160 +95,6 @@ u32 alcor_read32be(struct alcor_pci_priv *priv, unsigned int addr) } EXPORT_SYMBOL_GPL(alcor_read32be); -static int alcor_pci_find_cap_offset(struct alcor_pci_priv *priv, - struct pci_dev *pci) -{ - int where; - u8 val8; - u32 val32; - - where = ALCOR_CAP_START_OFFSET; - pci_read_config_byte(pci, where, &val8); - if (!val8) - return 0; - - where = (int)val8; - while (1) { - pci_read_config_dword(pci, where, &val32); - if (val32 == 0xffffffff) { - dev_dbg(priv->dev, "find_cap_offset invalid value %x.\n", - val32); - return 0; - } - - if ((val32 & 0xff) == 0x10) { - dev_dbg(priv->dev, "pcie cap offset: %x\n", where); - return where; - } - - if ((val32 & 0xff00) == 0x00) { - dev_dbg(priv->dev, "pci_find_cap_offset invalid value %x.\n", - val32); - break; - } - where = (int)((val32 >> 8) & 0xff); - } - - return 0; -} - -static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv) -{ - struct pci_dev *pci; - int where; - u32 val32; - - priv->pdev_cap_off = alcor_pci_find_cap_offset(priv, priv->pdev); - /* - * A device might be attached to root complex directly and - * priv->parent_pdev will be NULL. In this case we don't check its - * capability and disable ASPM completely. - */ - if (priv->parent_pdev) - priv->parent_cap_off = alcor_pci_find_cap_offset(priv, - priv->parent_pdev); - - if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) { - dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n", - priv->pdev_cap_off, priv->parent_cap_off); - return; - } - - /* link capability */ - pci = priv->pdev; - where = priv->pdev_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET; - pci_read_config_dword(pci, where, &val32); - priv->pdev_aspm_cap = (u8)(val32 >> 10) & 0x03; - - pci = priv->parent_pdev; - where = priv->parent_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET; - pci_read_config_dword(pci, where, &val32); - priv->parent_aspm_cap = (u8)(val32 >> 10) & 0x03; - - if (priv->pdev_aspm_cap != priv->parent_aspm_cap) { - u8 aspm_cap; - - dev_dbg(priv->dev, "pdev_aspm_cap: %x, parent_aspm_cap: %x\n", - priv->pdev_aspm_cap, priv->parent_aspm_cap); - aspm_cap = priv->pdev_aspm_cap & priv->parent_aspm_cap; - priv->pdev_aspm_cap = aspm_cap; - priv->parent_aspm_cap = aspm_cap; - } - - dev_dbg(priv->dev, "ext_config_dev_aspm: %x, pdev_aspm_cap: %x\n", - priv->ext_config_dev_aspm, priv->pdev_aspm_cap); - priv->ext_config_dev_aspm &= priv->pdev_aspm_cap; -} - -static void alcor_pci_aspm_ctrl(struct alcor_pci_priv *priv, u8 aspm_enable) -{ - struct pci_dev *pci; - u8 aspm_ctrl, i; - int where; - u32 val32; - - if ((!priv->pdev_cap_off) || (!priv->parent_cap_off)) { - dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n", - priv->pdev_cap_off, priv->parent_cap_off); - return; - } - - if (!priv->pdev_aspm_cap) - return; - - aspm_ctrl = 0; - if (aspm_enable) { - aspm_ctrl = priv->ext_config_dev_aspm; - - if (!aspm_ctrl) { - dev_dbg(priv->dev, "aspm_ctrl == 0\n"); - return; - } - } - - for (i = 0; i < 2; i++) { - - if (i) { - pci = priv->parent_pdev; - where = priv->parent_cap_off - + ALCOR_PCIE_LINK_CTRL_OFFSET; - } else { - pci = priv->pdev; - where = priv->pdev_cap_off - + ALCOR_PCIE_LINK_CTRL_OFFSET; - } - - pci_read_config_dword(pci, where, &val32); - val32 &= (~0x03); - val32 |= (aspm_ctrl & priv->pdev_aspm_cap); - pci_write_config_byte(pci, where, (u8)val32); - } - -} - -static inline void alcor_mask_sd_irqs(struct alcor_pci_priv *priv) -{ - alcor_write32(priv, 0, AU6601_REG_INT_ENABLE); -} - -static inline void alcor_unmask_sd_irqs(struct alcor_pci_priv *priv) -{ - alcor_write32(priv, AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK | - AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE | - AU6601_INT_OVER_CURRENT_ERR, - AU6601_REG_INT_ENABLE); -} - -static inline void alcor_mask_ms_irqs(struct alcor_pci_priv *priv) -{ - alcor_write32(priv, 0, AU6601_MS_INT_ENABLE); -} - -static inline void alcor_unmask_ms_irqs(struct alcor_pci_priv *priv) -{ - alcor_write32(priv, 0x3d00fa, AU6601_MS_INT_ENABLE); -} - static int alcor_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -308,7 +154,6 @@ static int alcor_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); pci_set_drvdata(pdev, priv); - alcor_pci_init_check_aspm(priv); for (i = 0; i < ARRAY_SIZE(alcor_pci_cells); i++) { alcor_pci_cells[i].platform_data = priv; @@ -319,7 +164,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, if (ret < 0) goto error_clear_drvdata; - alcor_pci_aspm_ctrl(priv, 0); + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); return 0; @@ -339,8 +184,6 @@ static void alcor_pci_remove(struct pci_dev *pdev) priv = pci_get_drvdata(pdev); - alcor_pci_aspm_ctrl(priv, 1); - mfd_remove_devices(&pdev->dev); ida_free(&alcor_pci_idr, priv->id); @@ -353,18 +196,16 @@ static void alcor_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int alcor_suspend(struct device *dev) { - struct alcor_pci_priv *priv = dev_get_drvdata(dev); - - alcor_pci_aspm_ctrl(priv, 1); return 0; } static int alcor_resume(struct device *dev) { - struct alcor_pci_priv *priv = dev_get_drvdata(dev); - alcor_pci_aspm_ctrl(priv, 0); + pci_disable_link_state(priv->pdev, + PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 5878329b011a..144d1f2d78ce 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -678,7 +678,7 @@ int __init cxl_file_init(void) pr_devel("CXL device allocated, MAJOR %i\n", MAJOR(cxl_dev)); - cxl_class = class_create(THIS_MODULE, "cxl"); + cxl_class = class_create("cxl"); if (IS_ERR(cxl_class)) { pr_err("Unable to create CXL class\n"); rc = PTR_ERR(cxl_class); diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 4ba966529458..76511d279aff 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -451,7 +451,6 @@ ATTRIBUTE_GROUPS(enclosure_class); static struct class enclosure_class = { .name = "enclosure", - .owner = THIS_MODULE, .dev_release = enclosure_release, .dev_groups = enclosure_class_groups, }; diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index f48466960f1b..30d4d0476248 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -316,12 +316,14 @@ static void fastrpc_free_map(struct kref *ref) if (map->table) { if (map->attr & FASTRPC_ATTR_SECUREMAP) { struct qcom_scm_vmperm perm; + int vmid = map->fl->cctx->vmperms[0].vmid; + u64 src_perms = BIT(QCOM_SCM_VMID_HLOS) | BIT(vmid); int err = 0; perm.vmid = QCOM_SCM_VMID_HLOS; perm.perm = QCOM_SCM_PERM_RWX; err = qcom_scm_assign_mem(map->phys, map->size, - &map->fl->cctx->perms, &perm, 1); + &src_perms, &perm, 1); if (err) { dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", map->phys, map->size, err); @@ -787,8 +789,12 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, goto map_err; } - map->phys = sg_dma_address(map->table->sgl); - map->phys += ((u64)fl->sctx->sid << 32); + if (attr & FASTRPC_ATTR_SECUREMAP) { + map->phys = sg_phys(map->table->sgl); + } else { + map->phys = sg_dma_address(map->table->sgl); + map->phys += ((u64)fl->sctx->sid << 32); + } map->size = len; map->va = sg_virt(map->table->sgl); map->len = len; @@ -798,9 +804,15 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, * If subsystem VMIDs are defined in DTSI, then do * hyp_assign from HLOS to those VM(s) */ + u64 src_perms = BIT(QCOM_SCM_VMID_HLOS); + struct qcom_scm_vmperm dst_perms[2] = {0}; + + dst_perms[0].vmid = QCOM_SCM_VMID_HLOS; + dst_perms[0].perm = QCOM_SCM_PERM_RW; + dst_perms[1].vmid = fl->cctx->vmperms[0].vmid; + dst_perms[1].perm = QCOM_SCM_PERM_RWX; map->attr = attr; - err = qcom_scm_assign_mem(map->phys, (u64)map->size, &fl->cctx->perms, - fl->cctx->vmperms, fl->cctx->vmcount); + err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2); if (err) { dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", map->phys, map->size, err); @@ -1892,7 +1904,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) req.vaddrout = rsp_msg.vaddr; /* Add memory to static PD pool, protection thru hypervisor */ - if (req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) { + if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) { struct qcom_scm_vmperm perm; perm.vmid = QCOM_SCM_VMID_HLOS; @@ -2337,8 +2349,10 @@ static void fastrpc_notify_users(struct fastrpc_user *user) struct fastrpc_invoke_ctx *ctx; spin_lock(&user->lock); - list_for_each_entry(ctx, &user->pending, node) + list_for_each_entry(ctx, &user->pending, node) { + ctx->retval = -EPIPE; complete(&ctx->work); + } spin_unlock(&user->lock); } @@ -2349,7 +2363,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) struct fastrpc_user *user; unsigned long flags; + /* No invocations past this point */ spin_lock_irqsave(&cctx->lock, flags); + cctx->rpdev = NULL; list_for_each_entry(user, &cctx->users, user) fastrpc_notify_users(user); spin_unlock_irqrestore(&cctx->lock, flags); @@ -2368,7 +2384,6 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) of_platform_depopulate(&rpdev->dev); - cctx->rpdev = NULL; fastrpc_channel_ctx_put(cctx); } diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index 5b63d179b24e..b03010810b89 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -1099,7 +1098,6 @@ static int genwqe_pci_setup(struct genwqe_dev *cd) } pci_set_master(pci_dev); - pci_enable_pcie_error_reporting(pci_dev); /* EEH recovery requires PCIe fundamental reset */ pci_dev->needs_freset = 1; @@ -1363,7 +1361,7 @@ static int __init genwqe_init_module(void) { int rc; - class_genwqe = class_create(THIS_MODULE, GENWQE_DEVNAME); + class_genwqe = class_create(GENWQE_DEVNAME); if (IS_ERR(class_genwqe)) { pr_err("[%s] create class failed\n", __func__); return -ENOMEM; diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index f778e11237a6..1c798d6b2dfb 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -210,7 +210,7 @@ u32 genwqe_crc32(u8 *buff, size_t len, u32 init) void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size, dma_addr_t *dma_handle) { - if (get_order(size) >= MAX_ORDER) + if (get_order(size) > MAX_ORDER) return NULL; return dma_alloc_coherent(&cd->pci_dev->dev, size, dma_handle, diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 8d00df9243c4..2fde8d63c5fe 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -392,12 +392,6 @@ static inline int is_db_reset(int db_out) return db_out & (1 << DB_RESET); } -static inline int is_device_reset(struct ilo_hwinfo *hw) -{ - /* check for global reset condition */ - return is_db_reset(get_device_outbound(hw)); -} - static inline void clear_pending_db(struct ilo_hwinfo *hw, int clr) { iowrite32(clr, &hw->mmio_vaddr[DB_OUT]); @@ -888,7 +882,7 @@ static int __init ilo_init(void) int error; dev_t dev; - ilo_class = class_create(THIS_MODULE, "iLO"); + ilo_class = class_create("iLO"); if (IS_ERR(ilo_class)) { error = PTR_ERR(ilo_class); goto out; diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 3a7808b796b1..299d316f1bda 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -965,19 +965,19 @@ int lis3lv02d_init_dt(struct lis3lv02d *lis3) if (!pdata) return -ENOMEM; - if (of_get_property(np, "st,click-single-x", NULL)) + if (of_property_read_bool(np, "st,click-single-x")) pdata->click_flags |= LIS3_CLICK_SINGLE_X; - if (of_get_property(np, "st,click-double-x", NULL)) + if (of_property_read_bool(np, "st,click-double-x")) pdata->click_flags |= LIS3_CLICK_DOUBLE_X; - if (of_get_property(np, "st,click-single-y", NULL)) + if (of_property_read_bool(np, "st,click-single-y")) pdata->click_flags |= LIS3_CLICK_SINGLE_Y; - if (of_get_property(np, "st,click-double-y", NULL)) + if (of_property_read_bool(np, "st,click-double-y")) pdata->click_flags |= LIS3_CLICK_DOUBLE_Y; - if (of_get_property(np, "st,click-single-z", NULL)) + if (of_property_read_bool(np, "st,click-single-z")) pdata->click_flags |= LIS3_CLICK_SINGLE_Z; - if (of_get_property(np, "st,click-double-z", NULL)) + if (of_property_read_bool(np, "st,click-double-z")) pdata->click_flags |= LIS3_CLICK_DOUBLE_Z; if (!of_property_read_u32(np, "st,click-threshold-x", &val)) @@ -994,31 +994,31 @@ int lis3lv02d_init_dt(struct lis3lv02d *lis3) if (!of_property_read_u32(np, "st,click-window", &val)) pdata->click_window = val; - if (of_get_property(np, "st,irq1-disable", NULL)) + if (of_property_read_bool(np, "st,irq1-disable")) pdata->irq_cfg |= LIS3_IRQ1_DISABLE; - if (of_get_property(np, "st,irq1-ff-wu-1", NULL)) + if (of_property_read_bool(np, "st,irq1-ff-wu-1")) pdata->irq_cfg |= LIS3_IRQ1_FF_WU_1; - if (of_get_property(np, "st,irq1-ff-wu-2", NULL)) + if (of_property_read_bool(np, "st,irq1-ff-wu-2")) pdata->irq_cfg |= LIS3_IRQ1_FF_WU_2; - if (of_get_property(np, "st,irq1-data-ready", NULL)) + if (of_property_read_bool(np, "st,irq1-data-ready")) pdata->irq_cfg |= LIS3_IRQ1_DATA_READY; - if (of_get_property(np, "st,irq1-click", NULL)) + if (of_property_read_bool(np, "st,irq1-click")) pdata->irq_cfg |= LIS3_IRQ1_CLICK; - if (of_get_property(np, "st,irq2-disable", NULL)) + if (of_property_read_bool(np, "st,irq2-disable")) pdata->irq_cfg |= LIS3_IRQ2_DISABLE; - if (of_get_property(np, "st,irq2-ff-wu-1", NULL)) + if (of_property_read_bool(np, "st,irq2-ff-wu-1")) pdata->irq_cfg |= LIS3_IRQ2_FF_WU_1; - if (of_get_property(np, "st,irq2-ff-wu-2", NULL)) + if (of_property_read_bool(np, "st,irq2-ff-wu-2")) pdata->irq_cfg |= LIS3_IRQ2_FF_WU_2; - if (of_get_property(np, "st,irq2-data-ready", NULL)) + if (of_property_read_bool(np, "st,irq2-data-ready")) pdata->irq_cfg |= LIS3_IRQ2_DATA_READY; - if (of_get_property(np, "st,irq2-click", NULL)) + if (of_property_read_bool(np, "st,irq2-click")) pdata->irq_cfg |= LIS3_IRQ2_CLICK; - if (of_get_property(np, "st,irq-open-drain", NULL)) + if (of_property_read_bool(np, "st,irq-open-drain")) pdata->irq_cfg |= LIS3_IRQ_OPEN_DRAIN; - if (of_get_property(np, "st,irq-active-low", NULL)) + if (of_property_read_bool(np, "st,irq-active-low")) pdata->irq_cfg |= LIS3_IRQ_ACTIVE_LOW; if (!of_property_read_u32(np, "st,wu-duration-1", &val)) @@ -1026,32 +1026,32 @@ int lis3lv02d_init_dt(struct lis3lv02d *lis3) if (!of_property_read_u32(np, "st,wu-duration-2", &val)) pdata->duration2 = val; - if (of_get_property(np, "st,wakeup-x-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup-x-lo")) pdata->wakeup_flags |= LIS3_WAKEUP_X_LO; - if (of_get_property(np, "st,wakeup-x-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup-x-hi")) pdata->wakeup_flags |= LIS3_WAKEUP_X_HI; - if (of_get_property(np, "st,wakeup-y-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup-y-lo")) pdata->wakeup_flags |= LIS3_WAKEUP_Y_LO; - if (of_get_property(np, "st,wakeup-y-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup-y-hi")) pdata->wakeup_flags |= LIS3_WAKEUP_Y_HI; - if (of_get_property(np, "st,wakeup-z-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup-z-lo")) pdata->wakeup_flags |= LIS3_WAKEUP_Z_LO; - if (of_get_property(np, "st,wakeup-z-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup-z-hi")) pdata->wakeup_flags |= LIS3_WAKEUP_Z_HI; if (of_get_property(np, "st,wakeup-threshold", &val)) pdata->wakeup_thresh = val; - if (of_get_property(np, "st,wakeup2-x-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup2-x-lo")) pdata->wakeup_flags2 |= LIS3_WAKEUP_X_LO; - if (of_get_property(np, "st,wakeup2-x-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup2-x-hi")) pdata->wakeup_flags2 |= LIS3_WAKEUP_X_HI; - if (of_get_property(np, "st,wakeup2-y-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup2-y-lo")) pdata->wakeup_flags2 |= LIS3_WAKEUP_Y_LO; - if (of_get_property(np, "st,wakeup2-y-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup2-y-hi")) pdata->wakeup_flags2 |= LIS3_WAKEUP_Y_HI; - if (of_get_property(np, "st,wakeup2-z-lo", NULL)) + if (of_property_read_bool(np, "st,wakeup2-z-lo")) pdata->wakeup_flags2 |= LIS3_WAKEUP_Z_LO; - if (of_get_property(np, "st,wakeup2-z-hi", NULL)) + if (of_property_read_bool(np, "st,wakeup2-z-hi")) pdata->wakeup_flags2 |= LIS3_WAKEUP_Z_HI; if (of_get_property(np, "st,wakeup2-threshold", &val)) pdata->wakeup_thresh2 = val; @@ -1073,9 +1073,9 @@ int lis3lv02d_init_dt(struct lis3lv02d *lis3) } } - if (of_get_property(np, "st,hipass1-disable", NULL)) + if (of_property_read_bool(np, "st,hipass1-disable")) pdata->hipass_ctrl |= LIS3_HIPASS1_DISABLE; - if (of_get_property(np, "st,hipass2-disable", NULL)) + if (of_property_read_bool(np, "st,hipass2-disable")) pdata->hipass_ctrl |= LIS3_HIPASS2_DISABLE; if (of_property_read_s32(np, "st,axis-x", &sval) == 0) @@ -1085,7 +1085,7 @@ int lis3lv02d_init_dt(struct lis3lv02d *lis3) if (of_property_read_s32(np, "st,axis-z", &sval) == 0) pdata->axis_z = sval; - if (of_get_property(np, "st,default-rate", NULL)) + if (of_property_read_u32(np, "st,default-rate", &val) == 0) pdata->default_rate = val; if (of_property_read_s32(np, "st,min-limit-x", &sval) == 0) diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c index 025b133297a6..f1d022160913 100644 --- a/drivers/misc/lkdtm/stackleak.c +++ b/drivers/misc/lkdtm/stackleak.c @@ -43,12 +43,14 @@ static void noinstr check_stackleak_irqoff(void) * STACK_END_MAGIC, and in either casee something is seriously wrong. */ if (current_sp < task_stack_low || current_sp >= task_stack_high) { + instrumentation_begin(); pr_err("FAIL: current_stack_pointer (0x%lx) outside of task stack bounds [0x%lx..0x%lx]\n", current_sp, task_stack_low, task_stack_high - 1); test_failed = true; goto out; } if (lowest_sp < task_stack_low || lowest_sp >= task_stack_high) { + instrumentation_begin(); pr_err("FAIL: current->lowest_stack (0x%lx) outside of task stack bounds [0x%lx..0x%lx]\n", lowest_sp, task_stack_low, task_stack_high - 1); test_failed = true; @@ -86,11 +88,14 @@ static void noinstr check_stackleak_irqoff(void) if (*(unsigned long *)poison_low == STACKLEAK_POISON) continue; + instrumentation_begin(); pr_err("FAIL: non-poison value %lu bytes below poison boundary: 0x%lx\n", poison_high - poison_low, *(unsigned long *)poison_low); test_failed = true; + goto out; } + instrumentation_begin(); pr_info("stackleak stack usage:\n" " high offset: %lu bytes\n" " current: %lu bytes\n" @@ -113,6 +118,7 @@ out: } else { pr_info("OK: the rest of the thread stack is properly erased\n"); } + instrumentation_end(); } static void lkdtm_STACKLEAK_ERASING(void) diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c index 3389803cb281..e616e3ec2b42 100644 --- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c +++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c @@ -175,9 +175,13 @@ static void pci1xxxx_gpio_irq_set_mask(struct irq_data *data, bool set) unsigned int gpio = irqd_to_hwirq(data); unsigned long flags; + if (!set) + gpiochip_enable_irq(chip, gpio); spin_lock_irqsave(&priv->lock, flags); pci1xxx_assign_bit(priv->reg_base, INTR_MASK_OFFSET(gpio), (gpio % 32), set); spin_unlock_irqrestore(&priv->lock, flags); + if (set) + gpiochip_disable_irq(chip, gpio); } static void pci1xxxx_gpio_irq_mask(struct irq_data *data) @@ -283,12 +287,14 @@ static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static struct irq_chip pci1xxxx_gpio_irqchip = { +static const struct irq_chip pci1xxxx_gpio_irqchip = { .name = "pci1xxxx_gpio", .irq_ack = pci1xxxx_gpio_irq_ack, .irq_mask = pci1xxxx_gpio_irq_mask, .irq_unmask = pci1xxxx_gpio_irq_unmask, .irq_set_type = pci1xxxx_gpio_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static int pci1xxxx_gpio_suspend(struct device *dev) @@ -351,7 +357,7 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq) return retval; girq = &priv->gpio.irq; - girq->chip = &pci1xxxx_gpio_irqchip; + gpio_irq_chip_set_chip(girq, &pci1xxxx_gpio_irqchip); girq->parent_handler = NULL; girq->num_parents = 0; girq->parents = NULL; diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 211536109308..31e3c74ca1f1 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -9,8 +9,8 @@ #include #include #include -#include +#include #include #include "mei_dev.h" diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 7728fe685476..85cbfc3413ee 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 319418ddf4fb..e910302fcd1f 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -7,7 +7,7 @@ #ifndef _MEI_HW_TYPES_H_ #define _MEI_HW_TYPES_H_ -#include +#include /* * Timeouts in Seconds diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 632d4ae21e46..51876da3fd65 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -1275,7 +1274,7 @@ static int __init mei_init(void) { int ret; - mei_class = class_create(THIS_MODULE, "mei"); + mei_class = class_create("mei"); if (IS_ERR(mei_class)) { pr_err("couldn't create class\n"); ret = PTR_ERR(mei_class); diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 7ee1fa7b1cb3..3bf560bbdee0 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c index 3b058654b45b..6e63f060e4cc 100644 --- a/drivers/misc/ocxl/file.c +++ b/drivers/misc/ocxl/file.c @@ -601,7 +601,7 @@ int ocxl_file_init(void) return rc; } - ocxl_class = class_create(THIS_MODULE, "ocxl"); + ocxl_class = class_create("ocxl"); if (IS_ERR(ocxl_class)) { pr_err("Unable to create ocxl class\n"); unregister_chrdev_region(ocxl_dev, OCXL_NUM_MINORS); diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index ce72e46a2e73..7966a6b8b5b3 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -503,7 +503,7 @@ static int __init phantom_init(void) int retval; dev_t dev; - phantom_class = class_create(THIS_MODULE, "phantom"); + phantom_class = class_create("phantom"); if (IS_ERR(phantom_class)) { retval = PTR_ERR(phantom_class); printk(KERN_ERR "phantom: can't register phantom class\n"); diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index b2c3c22fc13c..6da509d692bb 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -93,7 +93,7 @@ int xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT; static int xpc_disengage_min_timelimit; /* = 0 */ static int xpc_disengage_max_timelimit = 120; -static struct ctl_table xpc_sys_xpc_hb_dir[] = { +static struct ctl_table xpc_sys_xpc_hb[] = { { .procname = "hb_interval", .data = &xpc_hb_interval, @@ -112,11 +112,7 @@ static struct ctl_table xpc_sys_xpc_hb_dir[] = { .extra2 = &xpc_hb_check_max_interval}, {} }; -static struct ctl_table xpc_sys_xpc_dir[] = { - { - .procname = "hb", - .mode = 0555, - .child = xpc_sys_xpc_hb_dir}, +static struct ctl_table xpc_sys_xpc[] = { { .procname = "disengage_timelimit", .data = &xpc_disengage_timelimit, @@ -127,14 +123,9 @@ static struct ctl_table xpc_sys_xpc_dir[] = { .extra2 = &xpc_disengage_max_timelimit}, {} }; -static struct ctl_table xpc_sys_dir[] = { - { - .procname = "xpc", - .mode = 0555, - .child = xpc_sys_xpc_dir}, - {} -}; + static struct ctl_table_header *xpc_sysctl; +static struct ctl_table_header *xpc_sysctl_hb; /* non-zero if any remote partition disengage was timed out */ int xpc_disengage_timedout; @@ -1041,6 +1032,8 @@ xpc_do_exit(enum xp_retval reason) if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); + if (xpc_sysctl_hb) + unregister_sysctl_table(xpc_sysctl_hb); xpc_teardown_partitions(); @@ -1243,7 +1236,8 @@ xpc_init(void) goto out_1; } - xpc_sysctl = register_sysctl_table(xpc_sys_dir); + xpc_sysctl = register_sysctl("xpc", xpc_sys_xpc); + xpc_sysctl_hb = register_sysctl("xpc/hb", xpc_sys_xpc_hb); /* * Fill the partition reserved page with the information needed by @@ -1308,6 +1302,8 @@ out_3: (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); out_2: + if (xpc_sysctl_hb) + unregister_sysctl_table(xpc_sysctl_hb); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); diff --git a/drivers/misc/smpro-errmon.c b/drivers/misc/smpro-errmon.c index d1431d419aa4..a1f0b2c77fac 100644 --- a/drivers/misc/smpro-errmon.c +++ b/drivers/misc/smpro-errmon.c @@ -47,6 +47,12 @@ #define WARN_PMPRO_INFO_LO 0xAC #define WARN_PMPRO_INFO_HI 0xAD +/* Boot Stage Register */ +#define BOOTSTAGE 0xB0 +#define DIMM_SYNDROME_SEL 0xB4 +#define DIMM_SYNDROME_ERR 0xB5 +#define DIMM_SYNDROME_STAGE 4 + /* PCIE Error Registers */ #define PCIE_CE_ERR_CNT 0xC0 #define PCIE_CE_ERR_LEN 0xC1 @@ -67,6 +73,7 @@ #define VRD_WARN_FAULT_EVENT_DATA 0x78 #define VRD_HOT_EVENT_DATA 0x79 #define DIMM_HOT_EVENT_DATA 0x7A +#define DIMM_2X_REFRESH_EVENT_DATA 0x96 #define MAX_READ_BLOCK_LENGTH 48 @@ -190,6 +197,7 @@ enum EVENT_TYPES { VRD_WARN_FAULT_EVENT, VRD_HOT_EVENT, DIMM_HOT_EVENT, + DIMM_2X_REFRESH_EVENT, NUM_EVENTS_TYPE, }; @@ -198,6 +206,7 @@ static u8 smpro_event_table[NUM_EVENTS_TYPE] = { VRD_WARN_FAULT_EVENT_DATA, VRD_HOT_EVENT_DATA, DIMM_HOT_EVENT_DATA, + DIMM_2X_REFRESH_EVENT_DATA, }; static ssize_t smpro_event_data_read(struct device *dev, @@ -463,6 +472,62 @@ static DEVICE_ATTR_RO(warn_pmpro); EVENT_RO(vrd_warn_fault, VRD_WARN_FAULT_EVENT); EVENT_RO(vrd_hot, VRD_HOT_EVENT); EVENT_RO(dimm_hot, DIMM_HOT_EVENT); +EVENT_RO(dimm_2x_refresh, DIMM_2X_REFRESH_EVENT); + +static ssize_t smpro_dimm_syndrome_read(struct device *dev, struct device_attribute *da, + char *buf, unsigned int slot) +{ + struct smpro_errmon *errmon = dev_get_drvdata(dev); + unsigned int data; + int ret; + + ret = regmap_read(errmon->regmap, BOOTSTAGE, &data); + if (ret) + return ret; + + /* check for valid stage */ + data = (data >> 8) & 0xff; + if (data != DIMM_SYNDROME_STAGE) + return ret; + + /* Write the slot ID to retrieve Error Syndrome */ + ret = regmap_write(errmon->regmap, DIMM_SYNDROME_SEL, slot); + if (ret) + return ret; + + /* Read the Syndrome error */ + ret = regmap_read(errmon->regmap, DIMM_SYNDROME_ERR, &data); + if (ret || !data) + return ret; + + return sysfs_emit(buf, "%04x\n", data); +} + +#define EVENT_DIMM_SYNDROME(_slot) \ + static ssize_t event_dimm##_slot##_syndrome_show(struct device *dev, \ + struct device_attribute *da, \ + char *buf) \ + { \ + return smpro_dimm_syndrome_read(dev, da, buf, _slot); \ + } \ + static DEVICE_ATTR_RO(event_dimm##_slot##_syndrome) + +EVENT_DIMM_SYNDROME(0); +EVENT_DIMM_SYNDROME(1); +EVENT_DIMM_SYNDROME(2); +EVENT_DIMM_SYNDROME(3); +EVENT_DIMM_SYNDROME(4); +EVENT_DIMM_SYNDROME(5); +EVENT_DIMM_SYNDROME(6); +EVENT_DIMM_SYNDROME(7); +EVENT_DIMM_SYNDROME(8); +EVENT_DIMM_SYNDROME(9); +EVENT_DIMM_SYNDROME(10); +EVENT_DIMM_SYNDROME(11); +EVENT_DIMM_SYNDROME(12); +EVENT_DIMM_SYNDROME(13); +EVENT_DIMM_SYNDROME(14); +EVENT_DIMM_SYNDROME(15); static struct attribute *smpro_errmon_attrs[] = { &dev_attr_overflow_core_ce.attr, @@ -488,6 +553,23 @@ static struct attribute *smpro_errmon_attrs[] = { &dev_attr_event_vrd_warn_fault.attr, &dev_attr_event_vrd_hot.attr, &dev_attr_event_dimm_hot.attr, + &dev_attr_event_dimm_2x_refresh.attr, + &dev_attr_event_dimm0_syndrome.attr, + &dev_attr_event_dimm1_syndrome.attr, + &dev_attr_event_dimm2_syndrome.attr, + &dev_attr_event_dimm3_syndrome.attr, + &dev_attr_event_dimm4_syndrome.attr, + &dev_attr_event_dimm5_syndrome.attr, + &dev_attr_event_dimm6_syndrome.attr, + &dev_attr_event_dimm7_syndrome.attr, + &dev_attr_event_dimm8_syndrome.attr, + &dev_attr_event_dimm9_syndrome.attr, + &dev_attr_event_dimm10_syndrome.attr, + &dev_attr_event_dimm11_syndrome.attr, + &dev_attr_event_dimm12_syndrome.attr, + &dev_attr_event_dimm13_syndrome.attr, + &dev_attr_event_dimm14_syndrome.attr, + &dev_attr_event_dimm15_syndrome.attr, NULL }; diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index f0e7f02605eb..99413310956b 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -218,14 +218,9 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) block->res = child_res; list_add_tail(&block->list, &reserve_list); - if (of_find_property(child, "export", NULL)) - block->export = true; - - if (of_find_property(child, "pool", NULL)) - block->pool = true; - - if (of_find_property(child, "protect-exec", NULL)) - block->protect_exec = true; + block->export = of_property_read_bool(child, "export"); + block->pool = of_property_read_bool(child, "pool"); + block->protect_exec = of_property_read_bool(child, "protect-exec"); if ((block->export || block->pool || block->protect_exec) && block->size) { @@ -381,6 +376,7 @@ static int sram_probe(struct platform_device *pdev) struct sram_dev *sram; int ret; struct resource *res; + struct clk *clk; config = of_device_get_match_data(&pdev->dev); @@ -409,16 +405,14 @@ static int sram_probe(struct platform_device *pdev) return PTR_ERR(sram->pool); } - sram->clk = devm_clk_get(sram->dev, NULL); - if (IS_ERR(sram->clk)) - sram->clk = NULL; - else - clk_prepare_enable(sram->clk); + clk = devm_clk_get_optional_enabled(sram->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); ret = sram_reserve_regions(sram, platform_get_resource(pdev, IORESOURCE_MEM, 0)); if (ret) - goto err_disable_clk; + return ret; platform_set_drvdata(pdev, sram); @@ -436,9 +430,6 @@ static int sram_probe(struct platform_device *pdev) err_free_partitions: sram_free_partitions(sram); -err_disable_clk: - if (sram->clk) - clk_disable_unprepare(sram->clk); return ret; } @@ -452,9 +443,6 @@ static int sram_remove(struct platform_device *pdev) if (sram->pool && gen_pool_avail(sram->pool) < gen_pool_size(sram->pool)) dev_err(sram->dev, "removed while SRAM allocated\n"); - if (sram->clk) - clk_disable_unprepare(sram->clk); - return 0; } diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h index d2058d8c8f1d..397205b8bf6f 100644 --- a/drivers/misc/sram.h +++ b/drivers/misc/sram.h @@ -27,7 +27,6 @@ struct sram_dev { bool no_memory_wc; struct gen_pool *pool; - struct clk *clk; struct sram_partition *partition; u32 partitions; diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index 07023397afc7..346bd7cf2e94 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -620,7 +620,7 @@ static int __init uacce_init(void) { int ret; - uacce_class = class_create(THIS_MODULE, UACCE_NAME); + uacce_class = class_create(UACCE_NAME); if (IS_ERR(uacce_class)) return PTR_ERR(uacce_class); diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index 857b9851402a..abe79f6fd2a7 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -165,10 +165,16 @@ static int vmci_host_close(struct inode *inode, struct file *filp) static __poll_t vmci_host_poll(struct file *filp, poll_table *wait) { struct vmci_host_dev *vmci_host_dev = filp->private_data; - struct vmci_ctx *context = vmci_host_dev->context; + struct vmci_ctx *context; __poll_t mask = 0; if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) { + /* + * Read context only if ct_type == VMCIOBJ_CONTEXT to make + * sure that context is initialized + */ + context = vmci_host_dev->context; + /* Check for VMCI calls to this VM context. */ if (wait) poll_wait(filp, &context->host_context.wait_queue, diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 00c33edb9fb9..d920c4178389 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -264,6 +264,7 @@ static ssize_t power_ro_lock_store(struct device *dev, goto out_put; } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP; + req_to_mmc_queue_req(req)->drv_op_result = -EIO; blk_execute_rq(req, false); ret = req_to_mmc_queue_req(req)->drv_op_result; blk_mq_free_request(req); @@ -651,6 +652,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, idatas[0] = idata; req_to_mmc_queue_req(req)->drv_op = rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->drv_op_result = -EIO; req_to_mmc_queue_req(req)->drv_op_data = idatas; req_to_mmc_queue_req(req)->ioc_count = 1; blk_execute_rq(req, false); @@ -722,6 +724,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, } req_to_mmc_queue_req(req)->drv_op = rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->drv_op_result = -EIO; req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->ioc_count = n; blk_execute_rq(req, false); @@ -2806,6 +2809,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) if (IS_ERR(req)) return PTR_ERR(req); req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS; + req_to_mmc_queue_req(req)->drv_op_result = -EIO; blk_execute_rq(req, false); ret = req_to_mmc_queue_req(req)->drv_op_result; if (ret >= 0) { @@ -2844,6 +2848,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) goto out_free; } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD; + req_to_mmc_queue_req(req)->drv_op_result = -EIO; req_to_mmc_queue_req(req)->drv_op_data = &ext_csd; blk_execute_rq(req, false); err = req_to_mmc_queue_req(req)->drv_op_result; diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c index 2e120ad83020..0c5f5e371e1f 100644 --- a/drivers/mmc/core/pwrseq_sd8787.c +++ b/drivers/mmc/core/pwrseq_sd8787.c @@ -28,7 +28,6 @@ struct mmc_pwrseq_sd8787 { struct mmc_pwrseq pwrseq; struct gpio_desc *reset_gpio; struct gpio_desc *pwrdn_gpio; - u32 reset_pwrdwn_delay_ms; }; #define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq) @@ -39,7 +38,7 @@ static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host) gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); - msleep(pwrseq->reset_pwrdwn_delay_ms); + msleep(300); gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1); } @@ -51,17 +50,37 @@ static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host) gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); } +static void mmc_pwrseq_wilc1000_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + /* The pwrdn_gpio is really CHIP_EN, reset_gpio is RESETN */ + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1); + msleep(5); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); +} + +static void mmc_pwrseq_wilc1000_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0); +} + static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = { .pre_power_on = mmc_pwrseq_sd8787_pre_power_on, .power_off = mmc_pwrseq_sd8787_power_off, }; -static const u32 sd8787_delay_ms = 300; -static const u32 wilc1000_delay_ms = 5; +static const struct mmc_pwrseq_ops mmc_pwrseq_wilc1000_ops = { + .pre_power_on = mmc_pwrseq_wilc1000_pre_power_on, + .power_off = mmc_pwrseq_wilc1000_power_off, +}; static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = { - { .compatible = "mmc-pwrseq-sd8787", .data = &sd8787_delay_ms }, - { .compatible = "mmc-pwrseq-wilc1000", .data = &wilc1000_delay_ms }, + { .compatible = "mmc-pwrseq-sd8787", .data = &mmc_pwrseq_sd8787_ops }, + { .compatible = "mmc-pwrseq-wilc1000", .data = &mmc_pwrseq_wilc1000_ops }, {/* sentinel */}, }; MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match); @@ -77,7 +96,6 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev) return -ENOMEM; match = of_match_node(mmc_pwrseq_sd8787_of_match, pdev->dev.of_node); - pwrseq->reset_pwrdwn_delay_ms = *(u32 *)match->data; pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW); if (IS_ERR(pwrseq->pwrdn_gpio)) @@ -88,7 +106,7 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev) return PTR_ERR(pwrseq->reset_gpio); pwrseq->pwrseq.dev = dev; - pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops; + pwrseq->pwrseq.ops = match->data; pwrseq->pwrseq.owner = THIS_MODULE; platform_set_drvdata(pdev, pwrseq); diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index 50536fe59f1a..aa659758563f 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -478,13 +478,13 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { - tty->hw_stopped = 0; + tty->hw_stopped = false; sdio_uart_start_tx(port); tty_wakeup(tty); } } else { if (!cts) { - tty->hw_stopped = 1; + tty->hw_stopped = true; sdio_uart_stop_tx(port); } } @@ -633,7 +633,7 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) if (C_CRTSCTS(tty)) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) - tty->hw_stopped = 1; + tty->hw_stopped = true; clear_bit(TTY_IO_ERROR, &tty->flags); @@ -882,14 +882,14 @@ static void sdio_uart_set_termios(struct tty_struct *tty, /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - tty->hw_stopped = 0; + tty->hw_stopped = false; sdio_uart_start_tx(port); } /* Handle turning on CRTSCTS */ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) { - tty->hw_stopped = 1; + tty->hw_stopped = true; sdio_uart_stop_tx(port); } } diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index b24aa27da50c..d2f625054689 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -540,9 +540,11 @@ static int sdhci_cdns_probe(struct platform_device *pdev) if (host->mmc->caps & MMC_CAP_HW_RESET) { priv->rst_hw = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(priv->rst_hw)) - return dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), - "reset controller error\n"); + if (IS_ERR(priv->rst_hw)) { + ret = dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), + "reset controller error\n"); + goto free; + } if (priv->rst_hw) host->mmc_host_ops.card_hw_reset = sdhci_cdns_mmc_hw_reset; } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index d7c0c0b9e26c..eebf94604a7f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1634,6 +1634,10 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (ret) return ret; + /* HS400/HS400ES require 8 bit bus */ + if (!(host->mmc->caps & MMC_CAP_8_BIT_DATA)) + host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); + if (mmc_gpio_get_cd(host->mmc) >= 0) host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; @@ -1724,10 +1728,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->mmc_host_ops.init_card = usdhc_init_card; } - err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); - if (err) - goto disable_ahb_clk; - if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) sdhci_esdhc_ops.platform_execute_tuning = esdhc_executing_tuning; @@ -1735,15 +1735,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; - if (host->mmc->caps & MMC_CAP_8_BIT_DATA && - imx_data->socdata->flags & ESDHC_FLAG_HS400) + if (imx_data->socdata->flags & ESDHC_FLAG_HS400) host->mmc->caps2 |= MMC_CAP2_HS400; if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; - if (host->mmc->caps & MMC_CAP_8_BIT_DATA && - imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { + if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { host->mmc->caps2 |= MMC_CAP2_HS400_ES; host->mmc_host_ops.hs400_enhanced_strobe = esdhc_hs400_enhanced_strobe; @@ -1765,6 +1763,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) goto disable_ahb_clk; } + err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); + if (err) + goto disable_ahb_clk; + sdhci_esdhc_imx_hwinit(host); err = sdhci_add_host(host); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index e4c4bfac3763..9ec593d52f0f 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -1713,6 +1713,9 @@ static void construct_request_response(struct vub300_mmc_host *vub300, int bytes = 3 & less_cmd; int words = less_cmd >> 2; u8 *r = vub300->resp.response.command_response; + + if (!resp_len) + return; if (bytes == 3) { cmd->resp[words] = (r[1 + (words << 2)] << 24) | (r[2 + (words << 2)] << 16) diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c index 4ee536980f71..3ed8f461e01e 100644 --- a/drivers/most/most_cdev.c +++ b/drivers/most/most_cdev.c @@ -491,7 +491,7 @@ static int __init most_cdev_init(void) { int err; - comp.class = class_create(THIS_MODULE, "most_cdev"); + comp.class = class_create("most_cdev"); if (IS_ERR(comp.class)) return PTR_ERR(comp.class); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 01f1c6792df9..8dc4f5c493fc 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -590,8 +590,8 @@ static void adjust_oob_length(struct mtd_info *mtd, uint64_t start, (end_page - start_page + 1) * oob_per_page); } -static int mtdchar_write_ioctl(struct mtd_info *mtd, - struct mtd_write_req __user *argp) +static noinline_for_stack int +mtdchar_write_ioctl(struct mtd_info *mtd, struct mtd_write_req __user *argp) { struct mtd_info *master = mtd_get_master(mtd); struct mtd_write_req req; @@ -688,8 +688,8 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd, return ret; } -static int mtdchar_read_ioctl(struct mtd_info *mtd, - struct mtd_read_req __user *argp) +static noinline_for_stack int +mtdchar_read_ioctl(struct mtd_info *mtd, struct mtd_read_req __user *argp) { struct mtd_info *master = mtd_get_master(mtd); struct mtd_read_req req; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index a1a08c2b6f77..60670b2f70b9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -63,7 +63,6 @@ static SIMPLE_DEV_PM_OPS(mtd_cls_pm_ops, mtd_cls_suspend, mtd_cls_resume); static struct class mtd_class = { .name = "mtd", - .owner = THIS_MODULE, .pm = MTD_CLS_PM_OPS, }; diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h index 2cda439b5e11..017868f59f22 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.h @@ -36,25 +36,25 @@ int ingenic_ecc_correct(struct ingenic_ecc *ecc, void ingenic_ecc_release(struct ingenic_ecc *ecc); struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np); #else /* CONFIG_MTD_NAND_INGENIC_ECC */ -int ingenic_ecc_calculate(struct ingenic_ecc *ecc, +static inline int ingenic_ecc_calculate(struct ingenic_ecc *ecc, struct ingenic_ecc_params *params, const u8 *buf, u8 *ecc_code) { return -ENODEV; } -int ingenic_ecc_correct(struct ingenic_ecc *ecc, +static inline int ingenic_ecc_correct(struct ingenic_ecc *ecc, struct ingenic_ecc_params *params, u8 *buf, u8 *ecc_code) { return -ENODEV; } -void ingenic_ecc_release(struct ingenic_ecc *ecc) +static inline void ingenic_ecc_release(struct ingenic_ecc *ecc) { } -struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np) +static inline struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np) { return ERR_PTR(-ENODEV); } diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index afb424579f0b..30c15e4e1cc0 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -2457,6 +2457,12 @@ static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr, NDTR1_WAIT_MODE; } + /* + * Reset nfc->selected_chip so the next command will cause the timing + * registers to be updated in marvell_nfc_select_target(). + */ + nfc->selected_chip = NULL; + return 0; } @@ -2894,10 +2900,6 @@ static int marvell_nfc_init(struct marvell_nfc *nfc) regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL, GENCONF_CLK_GATING_CTRL_ND_GATE, GENCONF_CLK_GATING_CTRL_ND_GATE); - - regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL, - GENCONF_ND_CLK_CTRL_EN, - GENCONF_ND_CLK_CTRL_EN); } /* Configure the DMA if appropriate */ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0bb0ad14a2fc..5f29fac8669a 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2018,6 +2018,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { static const struct flash_info spi_nor_generic_flash = { .name = "spi-nor-generic", + .n_banks = 1, /* * JESD216 rev A doesn't specify the page size, therefore we need a * sane default. @@ -2921,7 +2922,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor) if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) spi_nor_init_default_locking_ops(nor); - nor->params->bank_size = div64_u64(nor->params->size, nor->info->n_banks); + if (nor->info->n_banks > 1) + params->bank_size = div64_u64(params->size, nor->info->n_banks); } /** @@ -2987,6 +2989,7 @@ static void spi_nor_init_default_params(struct spi_nor *nor) /* Set SPI NOR sizes. */ params->writesize = 1; params->size = (u64)info->sector_size * info->n_sectors; + params->bank_size = params->size; params->page_size = info->page_size; if (!(info->flags & SPI_NOR_NO_FR)) { diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 15f9a80c10b9..36876aa849ed 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -361,7 +361,7 @@ static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor, */ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) { - struct spi_mem_op op; + struct spi_mem_op op = {}; u8 addr_mode; int ret; @@ -492,7 +492,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt) { - struct spi_mem_op op; + struct spi_mem_op op = {}; int ret; ret = cypress_nor_set_addr_mode_nbytes(nor); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index ad025b2ee417..8b91a55ec0d2 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -95,7 +95,7 @@ static DEFINE_SPINLOCK(ubi_devices_lock); /* "Show" method for files in '//class/ubi/' */ /* UBI version attribute ('//class/ubi/version') */ -static ssize_t version_show(struct class *class, struct class_attribute *attr, +static ssize_t version_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sprintf(buf, "%d\n", UBI_VERSION); @@ -111,7 +111,6 @@ ATTRIBUTE_GROUPS(ubi_class); /* Root UBI "class" object (corresponds to '//class/ubi/') */ struct class ubi_class = { .name = UBI_NAME_STR, - .owner = THIS_MODULE, .class_groups = ubi_class_groups, }; @@ -1267,7 +1266,7 @@ static int __init ubi_init(void) mutex_lock(&ubi_devices_mutex); err = ubi_attach_mtd_dev(mtd, p->ubi_num, p->vid_hdr_offs, p->max_beb_per1024, - p->enable_fm == 0 ? true : false); + p->enable_fm == 0); mutex_unlock(&ubi_devices_mutex); if (err < 0) { pr_err("UBI error: cannot attach mtd%d\n", diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 403b79d6efd5..655ff41863e2 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -946,7 +946,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum, int offset, int len) { struct ubi_device *ubi = vol->ubi; - int pnum, opnum, err, vol_id = vol->vol_id; + int pnum, opnum, err, err2, vol_id = vol->vol_id; pnum = ubi_wl_get_peb(ubi); if (pnum < 0) { @@ -981,10 +981,19 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum, out_put: up_read(&ubi->fm_eba_sem); - if (err && pnum >= 0) - err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); - else if (!err && opnum >= 0) - err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); + if (err && pnum >= 0) { + err2 = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); + if (err2) { + ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", + pnum, err2); + } + } else if (!err && opnum >= 0) { + err2 = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0); + if (err2) { + ubi_warn(ubi, "failed to return physical eraseblock %d, error %d", + opnum, err2); + } + } return err; } diff --git a/drivers/mux/core.c b/drivers/mux/core.c index 49bedbe6316c..990e7bc17c85 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -45,7 +45,6 @@ struct mux_state { static struct class mux_class = { .name = "mux", - .owner = THIS_MODULE, }; static DEFINE_IDA(mux_ida); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 710548dbd0c1..edbaa1444f8e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1789,6 +1789,26 @@ static void bond_ether_setup(struct net_device *bond_dev) bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING; } +void bond_xdp_set_features(struct net_device *bond_dev) +{ + struct bonding *bond = netdev_priv(bond_dev); + xdp_features_t val = NETDEV_XDP_ACT_MASK; + struct list_head *iter; + struct slave *slave; + + ASSERT_RTNL(); + + if (!bond_xdp_check(bond)) { + xdp_clear_features_flag(bond_dev); + return; + } + + bond_for_each_slave(bond, slave, iter) + val &= slave->dev->xdp_features; + + xdp_set_features_flag(bond_dev, val); +} + /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, struct netlink_ext_ack *extack) @@ -2236,6 +2256,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, bpf_prog_inc(bond->xdp_prog); } + bond_xdp_set_features(bond_dev); + slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n", bond_is_active_slave(new_slave) ? "an active" : "a backup", new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); @@ -2483,6 +2505,7 @@ static int __bond_release_one(struct net_device *bond_dev, if (!netif_is_bond_master(slave_dev)) slave_dev->priv_flags &= ~IFF_BONDING; + bond_xdp_set_features(bond_dev); kobject_put(&slave->kobj); return 0; @@ -3924,12 +3947,19 @@ static int bond_slave_netdev_event(unsigned long event, unblock_netpoll_tx(); break; case NETDEV_FEAT_CHANGE: - bond_compute_features(bond); + if (!bond->notifier_ctx) { + bond->notifier_ctx = true; + bond_compute_features(bond); + bond->notifier_ctx = false; + } break; case NETDEV_RESEND_IGMP: /* Propagate to master device */ call_netdevice_notifiers(event, slave->bond->dev); break; + case NETDEV_XDP_FEAT_CHANGE: + bond_xdp_set_features(bond_dev); + break; default: break; } @@ -5874,6 +5904,9 @@ void bond_setup(struct net_device *bond_dev) if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) bond_dev->features |= BOND_XFRM_FEATURES; #endif /* CONFIG_XFRM_OFFLOAD */ + + if (bond_xdp_check(bond)) + bond_dev->xdp_features = NETDEV_XDP_ACT_MASK; } /* Destroy a bonding device. @@ -6313,6 +6346,8 @@ static int bond_init(struct net_device *bond_dev) if (!bond->wq) return -ENOMEM; + bond->notifier_ctx = false; + spin_lock_init(&bond->stats_lock); netdev_lockdep_set_classes(bond_dev); diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index c2d080fc4fc4..27cbe148f0db 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -84,6 +84,11 @@ nla_put_failure: return -EMSGSIZE; } +/* Limit the max delay range to 300s */ +static struct netlink_range_validation delay_range = { + .max = 300000, +}; + static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_MODE] = { .type = NLA_U8 }, [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, @@ -114,7 +119,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, .len = ETH_ALEN }, [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 }, - [IFLA_BOND_PEER_NOTIF_DELAY] = { .type = NLA_U32 }, + [IFLA_BOND_PEER_NOTIF_DELAY] = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range), [IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 }, [IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED }, }; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index f71d5517f829..f3f27f0bd2a6 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -169,6 +169,12 @@ static const struct bond_opt_value bond_num_peer_notif_tbl[] = { { NULL, -1, 0} }; +static const struct bond_opt_value bond_peer_notif_delay_tbl[] = { + { "off", 0, 0}, + { "maxval", 300000, BOND_VALFLAG_MAX}, + { NULL, -1, 0} +}; + static const struct bond_opt_value bond_primary_reselect_tbl[] = { { "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT}, { "better", BOND_PRI_RESELECT_BETTER, 0}, @@ -488,7 +494,7 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .id = BOND_OPT_PEER_NOTIF_DELAY, .name = "peer_notif_delay", .desc = "Delay between each peer notification on failover event, in milliseconds", - .values = bond_intmax_tbl, + .values = bond_peer_notif_delay_tbl, .set = bond_option_peer_notif_delay_set } }; @@ -877,6 +883,8 @@ static int bond_option_mode_set(struct bonding *bond, netdev_update_features(bond->dev); } + bond_xdp_set_features(bond->dev); + return 0; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8996bd0a194a..0bb59da24922 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -31,12 +31,12 @@ /* "show" function for the bond_masters attribute. * The class parameter is ignored. */ -static ssize_t bonding_show_bonds(struct class *cls, - struct class_attribute *attr, +static ssize_t bonding_show_bonds(const struct class *cls, + const struct class_attribute *attr, char *buf) { - struct bond_net *bn = - container_of(attr, struct bond_net, class_attr_bonding_masters); + const struct bond_net *bn = + container_of_const(attr, struct bond_net, class_attr_bonding_masters); int res = 0; struct bonding *bond; @@ -59,7 +59,7 @@ static ssize_t bonding_show_bonds(struct class *cls, return res; } -static struct net_device *bond_get_by_name(struct bond_net *bn, const char *ifname) +static struct net_device *bond_get_by_name(const struct bond_net *bn, const char *ifname) { struct bonding *bond; @@ -75,12 +75,12 @@ static struct net_device *bond_get_by_name(struct bond_net *bn, const char *ifna * * The class parameter is ignored. */ -static ssize_t bonding_store_bonds(struct class *cls, - struct class_attribute *attr, +static ssize_t bonding_store_bonds(const struct class *cls, + const struct class_attribute *attr, const char *buffer, size_t count) { - struct bond_net *bn = - container_of(attr, struct bond_net, class_attr_bonding_masters); + const struct bond_net *bn = + container_of_const(attr, struct bond_net, class_attr_bonding_masters); char command[IFNAMSIZ + 1] = {0, }; char *ifname; int rv, res = count; diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 3ceccafd701b..b190007c01be 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -95,7 +95,7 @@ config CAN_AT91 config CAN_BXCAN tristate "STM32 Basic Extended CAN (bxCAN) devices" - depends on OF || ARCH_STM32 || COMPILE_TEST + depends on ARCH_STM32 || COMPILE_TEST depends on HAS_IOMEM select CAN_RX_OFFLOAD help diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c index e26ccd41e3cb..027a8a162fe4 100644 --- a/drivers/net/can/bxcan.c +++ b/drivers/net/can/bxcan.c @@ -118,7 +118,7 @@ #define BXCAN_FiR1_REG(b) (0x40 + (b) * 8) #define BXCAN_FiR2_REG(b) (0x44 + (b) * 8) -#define BXCAN_FILTER_ID(primary) (primary ? 0 : 14) +#define BXCAN_FILTER_ID(cfg) ((cfg) == BXCAN_CFG_DUAL_SECONDARY ? 14 : 0) /* Filter primary register (FMR) bits */ #define BXCAN_FMR_CANSB_MASK GENMASK(13, 8) @@ -135,6 +135,12 @@ enum bxcan_lec_code { BXCAN_LEC_UNUSED }; +enum bxcan_cfg { + BXCAN_CFG_SINGLE = 0, + BXCAN_CFG_DUAL_PRIMARY, + BXCAN_CFG_DUAL_SECONDARY +}; + /* Structure of the message buffer */ struct bxcan_mb { u32 id; /* can identifier */ @@ -167,7 +173,7 @@ struct bxcan_priv { struct regmap *gcan; int tx_irq; int sce_irq; - bool primary; + enum bxcan_cfg cfg; struct clk *clk; spinlock_t rmw_lock; /* lock for read-modify-write operations */ unsigned int tx_head; @@ -202,17 +208,17 @@ static inline void bxcan_rmw(struct bxcan_priv *priv, void __iomem *addr, spin_unlock_irqrestore(&priv->rmw_lock, flags); } -static void bxcan_disable_filters(struct bxcan_priv *priv, bool primary) +static void bxcan_disable_filters(struct bxcan_priv *priv, enum bxcan_cfg cfg) { - unsigned int fid = BXCAN_FILTER_ID(primary); + unsigned int fid = BXCAN_FILTER_ID(cfg); u32 fmask = BIT(fid); regmap_update_bits(priv->gcan, BXCAN_FA1R_REG, fmask, 0); } -static void bxcan_enable_filters(struct bxcan_priv *priv, bool primary) +static void bxcan_enable_filters(struct bxcan_priv *priv, enum bxcan_cfg cfg) { - unsigned int fid = BXCAN_FILTER_ID(primary); + unsigned int fid = BXCAN_FILTER_ID(cfg); u32 fmask = BIT(fid); /* Filter settings: @@ -680,7 +686,7 @@ static int bxcan_chip_start(struct net_device *ndev) BXCAN_BTR_BRP_MASK | BXCAN_BTR_TS1_MASK | BXCAN_BTR_TS2_MASK | BXCAN_BTR_SJW_MASK, set); - bxcan_enable_filters(priv, priv->primary); + bxcan_enable_filters(priv, priv->cfg); /* Clear all internal status */ priv->tx_head = 0; @@ -806,7 +812,7 @@ static void bxcan_chip_stop(struct net_device *ndev) BXCAN_IER_EPVIE | BXCAN_IER_EWGIE | BXCAN_IER_FOVIE1 | BXCAN_IER_FFIE1 | BXCAN_IER_FMPIE1 | BXCAN_IER_FOVIE0 | BXCAN_IER_FFIE0 | BXCAN_IER_FMPIE0 | BXCAN_IER_TMEIE, 0); - bxcan_disable_filters(priv, priv->primary); + bxcan_disable_filters(priv, priv->cfg); bxcan_enter_sleep_mode(priv); priv->can.state = CAN_STATE_STOPPED; } @@ -931,7 +937,7 @@ static int bxcan_probe(struct platform_device *pdev) struct clk *clk = NULL; void __iomem *regs; struct regmap *gcan; - bool primary; + enum bxcan_cfg cfg; int err, rx_irq, tx_irq, sce_irq; regs = devm_platform_ioremap_resource(pdev, 0); @@ -946,7 +952,13 @@ static int bxcan_probe(struct platform_device *pdev) return PTR_ERR(gcan); } - primary = of_property_read_bool(np, "st,can-primary"); + if (of_property_read_bool(np, "st,can-primary")) + cfg = BXCAN_CFG_DUAL_PRIMARY; + else if (of_property_read_bool(np, "st,can-secondary")) + cfg = BXCAN_CFG_DUAL_SECONDARY; + else + cfg = BXCAN_CFG_SINGLE; + clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { dev_err(dev, "failed to get clock\n"); @@ -992,7 +1004,7 @@ static int bxcan_probe(struct platform_device *pdev) priv->clk = clk; priv->tx_irq = tx_irq; priv->sce_irq = sce_irq; - priv->primary = primary; + priv->cfg = cfg; priv->can.clock.freq = clk_get_rate(clk); spin_lock_init(&priv->rmw_lock); priv->tx_head = 0; diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 241ec636e91f..f6d05b3ef59a 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -54,7 +54,8 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, /* check flag whether this packet has to be looped back */ if (!(dev->flags & IFF_ECHO) || (skb->protocol != htons(ETH_P_CAN) && - skb->protocol != htons(ETH_P_CANFD))) { + skb->protocol != htons(ETH_P_CANFD) && + skb->protocol != htons(ETH_P_CANXL))) { kfree_skb(skb); return 0; } diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 53e8a914c88b..be189edb256c 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -71,10 +71,12 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_SYSID_BUILD_REG (KVASER_PCIEFD_SYSID_BASE + 0x14) /* Shared receive buffer registers */ #define KVASER_PCIEFD_SRB_BASE 0x1f200 +#define KVASER_PCIEFD_SRB_FIFO_LAST_REG (KVASER_PCIEFD_SRB_BASE + 0x1f4) #define KVASER_PCIEFD_SRB_CMD_REG (KVASER_PCIEFD_SRB_BASE + 0x200) #define KVASER_PCIEFD_SRB_IEN_REG (KVASER_PCIEFD_SRB_BASE + 0x204) #define KVASER_PCIEFD_SRB_IRQ_REG (KVASER_PCIEFD_SRB_BASE + 0x20c) #define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210) +#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214) #define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218) /* EPCS flash controller registers */ #define KVASER_PCIEFD_SPI_BASE 0x1fc00 @@ -111,6 +113,9 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* DMA support */ #define KVASER_PCIEFD_SRB_STAT_DMA BIT(24) +/* SRB current packet level */ +#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK 0xff + /* DMA Enable */ #define KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE BIT(0) @@ -526,7 +531,7 @@ static int kvaser_pciefd_set_tx_irq(struct kvaser_pciefd_can *can) KVASER_PCIEFD_KCAN_IRQ_TOF | KVASER_PCIEFD_KCAN_IRQ_ABD | KVASER_PCIEFD_KCAN_IRQ_TAE | KVASER_PCIEFD_KCAN_IRQ_TAL | KVASER_PCIEFD_KCAN_IRQ_FDIC | KVASER_PCIEFD_KCAN_IRQ_BPP | - KVASER_PCIEFD_KCAN_IRQ_TAR | KVASER_PCIEFD_KCAN_IRQ_TFD; + KVASER_PCIEFD_KCAN_IRQ_TAR; iowrite32(msk, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); @@ -554,6 +559,8 @@ static void kvaser_pciefd_setup_controller(struct kvaser_pciefd_can *can) if (can->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) mode |= KVASER_PCIEFD_KCAN_MODE_LOM; + else + mode &= ~KVASER_PCIEFD_KCAN_MODE_LOM; mode |= KVASER_PCIEFD_KCAN_MODE_EEN; mode |= KVASER_PCIEFD_KCAN_MODE_EPEN; @@ -572,7 +579,7 @@ static void kvaser_pciefd_start_controller_flush(struct kvaser_pciefd_can *can) spin_lock_irqsave(&can->lock, irq); iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD | KVASER_PCIEFD_KCAN_IRQ_TFD, + iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG); @@ -615,7 +622,7 @@ static int kvaser_pciefd_bus_on(struct kvaser_pciefd_can *can) iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD | KVASER_PCIEFD_KCAN_IRQ_TFD, + iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); @@ -719,6 +726,7 @@ static int kvaser_pciefd_stop(struct net_device *netdev) iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); del_timer(&can->bec_poll_timer); } + can->can.state = CAN_STATE_STOPPED; close_candev(netdev); return ret; @@ -1007,8 +1015,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) SET_NETDEV_DEV(netdev, &pcie->pci->dev); iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD | - KVASER_PCIEFD_KCAN_IRQ_TFD, + iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); pcie->can[i] = can; @@ -1058,6 +1065,7 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) { int i; u32 srb_status; + u32 srb_packet_count; dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT]; /* Disable the DMA */ @@ -1085,6 +1093,15 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) KVASER_PCIEFD_SRB_CMD_RDB1, pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); + /* Empty Rx FIFO */ + srb_packet_count = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG) & + KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK; + while (srb_packet_count) { + /* Drop current packet in FIFO */ + ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG); + srb_packet_count--; + } + srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG); if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) { dev_err(&pcie->pci->dev, "DMA not idle before enabling\n"); @@ -1425,9 +1442,6 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, cmd = KVASER_PCIEFD_KCAN_CMD_AT; cmd |= ++can->cmd_seq << KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT; iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); - - iowrite32(KVASER_PCIEFD_KCAN_IRQ_TFD, - can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); } else if (p->header[0] & KVASER_PCIEFD_SPACK_IDET && p->header[0] & KVASER_PCIEFD_SPACK_IRM && cmdseq == (p->header[1] & KVASER_PCIEFD_PACKET_SEQ_MSK) && @@ -1714,15 +1728,6 @@ static int kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) if (irq & KVASER_PCIEFD_KCAN_IRQ_TOF) netdev_err(can->can.dev, "Tx FIFO overflow\n"); - if (irq & KVASER_PCIEFD_KCAN_IRQ_TFD) { - u8 count = ioread32(can->reg_base + - KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff; - - if (count == 0) - iowrite32(KVASER_PCIEFD_KCAN_CTRL_EFLUSH, - can->reg_base + KVASER_PCIEFD_KCAN_CTRL_REG); - } - if (irq & KVASER_PCIEFD_KCAN_IRQ_BPP) netdev_err(can->can.dev, "Fail to change bittiming, when not in reset mode\n"); @@ -1824,6 +1829,11 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, if (err) goto err_teardown_can_ctrls; + err = request_irq(pcie->pci->irq, kvaser_pciefd_irq_handler, + IRQF_SHARED, KVASER_PCIEFD_DRV_NAME, pcie); + if (err) + goto err_teardown_can_ctrls; + iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1, pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG); @@ -1844,11 +1854,6 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); - err = request_irq(pcie->pci->irq, kvaser_pciefd_irq_handler, - IRQF_SHARED, KVASER_PCIEFD_DRV_NAME, pcie); - if (err) - goto err_teardown_can_ctrls; - err = kvaser_pciefd_reg_candev(pcie); if (err) goto err_free_irq; @@ -1856,6 +1861,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, return 0; err_free_irq: + /* Disable PCI interrupts */ + iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG); free_irq(pcie->pci->irq, pcie); err_teardown_can_ctrls: diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index c680873819b0..9bc54e1348cb 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -426,9 +426,9 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) else ssc_delta = 0x87; if (priv->id == ID_MT7621) { - /* PLL frequency: 150MHz: 1.2GBit */ + /* PLL frequency: 125MHz: 1.0GBit */ if (xtal == HWTRAP_XTAL_40MHZ) - ncpo1 = 0x0780; + ncpo1 = 0x0640; if (xtal == HWTRAP_XTAL_25MHZ) ncpo1 = 0x0a00; } else { /* PLL frequency: 250MHz: 2.0Gbit */ @@ -1002,9 +1002,9 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port) mt7530_write(priv, MT7530_PVC_P(port), PORT_SPEC_TAG); - /* Disable flooding by default */ - mt7530_rmw(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | UNU_FFP_MASK, - BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port))); + /* Enable flooding on the CPU port */ + mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | + UNU_FFP(BIT(port))); /* Set CPU port number */ if (priv->id == ID_MT7621) @@ -2367,6 +2367,10 @@ mt7531_setup_common(struct dsa_switch *ds) /* Enable and reset MIB counters */ mt7530_mib_reset(ds); + /* Disable flooding on all ports */ + mt7530_clear(priv, MT7530_MFC, BC_FFP_MASK | UNM_FFP_MASK | + UNU_FFP_MASK); + for (i = 0; i < MT7530_NUM_PORTS; i++) { /* Disable forwarding by default on all ports */ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index dc263cea205f..08a46ffd53af 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5194,6 +5194,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .set_cpu_port = mv88e6095_g1_set_cpu_port, .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -7169,7 +7170,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) goto out; } if (chip->reset) - usleep_range(1000, 2000); + usleep_range(10000, 20000); /* Detect if the device is configured in single chip addressing mode, * otherwise continue with address specific smi init/detection. diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index aec9d4fd20e3..d19b6303b91f 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -276,7 +276,7 @@ /* Offset 0x10: Extended Port Control Command */ #define MV88E6393X_PORT_EPC_CMD 0x10 #define MV88E6393X_PORT_EPC_CMD_BUSY 0x8000 -#define MV88E6393X_PORT_EPC_CMD_WRITE 0x0300 +#define MV88E6393X_PORT_EPC_CMD_WRITE 0x3000 #define MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE 0x02 /* Offset 0x11: Extended Port Control Data */ diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c index 919027cf2012..c37d2e537230 100644 --- a/drivers/net/dsa/rzn1_a5psw.c +++ b/drivers/net/dsa/rzn1_a5psw.c @@ -120,6 +120,22 @@ static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable) a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable); } +static void a5psw_port_tx_enable(struct a5psw *a5psw, int port, bool enable) +{ + u32 mask = A5PSW_PORT_ENA_TX(port); + u32 reg = enable ? mask : 0; + + /* Even though the port TX is disabled through TXENA bit in the + * PORT_ENA register, it can still send BPDUs. This depends on the tag + * configuration added when sending packets from the CPU port to the + * switch port. Indeed, when using forced forwarding without filtering, + * even disabled ports will be able to send packets that are tagged. + * This allows to implement STP support when ports are in a state where + * forwarding traffic should be stopped but BPDUs should still be sent. + */ + a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, mask, reg); +} + static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable) { u32 port_ena = 0; @@ -292,6 +308,22 @@ static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) return 0; } +static void a5psw_port_learning_set(struct a5psw *a5psw, int port, bool learn) +{ + u32 mask = A5PSW_INPUT_LEARN_DIS(port); + u32 reg = !learn ? mask : 0; + + a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg); +} + +static void a5psw_port_rx_block_set(struct a5psw *a5psw, int port, bool block) +{ + u32 mask = A5PSW_INPUT_LEARN_BLOCK(port); + u32 reg = block ? mask : 0; + + a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg); +} + static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port, bool set) { @@ -308,6 +340,14 @@ static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port, a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports); } +static void a5psw_port_set_standalone(struct a5psw *a5psw, int port, + bool standalone) +{ + a5psw_port_learning_set(a5psw, port, !standalone); + a5psw_flooding_set_resolution(a5psw, port, !standalone); + a5psw_port_mgmtfwd_set(a5psw, port, standalone); +} + static int a5psw_port_bridge_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, bool *tx_fwd_offload, @@ -323,8 +363,7 @@ static int a5psw_port_bridge_join(struct dsa_switch *ds, int port, } a5psw->br_dev = bridge.dev; - a5psw_flooding_set_resolution(a5psw, port, true); - a5psw_port_mgmtfwd_set(a5psw, port, false); + a5psw_port_set_standalone(a5psw, port, false); return 0; } @@ -334,8 +373,7 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port, { struct a5psw *a5psw = ds->priv; - a5psw_flooding_set_resolution(a5psw, port, false); - a5psw_port_mgmtfwd_set(a5psw, port, true); + a5psw_port_set_standalone(a5psw, port, true); /* No more ports bridged */ if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT)) @@ -344,28 +382,35 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port, static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { - u32 mask = A5PSW_INPUT_LEARN_DIS(port) | A5PSW_INPUT_LEARN_BLOCK(port); + bool learning_enabled, rx_enabled, tx_enabled; struct a5psw *a5psw = ds->priv; - u32 reg = 0; switch (state) { case BR_STATE_DISABLED: case BR_STATE_BLOCKING: - reg |= A5PSW_INPUT_LEARN_DIS(port); - reg |= A5PSW_INPUT_LEARN_BLOCK(port); - break; case BR_STATE_LISTENING: - reg |= A5PSW_INPUT_LEARN_DIS(port); + rx_enabled = false; + tx_enabled = false; + learning_enabled = false; break; case BR_STATE_LEARNING: - reg |= A5PSW_INPUT_LEARN_BLOCK(port); + rx_enabled = false; + tx_enabled = false; + learning_enabled = true; break; case BR_STATE_FORWARDING: - default: + rx_enabled = true; + tx_enabled = true; + learning_enabled = true; break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; } - a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg); + a5psw_port_learning_set(a5psw, port, learning_enabled); + a5psw_port_rx_block_set(a5psw, port, !rx_enabled); + a5psw_port_tx_enable(a5psw, port, tx_enabled); } static void a5psw_port_fast_age(struct dsa_switch *ds, int port) @@ -673,7 +718,7 @@ static int a5psw_setup(struct dsa_switch *ds) } /* Configure management port */ - reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_DISCARD; + reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_ENABLE; a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg); /* Set pattern 0 to forward all frame to mgmt port */ @@ -722,13 +767,15 @@ static int a5psw_setup(struct dsa_switch *ds) if (dsa_port_is_unused(dp)) continue; - /* Enable egress flooding for CPU port */ - if (dsa_port_is_cpu(dp)) + /* Enable egress flooding and learning for CPU port */ + if (dsa_port_is_cpu(dp)) { a5psw_flooding_set_resolution(a5psw, port, true); + a5psw_port_learning_set(a5psw, port, true); + } - /* Enable management forward only for user ports */ + /* Enable standalone mode for user ports */ if (dsa_port_is_user(dp)) - a5psw_port_mgmtfwd_set(a5psw, port, true); + a5psw_port_set_standalone(a5psw, port, true); } return 0; diff --git a/drivers/net/dsa/rzn1_a5psw.h b/drivers/net/dsa/rzn1_a5psw.h index c67abd49c013..b869192eef3f 100644 --- a/drivers/net/dsa/rzn1_a5psw.h +++ b/drivers/net/dsa/rzn1_a5psw.h @@ -19,6 +19,7 @@ #define A5PSW_PORT_OFFSET(port) (0x400 * (port)) #define A5PSW_PORT_ENA 0x8 +#define A5PSW_PORT_ENA_TX(port) BIT(port) #define A5PSW_PORT_ENA_RX_SHIFT 16 #define A5PSW_PORT_ENA_TX_RX(port) (BIT((port) + A5PSW_PORT_ENA_RX_SHIFT) | \ BIT(port)) @@ -36,7 +37,7 @@ #define A5PSW_INPUT_LEARN_BLOCK(p) BIT(p) #define A5PSW_MGMT_CFG 0x20 -#define A5PSW_MGMT_CFG_DISCARD BIT(7) +#define A5PSW_MGMT_CFG_ENABLE BIT(6) #define A5PSW_MODE_CFG 0x24 #define A5PSW_MODE_STATS_RESET BIT(31) diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index d2f4358cc550..ba3e7aa1a28f 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -66,8 +66,10 @@ static int max_interrupt_work = 20; #include #include #include - #include + +#include + #include #include diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index 82f94b1635bf..5267e9dcd87e 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -195,6 +195,7 @@ static int tc589_probe(struct pcmcia_device *link) { struct el3_private *lp; struct net_device *dev; + int ret; dev_dbg(&link->dev, "3c589_attach()\n"); @@ -218,7 +219,15 @@ static int tc589_probe(struct pcmcia_device *link) dev->ethtool_ops = &netdev_ethtool_ops; - return tc589_config(link); + ret = tc589_config(link); + if (ret) + goto err_free_netdev; + + return 0; + +err_free_netdev: + free_netdev(dev); + return ret; } static void tc589_detach(struct pcmcia_device *link) diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index 0a9118b8be0c..bc9c81dc00fd 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -52,6 +52,7 @@ static const char version2[] = #include #include #include +#include #include diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c index 6e62c37c9400..7465650c8078 100644 --- a/drivers/net/ethernet/8390/smc-ultra.c +++ b/drivers/net/ethernet/8390/smc-ultra.c @@ -66,6 +66,7 @@ static const char version[] = #include #include #include +#include #include #include diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c index 5b00c452bede..119021d41451 100644 --- a/drivers/net/ethernet/8390/wd.c +++ b/drivers/net/ethernet/8390/wd.c @@ -37,6 +37,7 @@ static const char version[] = #include #include #include +#include #include diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 235fcacef5c5..f8cc8925161c 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -189,6 +189,8 @@ config AMD_XGBE_HAVE_ECC config PDS_CORE tristate "AMD/Pensando Data Systems Core Device Support" depends on 64BIT && PCI + select AUXILIARY_BUS + select NET_DEVLINK help This enables the support for the AMD/Pensando Core device family of adapters. More specific information on this driver can be diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c index 8971665a4b2a..6cf38180cc01 100644 --- a/drivers/net/ethernet/amd/lance.c +++ b/drivers/net/ethernet/amd/lance.c @@ -59,6 +59,7 @@ static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@c #include #include #include +#include #include #include diff --git a/drivers/net/ethernet/amd/pds_core/Makefile b/drivers/net/ethernet/amd/pds_core/Makefile index 0abc33ce826c..8239742e681f 100644 --- a/drivers/net/ethernet/amd/pds_core/Makefile +++ b/drivers/net/ethernet/amd/pds_core/Makefile @@ -9,6 +9,5 @@ pds_core-y := main.o \ dev.o \ adminq.o \ core.o \ + debugfs.o \ fw.o - -pds_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index e2d14b1ca471..672757932246 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -244,11 +244,16 @@ static int pdsc_init_pf(struct pdsc *pdsc) set_bit(PDSC_S_FW_DEAD, &pdsc->state); err = pdsc_setup(pdsc, PDSC_SETUP_INIT); - if (err) + if (err) { + mutex_unlock(&pdsc->config_lock); goto err_out_unmap_bars; + } + err = pdsc_start(pdsc); - if (err) + if (err) { + mutex_unlock(&pdsc->config_lock); goto err_out_teardown; + } mutex_unlock(&pdsc->config_lock); @@ -257,13 +262,15 @@ static int pdsc_init_pf(struct pdsc *pdsc) err = devl_params_register(dl, pdsc_dl_params, ARRAY_SIZE(pdsc_dl_params)); if (err) { + devl_unlock(dl); dev_warn(pdsc->dev, "Failed to register devlink params: %pe\n", ERR_PTR(err)); - goto err_out_unlock_dl; + goto err_out_stop; } hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, 0, pdsc); if (IS_ERR(hr)) { + devl_unlock(dl); dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr); err = PTR_ERR(hr); goto err_out_unreg_params; @@ -279,15 +286,13 @@ static int pdsc_init_pf(struct pdsc *pdsc) return 0; err_out_unreg_params: - devl_params_unregister(dl, pdsc_dl_params, - ARRAY_SIZE(pdsc_dl_params)); -err_out_unlock_dl: - devl_unlock(dl); + devlink_params_unregister(dl, pdsc_dl_params, + ARRAY_SIZE(pdsc_dl_params)); +err_out_stop: pdsc_stop(pdsc); err_out_teardown: pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); err_out_unmap_bars: - mutex_unlock(&pdsc->config_lock); del_timer_sync(&pdsc->wdtimer); if (pdsc->wq) destroy_workqueue(pdsc->wq); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 33a9574e9e04..32d2c6fac652 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -1329,7 +1329,7 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) return pdata->phy_if.phy_impl.an_outcome(pdata); } -static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) +static bool xgbe_phy_status_result(struct xgbe_prv_data *pdata) { struct ethtool_link_ksettings *lks = &pdata->phy.lks; enum xgbe_mode mode; @@ -1367,8 +1367,13 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) pdata->phy.duplex = DUPLEX_FULL; - if (xgbe_set_mode(pdata, mode) && pdata->an_again) + if (!xgbe_set_mode(pdata, mode)) + return false; + + if (pdata->an_again) xgbe_phy_reconfig_aneg(pdata); + + return true; } static void xgbe_phy_status(struct xgbe_prv_data *pdata) @@ -1398,7 +1403,8 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata) return; } - xgbe_phy_status_result(pdata); + if (xgbe_phy_status_result(pdata)) + return; if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) clear_bit(XGBE_LINK_INIT, &pdata->dev_state); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 8647125d60ae..baa5f8cc31f2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -379,6 +379,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev) } } +#ifdef CONFIG_PM static int aq_suspend_common(struct device *dev) { struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev)); @@ -463,6 +464,7 @@ static const struct dev_pm_ops aq_pm_ops = { .restore = aq_pm_resume_restore, .thaw = aq_pm_thaw, }; +#endif static struct pci_driver aq_pci_ops = { .name = AQ_CFG_DRV_NAME, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c index 58d426dda3ed..674683b54304 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c @@ -336,7 +336,7 @@ static int aq_a2_fw_get_mac_permanent(struct aq_hw_s *self, u8 *mac) static void aq_a2_fill_a0_stats(struct aq_hw_s *self, struct statistics_s *stats) { - struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv; + struct hw_atl2_priv *priv = self->priv; struct aq_stats_s *cs = &self->curr_stats; struct aq_stats_s curr_stats = *cs; bool corrupted_stats = false; @@ -378,7 +378,7 @@ do { \ static void aq_a2_fill_b0_stats(struct aq_hw_s *self, struct statistics_s *stats) { - struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv; + struct hw_atl2_priv *priv = self->priv; struct aq_stats_s *cs = &self->curr_stats; struct aq_stats_s curr_stats = *cs; bool corrupted_stats = false; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 3bb5ea570c87..637d162bbcfa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -297,7 +297,7 @@ const u32 dmae_reg_go_c[] = { /* Global resources for unloading a previously loaded device */ #define BNX2X_PREV_WAIT_NEEDED 1 -static DEFINE_SEMAPHORE(bnx2x_prev_sem); +static DEFINE_SEMAPHORE(bnx2x_prev_sem, 1); static LIST_HEAD(bnx2x_prev_list); /* Forward declaration */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index a5408879e077..b31de4cf6534 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -10321,6 +10321,87 @@ struct hwrm_selftest_irq_output { u8 valid; }; +/* dbc_dbc (size:64b/8B) */ +struct dbc_dbc { + u32 index; + #define DBC_DBC_INDEX_MASK 0xffffffUL + #define DBC_DBC_INDEX_SFT 0 + #define DBC_DBC_EPOCH 0x1000000UL + #define DBC_DBC_TOGGLE_MASK 0x6000000UL + #define DBC_DBC_TOGGLE_SFT 25 + u32 type_path_xid; + #define DBC_DBC_XID_MASK 0xfffffUL + #define DBC_DBC_XID_SFT 0 + #define DBC_DBC_PATH_MASK 0x3000000UL + #define DBC_DBC_PATH_SFT 24 + #define DBC_DBC_PATH_ROCE (0x0UL << 24) + #define DBC_DBC_PATH_L2 (0x1UL << 24) + #define DBC_DBC_PATH_ENGINE (0x2UL << 24) + #define DBC_DBC_PATH_LAST DBC_DBC_PATH_ENGINE + #define DBC_DBC_VALID 0x4000000UL + #define DBC_DBC_DEBUG_TRACE 0x8000000UL + #define DBC_DBC_TYPE_MASK 0xf0000000UL + #define DBC_DBC_TYPE_SFT 28 + #define DBC_DBC_TYPE_SQ (0x0UL << 28) + #define DBC_DBC_TYPE_RQ (0x1UL << 28) + #define DBC_DBC_TYPE_SRQ (0x2UL << 28) + #define DBC_DBC_TYPE_SRQ_ARM (0x3UL << 28) + #define DBC_DBC_TYPE_CQ (0x4UL << 28) + #define DBC_DBC_TYPE_CQ_ARMSE (0x5UL << 28) + #define DBC_DBC_TYPE_CQ_ARMALL (0x6UL << 28) + #define DBC_DBC_TYPE_CQ_ARMENA (0x7UL << 28) + #define DBC_DBC_TYPE_SRQ_ARMENA (0x8UL << 28) + #define DBC_DBC_TYPE_CQ_CUTOFF_ACK (0x9UL << 28) + #define DBC_DBC_TYPE_NQ (0xaUL << 28) + #define DBC_DBC_TYPE_NQ_ARM (0xbUL << 28) + #define DBC_DBC_TYPE_NQ_MASK (0xeUL << 28) + #define DBC_DBC_TYPE_NULL (0xfUL << 28) + #define DBC_DBC_TYPE_LAST DBC_DBC_TYPE_NULL +}; + +/* db_push_start (size:64b/8B) */ +struct db_push_start { + u64 db; + #define DB_PUSH_START_DB_INDEX_MASK 0xffffffUL + #define DB_PUSH_START_DB_INDEX_SFT 0 + #define DB_PUSH_START_DB_PI_LO_MASK 0xff000000UL + #define DB_PUSH_START_DB_PI_LO_SFT 24 + #define DB_PUSH_START_DB_XID_MASK 0xfffff00000000ULL + #define DB_PUSH_START_DB_XID_SFT 32 + #define DB_PUSH_START_DB_PI_HI_MASK 0xf0000000000000ULL + #define DB_PUSH_START_DB_PI_HI_SFT 52 + #define DB_PUSH_START_DB_TYPE_MASK 0xf000000000000000ULL + #define DB_PUSH_START_DB_TYPE_SFT 60 + #define DB_PUSH_START_DB_TYPE_PUSH_START (0xcULL << 60) + #define DB_PUSH_START_DB_TYPE_PUSH_END (0xdULL << 60) + #define DB_PUSH_START_DB_TYPE_LAST DB_PUSH_START_DB_TYPE_PUSH_END +}; + +/* db_push_end (size:64b/8B) */ +struct db_push_end { + u64 db; + #define DB_PUSH_END_DB_INDEX_MASK 0xffffffUL + #define DB_PUSH_END_DB_INDEX_SFT 0 + #define DB_PUSH_END_DB_PI_LO_MASK 0xff000000UL + #define DB_PUSH_END_DB_PI_LO_SFT 24 + #define DB_PUSH_END_DB_XID_MASK 0xfffff00000000ULL + #define DB_PUSH_END_DB_XID_SFT 32 + #define DB_PUSH_END_DB_PI_HI_MASK 0xf0000000000000ULL + #define DB_PUSH_END_DB_PI_HI_SFT 52 + #define DB_PUSH_END_DB_PATH_MASK 0x300000000000000ULL + #define DB_PUSH_END_DB_PATH_SFT 56 + #define DB_PUSH_END_DB_PATH_ROCE (0x0ULL << 56) + #define DB_PUSH_END_DB_PATH_L2 (0x1ULL << 56) + #define DB_PUSH_END_DB_PATH_ENGINE (0x2ULL << 56) + #define DB_PUSH_END_DB_PATH_LAST DB_PUSH_END_DB_PATH_ENGINE + #define DB_PUSH_END_DB_DEBUG_TRACE 0x800000000000000ULL + #define DB_PUSH_END_DB_TYPE_MASK 0xf000000000000000ULL + #define DB_PUSH_END_DB_TYPE_SFT 60 + #define DB_PUSH_END_DB_TYPE_PUSH_START (0xcULL << 60) + #define DB_PUSH_END_DB_TYPE_PUSH_END (0xdULL << 60) + #define DB_PUSH_END_DB_TYPE_LAST DB_PUSH_END_DB_TYPE_PUSH_END +}; + /* db_push_info (size:64b/8B) */ struct db_push_info { u32 push_size_push_index; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index d937daa8ee88..eca0c92c0c84 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3450,7 +3450,7 @@ err_clk_disable: return ret; } -static void bcmgenet_netif_stop(struct net_device *dev) +static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -3465,7 +3465,8 @@ static void bcmgenet_netif_stop(struct net_device *dev) /* Disable MAC transmit. TX DMA disabled must be done before this */ umac_enable_set(priv, CMD_TX_EN, false); - phy_stop(dev->phydev); + if (stop_phy) + phy_stop(dev->phydev); bcmgenet_disable_rx_napi(priv); bcmgenet_intr_disable(priv); @@ -3486,7 +3487,7 @@ static int bcmgenet_close(struct net_device *dev) netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); - bcmgenet_netif_stop(dev); + bcmgenet_netif_stop(dev, false); /* Really kill the PHY state machine and disconnect from it */ phy_disconnect(dev->phydev); @@ -4304,7 +4305,7 @@ static int bcmgenet_suspend(struct device *d) netif_device_detach(dev); - bcmgenet_netif_stop(dev); + bcmgenet_netif_stop(dev, true); if (!device_may_wakeup(d)) phy_suspend(dev->phydev); diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index 06a0c00af99c..276c32c3926a 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -72,6 +72,8 @@ #include #include +#include + #include #include #if ALLOW_DMA diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 130ebf6853e6..83c27bbbc6ed 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -1247,7 +1247,7 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, int index; index = enetc_get_free_index(priv); - if (sfi->handle < 0) { + if (index < 0) { NL_SET_ERR_MSG_MOD(extack, "No Stream Filter resource!"); err = -ENOSPC; goto free_fmi; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 160c1b3525f5..38e5b5abe067 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3798,7 +3798,7 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, entries_free = fec_enet_get_free_txdesc_num(txq); if (entries_free < MAX_SKB_FRAGS + 1) { netdev_err(fep->netdev, "NOT enough BD for SG!\n"); - return NETDEV_TX_OK; + return NETDEV_TX_BUSY; } /* Fill in a Tx ring entry */ @@ -3834,6 +3834,11 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, index = fec_enet_get_bd_index(last_bdp, &txq->bd); txq->tx_skbuff[index] = NULL; + /* Make sure the updates to rest of the descriptor are performed before + * transferring ownership. + */ + dma_wmb(); + /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ @@ -3843,8 +3848,14 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, /* If this was the last BD in the ring, start at the beginning again. */ bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd); + /* Make sure the update to bdp are performed before txq->bd.cur. */ + dma_wmb(); + txq->bd.cur = bdp; + /* Trigger transmission start */ + writel(0, txq->bd.reg_desc_active); + return 0; } @@ -3856,6 +3867,7 @@ static int fec_enet_xdp_xmit(struct net_device *dev, struct fec_enet_private *fep = netdev_priv(dev); struct fec_enet_priv_tx_q *txq; int cpu = smp_processor_id(); + unsigned int sent_frames = 0; struct netdev_queue *nq; unsigned int queue; int i; @@ -3866,18 +3878,15 @@ static int fec_enet_xdp_xmit(struct net_device *dev, __netif_tx_lock(nq, cpu); - for (i = 0; i < num_frames; i++) - fec_enet_txq_xmit_frame(fep, txq, frames[i]); - - /* Make sure the update to bdp and tx_skbuff are performed. */ - wmb(); - - /* Trigger transmission start */ - writel(0, txq->bd.reg_desc_active); + for (i = 0; i < num_frames; i++) { + if (fec_enet_txq_xmit_frame(fep, txq, frames[i]) != 0) + break; + sent_frames++; + } __netif_tx_unlock(nq); - return num_frames; + return sent_frames; } static const struct net_device_ops fec_netdev_ops = { @@ -4473,9 +4482,11 @@ fec_drv_remove(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; int ret; - ret = pm_runtime_resume_and_get(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; + dev_err(&pdev->dev, + "Failed to resume device in remove callback (%pe)\n", + ERR_PTR(ret)); cancel_work_sync(&fep->tx_timeout_work); fec_ptp_stop(pdev); @@ -4488,8 +4499,13 @@ fec_drv_remove(struct platform_device *pdev) of_phy_deregister_fixed_link(np); of_node_put(fep->phy_node); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); + /* After pm_runtime_get_sync() failed, the clks are still off, so skip + * disabling them again. + */ + if (ret >= 0) { + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); + } pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 57ce74315eba..caa00c72aeeb 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -294,19 +294,6 @@ static int gve_napi_poll_dqo(struct napi_struct *napi, int budget) bool reschedule = false; int work_done = 0; - /* Clear PCI MSI-X Pending Bit Array (PBA) - * - * This bit is set if an interrupt event occurs while the vector is - * masked. If this bit is set and we reenable the interrupt, it will - * fire again. Since we're just about to poll the queue state, we don't - * need it to fire again. - * - * Under high softirq load, it's possible that the interrupt condition - * is triggered twice before we got the chance to process it. - */ - gve_write_irq_doorbell_dqo(priv, block, - GVE_ITR_NO_UPDATE_DQO | GVE_ITR_CLEAR_PBA_BIT_DQO); - if (block->tx) reschedule |= gve_tx_poll_dqo(block, /*do_clean=*/true); diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.c b/drivers/net/ethernet/hisilicon/hns/hnae.c index 9b26f0f2c748..8a1027ad340d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -448,7 +448,7 @@ EXPORT_SYMBOL(hnae_ae_unregister); static int __init hnae_init(void) { - hnae_class = class_create(THIS_MODULE, "hnae"); + hnae_class = class_create("hnae"); return PTR_ERR_OR_ZERO(hnae_class); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c index cbbab5b2b402..b85c412683dd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c @@ -331,9 +331,25 @@ static int hclge_comm_cmd_csq_done(struct hclge_comm_hw *hw) return head == hw->cmq.csq.next_to_use; } -static void hclge_comm_wait_for_resp(struct hclge_comm_hw *hw, +static u32 hclge_get_cmdq_tx_timeout(u16 opcode, u32 tx_timeout) +{ + static const struct hclge_cmdq_tx_timeout_map cmdq_tx_timeout_map[] = { + {HCLGE_OPC_CFG_RST_TRIGGER, HCLGE_COMM_CMDQ_TX_TIMEOUT_500MS}, + }; + u32 i; + + for (i = 0; i < ARRAY_SIZE(cmdq_tx_timeout_map); i++) + if (cmdq_tx_timeout_map[i].opcode == opcode) + return cmdq_tx_timeout_map[i].tx_timeout; + + return tx_timeout; +} + +static void hclge_comm_wait_for_resp(struct hclge_comm_hw *hw, u16 opcode, bool *is_completed) { + u32 cmdq_tx_timeout = hclge_get_cmdq_tx_timeout(opcode, + hw->cmq.tx_timeout); u32 timeout = 0; do { @@ -343,7 +359,7 @@ static void hclge_comm_wait_for_resp(struct hclge_comm_hw *hw, } udelay(1); timeout++; - } while (timeout < hw->cmq.tx_timeout); + } while (timeout < cmdq_tx_timeout); } static int hclge_comm_cmd_convert_err_code(u16 desc_ret) @@ -407,7 +423,8 @@ static int hclge_comm_cmd_check_result(struct hclge_comm_hw *hw, * if multi descriptors to be sent, use the first one to check */ if (HCLGE_COMM_SEND_SYNC(le16_to_cpu(desc->flag))) - hclge_comm_wait_for_resp(hw, &is_completed); + hclge_comm_wait_for_resp(hw, le16_to_cpu(desc->opcode), + &is_completed); if (!is_completed) ret = -EBADE; @@ -529,7 +546,7 @@ int hclge_comm_cmd_queue_init(struct pci_dev *pdev, struct hclge_comm_hw *hw) cmdq->crq.desc_num = HCLGE_COMM_NIC_CMQ_DESC_NUM; /* Setup Tx write back timeout */ - cmdq->tx_timeout = HCLGE_COMM_CMDQ_TX_TIMEOUT; + cmdq->tx_timeout = HCLGE_COMM_CMDQ_TX_TIMEOUT_DEFAULT; /* Setup queue rings */ ret = hclge_comm_alloc_cmd_queue(hw, HCLGE_COMM_TYPE_CSQ); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index de72ecbfd5ad..18f1b4bf362d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -54,7 +54,8 @@ #define HCLGE_COMM_NIC_SW_RST_RDY BIT(HCLGE_COMM_NIC_SW_RST_RDY_B) #define HCLGE_COMM_NIC_CMQ_DESC_NUM_S 3 #define HCLGE_COMM_NIC_CMQ_DESC_NUM 1024 -#define HCLGE_COMM_CMDQ_TX_TIMEOUT 30000 +#define HCLGE_COMM_CMDQ_TX_TIMEOUT_DEFAULT 30000 +#define HCLGE_COMM_CMDQ_TX_TIMEOUT_500MS 500000 enum hclge_opcode_type { /* Generic commands */ @@ -360,6 +361,11 @@ struct hclge_comm_caps_bit_map { u16 local_bit; }; +struct hclge_cmdq_tx_timeout_map { + u32 opcode; + u32 tx_timeout; +}; + struct hclge_comm_firmware_compat_cmd { __le32 compat; u8 rsv[20]; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 4c3e90a1c4d0..d385ffc21876 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -130,7 +130,7 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = { .name = "tx_bd_queue", .cmd = HNAE3_DBG_CMD_TX_BD, .dentry = HNS3_DBG_DENTRY_TX_BD, - .buf_len = HNS3_DBG_READ_LEN_4MB, + .buf_len = HNS3_DBG_READ_LEN_5MB, .init = hns3_dbg_bd_file_init, }, { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h index 97578eabb7d8..4a5ef8a90a10 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h @@ -10,6 +10,7 @@ #define HNS3_DBG_READ_LEN_128KB 0x20000 #define HNS3_DBG_READ_LEN_1MB 0x100000 #define HNS3_DBG_READ_LEN_4MB 0x400000 +#define HNS3_DBG_READ_LEN_5MB 0x500000 #define HNS3_DBG_WRITE_LEN 1024 #define HNS3_DBG_DATA_STR_LEN 32 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 7356ad965487..b676496ec6d7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1040,7 +1040,7 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) return; order = get_order(alloc_size); - if (order >= MAX_ORDER) { + if (order > MAX_ORDER) { if (net_ratelimit()) dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); return; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4fb5406c1951..2689b108f7df 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -8053,12 +8053,15 @@ static void hclge_ae_stop(struct hnae3_handle *handle) /* If it is not PF reset or FLR, the firmware will disable the MAC, * so it only need to stop phy here. */ - if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) && - hdev->reset_type != HNAE3_FUNC_RESET && - hdev->reset_type != HNAE3_FLR_RESET) { - hclge_mac_stop_phy(hdev); - hclge_update_link_status(hdev); - return; + if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) { + hclge_pfc_pause_en_cfg(hdev, HCLGE_PFC_TX_RX_DISABLE, + HCLGE_PFC_DISABLE); + if (hdev->reset_type != HNAE3_FUNC_RESET && + hdev->reset_type != HNAE3_FLR_RESET) { + hclge_mac_stop_phy(hdev); + hclge_update_link_status(hdev); + return; + } } hclge_reset_tqp(handle); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 4a33f65190e2..922c0da3660c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -171,8 +171,8 @@ int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx) return hclge_cmd_send(&hdev->hw, &desc, 1); } -static int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, - u8 pfc_bitmap) +int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, + u8 pfc_bitmap) { struct hclge_desc desc; struct hclge_pfc_en_cmd *pfc = (struct hclge_pfc_en_cmd *)desc.data; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 68f28a98e380..dd6f1fd486cf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -164,6 +164,9 @@ struct hclge_bp_to_qs_map_cmd { u32 rsvd1; }; +#define HCLGE_PFC_DISABLE 0 +#define HCLGE_PFC_TX_RX_DISABLE 0 + struct hclge_pfc_en_cmd { u8 tx_rx_en_bitmap; u8 pri_en_bitmap; @@ -235,6 +238,8 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc); void hclge_tm_pfc_info_update(struct hclge_dev *hdev); int hclge_tm_dwrr_cfg(struct hclge_dev *hdev); int hclge_tm_init_hw(struct hclge_dev *hdev, bool init); +int hclge_pfc_pause_en_cfg(struct hclge_dev *hdev, u8 tx_rx_bitmap, + u8 pfc_bitmap); int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx); int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr); void hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index f24046250341..dd08989a4c7c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1436,7 +1436,10 @@ static int hclgevf_reset_wait(struct hclgevf_dev *hdev) * might happen in case reset assertion was made by PF. Yes, this also * means we might end up waiting bit more even for VF reset. */ - msleep(5000); + if (hdev->reset_type == HNAE3_VF_FULL_RESET) + msleep(5000); + else + msleep(500); return 0; } diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index b35c9b6f913b..4e18b4cefa97 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -75,7 +75,7 @@ * pool for the 4MB. Thus the 16 Rx and Tx queues require 32 * 5 = 160 * plus 16 for the TSO pools for a total of 176 LTB mappings per VNIC. */ -#define IBMVNIC_ONE_LTB_MAX ((u32)((1 << (MAX_ORDER - 1)) * PAGE_SIZE)) +#define IBMVNIC_ONE_LTB_MAX ((u32)((1 << MAX_ORDER) * PAGE_SIZE)) #define IBMVNIC_ONE_LTB_SIZE min((u32)(8 << 20), IBMVNIC_ONE_LTB_MAX) #define IBMVNIC_LTB_SET_SIZE (38 << 20) diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 9afbbdac3590..7c0578b5457b 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -2238,11 +2238,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, iavf_process_config(adapter); adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES; - /* Request VLAN offload settings */ - if (VLAN_V2_ALLOWED(adapter)) - iavf_set_vlan_offload_features(adapter, 0, - netdev->features); - iavf_set_queue_vlan_tag_loc(adapter); was_mac_changed = !ether_addr_equal(netdev->dev_addr, diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index c6d4926f0fcf..850db8e0e6b0 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -932,10 +932,9 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring, if ((first->tx_flags & ICE_TX_FLAGS_HW_VLAN || first->tx_flags & ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN) || skb->priority != TC_PRIO_CONTROL) { - first->tx_flags &= ~ICE_TX_FLAGS_VLAN_PR_M; + first->vid &= ~VLAN_PRIO_MASK; /* Mask the lower 3 bits to set the 802.1p priority */ - first->tx_flags |= (skb->priority & 0x7) << - ICE_TX_FLAGS_VLAN_PR_S; + first->vid |= (skb->priority << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; /* if this is not already set it means a VLAN 0 + priority needs * to be offloaded */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 450317dfcca7..11ae0e41f518 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2745,6 +2745,8 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) goto unroll_vector_base; ice_vsi_map_rings_to_vectors(vsi); + vsi->stat_offsets_loaded = false; + if (ice_is_xdp_ena_vsi(vsi)) { ret = ice_vsi_determine_xdp_res(vsi); if (ret) @@ -2793,6 +2795,9 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) ret = ice_vsi_alloc_ring_stats(vsi); if (ret) goto unroll_vector_base; + + vsi->stat_offsets_loaded = false; + /* Do not exit if configuring RSS had an issue, at least * receive traffic on first queue. Hence no need to capture * return value diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index f1dca59bd844..588ad8696756 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -1171,7 +1171,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) if (!vf) return -EINVAL; - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1286,7 +1286,7 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) goto out_put_vf; } - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1340,7 +1340,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) return -EOPNOTSUPP; } - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1653,7 +1653,7 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, if (!vf) return -EINVAL; - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index 76f29a5bf8d7..d1a31f236d26 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -693,17 +693,18 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) * results into order of switch rule evaluation. */ rule_info.priority = 7; + rule_info.flags_info.act_valid = true; if (fltr->direction == ICE_ESWITCH_FLTR_INGRESS) { rule_info.sw_act.flag |= ICE_FLTR_RX; rule_info.sw_act.src = hw->pf_id; rule_info.rx = true; + rule_info.flags_info.act = ICE_SINGLE_ACT_LB_ENABLE; } else { rule_info.sw_act.flag |= ICE_FLTR_TX; rule_info.sw_act.src = vsi->idx; rule_info.rx = false; rule_info.flags_info.act = ICE_SINGLE_ACT_LAN_ENABLE; - rule_info.flags_info.act_valid = true; } /* specify the cookie as filter_rule_id */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 4fcf2d07eb85..52d0a126eb61 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1152,11 +1152,11 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) unsigned int total_rx_bytes = 0, total_rx_pkts = 0; unsigned int offset = rx_ring->rx_offset; struct xdp_buff *xdp = &rx_ring->xdp; + u32 cached_ntc = rx_ring->first_desc; struct ice_tx_ring *xdp_ring = NULL; struct bpf_prog *xdp_prog = NULL; u32 ntc = rx_ring->next_to_clean; u32 cnt = rx_ring->count; - u32 cached_ntc = ntc; u32 xdp_xmit = 0; u32 cached_ntu; bool failure; @@ -1664,8 +1664,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, if (first->tx_flags & ICE_TX_FLAGS_HW_VLAN) { td_cmd |= (u64)ICE_TX_DESC_CMD_IL2TAG1; - td_tag = (first->tx_flags & ICE_TX_FLAGS_VLAN_M) >> - ICE_TX_FLAGS_VLAN_S; + td_tag = first->vid; } dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); @@ -1998,7 +1997,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first) * VLAN offloads exclusively so we only care about the VLAN ID here */ if (skb_vlan_tag_present(skb)) { - first->tx_flags |= skb_vlan_tag_get(skb) << ICE_TX_FLAGS_VLAN_S; + first->vid = skb_vlan_tag_get(skb); if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2) first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN; else @@ -2388,8 +2387,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) offload.cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX | (ICE_TX_CTX_DESC_IL2TAG2 << ICE_TXD_CTX_QW1_CMD_S)); - offload.cd_l2tag2 = (first->tx_flags & ICE_TX_FLAGS_VLAN_M) >> - ICE_TX_FLAGS_VLAN_S; + offload.cd_l2tag2 = first->vid; } /* set up TSO offload */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index fff0efe28373..166413fc33f4 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -127,10 +127,6 @@ static inline int ice_skb_pad(void) #define ICE_TX_FLAGS_IPV6 BIT(6) #define ICE_TX_FLAGS_TUNNEL BIT(7) #define ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN BIT(8) -#define ICE_TX_FLAGS_VLAN_M 0xffff0000 -#define ICE_TX_FLAGS_VLAN_PR_M 0xe0000000 -#define ICE_TX_FLAGS_VLAN_PR_S 29 -#define ICE_TX_FLAGS_VLAN_S 16 #define ICE_XDP_PASS 0 #define ICE_XDP_CONSUMED BIT(0) @@ -182,8 +178,9 @@ struct ice_tx_buf { unsigned int gso_segs; unsigned int nr_frags; /* used for mbuf XDP */ }; - u32 type:16; /* &ice_tx_buf_type */ - u32 tx_flags:16; + u32 tx_flags:12; + u32 type:4; /* &ice_tx_buf_type */ + u32 vid:16; DEFINE_DMA_UNMAP_LEN(len); DEFINE_DMA_UNMAP_ADDR(dma); }; diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 89fd6982df09..bf74a2f3a4f8 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -185,6 +185,25 @@ int ice_check_vf_ready_for_cfg(struct ice_vf *vf) return 0; } +/** + * ice_check_vf_ready_for_reset - check if VF is ready to be reset + * @vf: VF to check if it's ready to be reset + * + * The purpose of this function is to ensure that the VF is not in reset, + * disabled, and is both initialized and active, thus enabling us to safely + * initialize another reset. + */ +int ice_check_vf_ready_for_reset(struct ice_vf *vf) +{ + int ret; + + ret = ice_check_vf_ready_for_cfg(vf); + if (!ret && !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + ret = -EAGAIN; + + return ret; +} + /** * ice_trigger_vf_reset - Reset a VF on HW * @vf: pointer to the VF structure diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index e3cda6fb71ab..a38ef00a3679 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -215,6 +215,7 @@ u16 ice_get_num_vfs(struct ice_pf *pf); struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf); bool ice_is_vf_disabled(struct ice_vf *vf); int ice_check_vf_ready_for_cfg(struct ice_vf *vf); +int ice_check_vf_ready_for_reset(struct ice_vf *vf); void ice_set_vf_state_dis(struct ice_vf *vf); bool ice_is_any_vf_in_unicast_promisc(struct ice_pf *pf); void diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 97243c616d5d..f4a524f80b11 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -3955,6 +3955,7 @@ error_handler: ice_vc_notify_vf_link_state(vf); break; case VIRTCHNL_OP_RESET_VF: + clear_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); ops->reset_vf(vf); break; case VIRTCHNL_OP_ADD_ETH_ADDR: diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index 205d577bdbba..caf91c6f52b4 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -426,7 +426,7 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value) static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) { u32 hash_value, hash_mask; - u8 bit_shift = 0; + u8 bit_shift = 1; /* Register count multiplied by bits per register */ hash_mask = (hw->mac.mta_reg_count * 32) - 1; @@ -434,7 +434,7 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) /* For a mc_filter_type of 0, bit_shift is the number of left-shifts * where 0xFF would still fall within the hash mask. */ - while (hash_mask >> bit_shift != 0xFF) + while (hash_mask >> bit_shift != 0xFF && bit_shift < 4) bit_shift++; /* The portion of the address that is used for the hash table diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index 7a992befca24..9f3827eda157 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h @@ -87,8 +87,13 @@ union igc_adv_rx_desc { #define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */ /* SRRCTL bit definitions */ -#define IGC_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */ -#define IGC_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */ -#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IGC_SRRCTL_BSIZEPKT_MASK GENMASK(6, 0) +#define IGC_SRRCTL_BSIZEPKT(x) FIELD_PREP(IGC_SRRCTL_BSIZEPKT_MASK, \ + (x) / 1024) /* in 1 KB resolution */ +#define IGC_SRRCTL_BSIZEHDR_MASK GENMASK(13, 8) +#define IGC_SRRCTL_BSIZEHDR(x) FIELD_PREP(IGC_SRRCTL_BSIZEHDR_MASK, \ + (x) / 64) /* in 64 bytes resolution */ +#define IGC_SRRCTL_DESCTYPE_MASK GENMASK(27, 25) +#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF FIELD_PREP(IGC_SRRCTL_DESCTYPE_MASK, 1) #endif /* _IGC_BASE_H */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index ba49728be919..1c4676882082 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -640,8 +640,11 @@ static void igc_configure_rx_ring(struct igc_adapter *adapter, else buf_size = IGC_RXBUFFER_2048; - srrctl = IGC_RX_HDR_LEN << IGC_SRRCTL_BSIZEHDRSIZE_SHIFT; - srrctl |= buf_size >> IGC_SRRCTL_BSIZEPKT_SHIFT; + srrctl = rd32(IGC_SRRCTL(reg_idx)); + srrctl &= ~(IGC_SRRCTL_BSIZEPKT_MASK | IGC_SRRCTL_BSIZEHDR_MASK | + IGC_SRRCTL_DESCTYPE_MASK); + srrctl |= IGC_SRRCTL_BSIZEHDR(IGC_RX_HDR_LEN); + srrctl |= IGC_SRRCTL_BSIZEPKT(buf_size); srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF; wr32(IGC_SRRCTL(reg_idx), srrctl); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index f8156fe4b1dc..0ee943db3dc9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -1035,9 +1035,6 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx) adapter->q_vector[v_idx] = NULL; __netif_napi_del(&q_vector->napi); - if (static_key_enabled(&ixgbe_xdp_locking_key)) - static_branch_dec(&ixgbe_xdp_locking_key); - /* * after a call to __netif_napi_del() napi may still be used and * ixgbe_get_stats64() might access the rings on this vector, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e961ef4bbf4d..5d83c887a3fc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6487,6 +6487,10 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, set_bit(0, adapter->fwd_bitmask); set_bit(__IXGBE_DOWN, &adapter->state); + /* enable locking for XDP_TX if we have more CPUs than queues */ + if (nr_cpu_ids > IXGBE_MAX_XDP_QS) + static_branch_enable(&ixgbe_xdp_locking_key); + return 0; } @@ -10270,8 +10274,6 @@ static int ixgbe_xdp_setup(struct net_device *dev, struct bpf_prog *prog) */ if (nr_cpu_ids > IXGBE_MAX_XDP_QS * 2) return -ENOMEM; - else if (nr_cpu_ids > IXGBE_MAX_XDP_QS) - static_branch_inc(&ixgbe_xdp_locking_key); old_prog = xchg(&adapter->xdp_prog, prog); need_reset = (!!prog != !!old_prog); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 724df6398bbe..bd77152bb8d7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -1231,6 +1231,14 @@ static inline void link_status_user_format(u64 lstat, linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat); linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat); linfo->lmac_type_id = FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, lstat); + + if (linfo->lmac_type_id >= LMAC_MODE_MAX) { + dev_err(&cgx->pdev->dev, "Unknown lmac_type_id %d reported by firmware on cgx port%d:%d", + linfo->lmac_type_id, cgx->cgx_id, lmac_id); + strncpy(linfo->lmac_type, "Unknown", LMACTYPE_STR_LEN - 1); + return; + } + lmac_string = cgx_lmactype_string[linfo->lmac_type_id]; strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c index 2898931d5260..9690ac01f02c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c @@ -157,7 +157,7 @@ EXPORT_SYMBOL(otx2_mbox_init); */ int otx2_mbox_regions_init(struct otx2_mbox *mbox, void **hwbase, struct pci_dev *pdev, void *reg_base, - int direction, int ndevs) + int direction, int ndevs, unsigned long *pf_bmap) { struct otx2_mbox_dev *mdev; int devid, err; @@ -169,6 +169,9 @@ int otx2_mbox_regions_init(struct otx2_mbox *mbox, void **hwbase, mbox->hwbase = hwbase[0]; for (devid = 0; devid < ndevs; devid++) { + if (!test_bit(devid, pf_bmap)) + continue; + mdev = &mbox->dev[devid]; mdev->mbase = hwbase[devid]; mdev->hwbase = hwbase[devid]; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 8fb5cae7285b..6389ed83637d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -96,9 +96,10 @@ void otx2_mbox_destroy(struct otx2_mbox *mbox); int otx2_mbox_init(struct otx2_mbox *mbox, void __force *hwbase, struct pci_dev *pdev, void __force *reg_base, int direction, int ndevs); + int otx2_mbox_regions_init(struct otx2_mbox *mbox, void __force **hwbase, struct pci_dev *pdev, void __force *reg_base, - int direction, int ndevs); + int direction, int ndevs, unsigned long *bmap); void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid); int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid); int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid); @@ -245,9 +246,9 @@ M(NPC_MCAM_READ_BASE_RULE, 0x6011, npc_read_base_steer_rule, \ M(NPC_MCAM_GET_STATS, 0x6012, npc_mcam_entry_stats, \ npc_mcam_get_stats_req, \ npc_mcam_get_stats_rsp) \ -M(NPC_GET_SECRET_KEY, 0x6013, npc_get_secret_key, \ - npc_get_secret_key_req, \ - npc_get_secret_key_rsp) \ +M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info, \ + npc_get_field_hash_info_req, \ + npc_get_field_hash_info_rsp) \ M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status, \ npc_get_field_status_req, \ npc_get_field_status_rsp) \ @@ -1524,14 +1525,20 @@ struct npc_mcam_get_stats_rsp { u8 stat_ena; /* enabled */ }; -struct npc_get_secret_key_req { +struct npc_get_field_hash_info_req { struct mbox_msghdr hdr; u8 intf; }; -struct npc_get_secret_key_rsp { +struct npc_get_field_hash_info_rsp { struct mbox_msghdr hdr; u64 secret_key[3]; +#define NPC_MAX_HASH 2 +#define NPC_MAX_HASH_MASK 2 + /* NPC_AF_INTF(0..1)_HASH(0..1)_MASK(0..1) */ + u64 hash_mask[NPC_MAX_INTF][NPC_MAX_HASH][NPC_MAX_HASH_MASK]; + /* NPC_AF_INTF(0..1)_HASH(0..1)_RESULT_CTRL */ + u64 hash_ctrl[NPC_MAX_INTF][NPC_MAX_HASH]; }; enum ptp_op { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c index f68a6a0e3aa4..c43f19dfbd74 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c @@ -473,6 +473,8 @@ void mcs_flowid_entry_write(struct mcs *mcs, u64 *data, u64 *mask, int flow_id, for (reg_id = 0; reg_id < 4; reg_id++) { reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_DATAX(reg_id, flow_id); mcs_reg_write(mcs, reg, data[reg_id]); + } + for (reg_id = 0; reg_id < 4; reg_id++) { reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id); mcs_reg_write(mcs, reg, mask[reg_id]); } @@ -480,6 +482,8 @@ void mcs_flowid_entry_write(struct mcs *mcs, u64 *data, u64 *mask, int flow_id, for (reg_id = 0; reg_id < 4; reg_id++) { reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_DATAX(reg_id, flow_id); mcs_reg_write(mcs, reg, data[reg_id]); + } + for (reg_id = 0; reg_id < 4; reg_id++) { reg = MCSX_CPM_TX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id); mcs_reg_write(mcs, reg, mask[reg_id]); } @@ -494,6 +498,9 @@ int mcs_install_flowid_bypass_entry(struct mcs *mcs) /* Flow entry */ flow_id = mcs->hw->tcam_entries - MCS_RSRC_RSVD_CNT; + __set_bit(flow_id, mcs->rx.flow_ids.bmap); + __set_bit(flow_id, mcs->tx.flow_ids.bmap); + for (reg_id = 0; reg_id < 4; reg_id++) { reg = MCSX_CPM_RX_SLAVE_FLOWID_TCAM_MASKX(reg_id, flow_id); mcs_reg_write(mcs, reg, GENMASK_ULL(63, 0)); @@ -504,6 +511,8 @@ int mcs_install_flowid_bypass_entry(struct mcs *mcs) } /* secy */ secy_id = mcs->hw->secy_entries - MCS_RSRC_RSVD_CNT; + __set_bit(secy_id, mcs->rx.secy.bmap); + __set_bit(secy_id, mcs->tx.secy.bmap); /* Set validate frames to NULL and enable control port */ plcy = 0x7ull; @@ -528,6 +537,7 @@ int mcs_install_flowid_bypass_entry(struct mcs *mcs) /* Enable Flowid entry */ mcs_ena_dis_flowid_entry(mcs, flow_id, MCS_RX, true); mcs_ena_dis_flowid_entry(mcs, flow_id, MCS_TX, true); + return 0; } @@ -926,60 +936,42 @@ static void mcs_tx_misc_intr_handler(struct mcs *mcs, u64 intr) mcs_add_intr_wq_entry(mcs, &event); } -static void mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir) +void cn10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, + enum mcs_direction dir) { - struct mcs_intr_event event = { 0 }; - int i; + u64 val, reg; + int lmac; - if (!(intr & MCS_BBE_INT_MASK)) + if (!(intr & 0x6ULL)) return; - event.mcs_id = mcs->mcs_id; - event.pcifunc = mcs->pf_map[0]; + if (intr & BIT_ULL(1)) + reg = (dir == MCS_RX) ? MCSX_BBE_RX_SLAVE_DFIFO_OVERFLOW_0 : + MCSX_BBE_TX_SLAVE_DFIFO_OVERFLOW_0; + else + reg = (dir == MCS_RX) ? MCSX_BBE_RX_SLAVE_PLFIFO_OVERFLOW_0 : + MCSX_BBE_TX_SLAVE_PLFIFO_OVERFLOW_0; + val = mcs_reg_read(mcs, reg); - for (i = 0; i < MCS_MAX_BBE_INT; i++) { - if (!(intr & BIT_ULL(i))) + /* policy/data over flow occurred */ + for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) { + if (!(val & BIT_ULL(lmac))) continue; - - /* Lower nibble denotes data fifo overflow interrupts and - * upper nibble indicates policy fifo overflow interrupts. - */ - if (intr & 0xFULL) - event.intr_mask = (dir == MCS_RX) ? - MCS_BBE_RX_DFIFO_OVERFLOW_INT : - MCS_BBE_TX_DFIFO_OVERFLOW_INT; - else - event.intr_mask = (dir == MCS_RX) ? - MCS_BBE_RX_PLFIFO_OVERFLOW_INT : - MCS_BBE_TX_PLFIFO_OVERFLOW_INT; - - /* Notify the lmac_id info which ran into BBE fatal error */ - event.lmac_id = i & 0x3ULL; - mcs_add_intr_wq_entry(mcs, &event); + dev_warn(mcs->dev, "BEE:Policy or data overflow occurred on lmac:%d\n", lmac); } } -static void mcs_pab_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir) +void cn10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr, + enum mcs_direction dir) { - struct mcs_intr_event event = { 0 }; - int i; + int lmac; - if (!(intr & MCS_PAB_INT_MASK)) + if (!(intr & 0xFFFFFULL)) return; - event.mcs_id = mcs->mcs_id; - event.pcifunc = mcs->pf_map[0]; - - for (i = 0; i < MCS_MAX_PAB_INT; i++) { - if (!(intr & BIT_ULL(i))) - continue; - - event.intr_mask = (dir == MCS_RX) ? MCS_PAB_RX_CHAN_OVERFLOW_INT : - MCS_PAB_TX_CHAN_OVERFLOW_INT; - - /* Notify the lmac_id info which ran into PAB fatal error */ - event.lmac_id = i; - mcs_add_intr_wq_entry(mcs, &event); + for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) { + if (intr & BIT_ULL(lmac)) + dev_warn(mcs->dev, "PAB: overflow occurred on lmac:%d\n", lmac); } } @@ -988,9 +980,8 @@ static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq) struct mcs *mcs = (struct mcs *)mcs_irq; u64 intr, cpm_intr, bbe_intr, pab_intr; - /* Disable and clear the interrupt */ + /* Disable the interrupt */ mcs_reg_write(mcs, MCSX_IP_INT_ENA_W1C, BIT_ULL(0)); - mcs_reg_write(mcs, MCSX_IP_INT, BIT_ULL(0)); /* Check which block has interrupt*/ intr = mcs_reg_read(mcs, MCSX_TOP_SLAVE_INT_SUM); @@ -1037,7 +1028,7 @@ static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq) /* BBE RX */ if (intr & MCS_BBE_RX_INT_ENA) { bbe_intr = mcs_reg_read(mcs, MCSX_BBE_RX_SLAVE_BBE_INT); - mcs_bbe_intr_handler(mcs, bbe_intr, MCS_RX); + mcs->mcs_ops->mcs_bbe_intr_handler(mcs, bbe_intr, MCS_RX); /* Clear the interrupt */ mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT_INTR_RW, 0); @@ -1047,7 +1038,7 @@ static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq) /* BBE TX */ if (intr & MCS_BBE_TX_INT_ENA) { bbe_intr = mcs_reg_read(mcs, MCSX_BBE_TX_SLAVE_BBE_INT); - mcs_bbe_intr_handler(mcs, bbe_intr, MCS_TX); + mcs->mcs_ops->mcs_bbe_intr_handler(mcs, bbe_intr, MCS_TX); /* Clear the interrupt */ mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT_INTR_RW, 0); @@ -1057,7 +1048,7 @@ static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq) /* PAB RX */ if (intr & MCS_PAB_RX_INT_ENA) { pab_intr = mcs_reg_read(mcs, MCSX_PAB_RX_SLAVE_PAB_INT); - mcs_pab_intr_handler(mcs, pab_intr, MCS_RX); + mcs->mcs_ops->mcs_pab_intr_handler(mcs, pab_intr, MCS_RX); /* Clear the interrupt */ mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT_INTR_RW, 0); @@ -1067,14 +1058,15 @@ static irqreturn_t mcs_ip_intr_handler(int irq, void *mcs_irq) /* PAB TX */ if (intr & MCS_PAB_TX_INT_ENA) { pab_intr = mcs_reg_read(mcs, MCSX_PAB_TX_SLAVE_PAB_INT); - mcs_pab_intr_handler(mcs, pab_intr, MCS_TX); + mcs->mcs_ops->mcs_pab_intr_handler(mcs, pab_intr, MCS_TX); /* Clear the interrupt */ mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_INTR_RW, 0); mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT, pab_intr); } - /* Enable the interrupt */ + /* Clear and enable the interrupt */ + mcs_reg_write(mcs, MCSX_IP_INT, BIT_ULL(0)); mcs_reg_write(mcs, MCSX_IP_INT_ENA_W1S, BIT_ULL(0)); return IRQ_HANDLED; @@ -1156,7 +1148,7 @@ static int mcs_register_interrupts(struct mcs *mcs) return ret; } - ret = request_irq(pci_irq_vector(mcs->pdev, MCS_INT_VEC_IP), + ret = request_irq(pci_irq_vector(mcs->pdev, mcs->hw->ip_vec), mcs_ip_intr_handler, 0, "MCS_IP", mcs); if (ret) { dev_err(mcs->dev, "MCS IP irq registration failed\n"); @@ -1175,11 +1167,11 @@ static int mcs_register_interrupts(struct mcs *mcs) mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_TX_INT_ENB, 0x7ULL); mcs_reg_write(mcs, MCSX_CPM_RX_SLAVE_RX_INT_ENB, 0x7FULL); - mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT_ENB, 0xff); - mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT_ENB, 0xff); + mcs_reg_write(mcs, MCSX_BBE_RX_SLAVE_BBE_INT_ENB, 0xFFULL); + mcs_reg_write(mcs, MCSX_BBE_TX_SLAVE_BBE_INT_ENB, 0xFFULL); - mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT_ENB, 0xff); - mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_ENB, 0xff); + mcs_reg_write(mcs, MCSX_PAB_RX_SLAVE_PAB_INT_ENB, 0xFFFFFULL); + mcs_reg_write(mcs, MCSX_PAB_TX_SLAVE_PAB_INT_ENB, 0xFFFFFULL); mcs->tx_sa_active = alloc_mem(mcs, mcs->hw->sc_entries); if (!mcs->tx_sa_active) { @@ -1190,7 +1182,7 @@ static int mcs_register_interrupts(struct mcs *mcs) return ret; free_irq: - free_irq(pci_irq_vector(mcs->pdev, MCS_INT_VEC_IP), mcs); + free_irq(pci_irq_vector(mcs->pdev, mcs->hw->ip_vec), mcs); exit: pci_free_irq_vectors(mcs->pdev); mcs->num_vec = 0; @@ -1325,8 +1317,11 @@ void mcs_reset_port(struct mcs *mcs, u8 port_id, u8 reset) void mcs_set_lmac_mode(struct mcs *mcs, int lmac_id, u8 mode) { u64 reg; + int id = lmac_id * 2; - reg = MCSX_MCS_TOP_SLAVE_CHANNEL_CFG(lmac_id * 2); + reg = MCSX_MCS_TOP_SLAVE_CHANNEL_CFG(id); + mcs_reg_write(mcs, reg, (u64)mode); + reg = MCSX_MCS_TOP_SLAVE_CHANNEL_CFG((id + 1)); mcs_reg_write(mcs, reg, (u64)mode); } @@ -1484,6 +1479,7 @@ void cn10kb_mcs_set_hw_capabilities(struct mcs *mcs) hw->lmac_cnt = 20; /* lmacs/ports per mcs block */ hw->mcs_x2p_intf = 5; /* x2p clabration intf */ hw->mcs_blks = 1; /* MCS blocks */ + hw->ip_vec = MCS_CN10KB_INT_VEC_IP; /* IP vector */ } static struct mcs_ops cn10kb_mcs_ops = { @@ -1492,6 +1488,8 @@ static struct mcs_ops cn10kb_mcs_ops = { .mcs_tx_sa_mem_map_write = cn10kb_mcs_tx_sa_mem_map_write, .mcs_rx_sa_mem_map_write = cn10kb_mcs_rx_sa_mem_map_write, .mcs_flowid_secy_map = cn10kb_mcs_flowid_secy_map, + .mcs_bbe_intr_handler = cn10kb_mcs_bbe_intr_handler, + .mcs_pab_intr_handler = cn10kb_mcs_pab_intr_handler, }; static int mcs_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -1592,7 +1590,7 @@ static void mcs_remove(struct pci_dev *pdev) /* Set MCS to external bypass */ mcs_set_external_bypass(mcs, true); - free_irq(pci_irq_vector(pdev, MCS_INT_VEC_IP), mcs); + free_irq(pci_irq_vector(pdev, mcs->hw->ip_vec), mcs); pci_free_irq_vectors(pdev); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.h b/drivers/net/ethernet/marvell/octeontx2/af/mcs.h index 64dc2b80e15d..0f89dcb76465 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.h @@ -43,24 +43,15 @@ /* Reserved resources for default bypass entry */ #define MCS_RSRC_RSVD_CNT 1 -/* MCS Interrupt Vector Enumeration */ -enum mcs_int_vec_e { - MCS_INT_VEC_MIL_RX_GBL = 0x0, - MCS_INT_VEC_MIL_RX_LMACX = 0x1, - MCS_INT_VEC_MIL_TX_LMACX = 0x5, - MCS_INT_VEC_HIL_RX_GBL = 0x9, - MCS_INT_VEC_HIL_RX_LMACX = 0xa, - MCS_INT_VEC_HIL_TX_GBL = 0xe, - MCS_INT_VEC_HIL_TX_LMACX = 0xf, - MCS_INT_VEC_IP = 0x13, - MCS_INT_VEC_CNT = 0x14, -}; +/* MCS Interrupt Vector */ +#define MCS_CNF10KB_INT_VEC_IP 0x13 +#define MCS_CN10KB_INT_VEC_IP 0x53 #define MCS_MAX_BBE_INT 8ULL #define MCS_BBE_INT_MASK 0xFFULL -#define MCS_MAX_PAB_INT 4ULL -#define MCS_PAB_INT_MASK 0xFULL +#define MCS_MAX_PAB_INT 8ULL +#define MCS_PAB_INT_MASK 0xFULL #define MCS_BBE_RX_INT_ENA BIT_ULL(0) #define MCS_BBE_TX_INT_ENA BIT_ULL(1) @@ -137,6 +128,7 @@ struct hwinfo { u8 lmac_cnt; u8 mcs_blks; unsigned long lmac_bmap; /* bitmap of enabled mcs lmac */ + u16 ip_vec; }; struct mcs { @@ -165,6 +157,8 @@ struct mcs_ops { void (*mcs_tx_sa_mem_map_write)(struct mcs *mcs, struct mcs_tx_sc_sa_map *map); void (*mcs_rx_sa_mem_map_write)(struct mcs *mcs, struct mcs_rx_sc_sa_map *map); void (*mcs_flowid_secy_map)(struct mcs *mcs, struct secy_mem_map *map, int dir); + void (*mcs_bbe_intr_handler)(struct mcs *mcs, u64 intr, enum mcs_direction dir); + void (*mcs_pab_intr_handler)(struct mcs *mcs, u64 intr, enum mcs_direction dir); }; extern struct pci_driver mcs_driver; @@ -219,6 +213,8 @@ void cn10kb_mcs_tx_sa_mem_map_write(struct mcs *mcs, struct mcs_tx_sc_sa_map *ma void cn10kb_mcs_flowid_secy_map(struct mcs *mcs, struct secy_mem_map *map, int dir); void cn10kb_mcs_rx_sa_mem_map_write(struct mcs *mcs, struct mcs_rx_sc_sa_map *map); void cn10kb_mcs_parser_cfg(struct mcs *mcs); +void cn10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir); +void cn10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir); /* CNF10K-B APIs */ struct mcs_ops *cnf10kb_get_mac_ops(void); @@ -229,6 +225,8 @@ void cnf10kb_mcs_rx_sa_mem_map_write(struct mcs *mcs, struct mcs_rx_sc_sa_map *m void cnf10kb_mcs_parser_cfg(struct mcs *mcs); void cnf10kb_mcs_tx_pn_thresh_reached_handler(struct mcs *mcs); void cnf10kb_mcs_tx_pn_wrapped_handler(struct mcs *mcs); +void cnf10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir); +void cnf10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr, enum mcs_direction dir); /* Stats APIs */ void mcs_get_sc_stats(struct mcs *mcs, struct mcs_sc_stats *stats, int id, int dir); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs_cnf10kb.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs_cnf10kb.c index 7b6205414428..9f9b904ab2cd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs_cnf10kb.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs_cnf10kb.c @@ -13,6 +13,8 @@ static struct mcs_ops cnf10kb_mcs_ops = { .mcs_tx_sa_mem_map_write = cnf10kb_mcs_tx_sa_mem_map_write, .mcs_rx_sa_mem_map_write = cnf10kb_mcs_rx_sa_mem_map_write, .mcs_flowid_secy_map = cnf10kb_mcs_flowid_secy_map, + .mcs_bbe_intr_handler = cnf10kb_mcs_bbe_intr_handler, + .mcs_pab_intr_handler = cnf10kb_mcs_pab_intr_handler, }; struct mcs_ops *cnf10kb_get_mac_ops(void) @@ -31,6 +33,7 @@ void cnf10kb_mcs_set_hw_capabilities(struct mcs *mcs) hw->lmac_cnt = 4; /* lmacs/ports per mcs block */ hw->mcs_x2p_intf = 1; /* x2p clabration intf */ hw->mcs_blks = 7; /* MCS blocks */ + hw->ip_vec = MCS_CNF10KB_INT_VEC_IP; /* IP vector */ } void cnf10kb_mcs_parser_cfg(struct mcs *mcs) @@ -212,3 +215,63 @@ void cnf10kb_mcs_tx_pn_wrapped_handler(struct mcs *mcs) mcs_add_intr_wq_entry(mcs, &event); } } + +void cnf10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr, + enum mcs_direction dir) +{ + struct mcs_intr_event event = { 0 }; + int i; + + if (!(intr & MCS_BBE_INT_MASK)) + return; + + event.mcs_id = mcs->mcs_id; + event.pcifunc = mcs->pf_map[0]; + + for (i = 0; i < MCS_MAX_BBE_INT; i++) { + if (!(intr & BIT_ULL(i))) + continue; + + /* Lower nibble denotes data fifo overflow interrupts and + * upper nibble indicates policy fifo overflow interrupts. + */ + if (intr & 0xFULL) + event.intr_mask = (dir == MCS_RX) ? + MCS_BBE_RX_DFIFO_OVERFLOW_INT : + MCS_BBE_TX_DFIFO_OVERFLOW_INT; + else + event.intr_mask = (dir == MCS_RX) ? + MCS_BBE_RX_PLFIFO_OVERFLOW_INT : + MCS_BBE_TX_PLFIFO_OVERFLOW_INT; + + /* Notify the lmac_id info which ran into BBE fatal error */ + event.lmac_id = i & 0x3ULL; + mcs_add_intr_wq_entry(mcs, &event); + } +} + +void cnf10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr, + enum mcs_direction dir) +{ + struct mcs_intr_event event = { 0 }; + int i; + + if (!(intr & MCS_PAB_INT_MASK)) + return; + + event.mcs_id = mcs->mcs_id; + event.pcifunc = mcs->pf_map[0]; + + for (i = 0; i < MCS_MAX_PAB_INT; i++) { + if (!(intr & BIT_ULL(i))) + continue; + + event.intr_mask = (dir == MCS_RX) ? + MCS_PAB_RX_CHAN_OVERFLOW_INT : + MCS_PAB_TX_CHAN_OVERFLOW_INT; + + /* Notify the lmac_id info which ran into PAB fatal error */ + event.lmac_id = i; + mcs_add_intr_wq_entry(mcs, &event); + } +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/mcs_reg.h index c95a8b8f5eaf..f3ab01fc363c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs_reg.h @@ -97,6 +97,7 @@ #define MCSX_PEX_TX_SLAVE_VLAN_CFGX(a) (0x46f8ull + (a) * 0x8ull) #define MCSX_PEX_TX_SLAVE_CUSTOM_TAG_REL_MODE_SEL(a) (0x788ull + (a) * 0x8ull) #define MCSX_PEX_TX_SLAVE_PORT_CONFIG(a) (0x4738ull + (a) * 0x8ull) +#define MCSX_PEX_RX_SLAVE_PORT_CFGX(a) (0x3b98ull + (a) * 0x8ull) #define MCSX_PEX_RX_SLAVE_RULE_ETYPE_CFGX(a) ({ \ u64 offset; \ \ @@ -275,7 +276,10 @@ #define MCSX_BBE_RX_SLAVE_CAL_ENTRY 0x180ull #define MCSX_BBE_RX_SLAVE_CAL_LEN 0x188ull #define MCSX_PAB_RX_SLAVE_FIFO_SKID_CFGX(a) (0x290ull + (a) * 0x40ull) - +#define MCSX_BBE_RX_SLAVE_DFIFO_OVERFLOW_0 0xe20 +#define MCSX_BBE_TX_SLAVE_DFIFO_OVERFLOW_0 0x1298 +#define MCSX_BBE_RX_SLAVE_PLFIFO_OVERFLOW_0 0xe40 +#define MCSX_BBE_TX_SLAVE_PLFIFO_OVERFLOW_0 0x12b8 #define MCSX_BBE_RX_SLAVE_BBE_INT ({ \ u64 offset; \ \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c index eb25e458266c..dfd23580e3b8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c @@ -11,6 +11,7 @@ #include "mcs.h" #include "rvu.h" +#include "mcs_reg.h" #include "lmac_common.h" #define M(_name, _id, _fn_name, _req_type, _rsp_type) \ @@ -32,6 +33,42 @@ static struct _req_type __maybe_unused \ MBOX_UP_MCS_MESSAGES #undef M +void rvu_mcs_ptp_cfg(struct rvu *rvu, u8 rpm_id, u8 lmac_id, bool ena) +{ + struct mcs *mcs; + u64 cfg; + u8 port; + + if (!rvu->mcs_blk_cnt) + return; + + /* When ptp is enabled, RPM appends 8B header for all + * RX packets. MCS PEX need to configure to skip 8B + * during packet parsing. + */ + + /* CNF10K-B */ + if (rvu->mcs_blk_cnt > 1) { + mcs = mcs_get_pdata(rpm_id); + cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION); + if (ena) + cfg |= BIT_ULL(lmac_id); + else + cfg &= ~BIT_ULL(lmac_id); + mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION, cfg); + return; + } + /* CN10KB */ + mcs = mcs_get_pdata(0); + port = (rpm_id * rvu->hw->lmac_per_cgx) + lmac_id; + cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port)); + if (ena) + cfg |= BIT_ULL(0); + else + cfg &= ~BIT_ULL(0); + mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port), cfg); +} + int rvu_mbox_handler_mcs_set_lmac_mode(struct rvu *rvu, struct mcs_set_lmac_mode *req, struct msg_rsp *rsp) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 8683ce57ed3f..9f673bda9dbd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -2282,7 +2282,7 @@ static inline void rvu_afvf_mbox_up_handler(struct work_struct *work) } static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr, - int num, int type) + int num, int type, unsigned long *pf_bmap) { struct rvu_hwinfo *hw = rvu->hw; int region; @@ -2294,6 +2294,9 @@ static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr, */ if (type == TYPE_AFVF) { for (region = 0; region < num; region++) { + if (!test_bit(region, pf_bmap)) + continue; + if (hw->cap.per_pf_mbox_regs) { bar4 = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFX_BAR4_ADDR(0)) + @@ -2315,6 +2318,9 @@ static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr, * RVU_AF_PF_BAR4_ADDR register. */ for (region = 0; region < num; region++) { + if (!test_bit(region, pf_bmap)) + continue; + if (hw->cap.per_pf_mbox_regs) { bar4 = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFX_BAR4_ADDR(region)); @@ -2343,12 +2349,33 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, int err = -EINVAL, i, dir, dir_up; void __iomem *reg_base; struct rvu_work *mwork; + unsigned long *pf_bmap; void **mbox_regions; const char *name; + u64 cfg; + + pf_bmap = bitmap_zalloc(num, GFP_KERNEL); + if (!pf_bmap) + return -ENOMEM; + + /* RVU VFs */ + if (type == TYPE_AFVF) + bitmap_set(pf_bmap, 0, num); + + if (type == TYPE_AFPF) { + /* Mark enabled PFs in bitmap */ + for (i = 0; i < num; i++) { + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(i)); + if (cfg & BIT_ULL(20)) + set_bit(i, pf_bmap); + } + } mbox_regions = kcalloc(num, sizeof(void *), GFP_KERNEL); - if (!mbox_regions) - return -ENOMEM; + if (!mbox_regions) { + err = -ENOMEM; + goto free_bitmap; + } switch (type) { case TYPE_AFPF: @@ -2356,7 +2383,7 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, dir = MBOX_DIR_AFPF; dir_up = MBOX_DIR_AFPF_UP; reg_base = rvu->afreg_base; - err = rvu_get_mbox_regions(rvu, mbox_regions, num, TYPE_AFPF); + err = rvu_get_mbox_regions(rvu, mbox_regions, num, TYPE_AFPF, pf_bmap); if (err) goto free_regions; break; @@ -2365,7 +2392,7 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, dir = MBOX_DIR_PFVF; dir_up = MBOX_DIR_PFVF_UP; reg_base = rvu->pfreg_base; - err = rvu_get_mbox_regions(rvu, mbox_regions, num, TYPE_AFVF); + err = rvu_get_mbox_regions(rvu, mbox_regions, num, TYPE_AFVF, pf_bmap); if (err) goto free_regions; break; @@ -2396,16 +2423,19 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, } err = otx2_mbox_regions_init(&mw->mbox, mbox_regions, rvu->pdev, - reg_base, dir, num); + reg_base, dir, num, pf_bmap); if (err) goto exit; err = otx2_mbox_regions_init(&mw->mbox_up, mbox_regions, rvu->pdev, - reg_base, dir_up, num); + reg_base, dir_up, num, pf_bmap); if (err) goto exit; for (i = 0; i < num; i++) { + if (!test_bit(i, pf_bmap)) + continue; + mwork = &mw->mbox_wrk[i]; mwork->rvu = rvu; INIT_WORK(&mwork->work, mbox_handler); @@ -2414,8 +2444,7 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, mwork->rvu = rvu; INIT_WORK(&mwork->work, mbox_up_handler); } - kfree(mbox_regions); - return 0; + goto free_regions; exit: destroy_workqueue(mw->mbox_wq); @@ -2424,6 +2453,8 @@ unmap_regions: iounmap((void __iomem *)mbox_regions[num]); free_regions: kfree(mbox_regions); +free_bitmap: + bitmap_free(pf_bmap); return err; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index ef721caeac49..d655bf04a483 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -920,6 +920,7 @@ int rvu_get_hwvf(struct rvu *rvu, int pcifunc); /* CN10K MCS */ int rvu_mcs_init(struct rvu *rvu); int rvu_mcs_flr_handler(struct rvu *rvu, u16 pcifunc); +void rvu_mcs_ptp_cfg(struct rvu *rvu, u8 rpm_id, u8 lmac_id, bool ena); void rvu_mcs_exit(struct rvu *rvu); #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 438b212fb54a..83b342fa8d75 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -773,6 +773,8 @@ static int rvu_cgx_ptp_rx_cfg(struct rvu *rvu, u16 pcifunc, bool enable) /* This flag is required to clean up CGX conf if app gets killed */ pfvf->hw_rx_tstamp_en = enable; + /* Inform MCS about 8B RX header */ + rvu_mcs_ptp_cfg(rvu, cgx_id, lmac_id, enable); return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c index 4ad9ff025c96..0e74c5a2231e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c @@ -60,13 +60,14 @@ static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, u64 iova, u64 *lmt_addr) { u64 pa, val, pf; - int err; + int err = 0; if (!iova) { dev_err(rvu->dev, "%s Requested Null address for transulation\n", __func__); return -EINVAL; } + mutex_lock(&rvu->rsrc_lock); rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova); pf = rvu_get_pf(pcifunc) & 0x1F; val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 | @@ -76,12 +77,13 @@ static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, err = rvu_poll_reg(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS, BIT_ULL(0), false); if (err) { dev_err(rvu->dev, "%s LMTLINE iova transulation failed\n", __func__); - return err; + goto exit; } val = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS); if (val & ~0x1ULL) { dev_err(rvu->dev, "%s LMTLINE iova transulation failed err:%llx\n", __func__, val); - return -EIO; + err = -EIO; + goto exit; } /* PA[51:12] = RVU_AF_SMMU_TLN_FLIT0[57:18] * PA[11:0] = IOVA[11:0] @@ -89,8 +91,9 @@ static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc, pa = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TLN_FLIT0) >> 18; pa &= GENMASK_ULL(39, 0); *lmt_addr = (pa << 12) | (iova & 0xFFF); - - return 0; +exit: + mutex_unlock(&rvu->rsrc_lock); + return err; } static int rvu_update_lmtaddr(struct rvu *rvu, u16 pcifunc, u64 lmt_addr) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 26cfa501f1a1..9533b1d92960 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -497,8 +497,9 @@ static int rvu_dbg_mcs_rx_secy_stats_display(struct seq_file *filp, void *unused stats.octet_validated_cnt); seq_printf(filp, "secy%d: Pkts on disable port: %lld\n", secy_id, stats.pkt_port_disabled_cnt); - seq_printf(filp, "secy%d: Octets validated: %lld\n", secy_id, stats.pkt_badtag_cnt); - seq_printf(filp, "secy%d: Octets validated: %lld\n", secy_id, stats.pkt_nosa_cnt); + seq_printf(filp, "secy%d: Pkts with badtag: %lld\n", secy_id, stats.pkt_badtag_cnt); + seq_printf(filp, "secy%d: Pkts with no SA(sectag.tci.c=0): %lld\n", secy_id, + stats.pkt_nosa_cnt); seq_printf(filp, "secy%d: Pkts with nosaerror: %lld\n", secy_id, stats.pkt_nosaerror_cnt); seq_printf(filp, "secy%d: Tagged ctrl pkts: %lld\n", secy_id, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 006beb5cf98d..952319453701 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -13,11 +13,6 @@ #include "rvu_npc_fs.h" #include "rvu_npc_hash.h" -#define NPC_BYTESM GENMASK_ULL(19, 16) -#define NPC_HDR_OFFSET GENMASK_ULL(15, 8) -#define NPC_KEY_OFFSET GENMASK_ULL(5, 0) -#define NPC_LDATA_EN BIT_ULL(7) - static const char * const npc_flow_names[] = { [NPC_DMAC] = "dmac", [NPC_SMAC] = "smac", @@ -442,6 +437,7 @@ done: static void npc_scan_ldata(struct rvu *rvu, int blkaddr, u8 lid, u8 lt, u64 cfg, u8 intf) { + struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash; struct npc_mcam *mcam = &rvu->hw->mcam; u8 hdr, key, nr_bytes, bit_offset; u8 la_ltype, la_start; @@ -490,8 +486,21 @@ do { \ NPC_SCAN_HDR(NPC_SIP_IPV4, NPC_LID_LC, NPC_LT_LC_IP, 12, 4); NPC_SCAN_HDR(NPC_DIP_IPV4, NPC_LID_LC, NPC_LT_LC_IP, 16, 4); NPC_SCAN_HDR(NPC_IPFRAG_IPV6, NPC_LID_LC, NPC_LT_LC_IP6_EXT, 6, 1); - NPC_SCAN_HDR(NPC_SIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 8, 16); - NPC_SCAN_HDR(NPC_DIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 24, 16); + if (rvu->hw->cap.npc_hash_extract) { + if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][0]) + NPC_SCAN_HDR(NPC_SIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 8, 4); + else + NPC_SCAN_HDR(NPC_SIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 8, 16); + + if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][1]) + NPC_SCAN_HDR(NPC_DIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 24, 4); + else + NPC_SCAN_HDR(NPC_DIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 24, 16); + } else { + NPC_SCAN_HDR(NPC_SIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 8, 16); + NPC_SCAN_HDR(NPC_DIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 24, 16); + } + NPC_SCAN_HDR(NPC_SPORT_UDP, NPC_LID_LD, NPC_LT_LD_UDP, 0, 2); NPC_SCAN_HDR(NPC_DPORT_UDP, NPC_LID_LD, NPC_LT_LD_UDP, 2, 2); NPC_SCAN_HDR(NPC_SPORT_TCP, NPC_LID_LD, NPC_LT_LD_TCP, 0, 2); @@ -594,8 +603,7 @@ static int npc_scan_kex(struct rvu *rvu, int blkaddr, u8 intf) */ masked_cfg = cfg & NPC_EXACT_NIBBLE; bitnr = NPC_EXACT_NIBBLE_START; - for_each_set_bit_from(bitnr, (unsigned long *)&masked_cfg, - NPC_EXACT_NIBBLE_START) { + for_each_set_bit_from(bitnr, (unsigned long *)&masked_cfg, NPC_EXACT_NIBBLE_END + 1) { npc_scan_exact_result(mcam, bitnr, key_nibble, intf); key_nibble++; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h index bdd65ce56a32..3f5c9042d10e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.h @@ -9,6 +9,10 @@ #define __RVU_NPC_FS_H #define IPV6_WORDS 4 +#define NPC_BYTESM GENMASK_ULL(19, 16) +#define NPC_HDR_OFFSET GENMASK_ULL(15, 8) +#define NPC_KEY_OFFSET GENMASK_ULL(5, 0) +#define NPC_LDATA_EN BIT_ULL(7) void npc_update_entry(struct rvu *rvu, enum key_fields type, struct mcam_entry *entry, u64 val_lo, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c index 20ebb9c95c73..51209119f0f2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c @@ -78,42 +78,43 @@ static u32 rvu_npc_toeplitz_hash(const u64 *data, u64 *key, size_t data_bit_len, return hash_out; } -u32 npc_field_hash_calc(u64 *ldata, struct npc_mcam_kex_hash *mkex_hash, - u64 *secret_key, u8 intf, u8 hash_idx) +u32 npc_field_hash_calc(u64 *ldata, struct npc_get_field_hash_info_rsp rsp, + u8 intf, u8 hash_idx) { u64 hash_key[3]; u64 data_padded[2]; u32 field_hash; - hash_key[0] = secret_key[1] << 31; - hash_key[0] |= secret_key[2]; - hash_key[1] = secret_key[1] >> 33; - hash_key[1] |= secret_key[0] << 31; - hash_key[2] = secret_key[0] >> 33; + hash_key[0] = rsp.secret_key[1] << 31; + hash_key[0] |= rsp.secret_key[2]; + hash_key[1] = rsp.secret_key[1] >> 33; + hash_key[1] |= rsp.secret_key[0] << 31; + hash_key[2] = rsp.secret_key[0] >> 33; - data_padded[0] = mkex_hash->hash_mask[intf][hash_idx][0] & ldata[0]; - data_padded[1] = mkex_hash->hash_mask[intf][hash_idx][1] & ldata[1]; + data_padded[0] = rsp.hash_mask[intf][hash_idx][0] & ldata[0]; + data_padded[1] = rsp.hash_mask[intf][hash_idx][1] & ldata[1]; field_hash = rvu_npc_toeplitz_hash(data_padded, hash_key, 128, 159); - field_hash &= mkex_hash->hash_ctrl[intf][hash_idx] >> 32; - field_hash |= mkex_hash->hash_ctrl[intf][hash_idx]; + field_hash &= FIELD_GET(GENMASK(63, 32), rsp.hash_ctrl[intf][hash_idx]); + field_hash += FIELD_GET(GENMASK(31, 0), rsp.hash_ctrl[intf][hash_idx]); return field_hash; } -static u64 npc_update_use_hash(int lt, int ld) +static u64 npc_update_use_hash(struct rvu *rvu, int blkaddr, + u8 intf, int lid, int lt, int ld) { - u64 cfg = 0; + u8 hdr, key; + u64 cfg; - switch (lt) { - case NPC_LT_LC_IP6: - /* Update use_hash(bit-20) and bytesm1 (bit-16:19) - * in KEX_LD_CFG - */ - cfg = KEX_LD_CFG_USE_HASH(0x1, 0x03, - ld ? 0x8 : 0x18, - 0x1, 0x0, 0x10); - break; - } + cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_LIDX_LTX_LDX_CFG(intf, lid, lt, ld)); + hdr = FIELD_GET(NPC_HDR_OFFSET, cfg); + key = FIELD_GET(NPC_KEY_OFFSET, cfg); + + /* Update use_hash(bit-20) to 'true' and + * bytesm1(bit-16:19) to '0x3' in KEX_LD_CFG + */ + cfg = KEX_LD_CFG_USE_HASH(0x1, 0x03, + hdr, 0x1, 0x0, key); return cfg; } @@ -132,12 +133,13 @@ static void npc_program_mkex_hash_rx(struct rvu *rvu, int blkaddr, for (lt = 0; lt < NPC_MAX_LT; lt++) { for (ld = 0; ld < NPC_MAX_LD; ld++) { if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][ld]) { - u64 cfg = npc_update_use_hash(lt, ld); + u64 cfg; - hash_cnt++; if (hash_cnt == NPC_MAX_HASH) return; + cfg = npc_update_use_hash(rvu, blkaddr, + intf, lid, lt, ld); /* Set updated KEX configuration */ SET_KEX_LD(intf, lid, lt, ld, cfg); /* Set HASH configuration */ @@ -149,6 +151,8 @@ static void npc_program_mkex_hash_rx(struct rvu *rvu, int blkaddr, mkex_hash->hash_mask[intf][ld][1]); SET_KEX_LD_HASH_CTRL(intf, ld, mkex_hash->hash_ctrl[intf][ld]); + + hash_cnt++; } } } @@ -169,12 +173,13 @@ static void npc_program_mkex_hash_tx(struct rvu *rvu, int blkaddr, for (lt = 0; lt < NPC_MAX_LT; lt++) { for (ld = 0; ld < NPC_MAX_LD; ld++) if (mkex_hash->lid_lt_ld_hash_en[intf][lid][lt][ld]) { - u64 cfg = npc_update_use_hash(lt, ld); + u64 cfg; - hash_cnt++; if (hash_cnt == NPC_MAX_HASH) return; + cfg = npc_update_use_hash(rvu, blkaddr, + intf, lid, lt, ld); /* Set updated KEX configuration */ SET_KEX_LD(intf, lid, lt, ld, cfg); /* Set HASH configuration */ @@ -187,8 +192,6 @@ static void npc_program_mkex_hash_tx(struct rvu *rvu, int blkaddr, SET_KEX_LD_HASH_CTRL(intf, ld, mkex_hash->hash_ctrl[intf][ld]); hash_cnt++; - if (hash_cnt == NPC_MAX_HASH) - return; } } } @@ -238,8 +241,8 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, struct flow_msg *omask) { struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash; - struct npc_get_secret_key_req req; - struct npc_get_secret_key_rsp rsp; + struct npc_get_field_hash_info_req req; + struct npc_get_field_hash_info_rsp rsp; u64 ldata[2], cfg; u32 field_hash; u8 hash_idx; @@ -250,7 +253,7 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, } req.intf = intf; - rvu_mbox_handler_npc_get_secret_key(rvu, &req, &rsp); + rvu_mbox_handler_npc_get_field_hash_info(rvu, &req, &rsp); for (hash_idx = 0; hash_idx < NPC_MAX_HASH; hash_idx++) { cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_HASHX_CFG(intf, hash_idx)); @@ -266,44 +269,45 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, * is hashed to 32 bit value. */ case NPC_LT_LC_IP6: - if (features & BIT_ULL(NPC_SIP_IPV6)) { + /* ld[0] == hash_idx[0] == Source IPv6 + * ld[1] == hash_idx[1] == Destination IPv6 + */ + if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) { u32 src_ip[IPV6_WORDS]; be32_to_cpu_array(src_ip, pkt->ip6src, IPV6_WORDS); - ldata[0] = (u64)src_ip[0] << 32 | src_ip[1]; - ldata[1] = (u64)src_ip[2] << 32 | src_ip[3]; + ldata[1] = (u64)src_ip[0] << 32 | src_ip[1]; + ldata[0] = (u64)src_ip[2] << 32 | src_ip[3]; field_hash = npc_field_hash_calc(ldata, - mkex_hash, - rsp.secret_key, + rsp, intf, hash_idx); npc_update_entry(rvu, NPC_SIP_IPV6, entry, - field_hash, 0, 32, 0, intf); + field_hash, 0, + GENMASK(31, 0), 0, intf); memcpy(&opkt->ip6src, &pkt->ip6src, sizeof(pkt->ip6src)); memcpy(&omask->ip6src, &mask->ip6src, sizeof(mask->ip6src)); - break; - } - - if (features & BIT_ULL(NPC_DIP_IPV6)) { + } else if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) { u32 dst_ip[IPV6_WORDS]; be32_to_cpu_array(dst_ip, pkt->ip6dst, IPV6_WORDS); - ldata[0] = (u64)dst_ip[0] << 32 | dst_ip[1]; - ldata[1] = (u64)dst_ip[2] << 32 | dst_ip[3]; + ldata[1] = (u64)dst_ip[0] << 32 | dst_ip[1]; + ldata[0] = (u64)dst_ip[2] << 32 | dst_ip[3]; field_hash = npc_field_hash_calc(ldata, - mkex_hash, - rsp.secret_key, + rsp, intf, hash_idx); npc_update_entry(rvu, NPC_DIP_IPV6, entry, - field_hash, 0, 32, 0, intf); + field_hash, 0, + GENMASK(31, 0), 0, intf); memcpy(&opkt->ip6dst, &pkt->ip6dst, sizeof(pkt->ip6dst)); memcpy(&omask->ip6dst, &mask->ip6dst, sizeof(mask->ip6dst)); } + break; } } @@ -311,13 +315,13 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, } } -int rvu_mbox_handler_npc_get_secret_key(struct rvu *rvu, - struct npc_get_secret_key_req *req, - struct npc_get_secret_key_rsp *rsp) +int rvu_mbox_handler_npc_get_field_hash_info(struct rvu *rvu, + struct npc_get_field_hash_info_req *req, + struct npc_get_field_hash_info_rsp *rsp) { u64 *secret_key = rsp->secret_key; u8 intf = req->intf; - int blkaddr; + int i, j, blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) { @@ -329,6 +333,19 @@ int rvu_mbox_handler_npc_get_secret_key(struct rvu *rvu, secret_key[1] = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_SECRET_KEY1(intf)); secret_key[2] = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_SECRET_KEY2(intf)); + for (i = 0; i < NPC_MAX_HASH; i++) { + for (j = 0; j < NPC_MAX_HASH_MASK; j++) { + rsp->hash_mask[NIX_INTF_RX][i][j] = + GET_KEX_LD_HASH_MASK(NIX_INTF_RX, i, j); + rsp->hash_mask[NIX_INTF_TX][i][j] = + GET_KEX_LD_HASH_MASK(NIX_INTF_TX, i, j); + } + } + + for (i = 0; i < NPC_MAX_INTF; i++) + for (j = 0; j < NPC_MAX_HASH; j++) + rsp->hash_ctrl[i][j] = GET_KEX_LD_HASH_CTRL(i, j); + return 0; } @@ -1868,9 +1885,9 @@ int rvu_npc_exact_init(struct rvu *rvu) rvu->hw->table = table; /* Read table size, ways and depth */ - table->mem_table.depth = FIELD_GET(GENMASK_ULL(31, 24), npc_const3); table->mem_table.ways = FIELD_GET(GENMASK_ULL(19, 16), npc_const3); - table->cam_table.depth = FIELD_GET(GENMASK_ULL(15, 0), npc_const3); + table->mem_table.depth = FIELD_GET(GENMASK_ULL(15, 0), npc_const3); + table->cam_table.depth = FIELD_GET(GENMASK_ULL(31, 24), npc_const3); dev_dbg(rvu->dev, "%s: NPC exact match 4way_2k table(ways=%d, depth=%d)\n", __func__, table->mem_table.ways, table->cam_table.depth); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h index 3efeb09c58de..a1c3d987b804 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.h @@ -31,6 +31,12 @@ rvu_write64(rvu, blkaddr, \ NPC_AF_INTFX_HASHX_MASKX(intf, ld, mask_idx), cfg) +#define GET_KEX_LD_HASH_CTRL(intf, ld) \ + rvu_read64(rvu, blkaddr, NPC_AF_INTFX_HASHX_RESULT_CTRL(intf, ld)) + +#define GET_KEX_LD_HASH_MASK(intf, ld, mask_idx) \ + rvu_read64(rvu, blkaddr, NPC_AF_INTFX_HASHX_MASKX(intf, ld, mask_idx)) + #define SET_KEX_LD_HASH_CTRL(intf, ld, cfg) \ rvu_write64(rvu, blkaddr, \ NPC_AF_INTFX_HASHX_RESULT_CTRL(intf, ld), cfg) @@ -56,8 +62,8 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf, struct flow_msg *omask); void npc_config_secret_key(struct rvu *rvu, int blkaddr); void npc_program_mkex_hash(struct rvu *rvu, int blkaddr); -u32 npc_field_hash_calc(u64 *ldata, struct npc_mcam_kex_hash *mkex_hash, - u64 *secret_key, u8 intf, u8 hash_idx); +u32 npc_field_hash_calc(u64 *ldata, struct npc_get_field_hash_info_rsp rsp, + u8 intf, u8 hash_idx); static struct npc_mcam_kex_hash npc_mkex_hash_default __maybe_unused = { .lid_lt_ld_hash_en = { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index 9ec5f38d38a8..a487a98eac88 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -9,6 +9,7 @@ #include #include "otx2_common.h" +#define MCS_TCAM0_MAC_DA_MASK GENMASK_ULL(47, 0) #define MCS_TCAM0_MAC_SA_MASK GENMASK_ULL(63, 48) #define MCS_TCAM1_MAC_SA_MASK GENMASK_ULL(31, 0) #define MCS_TCAM1_ETYPE_MASK GENMASK_ULL(47, 32) @@ -149,11 +150,20 @@ static void cn10k_mcs_free_rsrc(struct otx2_nic *pfvf, enum mcs_direction dir, enum mcs_rsrc_type type, u16 hw_rsrc_id, bool all) { + struct mcs_clear_stats *clear_req; struct mbox *mbox = &pfvf->mbox; struct mcs_free_rsrc_req *req; mutex_lock(&mbox->lock); + clear_req = otx2_mbox_alloc_msg_mcs_clear_stats(mbox); + if (!clear_req) + goto fail; + + clear_req->id = hw_rsrc_id; + clear_req->type = type; + clear_req->dir = dir; + req = otx2_mbox_alloc_msg_mcs_free_resources(mbox); if (!req) goto fail; @@ -237,8 +247,10 @@ static int cn10k_mcs_write_rx_flowid(struct otx2_nic *pfvf, struct cn10k_mcs_rxsc *rxsc, u8 hw_secy_id) { struct macsec_rx_sc *sw_rx_sc = rxsc->sw_rxsc; + struct macsec_secy *secy = rxsc->sw_secy; struct mcs_flowid_entry_write_req *req; struct mbox *mbox = &pfvf->mbox; + u64 mac_da; int ret; mutex_lock(&mbox->lock); @@ -249,11 +261,16 @@ static int cn10k_mcs_write_rx_flowid(struct otx2_nic *pfvf, goto fail; } + mac_da = ether_addr_to_u64(secy->netdev->dev_addr); + + req->data[0] = FIELD_PREP(MCS_TCAM0_MAC_DA_MASK, mac_da); + req->mask[0] = ~0ULL; + req->mask[0] = ~MCS_TCAM0_MAC_DA_MASK; + req->data[1] = FIELD_PREP(MCS_TCAM1_ETYPE_MASK, ETH_P_MACSEC); req->mask[1] = ~0ULL; req->mask[1] &= ~MCS_TCAM1_ETYPE_MASK; - req->mask[0] = ~0ULL; req->mask[2] = ~0ULL; req->mask[3] = ~0ULL; @@ -997,7 +1014,7 @@ static void cn10k_mcs_sync_stats(struct otx2_nic *pfvf, struct macsec_secy *secy /* Check if sync is really needed */ if (secy->validate_frames == txsc->last_validate_frames && - secy->protect_frames == txsc->last_protect_frames) + secy->replay_protect == txsc->last_replay_protect) return; cn10k_mcs_secy_stats(pfvf, txsc->hw_secy_id_rx, &rx_rsp, MCS_RX, true); @@ -1019,19 +1036,19 @@ static void cn10k_mcs_sync_stats(struct otx2_nic *pfvf, struct macsec_secy *secy rxsc->stats.InPktsInvalid += sc_rsp.pkt_invalid_cnt; rxsc->stats.InPktsNotValid += sc_rsp.pkt_notvalid_cnt; - if (txsc->last_protect_frames) + if (txsc->last_replay_protect) rxsc->stats.InPktsLate += sc_rsp.pkt_late_cnt; else rxsc->stats.InPktsDelayed += sc_rsp.pkt_late_cnt; - if (txsc->last_validate_frames == MACSEC_VALIDATE_CHECK) + if (txsc->last_validate_frames == MACSEC_VALIDATE_DISABLED) rxsc->stats.InPktsUnchecked += sc_rsp.pkt_unchecked_cnt; else rxsc->stats.InPktsOK += sc_rsp.pkt_unchecked_cnt; } txsc->last_validate_frames = secy->validate_frames; - txsc->last_protect_frames = secy->protect_frames; + txsc->last_replay_protect = secy->replay_protect; } static int cn10k_mdo_open(struct macsec_context *ctx) @@ -1100,7 +1117,7 @@ static int cn10k_mdo_add_secy(struct macsec_context *ctx) txsc->sw_secy = secy; txsc->encoding_sa = secy->tx_sc.encoding_sa; txsc->last_validate_frames = secy->validate_frames; - txsc->last_protect_frames = secy->protect_frames; + txsc->last_replay_protect = secy->replay_protect; list_add(&txsc->entry, &cfg->txsc_list); @@ -1117,6 +1134,7 @@ static int cn10k_mdo_upd_secy(struct macsec_context *ctx) struct macsec_secy *secy = ctx->secy; struct macsec_tx_sa *sw_tx_sa; struct cn10k_mcs_txsc *txsc; + bool active; u8 sa_num; int err; @@ -1124,15 +1142,19 @@ static int cn10k_mdo_upd_secy(struct macsec_context *ctx) if (!txsc) return -ENOENT; - txsc->encoding_sa = secy->tx_sc.encoding_sa; - - sa_num = txsc->encoding_sa; - sw_tx_sa = rcu_dereference_bh(secy->tx_sc.sa[sa_num]); + /* Encoding SA got changed */ + if (txsc->encoding_sa != secy->tx_sc.encoding_sa) { + txsc->encoding_sa = secy->tx_sc.encoding_sa; + sa_num = txsc->encoding_sa; + sw_tx_sa = rcu_dereference_bh(secy->tx_sc.sa[sa_num]); + active = sw_tx_sa ? sw_tx_sa->active : false; + cn10k_mcs_link_tx_sa2sc(pfvf, secy, txsc, sa_num, active); + } if (netif_running(secy->netdev)) { cn10k_mcs_sync_stats(pfvf, secy, txsc); - err = cn10k_mcs_secy_tx_cfg(pfvf, secy, txsc, sw_tx_sa, sa_num); + err = cn10k_mcs_secy_tx_cfg(pfvf, secy, txsc, NULL, 0); if (err) return err; } @@ -1521,12 +1543,12 @@ static int cn10k_mdo_get_rx_sc_stats(struct macsec_context *ctx) rxsc->stats.InPktsInvalid += rsp.pkt_invalid_cnt; rxsc->stats.InPktsNotValid += rsp.pkt_notvalid_cnt; - if (secy->protect_frames) + if (secy->replay_protect) rxsc->stats.InPktsLate += rsp.pkt_late_cnt; else rxsc->stats.InPktsDelayed += rsp.pkt_late_cnt; - if (secy->validate_frames == MACSEC_VALIDATE_CHECK) + if (secy->validate_frames == MACSEC_VALIDATE_DISABLED) rxsc->stats.InPktsUnchecked += rsp.pkt_unchecked_cnt; else rxsc->stats.InPktsOK += rsp.pkt_unchecked_cnt; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 3d22cc6a2804..0c8fc66ade82 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -335,11 +335,11 @@ struct otx2_flow_config { #define OTX2_PER_VF_VLAN_FLOWS 2 /* Rx + Tx per VF */ #define OTX2_VF_VLAN_RX_INDEX 0 #define OTX2_VF_VLAN_TX_INDEX 1 - u16 max_flows; - u8 dmacflt_max_flows; u32 *bmap_to_dmacindex; unsigned long *dmacflt_bmap; struct list_head flow_list; + u32 dmacflt_max_flows; + u16 max_flows; }; struct otx2_tc_info { @@ -389,7 +389,7 @@ struct cn10k_mcs_txsc { struct cn10k_txsc_stats stats; struct list_head entry; enum macsec_validation_type last_validate_frames; - bool last_protect_frames; + bool last_replay_protect; u16 hw_secy_id_tx; u16 hw_secy_id_rx; u16 hw_flow_id; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 179433d0a54a..18284ad75157 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1835,13 +1835,22 @@ int otx2_open(struct net_device *netdev) otx2_dmacflt_reinstall_flows(pf); err = otx2_rxtx_enable(pf, true); - if (err) + /* If a mbox communication error happens at this point then interface + * will end up in a state such that it is in down state but hardware + * mcam entries are enabled to receive the packets. Hence disable the + * packet I/O. + */ + if (err == EIO) + goto err_disable_rxtx; + else if (err) goto err_tx_stop_queues; otx2_do_set_rx_mode(pf); return 0; +err_disable_rxtx: + otx2_rxtx_enable(pf, false); err_tx_stop_queues: netif_tx_stop_all_queues(netdev); netif_carrier_off(netdev); @@ -3073,8 +3082,6 @@ static void otx2_remove(struct pci_dev *pdev) otx2_config_pause_frm(pf); } - cn10k_mcs_free(pf); - #ifdef CONFIG_DCB /* Disable PFC config */ if (pf->pfc_en) { @@ -3088,6 +3095,7 @@ static void otx2_remove(struct pci_dev *pdev) otx2_unregister_dl(pf); unregister_netdev(netdev); + cn10k_mcs_free(pf); otx2_sriov_disable(pf->pdev); otx2_sriov_vfcfg_cleanup(pf); if (pf->otx2_wq) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 044cc211424e..8392f63e433f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -544,7 +544,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node, if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) { if (ntohs(flow_spec->etype) == ETH_P_IP) { flow_spec->ip_flag = IPV4_FLAG_MORE; - flow_mask->ip_flag = 0xff; + flow_mask->ip_flag = IPV4_FLAG_MORE; req->features |= BIT_ULL(NPC_IPFRAG_IPV4); } else if (ntohs(flow_spec->etype) == ETH_P_IPV6) { flow_spec->next_header = IPPROTO_FRAGMENT; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index 7045fedfd73a..7af223b0a37f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -652,9 +652,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, htons(ext->lso_sb - skb_network_offset(skb)); } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { ext->lso_format = pfvf->hw.lso_tsov6_idx; - - ipv6_hdr(skb)->payload_len = - htons(ext->lso_sb - skb_network_offset(skb)); + ipv6_hdr(skb)->payload_len = htons(tcp_hdrlen(skb)); } else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { __be16 l3_proto = vlan_get_protocol(skb); struct udphdr *udph = udp_hdr(skb); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index ab126f8706c7..53366dbfbf27 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -621,7 +621,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = otx2vf_realloc_msix_vectors(vf); if (err) - goto err_mbox_destroy; + goto err_detach_rsrc; err = otx2_set_real_num_queues(netdev, qcount, qcount); if (err) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 9e948d091a69..834c644b67db 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1918,9 +1918,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, while (done < budget) { unsigned int pktlen, *rxdcsum; - bool has_hwaccel_tag = false; struct net_device *netdev; - u16 vlan_proto, vlan_tci; dma_addr_t dma_addr; u32 hash, reason; int mac = 0; @@ -2055,31 +2053,16 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { - if (trxd.rxd3 & RX_DMA_VTAG_V2) { - vlan_proto = RX_DMA_VPID(trxd.rxd4); - vlan_tci = RX_DMA_VID(trxd.rxd4); - has_hwaccel_tag = true; - } - } else if (trxd.rxd2 & RX_DMA_VTAG) { - vlan_proto = RX_DMA_VPID(trxd.rxd3); - vlan_tci = RX_DMA_VID(trxd.rxd3); - has_hwaccel_tag = true; - } - } - /* When using VLAN untagging in combination with DSA, the * hardware treats the MTK special tag as a VLAN and untags it. */ - if (has_hwaccel_tag && netdev_uses_dsa(netdev)) { - unsigned int port = vlan_proto & GENMASK(2, 0); + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && + (trxd.rxd2 & RX_DMA_VTAG) && netdev_uses_dsa(netdev)) { + unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0); if (port < ARRAY_SIZE(eth->dsa_meta) && eth->dsa_meta[port]) skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); - } else if (has_hwaccel_tag) { - __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci); } if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) @@ -2907,29 +2890,11 @@ static netdev_features_t mtk_fix_features(struct net_device *dev, static int mtk_set_features(struct net_device *dev, netdev_features_t features) { - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; netdev_features_t diff = dev->features ^ features; - int i; if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO)) mtk_hwlro_netdev_disable(dev); - /* Set RX VLAN offloading */ - if (!(diff & NETIF_F_HW_VLAN_CTAG_RX)) - return 0; - - mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX), - MTK_CDMP_EG_CTRL); - - /* sync features with other MAC */ - for (i = 0; i < MTK_MAC_COUNT; i++) { - if (!eth->netdev[i] || eth->netdev[i] == dev) - continue; - eth->netdev[i]->features &= ~NETIF_F_HW_VLAN_CTAG_RX; - eth->netdev[i]->features |= features & NETIF_F_HW_VLAN_CTAG_RX; - } - return 0; } @@ -3247,30 +3212,6 @@ static int mtk_open(struct net_device *dev) struct mtk_eth *eth = mac->hw; int i, err; - if (mtk_uses_dsa(dev) && !eth->prog) { - for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { - struct metadata_dst *md_dst = eth->dsa_meta[i]; - - if (md_dst) - continue; - - md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, - GFP_KERNEL); - if (!md_dst) - return -ENOMEM; - - md_dst->u.port_info.port_id = i; - eth->dsa_meta[i] = md_dst; - } - } else { - /* Hardware special tag parsing needs to be disabled if at least - * one MAC does not use DSA. - */ - u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); - val &= ~MTK_CDMP_STAG_EN; - mtk_w32(eth, val, MTK_CDMP_IG_CTRL); - } - err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, @@ -3309,6 +3250,36 @@ static int mtk_open(struct net_device *dev) phylink_start(mac->phylink); netif_tx_start_all_queues(dev); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + return 0; + + if (mtk_uses_dsa(dev) && !eth->prog) { + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + struct metadata_dst *md_dst = eth->dsa_meta[i]; + + if (md_dst) + continue; + + md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, + GFP_KERNEL); + if (!md_dst) + return -ENOMEM; + + md_dst->u.port_info.port_id = i; + eth->dsa_meta[i] = md_dst; + } + } else { + /* Hardware DSA untagging and VLAN RX offloading need to be + * disabled if at least one MAC does not use DSA. + */ + u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + + val &= ~MTK_CDMP_STAG_EN; + mtk_w32(eth, val, MTK_CDMP_IG_CTRL); + + mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); + } + return 0; } @@ -3793,10 +3764,9 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset) if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { val = mtk_r32(eth, MTK_CDMP_IG_CTRL); mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); - } - /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + } /* set interrupt delays based on current Net DIM sample */ mtk_dim_rx(ð->rx_dim.work); @@ -4453,7 +4423,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) eth->netdev[id]->hw_features |= NETIF_F_LRO; eth->netdev[id]->vlan_features = eth->soc->hw_features & - ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); + ~NETIF_F_HW_VLAN_CTAG_TX; eth->netdev[id]->features |= eth->soc->hw_features; eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index cdcf8534283e..707445f6bcb1 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -48,7 +48,6 @@ #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ NETIF_F_RXCSUM | \ NETIF_F_HW_VLAN_CTAG_TX | \ - NETIF_F_HW_VLAN_CTAG_RX | \ NETIF_F_SG | NETIF_F_TSO | \ NETIF_F_TSO6 | \ NETIF_F_IPV6_CSUM |\ diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 4c205afbd230..985cff910f30 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -654,7 +654,7 @@ __mtk_wed_detach(struct mtk_wed_device *dev) BIT(hw->index), BIT(hw->index)); } - if (!hw_list[!hw->index]->wed_dev && + if ((!hw_list[!hw->index] || !hw_list[!hw->index]->wed_dev) && hw->eth->dma_dev != hw->eth->dev) mtk_eth_set_dma_device(hw->eth, hw->eth->dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index d53de39539a8..d532883b42d7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1920,9 +1920,10 @@ static void mlx5_cmd_err_trace(struct mlx5_core_dev *dev, u16 opcode, u16 op_mod static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status, u32 syndrome, int err) { + const char *namep = mlx5_command_str(opcode); struct mlx5_cmd_stats *stats; - if (!err) + if (!err || !(strcmp(namep, "unknown command opcode"))) return; stats = &dev->cmd.stats[opcode]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index f40497823e65..7c0f2adbea00 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -490,7 +490,7 @@ static void poll_trace(struct mlx5_fw_tracer *tracer, (u64)timestamp_low; break; default: - if (tracer_event->event_id >= tracer->str_db.first_string_trace || + if (tracer_event->event_id >= tracer->str_db.first_string_trace && tracer_event->event_id <= tracer->str_db.first_string_trace + tracer->str_db.num_string_trace) { tracer_event->type = TRACER_EVENT_TYPE_STRING; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b8987a404d75..8e999f238194 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -327,6 +327,7 @@ struct mlx5e_params { unsigned int sw_mtu; int hard_mtu; bool ptp_rx; + __be32 terminate_lkey_be; }; static inline u8 mlx5e_get_dcb_num_tc(struct mlx5e_params *params) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c index ef546ed8b4d9..9c94807097cb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c @@ -930,8 +930,7 @@ static void mlx5e_build_rx_cq_param(struct mlx5_core_dev *mdev, static u8 rq_end_pad_mode(struct mlx5_core_dev *mdev, struct mlx5e_params *params) { bool lro_en = params->packet_merge.type == MLX5E_PACKET_MERGE_LRO; - bool ro = pcie_relaxed_ordering_enabled(mdev->pdev) && - MLX5_CAP_GEN(mdev, relaxed_ordering_write); + bool ro = MLX5_CAP_GEN(mdev, relaxed_ordering_write); return ro && lro_en ? MLX5_WQ_END_PAD_MODE_NONE : MLX5_WQ_END_PAD_MODE_ALIGN; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c index 7ac1ad9c46de..7e8e96cc5cd0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -51,7 +51,7 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv, if (err) goto out; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]); port_buffer->buffer[i].lossy = MLX5_GET(bufferx_reg, buffer, lossy); @@ -73,14 +73,24 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv, port_buffer->buffer[i].lossy); } - port_buffer->headroom_size = total_used; + port_buffer->internal_buffers_size = 0; + for (i = MLX5E_MAX_NETWORK_BUFFER; i < MLX5E_TOTAL_BUFFERS; i++) { + buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]); + port_buffer->internal_buffers_size += + MLX5_GET(bufferx_reg, buffer, size) * port_buff_cell_sz; + } + port_buffer->port_buffer_size = MLX5_GET(pbmc_reg, out, port_buffer_size) * port_buff_cell_sz; - port_buffer->spare_buffer_size = - port_buffer->port_buffer_size - total_used; + port_buffer->headroom_size = total_used; + port_buffer->spare_buffer_size = port_buffer->port_buffer_size - + port_buffer->internal_buffers_size - + port_buffer->headroom_size; - mlx5e_dbg(HW, priv, "total buffer size=%d, spare buffer size=%d\n", - port_buffer->port_buffer_size, + mlx5e_dbg(HW, priv, + "total buffer size=%u, headroom buffer size=%u, internal buffers size=%u, spare buffer size=%u\n", + port_buffer->port_buffer_size, port_buffer->headroom_size, + port_buffer->internal_buffers_size, port_buffer->spare_buffer_size); out: kfree(out); @@ -206,11 +216,11 @@ static int port_update_pool_cfg(struct mlx5_core_dev *mdev, if (!MLX5_CAP_GEN(mdev, sbcam_reg)) return 0; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) lossless_buff_count += ((port_buffer->buffer[i].size) && (!(port_buffer->buffer[i].lossy))); - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { p = select_sbcm_params(&port_buffer->buffer[i], lossless_buff_count); err = mlx5e_port_set_sbcm(mdev, 0, i, MLX5_INGRESS_DIR, @@ -293,7 +303,7 @@ static int port_set_buffer(struct mlx5e_priv *priv, if (err) goto out; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { void *buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]); u64 size = port_buffer->buffer[i].size; u64 xoff = port_buffer->buffer[i].xoff; @@ -351,7 +361,7 @@ static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer, { int i; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { if (port_buffer->buffer[i].lossy) { port_buffer->buffer[i].xoff = 0; port_buffer->buffer[i].xon = 0; @@ -408,7 +418,7 @@ static int update_buffer_lossy(struct mlx5_core_dev *mdev, int err; int i; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { prio_count = 0; lossy_count = 0; @@ -432,11 +442,11 @@ static int update_buffer_lossy(struct mlx5_core_dev *mdev, } if (changed) { - err = port_update_pool_cfg(mdev, port_buffer); + err = update_xoff_threshold(port_buffer, xoff, max_mtu, port_buff_cell_sz); if (err) return err; - err = update_xoff_threshold(port_buffer, xoff, max_mtu, port_buff_cell_sz); + err = port_update_pool_cfg(mdev, port_buffer); if (err) return err; @@ -515,7 +525,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) { update_prio2buffer = true; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) mlx5e_dbg(HW, priv, "%s: requested to map prio[%d] to buffer %d\n", __func__, i, prio2buffer[i]); @@ -530,7 +540,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, } if (change & MLX5E_PORT_BUFFER_SIZE) { - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]); if (!port_buffer.buffer[i].lossy && !buffer_size[i]) { mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n", @@ -544,7 +554,9 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used); - if (total_used > port_buffer.port_buffer_size) + if (total_used > port_buffer.headroom_size && + (total_used - port_buffer.headroom_size) > + port_buffer.spare_buffer_size) return -EINVAL; update_buffer = true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h index a6ef118de758..f4a19ffbb641 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h @@ -35,7 +35,8 @@ #include "en.h" #include "port.h" -#define MLX5E_MAX_BUFFER 8 +#define MLX5E_MAX_NETWORK_BUFFER 8 +#define MLX5E_TOTAL_BUFFERS 10 #define MLX5E_DEFAULT_CABLE_LEN 7 /* 7 meters */ #define MLX5_BUFFER_SUPPORTED(mdev) (MLX5_CAP_GEN(mdev, pcam_reg) && \ @@ -60,8 +61,9 @@ struct mlx5e_bufferx_reg { struct mlx5e_port_buffer { u32 port_buffer_size; u32 spare_buffer_size; - u32 headroom_size; - struct mlx5e_bufferx_reg buffer[MLX5E_MAX_BUFFER]; + u32 headroom_size; /* Buffers 0-7 */ + u32 internal_buffers_size; /* Buffers 8-9 */ + struct mlx5e_bufferx_reg buffer[MLX5E_MAX_NETWORK_BUFFER]; }; int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c index eb5abd0e55d9..3cbebfba582b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c @@ -175,6 +175,8 @@ static bool mlx5e_ptp_poll_ts_cq(struct mlx5e_cq *cq, int budget) /* ensure cq space is freed before enabling more cqes */ wmb(); + mlx5e_txqsq_wake(&ptpsq->txqsq); + return work_done == budget; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c index fc923a99b6a4..0380a04c3691 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c @@ -84,7 +84,7 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state, int mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state, - struct flow_action *flow_action, + struct flow_action *flow_action, int from, int to, struct mlx5_flow_attr *attr, enum mlx5_flow_namespace_type ns_type) { @@ -96,6 +96,11 @@ mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state, priv = parse_state->flow->priv; flow_action_for_each(i, act, flow_action) { + if (i < from) + continue; + else if (i > to) + break; + tc_act = mlx5e_tc_act_get(act->id, ns_type); if (!tc_act || !tc_act->post_parse) continue; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h index 0e6e1872ac62..d6c12d0ea55b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h @@ -112,7 +112,7 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state, int mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state, - struct flow_action *flow_action, + struct flow_action *flow_action, int from, int to, struct mlx5_flow_attr *attr, enum mlx5_flow_namespace_type ns_type); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c index 20c2d2ecaf93..f0c3464f037f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c @@ -492,6 +492,19 @@ void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) mlx5e_encap_dealloc(priv, e); } +static void mlx5e_encap_put_locked(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e) +{ + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + + lockdep_assert_held(&esw->offloads.encap_tbl_lock); + + if (!refcount_dec_and_test(&e->refcnt)) + return; + list_del(&e->route_list); + hash_del_rcu(&e->encap_hlist); + mlx5e_encap_dealloc(priv, e); +} + static void mlx5e_decap_put(struct mlx5e_priv *priv, struct mlx5e_decap_entry *d) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; @@ -816,6 +829,8 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv, uintptr_t hash_key; int err = 0; + lockdep_assert_held(&esw->offloads.encap_tbl_lock); + parse_attr = attr->parse_attr; tun_info = parse_attr->tun_info[out_index]; mpls_info = &parse_attr->mpls_info[out_index]; @@ -829,7 +844,6 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv, hash_key = hash_encap_info(&key); - mutex_lock(&esw->offloads.encap_tbl_lock); e = mlx5e_encap_get(priv, &key, hash_key); /* must verify if encap is valid or not */ @@ -840,15 +854,6 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv, goto out_err; } - mutex_unlock(&esw->offloads.encap_tbl_lock); - wait_for_completion(&e->res_ready); - - /* Protect against concurrent neigh update. */ - mutex_lock(&esw->offloads.encap_tbl_lock); - if (e->compl_result < 0) { - err = -EREMOTEIO; - goto out_err; - } goto attach_flow; } @@ -877,15 +882,12 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv, INIT_LIST_HEAD(&e->flows); hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key); tbl_time_before = mlx5e_route_tbl_get_last_update(priv); - mutex_unlock(&esw->offloads.encap_tbl_lock); if (family == AF_INET) err = mlx5e_tc_tun_create_header_ipv4(priv, mirred_dev, e); else if (family == AF_INET6) err = mlx5e_tc_tun_create_header_ipv6(priv, mirred_dev, e); - /* Protect against concurrent neigh update. */ - mutex_lock(&esw->offloads.encap_tbl_lock); complete_all(&e->res_ready); if (err) { e->compl_result = err; @@ -920,18 +922,15 @@ attach_flow: } else { flow_flag_set(flow, SLOW); } - mutex_unlock(&esw->offloads.encap_tbl_lock); return err; out_err: - mutex_unlock(&esw->offloads.encap_tbl_lock); if (e) - mlx5e_encap_put(priv, e); + mlx5e_encap_put_locked(priv, e); return err; out_err_init: - mutex_unlock(&esw->offloads.encap_tbl_lock); kfree(tun_info); kfree(e); return err; @@ -1016,6 +1015,93 @@ out_err: return err; } +int mlx5e_tc_tun_encap_dests_set(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_attr *attr, + struct netlink_ext_ack *extack, + bool *vf_tun) +{ + struct mlx5e_tc_flow_parse_attr *parse_attr; + struct mlx5_esw_flow_attr *esw_attr; + struct net_device *encap_dev = NULL; + struct mlx5e_rep_priv *rpriv; + struct mlx5e_priv *out_priv; + struct mlx5_eswitch *esw; + int out_index; + int err = 0; + + if (!mlx5e_is_eswitch_flow(flow)) + return 0; + + parse_attr = attr->parse_attr; + esw_attr = attr->esw_attr; + *vf_tun = false; + + esw = priv->mdev->priv.eswitch; + mutex_lock(&esw->offloads.encap_tbl_lock); + for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) { + struct net_device *out_dev; + int mirred_ifindex; + + if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) + continue; + + mirred_ifindex = parse_attr->mirred_ifindex[out_index]; + out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex); + if (!out_dev) { + NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found"); + err = -ENODEV; + goto out; + } + err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index, + extack, &encap_dev); + dev_put(out_dev); + if (err) + goto out; + + if (esw_attr->dests[out_index].flags & + MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE && + !esw_attr->dest_int_port) + *vf_tun = true; + + out_priv = netdev_priv(encap_dev); + rpriv = out_priv->ppriv; + esw_attr->dests[out_index].rep = rpriv->rep; + esw_attr->dests[out_index].mdev = out_priv->mdev; + } + + if (*vf_tun && esw_attr->out_count > 1) { + NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported"); + err = -EOPNOTSUPP; + goto out; + } + +out: + mutex_unlock(&esw->offloads.encap_tbl_lock); + return err; +} + +void mlx5e_tc_tun_encap_dests_unset(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_attr *attr) +{ + struct mlx5_esw_flow_attr *esw_attr; + int out_index; + + if (!mlx5e_is_eswitch_flow(flow)) + return; + + esw_attr = attr->esw_attr; + + for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) { + if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) + continue; + + mlx5e_detach_encap(flow->priv, flow, attr, out_index); + kfree(attr->parse_attr->tun_info[out_index]); + } +} + static int cmp_route_info(struct mlx5e_route_key *a, struct mlx5e_route_key *b) { @@ -1369,11 +1455,13 @@ static void mlx5e_invalidate_encap(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow; list_for_each_entry(flow, encap_flows, tmp_list) { - struct mlx5_flow_attr *attr = flow->attr; struct mlx5_esw_flow_attr *esw_attr; + struct mlx5_flow_attr *attr; if (!mlx5e_is_offloaded_flow(flow)) continue; + + attr = mlx5e_tc_get_encap_attr(flow); esw_attr = attr->esw_attr; if (flow_flag_test(flow, SLOW)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h index 8ad273dde40e..5d7d67687cbc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h @@ -30,6 +30,15 @@ int mlx5e_attach_decap_route(struct mlx5e_priv *priv, void mlx5e_detach_decap_route(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow); +int mlx5e_tc_tun_encap_dests_set(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_attr *attr, + struct netlink_ext_ack *extack, + bool *vf_tun); +void mlx5e_tc_tun_encap_dests_unset(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow, + struct mlx5_flow_attr *attr); + struct ip_tunnel_info *mlx5e_dup_tun_info(const struct ip_tunnel_info *tun_info); int mlx5e_tc_set_attr_rx_tun(struct mlx5e_tc_flow *flow, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h index 47381e949f1f..879d698b6119 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h @@ -193,6 +193,8 @@ static inline u16 mlx5e_txqsq_get_next_pi(struct mlx5e_txqsq *sq, u16 size) return pi; } +void mlx5e_txqsq_wake(struct mlx5e_txqsq *sq); + static inline u16 mlx5e_shampo_get_cqe_header_index(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) { return be16_to_cpu(cqe->shampo.header_entry_index) & (rq->mpwqe.shampo->hd_per_wq - 1); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index 4c9a3210600c..41c396e76457 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -39,12 +39,13 @@ void mlx5e_mkey_set_relaxed_ordering(struct mlx5_core_dev *mdev, void *mkc) { - bool ro_pci_enable = pcie_relaxed_ordering_enabled(mdev->pdev); bool ro_write = MLX5_CAP_GEN(mdev, relaxed_ordering_write); - bool ro_read = MLX5_CAP_GEN(mdev, relaxed_ordering_read); + bool ro_read = MLX5_CAP_GEN(mdev, relaxed_ordering_read) || + (pcie_relaxed_ordering_enabled(mdev->pdev) && + MLX5_CAP_GEN(mdev, relaxed_ordering_read_pci_enabled)); - MLX5_SET(mkc, mkc, relaxed_ordering_read, ro_pci_enable && ro_read); - MLX5_SET(mkc, mkc, relaxed_ordering_write, ro_pci_enable && ro_write); + MLX5_SET(mkc, mkc, relaxed_ordering_read, ro_read); + MLX5_SET(mkc, mkc, relaxed_ordering_write, ro_write); } int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey) @@ -149,10 +150,8 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb, inlen = MLX5_ST_SZ_BYTES(modify_tir_in); in = kvzalloc(inlen, GFP_KERNEL); - if (!in) { - err = -ENOMEM; - goto out; - } + if (!in) + return -ENOMEM; if (enable_uc_lb) lb_flags = MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; @@ -170,14 +169,13 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb, tirn = tir->tirn; err = mlx5_core_modify_tir(mdev, tirn, in); if (err) - goto out; + break; } + mutex_unlock(&mdev->mlx5e_res.hw_objs.td.list_lock); -out: kvfree(in); if (err) netdev_err(priv->netdev, "refresh tir(0x%x) failed, %d\n", tirn, err); - mutex_unlock(&mdev->mlx5e_res.hw_objs.td.list_lock); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index 89de92d06483..ebee52a8361a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -926,9 +926,10 @@ static int mlx5e_dcbnl_getbuffer(struct net_device *dev, if (err) return err; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) dcb_buffer->buffer_size[i] = port_buffer.buffer[i].size; - dcb_buffer->total_size = port_buffer.port_buffer_size; + dcb_buffer->total_size = port_buffer.port_buffer_size - + port_buffer.internal_buffers_size; return 0; } @@ -970,7 +971,7 @@ static int mlx5e_dcbnl_setbuffer(struct net_device *dev, if (err) return err; - for (i = 0; i < MLX5E_MAX_BUFFER; i++) { + for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { if (port_buffer.buffer[i].size != dcb_buffer->buffer_size[i]) { changed |= MLX5E_PORT_BUFFER_SIZE; buffer_size = dcb_buffer->buffer_size; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 2944691f06ad..a7c526ee5024 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -727,26 +727,6 @@ static void mlx5e_rq_free_shampo(struct mlx5e_rq *rq) mlx5e_rq_shampo_hd_free(rq); } -static __be32 mlx5e_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev) -{ - u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {}; - int res; - - if (!MLX5_CAP_GEN(dev, terminate_scatter_list_mkey)) - return MLX5_TERMINATE_SCATTER_LIST_LKEY; - - MLX5_SET(query_special_contexts_in, in, opcode, - MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); - res = mlx5_cmd_exec_inout(dev, query_special_contexts, in, out); - if (res) - return MLX5_TERMINATE_SCATTER_LIST_LKEY; - - res = MLX5_GET(query_special_contexts_out, out, - terminate_scatter_list_mkey); - return cpu_to_be32(res); -} - static int mlx5e_alloc_rq(struct mlx5e_params *params, struct mlx5e_xsk_param *xsk, struct mlx5e_rq_param *rqp, @@ -908,7 +888,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params, /* check if num_frags is not a pow of two */ if (rq->wqe.info.num_frags < (1 << rq->wqe.info.log_num_frags)) { wqe->data[f].byte_count = 0; - wqe->data[f].lkey = mlx5e_get_terminate_scatter_list_mkey(mdev); + wqe->data[f].lkey = params->terminate_lkey_be; wqe->data[f].addr = 0; } } @@ -5007,6 +4987,8 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16 /* RQ */ mlx5e_build_rq_params(mdev, params); + params->terminate_lkey_be = mlx5_core_get_terminate_scatter_list_mkey(mdev); + params->packet_merge.timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT); /* CQ moderation params */ @@ -5279,12 +5261,16 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev, mlx5e_timestamp_init(priv); + priv->dfs_root = debugfs_create_dir("nic", + mlx5_debugfs_get_dev_root(mdev)); + fs = mlx5e_fs_init(priv->profile, mdev, !test_bit(MLX5E_STATE_DESTROYING, &priv->state), priv->dfs_root); if (!fs) { err = -ENOMEM; mlx5_core_err(mdev, "FS initialization failed, %d\n", err); + debugfs_remove_recursive(priv->dfs_root); return err; } priv->fs = fs; @@ -5305,6 +5291,7 @@ static void mlx5e_nic_cleanup(struct mlx5e_priv *priv) mlx5e_health_destroy_reporters(priv); mlx5e_ktls_cleanup(priv); mlx5e_fs_cleanup(priv->fs); + debugfs_remove_recursive(priv->dfs_root); priv->fs = NULL; } @@ -5851,8 +5838,8 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv) } static int -mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mdev, - const struct mlx5e_profile *new_profile, void *new_ppriv) +mlx5e_netdev_init_profile(struct net_device *netdev, struct mlx5_core_dev *mdev, + const struct mlx5e_profile *new_profile, void *new_ppriv) { struct mlx5e_priv *priv = netdev_priv(netdev); int err; @@ -5868,6 +5855,25 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde err = new_profile->init(priv->mdev, priv->netdev); if (err) goto priv_cleanup; + + return 0; + +priv_cleanup: + mlx5e_priv_cleanup(priv); + return err; +} + +static int +mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mdev, + const struct mlx5e_profile *new_profile, void *new_ppriv) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err; + + err = mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv); + if (err) + return err; + err = mlx5e_attach_netdev(priv); if (err) goto profile_cleanup; @@ -5875,7 +5881,6 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde profile_cleanup: new_profile->cleanup(priv); -priv_cleanup: mlx5e_priv_cleanup(priv); return err; } @@ -5894,6 +5899,12 @@ int mlx5e_netdev_change_profile(struct mlx5e_priv *priv, priv->profile->cleanup(priv); mlx5e_priv_cleanup(priv); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv); + set_bit(MLX5E_STATE_DESTROYING, &priv->state); + return -EIO; + } + err = mlx5e_netdev_attach_profile(netdev, mdev, new_profile, new_ppriv); if (err) { /* roll back to original profile */ netdev_warn(netdev, "%s: new profile init failed, %d\n", __func__, err); @@ -5955,8 +5966,11 @@ static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state) struct net_device *netdev = priv->netdev; struct mlx5_core_dev *mdev = priv->mdev; - if (!netif_device_present(netdev)) + if (!netif_device_present(netdev)) { + if (test_bit(MLX5E_STATE_DESTROYING, &priv->state)) + mlx5e_destroy_mdev_resources(mdev); return -ENODEV; + } mlx5e_detach_netdev(priv); mlx5e_destroy_mdev_resources(mdev); @@ -6002,9 +6016,6 @@ static int mlx5e_probe(struct auxiliary_device *adev, priv->profile = profile; priv->ppriv = NULL; - priv->dfs_root = debugfs_create_dir("nic", - mlx5_debugfs_get_dev_root(priv->mdev)); - err = profile->init(mdev, netdev); if (err) { mlx5_core_err(mdev, "mlx5e_nic_profile init failed, %d\n", err); @@ -6033,7 +6044,6 @@ err_resume: err_profile_cleanup: profile->cleanup(priv); err_destroy_netdev: - debugfs_remove_recursive(priv->dfs_root); mlx5e_destroy_netdev(priv); err_devlink_port_unregister: mlx5e_devlink_port_unregister(mlx5e_dev); @@ -6053,7 +6063,6 @@ static void mlx5e_remove(struct auxiliary_device *adev) unregister_netdev(priv->netdev); mlx5e_suspend(adev, state); priv->profile->cleanup(priv); - debugfs_remove_recursive(priv->dfs_root); mlx5e_destroy_netdev(priv); mlx5e_devlink_port_unregister(mlx5e_dev); mlx5e_destroy_devlink(mlx5e_dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 1fc386eccaf8..3e7041bd5705 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -30,6 +30,7 @@ * SOFTWARE. */ +#include #include #include #include @@ -812,11 +813,15 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev, { struct mlx5e_priv *priv = netdev_priv(netdev); + priv->dfs_root = debugfs_create_dir("nic", + mlx5_debugfs_get_dev_root(mdev)); + priv->fs = mlx5e_fs_init(priv->profile, mdev, !test_bit(MLX5E_STATE_DESTROYING, &priv->state), priv->dfs_root); if (!priv->fs) { netdev_err(priv->netdev, "FS allocation failed\n"); + debugfs_remove_recursive(priv->dfs_root); return -ENOMEM; } @@ -829,6 +834,7 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev, static void mlx5e_cleanup_rep(struct mlx5e_priv *priv) { mlx5e_fs_cleanup(priv->fs); + debugfs_remove_recursive(priv->dfs_root); priv->fs = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 728b82ce4031..8a5a8703f0a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1665,11 +1665,9 @@ bool mlx5e_tc_is_vf_tunnel(struct net_device *out_dev, struct net_device *route_ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *route_dev, u16 *vport) { struct mlx5e_priv *out_priv, *route_priv; - struct mlx5_devcom *devcom = NULL; struct mlx5_core_dev *route_mdev; struct mlx5_eswitch *esw; u16 vhca_id; - int err; out_priv = netdev_priv(out_dev); esw = out_priv->mdev->priv.eswitch; @@ -1678,6 +1676,9 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro vhca_id = MLX5_CAP_GEN(route_mdev, vhca_id); if (mlx5_lag_is_active(out_priv->mdev)) { + struct mlx5_devcom *devcom; + int err; + /* In lag case we may get devices from different eswitch instances. * If we failed to get vport num, it means, mostly, that we on the wrong * eswitch. @@ -1686,101 +1687,16 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro if (err != -ENOENT) return err; + rcu_read_lock(); devcom = out_priv->mdev->priv.devcom; - esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!esw) - return -ENODEV; + esw = mlx5_devcom_get_peer_data_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + err = esw ? mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport) : -ENODEV; + rcu_read_unlock(); + + return err; } - err = mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); - if (devcom) - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - return err; -} - -static int -set_encap_dests(struct mlx5e_priv *priv, - struct mlx5e_tc_flow *flow, - struct mlx5_flow_attr *attr, - struct netlink_ext_ack *extack, - bool *vf_tun) -{ - struct mlx5e_tc_flow_parse_attr *parse_attr; - struct mlx5_esw_flow_attr *esw_attr; - struct net_device *encap_dev = NULL; - struct mlx5e_rep_priv *rpriv; - struct mlx5e_priv *out_priv; - int out_index; - int err = 0; - - if (!mlx5e_is_eswitch_flow(flow)) - return 0; - - parse_attr = attr->parse_attr; - esw_attr = attr->esw_attr; - *vf_tun = false; - - for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) { - struct net_device *out_dev; - int mirred_ifindex; - - if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) - continue; - - mirred_ifindex = parse_attr->mirred_ifindex[out_index]; - out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex); - if (!out_dev) { - NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found"); - err = -ENODEV; - goto out; - } - err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index, - extack, &encap_dev); - dev_put(out_dev); - if (err) - goto out; - - if (esw_attr->dests[out_index].flags & - MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE && - !esw_attr->dest_int_port) - *vf_tun = true; - - out_priv = netdev_priv(encap_dev); - rpriv = out_priv->ppriv; - esw_attr->dests[out_index].rep = rpriv->rep; - esw_attr->dests[out_index].mdev = out_priv->mdev; - } - - if (*vf_tun && esw_attr->out_count > 1) { - NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported"); - err = -EOPNOTSUPP; - goto out; - } - -out: - return err; -} - -static void -clean_encap_dests(struct mlx5e_priv *priv, - struct mlx5e_tc_flow *flow, - struct mlx5_flow_attr *attr) -{ - struct mlx5_esw_flow_attr *esw_attr; - int out_index; - - if (!mlx5e_is_eswitch_flow(flow)) - return; - - esw_attr = attr->esw_attr; - - for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) { - if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) - continue; - - mlx5e_detach_encap(priv, flow, attr, out_index); - kfree(attr->parse_attr->tun_info[out_index]); - } + return mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); } static int @@ -1819,7 +1735,7 @@ post_process_attr(struct mlx5e_tc_flow *flow, if (err) goto err_out; - err = set_encap_dests(flow->priv, flow, attr, extack, &vf_tun); + err = mlx5e_tc_tun_encap_dests_set(flow->priv, flow, attr, extack, &vf_tun); if (err) goto err_out; @@ -3943,8 +3859,8 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state, struct mlx5_flow_attr *prev_attr; struct flow_action_entry *act; struct mlx5e_tc_act *tc_act; + int err, i, i_split = 0; bool is_missable; - int err, i; ns_type = mlx5e_get_flow_namespace(flow); list_add(&attr->list, &flow->attrs); @@ -3985,7 +3901,8 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state, i < flow_action->num_entries - 1)) { is_missable = tc_act->is_missable ? tc_act->is_missable(act) : false; - err = mlx5e_tc_act_post_parse(parse_state, flow_action, attr, ns_type); + err = mlx5e_tc_act_post_parse(parse_state, flow_action, i_split, i, attr, + ns_type); if (err) goto out_free_post_acts; @@ -3995,6 +3912,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state, goto out_free_post_acts; } + i_split = i + 1; list_add(&attr->list, &flow->attrs); } @@ -4009,7 +3927,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state, } } - err = mlx5e_tc_act_post_parse(parse_state, flow_action, attr, ns_type); + err = mlx5e_tc_act_post_parse(parse_state, flow_action, i_split, i, attr, ns_type); if (err) goto out_free_post_acts; @@ -4323,7 +4241,7 @@ mlx5_free_flow_attr_actions(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *a if (attr->post_act_handle) mlx5e_tc_post_act_del(get_post_action(flow->priv), attr->post_act_handle); - clean_encap_dests(flow->priv, flow, attr); + mlx5e_tc_tun_encap_dests_unset(flow->priv, flow, attr); if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) mlx5_fc_destroy(counter_dev, attr->counter); @@ -5301,6 +5219,8 @@ int mlx5e_tc_esw_init(struct mlx5_rep_uplink_priv *uplink_priv) goto err_action_counter; } + mlx5_esw_offloads_devcom_init(esw); + return 0; err_action_counter: @@ -5329,7 +5249,7 @@ void mlx5e_tc_esw_cleanup(struct mlx5_rep_uplink_priv *uplink_priv) priv = netdev_priv(rpriv->netdev); esw = priv->mdev->priv.eswitch; - mlx5e_tc_clean_fdb_peer_flows(esw); + mlx5_esw_offloads_devcom_cleanup(esw); mlx5e_tc_tun_cleanup(uplink_priv->encap); @@ -5643,22 +5563,43 @@ bool mlx5e_tc_update_skb_nic(struct mlx5_cqe64 *cqe, struct sk_buff *skb) 0, NULL); } +static struct mapping_ctx * +mlx5e_get_priv_obj_mapping(struct mlx5e_priv *priv) +{ + struct mlx5e_tc_table *tc; + struct mlx5_eswitch *esw; + struct mapping_ctx *ctx; + + if (is_mdev_switchdev_mode(priv->mdev)) { + esw = priv->mdev->priv.eswitch; + ctx = esw->offloads.reg_c0_obj_pool; + } else { + tc = mlx5e_fs_get_tc(priv->fs); + ctx = tc->mapping; + } + + return ctx; +} + int mlx5e_tc_action_miss_mapping_get(struct mlx5e_priv *priv, struct mlx5_flow_attr *attr, u64 act_miss_cookie, u32 *act_miss_mapping) { - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_mapped_obj mapped_obj = {}; + struct mlx5_eswitch *esw; struct mapping_ctx *ctx; int err; - ctx = esw->offloads.reg_c0_obj_pool; - + ctx = mlx5e_get_priv_obj_mapping(priv); mapped_obj.type = MLX5_MAPPED_OBJ_ACT_MISS; mapped_obj.act_miss_cookie = act_miss_cookie; err = mapping_add(ctx, &mapped_obj, act_miss_mapping); if (err) return err; + if (!is_mdev_switchdev_mode(priv->mdev)) + return 0; + + esw = priv->mdev->priv.eswitch; attr->act_id_restore_rule = esw_add_restore_rule(esw, *act_miss_mapping); if (IS_ERR(attr->act_id_restore_rule)) goto err_rule; @@ -5673,10 +5614,9 @@ err_rule: void mlx5e_tc_action_miss_mapping_put(struct mlx5e_priv *priv, struct mlx5_flow_attr *attr, u32 act_miss_mapping) { - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; - struct mapping_ctx *ctx; + struct mapping_ctx *ctx = mlx5e_get_priv_obj_mapping(priv); - ctx = esw->offloads.reg_c0_obj_pool; - mlx5_del_flow_rules(attr->act_id_restore_rule); + if (is_mdev_switchdev_mode(priv->mdev)) + mlx5_del_flow_rules(attr->act_id_restore_rule); mapping_remove(ctx, act_miss_mapping); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index df5e780e8e6a..c7eb6b238c2b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -762,6 +762,17 @@ static void mlx5e_tx_wi_consume_fifo_skbs(struct mlx5e_txqsq *sq, struct mlx5e_t } } +void mlx5e_txqsq_wake(struct mlx5e_txqsq *sq) +{ + if (netif_tx_queue_stopped(sq->txq) && + mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) && + mlx5e_ptpsq_fifo_has_room(sq) && + !test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { + netif_tx_wake_queue(sq->txq); + sq->stats->wake++; + } +} + bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) { struct mlx5e_sq_stats *stats; @@ -861,13 +872,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) netdev_tx_completed_queue(sq->txq, npkts, nbytes); - if (netif_tx_queue_stopped(sq->txq) && - mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) && - mlx5e_ptpsq_fifo_has_room(sq) && - !test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { - netif_tx_wake_queue(sq->txq); - stats->wake++; - } + mlx5e_txqsq_wake(sq); return (i == MLX5E_TX_CQ_POLL_BUDGET); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index a50bfda18e96..fbb2d963fb7e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -161,20 +161,22 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) } } + /* budget=0 means we may be in IRQ context, do as little as possible */ + if (unlikely(!budget)) + goto out; + busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq.cq); if (c->xdp) busy |= mlx5e_poll_xdpsq_cq(&c->rq_xdpsq.cq); - if (likely(budget)) { /* budget=0 means: don't poll rx rings */ - if (xsk_open) - work_done = mlx5e_poll_rx_cq(&xskrq->cq, budget); + if (xsk_open) + work_done = mlx5e_poll_rx_cq(&xskrq->cq, budget); - if (likely(budget - work_done)) - work_done += mlx5e_poll_rx_cq(&rq->cq, budget - work_done); + if (likely(budget - work_done)) + work_done += mlx5e_poll_rx_cq(&rq->cq, budget - work_done); - busy |= work_done == budget; - } + busy |= work_done == budget; mlx5e_poll_ico_cq(&c->icosq.cq); if (mlx5e_poll_ico_cq(&c->async_icosq.cq)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 1c35d721a31d..3db4866d7880 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -824,7 +824,7 @@ static int comp_irqs_request_pci(struct mlx5_core_dev *dev) ncomp_eqs = table->num_comp_eqs; cpus = kcalloc(ncomp_eqs, sizeof(*cpus), GFP_KERNEL); if (!cpus) - ret = -ENOMEM; + return -ENOMEM; i = 0; rcu_read_lock(); @@ -1104,7 +1104,7 @@ void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev) struct mlx5_eq_table *table = dev->priv.eq_table; mutex_lock(&table->lock); /* sync with create/destroy_async_eq */ - mlx5_irq_table_destroy(dev); + mlx5_irq_table_free_irqs(dev); mutex_unlock(&table->lock); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 1a042c981713..add6cfa432a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -342,6 +342,7 @@ struct mlx5_eswitch { u32 large_group_num; } params; struct blocking_notifier_head n_head; + bool paired[MLX5_MAX_PORTS]; }; void esw_offloads_disable(struct mlx5_eswitch *esw); @@ -369,6 +370,8 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs); void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf); void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw); void mlx5_eswitch_disable(struct mlx5_eswitch *esw); +void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw); +void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw); int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, u16 vport, const u8 *mac); int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, @@ -767,6 +770,8 @@ static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {} static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) { return 0; } static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) {} static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {} +static inline void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) {} +static inline void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) {} static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; } static inline int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, u16 vport, int link_state) { return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 69215ffb9999..8d19c20d3447 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2742,6 +2742,9 @@ static int mlx5_esw_offloads_devcom_event(int event, mlx5_eswitch_vport_match_metadata_enabled(peer_esw)) break; + if (esw->paired[mlx5_get_dev_index(peer_esw->dev)]) + break; + err = mlx5_esw_offloads_set_ns_peer(esw, peer_esw, true); if (err) goto err_out; @@ -2753,14 +2756,18 @@ static int mlx5_esw_offloads_devcom_event(int event, if (err) goto err_pair; + esw->paired[mlx5_get_dev_index(peer_esw->dev)] = true; + peer_esw->paired[mlx5_get_dev_index(esw->dev)] = true; mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true); break; case ESW_OFFLOADS_DEVCOM_UNPAIR: - if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) + if (!esw->paired[mlx5_get_dev_index(peer_esw->dev)]) break; mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); + esw->paired[mlx5_get_dev_index(peer_esw->dev)] = false; + peer_esw->paired[mlx5_get_dev_index(esw->dev)] = false; mlx5_esw_offloads_unpair(peer_esw); mlx5_esw_offloads_unpair(esw); mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false); @@ -2779,7 +2786,7 @@ err_out: return err; } -static void esw_offloads_devcom_init(struct mlx5_eswitch *esw) +void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) { struct mlx5_devcom *devcom = esw->dev->priv.devcom; @@ -2802,7 +2809,7 @@ static void esw_offloads_devcom_init(struct mlx5_eswitch *esw) ESW_OFFLOADS_DEVCOM_PAIR, esw); } -static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) +void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) { struct mlx5_devcom *devcom = esw->dev->priv.devcom; @@ -3250,8 +3257,6 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) if (err) goto err_vports; - esw_offloads_devcom_init(esw); - return 0; err_vports: @@ -3292,7 +3297,6 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, void esw_offloads_disable(struct mlx5_eswitch *esw) { - esw_offloads_devcom_cleanup(esw); mlx5_eswitch_disable_pf_vf_vports(esw); esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK); esw_set_passing_vport_metadata(esw, false); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index adefde3ea941..b7d779d08d83 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -3,6 +3,7 @@ #include #include "lib/devcom.h" +#include "mlx5_core.h" static LIST_HEAD(devcom_list); @@ -13,7 +14,7 @@ static LIST_HEAD(devcom_list); struct mlx5_devcom_component { struct { - void *data; + void __rcu *data; } device[MLX5_DEVCOM_PORTS_SUPPORTED]; mlx5_devcom_event_handler_t handler; @@ -77,6 +78,7 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED) return NULL; + mlx5_dev_list_lock(); sguid0 = mlx5_query_nic_system_image_guid(dev); list_for_each_entry(iter, &devcom_list, list) { struct mlx5_core_dev *tmp_dev = NULL; @@ -102,8 +104,10 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) if (!priv) { priv = mlx5_devcom_list_alloc(); - if (!priv) - return ERR_PTR(-ENOMEM); + if (!priv) { + devcom = ERR_PTR(-ENOMEM); + goto out; + } idx = 0; new_priv = true; @@ -112,13 +116,16 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) priv->devs[idx] = dev; devcom = mlx5_devcom_alloc(priv, idx); if (!devcom) { - kfree(priv); - return ERR_PTR(-ENOMEM); + if (new_priv) + kfree(priv); + devcom = ERR_PTR(-ENOMEM); + goto out; } if (new_priv) list_add(&priv->list, &devcom_list); - +out: + mlx5_dev_list_unlock(); return devcom; } @@ -131,6 +138,7 @@ void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom) if (IS_ERR_OR_NULL(devcom)) return; + mlx5_dev_list_lock(); priv = devcom->priv; priv->devs[devcom->idx] = NULL; @@ -141,10 +149,12 @@ void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom) break; if (i != MLX5_DEVCOM_PORTS_SUPPORTED) - return; + goto out; list_del(&priv->list); kfree(priv); +out: + mlx5_dev_list_unlock(); } void mlx5_devcom_register_component(struct mlx5_devcom *devcom, @@ -162,7 +172,7 @@ void mlx5_devcom_register_component(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; down_write(&comp->sem); comp->handler = handler; - comp->device[devcom->idx].data = data; + rcu_assign_pointer(comp->device[devcom->idx].data, data); up_write(&comp->sem); } @@ -176,8 +186,9 @@ void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; down_write(&comp->sem); - comp->device[devcom->idx].data = NULL; + RCU_INIT_POINTER(comp->device[devcom->idx].data, NULL); up_write(&comp->sem); + synchronize_rcu(); } int mlx5_devcom_send_event(struct mlx5_devcom *devcom, @@ -193,12 +204,15 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; down_write(&comp->sem); - for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) - if (i != devcom->idx && comp->device[i].data) { - err = comp->handler(event, comp->device[i].data, - event_data); + for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) { + void *data = rcu_dereference_protected(comp->device[i].data, + lockdep_is_held(&comp->sem)); + + if (i != devcom->idx && data) { + err = comp->handler(event, data, event_data); break; } + } up_write(&comp->sem); return err; @@ -213,7 +227,7 @@ void mlx5_devcom_set_paired(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; WARN_ON(!rwsem_is_locked(&comp->sem)); - comp->paired = paired; + WRITE_ONCE(comp->paired, paired); } bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom, @@ -222,7 +236,7 @@ bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom, if (IS_ERR_OR_NULL(devcom)) return false; - return devcom->priv->components[id].paired; + return READ_ONCE(devcom->priv->components[id].paired); } void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, @@ -236,7 +250,7 @@ void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; down_read(&comp->sem); - if (!comp->paired) { + if (!READ_ONCE(comp->paired)) { up_read(&comp->sem); return NULL; } @@ -245,7 +259,29 @@ void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, if (i != devcom->idx) break; - return comp->device[i].data; + return rcu_dereference_protected(comp->device[i].data, lockdep_is_held(&comp->sem)); +} + +void *mlx5_devcom_get_peer_data_rcu(struct mlx5_devcom *devcom, enum mlx5_devcom_components id) +{ + struct mlx5_devcom_component *comp; + int i; + + if (IS_ERR_OR_NULL(devcom)) + return NULL; + + for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) + if (i != devcom->idx) + break; + + comp = &devcom->priv->components[id]; + /* This can change concurrently, however 'data' pointer will remain + * valid for the duration of RCU read section. + */ + if (!READ_ONCE(comp->paired)) + return NULL; + + return rcu_dereference(comp->device[i].data); } void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index 94313c18bb64..9a496f4722da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -41,6 +41,7 @@ bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom, void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); +void *mlx5_devcom_get_peer_data_rcu(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index edc738e86cac..d6ee016deae1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -691,6 +691,9 @@ static int handle_hca_cap_roce(struct mlx5_core_dev *dev, void *set_ctx) MLX5_ST_SZ_BYTES(roce_cap)); MLX5_SET(roce_cap, set_hca_cap, sw_r_roce_src_udp_port, 1); + if (MLX5_CAP_ROCE_MAX(dev, qp_ooo_transmit_default)) + MLX5_SET(roce_cap, set_hca_cap, qp_ooo_transmit_default, 1); + err = set_caps(dev, set_ctx, MLX5_SET_HCA_CAP_OP_MOD_ROCE); return err; } @@ -920,7 +923,6 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev, } mlx5_pci_vsc_init(dev); - dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev); return 0; err_clr_master: @@ -1046,7 +1048,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev) dev->dm = mlx5_dm_create(dev); if (IS_ERR(dev->dm)) - mlx5_core_warn(dev, "Failed to init device memory%d\n", err); + mlx5_core_warn(dev, "Failed to init device memory %ld\n", PTR_ERR(dev->dm)); dev->tracer = mlx5_fw_tracer_create(dev); dev->hv_vhca = mlx5_hv_vhca_create(dev); @@ -1152,6 +1154,7 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout goto err_cmd_cleanup; } + dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev); mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_UP); mlx5_start_health_poll(dev); @@ -1799,15 +1802,16 @@ static void remove_one(struct pci_dev *pdev) struct devlink *devlink = priv_to_devlink(dev); set_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state); - /* mlx5_drain_fw_reset() is using devlink APIs. Hence, we must drain - * fw_reset before unregistering the devlink. + /* mlx5_drain_fw_reset() and mlx5_drain_health_wq() are using + * devlink notify APIs. + * Hence, we must drain them before unregistering the devlink. */ mlx5_drain_fw_reset(dev); + mlx5_drain_health_wq(dev); devlink_unregister(devlink); mlx5_sriov_disable(pdev); mlx5_thermal_uninit(dev); mlx5_crdump_disable(dev); - mlx5_drain_health_wq(dev); mlx5_uninit_one(dev); mlx5_pci_close(dev); mlx5_mdev_uninit(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h index efd0c299c5c7..aa403a5ea34e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h @@ -15,6 +15,7 @@ int mlx5_irq_table_init(struct mlx5_core_dev *dev); void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev); int mlx5_irq_table_create(struct mlx5_core_dev *dev); void mlx5_irq_table_destroy(struct mlx5_core_dev *dev); +void mlx5_irq_table_free_irqs(struct mlx5_core_dev *dev); int mlx5_irq_table_get_num_comp(struct mlx5_irq_table *table); int mlx5_irq_table_get_sfs_vec(struct mlx5_irq_table *table); struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 9d735c343a3b..678f0be81375 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -32,6 +32,7 @@ #include #include +#include #include "mlx5_core.h" int mlx5_core_create_mkey(struct mlx5_core_dev *dev, u32 *mkey, u32 *in, @@ -122,3 +123,23 @@ int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num) return mlx5_cmd_exec_in(dev, destroy_psv, in); } EXPORT_SYMBOL(mlx5_core_destroy_psv); + +__be32 mlx5_core_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev) +{ + u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {}; + u32 mkey; + + if (!MLX5_CAP_GEN(dev, terminate_scatter_list_mkey)) + return MLX5_TERMINATE_SCATTER_LIST_LKEY; + + MLX5_SET(query_special_contexts_in, in, opcode, + MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); + if (mlx5_cmd_exec_inout(dev, query_special_contexts, in, out)) + return MLX5_TERMINATE_SCATTER_LIST_LKEY; + + mkey = MLX5_GET(query_special_contexts_out, out, + terminate_scatter_list_mkey); + return cpu_to_be32(mkey); +} +EXPORT_SYMBOL(mlx5_core_get_terminate_scatter_list_mkey); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c index 2245d3b2f393..843da89a9035 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c @@ -32,6 +32,7 @@ struct mlx5_irq { struct mlx5_irq_pool *pool; int refcount; struct msi_map map; + u32 pool_index; }; struct mlx5_irq_table { @@ -132,7 +133,7 @@ static void irq_release(struct mlx5_irq *irq) struct cpu_rmap *rmap; #endif - xa_erase(&pool->irqs, irq->map.index); + xa_erase(&pool->irqs, irq->pool_index); /* free_irq requires that affinity_hint and rmap will be cleared before * calling it. To satisfy this requirement, we call * irq_cpu_rmap_remove() to remove the notifier @@ -140,7 +141,7 @@ static void irq_release(struct mlx5_irq *irq) irq_update_affinity_hint(irq->map.virq, NULL); #ifdef CONFIG_RFS_ACCEL rmap = mlx5_eq_table_get_rmap(pool->dev); - if (rmap && irq->map.index) + if (rmap) irq_cpu_rmap_remove(rmap, irq->map.virq); #endif @@ -231,12 +232,13 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i, if (!irq) return ERR_PTR(-ENOMEM); if (!i || !pci_msix_can_alloc_dyn(dev->pdev)) { - /* The vector at index 0 was already allocated. - * Just get the irq number. If dynamic irq is not supported - * vectors have also been allocated. + /* The vector at index 0 is always statically allocated. If + * dynamic irq is not supported all vectors are statically + * allocated. In both cases just get the irq number and set + * the index. */ irq->map.virq = pci_irq_vector(dev->pdev, i); - irq->map.index = 0; + irq->map.index = i; } else { irq->map = pci_msix_alloc_irq_at(dev->pdev, MSI_ANY_INDEX, af_desc); if (!irq->map.virq) { @@ -276,11 +278,11 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i, } irq->pool = pool; irq->refcount = 1; - irq->map.index = i; - err = xa_err(xa_store(&pool->irqs, irq->map.index, irq, GFP_KERNEL)); + irq->pool_index = i; + err = xa_err(xa_store(&pool->irqs, irq->pool_index, irq, GFP_KERNEL)); if (err) { mlx5_core_err(dev, "Failed to alloc xa entry for irq(%u). err = %d\n", - irq->map.index, err); + irq->pool_index, err); goto err_xa; } return irq; @@ -567,13 +569,13 @@ int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs, struct mlx5_irq *irq; int i; - af_desc.is_managed = 1; + af_desc.is_managed = false; for (i = 0; i < nirqs; i++) { + cpumask_clear(&af_desc.mask); cpumask_set_cpu(cpus[i], &af_desc.mask); irq = mlx5_irq_request(dev, i + 1, &af_desc, rmap); if (IS_ERR(irq)) break; - cpumask_clear(&af_desc.mask); irqs[i] = irq; } @@ -691,6 +693,24 @@ static void irq_pools_destroy(struct mlx5_irq_table *table) irq_pool_free(table->pcif_pool); } +static void mlx5_irq_pool_free_irqs(struct mlx5_irq_pool *pool) +{ + struct mlx5_irq *irq; + unsigned long index; + + xa_for_each(&pool->irqs, index, irq) + free_irq(irq->map.virq, &irq->nh); +} + +static void mlx5_irq_pools_free_irqs(struct mlx5_irq_table *table) +{ + if (table->sf_ctrl_pool) { + mlx5_irq_pool_free_irqs(table->sf_comp_pool); + mlx5_irq_pool_free_irqs(table->sf_ctrl_pool); + } + mlx5_irq_pool_free_irqs(table->pcif_pool); +} + /* irq_table API */ int mlx5_irq_table_init(struct mlx5_core_dev *dev) @@ -774,6 +794,17 @@ void mlx5_irq_table_destroy(struct mlx5_core_dev *dev) pci_free_irq_vectors(dev->pdev); } +void mlx5_irq_table_free_irqs(struct mlx5_core_dev *dev) +{ + struct mlx5_irq_table *table = dev->priv.irq_table; + + if (mlx5_core_is_sf(dev)) + return; + + mlx5_irq_pools_free_irqs(table); + pci_free_irq_vectors(dev->pdev); +} + int mlx5_irq_table_get_sfs_vec(struct mlx5_irq_table *table) { if (table->sf_comp_pool) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c index e2f26d0bc615..0692363cf80e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c @@ -63,6 +63,7 @@ static void mlx5_sf_dev_remove(struct auxiliary_device *adev) struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); struct devlink *devlink = priv_to_devlink(sf_dev->mdev); + mlx5_drain_health_wq(sf_dev->mdev); devlink_unregister(devlink); mlx5_uninit_one(sf_dev->mdev); iounmap(sf_dev->mdev->iseg); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c index 3835ba3f4dda..1aa525e509f1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c @@ -117,6 +117,8 @@ int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, caps->gvmi = MLX5_CAP_GEN(mdev, vhca_id); caps->flex_protocols = MLX5_CAP_GEN(mdev, flex_parser_protocols); caps->sw_format_ver = MLX5_CAP_GEN(mdev, steering_format_version); + caps->roce_caps.fl_rc_qp_when_roce_disabled = + MLX5_CAP_GEN(mdev, fl_rc_qp_when_roce_disabled); if (MLX5_CAP_GEN(mdev, roce)) { err = dr_cmd_query_nic_vport_roce_en(mdev, 0, &roce_en); @@ -124,7 +126,7 @@ int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, return err; caps->roce_caps.roce_en = roce_en; - caps->roce_caps.fl_rc_qp_when_roce_disabled = + caps->roce_caps.fl_rc_qp_when_roce_disabled |= MLX5_CAP_ROCE(mdev, fl_rc_qp_when_roce_disabled); caps->roce_caps.fl_rc_qp_when_roce_enabled = MLX5_CAP_ROCE(mdev, fl_rc_qp_when_roce_enabled); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c index 13e06a6a6b22..d6947fe13d56 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c @@ -213,6 +213,8 @@ struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn) } INIT_LIST_HEAD(&mgr->ptrn_list); + mutex_init(&mgr->modify_hdr_mutex); + return mgr; free_mgr: @@ -237,5 +239,6 @@ void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr) } mlx5dr_icm_pool_destroy(mgr->ptrn_icm_pool); + mutex_destroy(&mgr->modify_hdr_mutex); kfree(mgr); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c index 9413aaf51251..e94fbb015efa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c @@ -15,7 +15,8 @@ static u32 dr_ste_crc32_calc(const void *input_data, size_t length) { u32 crc = crc32(0, input_data, length); - return (__force u32)htonl(crc); + return (__force u32)((crc >> 24) & 0xff) | ((crc << 8) & 0xff0000) | + ((crc >> 8) & 0xff00) | ((crc << 24) & 0xff000000); } bool mlx5dr_ste_supp_ttl_cs_recalc(struct mlx5dr_cmd_caps *caps) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c index afa3b92a6905..0d5a41a2ae01 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c @@ -245,12 +245,6 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) skb = priv->rx_skb[rx_pi_rem]; - skb_put(skb, datalen); - - skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ - - skb->protocol = eth_type_trans(skb, netdev); - /* Alloc another RX SKB for this same index */ rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, &rx_buf_dma, DMA_FROM_DEVICE); @@ -259,6 +253,13 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) priv->rx_skb[rx_pi_rem] = rx_skb; dma_unmap_single(priv->dev, *rx_wqe_addr, MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + + skb_put(skb, datalen); + + skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ + + skb->protocol = eth_type_trans(skb, netdev); + *rx_wqe_addr = rx_buf_dma; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { priv->stats.rx_mac_errors++; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 2b6e046e1d10..ee2698698d71 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -1039,6 +1039,16 @@ static int lan966x_reset_switch(struct lan966x *lan966x) reset_control_reset(switch_reset); + /* Don't reinitialize the switch core, if it is already initialized. In + * case it is initialized twice, some pointers inside the queue system + * in HW will get corrupted and then after a while the queue system gets + * full and no traffic is passing through the switch. The issue is seen + * when loading and unloading the driver and sending traffic through the + * switch. + */ + if (lan_rd(lan966x, SYS_RESET_CFG) & SYS_RESET_CFG_CORE_ENA) + return 0; + lan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan966x, SYS_RESET_CFG); lan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan966x, SYS_RAM_INIT); ret = readx_poll_timeout(lan966x_ram_init, lan966x, diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 06d6292e09b3..d907727c7b7a 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -1279,8 +1279,6 @@ static void mana_poll_tx_cq(struct mana_cq *cq) if (comp_read < 1) return; - apc->eth_stats.tx_cqes = comp_read; - for (i = 0; i < comp_read; i++) { struct mana_tx_comp_oob *cqe_oob; @@ -1363,8 +1361,6 @@ static void mana_poll_tx_cq(struct mana_cq *cq) WARN_ON_ONCE(1); cq->work_done = pkt_transmitted; - - apc->eth_stats.tx_cqes -= pkt_transmitted; } static void mana_post_pkt_rxq(struct mana_rxq *rxq) @@ -1626,15 +1622,11 @@ static void mana_poll_rx_cq(struct mana_cq *cq) { struct gdma_comp *comp = cq->gdma_comp_buf; struct mana_rxq *rxq = cq->rxq; - struct mana_port_context *apc; int comp_read, i; - apc = netdev_priv(rxq->ndev); - comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER); WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER); - apc->eth_stats.rx_cqes = comp_read; rxq->xdp_flush = false; for (i = 0; i < comp_read; i++) { @@ -1646,8 +1638,6 @@ static void mana_poll_rx_cq(struct mana_cq *cq) return; mana_process_rx_cqe(rxq, cq, &comp[i]); - - apc->eth_stats.rx_cqes--; } if (rxq->xdp_flush) diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index a64c81410dc1..0dc78679f620 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -13,11 +13,9 @@ static const struct { } mana_eth_stats[] = { {"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)}, {"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)}, - {"tx_cqes", offsetof(struct mana_ethtool_stats, tx_cqes)}, {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)}, {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, tx_cqe_unknown_type)}, - {"rx_cqes", offsetof(struct mana_ethtool_stats, rx_cqes)}, {"rx_coalesced_err", offsetof(struct mana_ethtool_stats, rx_coalesced_err)}, {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, diff --git a/drivers/net/ethernet/mscc/vsc7514_regs.c b/drivers/net/ethernet/mscc/vsc7514_regs.c index ef6fd3f6be30..5595bfe84bbb 100644 --- a/drivers/net/ethernet/mscc/vsc7514_regs.c +++ b/drivers/net/ethernet/mscc/vsc7514_regs.c @@ -307,15 +307,15 @@ static const u32 vsc7514_sys_regmap[] = { REG(SYS_COUNT_DROP_YELLOW_PRIO_4, 0x000218), REG(SYS_COUNT_DROP_YELLOW_PRIO_5, 0x00021c), REG(SYS_COUNT_DROP_YELLOW_PRIO_6, 0x000220), - REG(SYS_COUNT_DROP_YELLOW_PRIO_7, 0x000214), - REG(SYS_COUNT_DROP_GREEN_PRIO_0, 0x000218), - REG(SYS_COUNT_DROP_GREEN_PRIO_1, 0x00021c), - REG(SYS_COUNT_DROP_GREEN_PRIO_2, 0x000220), - REG(SYS_COUNT_DROP_GREEN_PRIO_3, 0x000224), - REG(SYS_COUNT_DROP_GREEN_PRIO_4, 0x000228), - REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00022c), - REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000230), - REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000234), + REG(SYS_COUNT_DROP_YELLOW_PRIO_7, 0x000224), + REG(SYS_COUNT_DROP_GREEN_PRIO_0, 0x000228), + REG(SYS_COUNT_DROP_GREEN_PRIO_1, 0x00022c), + REG(SYS_COUNT_DROP_GREEN_PRIO_2, 0x000230), + REG(SYS_COUNT_DROP_GREEN_PRIO_3, 0x000234), + REG(SYS_COUNT_DROP_GREEN_PRIO_4, 0x000238), + REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00023c), + REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000240), + REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000244), REG(SYS_RESET_CFG, 0x000508), REG(SYS_CMID, 0x00050c), REG(SYS_VLAN_ETYPE_CFG, 0x000510), diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.h b/drivers/net/ethernet/netronome/nfp/nic/main.h index 094374df42b8..38b8b10b03cd 100644 --- a/drivers/net/ethernet/netronome/nfp/nic/main.h +++ b/drivers/net/ethernet/netronome/nfp/nic/main.h @@ -8,7 +8,7 @@ #ifdef CONFIG_DCB /* DCB feature definitions */ -#define NFP_NET_MAX_DSCP 4 +#define NFP_NET_MAX_DSCP 64 #define NFP_NET_MAX_TC IEEE_8021QAZ_MAX_TCS #define NFP_NET_MAX_PRIO 8 #define NFP_DCB_CFG_STRIDE 256 diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 0605d1ee490d..7a549b834e97 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -6138,6 +6138,7 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) return 0; out_error: + nv_mgmt_release_sema(dev); if (phystate_orig) writel(phystate|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); out_freering: diff --git a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c index e6ff757895ab..4ec66a6be073 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c @@ -61,6 +61,8 @@ struct ionic *ionic_devlink_alloc(struct device *dev) struct devlink *dl; dl = devlink_alloc(&ionic_dl_ops, sizeof(struct ionic), dev); + if (!dl) + return NULL; return devlink_priv(dl); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index cf33503468a3..9b2b96fa36af 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -794,7 +794,7 @@ static int ionic_get_rxnfc(struct net_device *netdev, info->data = lif->nxqs; break; default: - netdev_err(netdev, "Command parameter %d is not supported\n", + netdev_dbg(netdev, "Command parameter %d is not supported\n", info->cmd); err = -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a7e376e7e689..4b19803a7dd0 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -616,10 +616,10 @@ struct rtl8169_private { struct work_struct work; } wk; - spinlock_t config25_lock; - spinlock_t mac_ocp_lock; + raw_spinlock_t config25_lock; + raw_spinlock_t mac_ocp_lock; - spinlock_t cfg9346_usage_lock; + raw_spinlock_t cfg9346_usage_lock; int cfg9346_usage_count; unsigned supports_gmii:1; @@ -671,20 +671,20 @@ static void rtl_lock_config_regs(struct rtl8169_private *tp) { unsigned long flags; - spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); + raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); if (!--tp->cfg9346_usage_count) RTL_W8(tp, Cfg9346, Cfg9346_Lock); - spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); } static void rtl_unlock_config_regs(struct rtl8169_private *tp) { unsigned long flags; - spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); + raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); if (!tp->cfg9346_usage_count++) RTL_W8(tp, Cfg9346, Cfg9346_Unlock); - spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); } static void rtl_pci_commit(struct rtl8169_private *tp) @@ -698,10 +698,10 @@ static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) unsigned long flags; u8 val; - spin_lock_irqsave(&tp->config25_lock, flags); + raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config2); RTL_W8(tp, Config2, (val & ~clear) | set); - spin_unlock_irqrestore(&tp->config25_lock, flags); + raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) @@ -709,10 +709,10 @@ static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) unsigned long flags; u8 val; - spin_lock_irqsave(&tp->config25_lock, flags); + raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config5); RTL_W8(tp, Config5, (val & ~clear) | set); - spin_unlock_irqrestore(&tp->config25_lock, flags); + raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static bool rtl_is_8125(struct rtl8169_private *tp) @@ -899,9 +899,9 @@ static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data) { unsigned long flags; - spin_lock_irqsave(&tp->mac_ocp_lock, flags); + raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags); __r8168_mac_ocp_write(tp, reg, data); - spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); + raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); } static u16 __r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg) @@ -919,9 +919,9 @@ static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg) unsigned long flags; u16 val; - spin_lock_irqsave(&tp->mac_ocp_lock, flags); + raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags); val = __r8168_mac_ocp_read(tp, reg); - spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); + raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); return val; } @@ -932,10 +932,10 @@ static void r8168_mac_ocp_modify(struct rtl8169_private *tp, u32 reg, u16 mask, unsigned long flags; u16 data; - spin_lock_irqsave(&tp->mac_ocp_lock, flags); + raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags); data = __r8168_mac_ocp_read(tp, reg); __r8168_mac_ocp_write(tp, reg, (data & ~mask) | set); - spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); + raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags); } /* Work around a hw issue with RTL8168g PHY, the quirk disables @@ -1420,14 +1420,14 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); } - spin_lock_irqsave(&tp->config25_lock, flags); + raw_spin_lock_irqsave(&tp->config25_lock, flags); for (i = 0; i < tmp; i++) { options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; if (wolopts & cfg[i].opt) options |= cfg[i].mask; RTL_W8(tp, cfg[i].reg, options); } - spin_unlock_irqrestore(&tp->config25_lock, flags); + raw_spin_unlock_irqrestore(&tp->config25_lock, flags); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: @@ -5179,9 +5179,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->eee_adv = -1; tp->ocp_base = OCP_STD_PHY_BASE; - spin_lock_init(&tp->cfg9346_usage_lock); - spin_lock_init(&tp->config25_lock); - spin_lock_init(&tp->mac_ocp_lock); + raw_spin_lock_init(&tp->cfg9346_usage_lock); + raw_spin_lock_init(&tp->config25_lock); + raw_spin_lock_init(&tp->mac_ocp_lock); dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, struct pcpu_sw_netstats); diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 29afaddb598d..aace87139cea 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1485,7 +1485,7 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - 1) { netif_stop_subqueue(ndev, 0); - return ret; + return NETDEV_TX_BUSY; } if (skb_put_padto(skb, ETH_ZLEN)) diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c index d916877b5a9a..be395cd8770b 100644 --- a/drivers/net/ethernet/sfc/ef100_netdev.c +++ b/drivers/net/ethernet/sfc/ef100_netdev.c @@ -378,7 +378,9 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data) efx->net_dev = net_dev; SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); - net_dev->features |= efx->type->offload_features; + /* enable all supported features except rx-fcs and rx-all */ + net_dev->features |= efx->type->offload_features & + ~(NETIF_F_RXFCS | NETIF_F_RXALL); net_dev->hw_features |= efx->type->offload_features; net_dev->hw_enc_features |= efx->type->offload_features; net_dev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_SG | diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c index 381b805659d3..ef9971cbb695 100644 --- a/drivers/net/ethernet/sfc/efx_devlink.c +++ b/drivers/net/ethernet/sfc/efx_devlink.c @@ -171,9 +171,14 @@ static int efx_devlink_info_nvram_partition(struct efx_nic *efx, rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL, 0); + + /* If the partition does not exist, that is not an error. */ + if (rc == -ENOENT) + return 0; + if (rc) { - netif_err(efx, drv, efx->net_dev, "mcdi nvram %s: failed\n", - version_name); + netif_err(efx, drv, efx->net_dev, "mcdi nvram %s: failed (rc=%d)\n", + version_name, rc); return rc; } @@ -187,36 +192,33 @@ static int efx_devlink_info_nvram_partition(struct efx_nic *efx, static int efx_devlink_info_stored_versions(struct efx_nic *efx, struct devlink_info_req *req) { - int rc; + int err; - rc = efx_devlink_info_nvram_partition(efx, req, - NVRAM_PARTITION_TYPE_BUNDLE, - DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID); - if (rc) - return rc; + /* We do not care here about the specific error but just if an error + * happened. The specific error will be reported inside the call + * through system messages, and if any error happened in any call + * below, we report it through extack. + */ + err = efx_devlink_info_nvram_partition(efx, req, + NVRAM_PARTITION_TYPE_BUNDLE, + DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID); - rc = efx_devlink_info_nvram_partition(efx, req, - NVRAM_PARTITION_TYPE_MC_FIRMWARE, - DEVLINK_INFO_VERSION_GENERIC_FW_MGMT); - if (rc) - return rc; + err |= efx_devlink_info_nvram_partition(efx, req, + NVRAM_PARTITION_TYPE_MC_FIRMWARE, + DEVLINK_INFO_VERSION_GENERIC_FW_MGMT); - rc = efx_devlink_info_nvram_partition(efx, req, - NVRAM_PARTITION_TYPE_SUC_FIRMWARE, - EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC); - if (rc) - return rc; + err |= efx_devlink_info_nvram_partition(efx, req, + NVRAM_PARTITION_TYPE_SUC_FIRMWARE, + EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC); - rc = efx_devlink_info_nvram_partition(efx, req, - NVRAM_PARTITION_TYPE_EXPANSION_ROM, - EFX_DEVLINK_INFO_VERSION_FW_EXPROM); - if (rc) - return rc; + err |= efx_devlink_info_nvram_partition(efx, req, + NVRAM_PARTITION_TYPE_EXPANSION_ROM, + EFX_DEVLINK_INFO_VERSION_FW_EXPROM); - rc = efx_devlink_info_nvram_partition(efx, req, - NVRAM_PARTITION_TYPE_EXPANSION_UEFI, - EFX_DEVLINK_INFO_VERSION_FW_UEFI); - return rc; + err |= efx_devlink_info_nvram_partition(efx, req, + NVRAM_PARTITION_TYPE_EXPANSION_UEFI, + EFX_DEVLINK_INFO_VERSION_FW_UEFI); + return err; } #define EFX_VER_FLAG(_f) \ @@ -587,27 +589,20 @@ static int efx_devlink_info_get(struct devlink *devlink, { struct efx_devlink *devlink_private = devlink_priv(devlink); struct efx_nic *efx = devlink_private->efx; - int rc; + int err; - /* Several different MCDI commands are used. We report first error - * through extack returning at that point. Specific error - * information via system messages. + /* Several different MCDI commands are used. We report if errors + * happened through extack. Specific error information via system + * messages inside the calls. */ - rc = efx_devlink_info_board_cfg(efx, req); - if (rc) { - NL_SET_ERR_MSG_MOD(extack, "Getting board info failed"); - return rc; - } - rc = efx_devlink_info_stored_versions(efx, req); - if (rc) { - NL_SET_ERR_MSG_MOD(extack, "Getting stored versions failed"); - return rc; - } - rc = efx_devlink_info_running_versions(efx, req); - if (rc) { - NL_SET_ERR_MSG_MOD(extack, "Getting running versions failed"); - return rc; - } + err = efx_devlink_info_board_cfg(efx, req); + + err |= efx_devlink_info_stored_versions(efx, req); + + err |= efx_devlink_info_running_versions(efx, req); + + if (err) + NL_SET_ERR_MSG_MOD(extack, "Errors when getting device info. Check system messages"); return 0; } diff --git a/drivers/net/ethernet/sfc/mcdi_port_common.c b/drivers/net/ethernet/sfc/mcdi_port_common.c index 899cc1671004..0ab14f3d01d4 100644 --- a/drivers/net/ethernet/sfc/mcdi_port_common.c +++ b/drivers/net/ethernet/sfc/mcdi_port_common.c @@ -972,12 +972,15 @@ static u32 efx_mcdi_phy_module_type(struct efx_nic *efx) /* A QSFP+ NIC may actually have an SFP+ module attached. * The ID is page 0, byte 0. + * QSFP28 is of type SFF_8636, however, this is treated + * the same by ethtool, so we can also treat them the same. */ switch (efx_mcdi_phy_get_module_eeprom_byte(efx, 0, 0)) { - case 0x3: + case 0x3: /* SFP */ return MC_CMD_MEDIA_SFP_PLUS; - case 0xc: - case 0xd: + case 0xc: /* QSFP */ + case 0xd: /* QSFP+ */ + case 0x11: /* QSFP28 */ return MC_CMD_MEDIA_QSFP_PLUS; default: return 0; @@ -1075,7 +1078,7 @@ int efx_mcdi_phy_get_module_info(struct efx_nic *efx, struct ethtool_modinfo *mo case MC_CMD_MEDIA_QSFP_PLUS: modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; break; default: diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 0327639a628a..c004443c1d58 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -624,13 +624,12 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, if (!found) { /* We don't care. */ netif_dbg(efx, drv, efx->net_dev, "Ignoring foreign filter that doesn't egdev us\n"); - rc = -EOPNOTSUPP; - goto release; + return -EOPNOTSUPP; } rc = efx_mae_match_check_caps(efx, &match.mask, NULL); if (rc) - goto release; + return rc; if (efx_tc_match_is_encap(&match.mask)) { enum efx_encap_type type; @@ -639,8 +638,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, if (type == EFX_ENCAP_TYPE_NONE) { NL_SET_ERR_MSG_MOD(extack, "Egress encap match on unsupported tunnel device"); - rc = -EOPNOTSUPP; - goto release; + return -EOPNOTSUPP; } rc = efx_mae_check_encap_type_supported(efx, type); @@ -648,25 +646,24 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, NL_SET_ERR_MSG_FMT_MOD(extack, "Firmware reports no support for %s encap match", efx_tc_encap_type_name(type)); - goto release; + return rc; } rc = efx_tc_flower_record_encap_match(efx, &match, type, extack); if (rc) - goto release; + return rc; } else { /* This is not a tunnel decap rule, ignore it */ netif_dbg(efx, drv, efx->net_dev, "Ignoring foreign filter without encap match\n"); - rc = -EOPNOTSUPP; - goto release; + return -EOPNOTSUPP; } rule = kzalloc(sizeof(*rule), GFP_USER); if (!rule) { rc = -ENOMEM; - goto release; + goto out_free; } INIT_LIST_HEAD(&rule->acts.list); rule->cookie = tc->cookie; @@ -678,7 +675,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, "Ignoring already-offloaded rule (cookie %lx)\n", tc->cookie); rc = -EEXIST; - goto release; + goto out_free; } act = kzalloc(sizeof(*act), GFP_USER); @@ -843,6 +840,7 @@ release: efx_tc_match_action_ht_params); efx_tc_free_action_set_list(efx, &rule->acts, false); } +out_free: kfree(rule); if (match.encap) efx_tc_flower_release_encap_match(efx, match.encap); @@ -899,8 +897,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, return rc; if (efx_tc_match_is_encap(&match.mask)) { NL_SET_ERR_MSG_MOD(extack, "Ingress enc_key matches not supported"); - rc = -EOPNOTSUPP; - goto release; + return -EOPNOTSUPP; } if (tc->common.chain_index) { @@ -924,9 +921,9 @@ static int efx_tc_flower_replace(struct efx_nic *efx, if (old) { netif_dbg(efx, drv, efx->net_dev, "Already offloaded rule (cookie %lx)\n", tc->cookie); - rc = -EEXIST; NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded"); - goto release; + kfree(rule); + return -EEXIST; } /* Parse actions */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 4538f334df57..d3c5306f1c41 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -181,6 +181,7 @@ enum power_event { #define GMAC4_LPI_CTRL_STATUS 0xd0 #define GMAC4_LPI_TIMER_CTRL 0xd4 #define GMAC4_LPI_ENTRY_TIMER 0xd8 +#define GMAC4_MAC_ONEUS_TIC_COUNTER 0xdc /* LPI control and status defines */ #define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT(21) /* LPI Tx Clock Stop Enable */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index afaec3fb9ab6..03b1c5a97826 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -25,6 +25,7 @@ static void dwmac4_core_init(struct mac_device_info *hw, struct stmmac_priv *priv = netdev_priv(dev); void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONFIG); + u32 clk_rate; value |= GMAC_CORE_INIT; @@ -47,6 +48,10 @@ static void dwmac4_core_init(struct mac_device_info *hw, writel(value, ioaddr + GMAC_CONFIG); + /* Configure LPI 1us counter to number of CSR clock ticks in 1us - 1 */ + clk_rate = clk_get_rate(priv->plat->stmmac_clk); + writel((clk_rate / 1000000) - 1, ioaddr + GMAC4_MAC_ONEUS_TIC_COUNTER); + /* Enable GMAC interrupts */ value = GMAC_INT_DEFAULT_ENABLE; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0fca81507a77..52cab9de05f2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7233,8 +7233,7 @@ int stmmac_dvr_probe(struct device *device, ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | - NETDEV_XDP_ACT_XSK_ZEROCOPY | - NETDEV_XDP_ACT_NDO_XMIT; + NETDEV_XDP_ACT_XSK_ZEROCOPY; ret = stmmac_tc_init(priv, priv); if (!ret) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c index 9d4d8c3dad0a..aa6f16d3df64 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c @@ -117,6 +117,9 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog, return -EOPNOTSUPP; } + if (!prog) + xdp_features_clear_redirect_target(dev); + need_update = !!priv->xdp_prog != !!prog; if (if_running && need_update) stmmac_xdp_release(dev); @@ -131,5 +134,8 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog, if (if_running && need_update) stmmac_xdp_open(dev); + if (prog) + xdp_features_set_redirect_target(dev, false); + return 0; } diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index 4ef05bad4613..d61dfa250feb 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -5077,6 +5077,8 @@ err_out_iounmap: cas_shutdown(cp); mutex_unlock(&cp->pm_mutex); + vfree(cp->fw_data); + pci_iounmap(pdev, cp->regs); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index dd5919ec408b..33d51e363913 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -1139,7 +1139,6 @@ struct netvsc_device { /* Receive buffer allocated by us but manages by NetVSP */ void *recv_buf; - void *recv_original_buf; u32 recv_buf_size; /* allocated bytes */ struct vmbus_gpadl recv_buf_gpadl_handle; u32 recv_section_cnt; @@ -1148,7 +1147,6 @@ struct netvsc_device { /* Send buffer allocated by us */ void *send_buf; - void *send_original_buf; u32 send_buf_size; struct vmbus_gpadl send_buf_gpadl_handle; u32 send_section_cnt; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index da737d959e81..82e9796c8f5e 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -154,17 +154,8 @@ static void free_netvsc_device(struct rcu_head *head) int i; kfree(nvdev->extension); - - if (nvdev->recv_original_buf) - vfree(nvdev->recv_original_buf); - else - vfree(nvdev->recv_buf); - - if (nvdev->send_original_buf) - vfree(nvdev->send_original_buf); - else - vfree(nvdev->send_buf); - + vfree(nvdev->recv_buf); + vfree(nvdev->send_buf); bitmap_free(nvdev->send_section_map); for (i = 0; i < VRSS_CHANNEL_MAX; i++) { @@ -347,7 +338,6 @@ static int netvsc_init_buf(struct hv_device *device, struct nvsp_message *init_packet; unsigned int buf_size; int i, ret = 0; - void *vaddr; /* Get receive buffer area. */ buf_size = device_info->recv_sections * device_info->recv_section_size; @@ -383,17 +373,6 @@ static int netvsc_init_buf(struct hv_device *device, goto cleanup; } - if (hv_isolation_type_snp()) { - vaddr = hv_map_memory(net_device->recv_buf, buf_size); - if (!vaddr) { - ret = -ENOMEM; - goto cleanup; - } - - net_device->recv_original_buf = net_device->recv_buf; - net_device->recv_buf = vaddr; - } - /* Notify the NetVsp of the gpadl handle */ init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); @@ -497,17 +476,6 @@ static int netvsc_init_buf(struct hv_device *device, goto cleanup; } - if (hv_isolation_type_snp()) { - vaddr = hv_map_memory(net_device->send_buf, buf_size); - if (!vaddr) { - ret = -ENOMEM; - goto cleanup; - } - - net_device->send_original_buf = net_device->send_buf; - net_device->send_buf = vaddr; - } - /* Notify the NetVsp of the gpadl handle */ init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); @@ -762,12 +730,6 @@ void netvsc_device_remove(struct hv_device *device) netvsc_teardown_send_gpadl(device, net_device, ndev); } - if (net_device->recv_original_buf) - hv_unmap_memory(net_device->recv_buf); - - if (net_device->send_original_buf) - hv_unmap_memory(net_device->send_buf); - /* Release all resources */ free_netvsc_device_rcu(net_device); } @@ -1844,12 +1806,6 @@ cleanup: netif_napi_del(&net_device->chan_table[0].napi); cleanup2: - if (net_device->recv_original_buf) - hv_unmap_memory(net_device->recv_buf); - - if (net_device->send_original_buf) - hv_unmap_memory(net_device->send_buf); - free_netvsc_device(&net_device->rcu); return ERR_PTR(ret); diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 2ee80ed140b7..afa1d56d9095 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -119,7 +119,7 @@ enum ipa_status_field_id { }; /* Size in bytes of an IPA packet status structure */ -#define IPA_STATUS_SIZE sizeof(__le32[4]) +#define IPA_STATUS_SIZE sizeof(__le32[8]) /* IPA status structure decoder; looks up field values for a structure */ static u32 ipa_status_extract(struct ipa *ipa, const void *data, diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 460b3d4f2245..ab5133eb1d51 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -436,6 +436,9 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb) goto err; } skb_dst_set(skb, &rt->dst); + + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + err = ip_local_out(net, skb->sk, skb); if (unlikely(net_xmit_eval(err))) dev->stats.tx_errors++; @@ -474,6 +477,9 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) goto err; } skb_dst_set(skb, dst); + + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); + err = ip6_local_out(net, skb->sk, skb); if (unlikely(net_xmit_eval(err))) dev->stats.tx_errors++; diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c index dde272586e80..60944a4beada 100644 --- a/drivers/net/ipvlan/ipvtap.c +++ b/drivers/net/ipvlan/ipvtap.c @@ -38,7 +38,6 @@ static const void *ipvtap_net_namespace(const struct device *d) static struct class ipvtap_class = { .name = "ipvtap", - .owner = THIS_MODULE, .ns_type = &net_ns_type_operations, .namespace = ipvtap_net_namespace, }; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 031344239f27..bddcc127812e 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -43,7 +43,6 @@ static const void *macvtap_net_namespace(const struct device *d) static struct class macvtap_class = { .name = "macvtap", - .owner = THIS_MODULE, .ns_type = &net_ns_type_operations, .namespace = macvtap_net_namespace, }; diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c index 1e0c206d0f2e..da2001ea1f99 100644 --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -291,7 +291,8 @@ static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd, return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); } -static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) +static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int devad, + int reg) { u8 buf[4], res[6]; int bus_addr, ret; @@ -302,7 +303,7 @@ static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) return 0xffff; buf[0] = ROLLBALL_DATA_ADDR; - buf[1] = (reg >> 16) & 0x1f; + buf[1] = devad; buf[2] = (reg >> 8) & 0xff; buf[3] = reg & 0xff; @@ -322,8 +323,8 @@ static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) return val; } -static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg, - u16 val) +static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad, + int reg, u16 val) { int bus_addr, ret; u8 buf[6]; @@ -333,7 +334,7 @@ static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg, return 0; buf[0] = ROLLBALL_DATA_ADDR; - buf[1] = (reg >> 16) & 0x1f; + buf[1] = devad; buf[2] = (reg >> 8) & 0xff; buf[3] = reg & 0xff; buf[4] = val >> 8; @@ -405,8 +406,8 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, return ERR_PTR(ret); } - mii->read = i2c_mii_read_rollball; - mii->write = i2c_mii_write_rollball; + mii->read_c45 = i2c_mii_read_rollball; + mii->write_c45 = i2c_mii_write_rollball; break; default: mii->read = i2c_mii_read_default_c22; diff --git a/drivers/net/mdio/mdio-mvusb.c b/drivers/net/mdio/mdio-mvusb.c index 68fc55906e78..554837c21e73 100644 --- a/drivers/net/mdio/mdio-mvusb.c +++ b/drivers/net/mdio/mdio-mvusb.c @@ -67,6 +67,7 @@ static int mvusb_mdio_probe(struct usb_interface *interface, struct device *dev = &interface->dev; struct mvusb_mdio *mvusb; struct mii_bus *mdio; + int ret; mdio = devm_mdiobus_alloc_size(dev, sizeof(*mvusb)); if (!mdio) @@ -87,7 +88,15 @@ static int mvusb_mdio_probe(struct usb_interface *interface, mdio->write = mvusb_mdio_write; usb_set_intfdata(interface, mvusb); - return of_mdiobus_register(mdio, dev->of_node); + ret = of_mdiobus_register(mdio, dev->of_node); + if (ret) + goto put_dev; + + return 0; + +put_dev: + usb_put_dev(mvusb->udev); + return ret; } static void mvusb_mdio_disconnect(struct usb_interface *interface) diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 0052968e881e..0787ad252dd9 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -132,7 +132,7 @@ static struct nsim_bus_dev * nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues); static ssize_t -new_device_store(struct bus_type *bus, const char *buf, size_t count) +new_device_store(const struct bus_type *bus, const char *buf, size_t count) { unsigned int id, port_count, num_queues; struct nsim_bus_dev *nsim_bus_dev; @@ -186,7 +186,7 @@ static BUS_ATTR_WO(new_device); static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); static ssize_t -del_device_store(struct bus_type *bus, const char *buf, size_t count) +del_device_store(const struct bus_type *bus, const char *buf, size_t count) { struct nsim_bus_dev *nsim_bus_dev, *tmp; unsigned int id; diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 539cd43eae8d..72f25e778840 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -873,7 +873,7 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, switch (compat->an_mode) { case DW_AN_C73: - if (phylink_autoneg_inband(mode)) { + if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) { ret = xpcs_config_aneg_c73(xpcs, compat); if (ret) return ret; @@ -1203,7 +1203,7 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { [DW_XPCS_2500BASEX] = { .supported = xpcs_2500basex_features, .interface = xpcs_2500basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_2500basex_features), + .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, }, }; diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 9902fb182099..729db441797a 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -40,6 +40,11 @@ static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); } +static inline int bcm_phy_read_exp_sel(struct phy_device *phydev, u16 reg) +{ + return bcm_phy_read_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER); +} + int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val); int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum); diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 06be71ecd2f8..f8c17a253f8b 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -486,7 +486,7 @@ static int bcm7xxx_16nm_ephy_afe_config(struct phy_device *phydev) bcm_phy_write_misc(phydev, 0x0038, 0x0002, 0xede0); /* Read CORE_EXPA9 */ - tmp = bcm_phy_read_exp(phydev, 0x00a9); + tmp = bcm_phy_read_exp_sel(phydev, 0x00a9); /* CORE_EXPA9[6:1] is rcalcode[5:0] */ rcalcode = (tmp & 0x7e) / 2; /* Correct RCAL code + 1 is -1% rprogr, LP: +16 */ diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index d75f526a20a4..76f5a2402fb0 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -44,6 +44,7 @@ #define DP83867_STRAP_STS1 0x006E #define DP83867_STRAP_STS2 0x006f #define DP83867_RGMIIDCTL 0x0086 +#define DP83867_DSP_FFE_CFG 0x012c #define DP83867_RXFCFG 0x0134 #define DP83867_RXFPMD1 0x0136 #define DP83867_RXFPMD2 0x0137 @@ -941,8 +942,27 @@ static int dp83867_phy_reset(struct phy_device *phydev) usleep_range(10, 20); - return phy_modify(phydev, MII_DP83867_PHYCTRL, + err = phy_modify(phydev, MII_DP83867_PHYCTRL, DP83867_PHYCR_FORCE_LINK_GOOD, 0); + if (err < 0) + return err; + + /* Configure the DSP Feedforward Equalizer Configuration register to + * improve short cable (< 1 meter) performance. This will not affect + * long cable performance. + */ + err = phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_DSP_FFE_CFG, + 0x0e81); + if (err < 0) + return err; + + err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESTART); + if (err < 0) + return err; + + usleep_range(10, 20); + + return 0; } static void dp83867_link_change_notify(struct phy_device *phydev) diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h index a50235fdf7d9..defe5cc6d4fc 100644 --- a/drivers/net/phy/mscc/mscc.h +++ b/drivers/net/phy/mscc/mscc.h @@ -179,6 +179,7 @@ enum rgmii_clock_delay { #define VSC8502_RGMII_CNTL 20 #define VSC8502_RGMII_RX_DELAY_MASK 0x0070 #define VSC8502_RGMII_TX_DELAY_MASK 0x0007 +#define VSC8502_RGMII_RX_CLK_DISABLE 0x0800 #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21 #define MSCC_PHY_WOL_MID_MAC_ADDR 22 @@ -276,6 +277,7 @@ enum rgmii_clock_delay { /* Microsemi PHY ID's * Code assumes lowest nibble is 0 */ +#define PHY_ID_VSC8501 0x00070530 #define PHY_ID_VSC8502 0x00070630 #define PHY_ID_VSC8504 0x000704c0 #define PHY_ID_VSC8514 0x00070670 diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 62bf99e45af1..28df8a2e4230 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -519,16 +519,27 @@ out_unlock: * * 2.0 ns (which causes the data to be sampled at exactly half way between * clock transitions at 1000 Mbps) if delays should be enabled */ -static int vsc85xx_rgmii_set_skews(struct phy_device *phydev, u32 rgmii_cntl, - u16 rgmii_rx_delay_mask, - u16 rgmii_tx_delay_mask) +static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl, + u16 rgmii_rx_delay_mask, + u16 rgmii_tx_delay_mask) { u16 rgmii_rx_delay_pos = ffs(rgmii_rx_delay_mask) - 1; u16 rgmii_tx_delay_pos = ffs(rgmii_tx_delay_mask) - 1; u16 reg_val = 0; - int rc; + u16 mask = 0; + int rc = 0; - mutex_lock(&phydev->lock); + /* For traffic to pass, the VSC8502 family needs the RX_CLK disable bit + * to be unset for all PHY modes, so do that as part of the paged + * register modification. + * For some family members (like VSC8530/31/40/41) this bit is reserved + * and read-only, and the RX clock is enabled by default. + */ + if (rgmii_cntl == VSC8502_RGMII_CNTL) + mask |= VSC8502_RGMII_RX_CLK_DISABLE; + + if (phy_interface_is_rgmii(phydev)) + mask |= rgmii_rx_delay_mask | rgmii_tx_delay_mask; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) @@ -537,31 +548,20 @@ static int vsc85xx_rgmii_set_skews(struct phy_device *phydev, u32 rgmii_cntl, phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_tx_delay_pos; - rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, - rgmii_cntl, - rgmii_rx_delay_mask | rgmii_tx_delay_mask, - reg_val); - - mutex_unlock(&phydev->lock); + if (mask) + rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, + rgmii_cntl, mask, reg_val); return rc; } static int vsc85xx_default_config(struct phy_device *phydev) { - int rc; - phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - if (phy_interface_mode_is_rgmii(phydev->interface)) { - rc = vsc85xx_rgmii_set_skews(phydev, VSC8502_RGMII_CNTL, - VSC8502_RGMII_RX_DELAY_MASK, - VSC8502_RGMII_TX_DELAY_MASK); - if (rc) - return rc; - } - - return 0; + return vsc85xx_update_rgmii_cntl(phydev, VSC8502_RGMII_CNTL, + VSC8502_RGMII_RX_DELAY_MASK, + VSC8502_RGMII_TX_DELAY_MASK); } static int vsc85xx_get_tunable(struct phy_device *phydev, @@ -1758,13 +1758,11 @@ static int vsc8584_config_init(struct phy_device *phydev) if (ret) return ret; - if (phy_interface_is_rgmii(phydev)) { - ret = vsc85xx_rgmii_set_skews(phydev, VSC8572_RGMII_CNTL, - VSC8572_RGMII_RX_DELAY_MASK, - VSC8572_RGMII_TX_DELAY_MASK); - if (ret) - return ret; - } + ret = vsc85xx_update_rgmii_cntl(phydev, VSC8572_RGMII_CNTL, + VSC8572_RGMII_RX_DELAY_MASK, + VSC8572_RGMII_TX_DELAY_MASK); + if (ret) + return ret; ret = genphy_soft_reset(phydev); if (ret) @@ -2316,6 +2314,30 @@ static int vsc85xx_probe(struct phy_device *phydev) /* Microsemi VSC85xx PHYs */ static struct phy_driver vsc85xx_driver[] = { +{ + .phy_id = PHY_ID_VSC8501, + .name = "Microsemi GE VSC8501 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_BASIC_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc85xx_config_init, + .config_aneg = &vsc85xx_config_aneg, + .read_status = &vsc85xx_read_status, + .handle_interrupt = vsc85xx_handle_interrupt, + .config_intr = &vsc85xx_config_intr, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc85xx_probe, + .set_wol = &vsc85xx_wol_set, + .get_wol = &vsc85xx_wol_get, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, { .phy_id = PHY_ID_VSC8502, .name = "Microsemi GE VSC8502 SyncE", @@ -2656,6 +2678,8 @@ static struct phy_driver vsc85xx_driver[] = { module_phy_driver(vsc85xx_driver); static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { + { PHY_ID_VSC8501, 0xfffffff0, }, + { PHY_ID_VSC8502, 0xfffffff0, }, { PHY_ID_VSC8504, 0xfffffff0, }, { PHY_ID_VSC8514, 0xfffffff0, }, { PHY_ID_VSC8530, 0xfffffff0, }, diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index 6301a9abfb95..ea1073adc5a1 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -274,13 +274,6 @@ static int gpy_config_init(struct phy_device *phydev) return ret < 0 ? ret : 0; } -static bool gpy_has_broken_mdint(struct phy_device *phydev) -{ - /* At least these PHYs are known to have broken interrupt handling */ - return phydev->drv->phy_id == PHY_ID_GPY215B || - phydev->drv->phy_id == PHY_ID_GPY215C; -} - static int gpy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -300,8 +293,7 @@ static int gpy_probe(struct phy_device *phydev) phydev->priv = priv; mutex_init(&priv->mbox_lock); - if (gpy_has_broken_mdint(phydev) && - !device_property_present(dev, "maxlinear,use-broken-interrupts")) + if (!device_property_present(dev, "maxlinear,use-broken-interrupts")) phydev->dev_flags |= PHY_F_NO_IRQ; fw_version = phy_read(phydev, PHY_FWV); @@ -659,11 +651,9 @@ static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev) * frame. Therefore, polling is the best we can do and won't do any more * harm. * It was observed that this bug happens on link state and link speed - * changes on a GPY215B and GYP215C independent of the firmware version - * (which doesn't mean that this list is exhaustive). + * changes independent of the firmware version. */ - if (gpy_has_broken_mdint(phydev) && - (reg & (PHY_IMASK_LSTC | PHY_IMASK_LSPC))) { + if (reg & (PHY_IMASK_LSTC | PHY_IMASK_LSPC)) { reg = gpy_mbox_read(phydev, REG_GPIO0_OUT); if (reg < 0) { phy_error(phydev); diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index a4111f1be375..e237949deee6 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2225,6 +2225,10 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, ASSERT_RTNL(); + /* Mask out unsupported advertisements */ + linkmode_and(config.advertising, kset->link_modes.advertising, + pl->supported); + if (pl->phydev) { /* We can rely on phylib for this update; we also do not need * to update the pl->link_config settings: @@ -2249,10 +2253,6 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, config = pl->link_config; - /* Mask out unsupported advertisements */ - linkmode_and(config.advertising, kset->link_modes.advertising, - pl->supported); - /* FIXME: should we reject autoneg if phy/mac does not support it? */ switch (kset->base.autoneg) { case AUTONEG_DISABLE: diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 1d71f5276241..a9beacd552cf 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1394,7 +1394,7 @@ static int __init ppp_init(void) goto out_net; } - ppp_class = class_create(THIS_MODULE, "ppp"); + ppp_class = class_create("ppp"); if (IS_ERR(ppp_class)) { err = PTR_ERR(ppp_class); goto out_chrdev; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index fbcb9d05da64..4eececc94513 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -662,8 +662,7 @@ static int rionet_shutdown(struct notifier_block *nb, unsigned long code, return NOTIFY_DONE; } -static void rionet_remove_mport(struct device *dev, - struct class_interface *class_intf) +static void rionet_remove_mport(struct device *dev) { struct rio_mport *mport = to_rio_mport(dev); struct net_device *ndev; diff --git a/drivers/net/tap.c b/drivers/net/tap.c index ce993cc75bf3..d30d730ed5a7 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -742,7 +742,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control, /* Move network header to the right position for VLAN tagged packets */ if (eth_type_vlan(skb->protocol) && - __vlan_get_protocol(skb, skb->protocol, &depth) != 0) + vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0) skb_set_network_header(skb, depth); /* copy skb_ubuf_info for callback when skb has no error */ @@ -1197,7 +1197,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) /* Move network header to the right position for VLAN tagged packets */ if (eth_type_vlan(skb->protocol) && - __vlan_get_protocol(skb, skb->protocol, &depth) != 0) + vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0) skb_set_network_header(skb, depth); rcu_read_lock(); diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index d10606f257c4..555b0b1e9a78 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1629,6 +1629,7 @@ static int team_init(struct net_device *dev) team->dev = dev; team_set_no_mode(team); + team->notifier_ctx = false; team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats); if (!team->pcpu_stats) @@ -3022,7 +3023,11 @@ static int team_device_event(struct notifier_block *unused, team_del_slave(port->team->dev, dev); break; case NETDEV_FEAT_CHANGE: - team_compute_features(port->team); + if (!port->team->notifier_ctx) { + port->team->notifier_ctx = true; + team_compute_features(port->team); + port->team->notifier_ctx = false; + } break; case NETDEV_PRECHANGEMTU: /* Forbid to change mtu of underlaying device */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d4d0a41a905a..d75456adc62a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1977,6 +1977,14 @@ napi_busy: int queue_len; spin_lock_bh(&queue->lock); + + if (unlikely(tfile->detached)) { + spin_unlock_bh(&queue->lock); + rcu_read_unlock(); + err = -EBUSY; + goto free_skb; + } + __skb_queue_tail(queue, skb); queue_len = skb_queue_len(queue); spin_unlock(&queue->lock); @@ -2512,6 +2520,13 @@ build: if (tfile->napi_enabled) { queue = &tfile->sk.sk_write_queue; spin_lock(&queue->lock); + + if (unlikely(tfile->detached)) { + spin_unlock(&queue->lock); + kfree_skb(skb); + return -EBUSY; + } + __skb_queue_tail(queue, skb); spin_unlock(&queue->lock); ret = 1; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 6ce8f4f0c70e..db05622f1f70 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -181,9 +181,12 @@ static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx) else min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32); - max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)); - if (max == 0) + if (le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) == 0) max = CDC_NCM_NTB_MAX_SIZE_TX; /* dwNtbOutMaxSize not set */ + else + max = clamp_t(u32, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize), + USB_CDC_NCM_NTB_MIN_OUT_SIZE, + CDC_NCM_NTB_MAX_SIZE_TX); /* some devices set dwNtbOutMaxSize too low for the above default */ min = min(min, max); @@ -1244,6 +1247,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * further. */ if (skb_out == NULL) { + /* If even the smallest allocation fails, abort. */ + if (ctx->tx_curr_size == USB_CDC_NCM_NTB_MIN_OUT_SIZE) + goto alloc_failed; ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1, (unsigned)CDC_NCM_LOW_MEM_MAX_CNT); ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt; @@ -1262,13 +1268,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC); /* No allocation possible so we will abort */ - if (skb_out == NULL) { - if (skb != NULL) { - dev_kfree_skb_any(skb); - dev->net->stats.tx_dropped++; - } - goto exit_no_skb; - } + if (!skb_out) + goto alloc_failed; ctx->tx_low_mem_val--; } if (ctx->is_ndp16) { @@ -1461,6 +1462,11 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) return skb_out; +alloc_failed: + if (skb) { + dev_kfree_skb_any(skb); + dev->net->stats.tx_dropped++; + } exit_no_skb: /* Start timer, if there is a remaining non-empty skb */ if (ctx->tx_curr_skb != NULL && n > 0) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 571e37e67f9c..f1865d047971 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1325,7 +1325,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)}, /* D-Link DWM-222 A2 */ {QMI_FIXED_INTF(0x2020, 0x2031, 4)}, /* Olicard 600 */ {QMI_FIXED_INTF(0x2020, 0x2033, 4)}, /* BroadMobi BM806U */ - {QMI_FIXED_INTF(0x2020, 0x2060, 4)}, /* BroadMobi BM818 */ + {QMI_QUIRK_SET_DTR(0x2020, 0x2060, 4)}, /* BroadMobi BM818 */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0fc4b959edc1..0999a58ca9d2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -199,6 +199,7 @@ #define OCP_EEE_AR 0xa41a #define OCP_EEE_DATA 0xa41c #define OCP_PHY_STATUS 0xa420 +#define OCP_INTR_EN 0xa424 #define OCP_NCTL_CFG 0xa42c #define OCP_POWER_CFG 0xa430 #define OCP_EEE_CFG 0xa432 @@ -620,6 +621,9 @@ enum spd_duplex { #define PHY_STAT_LAN_ON 3 #define PHY_STAT_PWRDN 5 +/* OCP_INTR_EN */ +#define INTR_SPEED_FORCE BIT(3) + /* OCP_NCTL_CFG */ #define PGA_RETURN_EN BIT(1) @@ -3023,12 +3027,16 @@ static int rtl_enable(struct r8152 *tp) ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); switch (tp->version) { - case RTL_VER_08: - case RTL_VER_09: - case RTL_VER_14: - r8153b_rx_agg_chg_indicate(tp); + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + case RTL_VER_07: break; default: + r8153b_rx_agg_chg_indicate(tp); break; } @@ -3082,7 +3090,6 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp) 640 / 8); ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR, ocp_data); - r8153b_rx_agg_chg_indicate(tp); break; default: @@ -3116,7 +3123,6 @@ static void r8153_set_rx_early_size(struct r8152 *tp) case RTL_VER_15: ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data / 8); - r8153b_rx_agg_chg_indicate(tp); break; default: WARN_ON_ONCE(1); @@ -5986,6 +5992,25 @@ static void rtl8153_disable(struct r8152 *tp) r8153_aldps_en(tp, true); } +static u32 fc_pause_on_auto(struct r8152 *tp) +{ + return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 6 * 1024); +} + +static u32 fc_pause_off_auto(struct r8152 *tp) +{ + return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 14 * 1024); +} + +static void r8156_fc_parameter(struct r8152 *tp) +{ + u32 pause_on = tp->fc_pause_on ? tp->fc_pause_on : fc_pause_on_auto(tp); + u32 pause_off = tp->fc_pause_off ? tp->fc_pause_off : fc_pause_off_auto(tp); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16); +} + static int rtl8156_enable(struct r8152 *tp) { u32 ocp_data; @@ -5994,6 +6019,7 @@ static int rtl8156_enable(struct r8152 *tp) if (test_bit(RTL8152_UNPLUG, &tp->flags)) return -ENODEV; + r8156_fc_parameter(tp); set_tx_qlen(tp); rtl_set_eee_plus(tp); r8153_set_rx_early_timeout(tp); @@ -6025,9 +6051,24 @@ static int rtl8156_enable(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_L1_CTRL, ocp_data); } + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK); + ocp_data &= ~FC_PATCH_TASK; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); + usleep_range(1000, 2000); + ocp_data |= FC_PATCH_TASK; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); + return rtl_enable(tp); } +static void rtl8156_disable(struct r8152 *tp) +{ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, 0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, 0); + + rtl8153_disable(tp); +} + static int rtl8156b_enable(struct r8152 *tp) { u32 ocp_data; @@ -6429,25 +6470,6 @@ static void rtl8153c_up(struct r8152 *tp) r8153b_u1u2en(tp, true); } -static inline u32 fc_pause_on_auto(struct r8152 *tp) -{ - return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 6 * 1024); -} - -static inline u32 fc_pause_off_auto(struct r8152 *tp) -{ - return (ALIGN(mtu_to_size(tp->netdev->mtu), 1024) + 14 * 1024); -} - -static void r8156_fc_parameter(struct r8152 *tp) -{ - u32 pause_on = tp->fc_pause_on ? tp->fc_pause_on : fc_pause_on_auto(tp); - u32 pause_off = tp->fc_pause_off ? tp->fc_pause_off : fc_pause_off_auto(tp); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_FULL, pause_on / 16); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RX_FIFO_EMPTY, pause_off / 16); -} - static void rtl8156_change_mtu(struct r8152 *tp) { u32 rx_max_size = mtu_to_size(tp->netdev->mtu); @@ -7538,6 +7560,11 @@ static void r8156_hw_phy_cfg(struct r8152 *tp) ((swap_a & 0x1f) << 8) | ((swap_a >> 8) & 0x1f)); } + + /* Notify the MAC when the speed is changed to force mode. */ + data = ocp_reg_read(tp, OCP_INTR_EN); + data |= INTR_SPEED_FORCE; + ocp_reg_write(tp, OCP_INTR_EN, data); break; default: break; @@ -7933,6 +7960,11 @@ static void r8156b_hw_phy_cfg(struct r8152 *tp) break; } + /* Notify the MAC when the speed is changed to force mode. */ + data = ocp_reg_read(tp, OCP_INTR_EN); + data |= INTR_SPEED_FORCE; + ocp_reg_write(tp, OCP_INTR_EN, data); + if (rtl_phy_patch_request(tp, true, true)) return; @@ -9340,7 +9372,7 @@ static int rtl_ops_init(struct r8152 *tp) case RTL_VER_10: ops->init = r8156_init; ops->enable = rtl8156_enable; - ops->disable = rtl8153_disable; + ops->disable = rtl8156_disable; ops->up = rtl8156_up; ops->down = rtl8156_down; ops->unload = rtl8153_unload; @@ -9878,6 +9910,7 @@ static struct usb_device_driver rtl8152_cfgselector_driver = { .probe = rtl8152_cfgselector_probe, .id_table = rtl8152_table, .generic_subclass = 1, + .supports_autosuspend = 1, }; static int __init rtl8152_driver_init(void) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 8d8038538fc4..56ca1d270304 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1868,6 +1868,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget) return received; } +static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index) +{ + virtnet_napi_tx_disable(&vi->sq[qp_index].napi); + napi_disable(&vi->rq[qp_index].napi); + xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq); +} + +static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index) +{ + struct net_device *dev = vi->dev; + int err; + + err = xdp_rxq_info_reg(&vi->rq[qp_index].xdp_rxq, dev, qp_index, + vi->rq[qp_index].napi.napi_id); + if (err < 0) + return err; + + err = xdp_rxq_info_reg_mem_model(&vi->rq[qp_index].xdp_rxq, + MEM_TYPE_PAGE_SHARED, NULL); + if (err < 0) + goto err_xdp_reg_mem_model; + + virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi); + virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi); + + return 0; + +err_xdp_reg_mem_model: + xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq); + return err; +} + static int virtnet_open(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -1881,22 +1913,20 @@ static int virtnet_open(struct net_device *dev) if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL)) schedule_delayed_work(&vi->refill, 0); - err = xdp_rxq_info_reg(&vi->rq[i].xdp_rxq, dev, i, vi->rq[i].napi.napi_id); + err = virtnet_enable_queue_pair(vi, i); if (err < 0) - return err; - - err = xdp_rxq_info_reg_mem_model(&vi->rq[i].xdp_rxq, - MEM_TYPE_PAGE_SHARED, NULL); - if (err < 0) { - xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); - return err; - } - - virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi); - virtnet_napi_tx_enable(vi, vi->sq[i].vq, &vi->sq[i].napi); + goto err_enable_qp; } return 0; + +err_enable_qp: + disable_delayed_refill(vi); + cancel_delayed_work_sync(&vi->refill); + + for (i--; i >= 0; i--) + virtnet_disable_queue_pair(vi, i); + return err; } static int virtnet_poll_tx(struct napi_struct *napi, int budget) @@ -2305,11 +2335,8 @@ static int virtnet_close(struct net_device *dev) /* Make sure refill_work doesn't re-enable napi! */ cancel_delayed_work_sync(&vi->refill); - for (i = 0; i < vi->max_queue_pairs; i++) { - virtnet_napi_tx_disable(&vi->sq[i].napi); - napi_disable(&vi->rq[i].napi); - xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq); - } + for (i = 0; i < vi->max_queue_pairs; i++) + virtnet_disable_queue_pair(vi, i); return 0; } @@ -3560,12 +3587,14 @@ static void free_unused_bufs(struct virtnet_info *vi) struct virtqueue *vq = vi->sq[i].vq; while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) virtnet_sq_free_unused_buf(vq, buf); + cond_resched(); } for (i = 0; i < vi->max_queue_pairs; i++) { struct virtqueue *vq = vi->rq[i].vq; while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) virtnet_rq_free_unused_buf(vq, buf); + cond_resched(); } } diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index 9fc7c088a539..67b4bac048e5 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -651,7 +651,7 @@ struct b43_iv { union { __be16 d16; __be32 d32; - } data __packed; + } __packed data; } __packed; diff --git a/drivers/net/wireless/broadcom/b43legacy/b43legacy.h b/drivers/net/wireless/broadcom/b43legacy/b43legacy.h index 6b0cec467938..f49365d14619 100644 --- a/drivers/net/wireless/broadcom/b43legacy/b43legacy.h +++ b/drivers/net/wireless/broadcom/b43legacy/b43legacy.h @@ -379,7 +379,7 @@ struct b43legacy_iv { union { __be16 d16; __be32 d32; - } data __packed; + } __packed data; } __packed; #define B43legacy_PHYMODE(phytype) (1 << (phytype)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index ff710b0b5071..00679a990e3d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1039,6 +1039,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; + if (!id) { + dev_err(&func->dev, "Error no sdio_device_id passed for %x:%x\n", func->vendor, func->device); + return -ENODEV; + } + brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Class=%x\n", func->class); brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 59f3e9c5e139..80220685f5e4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2394,6 +2394,9 @@ static void brcmf_pcie_debugfs_create(struct device *dev) } #endif +/* Forward declaration for pci_match_id() call */ +static const struct pci_device_id brcmf_pcie_devid_table[]; + static int brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -2404,6 +2407,14 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct brcmf_core *core; struct brcmf_bus *bus; + if (!id) { + id = pci_match_id(brcmf_pcie_devid_table, pdev); + if (!id) { + pci_err(pdev, "Error could not find pci_device_id for %x:%x\n", pdev->vendor, pdev->device); + return -ENODEV; + } + } + brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); ret = -ENOMEM; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 246843aeb696..2178675ae1a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1331,6 +1331,9 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo) brcmf_usb_detach(devinfo); } +/* Forward declaration for usb_match_id() call */ +static const struct usb_device_id brcmf_usb_devid_table[]; + static int brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1342,6 +1345,14 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) u32 num_of_eps; u8 endpoint_num, ep; + if (!id) { + id = usb_match_id(intf, brcmf_usb_devid_table); + if (!id) { + dev_err(&intf->dev, "Error could not find matching usb_device_id\n"); + return -ENODEV; + } + } + brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct); devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 5f4a51310add..cb9181f05501 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -38,7 +38,7 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { }, { .ident = "ASUS", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."), + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, {} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index d9faaae01abd..55219974b92b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1664,14 +1664,10 @@ static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id, } static void * -iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_dump_ini_region_data *reg_data, +iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id, struct iwl_fw_ini_monitor_dump *data, const struct iwl_fw_mon_regs *addrs) { - struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; - u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); - if (!iwl_trans_grab_nic_access(fwrt->trans)) { IWL_ERR(fwrt, "Failed to get monitor header\n"); return NULL; @@ -1702,8 +1698,10 @@ iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, void *data, u32 data_len) { struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); - return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + return iwl_dump_ini_mon_fill_header(fwrt, alloc_id, mon_dump, &fwrt->trans->cfg->mon_dram_regs); } @@ -1713,8 +1711,10 @@ iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, void *data, u32 data_len) { struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 alloc_id = le32_to_cpu(reg->internal_buffer.alloc_id); - return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + return iwl_dump_ini_mon_fill_header(fwrt, alloc_id, mon_dump, &fwrt->trans->cfg->mon_smem_regs); } @@ -1725,7 +1725,10 @@ iwl_dump_ini_mon_dbgi_fill_header(struct iwl_fw_runtime *fwrt, { struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; - return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + return iwl_dump_ini_mon_fill_header(fwrt, + /* no offset calculation later */ + IWL_FW_INI_ALLOCATION_ID_DBGC1, + mon_dump, &fwrt->trans->cfg->mon_dbgi_regs); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 3963a0d4ed04..652a603c4500 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -526,6 +526,11 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return PTR_ERR_OR_ZERO(sta); + } + if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) FTM_PUT_FLAG(PMF); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index b35c96cf7ad2..205c09bc9863 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1091,7 +1091,7 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { }, { .ident = "LENOVO", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Lenovo"), + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), }, }, { .ident = "DELL", @@ -1727,8 +1727,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) iwl_mvm_tas_init(mvm); iwl_mvm_leds_sync(mvm); - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) { + if (iwl_rfi_supported(mvm)) { if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE) iwl_rfi_send_config_cmd(mvm, NULL); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index eb828de40a3c..3814915cb1a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -123,11 +123,13 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (mvmvif->link[i]->phy_ctxt) count++; - /* FIXME: IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM should be - * defined per HW - */ - if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM) - return -EINVAL; + if (vif->type == NL80211_IFTYPE_AP) { + if (count > mvm->fw->ucode_capa.num_beacons) + return -EOPNOTSUPP; + /* this should be per HW or such */ + } else if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM) { + return -EOPNOTSUPP; + } } /* Catch early if driver tries to activate or deactivate a link diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 0f01b62357c6..17f788a5ff6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -3607,7 +3607,8 @@ static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; /* Beacon interval check - firmware will crash if the beacon * interval is less than 16. We can't avoid connecting at all, @@ -3616,14 +3617,11 @@ static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm, * wpa_s will blocklist the AP... */ - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_link_sta *link_sta = - link_sta_dereference_protected(sta, i); + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); - if (!link_conf || !link_sta) + if (!link_conf) continue; if (link_conf->beacon_int < IWL_MVM_MIN_BEACON_INTERVAL_TU) { @@ -3645,24 +3643,23 @@ static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw, bool is_sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_link_sta *link_sta = - link_sta_dereference_protected(sta, i); + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); - if (!link_conf || !link_sta || !mvmvif->link[i]) + if (!link_conf || !mvmvif->link[link_id]) continue; link_conf->he_support = link_sta->he_cap.has_he; if (is_sta) { - mvmvif->link[i]->he_ru_2mhz_block = false; + mvmvif->link[link_id]->he_ru_2mhz_block = false; if (link_sta->he_cap.has_he) - iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif, i, + iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif, + link_id, link_conf); } } @@ -3675,6 +3672,7 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_link_sta *link_sta; unsigned int i; int ret; @@ -3699,15 +3697,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, NL80211_TDLS_SETUP); } - for (i = 0; i < ARRAY_SIZE(sta->link); i++) { - struct ieee80211_link_sta *link_sta; - - link_sta = link_sta_dereference_protected(sta, i); - if (!link_sta) - continue; - + for_each_sta_active_link(vif, sta, link_sta, i) link_sta->agg.max_rc_amsdu_len = 1; - } + ieee80211_sta_recalc_aggregates(sta); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) @@ -3725,7 +3717,8 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); - unsigned int i; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; lockdep_assert_held(&mvm->mutex); @@ -3751,14 +3744,13 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, if (!mvm->mld_api_is_used) goto out; - for_each_set_bit(i, (unsigned long *)&sta->valid_links, - IEEE80211_MLD_MAX_NUM_LINKS) { + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, i); + link_conf_dereference_protected(vif, link_id); if (WARN_ON(!link_conf)) return -EINVAL; - if (!mvmvif->link[i]) + if (!mvmvif->link[link_id]) continue; iwl_mvm_link_changed(mvm, vif, link_conf, @@ -3889,6 +3881,9 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, * from the AP now. */ iwl_mvm_reset_cca_40mhz_workaround(mvm, vif); + + /* Also free dup data just in case any assertions below fail */ + kfree(mvm_sta->dup_data); } mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index fbc2d5ed1006..7fb66c570959 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -906,11 +906,12 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, n_active++; } - if (vif->type == NL80211_IFTYPE_AP && - n_active > mvm->fw->ucode_capa.num_beacons) - return -EOPNOTSUPP; - else if (n_active > 1) + if (vif->type == NL80211_IFTYPE_AP) { + if (n_active > mvm->fw->ucode_capa.num_beacons) + return -EOPNOTSUPP; + } else if (n_active > 1) { return -EOPNOTSUPP; + } } for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 0bfdf4462755..85a4ce8449ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -667,15 +667,15 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ret = iwl_mvm_mld_alloc_sta_links(mvm, vif, sta); if (ret) return ret; - } - spin_lock_init(&mvm_sta->lock); + spin_lock_init(&mvm_sta->lock); - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); - else ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA, STATION_TYPE_PEER); + } else { + ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); + } + if (ret) goto err; @@ -728,7 +728,7 @@ int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_link_sta *link_sta; unsigned int link_id; - int ret = 0; + int ret = -EINVAL; lockdep_assert_held(&mvm->mutex); @@ -791,8 +791,6 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); - kfree(mvm_sta->dup_data); - /* flush its queues here since we are freeing mvm_sta */ for_each_sta_active_link(vif, sta, link_sta, link_id) { struct iwl_mvm_link_sta *mvm_link_sta = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6e7470d3a826..9e5008e0e47f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2347,6 +2347,7 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm, u32 old_sta_mask, u32 new_sta_mask); +bool iwl_rfi_supported(struct iwl_mvm *mvm); int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_table); struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 6d18a1fd649b..fdf60afb0f3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -445,6 +445,11 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp->n_channels); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); @@ -456,6 +461,11 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp_v3, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kzalloc(resp_len, GFP_KERNEL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c index bb77bc9aa821..2ecd32bed752 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rfi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2020 - 2021 Intel Corporation + * Copyright (C) 2020 - 2022 Intel Corporation */ #include "mvm.h" @@ -70,6 +70,16 @@ static const struct iwl_rfi_lut_entry iwl_rfi_table[IWL_RFI_LUT_SIZE] = { PHY_BAND_6, PHY_BAND_6,}}, }; +bool iwl_rfi_supported(struct iwl_mvm *mvm) +{ + /* The feature depends on a platform bugfix, so for now + * it's always disabled. + * When the platform support detection is implemented we should + * check FW TLV and platform support instead. + */ + return false; +} + int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_table) { int ret; @@ -81,7 +91,7 @@ int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_t .len[0] = sizeof(cmd), }; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) + if (!iwl_rfi_supported(mvm)) return -EOPNOTSUPP; lockdep_assert_held(&mvm->mutex); @@ -113,7 +123,7 @@ struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm) .flags = CMD_WANT_SKB, }; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) + if (!iwl_rfi_supported(mvm)) return ERR_PTR(-EOPNOTSUPP); mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index a4c1e3bf4ff1..23266d0c9ce4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2691,6 +2691,8 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, return; lq_sta = mvm_sta; + + spin_lock(&lq_sta->pers.lock); iwl_mvm_hwrate_to_tx_rate_v1(lq_sta->last_rate_n_flags, info->band, &info->control.rates[0]); info->control.rates[0].count = 1; @@ -2705,6 +2707,7 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta, iwl_mvm_hwrate_to_tx_rate_v1(last_ucode_rate, info->band, &txrc->reported_rate); } + spin_unlock(&lq_sta->pers.lock); } static void *rs_drv_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index e1d02c260e69..6226e4e54a51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -691,6 +691,11 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) rcu_read_lock(); sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + goto out; + } + mvmsta = iwl_mvm_sta_from_mac80211(sta); /* SN is set to the last expired frame + 1 */ @@ -712,6 +717,8 @@ void iwl_mvm_reorder_timer_expired(struct timer_list *t) entries[index].e.reorder_time + 1 + RX_REORDER_BUF_TIMEOUT_MQ); } + +out: spin_unlock(&buf->lock); } @@ -2512,7 +2519,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); /* Unblock BCAST / MCAST station */ iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false); - cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); + cancel_delayed_work(&mvm->cs_tx_unblock_dwork); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5469d634e289..05a54a69c135 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -281,7 +281,7 @@ static void iwl_mvm_rx_agg_session_expired(struct timer_list *t) * A-MDPU and hence the timer continues to run. Then, the * timer expires and sta is NULL. */ - if (!sta) + if (IS_ERR_OR_NULL(sta)) goto unlock; mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -2089,9 +2089,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (iwl_mvm_has_new_rx_api(mvm)) - kfree(mvm_sta->dup_data); - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); if (ret) return ret; @@ -3785,6 +3782,9 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, u8 sta_id = mvmvif->deflink.ap_sta_id; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) + return NULL; + return sta->addr; } @@ -3822,6 +3822,11 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { addr = iwl_mvm_get_mac_addr(mvm, vif, sta); + if (!addr) { + IWL_ERR(mvm, "Failed to find mac address\n"); + return -EINVAL; + } + /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 10d7178f1071..00719e130438 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1875,7 +1875,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (WARN_ON_ONCE(!sta || !sta->wme)) { + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta) || !sta->wme)) { rcu_read_unlock(); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h index a5ec0f631385..fabf637bdf7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h @@ -173,7 +173,7 @@ enum { #define MT_TXS5_MPDU_TX_CNT GENMASK(31, 23) #define MT_TXS6_MPDU_FAIL_CNT GENMASK(31, 23) - +#define MT_TXS7_MPDU_RETRY_BYTE GENMASK(22, 0) #define MT_TXS7_MPDU_RETRY_CNT GENMASK(31, 23) /* RXD DW0 */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index ee0fbfcd07d6..d39a3cc5e381 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -608,7 +608,8 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid, /* PPDU based reporting */ if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) { stats->tx_bytes += - le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE); + le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) - + le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE); stats->tx_packets += le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT); stats->tx_failed += diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 130eb7b4fd91..39a4a73ef8e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1088,7 +1088,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, else if (beacon && mvif->beacon_rates_idx) idx = mvif->beacon_rates_idx; - txwi[6] |= FIELD_PREP(MT_TXD6_TX_RATE, idx); + txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 8eafbf1cee71..808c1c895113 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1803,6 +1803,7 @@ struct rtl8xxxu_priv { u32 rege9c; u32 regeb4; u32 regebc; + u32 regrcr; int next_mbox; int nr_out_eps; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index fd8c8c6d53d6..831639d73657 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4171,6 +4171,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL | RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC; rtl8xxxu_write32(priv, REG_RCR, val32); + priv->regrcr = val32; if (fops->init_reg_rxfltmap) { /* Accept all data frames */ @@ -6501,7 +6502,7 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { struct rtl8xxxu_priv *priv = hw->priv; - u32 rcr = rtl8xxxu_read32(priv, REG_RCR); + u32 rcr = priv->regrcr; dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n", __func__, changed_flags, *total_flags); @@ -6547,6 +6548,7 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, */ rtl8xxxu_write32(priv, REG_RCR, rcr); + priv->regrcr = rcr; *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | FIF_OTHER_BSS | FIF_PSPOLL | diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 7aa6edad0d01..a6c024cab7ee 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -918,7 +918,7 @@ static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw, struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; if (changed & IEEE80211_RC_BW_CHANGED) - rtw_update_sta_info(rtwdev, si, true); + ieee80211_queue_work(rtwdev->hw, &si->rc_work); } const struct ieee80211_ops rtw_ops = { diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 5bf6b4581557..d30a191c9291 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -319,6 +319,17 @@ static u8 rtw_acquire_macid(struct rtw_dev *rtwdev) return mac_id; } +static void rtw_sta_rc_work(struct work_struct *work) +{ + struct rtw_sta_info *si = container_of(work, struct rtw_sta_info, + rc_work); + struct rtw_dev *rtwdev = si->rtwdev; + + mutex_lock(&rtwdev->mutex); + rtw_update_sta_info(rtwdev, si, true); + mutex_unlock(&rtwdev->mutex); +} + int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { @@ -329,12 +340,14 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, if (si->mac_id >= RTW_MAX_MAC_ID_NUM) return -ENOSPC; + si->rtwdev = rtwdev; si->sta = sta; si->vif = vif; si->init_ra_lv = 1; ewma_rssi_init(&si->avg_rssi); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) rtw_txq_init(rtwdev, sta->txq[i]); + INIT_WORK(&si->rc_work, rtw_sta_rc_work); rtw_update_sta_info(rtwdev, si, true); rtw_fw_media_status_report(rtwdev, si->mac_id, true); @@ -353,6 +366,8 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; int i; + cancel_work_sync(&si->rc_work); + rtw_release_macid(rtwdev, si->mac_id); if (fw_exist) rtw_fw_media_status_report(rtwdev, si->mac_id, false); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index a563285e90ed..9e841f6991a9 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -743,6 +743,7 @@ struct rtw_txq { DECLARE_EWMA(rssi, 10, 16); struct rtw_sta_info { + struct rtw_dev *rtwdev; struct ieee80211_sta *sta; struct ieee80211_vif *vif; @@ -767,6 +768,8 @@ struct rtw_sta_info { bool use_cfg_mask; struct cfg80211_bitrate_mask *mask; + + struct work_struct rc_work; }; enum rtw_bfee_role { diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index af0459a79899..06fce7c3adda 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -87,11 +87,6 @@ static void rtw_sdio_writew(struct rtw_dev *rtwdev, u16 val, u32 addr, u8 buf[2]; int i; - if (rtw_sdio_use_memcpy_io(rtwdev, addr, 2)) { - sdio_writew(rtwsdio->sdio_func, val, addr, err_ret); - return; - } - *(__le16 *)buf = cpu_to_le16(val); for (i = 0; i < 2; i++) { @@ -125,9 +120,6 @@ static u16 rtw_sdio_readw(struct rtw_dev *rtwdev, u32 addr, int *err_ret) u8 buf[2]; int i; - if (rtw_sdio_use_memcpy_io(rtwdev, addr, 2)) - return sdio_readw(rtwsdio->sdio_func, addr, err_ret); - for (i = 0; i < 2; i++) { buf[i] = sdio_readb(rtwsdio->sdio_func, addr + i, err_ret); if (*err_ret) diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h index 30647f0dd61c..ad1d7955c6a5 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.h +++ b/drivers/net/wireless/realtek/rtw88/usb.h @@ -78,7 +78,7 @@ struct rtw_usb { u8 pipe_interrupt; u8 pipe_in; u8 out_ep[RTW_USB_EP_MAX]; - u8 qsel_to_ep[TX_DESC_QSEL_MAX]; + int qsel_to_ep[TX_DESC_QSEL_MAX]; u8 usb_txagg_num; struct workqueue_struct *txwq, *rxwq; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b8019cfc11b2..512de491a064 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1425,6 +1425,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size4 = {RTW89_WDE_PG_64, 0, 4096,}, /* PCIE 64 */ .wde_size6 = {RTW89_WDE_PG_64, 512, 0,}, + /* 8852B PCIE SCC */ + .wde_size7 = {RTW89_WDE_PG_64, 510, 2,}, /* DLFW */ .wde_size9 = {RTW89_WDE_PG_64, 0, 1024,}, /* 8852C DLFW */ @@ -1449,6 +1451,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt4 = {0, 0, 0, 0,}, /* PCIE 64 */ .wde_qt6 = {448, 48, 0, 16,}, + /* 8852B PCIE SCC */ + .wde_qt7 = {446, 48, 0, 16,}, /* 8852C DLFW */ .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index a8d9847ef0b4..6ba633ccdd03 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -792,6 +792,7 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size0; const struct rtw89_dle_size wde_size4; const struct rtw89_dle_size wde_size6; + const struct rtw89_dle_size wde_size7; const struct rtw89_dle_size wde_size9; const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; @@ -804,6 +805,7 @@ struct rtw89_mac_size_set { const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt4; const struct rtw89_wde_quota wde_qt6; + const struct rtw89_wde_quota wde_qt7; const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; const struct rtw89_ple_quota ple_qt4; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index eaa2ea0586bc..6da1b603a9a9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -18,25 +18,25 @@ RTW8852B_FW_BASENAME "-" __stringify(RTW8852B_FW_FORMAT_MAX) ".bin" static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_pcie[] = { - {5, 343, grp_0}, /* ACH 0 */ - {5, 343, grp_0}, /* ACH 1 */ - {5, 343, grp_0}, /* ACH 2 */ - {5, 343, grp_0}, /* ACH 3 */ + {5, 341, grp_0}, /* ACH 0 */ + {5, 341, grp_0}, /* ACH 1 */ + {4, 342, grp_0}, /* ACH 2 */ + {4, 342, grp_0}, /* ACH 3 */ {0, 0, grp_0}, /* ACH 4 */ {0, 0, grp_0}, /* ACH 5 */ {0, 0, grp_0}, /* ACH 6 */ {0, 0, grp_0}, /* ACH 7 */ - {4, 344, grp_0}, /* B0MGQ */ - {4, 344, grp_0}, /* B0HIQ */ + {4, 342, grp_0}, /* B0MGQ */ + {4, 342, grp_0}, /* B0HIQ */ {0, 0, grp_0}, /* B1MGQ */ {0, 0, grp_0}, /* B1HIQ */ {40, 0, 0} /* FWCMDQ */ }; static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_pcie = { - 448, /* Group 0 */ + 446, /* Group 0 */ 0, /* Group 1 */ - 448, /* Public Max */ + 446, /* Public Max */ 0 /* WP threshold */ }; @@ -49,13 +49,13 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = { }; static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { - [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, - &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, - &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18, + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size7, + &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7, + &rtw89_mac_size.wde_qt7, &rtw89_mac_size.ple_qt18, &rtw89_mac_size.ple_qt58}, - [RTW89_QTA_WOW] = {RTW89_QTA_WOW, &rtw89_mac_size.wde_size6, - &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, - &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18, + [RTW89_QTA_WOW] = {RTW89_QTA_WOW, &rtw89_mac_size.wde_size7, + &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7, + &rtw89_mac_size.wde_qt7, &rtw89_mac_size.ple_qt18, &rtw89_mac_size.ple_qt_52b_wow}, [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 2211fa58fe41..89c7a1420381 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -5964,10 +5964,11 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) ret = -ENOMEM; goto out_free; } + param.pmsr_capa = pmsr_capa; + ret = parse_pmsr_capa(info->attrs[HWSIM_ATTR_PMSR_SUPPORT], pmsr_capa, info); if (ret) goto out_free; - param.pmsr_capa = pmsr_capa; } ret = mac80211_hwsim_new_radio(info, ¶m); @@ -6556,7 +6557,7 @@ static int __init init_mac80211_hwsim(void) if (err) goto out_exit_netlink; - hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); + hwsim_class = class_create("mac80211_hwsim"); if (IS_ERR(hwsim_class)) { err = PTR_ERR(hwsim_class); goto out_exit_virtio; diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.c b/drivers/net/wwan/iosm/iosm_ipc_imem.c index c066b0040a3f..829515a601b3 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.c +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.c @@ -565,24 +565,32 @@ static void ipc_imem_run_state_worker(struct work_struct *instance) struct ipc_mux_config mux_cfg; struct iosm_imem *ipc_imem; u8 ctrl_chl_idx = 0; + int ret; ipc_imem = container_of(instance, struct iosm_imem, run_state_worker); if (ipc_imem->phase != IPC_P_RUN) { dev_err(ipc_imem->dev, "Modem link down. Exit run state worker."); - return; + goto err_out; } if (test_and_clear_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag)) ipc_devlink_deinit(ipc_imem->ipc_devlink); - if (!ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg)) - ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem); + ret = ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg); + if (ret < 0) + goto err_out; - ipc_imem_wwan_channel_init(ipc_imem, mux_cfg.protocol); - if (ipc_imem->mux) - ipc_imem->mux->wwan = ipc_imem->wwan; + ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem); + if (!ipc_imem->mux) + goto err_out; + + ret = ipc_imem_wwan_channel_init(ipc_imem, mux_cfg.protocol); + if (ret < 0) + goto err_ipc_mux_deinit; + + ipc_imem->mux->wwan = ipc_imem->wwan; while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) { if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) { @@ -622,6 +630,13 @@ static void ipc_imem_run_state_worker(struct work_struct *instance) /* Complete all memory stores after setting bit */ smp_mb__after_atomic(); + + return; + +err_ipc_mux_deinit: + ipc_mux_deinit(ipc_imem->mux); +err_out: + ipc_uevent_send(ipc_imem->dev, UEVENT_CD_READY_LINK_DOWN); } static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c index 66b90cc4c346..109cf8930488 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c +++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c @@ -77,8 +77,8 @@ out: } /* Initialize wwan channel */ -void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, - enum ipc_mux_protocol mux_type) +int ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, + enum ipc_mux_protocol mux_type) { struct ipc_chnl_cfg chnl_cfg = { 0 }; @@ -87,7 +87,7 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, /* If modem version is invalid (0xffffffff), do not initialize WWAN. */ if (ipc_imem->cp_version == -1) { dev_err(ipc_imem->dev, "invalid CP version"); - return; + return -EIO; } ipc_chnl_cfg_get(&chnl_cfg, ipc_imem->nr_of_channels); @@ -104,9 +104,13 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, /* WWAN registration. */ ipc_imem->wwan = ipc_wwan_init(ipc_imem, ipc_imem->dev); - if (!ipc_imem->wwan) + if (!ipc_imem->wwan) { dev_err(ipc_imem->dev, "failed to register the ipc_wwan interfaces"); + return -ENOMEM; + } + + return 0; } /* Map SKB to DMA for transfer */ diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h index f8afb217d9e2..026c5bd0f999 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h @@ -91,9 +91,11 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, int if_id, * MUX. * @ipc_imem: Pointer to iosm_imem struct. * @mux_type: Type of mux protocol. + * + * Return: 0 on success and failure value on error */ -void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, - enum ipc_mux_protocol mux_type); +int ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem, + enum ipc_mux_protocol mux_type); /** * ipc_imem_sys_devlink_open - Open a Flash/CD Channel link to CP diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index 226fc1703e90..91256e005b84 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -45,6 +45,7 @@ #define T7XX_PCI_IREG_BASE 0 #define T7XX_PCI_EREG_BASE 2 +#define T7XX_INIT_TIMEOUT 20 #define PM_SLEEP_DIS_TIMEOUT_MS 20 #define PM_ACK_TIMEOUT_MS 1500 #define PM_AUTOSUSPEND_MS 20000 @@ -96,6 +97,7 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev) spin_lock_init(&t7xx_dev->md_pm_lock); init_completion(&t7xx_dev->sleep_lock_acquire); init_completion(&t7xx_dev->pm_sr_ack); + init_completion(&t7xx_dev->init_done); atomic_set(&t7xx_dev->md_pm_state, MTK_PM_INIT); device_init_wakeup(&pdev->dev, true); @@ -124,6 +126,7 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev) pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev); pm_runtime_allow(&t7xx_dev->pdev->dev); pm_runtime_put_noidle(&t7xx_dev->pdev->dev); + complete_all(&t7xx_dev->init_done); } static int t7xx_pci_pm_reinit(struct t7xx_pci_dev *t7xx_dev) @@ -529,6 +532,20 @@ static void t7xx_pci_shutdown(struct pci_dev *pdev) __t7xx_pci_pm_suspend(pdev); } +static int t7xx_pci_pm_prepare(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct t7xx_pci_dev *t7xx_dev; + + t7xx_dev = pci_get_drvdata(pdev); + if (!wait_for_completion_timeout(&t7xx_dev->init_done, T7XX_INIT_TIMEOUT * HZ)) { + dev_warn(dev, "Not ready for system sleep.\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int t7xx_pci_pm_suspend(struct device *dev) { return __t7xx_pci_pm_suspend(to_pci_dev(dev)); @@ -555,6 +572,7 @@ static int t7xx_pci_pm_runtime_resume(struct device *dev) } static const struct dev_pm_ops t7xx_pci_pm_ops = { + .prepare = t7xx_pci_pm_prepare, .suspend = t7xx_pci_pm_suspend, .resume = t7xx_pci_pm_resume, .resume_noirq = t7xx_pci_pm_resume_noirq, diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h index 112efa534eac..f08f1ab74469 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.h +++ b/drivers/net/wwan/t7xx/t7xx_pci.h @@ -69,6 +69,7 @@ struct t7xx_pci_dev { struct t7xx_modem *md; struct t7xx_ccmni_ctrl *ccmni_ctlb; bool rgu_pci_irq_en; + struct completion init_done; /* Low Power Items */ struct list_head md_pm_entities; diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index aa54fa6d5f90..284ab1f56391 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -1207,7 +1207,7 @@ static int __init wwan_init(void) if (err) return err; - wwan_class = class_create(THIS_MODULE, "wwan"); + wwan_class = class_create("wwan"); if (IS_ERR(wwan_class)) { err = PTR_ERR(wwan_class); goto unregister; diff --git a/drivers/net/wwan/wwan_hwsim.c b/drivers/net/wwan/wwan_hwsim.c index dfbdaa259a3f..ff3dd24ddb33 100644 --- a/drivers/net/wwan/wwan_hwsim.c +++ b/drivers/net/wwan/wwan_hwsim.c @@ -511,7 +511,7 @@ static int __init wwan_hwsim_init(void) if (!wwan_wq) return -ENOMEM; - wwan_hwsim_class = class_create(THIS_MODULE, "wwan_hwsim"); + wwan_hwsim_class = class_create("wwan_hwsim"); if (IS_ERR(wwan_hwsim_class)) { err = PTR_ERR(wwan_hwsim_class); goto err_wq_destroy; diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c index 44eeb17ae48d..a55381f80cd6 100644 --- a/drivers/nfc/nfcsim.c +++ b/drivers/nfc/nfcsim.c @@ -336,10 +336,6 @@ static struct dentry *nfcsim_debugfs_root; static void nfcsim_debugfs_init(void) { nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL); - - if (!nfcsim_debugfs_root) - pr_err("Could not create debugfs entry\n"); - } static void nfcsim_debugfs_remove(void) diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 88ae18b0efa8..d6bbcc7b5b90 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1470,8 +1470,7 @@ static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) return rc; } -static int switchtec_ntb_add(struct device *dev, - struct class_interface *class_intf) +static int switchtec_ntb_add(struct device *dev) { struct switchtec_dev *stdev = to_stdev(dev); struct switchtec_ntb *sndev; @@ -1541,8 +1540,7 @@ free_and_exit: return rc; } -static void switchtec_ntb_remove(struct device *dev, - struct class_interface *class_intf) +static void switchtec_ntb_remove(struct device *dev) { struct switchtec_dev *stdev = to_stdev(dev); struct switchtec_ntb *sndev = stdev->sndev; diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 4976a0069e9c..954dbc105fc8 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -1320,7 +1320,7 @@ int __init nvdimm_bus_init(void) goto err_dimm_chrdev; nvdimm_major = rc; - nd_class = class_create(THIS_MODULE, "nd"); + nd_class = class_create("nd"); if (IS_ERR(nd_class)) { rc = PTR_ERR(nd_class); goto err_class; diff --git a/drivers/nvme/host/constants.c b/drivers/nvme/host/constants.c index bc523ca02254..5e4f8848dce0 100644 --- a/drivers/nvme/host/constants.c +++ b/drivers/nvme/host/constants.c @@ -21,7 +21,7 @@ static const char * const nvme_ops[] = { [nvme_cmd_resv_release] = "Reservation Release", [nvme_cmd_zone_mgmt_send] = "Zone Management Send", [nvme_cmd_zone_mgmt_recv] = "Zone Management Receive", - [nvme_cmd_zone_append] = "Zone Management Append", + [nvme_cmd_zone_append] = "Zone Append", }; static const char * const nvme_admin_ops[] = { diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 1bfd52eae2ee..3ec38e2b9173 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -397,7 +397,16 @@ void nvme_complete_rq(struct request *req) trace_nvme_complete_rq(req); nvme_cleanup_cmd(req); - if (ctrl->kas) + /* + * Completions of long-running commands should not be able to + * defer sending of periodic keep alives, since the controller + * may have completed processing such commands a long time ago + * (arbitrarily close to command submission time). + * req->deadline - req->timeout is the command submission time + * in jiffies. + */ + if (ctrl->kas && + req->deadline - req->timeout >= ctrl->ka_last_check_time) ctrl->comp_seen = true; switch (nvme_decide_disposition(req)) { @@ -1115,7 +1124,7 @@ u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) } EXPORT_SYMBOL_NS_GPL(nvme_passthru_start, NVME_TARGET_PASSTHRU); -void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, +void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects, struct nvme_command *cmd, int status) { if (effects & NVME_CMD_EFFECTS_CSE_MASK) { @@ -1132,6 +1141,8 @@ void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, nvme_queue_scan(ctrl); flush_work(&ctrl->scan_work); } + if (ns) + return; switch (cmd->common.opcode) { case nvme_admin_set_features: @@ -1161,9 +1172,25 @@ EXPORT_SYMBOL_NS_GPL(nvme_passthru_end, NVME_TARGET_PASSTHRU); * The host should send Keep Alive commands at half of the Keep Alive Timeout * accounting for transport roundtrip times [..]. */ +static unsigned long nvme_keep_alive_work_period(struct nvme_ctrl *ctrl) +{ + unsigned long delay = ctrl->kato * HZ / 2; + + /* + * When using Traffic Based Keep Alive, we need to run + * nvme_keep_alive_work at twice the normal frequency, as one + * command completion can postpone sending a keep alive command + * by up to twice the delay between runs. + */ + if (ctrl->ctratt & NVME_CTRL_ATTR_TBKAS) + delay /= 2; + return delay; +} + static void nvme_queue_keep_alive_work(struct nvme_ctrl *ctrl) { - queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ / 2); + queue_delayed_work(nvme_wq, &ctrl->ka_work, + nvme_keep_alive_work_period(ctrl)); } static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, @@ -1172,6 +1199,20 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, struct nvme_ctrl *ctrl = rq->end_io_data; unsigned long flags; bool startka = false; + unsigned long rtt = jiffies - (rq->deadline - rq->timeout); + unsigned long delay = nvme_keep_alive_work_period(ctrl); + + /* + * Subtract off the keepalive RTT so nvme_keep_alive_work runs + * at the desired frequency. + */ + if (rtt <= delay) { + delay -= rtt; + } else { + dev_warn(ctrl->device, "long keepalive RTT (%u ms)\n", + jiffies_to_msecs(rtt)); + delay = 0; + } blk_mq_free_request(rq); @@ -1182,6 +1223,7 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, return RQ_END_IO_NONE; } + ctrl->ka_last_check_time = jiffies; ctrl->comp_seen = false; spin_lock_irqsave(&ctrl->lock, flags); if (ctrl->state == NVME_CTRL_LIVE || @@ -1189,7 +1231,7 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, startka = true; spin_unlock_irqrestore(&ctrl->lock, flags); if (startka) - nvme_queue_keep_alive_work(ctrl); + queue_delayed_work(nvme_wq, &ctrl->ka_work, delay); return RQ_END_IO_NONE; } @@ -1200,6 +1242,8 @@ static void nvme_keep_alive_work(struct work_struct *work) bool comp_seen = ctrl->comp_seen; struct request *rq; + ctrl->ka_last_check_time = jiffies; + if ((ctrl->ctratt & NVME_CTRL_ATTR_TBKAS) && comp_seen) { dev_dbg(ctrl->device, "reschedule traffic based keep-alive timer\n"); @@ -3585,6 +3629,9 @@ static ssize_t nvme_sysfs_delete(struct device *dev, { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); + if (!test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags)) + return -EBUSY; + if (device_remove_file_self(dev, attr)) nvme_delete_ctrl_sync(ctrl); return count; @@ -5045,7 +5092,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl) * that were missed. We identify persistent discovery controllers by * checking that they started once before, hence are reconnecting back. */ - if (test_and_set_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags) && + if (test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags) && nvme_discovery_ctrl(ctrl)) nvme_change_uevent(ctrl, "NVME_EVENT=rediscover"); @@ -5056,6 +5103,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl) } nvme_change_uevent(ctrl, "NVME_EVENT=connected"); + set_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags); } EXPORT_SYMBOL_GPL(nvme_start_ctrl); @@ -5389,14 +5437,14 @@ static int __init nvme_core_init(void) if (result < 0) goto destroy_delete_wq; - nvme_class = class_create(THIS_MODULE, "nvme"); + nvme_class = class_create("nvme"); if (IS_ERR(nvme_class)) { result = PTR_ERR(nvme_class); goto unregister_chrdev; } nvme_class->dev_uevent = nvme_class_uevent; - nvme_subsys_class = class_create(THIS_MODULE, "nvme-subsystem"); + nvme_subsys_class = class_create("nvme-subsystem"); if (IS_ERR(nvme_subsys_class)) { result = PTR_ERR(nvme_subsys_class); goto destroy_class; @@ -5407,7 +5455,7 @@ static int __init nvme_core_init(void) if (result < 0) goto destroy_subsys_class; - nvme_ns_chr_class = class_create(THIS_MODULE, "nvme-generic"); + nvme_ns_chr_class = class_create("nvme-generic"); if (IS_ERR(nvme_ns_chr_class)) { result = PTR_ERR(nvme_ns_chr_class); goto unregister_generic_ns; diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index bbaa04a0c502..0069ebff85df 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -1254,7 +1254,7 @@ static int __init nvmf_init(void) if (!nvmf_default_host) return -ENOMEM; - nvmf_class = class_create(THIS_MODULE, "nvme-fabrics"); + nvmf_class = class_create("nvme-fabrics"); if (IS_ERR(nvmf_class)) { pr_err("couldn't register class nvme-fabrics\n"); ret = PTR_ERR(nvmf_class); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 456ee42a6133..2ed75923507d 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3875,7 +3875,6 @@ static const struct attribute_group *nvme_fc_attr_groups[] = { static struct class fc_class = { .name = "fc", .dev_groups = nvme_fc_attr_groups, - .owner = THIS_MODULE, }; static int __init nvme_fc_init_module(void) diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c index 9e6e56c20ec9..316f3e4ca7cc 100644 --- a/drivers/nvme/host/hwmon.c +++ b/drivers/nvme/host/hwmon.c @@ -163,7 +163,9 @@ static umode_t nvme_hwmon_is_visible(const void *_data, case hwmon_temp_max: case hwmon_temp_min: if ((!channel && data->ctrl->wctemp) || - (channel && data->log->temp_sensor[channel - 1])) { + (channel && data->log->temp_sensor[channel - 1] && + !(data->ctrl->quirks & + NVME_QUIRK_NO_SECONDARY_TEMP_THRESH))) { if (data->ctrl->quirks & NVME_QUIRK_NO_TEMP_THRESH_CHANGE) return 0444; diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index d24ea2e05156..f15e7330b75a 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -254,7 +254,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, blk_mq_free_request(req); if (effects) - nvme_passthru_end(ctrl, effects, cmd, ret); + nvme_passthru_end(ctrl, ns, effects, cmd, ret); return ret; } @@ -552,7 +552,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, struct io_uring_cmd *ioucmd, unsigned int issue_flags, bool vec) { struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd); - const struct nvme_uring_cmd *cmd = ioucmd->cmd; + const struct nvme_uring_cmd *cmd = io_uring_sqe_cmd(ioucmd->sqe); struct request_queue *q = ns ? ns->queue : ctrl->admin_q; struct nvme_uring_data d; struct nvme_command c; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 9171452e2f6d..2bc159a318ff 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -884,7 +884,6 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head) { if (!head->disk) return; - blk_mark_disk_dead(head->disk); /* make sure all pending bios are cleaned up */ kblockd_schedule_work(&head->requeue_work); flush_work(&head->requeue_work); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bf46f122e9e1..8657811f8b88 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -149,6 +149,11 @@ enum nvme_quirks { * Reports garbage in the namespace identifiers (eui64, nguid, uuid). */ NVME_QUIRK_BOGUS_NID = (1 << 18), + + /* + * No temperature thresholds for channels other than 0 (Composite). + */ + NVME_QUIRK_NO_SECONDARY_TEMP_THRESH = (1 << 19), }; /* @@ -323,6 +328,7 @@ struct nvme_ctrl { struct delayed_work ka_work; struct delayed_work failfast_work; struct nvme_command ka_cmd; + unsigned long ka_last_check_time; struct work_struct fw_act_work; unsigned long events; @@ -1072,7 +1078,7 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode); u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode); int nvme_execute_rq(struct request *rq, bool at_head); -void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects, +void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects, struct nvme_command *cmd, int status); struct nvme_ctrl *nvme_ctrl_from_file(struct file *file); struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 7f25c0fe3a0b..492f319ebdf3 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2956,7 +2956,7 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, * over a single page. */ dev->ctrl.max_hw_sectors = min_t(u32, - NVME_MAX_KB_SZ << 1, dma_max_mapping_size(&pdev->dev) >> 9); + NVME_MAX_KB_SZ << 1, dma_opt_mapping_size(&pdev->dev) >> 9); dev->ctrl.max_segments = NVME_MAX_SEGS; /* @@ -3402,6 +3402,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, { PCI_DEVICE(0x2646, 0x2263), /* KINGSTON A2000 NVMe SSD */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0x2646, 0x5013), /* Kingston KC3000, Kingston FURY Renegade */ + .driver_data = NVME_QUIRK_NO_SECONDARY_TEMP_THRESH, }, { PCI_DEVICE(0x2646, 0x5018), /* KINGSTON OM8SFP4xxxxP OS21012 NVMe SSD */ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, { PCI_DEVICE(0x2646, 0x5016), /* KINGSTON OM3PGP4xxxxP OS21011 NVMe SSD */ @@ -3422,6 +3424,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x1e4B, 0x1202), /* MAXIO MAP1202 */ .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1e4B, 0x1602), /* MAXIO MAP1602 */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x1cc1, 0x5350), /* ADATA XPG GAMMIX S50 */ .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x1dbe, 0x5236), /* ADATA XPG GAMMIX S70 */ @@ -3441,6 +3445,10 @@ static const struct pci_device_id nvme_id_table[] = { NVME_QUIRK_IGNORE_DEV_SUBNQN, }, { PCI_DEVICE(0x10ec, 0x5763), /* TEAMGROUP T-FORCE CARDEA ZERO Z330 SSD */ .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1e4b, 0x1602), /* HS-SSD-FUTURE 2048G */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x10ec, 0x5765), /* TEAMGROUP MP33 2TB SSD */ + .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0061), .driver_data = NVME_QUIRK_DMA_ADDRESS_BITS_48, }, { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0065), diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index c780af36c1d4..e940a7d37a9d 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -1568,7 +1568,7 @@ static int __init fcloop_init(void) { int ret; - fcloop_class = class_create(THIS_MODULE, "fcloop"); + fcloop_class = class_create("fcloop"); if (IS_ERR(fcloop_class)) { pr_err("couldn't register class fcloop\n"); ret = PTR_ERR(fcloop_class); diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 511c980d538d..71a9c1cc57f5 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -243,7 +243,7 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w) blk_mq_free_request(rq); if (effects) - nvme_passthru_end(ctrl, effects, req->cmd, status); + nvme_passthru_end(ctrl, ns, effects, req->cmd, status); } static enum rq_end_io_ret nvmet_passthru_req_done(struct request *rq, diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 6dec38805041..b291b27048c7 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -21,6 +21,10 @@ config NVMEM_SYSFS This interface is mostly used by userspace applications to read/write directly into nvmem. +# Layouts + +source "drivers/nvmem/layouts/Kconfig" + # Devices config NVMEM_APPLE_EFUSES @@ -336,6 +340,7 @@ config NVMEM_U_BOOT_ENV tristate "U-Boot environment variables support" depends on OF && MTD select CRC32 + select GENERIC_NET_UTILS help U-Boot stores its setup as environment variables. This driver adds support for verifying & exporting such data. It also exposes variables @@ -368,7 +373,7 @@ config NVMEM_VF610_OCOTP be called nvmem-vf610-ocotp. config NVMEM_ZYNQMP - bool "Xilinx ZYNQMP SoC nvmem firmware support" + tristate "Xilinx ZYNQMP SoC nvmem firmware support" depends on ARCH_ZYNQMP help This is a driver to access hardware related data like diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 6a1efffa88f0..f82431ec8aef 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o +obj-y += layouts/ # Devices obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c index a128c7f5e351..0c1fa0c4feb2 100644 --- a/drivers/nvmem/bcm-ocotp.c +++ b/drivers/nvmem/bcm-ocotp.c @@ -244,7 +244,6 @@ MODULE_DEVICE_TABLE(acpi, bcm_otpc_acpi_ids); static int bcm_otpc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; struct otpc_priv *priv; struct nvmem_device *nvmem; int err; @@ -259,8 +258,7 @@ static int bcm_otpc_probe(struct platform_device *pdev) return -ENODEV; /* Get OTP base address register. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(dev, res); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { dev_err(dev, "unable to map I/O memory\n"); return PTR_ERR(priv->base); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 22024b830788..342cd380b420 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include struct nvmem_device { @@ -38,8 +39,8 @@ struct nvmem_device { unsigned int nkeepout; nvmem_reg_read_t reg_read; nvmem_reg_write_t reg_write; - nvmem_cell_post_process_t cell_post_process; struct gpio_desc *wp_gpio; + struct nvmem_layout *layout; void *priv; }; @@ -49,9 +50,12 @@ struct nvmem_device { struct nvmem_cell_entry { const char *name; int offset; + size_t raw_len; int bytes; int bit_offset; int nbits; + nvmem_cell_post_process_t read_post_process; + void *priv; struct device_node *np; struct nvmem_device *nvmem; struct list_head node; @@ -74,6 +78,9 @@ static LIST_HEAD(nvmem_lookup_list); static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); +static DEFINE_SPINLOCK(nvmem_layout_lock); +static LIST_HEAD(nvmem_layouts); + static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, void *val, size_t bytes) { @@ -463,8 +470,11 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, { cell->nvmem = nvmem; cell->offset = info->offset; + cell->raw_len = info->raw_len ?: info->bytes; cell->bytes = info->bytes; cell->name = info->name; + cell->read_post_process = info->read_post_process; + cell->priv = info->priv; cell->bit_offset = info->bit_offset; cell->nbits = info->nbits; @@ -688,6 +698,7 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem) static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) { + struct nvmem_layout *layout = nvmem->layout; struct device *dev = &nvmem->dev; struct device_node *child; const __be32 *addr; @@ -717,6 +728,9 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) info.np = of_node_get(child); + if (layout && layout->fixup_cell_info) + layout->fixup_cell_info(nvmem, layout, &info); + ret = nvmem_add_one_cell(nvmem, &info); kfree(info.name); if (ret) { @@ -728,6 +742,108 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) return 0; } +int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner) +{ + layout->owner = owner; + + spin_lock(&nvmem_layout_lock); + list_add(&layout->node, &nvmem_layouts); + spin_unlock(&nvmem_layout_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(__nvmem_layout_register); + +void nvmem_layout_unregister(struct nvmem_layout *layout) +{ + spin_lock(&nvmem_layout_lock); + list_del(&layout->node); + spin_unlock(&nvmem_layout_lock); +} +EXPORT_SYMBOL_GPL(nvmem_layout_unregister); + +static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem) +{ + struct device_node *layout_np, *np = nvmem->dev.of_node; + struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER); + + layout_np = of_get_child_by_name(np, "nvmem-layout"); + if (!layout_np) + return NULL; + + /* + * In case the nvmem device was built-in while the layout was built as a + * module, we shall manually request the layout driver loading otherwise + * we'll never have any match. + */ + of_request_module(layout_np); + + spin_lock(&nvmem_layout_lock); + + list_for_each_entry(l, &nvmem_layouts, node) { + if (of_match_node(l->of_match_table, layout_np)) { + if (try_module_get(l->owner)) + layout = l; + + break; + } + } + + spin_unlock(&nvmem_layout_lock); + of_node_put(layout_np); + + return layout; +} + +static void nvmem_layout_put(struct nvmem_layout *layout) +{ + if (layout) + module_put(layout->owner); +} + +static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem) +{ + struct nvmem_layout *layout = nvmem->layout; + int ret; + + if (layout && layout->add_cells) { + ret = layout->add_cells(&nvmem->dev, nvmem, layout); + if (ret) + return ret; + } + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +/** + * of_nvmem_layout_get_container() - Get OF node to layout container. + * + * @nvmem: nvmem device. + * + * Return: a node pointer with refcount incremented or NULL if no + * container exists. Use of_node_put() on it when done. + */ +struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) +{ + return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout"); +} +EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container); +#endif + +const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem, + struct nvmem_layout *layout) +{ + struct device_node __maybe_unused *layout_np; + const struct of_device_id *match; + + layout_np = of_nvmem_layout_get_container(nvmem); + match = of_match_node(layout->of_match_table, layout_np); + + return match ? match->data : NULL; +} +EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data); + /** * nvmem_register() - Register a nvmem device for given nvmem_config. * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem @@ -790,7 +906,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->type = config->type; nvmem->reg_read = config->reg_read; nvmem->reg_write = config->reg_write; - nvmem->cell_post_process = config->cell_post_process; nvmem->keepout = config->keepout; nvmem->nkeepout = config->nkeepout; if (config->of_node) @@ -834,6 +949,19 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) goto err_put_device; } + /* + * If the driver supplied a layout by config->layout, the module + * pointer will be NULL and nvmem_layout_put() will be a noop. + */ + nvmem->layout = config->layout ?: nvmem_layout_get(nvmem); + if (IS_ERR(nvmem->layout)) { + rval = PTR_ERR(nvmem->layout); + nvmem->layout = NULL; + + if (rval == -EPROBE_DEFER) + goto err_teardown_compat; + } + if (config->cells) { rval = nvmem_add_cells(nvmem, config->cells, config->ncells); if (rval) @@ -854,12 +982,18 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (rval) goto err_remove_cells; + rval = nvmem_add_cells_from_layout(nvmem); + if (rval) + goto err_remove_cells; + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); return nvmem; err_remove_cells: nvmem_device_remove_all_cells(nvmem); + nvmem_layout_put(nvmem->layout); +err_teardown_compat: if (config->compat) nvmem_sysfs_remove_compat(nvmem, config); err_put_device: @@ -881,6 +1015,7 @@ static void nvmem_device_release(struct kref *kref) device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); nvmem_device_remove_all_cells(nvmem); + nvmem_layout_put(nvmem->layout); device_unregister(&nvmem->dev); } @@ -1246,6 +1381,15 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) return ERR_PTR(-EINVAL); } + /* nvmem layouts produce cells within the nvmem-layout container */ + if (of_node_name_eq(nvmem_np, "nvmem-layout")) { + nvmem_np = of_get_next_parent(nvmem_np); + if (!nvmem_np) { + of_node_put(cell_np); + return ERR_PTR(-EINVAL); + } + } + nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); of_node_put(nvmem_np); if (IS_ERR(nvmem)) { @@ -1418,7 +1562,7 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem, { int rc; - rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); + rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->raw_len); if (rc) return rc; @@ -1427,9 +1571,9 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem, if (cell->bit_offset || cell->nbits) nvmem_shift_read_buffer_in_place(cell, buf); - if (nvmem->cell_post_process) { - rc = nvmem->cell_post_process(nvmem->priv, id, index, - cell->offset, buf, cell->bytes); + if (cell->read_post_process) { + rc = cell->read_post_process(cell->priv, id, index, + cell->offset, buf, cell->raw_len); if (rc) return rc; } @@ -1452,14 +1596,15 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem, */ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) { - struct nvmem_device *nvmem = cell->entry->nvmem; + struct nvmem_cell_entry *entry = cell->entry; + struct nvmem_device *nvmem = entry->nvmem; u8 *buf; int rc; if (!nvmem) return ERR_PTR(-EINVAL); - buf = kzalloc(cell->entry->bytes, GFP_KERNEL); + buf = kzalloc(max_t(size_t, entry->raw_len, entry->bytes), GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); @@ -1535,6 +1680,14 @@ static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, si (cell->bit_offset == 0 && len != cell->bytes)) return -EINVAL; + /* + * Any cells which have a read_post_process hook are read-only because + * we cannot reverse the operation and it might affect other cells, + * too. + */ + if (cell->read_post_process) + return -EINVAL; + if (cell->bit_offset || cell->nbits) { buf = nvmem_cell_prepare_write_buffer(cell, buf, len); if (IS_ERR(buf)) @@ -1958,4 +2111,3 @@ module_exit(nvmem_exit); MODULE_AUTHOR("Srinivas Kandagatla params->reverse_mac_address) { - u8 *buf = data; - int i; - - for (i = 0; i < bytes/2; i++) - swap(buf[i], buf[bytes - i - 1]); - } - } + if (id && !strcmp(id, "mac-address")) + for (i = 0; i < bytes / 2; i++) + swap(buf[i], buf[bytes - i - 1]); return 0; } @@ -488,7 +483,6 @@ static struct nvmem_config imx_ocotp_nvmem_config = { .stride = 1, .reg_read = imx_ocotp_read, .reg_write = imx_ocotp_write, - .cell_post_process = imx_ocotp_cell_pp, }; static const struct ocotp_params imx6q_params = { @@ -595,6 +589,17 @@ static const struct of_device_id imx_ocotp_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); +static void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem, + struct nvmem_layout *layout, + struct nvmem_cell_info *cell) +{ + cell->read_post_process = imx_ocotp_cell_pp; +} + +struct nvmem_layout imx_ocotp_layout = { + .fixup_cell_info = imx_ocotp_fixup_cell_info, +}; + static int imx_ocotp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -619,6 +624,9 @@ static int imx_ocotp_probe(struct platform_device *pdev) imx_ocotp_nvmem_config.size = 4 * priv->params->nregs; imx_ocotp_nvmem_config.dev = dev; imx_ocotp_nvmem_config.priv = priv; + if (priv->params->reverse_mac_address) + imx_ocotp_nvmem_config.layout = &imx_ocotp_layout; + priv->config = &imx_ocotp_nvmem_config; clk_prepare_enable(priv->clk); diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig new file mode 100644 index 000000000000..7ff1ee1c1f05 --- /dev/null +++ b/drivers/nvmem/layouts/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0 + +menu "Layout Types" + +config NVMEM_LAYOUT_SL28_VPD + tristate "Kontron sl28 VPD layout support" + select CRC8 + help + Say Y here if you want to support the VPD layout of the Kontron + SMARC-sAL28 boards. + + If unsure, say N. + +config NVMEM_LAYOUT_ONIE_TLV + tristate "ONIE tlv support" + select CRC32 + help + Say Y here if you want to support the Open Compute Project ONIE + Type-Length-Value standard table. + + If unsure, say N. + +endmenu diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile new file mode 100644 index 000000000000..2974bd7d33ed --- /dev/null +++ b/drivers/nvmem/layouts/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for nvmem layouts. +# + +obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o +obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c new file mode 100644 index 000000000000..59fc87ccfcff --- /dev/null +++ b/drivers/nvmem/layouts/onie-tlv.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ONIE tlv NVMEM cells provider + * + * Copyright (C) 2022 Open Compute Group ONIE + * Author: Miquel Raynal + * Based on the nvmem driver written by: Vadym Kochan + * Inspired by the first layout written by: Rafał Miłecki + */ + +#include +#include +#include +#include +#include + +#define ONIE_TLV_MAX_LEN 2048 +#define ONIE_TLV_CRC_FIELD_SZ 6 +#define ONIE_TLV_CRC_SZ 4 +#define ONIE_TLV_HDR_ID "TlvInfo" + +struct onie_tlv_hdr { + u8 id[8]; + u8 version; + __be16 data_len; +} __packed; + +struct onie_tlv { + u8 type; + u8 len; +} __packed; + +static const char *onie_tlv_cell_name(u8 type) +{ + switch (type) { + case 0x21: + return "product-name"; + case 0x22: + return "part-number"; + case 0x23: + return "serial-number"; + case 0x24: + return "mac-address"; + case 0x25: + return "manufacture-date"; + case 0x26: + return "device-version"; + case 0x27: + return "label-revision"; + case 0x28: + return "platform-name"; + case 0x29: + return "onie-version"; + case 0x2A: + return "num-macs"; + case 0x2B: + return "manufacturer"; + case 0x2C: + return "country-code"; + case 0x2D: + return "vendor"; + case 0x2E: + return "diag-version"; + case 0x2F: + return "service-tag"; + case 0xFD: + return "vendor-extension"; + case 0xFE: + return "crc32"; + default: + break; + } + + return NULL; +} + +static int onie_tlv_mac_read_cb(void *priv, const char *id, int index, + unsigned int offset, void *buf, + size_t bytes) +{ + eth_addr_add(buf, index); + + return 0; +} + +static nvmem_cell_post_process_t onie_tlv_read_cb(u8 type, u8 *buf) +{ + switch (type) { + case 0x24: + return &onie_tlv_mac_read_cb; + default: + break; + } + + return NULL; +} + +static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem, + size_t data_len, u8 *data) +{ + struct nvmem_cell_info cell = {}; + struct device_node *layout; + struct onie_tlv tlv; + unsigned int hdr_len = sizeof(struct onie_tlv_hdr); + unsigned int offset = 0; + int ret; + + layout = of_nvmem_layout_get_container(nvmem); + if (!layout) + return -ENOENT; + + while (offset < data_len) { + memcpy(&tlv, data + offset, sizeof(tlv)); + if (offset + tlv.len >= data_len) { + dev_err(dev, "Out of bounds field (0x%x bytes at 0x%x)\n", + tlv.len, hdr_len + offset); + break; + } + + cell.name = onie_tlv_cell_name(tlv.type); + if (!cell.name) + continue; + + cell.offset = hdr_len + offset + sizeof(tlv.type) + sizeof(tlv.len); + cell.bytes = tlv.len; + cell.np = of_get_child_by_name(layout, cell.name); + cell.read_post_process = onie_tlv_read_cb(tlv.type, data + offset + sizeof(tlv)); + + ret = nvmem_add_one_cell(nvmem, &cell); + if (ret) { + of_node_put(layout); + return ret; + } + + offset += sizeof(tlv) + tlv.len; + } + + of_node_put(layout); + + return 0; +} + +static bool onie_tlv_hdr_is_valid(struct device *dev, struct onie_tlv_hdr *hdr) +{ + if (memcmp(hdr->id, ONIE_TLV_HDR_ID, sizeof(hdr->id))) { + dev_err(dev, "Invalid header\n"); + return false; + } + + if (hdr->version != 0x1) { + dev_err(dev, "Invalid version number\n"); + return false; + } + + return true; +} + +static bool onie_tlv_crc_is_valid(struct device *dev, size_t table_len, u8 *table) +{ + struct onie_tlv crc_hdr; + u32 read_crc, calc_crc; + __be32 crc_be; + + memcpy(&crc_hdr, table + table_len - ONIE_TLV_CRC_FIELD_SZ, sizeof(crc_hdr)); + if (crc_hdr.type != 0xfe || crc_hdr.len != ONIE_TLV_CRC_SZ) { + dev_err(dev, "Invalid CRC field\n"); + return false; + } + + /* The table contains a JAMCRC, which is XOR'ed compared to the original + * CRC32 implementation as known in the Ethernet world. + */ + memcpy(&crc_be, table + table_len - ONIE_TLV_CRC_SZ, ONIE_TLV_CRC_SZ); + read_crc = be32_to_cpu(crc_be); + calc_crc = crc32(~0, table, table_len - ONIE_TLV_CRC_SZ) ^ 0xFFFFFFFF; + if (read_crc != calc_crc) { + dev_err(dev, "Invalid CRC read: 0x%08x, expected: 0x%08x\n", + read_crc, calc_crc); + return false; + } + + return true; +} + +static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem, + struct nvmem_layout *layout) +{ + struct onie_tlv_hdr hdr; + size_t table_len, data_len, hdr_len; + u8 *table, *data; + int ret; + + ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); + if (ret < 0) + return ret; + + if (!onie_tlv_hdr_is_valid(dev, &hdr)) { + dev_err(dev, "Invalid ONIE TLV header\n"); + return -EINVAL; + } + + hdr_len = sizeof(hdr.id) + sizeof(hdr.version) + sizeof(hdr.data_len); + data_len = be16_to_cpu(hdr.data_len); + table_len = hdr_len + data_len; + if (table_len > ONIE_TLV_MAX_LEN) { + dev_err(dev, "Invalid ONIE TLV data length\n"); + return -EINVAL; + } + + table = devm_kmalloc(dev, table_len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + ret = nvmem_device_read(nvmem, 0, table_len, table); + if (ret != table_len) + return ret; + + if (!onie_tlv_crc_is_valid(dev, table_len, table)) + return -EINVAL; + + data = table + hdr_len; + ret = onie_tlv_add_cells(dev, nvmem, data_len, data); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id onie_tlv_of_match_table[] = { + { .compatible = "onie,tlv-layout", }, + {}, +}; +MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table); + +static struct nvmem_layout onie_tlv_layout = { + .name = "ONIE tlv layout", + .of_match_table = onie_tlv_of_match_table, + .add_cells = onie_tlv_parse_table, +}; +module_nvmem_layout_driver(onie_tlv_layout); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Miquel Raynal "); +MODULE_DESCRIPTION("NVMEM layout driver for Onie TLV table parsing"); diff --git a/drivers/nvmem/layouts/sl28vpd.c b/drivers/nvmem/layouts/sl28vpd.c new file mode 100644 index 000000000000..05671371f631 --- /dev/null +++ b/drivers/nvmem/layouts/sl28vpd.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +#define SL28VPD_MAGIC 'V' + +struct sl28vpd_header { + u8 magic; + u8 version; +} __packed; + +struct sl28vpd_v1 { + struct sl28vpd_header header; + char serial_number[15]; + u8 base_mac_address[ETH_ALEN]; + u8 crc8; +} __packed; + +static int sl28vpd_mac_address_pp(void *priv, const char *id, int index, + unsigned int offset, void *buf, + size_t bytes) +{ + if (bytes != ETH_ALEN) + return -EINVAL; + + if (index < 0) + return -EINVAL; + + if (!is_valid_ether_addr(buf)) + return -EINVAL; + + eth_addr_add(buf, index); + + return 0; +} + +static const struct nvmem_cell_info sl28vpd_v1_entries[] = { + { + .name = "serial-number", + .offset = offsetof(struct sl28vpd_v1, serial_number), + .bytes = sizeof_field(struct sl28vpd_v1, serial_number), + }, + { + .name = "base-mac-address", + .offset = offsetof(struct sl28vpd_v1, base_mac_address), + .bytes = sizeof_field(struct sl28vpd_v1, base_mac_address), + .read_post_process = sl28vpd_mac_address_pp, + }, +}; + +static int sl28vpd_v1_check_crc(struct device *dev, struct nvmem_device *nvmem) +{ + struct sl28vpd_v1 data_v1; + u8 table[CRC8_TABLE_SIZE]; + int ret; + u8 crc; + + crc8_populate_msb(table, 0x07); + + ret = nvmem_device_read(nvmem, 0, sizeof(data_v1), &data_v1); + if (ret < 0) + return ret; + else if (ret != sizeof(data_v1)) + return -EIO; + + crc = crc8(table, (void *)&data_v1, sizeof(data_v1) - 1, 0); + + if (crc != data_v1.crc8) { + dev_err(dev, + "Checksum is invalid (got %02x, expected %02x).\n", + crc, data_v1.crc8); + return -EINVAL; + } + + return 0; +} + +static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem, + struct nvmem_layout *layout) +{ + const struct nvmem_cell_info *pinfo; + struct nvmem_cell_info info = {0}; + struct device_node *layout_np; + struct sl28vpd_header hdr; + int ret, i; + + /* check header */ + ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); + if (ret < 0) + return ret; + else if (ret != sizeof(hdr)) + return -EIO; + + if (hdr.magic != SL28VPD_MAGIC) { + dev_err(dev, "Invalid magic value (%02x)\n", hdr.magic); + return -EINVAL; + } + + if (hdr.version != 1) { + dev_err(dev, "Version %d is unsupported.\n", hdr.version); + return -EINVAL; + } + + ret = sl28vpd_v1_check_crc(dev, nvmem); + if (ret) + return ret; + + layout_np = of_nvmem_layout_get_container(nvmem); + if (!layout_np) + return -ENOENT; + + for (i = 0; i < ARRAY_SIZE(sl28vpd_v1_entries); i++) { + pinfo = &sl28vpd_v1_entries[i]; + + info.name = pinfo->name; + info.offset = pinfo->offset; + info.bytes = pinfo->bytes; + info.read_post_process = pinfo->read_post_process; + info.np = of_get_child_by_name(layout_np, pinfo->name); + + ret = nvmem_add_one_cell(nvmem, &info); + if (ret) { + of_node_put(layout_np); + return ret; + } + } + + of_node_put(layout_np); + + return 0; +} + +static const struct of_device_id sl28vpd_of_match_table[] = { + { .compatible = "kontron,sl28-vpd" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table); + +static struct nvmem_layout sl28vpd_layout = { + .name = "sl28-vpd", + .of_match_table = sl28vpd_of_match_table, + .add_cells = sl28vpd_add_cells, +}; +module_nvmem_layout_driver(sl28vpd_layout); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Walle "); +MODULE_DESCRIPTION("NVMEM layout driver for the VPD of Kontron sl28 boards"); diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index a08e0aedd21c..b36cd0dcc8c7 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -10,6 +10,11 @@ #include #include #include +#include + +struct mtk_efuse_pdata { + bool uses_post_processing; +}; struct mtk_efuse_priv { void __iomem *base; @@ -29,6 +34,37 @@ static int mtk_reg_read(void *context, return 0; } +static int mtk_efuse_gpu_speedbin_pp(void *context, const char *id, int index, + unsigned int offset, void *data, size_t bytes) +{ + u8 *val = data; + + if (val[0] < 8) + val[0] = BIT(val[0]); + + return 0; +} + +static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem, + struct nvmem_layout *layout, + struct nvmem_cell_info *cell) +{ + size_t sz = strlen(cell->name); + + /* + * On some SoCs, the GPU speedbin is not read as bitmask but as + * a number with range [0-7] (max 3 bits): post process to use + * it in OPP tables to describe supported-hw. + */ + if (cell->nbits <= 3 && + strncmp(cell->name, "gpu-speedbin", min(sz, strlen("gpu-speedbin"))) == 0) + cell->read_post_process = mtk_efuse_gpu_speedbin_pp; +} + +static struct nvmem_layout mtk_efuse_layout = { + .fixup_cell_info = mtk_efuse_fixup_cell_info, +}; + static int mtk_efuse_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -36,6 +72,7 @@ static int mtk_efuse_probe(struct platform_device *pdev) struct nvmem_device *nvmem; struct nvmem_config econfig = {}; struct mtk_efuse_priv *priv; + const struct mtk_efuse_pdata *pdata; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -45,20 +82,32 @@ static int mtk_efuse_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); + pdata = device_get_match_data(dev); econfig.stride = 1; econfig.word_size = 1; econfig.reg_read = mtk_reg_read; econfig.size = resource_size(res); econfig.priv = priv; econfig.dev = dev; + if (pdata->uses_post_processing) + econfig.layout = &mtk_efuse_layout; nvmem = devm_nvmem_register(dev, &econfig); return PTR_ERR_OR_ZERO(nvmem); } +static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = { + .uses_post_processing = true, +}; + +static const struct mtk_efuse_pdata mtk_efuse_pdata = { + .uses_post_processing = false, +}; + static const struct of_device_id mtk_efuse_of_match[] = { - { .compatible = "mediatek,mt8173-efuse",}, - { .compatible = "mediatek,efuse",}, + { .compatible = "mediatek,mt8173-efuse", .data = &mtk_efuse_pdata }, + { .compatible = "mediatek,mt8186-efuse", .data = &mtk_mt8186_efuse_pdata }, + { .compatible = "mediatek,efuse", .data = &mtk_efuse_pdata }, {/* sentinel */}, }; MODULE_DEVICE_TABLE(of, mtk_efuse_of_match); diff --git a/drivers/nvmem/nintendo-otp.c b/drivers/nvmem/nintendo-otp.c index 33961b17f9f1..355e7f1fc6d5 100644 --- a/drivers/nvmem/nintendo-otp.c +++ b/drivers/nvmem/nintendo-otp.c @@ -76,7 +76,6 @@ static int nintendo_otp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct of_device_id *of_id = of_match_device(nintendo_otp_of_table, dev); - struct resource *res; struct nvmem_device *nvmem; struct nintendo_otp_priv *priv; @@ -92,8 +91,7 @@ static int nintendo_otp_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c index ba779e26937a..38d0bf557129 100644 --- a/drivers/nvmem/stm32-romem.c +++ b/drivers/nvmem/stm32-romem.c @@ -268,7 +268,7 @@ static const struct stm32_romem_cfg stm32mp13_bsec_cfg = { .ta = true, }; -static const struct of_device_id stm32_romem_of_match[] = { +static const struct of_device_id stm32_romem_of_match[] __maybe_unused = { { .compatible = "st,stm32f4-otp", }, { .compatible = "st,stm32mp15-bsec", .data = (void *)&stm32mp15_bsec_cfg, diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c index 29b1d87a3c51..ee9fd9989b6e 100644 --- a/drivers/nvmem/u-boot-env.c +++ b/drivers/nvmem/u-boot-env.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include #include @@ -70,6 +72,25 @@ static int u_boot_env_read(void *context, unsigned int offset, void *val, return 0; } +static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, int index, + unsigned int offset, void *buf, size_t bytes) +{ + u8 mac[ETH_ALEN]; + + if (bytes != 3 * ETH_ALEN - 1) + return -EINVAL; + + if (!mac_pton(buf, mac)) + return -EINVAL; + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf, size_t data_offset, size_t data_len) { @@ -101,6 +122,11 @@ static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf, priv->cells[idx].offset = data_offset + value - data; priv->cells[idx].bytes = strlen(value); priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); + if (!strcmp(var, "ethaddr")) { + priv->cells[idx].raw_len = strlen(value); + priv->cells[idx].bytes = ETH_ALEN; + priv->cells[idx].read_post_process = u_boot_env_read_post_process_ethaddr; + } } if (WARN_ON(idx != priv->ncells)) diff --git a/drivers/nvmem/vf610-ocotp.c b/drivers/nvmem/vf610-ocotp.c index 5b6cad16892f..ee9c61ae727d 100644 --- a/drivers/nvmem/vf610-ocotp.c +++ b/drivers/nvmem/vf610-ocotp.c @@ -219,8 +219,7 @@ static int vf610_ocotp_probe(struct platform_device *pdev) if (!ocotp_dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ocotp_dev->base = devm_ioremap_resource(dev, res); + ocotp_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ocotp_dev->base)) return PTR_ERR(ocotp_dev->base); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 644386833a7b..e40f10bf2ba4 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -102,8 +102,4 @@ config OF_OVERLAY config OF_NUMA bool -config OF_DMA_DEFAULT_COHERENT - # arches should select this if DMA is coherent by default for OF devices - bool - endif # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 10f704592561..eff624854575 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y = base.o cpu.o device.o platform.o property.o +obj-y = base.o cpu.o device.o module.o platform.o property.o obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o diff --git a/drivers/of/address.c b/drivers/of/address.c index 0d49f8c9ed88..e692809ff822 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -1037,7 +1037,7 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np) bool of_dma_is_coherent(struct device_node *np) { struct device_node *node; - bool is_coherent = IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT); + bool is_coherent = dma_default_coherent; node = of_node_get(np); diff --git a/drivers/of/base.c b/drivers/of/base.c index 7f1720af813c..166fb7d75337 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1021,19 +1021,23 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from, EXPORT_SYMBOL(of_find_matching_node_and_match); /** - * of_modalias_node - Lookup appropriate modalias for a device node + * of_alias_from_compatible - Lookup appropriate alias for a device node + * depending on compatible * @node: pointer to a device tree node - * @modalias: Pointer to buffer that modalias value will be copied into - * @len: Length of modalias value + * @alias: Pointer to buffer that alias value will be copied into + * @len: Length of alias value * * Based on the value of the compatible property, this routine will attempt - * to choose an appropriate modalias value for a particular device tree node. + * to choose an appropriate alias value for a particular device tree node. * It does this by stripping the manufacturer prefix (as delimited by a ',') * from the first entry in the compatible list property. * + * Note: The matching on just the "product" side of the compatible is a relic + * from I2C and SPI. Please do not add any new user. + * * Return: This routine returns 0 on success, <0 on failure. */ -int of_modalias_node(struct device_node *node, char *modalias, int len) +int of_alias_from_compatible(const struct device_node *node, char *alias, int len) { const char *compatible, *p; int cplen; @@ -1042,10 +1046,10 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) if (!compatible || strlen(compatible) > cplen) return -ENODEV; p = strchr(compatible, ','); - strscpy(modalias, p ? p + 1 : compatible, len); + strscpy(alias, p ? p + 1 : compatible, len); return 0; } -EXPORT_SYMBOL_GPL(of_modalias_node); +EXPORT_SYMBOL_GPL(of_alias_from_compatible); /** * of_find_node_by_phandle - Find a node given a phandle diff --git a/drivers/of/device.c b/drivers/of/device.c index 955bfb3d1a83..0f00f1b80708 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include #include #include @@ -9,7 +8,6 @@ #include /* for bus_dma_region */ #include #include -#include #include #include #include @@ -248,68 +246,6 @@ const void *of_device_get_match_data(const struct device *dev) } EXPORT_SYMBOL(of_device_get_match_data); -static ssize_t of_device_get_modalias(const struct device *dev, char *str, ssize_t len) -{ - const char *compat; - char *c; - struct property *p; - ssize_t csize; - ssize_t tsize; - - if ((!dev) || (!dev->of_node) || dev->of_node_reused) - return -ENODEV; - - /* Name & Type */ - /* %p eats all alphanum characters, so %c must be used here */ - csize = snprintf(str, len, "of:N%pOFn%c%s", dev->of_node, 'T', - of_node_get_device_type(dev->of_node)); - tsize = csize; - len -= csize; - if (str) - str += csize; - - of_property_for_each_string(dev->of_node, "compatible", p, compat) { - csize = strlen(compat) + 1; - tsize += csize; - if (csize > len) - continue; - - csize = snprintf(str, len, "C%s", compat); - for (c = str; c; ) { - c = strchr(c, ' '); - if (c) - *c++ = '_'; - } - len -= csize; - str += csize; - } - - return tsize; -} - -int of_device_request_module(struct device *dev) -{ - char *str; - ssize_t size; - int ret; - - size = of_device_get_modalias(dev, NULL, 0); - if (size < 0) - return size; - - str = kmalloc(size + 1, GFP_KERNEL); - if (!str) - return -ENOMEM; - - of_device_get_modalias(dev, str, size); - str[size] = '\0'; - ret = request_module(str); - kfree(str); - - return ret; -} -EXPORT_SYMBOL_GPL(of_device_request_module); - /** * of_device_modalias - Fill buffer with newline terminated modalias string * @dev: Calling device @@ -318,7 +254,12 @@ EXPORT_SYMBOL_GPL(of_device_request_module); */ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) { - ssize_t sl = of_device_get_modalias(dev, str, len - 2); + ssize_t sl; + + if (!dev || !dev->of_node || dev->of_node_reused) + return -ENODEV; + + sl = of_modalias(dev->of_node, str, len - 2); if (sl < 0) return sl; if (sl > len - 2) @@ -383,8 +324,8 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env * if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], - sizeof(env->buf) - env->buflen); + sl = of_modalias(dev->of_node, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); if (sl < 0) return sl; if (sl >= (sizeof(env->buf) - env->buflen)) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index d1a68b6d03b3..bf502ba8da95 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -635,6 +635,9 @@ void __init early_init_fdt_scan_reserved_mem(void) if (!initial_boot_params) return; + fdt_scan_reserved_mem(); + fdt_reserve_elfcorehdr(); + /* Process header /memreserve/ fields */ for (n = 0; ; n++) { fdt_get_mem_rsv(initial_boot_params, n, &base, &size); @@ -643,8 +646,6 @@ void __init early_init_fdt_scan_reserved_mem(void) memblock_reserve(base, size); } - fdt_scan_reserved_mem(); - fdt_reserve_elfcorehdr(); fdt_init_reserved_mem(); } @@ -887,12 +888,13 @@ const void * __init of_flat_dt_match_machine(const void *default_match, static void __early_init_dt_declare_initrd(unsigned long start, unsigned long end) { - /* ARM64 would cause a BUG to occur here when CONFIG_DEBUG_VM is - * enabled since __va() is called too early. ARM64 does make use - * of phys_initrd_start/phys_initrd_size so we can skip this - * conversion. + /* + * __va() is not yet available this early on some platforms. In that + * case, the platform uses phys_initrd_start/phys_initrd_size instead + * and does the VA conversion itself. */ - if (!IS_ENABLED(CONFIG_ARM64)) { + if (!IS_ENABLED(CONFIG_ARM64) && + !(IS_ENABLED(CONFIG_RISCV) && IS_ENABLED(CONFIG_64BIT))) { initrd_start = (unsigned long)__va(start); initrd_end = (unsigned long)__va(end); initrd_below_start_ok = 1; diff --git a/drivers/of/module.c b/drivers/of/module.c new file mode 100644 index 000000000000..0e8aa974f0f2 --- /dev/null +++ b/drivers/of/module.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux kernel module helpers. + */ + +#include +#include +#include +#include + +ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) +{ + const char *compat; + char *c; + struct property *p; + ssize_t csize; + ssize_t tsize; + + /* Name & Type */ + /* %p eats all alphanum characters, so %c must be used here */ + csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', + of_node_get_device_type(np)); + tsize = csize; + len -= csize; + if (str) + str += csize; + + of_property_for_each_string(np, "compatible", p, compat) { + csize = strlen(compat) + 1; + tsize += csize; + if (csize > len) + continue; + + csize = snprintf(str, len, "C%s", compat); + for (c = str; c; ) { + c = strchr(c, ' '); + if (c) + *c++ = '_'; + } + len -= csize; + str += csize; + } + + return tsize; +} + +int of_request_module(const struct device_node *np) +{ + char *str; + ssize_t size; + int ret; + + if (!np) + return -ENODEV; + + size = of_modalias(np, NULL, 0); + if (size < 0) + return size; + + /* Reserve an additional byte for the trailing '\0' */ + size++; + + str = kmalloc(size, GFP_KERNEL); + if (!str) + return -ENOMEM; + + of_modalias(np, str, size); + str[size - 1] = '\0'; + ret = request_module(str); + kfree(str); + + return ret; +} +EXPORT_SYMBOL_GPL(of_request_module); diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 456776bd8ee6..6f5e5f0230d3 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -175,16 +174,21 @@ static void powerfail_interrupt(int code, void *x) -/* parisc_panic_event() is called by the panic handler. - * As soon as a panic occurs, our tasklets above will not be - * executed any longer. This function then re-enables the - * soft-power switch and allows the user to switch off the system +/* + * parisc_panic_event() is called by the panic handler. + * + * As soon as a panic occurs, our tasklets above will not + * be executed any longer. This function then re-enables + * the soft-power switch and allows the user to switch off + * the system. We rely in pdc_soft_power_button_panic() + * since this version spin_trylocks (instead of regular + * spinlock), preventing deadlocks on panic path. */ static int parisc_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { /* re-enable the soft-power switch */ - pdc_soft_power_button(0); + pdc_soft_power_button_panic(0); return NOTIFY_DONE; } diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index f33370b75628..bc32662c6bb7 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -508,19 +508,11 @@ struct hv_pcibus_device { struct msi_domain_info msi_info; struct irq_domain *irq_domain; - spinlock_t retarget_msi_interrupt_lock; - struct workqueue_struct *wq; /* Highest slot of child device with resources allocated */ int wslot_res_allocated; - - /* hypercall arg, must not cross page boundary */ - struct hv_retarget_device_interrupt retarget_msi_interrupt_params; - - /* - * Don't put anything here: retarget_msi_interrupt_params must be last - */ + bool use_calls; /* Use hypercalls to access mmio cfg space */ }; /* @@ -644,9 +636,9 @@ static void hv_arch_irq_unmask(struct irq_data *data) hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata); int_desc = data->chip_data; - spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags); + local_irq_save(flags); - params = &hbus->retarget_msi_interrupt_params; + params = *this_cpu_ptr(hyperv_pcpu_input_arg); memset(params, 0, sizeof(*params)); params->partition_id = HV_PARTITION_ID_SELF; params->int_entry.source = HV_INTERRUPT_SOURCE_MSI; @@ -679,7 +671,7 @@ static void hv_arch_irq_unmask(struct irq_data *data) if (!alloc_cpumask_var(&tmp, GFP_ATOMIC)) { res = 1; - goto exit_unlock; + goto out; } cpumask_and(tmp, dest, cpu_online_mask); @@ -688,7 +680,7 @@ static void hv_arch_irq_unmask(struct irq_data *data) if (nr_bank <= 0) { res = 1; - goto exit_unlock; + goto out; } /* @@ -707,8 +699,8 @@ static void hv_arch_irq_unmask(struct irq_data *data) res = hv_do_hypercall(HVCALL_RETARGET_INTERRUPT | (var_size << 17), params, NULL); -exit_unlock: - spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags); +out: + local_irq_restore(flags); /* * During hibernation, when a CPU is offlined, the kernel tries @@ -1041,6 +1033,70 @@ static int wslot_to_devfn(u32 wslot) return PCI_DEVFN(slot_no.bits.dev, slot_no.bits.func); } +static void hv_pci_read_mmio(struct device *dev, phys_addr_t gpa, int size, u32 *val) +{ + struct hv_mmio_read_input *in; + struct hv_mmio_read_output *out; + u64 ret; + + /* + * Must be called with interrupts disabled so it is safe + * to use the per-cpu input argument page. Use it for + * both input and output. + */ + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + out = *this_cpu_ptr(hyperv_pcpu_input_arg) + sizeof(*in); + in->gpa = gpa; + in->size = size; + + ret = hv_do_hypercall(HVCALL_MMIO_READ, in, out); + if (hv_result_success(ret)) { + switch (size) { + case 1: + *val = *(u8 *)(out->data); + break; + case 2: + *val = *(u16 *)(out->data); + break; + default: + *val = *(u32 *)(out->data); + break; + } + } else + dev_err(dev, "MMIO read hypercall error %llx addr %llx size %d\n", + ret, gpa, size); +} + +static void hv_pci_write_mmio(struct device *dev, phys_addr_t gpa, int size, u32 val) +{ + struct hv_mmio_write_input *in; + u64 ret; + + /* + * Must be called with interrupts disabled so it is safe + * to use the per-cpu input argument memory. + */ + in = *this_cpu_ptr(hyperv_pcpu_input_arg); + in->gpa = gpa; + in->size = size; + switch (size) { + case 1: + *(u8 *)(in->data) = val; + break; + case 2: + *(u16 *)(in->data) = val; + break; + default: + *(u32 *)(in->data) = val; + break; + } + + ret = hv_do_hypercall(HVCALL_MMIO_WRITE, in, NULL); + if (!hv_result_success(ret)) + dev_err(dev, "MMIO write hypercall error %llx addr %llx size %d\n", + ret, gpa, size); +} + /* * PCI Configuration Space for these root PCI buses is implemented as a pair * of pages in memory-mapped I/O space. Writing to the first page chooses @@ -1059,8 +1115,10 @@ static int wslot_to_devfn(u32 wslot) static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, int size, u32 *val) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + int offset = where + CFG_PAGE_OFFSET; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where; /* * If the attempt is to read the IDs or the ROM BAR, simulate that. @@ -1088,56 +1146,79 @@ static void _hv_pcifront_read_config(struct hv_pci_dev *hpdev, int where, */ *val = 0; } else if (where + size <= CFG_PAGE_SIZE) { - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); - /* Choose the function to be read. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start reading. */ - mb(); - /* Read from that function's config space. */ - switch (size) { - case 1: - *val = readb(addr); - break; - case 2: - *val = readw(addr); - break; - default: - *val = readl(addr); - break; + + spin_lock_irqsave(&hbus->config_lock, flags); + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + offset; + + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_read_mmio(dev, addr, size, val); + } else { + void __iomem *addr = hbus->cfg_addr + offset; + + /* Choose the function to be read. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before reading. */ + mb(); + /* Read from that function's config space. */ + switch (size) { + case 1: + *val = readb(addr); + break; + case 2: + *val = readw(addr); + break; + default: + *val = readl(addr); + break; + } + /* + * Make sure the read was done before we release the + * spinlock allowing consecutive reads/writes. + */ + mb(); } - /* - * Make sure the read was done before we release the spinlock - * allowing consecutive reads/writes. - */ - mb(); - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + spin_unlock_irqrestore(&hbus->config_lock, flags); } else { - dev_err(&hpdev->hbus->hdev->device, - "Attempt to read beyond a function's config space.\n"); + dev_err(dev, "Attempt to read beyond a function's config space.\n"); } } static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + u32 val; u16 ret; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + - PCI_VENDOR_ID; - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); + spin_lock_irqsave(&hbus->config_lock, flags); - /* Choose the function to be read. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start reading. */ - mb(); - /* Read from that function's config space. */ - ret = readw(addr); - /* - * mb() is not required here, because the spin_unlock_irqrestore() - * is a barrier. - */ + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + + CFG_PAGE_OFFSET + PCI_VENDOR_ID; - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_read_mmio(dev, addr, 2, &val); + ret = val; /* Truncates to 16 bits */ + } else { + void __iomem *addr = hbus->cfg_addr + CFG_PAGE_OFFSET + + PCI_VENDOR_ID; + /* Choose the function to be read. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before we start reading. */ + mb(); + /* Read from that function's config space. */ + ret = readw(addr); + /* + * mb() is not required here, because the + * spin_unlock_irqrestore() is a barrier. + */ + } + + spin_unlock_irqrestore(&hbus->config_lock, flags); return ret; } @@ -1152,39 +1233,51 @@ static u16 hv_pcifront_get_vendor_id(struct hv_pci_dev *hpdev) static void _hv_pcifront_write_config(struct hv_pci_dev *hpdev, int where, int size, u32 val) { + struct hv_pcibus_device *hbus = hpdev->hbus; + struct device *dev = &hbus->hdev->device; + int offset = where + CFG_PAGE_OFFSET; unsigned long flags; - void __iomem *addr = hpdev->hbus->cfg_addr + CFG_PAGE_OFFSET + where; if (where >= PCI_SUBSYSTEM_VENDOR_ID && where + size <= PCI_CAPABILITY_LIST) { /* SSIDs and ROM BARs are read-only */ } else if (where >= PCI_COMMAND && where + size <= CFG_PAGE_SIZE) { - spin_lock_irqsave(&hpdev->hbus->config_lock, flags); - /* Choose the function to be written. (See comment above) */ - writel(hpdev->desc.win_slot.slot, hpdev->hbus->cfg_addr); - /* Make sure the function was chosen before we start writing. */ - wmb(); - /* Write to that function's config space. */ - switch (size) { - case 1: - writeb(val, addr); - break; - case 2: - writew(val, addr); - break; - default: - writel(val, addr); - break; + spin_lock_irqsave(&hbus->config_lock, flags); + + if (hbus->use_calls) { + phys_addr_t addr = hbus->mem_config->start + offset; + + hv_pci_write_mmio(dev, hbus->mem_config->start, 4, + hpdev->desc.win_slot.slot); + hv_pci_write_mmio(dev, addr, size, val); + } else { + void __iomem *addr = hbus->cfg_addr + offset; + + /* Choose the function to write. (See comment above) */ + writel(hpdev->desc.win_slot.slot, hbus->cfg_addr); + /* Make sure the function was chosen before writing. */ + wmb(); + /* Write to that function's config space. */ + switch (size) { + case 1: + writeb(val, addr); + break; + case 2: + writew(val, addr); + break; + default: + writel(val, addr); + break; + } + /* + * Make sure the write was done before we release the + * spinlock allowing consecutive reads/writes. + */ + mb(); } - /* - * Make sure the write was done before we release the spinlock - * allowing consecutive reads/writes. - */ - mb(); - spin_unlock_irqrestore(&hpdev->hbus->config_lock, flags); + spin_unlock_irqrestore(&hbus->config_lock, flags); } else { - dev_err(&hpdev->hbus->hdev->device, - "Attempt to write beyond a function's config space.\n"); + dev_err(dev, "Attempt to write beyond a function's config space.\n"); } } @@ -3496,35 +3589,11 @@ static int hv_pci_probe(struct hv_device *hdev, bool enter_d0_retry = true; int ret; - /* - * hv_pcibus_device contains the hypercall arguments for retargeting in - * hv_irq_unmask(). Those must not cross a page boundary. - */ - BUILD_BUG_ON(sizeof(*hbus) > HV_HYP_PAGE_SIZE); - bridge = devm_pci_alloc_host_bridge(&hdev->device, 0); if (!bridge) return -ENOMEM; - /* - * With the recent 59bb47985c1d ("mm, sl[aou]b: guarantee natural - * alignment for kmalloc(power-of-two)"), kzalloc() is able to allocate - * a 4KB buffer that is guaranteed to be 4KB-aligned. Here the size and - * alignment of hbus is important because hbus's field - * retarget_msi_interrupt_params must not cross a 4KB page boundary. - * - * Here we prefer kzalloc to get_zeroed_page(), because a buffer - * allocated by the latter is not tracked and scanned by kmemleak, and - * hence kmemleak reports the pointer contained in the hbus buffer - * (i.e. the hpdev struct, which is created in new_pcichild_device() and - * is tracked by hbus->children) as memory leak (false positive). - * - * If the kernel doesn't have 59bb47985c1d, get_zeroed_page() *must* be - * used to allocate the hbus buffer and we can avoid the kmemleak false - * positive by using kmemleak_alloc() and kmemleak_free() to ask - * kmemleak to track and scan the hbus buffer. - */ - hbus = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); + hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); if (!hbus) return -ENOMEM; @@ -3563,6 +3632,7 @@ static int hv_pci_probe(struct hv_device *hdev, hbus->bridge->domain_nr = dom; #ifdef CONFIG_X86 hbus->sysdata.domain = dom; + hbus->use_calls = !!(ms_hyperv.hints & HV_X64_USE_MMIO_HYPERCALLS); #elif defined(CONFIG_ARM64) /* * Set the PCI bus parent to be the corresponding VMbus @@ -3572,6 +3642,7 @@ static int hv_pci_probe(struct hv_device *hdev, * information to devices created on the bus. */ hbus->sysdata.parent = hdev->device.parent; + hbus->use_calls = false; #endif hbus->hdev = hdev; @@ -3579,7 +3650,6 @@ static int hv_pci_probe(struct hv_device *hdev, INIT_LIST_HEAD(&hbus->dr_list); spin_lock_init(&hbus->config_lock); spin_lock_init(&hbus->device_list_lock); - spin_lock_init(&hbus->retarget_msi_interrupt_lock); hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0, hbus->bridge->domain_nr); if (!hbus->wq) { diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index e5e9b287b976..1b97a5ab71a9 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -20,6 +20,8 @@ #include #include +#include "pci.h" + #define PCI_DOE_PROTOCOL_DISCOVERY 0 /* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */ @@ -37,7 +39,7 @@ * * 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() + * the helpers below after being created by pci_doe_create_mb(). * * @pdev: PCI device this mailbox belongs to * @cap_offset: Capability offset @@ -56,6 +58,40 @@ struct pci_doe_mb { unsigned long flags; }; +struct pci_doe_protocol { + u16 vid; + u8 type; +}; + +/** + * 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 + */ +struct pci_doe_task { + struct pci_doe_protocol prot; + const __le32 *request_pl; + size_t request_pl_sz; + __le32 *response_pl; + size_t response_pl_sz; + int rv; + void (*complete)(struct pci_doe_task *task); + void *private; + + /* initialized by pci_doe_submit_task() */ + struct work_struct work; + struct pci_doe_mb *doe_mb; +}; + static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout) { if (wait_event_timeout(doe_mb->wq, @@ -110,7 +146,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, { struct pci_dev *pdev = doe_mb->pdev; int offset = doe_mb->cap_offset; - size_t length; + size_t length, remainder; u32 val; int i; @@ -128,7 +164,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, return -EIO; /* Length is 2 DW of header + length of payload in DW */ - length = 2 + task->request_pl_sz / sizeof(__le32); + length = 2 + DIV_ROUND_UP(task->request_pl_sz, sizeof(__le32)); if (length > PCI_DOE_MAX_LENGTH) return -EIO; if (length == PCI_DOE_MAX_LENGTH) @@ -141,10 +177,21 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, length)); + + /* Write payload */ for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++) pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, le32_to_cpu(task->request_pl[i])); + /* Write last payload dword */ + remainder = task->request_pl_sz % sizeof(__le32); + if (remainder) { + val = 0; + memcpy(&val, &task->request_pl[i], remainder); + le32_to_cpus(&val); + pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val); + } + pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO); return 0; @@ -164,11 +211,11 @@ static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb) static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) { + size_t length, payload_length, remainder, received; struct pci_dev *pdev = doe_mb->pdev; int offset = doe_mb->cap_offset; - size_t length, payload_length; + int i = 0; u32 val; - int i; /* Read the first dword to get the protocol */ pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); @@ -195,15 +242,38 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas /* First 2 dwords have already been read */ length -= 2; - payload_length = min(length, task->response_pl_sz / sizeof(__le32)); - /* Read the rest of the response payload */ - for (i = 0; i < payload_length; i++) { + received = task->response_pl_sz; + payload_length = DIV_ROUND_UP(task->response_pl_sz, sizeof(__le32)); + remainder = task->response_pl_sz % sizeof(__le32); + + /* remainder signifies number of data bytes in last payload dword */ + if (!remainder) + remainder = sizeof(__le32); + + if (length < payload_length) { + received = length * sizeof(__le32); + payload_length = length; + remainder = sizeof(__le32); + } + + if (payload_length) { + /* Read all payload dwords except the last */ + for (; i < payload_length - 1; i++) { + pci_read_config_dword(pdev, offset + PCI_DOE_READ, + &val); + task->response_pl[i] = cpu_to_le32(val); + pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); + } + + /* Read last payload dword */ pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); - task->response_pl[i] = cpu_to_le32(val); + cpu_to_le32s(&val); + memcpy(&task->response_pl[i], &val, remainder); /* Prior to the last ack, ensure Data Object Ready */ - if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb)) + if (!pci_doe_data_obj_ready(doe_mb)) return -EIO; pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); + i++; } /* Flush excess length */ @@ -217,7 +287,7 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) return -EIO; - return min(length, task->response_pl_sz / sizeof(__le32)) * sizeof(__le32); + return received; } static void signal_task_complete(struct pci_doe_task *task, int rv) @@ -321,26 +391,15 @@ static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid, __le32 request_pl_le = cpu_to_le32(request_pl); __le32 response_pl_le; 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_le, - .request_pl_sz = sizeof(request_pl), - .response_pl = &response_pl_le, - .response_pl_sz = sizeof(response_pl), - .complete = pci_doe_task_complete, - .private = &c, - }; int rc; - rc = pci_doe_submit_task(doe_mb, &task); + rc = pci_doe(doe_mb, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_PROTOCOL_DISCOVERY, + &request_pl_le, sizeof(request_pl_le), + &response_pl_le, sizeof(response_pl_le)); if (rc < 0) return rc; - wait_for_completion(&c); - - if (task.rv != sizeof(response_pl)) + if (rc != sizeof(response_pl_le)) return -EIO; response_pl = le32_to_cpu(response_pl_le); @@ -385,37 +444,18 @@ static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb) return 0; } -static void pci_doe_xa_destroy(void *mb) +static void pci_doe_cancel_tasks(struct pci_doe_mb *doe_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 + * pci_doe_create_mb() - Create a DOE mailbox object * * @pdev: PCI device to create the DOE mailbox for * @cap_offset: Offset of the DOE mailbox @@ -426,64 +466,77 @@ static void pci_doe_flush_mb(void *mb) * 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) +static struct pci_doe_mb *pci_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); + doe_mb = kzalloc(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), + dev_bus_name(&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 = -ENOMEM; + goto err_free; } - 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); + goto err_destroy_wq; } /* * The state machine and the mailbox should be in sync now; - * Set up mailbox flush prior to using the mailbox to query protocols. + * Use 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); + goto err_cancel; } return doe_mb; + +err_cancel: + pci_doe_cancel_tasks(doe_mb); + xa_destroy(&doe_mb->prots); +err_destroy_wq: + destroy_workqueue(doe_mb->work_queue); +err_free: + kfree(doe_mb); + return ERR_PTR(rc); +} + +/** + * pci_doe_destroy_mb() - Destroy a DOE mailbox object + * + * @doe_mb: DOE mailbox + * + * Destroy all internal data structures created for the DOE mailbox. + */ +static void pci_doe_destroy_mb(struct pci_doe_mb *doe_mb) +{ + pci_doe_cancel_tasks(doe_mb); + xa_destroy(&doe_mb->prots); + destroy_workqueue(doe_mb->work_queue); + kfree(doe_mb); } -EXPORT_SYMBOL_GPL(pcim_doe_create_mb); /** * pci_doe_supports_prot() - Return if the DOE instance supports the given @@ -494,7 +547,7 @@ EXPORT_SYMBOL_GPL(pcim_doe_create_mb); * * 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) +static bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type) { unsigned long index; void *entry; @@ -509,7 +562,6 @@ bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type) return false; } -EXPORT_SYMBOL_GPL(pci_doe_supports_prot); /** * pci_doe_submit_task() - Submit a task to be processed by the state machine @@ -530,19 +582,12 @@ EXPORT_SYMBOL_GPL(pci_doe_supports_prot); * * 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) +static 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(__le32) || - task->response_pl_sz < sizeof(__le32)) - return -EINVAL; - if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) return -EIO; @@ -551,4 +596,129 @@ int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) queue_work(doe_mb->work_queue, &task->work); return 0; } -EXPORT_SYMBOL_GPL(pci_doe_submit_task); + +/** + * pci_doe() - Perform Data Object Exchange + * + * @doe_mb: DOE Mailbox + * @vendor: Vendor ID + * @type: Data Object Type + * @request: Request payload + * @request_sz: Size of request payload (bytes) + * @response: Response payload + * @response_sz: Size of response payload (bytes) + * + * Submit @request to @doe_mb and store the @response. + * The DOE exchange is performed synchronously and may therefore sleep. + * + * Payloads are treated as opaque byte streams which are transmitted verbatim, + * without byte-swapping. If payloads contain little-endian register values, + * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu(). + * + * For convenience, arbitrary payload sizes are allowed even though PCIe r6.0 + * sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords. The last + * (partial) dword is copied with byte granularity and padded with zeroes if + * necessary. Callers are thus relieved of using dword-sized bounce buffers. + * + * RETURNS: Length of received response or negative errno. + * Received data in excess of @response_sz is discarded. + * The length may be smaller than @response_sz and the caller + * is responsible for checking that. + */ +int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type, + const void *request, size_t request_sz, + void *response, size_t response_sz) +{ + DECLARE_COMPLETION_ONSTACK(c); + struct pci_doe_task task = { + .prot.vid = vendor, + .prot.type = type, + .request_pl = request, + .request_pl_sz = request_sz, + .response_pl = response, + .response_pl_sz = response_sz, + .complete = pci_doe_task_complete, + .private = &c, + }; + int rc; + + rc = pci_doe_submit_task(doe_mb, &task); + if (rc) + return rc; + + wait_for_completion(&c); + + return task.rv; +} +EXPORT_SYMBOL_GPL(pci_doe); + +/** + * pci_find_doe_mailbox() - Find Data Object Exchange mailbox + * + * @pdev: PCI device + * @vendor: Vendor ID + * @type: Data Object Type + * + * Find first DOE mailbox of a PCI device which supports the given protocol. + * + * RETURNS: Pointer to the DOE mailbox or NULL if none was found. + */ +struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor, + u8 type) +{ + struct pci_doe_mb *doe_mb; + unsigned long index; + + xa_for_each(&pdev->doe_mbs, index, doe_mb) + if (pci_doe_supports_prot(doe_mb, vendor, type)) + return doe_mb; + + return NULL; +} +EXPORT_SYMBOL_GPL(pci_find_doe_mailbox); + +void pci_doe_init(struct pci_dev *pdev) +{ + struct pci_doe_mb *doe_mb; + u16 offset = 0; + int rc; + + xa_init(&pdev->doe_mbs); + + while ((offset = pci_find_next_ext_capability(pdev, offset, + PCI_EXT_CAP_ID_DOE))) { + doe_mb = pci_doe_create_mb(pdev, offset); + if (IS_ERR(doe_mb)) { + pci_err(pdev, "[%x] failed to create mailbox: %ld\n", + offset, PTR_ERR(doe_mb)); + continue; + } + + rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL); + if (rc) { + pci_err(pdev, "[%x] failed to insert mailbox: %d\n", + offset, rc); + pci_doe_destroy_mb(doe_mb); + } + } +} + +void pci_doe_destroy(struct pci_dev *pdev) +{ + struct pci_doe_mb *doe_mb; + unsigned long index; + + xa_for_each(&pdev->doe_mbs, index, doe_mb) + pci_doe_destroy_mb(doe_mb); + + xa_destroy(&pdev->doe_mbs); +} + +void pci_doe_disconnected(struct pci_dev *pdev) +{ + struct pci_doe_mb *doe_mb; + unsigned long index; + + xa_for_each(&pdev->doe_mbs, index, doe_mb) + pci_doe_cancel_tasks(doe_mb); +} diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 9440d9811eea..46c9a5c3ca14 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -860,7 +860,7 @@ EXPORT_SYMBOL_GPL(__devm_pci_epc_create); static int __init pci_epc_init(void) { - pci_epc_class = class_create(THIS_MODULE, "pci_epc"); + pci_epc_class = class_create("pci_epc"); if (IS_ERR(pci_epc_class)) { pr_err("failed to create pci epc class --> %ld\n", PTR_ERR(pci_epc_class)); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index dd0d9d9bc509..ab32a91f287b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -428,7 +428,7 @@ static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(msi_bus); -static ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { unsigned long val; struct pci_bus *b = NULL; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 199024beaee9..5ede93222bc1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6684,7 +6684,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) } } -static ssize_t resource_alignment_show(struct bus_type *bus, char *buf) +static ssize_t resource_alignment_show(const struct bus_type *bus, char *buf) { size_t count = 0; @@ -6696,7 +6696,7 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf) return count; } -static ssize_t resource_alignment_store(struct bus_type *bus, +static ssize_t resource_alignment_store(const struct bus_type *bus, const char *buf, size_t count) { char *param, *old, *end; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 67005a0ee381..2475098f6518 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -311,6 +311,16 @@ struct pci_sriov { bool drivers_autoprobe; /* Auto probing of VFs by driver */ }; +#ifdef CONFIG_PCI_DOE +void pci_doe_init(struct pci_dev *pdev); +void pci_doe_destroy(struct pci_dev *pdev); +void pci_doe_disconnected(struct pci_dev *pdev); +#else +static inline void pci_doe_init(struct pci_dev *pdev) { } +static inline void pci_doe_destroy(struct pci_dev *pdev) { } +static inline void pci_doe_disconnected(struct pci_dev *pdev) { } +#endif + /** * pci_dev_set_io_state - Set the new error state if possible. * @@ -347,6 +357,7 @@ static inline bool pci_dev_set_io_state(struct pci_dev *dev, static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) { pci_dev_set_io_state(dev, pci_channel_io_perm_failure); + pci_doe_disconnected(dev); return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9123bafab451..0b2826c4a832 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2479,6 +2479,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_aer_init(dev); /* Advanced Error Reporting */ pci_dpc_init(dev); /* Downstream Port Containment */ pci_rcec_init(dev); /* Root Complex Event Collector */ + pci_doe_init(dev); /* Data Object Exchange */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f4e2a88729fd..c525867760bf 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -6003,8 +6003,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x56c1, aspm_l1_acceptable_latency #ifdef CONFIG_PCIE_DPC /* - * Intel Tiger Lake and Alder Lake BIOS has a bug that clears the DPC - * RP PIO Log Size of the integrated Thunderbolt PCIe Root Ports. + * Intel Ice Lake, Tiger Lake and Alder Lake BIOS has a bug that clears + * the DPC RP PIO Log Size of the integrated Thunderbolt PCIe Root + * Ports. */ static void dpc_log_size(struct pci_dev *dev) { @@ -6027,6 +6028,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x461f, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x462f, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x463f, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x466e, dpc_log_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8a1d, dpc_log_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8a1f, dpc_log_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8a21, dpc_log_size); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8a23, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a23, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a25, dpc_log_size); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a27, dpc_log_size); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 30a787d45d2e..d68aee29386b 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -38,6 +38,7 @@ static void pci_destroy_dev(struct pci_dev *dev) list_del(&dev->bus_list); up_write(&pci_bus_sem); + pci_doe_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); pci_free_resources(dev); diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 3d6f17ff2429..d837da055921 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1804,7 +1804,7 @@ static int __init switchtec_init(void) if (rc) return rc; - switchtec_class = class_create(THIS_MODULE, "switchtec"); + switchtec_class = class_create("switchtec"); if (IS_ERR(switchtec_class)) { rc = PTR_ERR(switchtec_class); goto err_create_class; diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e3224e49c43f..5658745c398f 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -824,7 +824,7 @@ static int pcmcia_socket_uevent(const struct device *dev, static struct completion pcmcia_unload; -static void pcmcia_release_socket_class(struct class *data) +static void pcmcia_release_socket_class(const struct class *data) { complete(&pcmcia_unload); } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index c8087efa5e4a..d500e5dbbc3f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1335,8 +1335,7 @@ static struct pcmcia_callback pcmcia_bus_callback = { .resume = pcmcia_bus_resume, }; -static int pcmcia_bus_add_socket(struct device *dev, - struct class_interface *class_intf) +static int pcmcia_bus_add_socket(struct device *dev) { struct pcmcia_socket *socket = dev_get_drvdata(dev); int ret; @@ -1369,8 +1368,7 @@ static int pcmcia_bus_add_socket(struct device *dev, return 0; } -static void pcmcia_bus_remove_socket(struct device *dev, - struct class_interface *class_intf) +static void pcmcia_bus_remove_socket(struct device *dev) { struct pcmcia_socket *socket = dev_get_drvdata(dev); diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index ad1141fddb4c..471e0c5815f3 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -1200,8 +1200,7 @@ static const struct attribute_group rsrc_attributes = { .attrs = pccard_rsrc_attributes, }; -static int pccard_sysfs_add_rsrc(struct device *dev, - struct class_interface *class_intf) +static int pccard_sysfs_add_rsrc(struct device *dev) { struct pcmcia_socket *s = dev_get_drvdata(dev); @@ -1210,8 +1209,7 @@ static int pccard_sysfs_add_rsrc(struct device *dev, return sysfs_create_group(&dev->kobj, &rsrc_attributes); } -static void pccard_sysfs_remove_rsrc(struct device *dev, - struct class_interface *class_intf) +static void pccard_sysfs_remove_rsrc(struct device *dev) { struct pcmcia_socket *s = dev_get_drvdata(dev); diff --git a/drivers/peci/sysfs.c b/drivers/peci/sysfs.c index db9ef05776e3..c04244075794 100644 --- a/drivers/peci/sysfs.c +++ b/drivers/peci/sysfs.c @@ -15,7 +15,7 @@ static int rescan_controller(struct device *dev, void *data) return peci_controller_scan_devices(to_peci_controller(dev)); } -static ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { bool res; int ret; diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 70cb50fd41c2..4f3ac296b3e2 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -924,7 +924,7 @@ static int __init pmu_sbi_devinit(void) struct platform_device *pdev; if (sbi_spec_version < sbi_mk_version(0, 3) || - sbi_probe_extension(SBI_EXT_PMU) <= 0) { + !sbi_probe_extension(SBI_EXT_PMU)) { return 0; } diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 7bd00a11d074..f46e3148d286 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -44,7 +44,7 @@ config PHY_PISTACHIO_USB config PHY_XGENE tristate "APM X-Gene 15Gbps PHY support" - depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) + depends on HAS_IOMEM && OF && (ARCH_XGENE || COMPILE_TEST) select GENERIC_PHY help This option enables support for APM X-Gene SoC multi-purpose PHY. diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index fbcd7014ab43..56d53f78d002 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -698,7 +698,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, return data->phys[args->args[0]].phy; } -static int sun4i_usb_phy_remove(struct platform_device *pdev) +static void sun4i_usb_phy_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); @@ -711,8 +711,6 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) devm_free_irq(dev, data->vbus_det_irq, data); cancel_delayed_work_sync(&data->detect); - - return 0; } static const unsigned int sun4i_usb_phy0_cable[] = { @@ -758,7 +756,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(data->vbus_det_gpio); } - if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { + if (of_property_present(np, "usb0_vbus_power-supply")) { data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, "usb0_vbus_power-supply"); if (IS_ERR(data->vbus_power_supply)) { @@ -1054,7 +1052,7 @@ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { .probe = sun4i_usb_phy_probe, - .remove = sun4i_usb_phy_remove, + .remove_new = sun4i_usb_phy_remove, .driver = { .of_match_table = sun4i_usb_phy_of_match, .name = "sun4i-usb-phy", diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c index 32d1ff09befb..6e9af79e152c 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c @@ -335,7 +335,6 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct phy_provider *phy_provider; - struct resource *res; struct phy_meson_axg_mipi_dphy_priv *priv; struct phy *phy; void __iomem *base; @@ -348,8 +347,7 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev) priv->dev = dev; platform_set_drvdata(pdev, priv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c b/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c index c14089fa7db4..cabdddbbabfd 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c +++ b/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c @@ -70,7 +70,7 @@ static int phy_g12a_mipi_dphy_analog_power_on(struct phy *phy) HHI_MIPI_CNTL1_BANDGAP); regmap_write(priv->regmap, HHI_MIPI_CNTL2, - FIELD_PREP(HHI_MIPI_CNTL2_DIF_TX_CTL0, 0x459) | + FIELD_PREP(HHI_MIPI_CNTL2_DIF_TX_CTL0, 0x45a) | FIELD_PREP(HHI_MIPI_CNTL2_DIF_TX_CTL1, 0x2680)); reg = DSI_LANE_CLK; diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c index 6a36e187d100..269564bdf687 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c @@ -107,7 +107,7 @@ static int bcm_ns_usb2_probe(struct platform_device *pdev) return -ENOMEM; usb2->dev = dev; - if (of_find_property(dev->of_node, "brcm,syscon-clkset", NULL)) { + if (of_property_present(dev->of_node, "brcm,syscon-clkset")) { usb2->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(usb2->base)) { dev_err(dev, "Failed to map control reg\n"); diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index 4de39999f43d..a4cfb777dd83 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -572,14 +572,12 @@ static int brcm_usb_phy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } -static int brcm_usb_phy_remove(struct platform_device *pdev) +static void brcm_usb_phy_remove(struct platform_device *pdev) { struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev); sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group); unregister_pm_notifier(&priv->pm_notifier); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -670,7 +668,7 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids); static struct platform_driver brcm_usb_driver = { .probe = brcm_usb_phy_probe, - .remove = brcm_usb_phy_remove, + .remove_new = brcm_usb_phy_remove, .driver = { .name = "brcmstb-usb-phy", .pm = &brcm_usb_phy_pm_ops, diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c index 572c70089a94..c05b043893a9 100644 --- a/drivers/phy/cadence/cdns-dphy-rx.c +++ b/drivers/phy/cadence/cdns-dphy-rx.c @@ -11,10 +11,12 @@ #include #include #include +#include #define DPHY_PMA_CMN(reg) (reg) #define DPHY_PCS(reg) (0xb00 + (reg)) #define DPHY_ISO(reg) (0xc00 + (reg)) +#define DPHY_WRAP(reg) (0x1000 + (reg)) #define DPHY_CMN_SSM DPHY_PMA_CMN(0x20) #define DPHY_CMN_RX_MODE_EN BIT(10) @@ -33,6 +35,9 @@ #define DPHY_POWER_ISLAND_EN_CLK DPHY_PCS(0xc) #define DPHY_POWER_ISLAND_EN_CLK_VAL 0xaa +#define DPHY_LANE DPHY_WRAP(0x0) +#define DPHY_LANE_RESET_CMN_EN BIT(23) + #define DPHY_ISO_CL_CTRL_L DPHY_ISO(0x10) #define DPHY_ISO_DL_CTRL_L0 DPHY_ISO(0x14) #define DPHY_ISO_DL_CTRL_L1 DPHY_ISO(0x20) @@ -57,6 +62,10 @@ struct cdns_dphy_rx_band { unsigned int max_rate; }; +struct cdns_dphy_soc_data { + bool has_hw_cmn_rstb; +}; + /* Order of bands is important since the index is the band number. */ static const struct cdns_dphy_rx_band bands[] = { { 80, 100 }, { 100, 120 }, { 120, 160 }, { 160, 200 }, { 200, 240 }, @@ -142,13 +151,36 @@ static int cdns_dphy_rx_wait_lane_ready(struct cdns_dphy_rx *dphy, return 0; } +static struct cdns_dphy_soc_data j721e_soc_data = { + .has_hw_cmn_rstb = true, +}; + +static const struct soc_device_attribute cdns_dphy_socinfo[] = { + { + .family = "J721E", + .revision = "SR1.0", + .data = &j721e_soc_data, + }, + {/* sentinel */} +}; + static int cdns_dphy_rx_configure(struct phy *phy, union phy_configure_opts *opts) { struct cdns_dphy_rx *dphy = phy_get_drvdata(phy); unsigned int reg, lanes = opts->mipi_dphy.lanes; + const struct cdns_dphy_soc_data *soc_data = NULL; + const struct soc_device_attribute *soc; int band_ctrl, ret; + soc = soc_device_match(cdns_dphy_socinfo); + if (soc && soc->data) + soc_data = soc->data; + if (!soc || (soc_data && !soc_data->has_hw_cmn_rstb)) { + reg = DPHY_LANE_RESET_CMN_EN; + writel(reg, dphy->regs + DPHY_LANE); + } + /* Data lanes. Minimum one lane is mandatory. */ if (lanes < DPHY_LANES_MIN || lanes > DPHY_LANES_MAX) return -EINVAL; diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index 3dfdfb33cd0a..6e58012b6488 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -456,14 +456,12 @@ static int cdns_dphy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } -static int cdns_dphy_remove(struct platform_device *pdev) +static void cdns_dphy_remove(struct platform_device *pdev) { struct cdns_dphy *dphy = dev_get_drvdata(&pdev->dev); if (dphy->ops->remove) dphy->ops->remove(dphy); - - return 0; } static const struct of_device_id cdns_dphy_of_match[] = { @@ -475,7 +473,7 @@ MODULE_DEVICE_TABLE(of, cdns_dphy_of_match); static struct platform_driver cdns_dphy_platform_driver = { .probe = cdns_dphy_probe, - .remove = cdns_dphy_remove, + .remove_new = cdns_dphy_remove, .driver = { .name = "cdns-mipi-dphy", .of_match_table = cdns_dphy_of_match, diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 6e86a6517f37..13fcd3a65fe9 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -24,7 +24,7 @@ #include #define NUM_SSC_MODE 3 -#define NUM_PHY_TYPE 4 +#define NUM_PHY_TYPE 5 /* PHY register offsets */ #define SIERRA_COMMON_CDB_OFFSET 0x0 @@ -46,7 +46,9 @@ #define SIERRA_CMN_REFRCV_PREG 0x98 #define SIERRA_CMN_REFRCV1_PREG 0xB8 #define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2 +#define SIERRA_CMN_PLLLC1_FBDIV_INT_PREG 0xC3 #define SIERRA_CMN_PLLLC1_LF_COEFF_MODE0_PREG 0xCA +#define SIERRA_CMN_PLLLC1_CLK0_PREG 0xCE #define SIERRA_CMN_PLLLC1_BWCAL_MODE0_PREG 0xD0 #define SIERRA_CMN_PLLLC1_SS_TIME_STEPSIZE_MODE_PREG 0xE2 @@ -74,6 +76,7 @@ #define SIERRA_PSC_RX_A1_PREG 0x031 #define SIERRA_PSC_RX_A2_PREG 0x032 #define SIERRA_PSC_RX_A3_PREG 0x033 +#define SIERRA_PLLCTRL_FBDIV_MODE01_PREG 0x039 #define SIERRA_PLLCTRL_SUBRATE_PREG 0x03A #define SIERRA_PLLCTRL_GEN_A_PREG 0x03B #define SIERRA_PLLCTRL_GEN_D_PREG 0x03E @@ -206,13 +209,11 @@ #define PLL_LOCK_TIME 100000 #define CDNS_SIERRA_OUTPUT_CLOCKS 3 -#define CDNS_SIERRA_INPUT_CLOCKS 5 +#define CDNS_SIERRA_INPUT_CLOCKS 3 enum cdns_sierra_clock_input { PHY_CLK, CMN_REFCLK_DIG_DIV, CMN_REFCLK1_DIG_DIV, - PLL0_REFCLK, - PLL1_REFCLK, }; #define SIERRA_NUM_CMN_PLLC 2 @@ -274,9 +275,18 @@ struct cdns_sierra_pll_mux { #define to_cdns_sierra_pll_mux(_hw) \ container_of(_hw, struct cdns_sierra_pll_mux, hw) -static const int pll_mux_parent_index[][SIERRA_NUM_CMN_PLLC_PARENTS] = { - [CMN_PLLLC] = { PLL0_REFCLK, PLL1_REFCLK }, - [CMN_PLLLC1] = { PLL1_REFCLK, PLL0_REFCLK }, +#define PLL0_REFCLK_NAME "pll0_refclk" +#define PLL1_REFCLK_NAME "pll1_refclk" + +static const struct clk_parent_data pll_mux_parent_data[][SIERRA_NUM_CMN_PLLC_PARENTS] = { + [CMN_PLLLC] = { + { .fw_name = PLL0_REFCLK_NAME }, + { .fw_name = PLL1_REFCLK_NAME } + }, + [CMN_PLLLC1] = { + { .fw_name = PLL1_REFCLK_NAME }, + { .fw_name = PLL0_REFCLK_NAME } + }, }; static u32 cdns_sierra_pll_mux_table[][SIERRA_NUM_CMN_PLLC_PARENTS] = { @@ -298,6 +308,7 @@ enum cdns_sierra_phy_type { TYPE_NONE, TYPE_PCIE, TYPE_USB, + TYPE_SGMII, TYPE_QSGMII }; @@ -371,8 +382,8 @@ struct cdns_sierra_phy { u32 num_lanes; bool autoconf; int already_configured; - struct clk_onecell_data clk_data; - struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS]; + struct clk *pll_clks[SIERRA_NUM_CMN_PLLC]; + struct clk_hw_onecell_data clk_data; }; static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val) @@ -722,38 +733,21 @@ static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp, struct cdns_sierra_pll_mux *mux; struct device *dev = sp->dev; struct clk_init_data *init; - const char **parent_names; - unsigned int num_parents; char clk_name[100]; - struct clk *clk; - int i; + int ret; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); if (!mux) return -ENOMEM; - num_parents = SIERRA_NUM_CMN_PLLC_PARENTS; - parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL); - if (!parent_names) - return -ENOMEM; - - for (i = 0; i < num_parents; i++) { - clk = sp->input_clks[pll_mux_parent_index[clk_index][i]]; - if (IS_ERR_OR_NULL(clk)) { - dev_err(dev, "No parent clock for PLL mux clocks\n"); - return IS_ERR(clk) ? PTR_ERR(clk) : -ENOENT; - } - parent_names[i] = __clk_get_name(clk); - } - snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), clk_names[clk_index]); init = &mux->clk_data; init->ops = &cdns_sierra_pll_mux_ops; init->flags = CLK_SET_RATE_NO_REPARENT; - init->parent_names = parent_names; - init->num_parents = num_parents; + init->parent_data = pll_mux_parent_data[clk_index]; + init->num_parents = SIERRA_NUM_CMN_PLLC_PARENTS; init->name = clk_name; mux->pfdclk_sel_preg = pfdclk1_sel_field; @@ -761,11 +755,14 @@ static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp, mux->termen_field = termen_field; mux->hw.init = init; - clk = devm_clk_register(dev, &mux->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &mux->hw); + if (ret) + return ret; - sp->output_clks[clk_index] = clk; + sp->clk_data.hws[clk_index] = &mux->hw; + + sp->pll_clks[clk_index] = devm_clk_hw_get_clk(dev, &mux->hw, + clk_names[clk_index]); return 0; } @@ -838,7 +835,7 @@ static int cdns_sierra_derived_refclk_register(struct cdns_sierra_phy *sp) struct clk_init_data *init; struct regmap *regmap; char clk_name[100]; - struct clk *clk; + int ret; derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL); if (!derived_refclk) @@ -871,11 +868,11 @@ static int cdns_sierra_derived_refclk_register(struct cdns_sierra_phy *sp) derived_refclk->hw.init = init; - clk = devm_clk_register(dev, &derived_refclk->hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_hw_register(dev, &derived_refclk->hw); + if (ret) + return ret; - sp->output_clks[CDNS_SIERRA_DERIVED_REFCLK] = clk; + sp->clk_data.hws[CDNS_SIERRA_DERIVED_REFCLK] = &derived_refclk->hw; return 0; } @@ -906,9 +903,9 @@ static int cdns_sierra_clk_register(struct cdns_sierra_phy *sp) return ret; } - sp->clk_data.clks = sp->output_clks; - sp->clk_data.clk_num = CDNS_SIERRA_OUTPUT_CLOCKS; - ret = of_clk_add_provider(node, of_clk_src_onecell_get, &sp->clk_data); + sp->clk_data.num = CDNS_SIERRA_OUTPUT_CLOCKS; + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, + &sp->clk_data); if (ret) dev_err(dev, "Failed to add clock provider: %s\n", node->name); @@ -936,6 +933,9 @@ static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst, case PHY_TYPE_USB3: inst->phy_type = TYPE_USB; break; + case PHY_TYPE_SGMII: + inst->phy_type = TYPE_SGMII; + break; case PHY_TYPE_QSGMII: inst->phy_type = TYPE_QSGMII; break; @@ -1147,22 +1147,6 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp, } sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk; - clk = devm_clk_get_optional(dev, "pll0_refclk"); - if (IS_ERR(clk)) { - dev_err(dev, "pll0_refclk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - sp->input_clks[PLL0_REFCLK] = clk; - - clk = devm_clk_get_optional(dev, "pll1_refclk"); - if (IS_ERR(clk)) { - dev_err(dev, "pll1_refclk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - sp->input_clks[PLL1_REFCLK] = clk; - return 0; } @@ -1190,26 +1174,26 @@ static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp) { int ret; - ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + ret = clk_prepare_enable(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]); if (ret) return ret; - ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); + ret = clk_prepare_enable(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC1]); if (ret) goto err_pll_cmnlc1; return 0; err_pll_cmnlc1: - clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]); return ret; } static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp) { - clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); - clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); + clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC1]); + clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]); if (!sp->already_configured) clk_disable_unprepare(sp->input_clks[PHY_CLK]); } @@ -1339,7 +1323,7 @@ static int cdns_sierra_phy_configure_multilink(struct cdns_sierra_phy *sp) } } - if (phy_t1 == TYPE_QSGMII) + if (phy_t1 == TYPE_SGMII || phy_t1 == TYPE_QSGMII) reset_control_deassert(sp->phys[node].lnk_rst); } @@ -1370,7 +1354,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (!data) return -EINVAL; - sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL); + sp = devm_kzalloc(dev, struct_size(sp, clk_data.hws, + CDNS_SIERRA_OUTPUT_CLOCKS), + GFP_KERNEL); if (!sp) return -ENOMEM; dev_set_drvdata(dev, sp); @@ -1513,7 +1499,7 @@ unregister_clk: return ret; } -static int cdns_sierra_phy_remove(struct platform_device *pdev) +static void cdns_sierra_phy_remove(struct platform_device *pdev) { struct cdns_sierra_phy *phy = platform_get_drvdata(pdev); int i; @@ -1533,10 +1519,73 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev) } cdns_sierra_clk_unregister(phy); - - return 0; } +/* SGMII PHY PMA lane configuration */ +static struct cdns_reg_pairs sgmii_phy_pma_ln_regs[] = { + {0x9010, SIERRA_PHY_PMA_XCVR_CTRL} +}; + +static struct cdns_sierra_vals sgmii_phy_pma_ln_vals = { + .reg_pairs = sgmii_phy_pma_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_phy_pma_ln_regs), +}; + +/* SGMII refclk 100MHz, no ssc, opt3 and GE1 links using PLL LC1 */ +static const struct cdns_reg_pairs sgmii_100_no_ssc_plllc1_opt3_cmn_regs[] = { + {0x002D, SIERRA_CMN_PLLLC1_FBDIV_INT_PREG}, + {0x2085, SIERRA_CMN_PLLLC1_LF_COEFF_MODE0_PREG}, + {0x1005, SIERRA_CMN_PLLLC1_CLK0_PREG}, + {0x0000, SIERRA_CMN_PLLLC1_BWCAL_MODE0_PREG}, + {0x0800, SIERRA_CMN_PLLLC1_SS_TIME_STEPSIZE_MODE_PREG} +}; + +static const struct cdns_reg_pairs sgmii_100_no_ssc_plllc1_opt3_ln_regs[] = { + {0x688E, SIERRA_DET_STANDEC_D_PREG}, + {0x0004, SIERRA_PSC_LN_IDLE_PREG}, + {0x0FFE, SIERRA_PSC_RX_A0_PREG}, + {0x0106, SIERRA_PLLCTRL_FBDIV_MODE01_PREG}, + {0x0013, SIERRA_PLLCTRL_SUBRATE_PREG}, + {0x0003, SIERRA_PLLCTRL_GEN_A_PREG}, + {0x0106, SIERRA_PLLCTRL_GEN_D_PREG}, + {0x5231, SIERRA_PLLCTRL_CPGAIN_MODE_PREG }, + {0x0000, SIERRA_DRVCTRL_ATTEN_PREG}, + {0x9702, SIERRA_DRVCTRL_BOOST_PREG}, + {0x0051, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG}, + {0x3C0E, SIERRA_CREQ_CCLKDET_MODE01_PREG}, + {0x3220, SIERRA_CREQ_FSMCLK_SEL_PREG}, + {0x0000, SIERRA_CREQ_EQ_CTRL_PREG}, + {0x0002, SIERRA_DEQ_PHALIGN_CTRL}, + {0x0186, SIERRA_DEQ_GLUT0}, + {0x0186, SIERRA_DEQ_GLUT1}, + {0x0186, SIERRA_DEQ_GLUT2}, + {0x0186, SIERRA_DEQ_GLUT3}, + {0x0186, SIERRA_DEQ_GLUT4}, + {0x0861, SIERRA_DEQ_ALUT0}, + {0x07E0, SIERRA_DEQ_ALUT1}, + {0x079E, SIERRA_DEQ_ALUT2}, + {0x071D, SIERRA_DEQ_ALUT3}, + {0x03F5, SIERRA_DEQ_DFETAP_CTRL_PREG}, + {0x0C01, SIERRA_DEQ_TAU_CTRL1_FAST_MAINT_PREG}, + {0x3C40, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, + {0x1C04, SIERRA_DEQ_TAU_CTRL2_PREG}, + {0x0033, SIERRA_DEQ_PICTRL_PREG}, + {0x0000, SIERRA_CPI_OUTBUF_RATESEL_PREG}, + {0x0B6D, SIERRA_CPI_RESBIAS_BIN_PREG}, + {0x0102, SIERRA_RXBUFFER_CTLECTRL_PREG}, + {0x0002, SIERRA_RXBUFFER_RCDFECTRL_PREG} +}; + +static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_cmn_vals = { + .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_cmn_regs, + .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_cmn_regs), +}; + +static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_ln_vals = { + .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_ln_regs), +}; + /* QSGMII PHY PMA lane configuration */ static struct cdns_reg_pairs qsgmii_phy_pma_ln_regs[] = { {0x9010, SIERRA_PHY_PMA_XCVR_CTRL} @@ -2363,6 +2412,11 @@ static const struct cdns_sierra_data cdns_map_sierra = { [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_phy_pcs_cmn_vals, + [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, + [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &pcie_phy_pcs_cmn_vals, [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, @@ -2377,6 +2431,11 @@ static const struct cdns_sierra_data cdns_map_sierra = { [EXTERNAL_SSC] = &pcie_100_ext_ssc_cmn_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_plllc_cmn_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals, [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals, @@ -2388,6 +2447,13 @@ static const struct cdns_sierra_data cdns_map_sierra = { [EXTERNAL_SSC] = &usb_100_ext_ssc_cmn_vals, }, }, + [TYPE_SGMII] = { + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + }, + }, [TYPE_QSGMII] = { [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_plllc1_cmn_vals, @@ -2403,6 +2469,11 @@ static const struct cdns_sierra_data cdns_map_sierra = { [EXTERNAL_SSC] = &pcie_100_ext_ssc_ln_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &ml_pcie_100_no_ssc_ln_vals, + [EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals, + [INTERNAL_SSC] = &ml_pcie_100_int_ssc_ln_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &ml_pcie_100_no_ssc_ln_vals, [EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals, @@ -2414,6 +2485,13 @@ static const struct cdns_sierra_data cdns_map_sierra = { [EXTERNAL_SSC] = &usb_100_ext_ssc_ln_vals, }, }, + [TYPE_SGMII] = { + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + }, + }, [TYPE_QSGMII] = { [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_plllc1_ln_vals, @@ -2435,6 +2513,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_phy_pcs_cmn_vals, + [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, + [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &pcie_phy_pcs_cmn_vals, [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals, @@ -2443,6 +2526,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { }, }, .phy_pma_ln_vals = { + [TYPE_SGMII] = { + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_phy_pma_ln_vals, + [EXTERNAL_SSC] = &sgmii_phy_pma_ln_vals, + [INTERNAL_SSC] = &sgmii_phy_pma_ln_vals, + }, + }, [TYPE_QSGMII] = { [TYPE_PCIE] = { [NO_SSC] = &qsgmii_phy_pma_ln_vals, @@ -2458,6 +2548,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { [EXTERNAL_SSC] = &pcie_100_ext_ssc_cmn_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_plllc_cmn_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals, [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals, @@ -2469,6 +2564,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { [EXTERNAL_SSC] = &usb_100_ext_ssc_cmn_vals, }, }, + [TYPE_SGMII] = { + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, + }, + }, [TYPE_QSGMII] = { [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_plllc1_cmn_vals, @@ -2484,6 +2586,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { [EXTERNAL_SSC] = &pcie_100_ext_ssc_ln_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals, }, + [TYPE_SGMII] = { + [NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals, + [EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals, + [INTERNAL_SSC] = &ti_ml_pcie_100_int_ssc_ln_vals, + }, [TYPE_QSGMII] = { [NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals, [EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals, @@ -2495,6 +2602,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { [EXTERNAL_SSC] = &usb_100_ext_ssc_ln_vals, }, }, + [TYPE_SGMII] = { + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, + }, + }, [TYPE_QSGMII] = { [TYPE_PCIE] = { [NO_SSC] = &qsgmii_100_no_ssc_plllc1_ln_vals, @@ -2520,7 +2634,7 @@ MODULE_DEVICE_TABLE(of, cdns_sierra_id_table); static struct platform_driver cdns_sierra_driver = { .probe = cdns_sierra_phy_probe, - .remove = cdns_sierra_phy_remove, + .remove_new = cdns_sierra_phy_remove, .driver = { .name = "cdns-sierra-phy", .of_match_table = cdns_sierra_id_table, diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index f099053c583c..3831f596d50c 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -2777,7 +2777,7 @@ clk_cleanup: return ret; } -static int cdns_torrent_phy_remove(struct platform_device *pdev) +static void cdns_torrent_phy_remove(struct platform_device *pdev) { struct cdns_torrent_phy *cdns_phy = platform_get_drvdata(pdev); int i; @@ -2791,8 +2791,6 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev) clk_disable_unprepare(cdns_phy->clk); cdns_torrent_clk_cleanup(cdns_phy); - - return 0; } /* Single DisplayPort(DP) link configuration */ @@ -4708,7 +4706,7 @@ MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match); static struct platform_driver cdns_torrent_phy_driver = { .probe = cdns_torrent_phy_probe, - .remove = cdns_torrent_phy_remove, + .remove_new = cdns_torrent_phy_remove, .driver = { .name = "cdns-torrent-phy", .of_match_table = cdns_torrent_phy_of_match, diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index e514b64bfdab..0ae052df3765 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -391,11 +391,9 @@ err: return ret; } -static int mixel_lvds_phy_remove(struct platform_device *pdev) +static void mixel_lvds_phy_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static int __maybe_unused mixel_lvds_phy_runtime_suspend(struct device *dev) @@ -436,7 +434,7 @@ MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match); static struct platform_driver mixel_lvds_phy_driver = { .probe = mixel_lvds_phy_probe, - .remove = mixel_lvds_phy_remove, + .remove_new = mixel_lvds_phy_remove, .driver = { .pm = &mixel_lvds_phy_pm_ops, .name = "mixel-lvds-phy", diff --git a/drivers/phy/intel/Kconfig b/drivers/phy/intel/Kconfig index 18a3cc5b98c0..ac42bb2fb394 100644 --- a/drivers/phy/intel/Kconfig +++ b/drivers/phy/intel/Kconfig @@ -46,13 +46,3 @@ config PHY_INTEL_LGM_EMMC select GENERIC_PHY help Enable this to support the Intel EMMC PHY - -config PHY_INTEL_THUNDERBAY_EMMC - tristate "Intel Thunder Bay eMMC PHY driver" - depends on OF && (ARCH_THUNDERBAY || COMPILE_TEST) - select GENERIC_PHY - help - This option enables support for Intel Thunder Bay SoC eMMC PHY. - - To compile this driver as a module, choose M here: the module - will be called phy-intel-thunderbay-emmc.ko. diff --git a/drivers/phy/intel/Makefile b/drivers/phy/intel/Makefile index b7321d56b0bb..14550981a707 100644 --- a/drivers/phy/intel/Makefile +++ b/drivers/phy/intel/Makefile @@ -3,4 +3,3 @@ obj-$(CONFIG_PHY_INTEL_KEEMBAY_EMMC) += phy-intel-keembay-emmc.o obj-$(CONFIG_PHY_INTEL_KEEMBAY_USB) += phy-intel-keembay-usb.o obj-$(CONFIG_PHY_INTEL_LGM_COMBO) += phy-intel-lgm-combo.o obj-$(CONFIG_PHY_INTEL_LGM_EMMC) += phy-intel-lgm-emmc.o -obj-$(CONFIG_PHY_INTEL_THUNDERBAY_EMMC) += phy-intel-thunderbay-emmc.o diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index 6010e246d52e..d32e267c0001 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -589,13 +589,12 @@ static int intel_cbphy_probe(struct platform_device *pdev) return intel_cbphy_create(cbphy); } -static int intel_cbphy_remove(struct platform_device *pdev) +static void intel_cbphy_remove(struct platform_device *pdev) { struct intel_combo_phy *cbphy = platform_get_drvdata(pdev); intel_cbphy_rst_assert(cbphy); clk_disable_unprepare(cbphy->core_clk); - return 0; } static const struct of_device_id of_intel_cbphy_match[] = { @@ -606,7 +605,7 @@ static const struct of_device_id of_intel_cbphy_match[] = { static struct platform_driver intel_cbphy_driver = { .probe = intel_cbphy_probe, - .remove = intel_cbphy_remove, + .remove_new = intel_cbphy_remove, .driver = { .name = "intel-combo-phy", .of_match_table = of_intel_cbphy_match, @@ -616,4 +615,3 @@ static struct platform_driver intel_cbphy_driver = { module_platform_driver(intel_cbphy_driver); MODULE_DESCRIPTION("Intel Combo-phy driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/intel/phy-intel-thunderbay-emmc.c b/drivers/phy/intel/phy-intel-thunderbay-emmc.c deleted file mode 100644 index 593f6970b81e..000000000000 --- a/drivers/phy/intel/phy-intel-thunderbay-emmc.c +++ /dev/null @@ -1,509 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel ThunderBay eMMC PHY driver - * - * Copyright (C) 2021 Intel Corporation - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* eMMC/SD/SDIO core/phy configuration registers */ -#define CTRL_CFG_0 0x00 -#define CTRL_CFG_1 0x04 -#define CTRL_PRESET_0 0x08 -#define CTRL_PRESET_1 0x0c -#define CTRL_PRESET_2 0x10 -#define CTRL_PRESET_3 0x14 -#define CTRL_PRESET_4 0x18 -#define CTRL_CFG_2 0x1c -#define CTRL_CFG_3 0x20 -#define PHY_CFG_0 0x24 -#define PHY_CFG_1 0x28 -#define PHY_CFG_2 0x2c -#define PHYBIST_CTRL 0x30 -#define SDHC_STAT3 0x34 -#define PHY_STAT 0x38 -#define PHYBIST_STAT_0 0x3c -#define PHYBIST_STAT_1 0x40 -#define EMMC_AXI 0x44 - -/* CTRL_PRESET_3 */ -#define CTRL_PRESET3_MASK GENMASK(31, 0) -#define CTRL_PRESET3_SHIFT 0 - -/* CTRL_CFG_0 bit fields */ -#define SUPPORT_HS_MASK BIT(26) -#define SUPPORT_HS_SHIFT 26 - -#define SUPPORT_8B_MASK BIT(24) -#define SUPPORT_8B_SHIFT 24 - -/* CTRL_CFG_1 bit fields */ -#define SUPPORT_SDR50_MASK BIT(28) -#define SUPPORT_SDR50_SHIFT 28 -#define SLOT_TYPE_MASK GENMASK(27, 26) -#define SLOT_TYPE_OFFSET 26 -#define SUPPORT_64B_MASK BIT(24) -#define SUPPORT_64B_SHIFT 24 -#define SUPPORT_HS400_MASK BIT(2) -#define SUPPORT_HS400_SHIFT 2 -#define SUPPORT_DDR50_MASK BIT(1) -#define SUPPORT_DDR50_SHIFT 1 -#define SUPPORT_SDR104_MASK BIT(0) -#define SUPPORT_SDR104_SHIFT 0 - -/* PHY_CFG_0 bit fields */ -#define SEL_DLY_TXCLK_MASK BIT(29) -#define SEL_DLY_TXCLK_SHIFT 29 -#define SEL_DLY_RXCLK_MASK BIT(28) -#define SEL_DLY_RXCLK_SHIFT 28 - -#define OTAP_DLY_ENA_MASK BIT(27) -#define OTAP_DLY_ENA_SHIFT 27 -#define OTAP_DLY_SEL_MASK GENMASK(26, 23) -#define OTAP_DLY_SEL_SHIFT 23 -#define ITAP_CHG_WIN_MASK BIT(22) -#define ITAP_CHG_WIN_SHIFT 22 -#define ITAP_DLY_ENA_MASK BIT(21) -#define ITAP_DLY_ENA_SHIFT 21 -#define ITAP_DLY_SEL_MASK GENMASK(20, 16) -#define ITAP_DLY_SEL_SHIFT 16 -#define RET_ENB_MASK BIT(15) -#define RET_ENB_SHIFT 15 -#define RET_EN_MASK BIT(14) -#define RET_EN_SHIFT 14 -#define DLL_IFF_MASK GENMASK(13, 11) -#define DLL_IFF_SHIFT 11 -#define DLL_EN_MASK BIT(10) -#define DLL_EN_SHIFT 10 -#define DLL_TRIM_ICP_MASK GENMASK(9, 6) -#define DLL_TRIM_ICP_SHIFT 6 -#define RETRIM_EN_MASK BIT(5) -#define RETRIM_EN_SHIFT 5 -#define RETRIM_MASK BIT(4) -#define RETRIM_SHIFT 4 -#define DR_TY_MASK GENMASK(3, 1) -#define DR_TY_SHIFT 1 -#define PWR_DOWN_MASK BIT(0) -#define PWR_DOWN_SHIFT 0 - -/* PHY_CFG_1 bit fields */ -#define REN_DAT_MASK GENMASK(19, 12) -#define REN_DAT_SHIFT 12 -#define REN_CMD_MASK BIT(11) -#define REN_CMD_SHIFT 11 -#define REN_STRB_MASK BIT(10) -#define REN_STRB_SHIFT 10 -#define PU_STRB_MASK BIT(20) -#define PU_STRB_SHIFT 20 - -/* PHY_CFG_2 bit fields */ -#define CLKBUF_MASK GENMASK(24, 21) -#define CLKBUF_SHIFT 21 -#define SEL_STRB_MASK GENMASK(20, 13) -#define SEL_STRB_SHIFT 13 -#define SEL_FREQ_MASK GENMASK(12, 10) -#define SEL_FREQ_SHIFT 10 - -/* PHY_STAT bit fields */ -#define CAL_DONE BIT(6) -#define DLL_RDY BIT(5) - -#define OTAP_DLY 0x0 -#define ITAP_DLY 0x0 -#define STRB 0x33 - -/* From ACS_eMMC51_16nFFC_RO1100_Userguide_v1p0.pdf p17 */ -#define FREQSEL_200M_170M 0x0 -#define FREQSEL_170M_140M 0x1 -#define FREQSEL_140M_110M 0x2 -#define FREQSEL_110M_80M 0x3 -#define FREQSEL_80M_50M 0x4 -#define FREQSEL_275M_250M 0x5 -#define FREQSEL_250M_225M 0x6 -#define FREQSEL_225M_200M 0x7 - -/* Phy power status */ -#define PHY_UNINITIALIZED 0 -#define PHY_INITIALIZED 1 - -/* - * During init(400KHz) phy_settings will be called with 200MHZ clock - * To avoid incorrectly setting the phy for init(400KHZ) "phy_power_sts" is used. - * When actual clock is set always phy is powered off once and then powered on. - * (sdhci_arasan_set_clock). That feature will be used to identify whether the - * settings are for init phy_power_on or actual clock phy_power_on - * 0 --> init settings - * 1 --> actual settings - */ - -struct thunderbay_emmc_phy { - void __iomem *reg_base; - struct clk *emmcclk; - int phy_power_sts; -}; - -static inline void update_reg(struct thunderbay_emmc_phy *tbh_phy, u32 offset, - u32 mask, u32 shift, u32 val) -{ - u32 tmp; - - tmp = readl(tbh_phy->reg_base + offset); - tmp &= ~mask; - tmp |= val << shift; - writel(tmp, tbh_phy->reg_base + offset); -} - -static int thunderbay_emmc_phy_power(struct phy *phy, bool power_on) -{ - struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy); - unsigned int freqsel = FREQSEL_200M_170M; - unsigned long rate; - static int lock; - u32 val; - int ret; - - /* Disable DLL */ - rate = clk_get_rate(tbh_phy->emmcclk); - switch (rate) { - case 200000000: - /* lock dll only when it is used, i.e only if SEL_DLY_TXCLK/RXCLK are 0 */ - update_reg(tbh_phy, PHY_CFG_0, DLL_EN_MASK, DLL_EN_SHIFT, 0x0); - break; - - /* dll lock not required for other frequencies */ - case 50000000 ... 52000000: - case 400000: - default: - break; - } - - if (!power_on) - return 0; - - rate = clk_get_rate(tbh_phy->emmcclk); - switch (rate) { - case 170000001 ... 200000000: - freqsel = FREQSEL_200M_170M; - break; - - case 140000001 ... 170000000: - freqsel = FREQSEL_170M_140M; - break; - - case 110000001 ... 140000000: - freqsel = FREQSEL_140M_110M; - break; - - case 80000001 ... 110000000: - freqsel = FREQSEL_110M_80M; - break; - - case 50000000 ... 80000000: - freqsel = FREQSEL_80M_50M; - break; - - case 250000001 ... 275000000: - freqsel = FREQSEL_275M_250M; - break; - - case 225000001 ... 250000000: - freqsel = FREQSEL_250M_225M; - break; - - case 200000001 ... 225000000: - freqsel = FREQSEL_225M_200M; - break; - default: - break; - } - /* Clock rate is checked against upper limit. It may fall low during init */ - if (rate > 200000000) - dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate); - - udelay(5); - - if (lock == 0) { - /* PDB will be done only once per boot */ - update_reg(tbh_phy, PHY_CFG_0, PWR_DOWN_MASK, - PWR_DOWN_SHIFT, 0x1); - lock = 1; - /* - * According to the user manual, it asks driver to wait 5us for - * calpad busy trimming. However it is documented that this value is - * PVT(A.K.A. process, voltage and temperature) relevant, so some - * failure cases are found which indicates we should be more tolerant - * to calpad busy trimming. - */ - ret = readl_poll_timeout(tbh_phy->reg_base + PHY_STAT, - val, (val & CAL_DONE), 10, 50); - if (ret) { - dev_err(&phy->dev, "caldone failed, ret=%d\n", ret); - return ret; - } - } - rate = clk_get_rate(tbh_phy->emmcclk); - switch (rate) { - case 200000000: - /* Set frequency of the DLL operation */ - update_reg(tbh_phy, PHY_CFG_2, SEL_FREQ_MASK, SEL_FREQ_SHIFT, freqsel); - - /* Enable DLL */ - update_reg(tbh_phy, PHY_CFG_0, DLL_EN_MASK, DLL_EN_SHIFT, 0x1); - - /* - * After enabling analog DLL circuits docs say that we need 10.2 us if - * our source clock is at 50 MHz and that lock time scales linearly - * with clock speed. If we are powering on the PHY and the card clock - * is super slow (like 100kHz) this could take as long as 5.1 ms as - * per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms - * hopefully we won't be running at 100 kHz, but we should still make - * sure we wait long enough. - * - * NOTE: There appear to be corner cases where the DLL seems to take - * extra long to lock for reasons that aren't understood. In some - * extreme cases we've seen it take up to over 10ms (!). We'll be - * generous and give it 50ms. - */ - ret = readl_poll_timeout(tbh_phy->reg_base + PHY_STAT, - val, (val & DLL_RDY), 10, 50 * USEC_PER_MSEC); - if (ret) { - dev_err(&phy->dev, "dllrdy failed, ret=%d\n", ret); - return ret; - } - break; - - default: - break; - } - return 0; -} - -static int thunderbay_emmc_phy_init(struct phy *phy) -{ - struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy); - - tbh_phy->emmcclk = clk_get(&phy->dev, "emmcclk"); - - return PTR_ERR_OR_ZERO(tbh_phy->emmcclk); -} - -static int thunderbay_emmc_phy_exit(struct phy *phy) -{ - struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy); - - clk_put(tbh_phy->emmcclk); - - return 0; -} - -static int thunderbay_emmc_phy_power_on(struct phy *phy) -{ - struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy); - unsigned long rate; - - /* Overwrite capability bits configurable in bootloader */ - update_reg(tbh_phy, CTRL_CFG_0, - SUPPORT_HS_MASK, SUPPORT_HS_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_0, - SUPPORT_8B_MASK, SUPPORT_8B_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_1, - SUPPORT_SDR50_MASK, SUPPORT_SDR50_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_1, - SUPPORT_DDR50_MASK, SUPPORT_DDR50_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_1, - SUPPORT_SDR104_MASK, SUPPORT_SDR104_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_1, - SUPPORT_HS400_MASK, SUPPORT_HS400_SHIFT, 0x1); - update_reg(tbh_phy, CTRL_CFG_1, - SUPPORT_64B_MASK, SUPPORT_64B_SHIFT, 0x1); - - if (tbh_phy->phy_power_sts == PHY_UNINITIALIZED) { - /* Indicates initialization, settings for init, same as 400KHZ setting */ - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, SEL_DLY_TXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, SEL_DLY_RXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, ITAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, ITAP_DLY_SEL_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, OTAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, OTAP_DLY_SEL_SHIFT, 0); - update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, DLL_TRIM_ICP_SHIFT, 0); - update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, DR_TY_SHIFT, 0x1); - - } else if (tbh_phy->phy_power_sts == PHY_INITIALIZED) { - /* Indicates actual clock setting */ - rate = clk_get_rate(tbh_phy->emmcclk); - switch (rate) { - case 200000000: - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, - SEL_DLY_TXCLK_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, - SEL_DLY_RXCLK_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, - ITAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, - ITAP_DLY_SEL_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, - OTAP_DLY_ENA_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, - OTAP_DLY_SEL_SHIFT, 2); - update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, - DLL_TRIM_ICP_SHIFT, 0x8); - update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, - DR_TY_SHIFT, 0x1); - /* For HS400 only */ - update_reg(tbh_phy, PHY_CFG_2, SEL_STRB_MASK, - SEL_STRB_SHIFT, STRB); - break; - - case 50000000 ... 52000000: - /* For both HS and DDR52 this setting works */ - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, - SEL_DLY_TXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, - SEL_DLY_RXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, - ITAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, - ITAP_DLY_SEL_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, - OTAP_DLY_ENA_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, - OTAP_DLY_SEL_SHIFT, 4); - update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, - DLL_TRIM_ICP_SHIFT, 0x8); - update_reg(tbh_phy, PHY_CFG_0, - DR_TY_MASK, DR_TY_SHIFT, 0x1); - break; - - case 400000: - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, - SEL_DLY_TXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, - SEL_DLY_RXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, - ITAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, - ITAP_DLY_SEL_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, - OTAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, - OTAP_DLY_SEL_SHIFT, 0); - update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, - DLL_TRIM_ICP_SHIFT, 0); - update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, DR_TY_SHIFT, 0x1); - break; - - default: - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, - SEL_DLY_TXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, - SEL_DLY_RXCLK_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, - ITAP_DLY_ENA_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, - ITAP_DLY_SEL_SHIFT, 0x0); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, - OTAP_DLY_ENA_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, - OTAP_DLY_SEL_SHIFT, 2); - update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, - DLL_TRIM_ICP_SHIFT, 0x8); - update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, - DR_TY_SHIFT, 0x1); - break; - } - /* Reset, init seq called without phy_power_off, this indicates init seq */ - tbh_phy->phy_power_sts = PHY_UNINITIALIZED; - } - - update_reg(tbh_phy, PHY_CFG_0, RETRIM_EN_MASK, RETRIM_EN_SHIFT, 0x1); - update_reg(tbh_phy, PHY_CFG_0, RETRIM_MASK, RETRIM_SHIFT, 0x0); - - return thunderbay_emmc_phy_power(phy, 1); -} - -static int thunderbay_emmc_phy_power_off(struct phy *phy) -{ - struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy); - - tbh_phy->phy_power_sts = PHY_INITIALIZED; - - return thunderbay_emmc_phy_power(phy, 0); -} - -static const struct phy_ops thunderbay_emmc_phy_ops = { - .init = thunderbay_emmc_phy_init, - .exit = thunderbay_emmc_phy_exit, - .power_on = thunderbay_emmc_phy_power_on, - .power_off = thunderbay_emmc_phy_power_off, - .owner = THIS_MODULE, -}; - -static const struct of_device_id thunderbay_emmc_phy_of_match[] = { - { .compatible = "intel,thunderbay-emmc-phy", - (void *)&thunderbay_emmc_phy_ops }, - {} -}; -MODULE_DEVICE_TABLE(of, thunderbay_emmc_phy_of_match); - -static int thunderbay_emmc_phy_probe(struct platform_device *pdev) -{ - struct thunderbay_emmc_phy *tbh_phy; - struct phy_provider *phy_provider; - struct device *dev = &pdev->dev; - const struct of_device_id *id; - struct phy *generic_phy; - struct resource *res; - - if (!dev->of_node) - return -ENODEV; - - tbh_phy = devm_kzalloc(dev, sizeof(*tbh_phy), GFP_KERNEL); - if (!tbh_phy) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tbh_phy->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tbh_phy->reg_base)) - return PTR_ERR(tbh_phy->reg_base); - - tbh_phy->phy_power_sts = PHY_UNINITIALIZED; - id = of_match_node(thunderbay_emmc_phy_of_match, pdev->dev.of_node); - if (!id) { - dev_err(dev, "failed to get match_node\n"); - return -EINVAL; - } - - generic_phy = devm_phy_create(dev, dev->of_node, id->data); - if (IS_ERR(generic_phy)) { - dev_err(dev, "failed to create PHY\n"); - return PTR_ERR(generic_phy); - } - - phy_set_drvdata(generic_phy, tbh_phy); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - - return PTR_ERR_OR_ZERO(phy_provider); -} - -static struct platform_driver thunderbay_emmc_phy_driver = { - .probe = thunderbay_emmc_phy_probe, - .driver = { - .name = "thunderbay-emmc-phy", - .of_match_table = thunderbay_emmc_phy_of_match, - }, -}; -module_platform_driver(thunderbay_emmc_phy_driver); - -MODULE_AUTHOR("Nandhini S "); -MODULE_AUTHOR("Rashmi A "); -MODULE_DESCRIPTION("Intel Thunder Bay eMMC PHY driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/marvell/phy-pxa-28nm-hsic.c b/drivers/phy/marvell/phy-pxa-28nm-hsic.c index c5c100563f55..eff6dd6b2dd0 100644 --- a/drivers/phy/marvell/phy-pxa-28nm-hsic.c +++ b/drivers/phy/marvell/phy-pxa-28nm-hsic.c @@ -199,7 +199,7 @@ static struct platform_driver mv_hsic_phy_driver = { .probe = mv_hsic_phy_probe, .driver = { .name = "mv-hsic-phy", - .of_match_table = of_match_ptr(mv_hsic_phy_dt_match), + .of_match_table = mv_hsic_phy_dt_match, }, }; module_platform_driver(mv_hsic_phy_driver); diff --git a/drivers/phy/marvell/phy-pxa-28nm-usb2.c b/drivers/phy/marvell/phy-pxa-28nm-usb2.c index 0b390b9d2ae1..1b2107f80f3a 100644 --- a/drivers/phy/marvell/phy-pxa-28nm-usb2.c +++ b/drivers/phy/marvell/phy-pxa-28nm-usb2.c @@ -331,7 +331,7 @@ static struct platform_driver mv_usb2_phy_driver = { .probe = mv_usb2_phy_probe, .driver = { .name = "mv-usb2-phy", - .of_match_table = of_match_ptr(mv_usbphy_dt_match), + .of_match_table = mv_usbphy_dt_match, }, }; module_platform_driver(mv_usb2_phy_driver); diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index fb1f8edaffa7..c9a50395533e 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8173.o +phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8195.o obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o phy-mtk-mipi-dsi-drv-y := phy-mtk-mipi-dsi.o diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c new file mode 100644 index 000000000000..8aa7251de4a9 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-mtk-io.h" +#include "phy-mtk-hdmi.h" +#include "phy-mtk-hdmi-mt8195.h" + +static void mtk_hdmi_ana_fifo_en(struct mtk_hdmi_phy *hdmi_phy) +{ + /* make data fifo writable for hdmi2.0 */ + mtk_phy_set_bits(hdmi_phy->regs + HDMI_ANA_CTL, REG_ANA_HDMI20_FIFO_EN); +} + +static void +mtk_phy_tmds_clk_ratio(struct mtk_hdmi_phy *hdmi_phy, bool enable) +{ + void __iomem *regs = hdmi_phy->regs; + + mtk_hdmi_ana_fifo_en(hdmi_phy); + + /* HDMI 2.0 specification, 3.4Gbps <= TMDS Bit Rate <= 6G, + * clock bit ratio 1:40, under 3.4Gbps, clock bit ratio 1:10 + */ + if (enable) + mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, 3); + else + mtk_phy_clear_bits(regs + HDMI20_CLK_CFG, REG_TXC_DIV); +} + +static void mtk_hdmi_pll_sel_src(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + + mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_REF_XTAL_SEL); + mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_REF_RESPLL_SEL); + + /* DA_HDMITX21_REF_CK for TXPLL input source */ + mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITXPLL_REF_CK_SEL); +} + +static void mtk_hdmi_pll_perf(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_BP2); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BC); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_IC, 0x1); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BR, 0x2); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_IR, 0x2); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BP); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_IBAND_FIX_EN); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT14); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_HIKVCO); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_HREN, 0x1); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_LVR_SEL, 0x1); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT12_11); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_TCL_EN); +} + +static int mtk_hdmi_pll_set_hw(struct clk_hw *hw, u8 prediv, + u8 fbkdiv_high, + u32 fbkdiv_low, + u8 fbkdiv_hs3, u8 posdiv1, + u8 posdiv2, u8 txprediv, + u8 txposdiv, + u8 digital_div) +{ + u8 txposdiv_value; + u8 div3_ctrl_value; + u8 posdiv_vallue; + u8 div_ctrl_value; + u8 reserve_3_2_value; + u8 prediv_value; + u8 reserve13_value; + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + + mtk_hdmi_pll_sel_src(hw); + + mtk_hdmi_pll_perf(hw); + + mtk_phy_update_field(regs + HDMI_1_CFG_10, RG_HDMITX21_BIAS_PE_BG_VREF_SEL, 0x2); + mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_VREF_SEL); + mtk_phy_update_field(regs + HDMI_1_CFG_9, RG_HDMITX21_SLDO_VREF_SEL, 0x2); + mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BIAS_PE_VREF_SELB); + mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDOLPF_EN); + mtk_phy_update_field(regs + HDMI_1_CFG_6, RG_HDMITX21_INTR_CAL, 0x11); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD); + + /* TXPOSDIV */ + txposdiv_value = ilog2(txposdiv); + + mtk_phy_update_field(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV, txposdiv_value); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_EN); + + /* TXPREDIV */ + switch (txprediv) { + case 2: + div3_ctrl_value = 0x0; + posdiv_vallue = 0x0; + break; + case 4: + div3_ctrl_value = 0x0; + posdiv_vallue = 0x1; + break; + case 6: + div3_ctrl_value = 0x1; + posdiv_vallue = 0x0; + break; + case 12: + div3_ctrl_value = 0x1; + posdiv_vallue = 0x1; + break; + default: + return -EINVAL; + } + + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_POSDIV_DIV3_CTRL, div3_ctrl_value); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_POSDIV, posdiv_vallue); + + /* POSDIV1 */ + switch (posdiv1) { + case 5: + div_ctrl_value = 0x0; + break; + case 10: + div_ctrl_value = 0x1; + break; + case 12: + div_ctrl_value = 0x2; + break; + case 15: + div_ctrl_value = 0x3; + break; + default: + return -EINVAL; + } + + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_DIV_CTRL, div_ctrl_value); + + /* DE add new setting */ + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT14); + + /* POSDIV2 */ + switch (posdiv2) { + case 1: + reserve_3_2_value = 0x0; + break; + case 2: + reserve_3_2_value = 0x1; + break; + case 4: + reserve_3_2_value = 0x2; + break; + case 6: + reserve_3_2_value = 0x3; + break; + default: + return -EINVAL; + } + + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT3_2, reserve_3_2_value); + + /* DE add new setting */ + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT1_0, 0x2); + + /* PREDIV */ + prediv_value = ilog2(prediv); + + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_PREDIV, prediv_value); + + /* FBKDIV_HS3 */ + reserve13_value = ilog2(fbkdiv_hs3); + + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT13, reserve13_value); + + /* FBDIV */ + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_FBKDIV_HIGH, fbkdiv_high); + mtk_phy_update_field(regs + HDMI_1_PLL_CFG_3, RG_HDMITXPLL_FBKDIV_LOW, fbkdiv_low); + + /* Digital DIVIDER */ + mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_PIXEL_CLOCK_SEL); + + if (digital_div == 1) { + mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_PIXEL_CLOCK); + } else { + mtk_phy_set_bits(regs + HDMI_CTL_3, REG_HDMITX_PIXEL_CLOCK); + mtk_phy_update_field(regs + HDMI_CTL_3, REG_HDMITXPLL_DIV, digital_div - 1); + } + + return 0; +} + +static int mtk_hdmi_pll_calc(struct mtk_hdmi_phy *hdmi_phy, struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + u8 digital_div, txprediv, txposdiv, fbkdiv_high, posdiv1, posdiv2; + u64 tmds_clk, pixel_clk, da_hdmitx21_ref_ck, ns_hdmipll_ck, pcw; + u8 txpredivs[4] = { 2, 4, 6, 12 }; + u32 fbkdiv_low; + int i; + + pixel_clk = rate; + tmds_clk = pixel_clk; + + if (tmds_clk < 25 * MEGA || tmds_clk > 594 * MEGA) + return -EINVAL; + + if (tmds_clk >= 340 * MEGA) + hdmi_phy->tmds_over_340M = true; + else + hdmi_phy->tmds_over_340M = false; + + /* in Hz */ + da_hdmitx21_ref_ck = 26 * MEGA; + + /* TXPOSDIV stage treatment: + * 0M < TMDS clk < 54M /8 + * 54M <= TMDS clk < 148.35M /4 + * 148.35M <=TMDS clk < 296.7M /2 + * 296.7 <=TMDS clk <= 594M /1 + */ + if (tmds_clk < 54 * MEGA) + txposdiv = 8; + else if (tmds_clk >= 54 * MEGA && (tmds_clk * 100) < 14835 * MEGA) + txposdiv = 4; + else if ((tmds_clk * 100) >= 14835 * MEGA && (tmds_clk * 10) < 2967 * MEGA) + txposdiv = 2; + else if ((tmds_clk * 10) >= 2967 * MEGA && tmds_clk <= 594 * MEGA) + txposdiv = 1; + else + return -EINVAL; + + /* calculate txprediv: can be 2, 4, 6, 12 + * ICO clk = 5*TMDS_CLK*TXPOSDIV*TXPREDIV + * ICO clk constraint: 5G =< ICO clk <= 12G + */ + for (i = 0; i < ARRAY_SIZE(txpredivs); i++) { + ns_hdmipll_ck = 5 * tmds_clk * txposdiv * txpredivs[i]; + if (ns_hdmipll_ck >= 5 * GIGA && + ns_hdmipll_ck <= 1 * GIGA) + break; + } + if (i == (ARRAY_SIZE(txpredivs) - 1) && + (ns_hdmipll_ck < 5 * GIGA || ns_hdmipll_ck > 12 * GIGA)) { + return -EINVAL; + } + if (i == ARRAY_SIZE(txpredivs)) + return -EINVAL; + + txprediv = txpredivs[i]; + + /* PCW calculation: FBKDIV + * formula: pcw=(frequency_out*2^pcw_bit) / frequency_in / FBKDIV_HS3; + * RG_HDMITXPLL_FBKDIV[32:0]: + * [32,24] 9bit integer, [23,0]:24bit fraction + */ + pcw = div_u64(((u64)ns_hdmipll_ck) << PCW_DECIMAL_WIDTH, + da_hdmitx21_ref_ck * PLL_FBKDIV_HS3); + + if (pcw > GENMASK_ULL(32, 0)) + return -EINVAL; + + fbkdiv_high = FIELD_GET(GENMASK_ULL(63, 32), pcw); + fbkdiv_low = FIELD_GET(GENMASK(31, 0), pcw); + + /* posdiv1: + * posdiv1 stage treatment according to color_depth: + * 24bit -> posdiv1 /10, 30bit -> posdiv1 /12.5, + * 36bit -> posdiv1 /15, 48bit -> posdiv1 /10 + */ + posdiv1 = 10; + posdiv2 = 1; + + /* Digital clk divider, max /32 */ + digital_div = div_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk); + if (!(digital_div <= 32 && digital_div >= 1)) + return -EINVAL; + + return mtk_hdmi_pll_set_hw(hw, PLL_PREDIV, fbkdiv_high, fbkdiv_low, + PLL_FBKDIV_HS3, posdiv1, posdiv2, txprediv, + txposdiv, digital_div); +} + +static int mtk_hdmi_pll_drv_setting(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + u8 data_channel_bias, clk_channel_bias; + u8 impedance, impedance_en; + u32 tmds_clk; + u32 pixel_clk = hdmi_phy->pll_rate; + + tmds_clk = pixel_clk; + + /* bias & impedance setting: + * 3G < data rate <= 6G: enable impedance 100ohm, + * data channel bias 24mA, clock channel bias 20mA + * pixel clk >= HD, 74.175MHZ <= pixel clk <= 300MHZ: + * enalbe impedance 100ohm + * data channel 20mA, clock channel 16mA + * 27M =< pixel clk < 74.175: disable impedance + * data channel & clock channel bias 10mA + */ + + /* 3G < data rate <= 6G, 300M < tmds rate <= 594M */ + if (tmds_clk > 300 * MEGA && tmds_clk <= 594 * MEGA) { + data_channel_bias = 0x3c; /* 24mA */ + clk_channel_bias = 0x34; /* 20mA */ + impedance_en = 0xf; + impedance = 0x36; /* 100ohm */ + } else if (((u64)pixel_clk * 1000) >= 74175 * MEGA && pixel_clk <= 300 * MEGA) { + data_channel_bias = 0x34; /* 20mA */ + clk_channel_bias = 0x2c; /* 16mA */ + impedance_en = 0xf; + impedance = 0x36; /* 100ohm */ + } else if (pixel_clk >= 27 * MEGA && ((u64)pixel_clk * 1000) < 74175 * MEGA) { + data_channel_bias = 0x14; /* 10mA */ + clk_channel_bias = 0x14; /* 10mA */ + impedance_en = 0x0; + impedance = 0x0; + } else { + return -EINVAL; + } + + /* bias */ + mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D0, data_channel_bias); + mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D1, data_channel_bias); + mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D2, data_channel_bias); + mtk_phy_update_field(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_IBIAS_CLK, clk_channel_bias); + + /* impedance */ + mtk_phy_update_field(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_IMP_EN, impedance_en); + mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D0_EN1, impedance); + mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D1_EN1, impedance); + mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D2_EN1, impedance); + mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_CLK_EN1, impedance); + + return 0; +} + +static int mtk_hdmi_pll_prepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV_EN); + + mtk_phy_set_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_SER_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D0_DRV_OP_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D1_DRV_OP_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D2_DRV_OP_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_CK_DRV_OP_EN); + + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D0_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D1_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D2_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_CK_EN); + + mtk_hdmi_pll_drv_setting(hw); + + mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BG_PWD); + mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_BIAS_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_CKLDO_EN); + mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDO_EN); + + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_PWR_ON); + usleep_range(5, 10); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_ISO_EN); + usleep_range(5, 10); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD); + usleep_range(30, 50); + return 0; +} + +static void mtk_hdmi_pll_unprepare(struct clk_hw *hw) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + void __iomem *regs = hdmi_phy->regs; + + mtk_phy_set_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BG_PWD); + mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_BIAS_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_CKLDO_EN); + mtk_phy_clear_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDO_EN); + + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD); + usleep_range(10, 20); + mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_ISO_EN); + usleep_range(10, 20); + mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_PWR_ON); +} + +static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__, rate, + parent_rate); + + return mtk_hdmi_pll_calc(hdmi_phy, hw, rate, parent_rate); +} + +static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + hdmi_phy->pll_rate = rate; + return rate; +} + +static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); + + return hdmi_phy->pll_rate; +} + +static const struct clk_ops mtk_hdmi_pll_ops = { + .prepare = mtk_hdmi_pll_prepare, + .unprepare = mtk_hdmi_pll_unprepare, + .set_rate = mtk_hdmi_pll_set_rate, + .round_rate = mtk_hdmi_pll_round_rate, + .recalc_rate = mtk_hdmi_pll_recalc_rate, +}; + +static void vtx_signal_en(struct mtk_hdmi_phy *hdmi_phy, bool on) +{ + void __iomem *regs = hdmi_phy->regs; + + if (on) + mtk_phy_set_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_EN); + else + mtk_phy_clear_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_EN); +} + +static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + vtx_signal_en(hdmi_phy, true); + usleep_range(100, 150); +} + +static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) +{ + vtx_signal_en(hdmi_phy, false); +} + +static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct phy_configure_opts_dp *dp_opts = &opts->dp; + struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); + int ret; + + ret = clk_set_rate(hdmi_phy->pll, dp_opts->link_rate); + + if (ret) + return ret; + + mtk_phy_tmds_clk_ratio(hdmi_phy, hdmi_phy->tmds_over_340M); + + return ret; +} + +struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf = { + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, + .hdmi_phy_clk_ops = &mtk_hdmi_pll_ops, + .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, + .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, + .hdmi_phy_configure = mtk_hdmi_phy_configure, +}; + +MODULE_AUTHOR("Can Zeng "); +MODULE_DESCRIPTION("MediaTek MT8195 HDMI PHY Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h new file mode 100644 index 000000000000..22a68dc9550c --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Copyright (c) 2022 BayLibre, SAS + */ + +#ifndef _MTK_HDMI_PHY_8195_H +#define _MTK_HDMI_PHY_8195_H + +#include +#include +#include + +#define PCW_DECIMAL_WIDTH 24 +#define PLL_PREDIV 1 +#define PLL_FBKDIV_HS3 1 + +#define HDMI20_CLK_CFG 0x70 +#define REG_TXC_DIV GENMASK(31, 30) + +#define HDMI_1_CFG_0 0x00 +#define RG_HDMITX21_DRV_IBIAS_CLK GENMASK(10, 5) +#define RG_HDMITX21_DRV_IMP_EN GENMASK(23, 20) +#define RG_HDMITX21_DRV_EN GENMASK(27, 24) +#define RG_HDMITX21_SER_EN GENMASK(31, 28) + +#define HDMI_1_CFG_1 0x04 +#define RG_HDMITX21_DRV_IBIAS_D0 GENMASK(19, 14) +#define RG_HDMITX21_DRV_IBIAS_D1 GENMASK(25, 20) +#define RG_HDMITX21_DRV_IBIAS_D2 GENMASK(31, 26) + +#define HDMI_1_CFG_10 0x40 +#define RG_HDMITXPLL_REF_CK_SEL GENMASK(2, 1) +#define RG_HDMITX21_VREF_SEL BIT(4) +#define RG_HDMITX21_BIAS_PE_VREF_SELB BIT(10) +#define RG_HDMITX21_BIAS_PE_BG_VREF_SEL GENMASK(16, 15) +#define RG_HDMITX21_BG_PWD BIT(20) + +#define HDMI_1_CFG_2 0x08 +#define RG_HDMITX21_DRV_IMP_D0_EN1 GENMASK(13, 8) +#define RG_HDMITX21_DRV_IMP_D1_EN1 GENMASK(19, 14) +#define RG_HDMITX21_DRV_IMP_D2_EN1 GENMASK(25, 20) +#define RG_HDMITX21_DRV_IMP_CLK_EN1 GENMASK(31, 26) + +#define HDMI_1_CFG_3 0x0c +#define RG_HDMITX21_CKLDO_EN BIT(3) +#define RG_HDMITX21_SLDOLPF_EN BIT(7) +#define RG_HDMITX21_SLDO_EN GENMASK(11, 8) + +#define HDMI_1_CFG_6 0x18 +#define RG_HDMITX21_D2_DRV_OP_EN BIT(8) +#define RG_HDMITX21_D1_DRV_OP_EN BIT(9) +#define RG_HDMITX21_D0_DRV_OP_EN BIT(10) +#define RG_HDMITX21_CK_DRV_OP_EN BIT(11) +#define RG_HDMITX21_FRL_EN BIT(12) +#define RG_HDMITX21_FRL_CK_EN BIT(13) +#define RG_HDMITX21_FRL_D0_EN BIT(14) +#define RG_HDMITX21_FRL_D1_EN BIT(15) +#define RG_HDMITX21_FRL_D2_EN BIT(16) +#define RG_HDMITX21_INTR_CAL GENMASK(22, 18) +#define RG_HDMITX21_TX_POSDIV GENMASK(27, 26) +#define RG_HDMITX21_TX_POSDIV_EN BIT(28) +#define RG_HDMITX21_BIAS_EN BIT(29) + +#define HDMI_1_CFG_9 0x24 +#define RG_HDMITX21_SLDO_VREF_SEL GENMASK(5, 4) + +#define HDMI_1_PLL_CFG_0 0x44 +#define RG_HDMITXPLL_HREN GENMASK(13, 12) +#define RG_HDMITXPLL_IBAND_FIX_EN BIT(24) +#define RG_HDMITXPLL_LVR_SEL GENMASK(27, 26) +#define RG_HDMITXPLL_BP2 BIT(30) +#define RG_HDMITXPLL_TCL_EN BIT(31) + +#define HDMI_1_PLL_CFG_1 0x48 +#define RG_HDMITXPLL_RESERVE_BIT1_0 GENMASK(1, 0) +#define RG_HDMITXPLL_RESERVE_BIT3_2 GENMASK(3, 2) +#define RG_HDMITXPLL_RESERVE_BIT12_11 GENMASK(12, 11) +#define RG_HDMITXPLL_RESERVE_BIT13 BIT(13) +#define RG_HDMITXPLL_RESERVE_BIT14 BIT(14) + +#define HDMI_1_PLL_CFG_2 0x4c +#define RG_HDMITXPLL_BC GENMASK(28, 27) +#define RG_HDMITXPLL_IC GENMASK(26, 22) +#define RG_HDMITXPLL_BR GENMASK(21, 19) +#define RG_HDMITXPLL_IR GENMASK(18, 14) +#define RG_HDMITXPLL_BP GENMASK(13, 10) +#define RG_HDMITXPLL_HIKVCO BIT(29) +#define RG_HDMITXPLL_PWD BIT(31) + +#define HDMI_1_PLL_CFG_3 0x50 +#define RG_HDMITXPLL_FBKDIV_LOW GENMASK(31, 0) + +#define HDMI_1_PLL_CFG_4 0x54 +#define DA_HDMITXPLL_ISO_EN BIT(1) +#define DA_HDMITXPLL_PWR_ON BIT(2) +#define RG_HDMITXPLL_POSDIV_DIV3_CTRL BIT(21) +#define RG_HDMITXPLL_POSDIV GENMASK(23, 22) +#define RG_HDMITXPLL_DIV_CTRL GENMASK(25, 24) +#define RG_HDMITXPLL_PREDIV GENMASK(29, 28) +#define RG_HDMITXPLL_FBKDIV_HIGH BIT(31) + +#define HDMI_ANA_CTL 0x7c +#define REG_ANA_HDMI20_FIFO_EN BIT(16) + +#define HDMI_CTL_3 0xcc +#define REG_HDMITXPLL_DIV GENMASK(4, 0) +#define REG_HDMITX_REF_XTAL_SEL BIT(7) +#define REG_HDMITX_REF_RESPLL_SEL BIT(9) +#define REG_PIXEL_CLOCK_SEL BIT(10) +#define REG_HDMITX_PIXEL_CLOCK BIT(23) + +#endif /* MTK_HDMI_PHY_8195_H */ diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c index b16d437d6721..d2e824771f9d 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi.c @@ -8,10 +8,12 @@ static int mtk_hdmi_phy_power_on(struct phy *phy); static int mtk_hdmi_phy_power_off(struct phy *phy); +static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts); static const struct phy_ops mtk_hdmi_phy_dev_ops = { .power_on = mtk_hdmi_phy_power_on, .power_off = mtk_hdmi_phy_power_off, + .configure = mtk_hdmi_phy_configure, .owner = THIS_MODULE, }; @@ -43,6 +45,16 @@ static int mtk_hdmi_phy_power_off(struct phy *phy) return 0; } +static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); + + if (hdmi_phy->conf->hdmi_phy_configure) + return hdmi_phy->conf->hdmi_phy_configure(phy, opts); + + return 0; +} + static const struct phy_ops * mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy) { @@ -149,6 +161,9 @@ static const struct of_device_id mtk_hdmi_phy_match[] = { { .compatible = "mediatek,mt8173-hdmi-phy", .data = &mtk_hdmi_phy_8173_conf, }, + { .compatible = "mediatek,mt8195-hdmi-phy", + .data = &mtk_hdmi_phy_8195_conf, + }, {}, }; MODULE_DEVICE_TABLE(of, mtk_hdmi_phy_match); diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h index c7fa65cff989..fc2ad6a0527f 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.h +++ b/drivers/phy/mediatek/phy-mtk-hdmi.h @@ -24,6 +24,7 @@ struct mtk_hdmi_phy_conf { const struct clk_ops *hdmi_phy_clk_ops; void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); + int (*hdmi_phy_configure)(struct phy *phy, union phy_configure_opts *opts); }; struct mtk_hdmi_phy { @@ -39,10 +40,12 @@ struct mtk_hdmi_phy { unsigned char drv_imp_d0; unsigned int ibias; unsigned int ibias_up; + bool tmds_over_340M; }; struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); +extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf; extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf; diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index cf9c386385bb..526c05a4af5e 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -180,10 +180,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) mipi_tx->pll); } -static int mtk_mipi_tx_remove(struct platform_device *pdev) +static void mtk_mipi_tx_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - return 0; } static const struct of_device_id mtk_mipi_tx_match[] = { @@ -199,7 +198,7 @@ MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match); static struct platform_driver mtk_mipi_tx_driver = { .probe = mtk_mipi_tx_probe, - .remove = mtk_mipi_tx_remove, + .remove_new = mtk_mipi_tx_remove, .driver = { .name = "mediatek-mipi-tx", .of_match_table = mtk_mipi_tx_match, diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 2f8210167b77..74333e814221 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -692,7 +692,7 @@ out_reg_disable: return error; } -static int cpcap_usb_phy_remove(struct platform_device *pdev) +static void cpcap_usb_phy_remove(struct platform_device *pdev) { struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev); int error; @@ -707,13 +707,11 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev) usb_remove_phy(&ddata->phy); cancel_delayed_work_sync(&ddata->detect_work); regulator_disable(ddata->vusb); - - return 0; } static struct platform_driver cpcap_usb_phy_driver = { .probe = cpcap_usb_phy_probe, - .remove = cpcap_usb_phy_remove, + .remove_new = cpcap_usb_phy_remove, .driver = { .name = "cpcap-usb-phy", .of_match_table = of_match_ptr(cpcap_usb_phy_id_table), diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index 3cd4d51c247c..1d567604b650 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -634,7 +634,7 @@ cleanup: return error; } -static int phy_mdm6600_remove(struct platform_device *pdev) +static void phy_mdm6600_remove(struct platform_device *pdev) { struct phy_mdm6600 *ddata = platform_get_drvdata(pdev); struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET]; @@ -653,13 +653,11 @@ static int phy_mdm6600_remove(struct platform_device *pdev) cancel_delayed_work_sync(&ddata->modem_wake_work); cancel_delayed_work_sync(&ddata->bootup_work); cancel_delayed_work_sync(&ddata->status_work); - - return 0; } static struct platform_driver phy_mdm6600_driver = { .probe = phy_mdm6600_probe, - .remove = phy_mdm6600_remove, + .remove_new = phy_mdm6600_remove, .driver = { .name = "phy-mapphone-mdm6600", .pm = &phy_mdm6600_pm_ops, diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 9951efc03eaa..6464dcb56d56 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -1233,7 +1233,7 @@ static void phy_release(struct device *dev) static int __init phy_core_init(void) { - phy_class = class_create(THIS_MODULE, "phy"); + phy_class = class_create("phy"); if (IS_ERR(phy_class)) { pr_err("failed to create phy class --> %ld\n", PTR_ERR(phy_class)); diff --git a/drivers/phy/phy-lgm-usb.c b/drivers/phy/phy-lgm-usb.c index 309c8f0e0724..410729c7f513 100644 --- a/drivers/phy/phy-lgm-usb.c +++ b/drivers/phy/phy-lgm-usb.c @@ -252,13 +252,11 @@ static int phy_probe(struct platform_device *pdev) return usb_add_phy_dev(phy); } -static int phy_remove(struct platform_device *pdev) +static void phy_remove(struct platform_device *pdev) { struct tca_apb *ta = platform_get_drvdata(pdev); usb_remove_phy(&ta->phy); - - return 0; } static const struct of_device_id intel_usb_phy_dt_ids[] = { @@ -273,7 +271,7 @@ static struct platform_driver lgm_phy_driver = { .of_match_table = intel_usb_phy_dt_ids, }, .probe = phy_probe, - .remove = phy_remove, + .remove_new = phy_remove, }; module_platform_driver(lgm_phy_driver); diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c index d437a249cd73..8814f4322adf 100644 --- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c @@ -243,13 +243,11 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) return 0; } -static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev) +static void qcom_apq8064_sata_phy_remove(struct platform_device *pdev) { struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev); clk_disable_unprepare(phy->cfg_clk); - - return 0; } static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { @@ -260,7 +258,7 @@ MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); static struct platform_driver qcom_apq8064_sata_phy_driver = { .probe = qcom_apq8064_sata_phy_probe, - .remove = qcom_apq8064_sata_phy_remove, + .remove_new = qcom_apq8064_sata_phy_remove, .driver = { .name = "qcom-apq8064-sata-phy", .of_match_table = qcom_apq8064_sata_phy_of_match, diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index 3f265ac2df20..90f8543ba265 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -223,16 +223,14 @@ static int eusb2_repeater_probe(struct platform_device *pdev) return 0; } -static int eusb2_repeater_remove(struct platform_device *pdev) +static void eusb2_repeater_remove(struct platform_device *pdev) { struct eusb2_repeater *rptr = platform_get_drvdata(pdev); if (!rptr) - return 0; + return; eusb2_repeater_exit(rptr->phy); - - return 0; } static const struct of_device_id eusb2_repeater_of_match_table[] = { @@ -246,7 +244,7 @@ MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); static struct platform_driver eusb2_repeater_driver = { .probe = eusb2_repeater_probe, - .remove = eusb2_repeater_remove, + .remove_new = eusb2_repeater_remove, .driver = { .name = "qcom-eusb2-repeater", .of_match_table = eusb2_repeater_of_match_table, diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c index 0fc2a1ed39b3..f0a72b82c770 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c @@ -170,13 +170,11 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev) return 0; } -static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) +static void qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) { struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev); clk_disable_unprepare(phy->cfg_clk); - - return 0; } static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { @@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); static struct platform_driver qcom_ipq806x_sata_phy_driver = { .probe = qcom_ipq806x_sata_phy_probe, - .remove = qcom_ipq806x_sata_phy_remove, + .remove_new = qcom_ipq806x_sata_phy_remove, .driver = { .name = "qcom-ipq806x-sata-phy", .of_match_table = qcom_ipq806x_sata_phy_of_match, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index c1483e157af4..87b17e5877ab 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1396,6 +1396,7 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v3 = { .usb3_serdes = 0x1000, .usb3_pcs_misc = 0x1a00, .usb3_pcs = 0x1c00, + .usb3_pcs_usb = 0x1f00, .dp_serdes = 0x2000, .dp_txa = 0x2200, .dp_txb = 0x2600, @@ -1416,22 +1417,6 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = { .dp_dp_phy = 0x2200, }; -static const struct qmp_combo_offsets qmp_combo_offsets_v6 = { - .com = 0x0000, - .txa = 0x1200, - .rxa = 0x1400, - .txb = 0x1600, - .rxb = 0x1800, - .usb3_serdes = 0x1000, - .usb3_pcs_misc = 0x1a00, - .usb3_pcs = 0x1c00, - .usb3_pcs_usb = 0x1f00, - .dp_serdes = 0x2000, - .dp_txa = 0x2200, - .dp_txb = 0x2600, - .dp_dp_phy = 0x2a00, -}; - static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), @@ -1758,7 +1743,7 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { - .offsets = &qmp_combo_offsets_v6, + .offsets = &qmp_combo_offsets_v3, .serdes_tbl = sm8550_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8550_usb3_serdes_tbl), @@ -2487,7 +2472,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp) ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); if (ret) { dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); - goto err_unlock; + goto err_decrement_count; } ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); @@ -2537,7 +2522,8 @@ err_assert_reset: reset_control_bulk_assert(cfg->num_resets, qmp->resets); err_disable_regulators: regulator_bulk_disable(cfg->num_vregs, qmp->vregs); -err_unlock: +err_decrement_count: + qmp->init_count--; mutex_unlock(&qmp->phy_mutex); return ret; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index 09824be088c9..0c603bc06e09 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -379,7 +379,7 @@ static int qmp_pcie_msm8996_com_init(struct qmp_phy *qphy) ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); if (ret) { dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); - goto err_unlock; + goto err_decrement_count; } ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); @@ -409,7 +409,8 @@ err_assert_reset: reset_control_bulk_assert(cfg->num_resets, qmp->resets); err_disable_regulators: regulator_bulk_disable(cfg->num_vregs, qmp->vregs); -err_unlock: +err_decrement_count: + qmp->init_count--; mutex_unlock(&qmp->phy_mutex); return ret; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 5182aeac43ee..df505279edfd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -725,9 +725,6 @@ static const struct qmp_phy_init_tbl sdm845_qhp_pcie_tx_tbl[] = { QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RSM_START, 0x01), }; -static const struct qmp_phy_init_tbl sdm845_qhp_pcie_rx_tbl[] = { -}; - static const struct qmp_phy_init_tbl sdm845_qhp_pcie_pcs_tbl[] = { QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG, 0x3f), QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG, 0x50), @@ -1130,10 +1127,60 @@ static const struct qmp_phy_init_tbl sm8250_qmp_gen3x2_pcie_pcs_misc_tbl[] = { }; static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x02), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x18), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x07), QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC2, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MODE, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_DC_LEVEL_CTRL, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x22), +}; + +static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rc_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xce), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_EP_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_EP_DIV_MODE1, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0xc3), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0xd0), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xd8), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x20), +}; + +static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x07), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x19), @@ -1141,8 +1188,6 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x03), QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x03), QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x46), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_CFG, 0x04), QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x02), QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0xff), @@ -1154,21 +1199,11 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x01), QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE1, 0xfb), QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE1, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x04), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC1, 0x88), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC2, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MODE, 0x17), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_DC_LEVEL_CTRL, 0x0b), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x56), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1d), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x4b), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x22), }; static const struct qmp_phy_init_tbl sdx55_qmp_pcie_tx_tbl[] = { @@ -1220,10 +1255,151 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME, 0x13), QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG2, 0x01), QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02), +}; + +static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rc_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), +}; + +static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00), QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00), }; +static const struct qmp_phy_init_tbl sdx65_qmp_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BG_TIMER, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYS_CLK_CTRL, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x27), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE0, 0xfb), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE1, 0xfb), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE_CONTD, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl sdx65_qmp_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_2, 0xf6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_VMODE_CTRL1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_PI_QEC_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_RX, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RCV_DETECT_LVL_2, 0x12), +}; + +static const struct qmp_phy_init_tbl sdx65_qmp_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH1, 0x3e), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH2, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH2, 0x1d), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x44), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x74), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xcc), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xcc), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x29), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0xc5), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xac), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xfb), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xc5), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_EN_TIMER, 0x28), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), +}; + +static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22), +}; + +static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3, 0x28), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x08), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00), +}; + static const struct qmp_phy_init_tbl sm8450_qmp_gen3_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34), @@ -2033,8 +2209,6 @@ static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = { .serdes_num = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl), .tx = sdm845_qhp_pcie_tx_tbl, .tx_num = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl), - .rx = sdm845_qhp_pcie_rx_tbl, - .rx_num = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl), .pcs = sdm845_qhp_pcie_pcs_tbl, .pcs_num = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl), }, @@ -2152,7 +2326,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = { }; static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { - .lanes = 1, + .lanes = 2, .tbls = { .serdes = sc8180x_qmp_pcie_serdes_tbl, @@ -2301,6 +2475,21 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { .pcs_misc = sdx55_qmp_pcie_pcs_misc_tbl, .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_pcs_misc_tbl), }, + + .tbls_rc = &(const struct qmp_phy_cfg_tbls) { + .serdes = sdx55_qmp_pcie_rc_serdes_tbl, + .serdes_num = ARRAY_SIZE(sdx55_qmp_pcie_rc_serdes_tbl), + .pcs_misc = sdx55_qmp_pcie_rc_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_rc_pcs_misc_tbl), + }, + + .tbls_ep = &(const struct qmp_phy_cfg_tbls) { + .serdes = sdx55_qmp_pcie_ep_serdes_tbl, + .serdes_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_serdes_tbl), + .pcs_misc = sdx55_qmp_pcie_ep_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_pcs_misc_tbl), + }, + .clk_list = sdm845_pciephy_clk_l, .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l), .reset_list = sdm845_pciephy_reset_l, @@ -2309,7 +2498,7 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = pciephy_v4_regs_layout, - .pwrdn_ctrl = SW_PWRDN, + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, }; @@ -2387,6 +2576,35 @@ static const struct qmp_phy_cfg sm8350_qmp_gen3x2_pciephy_cfg = { .phy_status = PHYSTATUS, }; +static const struct qmp_phy_cfg sdx65_qmp_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_v6_20, + + .tbls = { + .serdes = sdx65_qmp_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(sdx65_qmp_pcie_serdes_tbl), + .tx = sdx65_qmp_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(sdx65_qmp_pcie_tx_tbl), + .rx = sdx65_qmp_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(sdx65_qmp_pcie_rx_tbl), + .pcs = sdx65_qmp_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_tbl), + .pcs_misc = sdx65_qmp_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_misc_tbl), + }, + .clk_list = sdm845_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = pciephy_v5_regs_layout, + + .pwrdn_ctrl = SW_PWRDN, + .phy_status = PHYSTATUS_4_20, +}; + static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = { .lanes = 1, @@ -3180,6 +3398,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,sdx55-qmp-pcie-phy", .data = &sdx55_qmp_pciephy_cfg, + }, { + .compatible = "qcom,sdx65-qmp-gen4x2-pcie-phy", + .data = &sdx65_qmp_pciephy_cfg, }, { .compatible = "qcom,sm8250-qmp-gen3x1-pcie-phy", .data = &sm8250_qmp_gen3x1_pciephy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h index af273602998e..ac872a9eff9a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h @@ -6,6 +6,8 @@ #ifndef QCOM_PHY_QMP_PCS_PCIE_V4_20_H_ #define QCOM_PHY_QMP_PCS_PCIE_V4_20_H_ +#define QPHY_V4_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x01c +#define QPHY_V4_20_PCS_PCIE_OSC_DTCT_ACTIONS 0x090 #define QPHY_V4_20_PCS_PCIE_EQ_CONFIG1 0x0a0 #define QPHY_V4_20_PCS_PCIE_G3_RXEQEVAL_TIME 0x0f0 #define QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME 0x0f4 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h index 3d9713d348fe..a3a056741fc7 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h @@ -12,8 +12,11 @@ #define QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS 0x090 #define QPHY_V5_20_PCS_PCIE_EQ_CONFIG1 0x0a0 #define QPHY_V5_20_PCS_PCIE_PRESET_P10_POST 0x0e0 +#define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG2 0x0fc #define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5 0x108 #define QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN 0x15c #define QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3 0x184 +#define QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2 0xa24 +#define QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2 0xa28 #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h index 9a5a20daf62c..f0754b6f9e3a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h @@ -8,6 +8,7 @@ #define QPHY_V5_20_PCS_G3S2_PRE_GAIN 0x170 #define QPHY_V5_20_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V5_20_PCS_EQ_CONFIG2 0x1d8 #define QPHY_V5_20_PCS_EQ_CONFIG4 0x1e0 #define QPHY_V5_20_PCS_EQ_CONFIG5 0x1e4 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h index 86c01104799e..c7b12c1fb7f5 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h @@ -11,6 +11,10 @@ #define QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_RX 0x34 #define QSERDES_V5_20_TX_LANE_MODE_1 0x78 #define QSERDES_V5_20_TX_LANE_MODE_2 0x7c +#define QSERDES_V5_20_TX_LANE_MODE_3 0x80 +#define QSERDES_V5_20_TX_RCV_DETECT_LVL_2 0x90 +#define QSERDES_V5_20_TX_VMODE_CTRL1 0xb0 +#define QSERDES_V5_20_TX_PI_QEC_CTRL 0xcc /* Only for QMP V5_20 PHY - RX registers */ #define QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2 0x008 @@ -19,16 +23,33 @@ #define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1 0x02c #define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3 0x030 #define QSERDES_V5_20_RX_RX_IDAC_SAOFFSET 0x07c +#define QSERDES_V5_20_RX_DFE_1 0x088 +#define QSERDES_V5_20_RX_DFE_2 0x08c #define QSERDES_V5_20_RX_DFE_3 0x090 #define QSERDES_V5_20_RX_DFE_DAC_ENABLE1 0x0b4 +#define QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH1 0x0bc +#define QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH2 0x0c0 #define QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1 0x0c4 #define QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2 0x0c8 +#define QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH1 0x0cc +#define QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH2 0x0d0 +#define QSERDES_V5_20_RX_VGA_CAL_CNTRL1 0x0d4 +#define QSERDES_V5_20_RX_VGA_CAL_CNTRL2 0x0d8 #define QSERDES_V5_20_RX_VGA_CAL_MAN_VAL 0x0dc #define QSERDES_V5_20_RX_GM_CAL 0x0ec +#define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL2 0x100 +#define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL3 0x104 #define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4 0x108 +#define QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x118 +#define QSERDES_V5_20_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x11c +#define QSERDES_V5_20_RX_SIGDET_ENABLES 0x120 +#define QSERDES_V5_20_RX_SIGDET_CNTRL 0x124 +#define QSERDES_V5_20_RX_SIGDET_DEGLITCH_CNTRL 0x12c +#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0 0x160 #define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1 0x164 #define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2 0x168 #define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3 0x16c +#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4 0x170 #define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5 0x174 #define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6 0x178 #define QSERDES_V5_20_RX_RX_MODE_RATE2_B0 0x17c @@ -46,7 +67,10 @@ #define QSERDES_V5_20_RX_RX_MODE_RATE3_B5 0x1ac #define QSERDES_V5_20_RX_RX_MODE_RATE3_B6 0x1b0 #define QSERDES_V5_20_RX_PHPRE_CTRL 0x1b4 +#define QSERDES_V5_20_RX_DFE_DAC_ENABLE2 0x1b8 +#define QSERDES_V5_20_RX_DFE_EN_TIMER 0x1bc #define QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET 0x1c0 +#define QSERDES_V5_20_RX_DCC_CTRL1 0x1c4 #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210 0x1f4 #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3 0x1f8 #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210 0x1fc diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 994ddd5d4a81..8c877b668bb9 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -349,6 +349,36 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02), }; +static const struct qmp_phy_init_tbl sm7150_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), +}; + +static const struct qmp_phy_init_tbl sm7150_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11), @@ -823,6 +853,40 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .no_pcs_sw_reset = true, }; +static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sm8350_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes), + .tx = sm8350_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8350_ufsphy_tx), + .rx = sm8350_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8350_ufsphy_rx), + .pcs = sm8350_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8350_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8350_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), + }, + .tbls_hs_g4 = { + .tx = sm8350_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), + .rx = sm8350_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), + .pcs = sm8350_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + }, + .clk_list = sm8450_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = ufsphy_v5_regs_layout, +}; + static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .lanes = 2, @@ -911,6 +975,34 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .no_pcs_sw_reset = true, }; +static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { + .lanes = 1, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sdm845_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes), + .tx = sdm845_ufsphy_tx, + .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx), + .rx = sm7150_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm7150_ufsphy_rx), + .pcs = sm7150_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm7150_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sdm845_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = ufsphy_v3_regs_layout, + + .no_pcs_sw_reset = true, +}; + static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .lanes = 2, @@ -1542,6 +1634,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { }, { .compatible = "qcom,msm8998-qmp-ufs-phy", .data = &sdm845_ufsphy_cfg, + }, { + .compatible = "qcom,sa8775p-qmp-ufs-phy", + .data = &sa8775p_ufsphy_cfg, }, { .compatible = "qcom,sc8180x-qmp-ufs-phy", .data = &sm8150_ufsphy_cfg, @@ -1560,6 +1655,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { }, { .compatible = "qcom,sm6350-qmp-ufs-phy", .data = &sdm845_ufsphy_cfg, + }, { + .compatible = "qcom,sm7150-qmp-ufs-phy", + .data = &sm7150_ufsphy_cfg, }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = &sm8150_ufsphy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c index a59063596214..6c237f3cc66d 100644 --- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c @@ -115,11 +115,11 @@ struct phy_override_seq { * * @cfg_ahb_clk: AHB2PHY interface clock * @ref_clk: phy reference clock - * @iface_clk: phy interface clock * @phy_reset: phy reset control * @vregs: regulator supplies bulk data * @phy_initialized: if PHY has been initialized correctly * @mode: contains the current mode the PHY is in + * @update_seq_cfg: tuning parameters for phy init */ struct qcom_snps_hsphy { struct phy *phy; diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c index 4dc721eb9577..9cf786a7daac 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c +++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c @@ -126,11 +126,9 @@ error: return error; } -static int rcar_gen3_phy_pcie_remove(struct platform_device *pdev) +static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; }; static struct platform_driver rcar_gen3_phy_driver = { @@ -139,7 +137,7 @@ static struct platform_driver rcar_gen3_phy_driver = { .of_match_table = rcar_gen3_phy_pcie_match_table, }, .probe = rcar_gen3_phy_pcie_probe, - .remove = rcar_gen3_phy_pcie_remove, + .remove_new = rcar_gen3_phy_pcie_remove, }; module_platform_driver(rcar_gen3_phy_driver); diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 9de617ca9daa..d4e2ee7e4efb 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -755,7 +755,7 @@ error: return ret; } -static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev) +static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) { struct rcar_gen3_chan *channel = platform_get_drvdata(pdev); @@ -763,8 +763,6 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_role); pm_runtime_disable(&pdev->dev); - - return 0; }; static struct platform_driver rcar_gen3_phy_usb2_driver = { @@ -773,7 +771,7 @@ static struct platform_driver rcar_gen3_phy_usb2_driver = { .of_match_table = rcar_gen3_phy_usb2_match_table, }, .probe = rcar_gen3_phy_usb2_probe, - .remove = rcar_gen3_phy_usb2_remove, + .remove_new = rcar_gen3_phy_usb2_remove, }; module_platform_driver(rcar_gen3_phy_usb2_driver); diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c index f27d6f471629..e2d630edd992 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -199,11 +199,9 @@ error: return ret; } -static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev) +static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; }; static struct platform_driver rcar_gen3_phy_usb3_driver = { @@ -212,7 +210,7 @@ static struct platform_driver rcar_gen3_phy_usb3_driver = { .of_match_table = rcar_gen3_phy_usb3_match_table, }, .probe = rcar_gen3_phy_usb3_probe, - .remove = rcar_gen3_phy_usb3_remove, + .remove_new = rcar_gen3_phy_usb3_remove, }; module_platform_driver(rcar_gen3_phy_usb3_driver); diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index c5206ef9195b..55b7bdfc10d3 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -388,19 +388,17 @@ static int r8a779f0_eth_serdes_probe(struct platform_device *pdev) return 0; } -static int r8a779f0_eth_serdes_remove(struct platform_device *pdev) +static void r8a779f0_eth_serdes_remove(struct platform_device *pdev) { pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); platform_set_drvdata(pdev, NULL); - - return 0; } static struct platform_driver r8a779f0_eth_serdes_driver_platform = { .probe = r8a779f0_eth_serdes_probe, - .remove = r8a779f0_eth_serdes_remove, + .remove_new = r8a779f0_eth_serdes_remove, .driver = { .name = "r8a779f0_eth_serdes", .of_match_table = r8a779f0_eth_serdes_of_table, diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 75f948bdea6a..98c92d6c482f 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -459,13 +459,11 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev) return 0; } -static int rockchip_inno_csidphy_remove(struct platform_device *pdev) +static void rockchip_inno_csidphy_remove(struct platform_device *pdev) { struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev); pm_runtime_disable(priv->dev); - - return 0; } static struct platform_driver rockchip_inno_csidphy_driver = { @@ -474,7 +472,7 @@ static struct platform_driver rockchip_inno_csidphy_driver = { .of_match_table = rockchip_inno_csidphy_match_id, }, .probe = rockchip_inno_csidphy_probe, - .remove = rockchip_inno_csidphy_remove, + .remove_new = rockchip_inno_csidphy_remove, }; module_platform_driver(rockchip_inno_csidphy_driver); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c index 2c5847faff63..401b0aabb159 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -281,11 +281,6 @@ struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_2_5ghz[] = { {2500000000, 0x15, 0x54, 0x7f, 0x15, 0x6a}, }; -static inline struct inno_dsidphy *hw_to_inno(struct clk_hw *hw) -{ - return container_of(hw, struct inno_dsidphy, pll.hw); -} - static void phy_update_bits(struct inno_dsidphy *inno, u8 first, u8 second, u8 mask, u8 val) { @@ -755,13 +750,11 @@ static int inno_dsidphy_probe(struct platform_device *pdev) return 0; } -static int inno_dsidphy_remove(struct platform_device *pdev) +static void inno_dsidphy_remove(struct platform_device *pdev) { struct inno_dsidphy *inno = platform_get_drvdata(pdev); pm_runtime_disable(inno->dev); - - return 0; } static const struct of_device_id inno_dsidphy_of_match[] = { @@ -788,7 +781,7 @@ static struct platform_driver inno_dsidphy_driver = { .of_match_table = of_match_ptr(inno_dsidphy_of_match), }, .probe = inno_dsidphy_probe, - .remove = inno_dsidphy_remove, + .remove_new = inno_dsidphy_remove, }; module_platform_driver(inno_dsidphy_driver); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index 80acca4e9e14..1e1563f5fffc 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -1246,11 +1246,9 @@ static int inno_hdmi_phy_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } -static int inno_hdmi_phy_remove(struct platform_device *pdev) +static void inno_hdmi_phy_remove(struct platform_device *pdev) { of_clk_del_provider(pdev->dev.of_node); - - return 0; } static const struct of_device_id inno_hdmi_phy_of_match[] = { @@ -1266,7 +1264,7 @@ MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); static struct platform_driver inno_hdmi_phy_driver = { .probe = inno_hdmi_phy_probe, - .remove = inno_hdmi_phy_remove, + .remove_new = inno_hdmi_phy_remove, .driver = { .name = "inno-hdmi-phy", .of_match_table = inno_hdmi_phy_of_match, diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 7b213825fb5d..7b8b001e4f9e 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -63,6 +63,9 @@ #define PHYREG18 0x44 #define PHYREG18_PLL_LOOP 0x32 +#define PHYREG27 0x6C +#define PHYREG27_RX_TRIM_RK3588 0x4C + #define PHYREG32 0x7C #define PHYREG32_SSC_MASK GENMASK(7, 4) #define PHYREG32_SSC_DIR_SHIFT 4 @@ -114,7 +117,10 @@ struct rockchip_combphy_grfcfg { struct combphy_reg con2_for_sata; struct combphy_reg con3_for_sata; struct combphy_reg pipe_con0_for_sata; + struct combphy_reg pipe_con1_for_sata; struct combphy_reg pipe_xpcs_phy_ready; + struct combphy_reg pipe_pcie1l0_sel; + struct combphy_reg pipe_pcie1l1_sel; }; struct rockchip_combphy_cfg { @@ -559,11 +565,189 @@ static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = { .combphy_cfg = rk3568_combphy_cfg, }; +static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) +{ + const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg; + unsigned long rate; + u32 val; + + switch (priv->type) { + case PHY_TYPE_PCIE: + rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l0_sel, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l1_sel, true); + break; + case PHY_TYPE_USB3: + /* Set SSC downward spread spectrum */ + rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, + PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT, + PHYREG32); + + /* Enable adaptive CTLE for USB3.0 Rx. */ + val = readl(priv->mmio + PHYREG15); + val |= PHYREG15_CTLE_EN; + writel(val, priv->mmio + PHYREG15); + + /* Set PLL KVCO fine tuning signals. */ + rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, + PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT, + PHYREG33); + + /* Enable controlling random jitter. */ + writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + + /* Set PLL input clock divider 1/2. */ + rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, + PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT, + PHYREG6); + + writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18); + writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false); + rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true); + break; + case PHY_TYPE_SATA: + /* Enable adaptive CTLE for SATA Rx. */ + val = readl(priv->mmio + PHYREG15); + val |= PHYREG15_CTLE_EN; + writel(val, priv->mmio + PHYREG15); + /* + * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA. + * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm) + */ + val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT; + val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT; + writel(val, priv->mmio + PHYREG7); + + rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_sata, true); + rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_sata, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true); + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true); + break; + case PHY_TYPE_SGMII: + case PHY_TYPE_QSGMII: + default: + dev_err(priv->dev, "incompatible PHY type\n"); + return -EINVAL; + } + + rate = clk_get_rate(priv->refclk); + + switch (rate) { + case REF_CLOCK_24MHz: + if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) { + /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */ + val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT; + rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK, + val, PHYREG15); + + writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16); + } + break; + + case REF_CLOCK_25MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true); + break; + case REF_CLOCK_100MHz: + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true); + if (priv->type == PHY_TYPE_PCIE) { + /* PLL KVCO fine tuning. */ + val = 4 << PHYREG33_PLL_KVCO_SHIFT; + rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, + val, PHYREG33); + + /* Enable controlling random jitter. */ + writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12); + + /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ + writel(PHYREG27_RX_TRIM_RK3588, priv->mmio + PHYREG27); + + /* Set up su_trim: */ + writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11); + } else if (priv->type == PHY_TYPE_SATA) { + /* downward spread spectrum +500ppm */ + val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT; + val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT; + rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32); + } + break; + default: + dev_err(priv->dev, "Unsupported rate: %lu\n", rate); + return -EINVAL; + } + + if (priv->ext_refclk) { + rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true); + if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) { + val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT; + val |= PHYREG13_CKRCV_AMP0; + rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13); + + val = readl(priv->mmio + PHYREG14); + val |= PHYREG14_CKRCV_AMP1; + writel(val, priv->mmio + PHYREG14); + } + } + + if (priv->enable_ssc) { + val = readl(priv->mmio + PHYREG8); + val |= PHYREG8_SSC_EN; + writel(val, priv->mmio + PHYREG8); + } + + return 0; +} + +static const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = { + /* pipe-phy-grf */ + .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 }, + .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 }, + .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 }, + .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 }, + .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 }, + .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 }, + .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 }, + .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 }, + .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 }, + .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 }, + .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 }, + .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 }, + .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 }, + .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 }, + .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 }, + .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 }, + .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 }, + .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 }, + .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 }, + .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 }, + /* pipe-grf */ + .pipe_con0_for_sata = { 0x0000, 11, 5, 0x00, 0x22 }, + .pipe_con1_for_sata = { 0x0000, 2, 0, 0x00, 0x2 }, + .pipe_pcie1l0_sel = { 0x0100, 0, 0, 0x01, 0x0 }, + .pipe_pcie1l1_sel = { 0x0100, 1, 1, 0x01, 0x0 }, +}; + +static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = { + .grfcfg = &rk3588_combphy_grfcfgs, + .combphy_cfg = rk3588_combphy_cfg, +}; + static const struct of_device_id rockchip_combphy_of_match[] = { { .compatible = "rockchip,rk3568-naneng-combphy", .data = &rk3568_combphy_cfgs, }, + { + .compatible = "rockchip,rk3588-naneng-combphy", + .data = &rk3588_combphy_cfgs, + }, { }, }; MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match); diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c index 75216091d901..8234b83fdd88 100644 --- a/drivers/phy/rockchip/phy-rockchip-pcie.c +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -119,21 +119,6 @@ static inline void phy_wr_cfg(struct rockchip_pcie_phy *rk_phy, PHY_CFG_WR_SHIFT)); } -static inline u32 phy_rd_cfg(struct rockchip_pcie_phy *rk_phy, - u32 addr) -{ - u32 val; - - regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, - HIWORD_UPDATE(addr, - PHY_CFG_RD_MASK, - PHY_CFG_ADDR_SHIFT)); - regmap_read(rk_phy->reg_base, - rk_phy->phy_data->pcie_status, - &val); - return val; -} - static int rockchip_pcie_phy_power_off(struct phy *phy) { struct phy_pcie_instance *inst = phy_get_drvdata(phy); diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 39db8acde61a..8b1667be4915 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1194,11 +1194,9 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) return 0; } -static int rockchip_typec_phy_remove(struct platform_device *pdev) +static void rockchip_typec_phy_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id rockchip_typec_phy_dt_ids[] = { @@ -1213,7 +1211,7 @@ MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); static struct platform_driver rockchip_typec_phy_driver = { .probe = rockchip_typec_phy_probe, - .remove = rockchip_typec_phy_remove, + .remove_new = rockchip_typec_phy_remove, .driver = { .name = "rockchip-typec-phy", .of_match_table = rockchip_typec_phy_dt_ids, diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c index 068160a34f5c..e30305b77f0d 100644 --- a/drivers/phy/st/phy-miphy28lp.c +++ b/drivers/phy/st/phy-miphy28lp.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -484,19 +485,11 @@ static inline void miphy28lp_pcie_config_gen(struct miphy28lp_phy *miphy_phy) static inline int miphy28lp_wait_compensation(struct miphy28lp_phy *miphy_phy) { - unsigned long finish = jiffies + 5 * HZ; u8 val; /* Waiting for Compensation to complete */ - do { - val = readb_relaxed(miphy_phy->base + MIPHY_COMP_FSM_6); - - if (time_after_eq(jiffies, finish)) - return -EBUSY; - cpu_relax(); - } while (!(val & COMP_DONE)); - - return 0; + return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_COMP_FSM_6, + val, val & COMP_DONE, 1, 5 * USEC_PER_SEC); } @@ -805,7 +798,6 @@ static inline void miphy28lp_configure_usb3(struct miphy28lp_phy *miphy_phy) static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy) { - unsigned long finish = jiffies + 5 * HZ; u8 mask = HFC_PLL | HFC_RDY; u8 val; @@ -816,21 +808,14 @@ static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy) if (miphy_phy->type == PHY_TYPE_SATA) mask |= PHY_RDY; - do { - val = readb_relaxed(miphy_phy->base + MIPHY_STATUS_1); - if ((val & mask) != mask) - cpu_relax(); - else - return 0; - } while (!time_after_eq(jiffies, finish)); - - return -EBUSY; + return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_STATUS_1, + val, (val & mask) == mask, 1, + 5 * USEC_PER_SEC); } static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy) { struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; - unsigned long finish = jiffies + 5 * HZ; u32 val; if (!miphy_phy->osc_rdy) @@ -839,17 +824,10 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy) if (!miphy_phy->syscfg_reg[SYSCFG_STATUS]) return -EINVAL; - do { - regmap_read(miphy_dev->regmap, - miphy_phy->syscfg_reg[SYSCFG_STATUS], &val); - - if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY) - cpu_relax(); - else - return 0; - } while (!time_after_eq(jiffies, finish)); - - return -EBUSY; + return regmap_read_poll_timeout(miphy_dev->regmap, + miphy_phy->syscfg_reg[SYSCFG_STATUS], + val, val & MIPHY_OSC_RDY, 1, + 5 * USEC_PER_SEC); } static int miphy28lp_get_resource_byname(struct device_node *child, diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c index 8871cd186304..292413db7da4 100644 --- a/drivers/phy/st/phy-spear1310-miphy.c +++ b/drivers/phy/st/phy-spear1310-miphy.c @@ -246,7 +246,7 @@ static struct platform_driver spear1310_miphy_driver = { .probe = spear1310_miphy_probe, .driver = { .name = "spear1310-miphy", - .of_match_table = of_match_ptr(spear1310_miphy_of_match), + .of_match_table = spear1310_miphy_of_match, }, }; diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c index ed4d0e2df053..c1d9ffa5a311 100644 --- a/drivers/phy/st/phy-spear1340-miphy.c +++ b/drivers/phy/st/phy-spear1340-miphy.c @@ -279,7 +279,7 @@ static struct platform_driver spear1340_miphy_driver = { .driver = { .name = "spear1340-miphy", .pm = &spear1340_miphy_pm_ops, - .of_match_table = of_match_ptr(spear1340_miphy_of_match), + .of_match_table = spear1340_miphy_of_match, }, }; diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index 5bb9647b078f..0a8552628cbd 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -317,6 +317,9 @@ static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) stm32_usbphyc_set_bits(pll_reg, PLLEN); + /* Wait for maximum lock time */ + usleep_range(200, 300); + return 0; reg_disable: @@ -766,7 +769,7 @@ clk_disable: return ret; } -static int stm32_usbphyc_remove(struct platform_device *pdev) +static void stm32_usbphyc_remove(struct platform_device *pdev) { struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); int port; @@ -779,8 +782,6 @@ static int stm32_usbphyc_remove(struct platform_device *pdev) stm32_usbphyc_clk48_unregister(usbphyc); clk_disable_unprepare(usbphyc->clk); - - return 0; } static int __maybe_unused stm32_usbphyc_resume(struct device *dev) @@ -810,7 +811,7 @@ MODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match); static struct platform_driver stm32_usbphyc_driver = { .probe = stm32_usbphyc_probe, - .remove = stm32_usbphyc_remove, + .remove_new = stm32_usbphyc_remove, .driver = { .of_match_table = stm32_usbphyc_of_match, .name = "stm32-usbphyc", diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c index 1aae8535f452..0f60d5d1c167 100644 --- a/drivers/phy/tegra/xusb-tegra186.c +++ b/drivers/phy/tegra/xusb-tegra186.c @@ -145,6 +145,8 @@ #define MODE_HS MODE(0) #define MODE_RST MODE(1) +#define XUSB_AO_UTMIP_SLEEPWALK_STATUS(x) (0xa0 + (x) * 4) + #define XUSB_AO_UTMIP_SLEEPWALK_CFG(x) (0xd0 + (x) * 4) #define XUSB_AO_UHSIC_SLEEPWALK_CFG(x) (0xf0 + (x) * 4) #define FAKE_USBOP_VAL BIT(0) @@ -172,24 +174,30 @@ #define AP_A BIT(4) #define AN_A BIT(5) #define HIGHZ_A BIT(6) +#define MASTER_ENABLE_A BIT(7) /* phase B */ #define USBOP_RPD_B BIT(8) #define USBON_RPD_B BIT(9) #define AP_B BIT(12) #define AN_B BIT(13) #define HIGHZ_B BIT(14) +#define MASTER_ENABLE_B BIT(15) /* phase C */ #define USBOP_RPD_C BIT(16) #define USBON_RPD_C BIT(17) #define AP_C BIT(20) #define AN_C BIT(21) #define HIGHZ_C BIT(22) +#define MASTER_ENABLE_C BIT(23) /* phase D */ #define USBOP_RPD_D BIT(24) #define USBON_RPD_D BIT(25) #define AP_D BIT(28) #define AN_D BIT(29) #define HIGHZ_D BIT(30) +#define MASTER_ENABLE_D BIT(31) +#define MASTER_ENABLE_B_C_D \ + (MASTER_ENABLE_B | MASTER_ENABLE_C | MASTER_ENABLE_D) #define XUSB_AO_UHSIC_SLEEPWALK(x) (0x120 + (x) * 4) /* phase A */ @@ -417,6 +425,8 @@ static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, value |= HIGHZ_A; value |= AP_A; value |= AN_B | AN_C | AN_D; + if (padctl->soc->supports_lp_cfg_en) + value |= MASTER_ENABLE_B_C_D; break; case USB_SPEED_LOW: @@ -424,6 +434,8 @@ static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, value |= HIGHZ_A; value |= AN_A; value |= AP_B | AP_C | AP_D; + if (padctl->soc->supports_lp_cfg_en) + value |= MASTER_ENABLE_B_C_D; break; default: @@ -488,6 +500,13 @@ static int tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) value |= WAKE_VAL_NONE; ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index)); + if (padctl->soc->supports_lp_cfg_en) { + /* disable the four stages of sleepwalk */ + value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK(index)); + value &= ~(MASTER_ENABLE_A | MASTER_ENABLE_B_C_D); + ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index)); + } + /* power down the line state detectors of the port */ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index)); value |= USBOP_VAL_PD | USBON_VAL_PD; @@ -1673,6 +1692,7 @@ const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = { .supports_gen2 = true, .poll_trk_completed = true, .trk_hw_mode = true, + .supports_lp_cfg_en = true, }; EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc); #endif diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 78045bd6c214..b55d4e9f42b5 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -805,6 +805,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl, usb2->base.lane = usb2->base.ops->map(&usb2->base); if (IS_ERR(usb2->base.lane)) { err = PTR_ERR(usb2->base.lane); + tegra_xusb_port_unregister(&usb2->base); goto out; } @@ -871,6 +872,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl, ulpi->base.lane = ulpi->base.ops->map(&ulpi->base); if (IS_ERR(ulpi->base.lane)) { err = PTR_ERR(ulpi->base.lane); + tegra_xusb_port_unregister(&ulpi->base); goto out; } @@ -1267,7 +1269,7 @@ remove: return err; } -static int tegra_xusb_padctl_remove(struct platform_device *pdev) +static void tegra_xusb_padctl_remove(struct platform_device *pdev) { struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); int err; @@ -1285,8 +1287,6 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) dev_err(&pdev->dev, "failed to assert reset: %d\n", err); padctl->soc->ops->remove(padctl); - - return 0; } static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev) @@ -1321,7 +1321,7 @@ static struct platform_driver tegra_xusb_padctl_driver = { .pm = &tegra_xusb_padctl_pm_ops, }, .probe = tegra_xusb_padctl_probe, - .remove = tegra_xusb_padctl_remove, + .remove_new = tegra_xusb_padctl_remove, }; module_platform_driver(tegra_xusb_padctl_driver); diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h index 8bd6cd281119..6e45d194c689 100644 --- a/drivers/phy/tegra/xusb.h +++ b/drivers/phy/tegra/xusb.h @@ -434,6 +434,7 @@ struct tegra_xusb_padctl_soc { bool need_fake_usb3_port; bool poll_trk_completed; bool trk_hw_mode; + bool supports_lp_cfg_en; }; struct tegra_xusb_padctl { diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 0be727bb9f79..4ed2d951d3df 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -842,20 +842,18 @@ clk_err: return ret; } -static int serdes_am654_remove(struct platform_device *pdev) +static void serdes_am654_remove(struct platform_device *pdev) { struct serdes_am654 *am654_phy = platform_get_drvdata(pdev); struct device_node *node = am654_phy->of_node; pm_runtime_disable(&pdev->dev); of_clk_del_provider(node); - - return 0; } static struct platform_driver serdes_am654_driver = { .probe = serdes_am654_probe, - .remove = serdes_am654_remove, + .remove_new = serdes_am654_remove, .driver = { .name = "phy-am654", .of_match_table = serdes_am654_id_table, diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c index 83bc0a9afe12..b7a9ef3f4654 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -211,7 +211,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) return 0; } -static int da8xx_usb_phy_remove(struct platform_device *pdev) +static void da8xx_usb_phy_remove(struct platform_device *pdev) { struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev); @@ -219,8 +219,6 @@ static int da8xx_usb_phy_remove(struct platform_device *pdev) phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx"); phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx"); } - - return 0; } static const struct of_device_id da8xx_usb_phy_ids[] = { @@ -231,7 +229,7 @@ MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); static struct platform_driver da8xx_usb_phy_driver = { .probe = da8xx_usb_phy_probe, - .remove = da8xx_usb_phy_remove, + .remove_new = da8xx_usb_phy_remove, .driver = { .name = "da8xx-usb-phy", .of_match_table = da8xx_usb_phy_ids, diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index fb619908f912..db153a55f4e1 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -257,20 +257,18 @@ clk_unprepare: return error; } -static int dm816x_usb_phy_remove(struct platform_device *pdev) +static void dm816x_usb_phy_remove(struct platform_device *pdev) { struct dm816x_usb_phy *phy = platform_get_drvdata(pdev); usb_remove_phy(&phy->phy); pm_runtime_disable(phy->dev); clk_unprepare(phy->refclk); - - return 0; } static struct platform_driver dm816x_usb_phy_driver = { .probe = dm816x_usb_phy_probe, - .remove = dm816x_usb_phy_remove, + .remove_new = dm816x_usb_phy_remove, .driver = { .name = "dm816x-usb-phy", .pm = &dm816x_usb_phy_pm_ops, diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 1b83c98a78f0..d91923799df2 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -443,18 +443,17 @@ static int wiz_mode_select(struct wiz *wiz) int i; for (i = 0; i < num_lanes; i++) { - if (wiz->lane_phy_type[i] == PHY_TYPE_DP) + if (wiz->lane_phy_type[i] == PHY_TYPE_DP) { mode = LANE_MODE_GEN1; - else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) + } else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) { mode = LANE_MODE_GEN2; - else - continue; - - if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { + } else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3); ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3); ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3); mode = LANE_MODE_GEN1; + } else { + continue; } ret = regmap_field_write(wiz->p_standard_mode[i], mode); @@ -1235,6 +1234,8 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane) if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE) return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1); break; + + case J721E_WIZ_16G: case J721E_WIZ_10G: case J7200_WIZ_10G: case J721S2_WIZ_10G: @@ -1636,7 +1637,7 @@ err_addr_to_resource: return ret; } -static int wiz_remove(struct platform_device *pdev) +static void wiz_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; @@ -1650,13 +1651,11 @@ static int wiz_remove(struct platform_device *pdev) wiz_clock_cleanup(wiz, node); pm_runtime_put(dev); pm_runtime_disable(dev); - - return 0; } static struct platform_driver wiz_driver = { .probe = wiz_probe, - .remove = wiz_remove, + .remove_new = wiz_remove, .driver = { .name = "wiz", .of_match_table = wiz_id_table, diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c index 31a775877f6e..762d3de8b3c5 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -445,11 +445,9 @@ static int omap_usb2_probe(struct platform_device *pdev) PTR_ERR(phy->wkupclk)); phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); - if (IS_ERR(phy->wkupclk)) { - if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); - return PTR_ERR(phy->wkupclk); - } + if (IS_ERR(phy->wkupclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(phy->wkupclk), + "unable to get usb_phy_cm_clk32k\n"); dev_warn(&pdev->dev, "found usb_phy_cm_clk32k, please fix DTS\n"); @@ -506,19 +504,17 @@ static int omap_usb2_probe(struct platform_device *pdev) return 0; } -static int omap_usb2_remove(struct platform_device *pdev) +static void omap_usb2_remove(struct platform_device *pdev) { struct omap_usb *phy = platform_get_drvdata(pdev); usb_remove_phy(&phy->phy); pm_runtime_disable(phy->dev); - - return 0; } static struct platform_driver omap_usb2_driver = { .probe = omap_usb2_probe, - .remove = omap_usb2_remove, + .remove_new = omap_usb2_remove, .driver = { .name = "omap-usb2", .of_match_table = omap_usb2_id_table, diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index f502c36f3be5..507e1552db5e 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -841,7 +841,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(phy_provider); } -static int ti_pipe3_remove(struct platform_device *pdev) +static void ti_pipe3_remove(struct platform_device *pdev) { struct ti_pipe3 *phy = platform_get_drvdata(pdev); @@ -850,8 +850,6 @@ static int ti_pipe3_remove(struct platform_device *pdev) phy->sata_refclk_enabled = false; } pm_runtime_disable(&pdev->dev); - - return 0; } static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) @@ -928,7 +926,7 @@ MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); static struct platform_driver ti_pipe3_driver = { .probe = ti_pipe3_probe, - .remove = ti_pipe3_remove, + .remove_new = ti_pipe3_remove, .driver = { .name = "ti-pipe3", .of_match_table = ti_pipe3_id_table, diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index ac71017a0bc1..da50732625d1 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -787,7 +787,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) return 0; } -static int twl4030_usb_remove(struct platform_device *pdev) +static void twl4030_usb_remove(struct platform_device *pdev) { struct twl4030_usb *twl = platform_get_drvdata(pdev); int val; @@ -821,8 +821,6 @@ static int twl4030_usb_remove(struct platform_device *pdev) /* disable complete OTG block */ twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); - - return 0; } #ifdef CONFIG_OF @@ -835,7 +833,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, - .remove = twl4030_usb_remove, + .remove_new = twl4030_usb_remove, .driver = { .name = "twl4030_usb", .pm = &twl4030_usb_pm_ops, diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 9be9535ad7ab..8833680923a1 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -8,9 +8,8 @@ * Author: Subbaraya Sundeep * Author: Laurent Pinchart * - * This driver is tested for USB, SATA and Display Port currently. - * Other controllers PCIe and SGMII should also work but that is - * experimental as of now. + * This driver is tested for USB, SGMII, SATA and Display Port currently. + * PCIe should also work but that is experimental as of now. */ #include diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index dcb53c4a9584..5787c579dcf6 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -480,25 +480,6 @@ config PINCTRL_TB10X depends on OF && ARC_PLAT_TB10X select GPIOLIB -config PINCTRL_THUNDERBAY - tristate "Generic pinctrl and GPIO driver for Intel Thunder Bay SoC" - depends on ARCH_THUNDERBAY || (ARM64 && COMPILE_TEST) - depends on HAS_IOMEM - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GENERIC_PINCTRL_GROUPS - select GENERIC_PINMUX_FUNCTIONS - select GPIOLIB - select GPIOLIB_IRQCHIP - select GPIO_GENERIC - help - This selects pin control driver for the Intel Thunder Bay SoC. - It provides pin config functions such as pull-up, pull-down, - interrupt, drive strength, sec lock, Schmitt trigger, slew - rate control and direction control. This module will be - called as pinctrl-thunderbay. - config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ @@ -523,6 +504,19 @@ config PINCTRL_ZYNQMP This driver can also be built as a module. If so, the module will be called pinctrl-zynqmp. +config PINCTRL_MLXBF3 + tristate "NVIDIA BlueField-3 SoC Pinctrl driver" + depends on (MELLANOX_PLATFORM && ARM64) || COMPILE_TEST + select PINMUX + select GPIOLIB + select GPIOLIB_IRQCHIP + select GPIO_MLXBF3 + help + Say Y to select the pinctrl driver for BlueField-3 SoCs. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-mlxbf3. + source "drivers/pinctrl/actions/Kconfig" source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" @@ -535,9 +529,9 @@ source "drivers/pinctrl/meson/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/nomadik/Kconfig" source "drivers/pinctrl/nuvoton/Kconfig" +source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/pxa/Kconfig" source "drivers/pinctrl/qcom/Kconfig" -source "drivers/pinctrl/ralink/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/samsung/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d5939840bb2a..e196c6e324ad 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_PINCTRL_MCP23S08_I2C) += pinctrl-mcp23s08_i2c.o obj-$(CONFIG_PINCTRL_MCP23S08_SPI) += pinctrl-mcp23s08_spi.o obj-$(CONFIG_PINCTRL_MCP23S08) += pinctrl-mcp23s08.o obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o +obj-$(CONFIG_PINCTRL_MLXBF3) += pinctrl-mlxbf3.o obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_PINCTRL_OXNAS) += pinctrl-oxnas.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o @@ -48,7 +49,6 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o -obj-$(CONFIG_PINCTRL_THUNDERBAY) += pinctrl-thunderbay.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o @@ -64,9 +64,9 @@ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-y += mvebu/ obj-y += nomadik/ obj-y += nuvoton/ +obj-y += nxp/ obj-$(CONFIG_PINCTRL_PXA) += pxa/ obj-$(CONFIG_ARCH_QCOM) += qcom/ -obj-$(CONFIG_PINCTRL_RALINK) += ralink/ obj-$(CONFIG_PINCTRL_RENESAS) += renesas/ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ obj-$(CONFIG_PINCTRL_SPEAR) += spear/ diff --git a/drivers/pinctrl/actions/pinctrl-s500.c b/drivers/pinctrl/actions/pinctrl-s500.c index ced778079b76..3bed4b8d08e6 100644 --- a/drivers/pinctrl/actions/pinctrl-s500.c +++ b/drivers/pinctrl/actions/pinctrl-s500.c @@ -1724,4 +1724,3 @@ module_exit(s500_pinctrl_exit); MODULE_AUTHOR("Actions Semi Inc."); MODULE_AUTHOR("Cristian Ciocaltea "); MODULE_DESCRIPTION("Actions Semi S500 SoC Pinctrl Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/actions/pinctrl-s700.c b/drivers/pinctrl/actions/pinctrl-s700.c index fd00940a5799..c2b472660e53 100644 --- a/drivers/pinctrl/actions/pinctrl-s700.c +++ b/drivers/pinctrl/actions/pinctrl-s700.c @@ -1908,4 +1908,3 @@ module_exit(s700_pinctrl_exit); MODULE_AUTHOR("Actions Semi Inc."); MODULE_DESCRIPTION("Actions Semi S700 Soc Pinctrl Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/actions/pinctrl-s900.c b/drivers/pinctrl/actions/pinctrl-s900.c index 811249a8011e..8638d3007cd9 100644 --- a/drivers/pinctrl/actions/pinctrl-s900.c +++ b/drivers/pinctrl/actions/pinctrl-s900.c @@ -1827,4 +1827,3 @@ module_exit(s900_pinctrl_exit); MODULE_AUTHOR("Actions Semi Inc."); MODULE_AUTHOR("Manivannan Sadhasivam "); MODULE_DESCRIPTION("Actions Semi S900 SoC Pinctrl Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index 8e2551a08c37..7435173e10f4 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -90,6 +90,8 @@ struct bcm2835_pinctrl { struct pinctrl_gpio_range gpio_range; raw_spinlock_t irq_lock[BCM2835_NUM_BANKS]; + /* Protect FSEL registers */ + spinlock_t fsel_lock; }; /* pins are just named GPIO0..GPIO53 */ @@ -284,14 +286,19 @@ static inline void bcm2835_pinctrl_fsel_set( struct bcm2835_pinctrl *pc, unsigned pin, enum bcm2835_fsel fsel) { - u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); - enum bcm2835_fsel cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; + u32 val; + enum bcm2835_fsel cur; + unsigned long flags; + + spin_lock_irqsave(&pc->fsel_lock, flags); + val = bcm2835_gpio_rd(pc, FSEL_REG(pin)); + cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK; dev_dbg(pc->dev, "read %08x (%u => %s)\n", val, pin, - bcm2835_functions[cur]); + bcm2835_functions[cur]); if (cur == fsel) - return; + goto unlock; if (cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN) { /* always transition through GPIO_IN */ @@ -309,6 +316,9 @@ static inline void bcm2835_pinctrl_fsel_set( dev_dbg(pc->dev, "write %08x (%u <= %s)\n", val, pin, bcm2835_functions[fsel]); bcm2835_gpio_wr(pc, FSEL_REG(pin), val); + +unlock: + spin_unlock_irqrestore(&pc->fsel_lock, flags); } static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -1248,6 +1258,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) pc->gpio_chip = *pdata->gpio_chip; pc->gpio_chip.parent = dev; + spin_lock_init(&pc->fsel_lock); for (i = 0; i < BCM2835_NUM_BANKS; i++) { unsigned long events; unsigned offset; diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c index 3df56a4ea510..cc3eb7409ab3 100644 --- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -108,7 +109,6 @@ struct iproc_gpio { raw_spinlock_t lock; - struct irq_chip irqchip; struct gpio_chip gc; unsigned num_banks; @@ -217,7 +217,7 @@ static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct iproc_gpio *chip = gpiochip_get_data(gc); - unsigned gpio = d->hwirq; + unsigned gpio = irqd_to_hwirq(d); iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask); } @@ -231,6 +231,7 @@ static void iproc_gpio_irq_mask(struct irq_data *d) raw_spin_lock_irqsave(&chip->lock, flags); iproc_gpio_irq_set_mask(d, false); raw_spin_unlock_irqrestore(&chip->lock, flags); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void iproc_gpio_irq_unmask(struct irq_data *d) @@ -239,6 +240,7 @@ static void iproc_gpio_irq_unmask(struct irq_data *d) struct iproc_gpio *chip = gpiochip_get_data(gc); unsigned long flags; + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); raw_spin_lock_irqsave(&chip->lock, flags); iproc_gpio_irq_set_mask(d, true); raw_spin_unlock_irqrestore(&chip->lock, flags); @@ -302,6 +304,26 @@ static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct iproc_gpio *chip = gpiochip_get_data(gc); + + seq_printf(p, dev_name(chip->dev)); +} + +static const struct irq_chip iproc_gpio_irq_chip = { + .irq_ack = iproc_gpio_irq_ack, + .irq_mask = iproc_gpio_irq_mask, + .irq_unmask = iproc_gpio_irq_unmask, + .irq_set_type = iproc_gpio_irq_set_type, + .irq_enable = iproc_gpio_irq_unmask, + .irq_disable = iproc_gpio_irq_mask, + .irq_print_chip = iproc_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + /* * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO */ @@ -852,20 +874,10 @@ static int iproc_gpio_probe(struct platform_device *pdev) /* optional GPIO interrupt support */ irq = platform_get_irq_optional(pdev, 0); if (irq > 0) { - struct irq_chip *irqc; struct gpio_irq_chip *girq; - irqc = &chip->irqchip; - irqc->name = dev_name(dev); - irqc->irq_ack = iproc_gpio_irq_ack; - irqc->irq_mask = iproc_gpio_irq_mask; - irqc->irq_unmask = iproc_gpio_irq_unmask; - irqc->irq_set_type = iproc_gpio_irq_set_type; - irqc->irq_enable = iproc_gpio_irq_unmask; - irqc->irq_disable = iproc_gpio_irq_mask; - girq = &gc->irq; - girq->chip = irqc; + gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip); girq->parent_handler = iproc_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c index 465cc96814a1..f80630a74d34 100644 --- a/drivers/pinctrl/bcm/pinctrl-ns.c +++ b/drivers/pinctrl/bcm/pinctrl-ns.c @@ -299,5 +299,4 @@ static struct platform_driver ns_pinctrl_driver = { module_platform_driver(ns_pinctrl_driver); MODULE_AUTHOR("Rafał Miłecki"); -MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(of, ns_pinctrl_of_match_table); diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c index 3c792bf03bda..5045a7e57f1d 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c @@ -60,7 +60,6 @@ struct nsp_gpio { struct device *dev; void __iomem *base; void __iomem *io_ctrl; - struct irq_chip irqchip; struct gpio_chip gc; struct pinctrl_dev *pctl; struct pinctrl_desc pctldesc; @@ -193,6 +192,7 @@ static void nsp_gpio_irq_mask(struct irq_data *d) raw_spin_lock_irqsave(&chip->lock, flags); nsp_gpio_irq_set_mask(d, false); raw_spin_unlock_irqrestore(&chip->lock, flags); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void nsp_gpio_irq_unmask(struct irq_data *d) @@ -201,6 +201,7 @@ static void nsp_gpio_irq_unmask(struct irq_data *d) struct nsp_gpio *chip = gpiochip_get_data(gc); unsigned long flags; + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); raw_spin_lock_irqsave(&chip->lock, flags); nsp_gpio_irq_set_mask(d, true); raw_spin_unlock_irqrestore(&chip->lock, flags); @@ -258,6 +259,16 @@ static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static const struct irq_chip nsp_gpio_irq_chip = { + .name = "gpio-a", + .irq_ack = nsp_gpio_irq_ack, + .irq_mask = nsp_gpio_irq_mask, + .irq_unmask = nsp_gpio_irq_unmask, + .irq_set_type = nsp_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) { struct nsp_gpio *chip = gpiochip_get_data(gc); @@ -650,14 +661,6 @@ static int nsp_gpio_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq > 0) { struct gpio_irq_chip *girq; - struct irq_chip *irqc; - - irqc = &chip->irqchip; - irqc->name = "gpio-a"; - irqc->irq_ack = nsp_gpio_irq_ack; - irqc->irq_mask = nsp_gpio_irq_mask; - irqc->irq_unmask = nsp_gpio_irq_unmask; - irqc->irq_set_type = nsp_gpio_irq_set_type; val = readl(chip->base + NSP_CHIP_A_INT_MASK); val = val | NSP_CHIP_A_GPIO_INT_BIT; @@ -673,7 +676,7 @@ static int nsp_gpio_probe(struct platform_device *pdev) } girq = &chip->gc.irq; - girq->chip = irqc; + gpio_irq_chip_set_chip(girq, &nsp_gpio_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 7a32f77792d9..27bdc548f3a7 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -4,7 +4,7 @@ config PINCTRL_IMX depends on OF select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS - select GENERIC_PINCONF + select PINCONF select REGMAP config PINCTRL_IMX_SCU diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index e9aef764138f..93ffb5fc04e7 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -292,62 +292,6 @@ struct pinmux_ops imx_pmx_ops = { .set_mux = imx_pmx_set, }; -/* decode generic config into raw register values */ -static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl, - unsigned long *configs, - unsigned int num_configs) -{ - const struct imx_pinctrl_soc_info *info = ipctl->info; - const struct imx_cfg_params_decode *decode; - enum pin_config_param param; - u32 raw_config = 0; - u32 param_val; - int i, j; - - WARN_ON(num_configs > info->num_decodes); - - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - param_val = pinconf_to_config_argument(configs[i]); - decode = info->decodes; - for (j = 0; j < info->num_decodes; j++) { - if (param == decode->param) { - if (decode->invert) - param_val = !param_val; - raw_config |= (param_val << decode->shift) - & decode->mask; - break; - } - decode++; - } - } - - if (info->fixup) - info->fixup(configs, num_configs, &raw_config); - - return raw_config; -} - -static u32 imx_pinconf_parse_generic_config(struct device_node *np, - struct imx_pinctrl *ipctl) -{ - const struct imx_pinctrl_soc_info *info = ipctl->info; - struct pinctrl_dev *pctl = ipctl->pctl; - unsigned int num_configs; - unsigned long *configs; - int ret; - - if (!info->generic_pinconf) - return 0; - - ret = pinconf_generic_parse_dt_config(np, pctl, &configs, - &num_configs); - if (ret) - return 0; - - return imx_pinconf_decode_generic_config(ipctl, configs, num_configs); -} - static int imx_pinconf_get_mmio(struct pinctrl_dev *pctldev, unsigned pin_id, unsigned long *config) { @@ -500,7 +444,6 @@ static const struct pinconf_ops imx_pinconf_ops = { /* * Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin. - * For generic_pinconf case, there's no extra u32 CONFIG. * * PIN_FUNC_ID format: * Default: @@ -548,18 +491,12 @@ static void imx_pinctrl_parse_pin_mmio(struct imx_pinctrl *ipctl, pin_mmio->mux_mode = be32_to_cpu(*list++); pin_mmio->input_val = be32_to_cpu(*list++); - if (info->generic_pinconf) { - /* generic pin config decoded */ - pin_mmio->config = imx_pinconf_parse_generic_config(np, ipctl); - } else { - /* legacy pin config read from devicetree */ - config = be32_to_cpu(*list++); + config = be32_to_cpu(*list++); - /* SION bit is in mux register */ - if (config & IMX_PAD_SION) - pin_mmio->mux_mode |= IOMUXC_CONFIG_SION; - pin_mmio->config = config & ~IMX_PAD_SION; - } + /* SION bit is in mux register */ + if (config & IMX_PAD_SION) + pin_mmio->mux_mode |= IOMUXC_CONFIG_SION; + pin_mmio->config = config & ~IMX_PAD_SION; *list_p = list; @@ -587,9 +524,6 @@ static int imx_pinctrl_parse_groups(struct device_node *np, else pin_size = FSL_PIN_SIZE; - if (info->generic_pinconf) - pin_size -= 4; - /* Initialise group */ grp->name = np->name; @@ -855,10 +789,6 @@ int imx_pinctrl_probe(struct platform_device *pdev, imx_pinctrl_desc->confops = &imx_pinconf_ops; imx_pinctrl_desc->owner = THIS_MODULE; - /* for generic pinconf */ - imx_pinctrl_desc->custom_params = info->custom_params; - imx_pinctrl_desc->num_custom_params = info->num_custom_params; - /* platform specific callback */ imx_pmx_ops.gpio_set_direction = info->gpio_set_direction; diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index fd8c4b6b3e36..f65ff45b4003 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -11,7 +11,6 @@ #ifndef __DRIVERS_PINCTRL_IMX_H #define __DRIVERS_PINCTRL_IMX_H -#include #include struct platform_device; @@ -67,14 +66,6 @@ struct imx_pin_reg { s16 conf_reg; }; -/* decode a generic config into raw register value */ -struct imx_cfg_params_decode { - enum pin_config_param param; - u32 mask; - u8 shift; - bool invert; -}; - /** * @dev: a pointer back to containing device * @base: the offset to the controller in virtual memory @@ -100,15 +91,6 @@ struct imx_pinctrl_soc_info { unsigned int mux_mask; u8 mux_shift; - /* generic pinconf */ - bool generic_pinconf; - const struct pinconf_generic_params *custom_params; - unsigned int num_custom_params; - const struct imx_cfg_params_decode *decodes; - unsigned int num_decodes; - void (*fixup)(unsigned long *configs, unsigned int num_configs, - u32 *raw_config); - int (*gpio_set_direction)(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, @@ -122,12 +104,6 @@ struct imx_pinctrl_soc_info { const __be32 **list_p); }; -#define IMX_CFG_PARAMS_DECODE(p, m, o) \ - { .param = p, .mask = m, .shift = o, .invert = false, } - -#define IMX_CFG_PARAMS_DECODE_INVERT(p, m, o) \ - { .param = p, .mask = m, .shift = o, .invert = true, } - #define SHARE_MUX_CONF_REG BIT(0) #define ZERO_OFFSET_VALID BIT(1) #define IMX_USE_SCU BIT(2) diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index a71874fed3d6..7af287252834 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "MediaTek pinctrl drivers" - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST config EINT_MTK tristate "MediaTek External Interrupt Support" @@ -17,11 +17,16 @@ config PINCTRL_MTK select GENERIC_PINCONF select GPIOLIB select EINT_MTK - select OF_GPIO config PINCTRL_MTK_V2 tristate +config PINCTRL_MTK_MTMIPS + bool + depends on RALINK + select PINMUX + select GENERIC_PINCONF + config PINCTRL_MTK_MOORE bool depends on OF @@ -29,7 +34,6 @@ config PINCTRL_MTK_MOORE select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS select GPIOLIB - select OF_GPIO select EINT_MTK select PINCTRL_MTK_V2 @@ -40,9 +44,51 @@ config PINCTRL_MTK_PARIS select GENERIC_PINCONF select GPIOLIB select EINT_MTK - select OF_GPIO select PINCTRL_MTK_V2 +# For MIPS SoCs +config PINCTRL_MT7620 + bool "MediaTek MT7620 pin control" + depends on SOC_MT7620 || COMPILE_TEST + depends on RALINK + default SOC_MT7620 + select PINCTRL_MTK_MTMIPS + +config PINCTRL_MT7621 + bool "MediaTek MT7621 pin control" + depends on SOC_MT7621 || COMPILE_TEST + depends on RALINK + default SOC_MT7621 + select PINCTRL_MTK_MTMIPS + +config PINCTRL_MT76X8 + bool "MediaTek MT76X8 pin control" + depends on SOC_MT7620 || COMPILE_TEST + depends on RALINK + default SOC_MT7620 + select PINCTRL_MTK_MTMIPS + +config PINCTRL_RT2880 + bool "Ralink RT2880 pin control" + depends on SOC_RT288X || COMPILE_TEST + depends on RALINK + default SOC_RT288X + select PINCTRL_MTK_MTMIPS + +config PINCTRL_RT305X + bool "Ralink RT305X pin control" + depends on SOC_RT305X || COMPILE_TEST + depends on RALINK + default SOC_RT305X + select PINCTRL_MTK_MTMIPS + +config PINCTRL_RT3883 + bool "Ralink RT3883 pin control" + depends on SOC_RT3883 || COMPILE_TEST + depends on RALINK + default SOC_RT3883 + select PINCTRL_MTK_MTMIPS + # For ARMv7 SoCs config PINCTRL_MT2701 bool "MediaTek MT2701 pin control" diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 44d197af516a..680f7e8526e0 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -1,32 +1,39 @@ # SPDX-License-Identifier: GPL-2.0 # Core -obj-$(CONFIG_EINT_MTK) += mtk-eint.o -obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o -obj-$(CONFIG_PINCTRL_MTK_V2) += pinctrl-mtk-common-v2.o -obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o -obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o +obj-$(CONFIG_EINT_MTK) += mtk-eint.o +obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o +obj-$(CONFIG_PINCTRL_MTK_V2) += pinctrl-mtk-common-v2.o +obj-$(CONFIG_PINCTRL_MTK_MTMIPS) += pinctrl-mtmips.o +obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o +obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o # SoC Drivers -obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o -obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o -obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o -obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o -obj-$(CONFIG_PINCTRL_MT6765) += pinctrl-mt6765.o -obj-$(CONFIG_PINCTRL_MT6779) += pinctrl-mt6779.o -obj-$(CONFIG_PINCTRL_MT6795) += pinctrl-mt6795.o -obj-$(CONFIG_PINCTRL_MT6797) += pinctrl-mt6797.o -obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o -obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o -obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o -obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o -obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o -obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o -obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o -obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o -obj-$(CONFIG_PINCTRL_MT8186) += pinctrl-mt8186.o -obj-$(CONFIG_PINCTRL_MT8188) += pinctrl-mt8188.o -obj-$(CONFIG_PINCTRL_MT8192) += pinctrl-mt8192.o -obj-$(CONFIG_PINCTRL_MT8195) += pinctrl-mt8195.o -obj-$(CONFIG_PINCTRL_MT8365) += pinctrl-mt8365.o -obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o -obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o +obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o +obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o +obj-$(CONFIG_PINCTRL_MT76X8) += pinctrl-mt76x8.o +obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o +obj-$(CONFIG_PINCTRL_RT305X) += pinctrl-rt305x.o +obj-$(CONFIG_PINCTRL_RT3883) += pinctrl-rt3883.o +obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o +obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o +obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o +obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o +obj-$(CONFIG_PINCTRL_MT6765) += pinctrl-mt6765.o +obj-$(CONFIG_PINCTRL_MT6779) += pinctrl-mt6779.o +obj-$(CONFIG_PINCTRL_MT6795) += pinctrl-mt6795.o +obj-$(CONFIG_PINCTRL_MT6797) += pinctrl-mt6797.o +obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o +obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o +obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o +obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o +obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o +obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o +obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o +obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o +obj-$(CONFIG_PINCTRL_MT8186) += pinctrl-mt8186.o +obj-$(CONFIG_PINCTRL_MT8188) += pinctrl-mt8188.o +obj-$(CONFIG_PINCTRL_MT8192) += pinctrl-mt8192.o +obj-$(CONFIG_PINCTRL_MT8195) += pinctrl-mt8195.o +obj-$(CONFIG_PINCTRL_MT8365) += pinctrl-mt8365.o +obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o +obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c index 007b98ce5631..8649a2f9d324 100644 --- a/drivers/pinctrl/mediatek/pinctrl-moore.c +++ b/drivers/pinctrl/mediatek/pinctrl-moore.c @@ -586,7 +586,7 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw) * Documentation/devicetree/bindings/gpio/gpio.txt on how to * bind pinctrl and gpio drivers via the "gpio-ranges" property. */ - if (!of_find_property(hw->dev->of_node, "gpio-ranges", NULL)) { + if (!of_property_present(hw->dev->of_node, "gpio-ranges")) { ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, chip->ngpio); if (ret < 0) { diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7620.c b/drivers/pinctrl/mediatek/pinctrl-mt7620.c new file mode 100644 index 000000000000..d2624b9b5bc4 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7620.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include "pinctrl-mtmips.h" + +#define MT7620_GPIO_MODE_UART0_SHIFT 2 +#define MT7620_GPIO_MODE_UART0_MASK 0x7 +#define MT7620_GPIO_MODE_UART0(x) ((x) << MT7620_GPIO_MODE_UART0_SHIFT) +#define MT7620_GPIO_MODE_UARTF 0x0 +#define MT7620_GPIO_MODE_PCM_UARTF 0x1 +#define MT7620_GPIO_MODE_PCM_I2S 0x2 +#define MT7620_GPIO_MODE_I2S_UARTF 0x3 +#define MT7620_GPIO_MODE_PCM_GPIO 0x4 +#define MT7620_GPIO_MODE_GPIO_UARTF 0x5 +#define MT7620_GPIO_MODE_GPIO_I2S 0x6 +#define MT7620_GPIO_MODE_GPIO 0x7 + +#define MT7620_GPIO_MODE_NAND 0 +#define MT7620_GPIO_MODE_SD 1 +#define MT7620_GPIO_MODE_ND_SD_GPIO 2 +#define MT7620_GPIO_MODE_ND_SD_MASK 0x3 +#define MT7620_GPIO_MODE_ND_SD_SHIFT 18 + +#define MT7620_GPIO_MODE_PCIE_RST 0 +#define MT7620_GPIO_MODE_PCIE_REF 1 +#define MT7620_GPIO_MODE_PCIE_GPIO 2 +#define MT7620_GPIO_MODE_PCIE_MASK 0x3 +#define MT7620_GPIO_MODE_PCIE_SHIFT 16 + +#define MT7620_GPIO_MODE_WDT_RST 0 +#define MT7620_GPIO_MODE_WDT_REF 1 +#define MT7620_GPIO_MODE_WDT_GPIO 2 +#define MT7620_GPIO_MODE_WDT_MASK 0x3 +#define MT7620_GPIO_MODE_WDT_SHIFT 21 + +#define MT7620_GPIO_MODE_MDIO 0 +#define MT7620_GPIO_MODE_MDIO_REFCLK 1 +#define MT7620_GPIO_MODE_MDIO_GPIO 2 +#define MT7620_GPIO_MODE_MDIO_MASK 0x3 +#define MT7620_GPIO_MODE_MDIO_SHIFT 7 + +#define MT7620_GPIO_MODE_I2C 0 +#define MT7620_GPIO_MODE_UART1 5 +#define MT7620_GPIO_MODE_RGMII1 9 +#define MT7620_GPIO_MODE_RGMII2 10 +#define MT7620_GPIO_MODE_SPI 11 +#define MT7620_GPIO_MODE_SPI_REF_CLK 12 +#define MT7620_GPIO_MODE_WLED 13 +#define MT7620_GPIO_MODE_JTAG 15 +#define MT7620_GPIO_MODE_EPHY 15 +#define MT7620_GPIO_MODE_PA 20 + +static struct mtmips_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct mtmips_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; +static struct mtmips_pmx_func mdio_grp[] = { + FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2), + FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2), +}; +static struct mtmips_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) }; +static struct mtmips_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) }; +static struct mtmips_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) }; +static struct mtmips_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) }; +static struct mtmips_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) }; +static struct mtmips_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) }; +static struct mtmips_pmx_func uartf_grp[] = { + FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", MT7620_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", MT7620_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct mtmips_pmx_func wdt_grp[] = { + FUNC("wdt rst", 0, 17, 1), + FUNC("wdt refclk", 0, 17, 1), + }; +static struct mtmips_pmx_func pcie_rst_grp[] = { + FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1), + FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1) +}; +static struct mtmips_pmx_func nd_sd_grp[] = { + FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15), + FUNC("sd", MT7620_GPIO_MODE_SD, 47, 13) +}; + +static struct mtmips_pmx_group mt7620a_pinmux_data[] = { + GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C), + GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK, + MT7620_GPIO_MODE_UART0_SHIFT), + GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI), + GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1), + GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK, + MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT), + GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK, + MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT), + GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1), + GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK), + GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK, + MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT), + GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK, + MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT), + GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2), + GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED), + GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY), + GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA), + { 0 } +}; + +static int mt7620_pinctrl_probe(struct platform_device *pdev) +{ + return mtmips_pinctrl_init(pdev, mt7620a_pinmux_data); +} + +static const struct of_device_id mt7620_pinctrl_match[] = { + { .compatible = "ralink,mt7620-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt7620_pinctrl_match); + +static struct platform_driver mt7620_pinctrl_driver = { + .probe = mt7620_pinctrl_probe, + .driver = { + .name = "mt7620-pinctrl", + .of_match_table = mt7620_pinctrl_match, + }, +}; + +static int __init mt7620_pinctrl_init(void) +{ + return platform_driver_register(&mt7620_pinctrl_driver); +} +core_initcall_sync(mt7620_pinctrl_init); diff --git a/drivers/pinctrl/ralink/pinctrl-mt7621.c b/drivers/pinctrl/mediatek/pinctrl-mt7621.c similarity index 79% rename from drivers/pinctrl/ralink/pinctrl-mt7621.c rename to drivers/pinctrl/mediatek/pinctrl-mt7621.c index eddc0ba6d468..b18c1a47bbeb 100644 --- a/drivers/pinctrl/ralink/pinctrl-mt7621.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7621.c @@ -3,7 +3,7 @@ #include #include #include -#include "pinctrl-ralink.h" +#include "pinctrl-mtmips.h" #define MT7621_GPIO_MODE_UART1 1 #define MT7621_GPIO_MODE_I2C 2 @@ -34,40 +34,40 @@ #define MT7621_GPIO_MODE_SDHCI_SHIFT 18 #define MT7621_GPIO_MODE_SDHCI_GPIO 1 -static struct ralink_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) }; -static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) }; -static struct ralink_pmx_func uart3_grp[] = { +static struct mtmips_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) }; +static struct mtmips_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) }; +static struct mtmips_pmx_func uart3_grp[] = { FUNC("uart3", 0, 5, 4), FUNC("i2s", 2, 5, 4), FUNC("spdif3", 3, 5, 4), }; -static struct ralink_pmx_func uart2_grp[] = { +static struct mtmips_pmx_func uart2_grp[] = { FUNC("uart2", 0, 9, 4), FUNC("pcm", 2, 9, 4), FUNC("spdif2", 3, 9, 4), }; -static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) }; -static struct ralink_pmx_func wdt_grp[] = { +static struct mtmips_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) }; +static struct mtmips_pmx_func wdt_grp[] = { FUNC("wdt rst", 0, 18, 1), FUNC("wdt refclk", 2, 18, 1), }; -static struct ralink_pmx_func pcie_rst_grp[] = { +static struct mtmips_pmx_func pcie_rst_grp[] = { FUNC("pcie rst", MT7621_GPIO_MODE_PCIE_RST, 19, 1), FUNC("pcie refclk", MT7621_GPIO_MODE_PCIE_REF, 19, 1) }; -static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) }; -static struct ralink_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) }; -static struct ralink_pmx_func spi_grp[] = { +static struct mtmips_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) }; +static struct mtmips_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 34, 7), FUNC("nand1", 2, 34, 7), }; -static struct ralink_pmx_func sdhci_grp[] = { +static struct mtmips_pmx_func sdhci_grp[] = { FUNC("sdhci", 0, 41, 8), FUNC("nand2", 2, 41, 8), }; -static struct ralink_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) }; +static struct mtmips_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) }; -static struct ralink_pmx_group mt7621_pinmux_data[] = { +static struct mtmips_pmx_group mt7621_pinmux_data[] = { GRP("uart1", uart1_grp, 1, MT7621_GPIO_MODE_UART1), GRP("i2c", i2c_grp, 1, MT7621_GPIO_MODE_I2C), GRP_G("uart3", uart3_grp, MT7621_GPIO_MODE_UART3_MASK, @@ -92,11 +92,12 @@ static struct ralink_pmx_group mt7621_pinmux_data[] = { static int mt7621_pinctrl_probe(struct platform_device *pdev) { - return ralink_pinctrl_init(pdev, mt7621_pinmux_data); + return mtmips_pinctrl_init(pdev, mt7621_pinmux_data); } static const struct of_device_id mt7621_pinctrl_match[] = { { .compatible = "ralink,mt7621-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, {} }; MODULE_DEVICE_TABLE(of, mt7621_pinctrl_match); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt76x8.c b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c new file mode 100644 index 000000000000..e7d6ad2f62e4 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include "pinctrl-mtmips.h" + +#define MT76X8_GPIO_MODE_MASK 0x3 + +#define MT76X8_GPIO_MODE_P4LED_KN 58 +#define MT76X8_GPIO_MODE_P3LED_KN 56 +#define MT76X8_GPIO_MODE_P2LED_KN 54 +#define MT76X8_GPIO_MODE_P1LED_KN 52 +#define MT76X8_GPIO_MODE_P0LED_KN 50 +#define MT76X8_GPIO_MODE_WLED_KN 48 +#define MT76X8_GPIO_MODE_P4LED_AN 42 +#define MT76X8_GPIO_MODE_P3LED_AN 40 +#define MT76X8_GPIO_MODE_P2LED_AN 38 +#define MT76X8_GPIO_MODE_P1LED_AN 36 +#define MT76X8_GPIO_MODE_P0LED_AN 34 +#define MT76X8_GPIO_MODE_WLED_AN 32 +#define MT76X8_GPIO_MODE_PWM1 30 +#define MT76X8_GPIO_MODE_PWM0 28 +#define MT76X8_GPIO_MODE_UART2 26 +#define MT76X8_GPIO_MODE_UART1 24 +#define MT76X8_GPIO_MODE_I2C 20 +#define MT76X8_GPIO_MODE_REFCLK 18 +#define MT76X8_GPIO_MODE_PERST 16 +#define MT76X8_GPIO_MODE_WDT 14 +#define MT76X8_GPIO_MODE_SPI 12 +#define MT76X8_GPIO_MODE_SDMODE 10 +#define MT76X8_GPIO_MODE_UART0 8 +#define MT76X8_GPIO_MODE_I2S 6 +#define MT76X8_GPIO_MODE_CS1 4 +#define MT76X8_GPIO_MODE_SPIS 2 +#define MT76X8_GPIO_MODE_GPIO 0 + +static struct mtmips_pmx_func pwm1_grp[] = { + FUNC("sdxc d6", 3, 19, 1), + FUNC("utif", 2, 19, 1), + FUNC("gpio", 1, 19, 1), + FUNC("pwm1", 0, 19, 1), +}; + +static struct mtmips_pmx_func pwm0_grp[] = { + FUNC("sdxc d7", 3, 18, 1), + FUNC("utif", 2, 18, 1), + FUNC("gpio", 1, 18, 1), + FUNC("pwm0", 0, 18, 1), +}; + +static struct mtmips_pmx_func uart2_grp[] = { + FUNC("sdxc d5 d4", 3, 20, 2), + FUNC("pwm", 2, 20, 2), + FUNC("gpio", 1, 20, 2), + FUNC("uart2", 0, 20, 2), +}; + +static struct mtmips_pmx_func uart1_grp[] = { + FUNC("sw_r", 3, 45, 2), + FUNC("pwm", 2, 45, 2), + FUNC("gpio", 1, 45, 2), + FUNC("uart1", 0, 45, 2), +}; + +static struct mtmips_pmx_func i2c_grp[] = { + FUNC("-", 3, 4, 2), + FUNC("debug", 2, 4, 2), + FUNC("gpio", 1, 4, 2), + FUNC("i2c", 0, 4, 2), +}; + +static struct mtmips_pmx_func refclk_grp[] = { FUNC("refclk", 0, 37, 1) }; +static struct mtmips_pmx_func perst_grp[] = { FUNC("perst", 0, 36, 1) }; +static struct mtmips_pmx_func wdt_grp[] = { FUNC("wdt", 0, 38, 1) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 7, 4) }; + +static struct mtmips_pmx_func sd_mode_grp[] = { + FUNC("jtag", 3, 22, 8), + FUNC("utif", 2, 22, 8), + FUNC("gpio", 1, 22, 8), + FUNC("sdxc", 0, 22, 8), +}; + +static struct mtmips_pmx_func uart0_grp[] = { + FUNC("-", 3, 12, 2), + FUNC("-", 2, 12, 2), + FUNC("gpio", 1, 12, 2), + FUNC("uart0", 0, 12, 2), +}; + +static struct mtmips_pmx_func i2s_grp[] = { + FUNC("antenna", 3, 0, 4), + FUNC("pcm", 2, 0, 4), + FUNC("gpio", 1, 0, 4), + FUNC("i2s", 0, 0, 4), +}; + +static struct mtmips_pmx_func spi_cs1_grp[] = { + FUNC("-", 3, 6, 1), + FUNC("refclk", 2, 6, 1), + FUNC("gpio", 1, 6, 1), + FUNC("spi cs1", 0, 6, 1), +}; + +static struct mtmips_pmx_func spis_grp[] = { + FUNC("pwm_uart2", 3, 14, 4), + FUNC("utif", 2, 14, 4), + FUNC("gpio", 1, 14, 4), + FUNC("spis", 0, 14, 4), +}; + +static struct mtmips_pmx_func gpio_grp[] = { + FUNC("pcie", 3, 11, 1), + FUNC("refclk", 2, 11, 1), + FUNC("gpio", 1, 11, 1), + FUNC("gpio", 0, 11, 1), +}; + +static struct mtmips_pmx_func p4led_kn_grp[] = { + FUNC("jtag", 3, 30, 1), + FUNC("utif", 2, 30, 1), + FUNC("gpio", 1, 30, 1), + FUNC("p4led_kn", 0, 30, 1), +}; + +static struct mtmips_pmx_func p3led_kn_grp[] = { + FUNC("jtag", 3, 31, 1), + FUNC("utif", 2, 31, 1), + FUNC("gpio", 1, 31, 1), + FUNC("p3led_kn", 0, 31, 1), +}; + +static struct mtmips_pmx_func p2led_kn_grp[] = { + FUNC("jtag", 3, 32, 1), + FUNC("utif", 2, 32, 1), + FUNC("gpio", 1, 32, 1), + FUNC("p2led_kn", 0, 32, 1), +}; + +static struct mtmips_pmx_func p1led_kn_grp[] = { + FUNC("jtag", 3, 33, 1), + FUNC("utif", 2, 33, 1), + FUNC("gpio", 1, 33, 1), + FUNC("p1led_kn", 0, 33, 1), +}; + +static struct mtmips_pmx_func p0led_kn_grp[] = { + FUNC("jtag", 3, 34, 1), + FUNC("rsvd", 2, 34, 1), + FUNC("gpio", 1, 34, 1), + FUNC("p0led_kn", 0, 34, 1), +}; + +static struct mtmips_pmx_func wled_kn_grp[] = { + FUNC("rsvd", 3, 35, 1), + FUNC("rsvd", 2, 35, 1), + FUNC("gpio", 1, 35, 1), + FUNC("wled_kn", 0, 35, 1), +}; + +static struct mtmips_pmx_func p4led_an_grp[] = { + FUNC("jtag", 3, 39, 1), + FUNC("utif", 2, 39, 1), + FUNC("gpio", 1, 39, 1), + FUNC("p4led_an", 0, 39, 1), +}; + +static struct mtmips_pmx_func p3led_an_grp[] = { + FUNC("jtag", 3, 40, 1), + FUNC("utif", 2, 40, 1), + FUNC("gpio", 1, 40, 1), + FUNC("p3led_an", 0, 40, 1), +}; + +static struct mtmips_pmx_func p2led_an_grp[] = { + FUNC("jtag", 3, 41, 1), + FUNC("utif", 2, 41, 1), + FUNC("gpio", 1, 41, 1), + FUNC("p2led_an", 0, 41, 1), +}; + +static struct mtmips_pmx_func p1led_an_grp[] = { + FUNC("jtag", 3, 42, 1), + FUNC("utif", 2, 42, 1), + FUNC("gpio", 1, 42, 1), + FUNC("p1led_an", 0, 42, 1), +}; + +static struct mtmips_pmx_func p0led_an_grp[] = { + FUNC("jtag", 3, 43, 1), + FUNC("rsvd", 2, 43, 1), + FUNC("gpio", 1, 43, 1), + FUNC("p0led_an", 0, 43, 1), +}; + +static struct mtmips_pmx_func wled_an_grp[] = { + FUNC("rsvd", 3, 44, 1), + FUNC("rsvd", 2, 44, 1), + FUNC("gpio", 1, 44, 1), + FUNC("wled_an", 0, 44, 1), +}; + +static struct mtmips_pmx_group mt76x8_pinmux_data[] = { + GRP_G("pwm1", pwm1_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_PWM1), + GRP_G("pwm0", pwm0_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_PWM0), + GRP_G("uart2", uart2_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_UART2), + GRP_G("uart1", uart1_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_UART1), + GRP_G("i2c", i2c_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_I2C), + GRP("refclk", refclk_grp, 1, MT76X8_GPIO_MODE_REFCLK), + GRP("perst", perst_grp, 1, MT76X8_GPIO_MODE_PERST), + GRP("wdt", wdt_grp, 1, MT76X8_GPIO_MODE_WDT), + GRP("spi", spi_grp, 1, MT76X8_GPIO_MODE_SPI), + GRP_G("sdmode", sd_mode_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_SDMODE), + GRP_G("uart0", uart0_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_UART0), + GRP_G("i2s", i2s_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_I2S), + GRP_G("spi cs1", spi_cs1_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_CS1), + GRP_G("spis", spis_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_SPIS), + GRP_G("gpio", gpio_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_GPIO), + GRP_G("wled_an", wled_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_WLED_AN), + GRP_G("p0led_an", p0led_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P0LED_AN), + GRP_G("p1led_an", p1led_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P1LED_AN), + GRP_G("p2led_an", p2led_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P2LED_AN), + GRP_G("p3led_an", p3led_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P3LED_AN), + GRP_G("p4led_an", p4led_an_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P4LED_AN), + GRP_G("wled_kn", wled_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_WLED_KN), + GRP_G("p0led_kn", p0led_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P0LED_KN), + GRP_G("p1led_kn", p1led_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P1LED_KN), + GRP_G("p2led_kn", p2led_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P2LED_KN), + GRP_G("p3led_kn", p3led_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P3LED_KN), + GRP_G("p4led_kn", p4led_kn_grp, MT76X8_GPIO_MODE_MASK, + 1, MT76X8_GPIO_MODE_P4LED_KN), + { 0 } +}; + +static int mt76x8_pinctrl_probe(struct platform_device *pdev) +{ + return mtmips_pinctrl_init(pdev, mt76x8_pinmux_data); +} + +static const struct of_device_id mt76x8_pinctrl_match[] = { + { .compatible = "ralink,mt76x8-pinctrl" }, + { .compatible = "ralink,mt7620-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt76x8_pinctrl_match); + +static struct platform_driver mt76x8_pinctrl_driver = { + .probe = mt76x8_pinctrl_probe, + .driver = { + .name = "mt76x8-pinctrl", + .of_match_table = mt76x8_pinctrl_match, + }, +}; + +static int __init mt76x8_pinctrl_init(void) +{ + return platform_driver_register(&mt76x8_pinctrl_driver); +} +core_initcall_sync(mt76x8_pinctrl_init); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8188.c b/drivers/pinctrl/mediatek/pinctrl-mt8188.c index 6a3d0126288e..c067e043e619 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8188.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8188.c @@ -1670,5 +1670,4 @@ static int __init mt8188_pinctrl_init(void) arch_initcall(mt8188_pinctrl_init); -MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MediaTek MT8188 Pinctrl Driver"); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8192.c b/drivers/pinctrl/mediatek/pinctrl-mt8192.c index 9695f4ec6aba..dee1b3aefd36 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8192.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8192.c @@ -1431,5 +1431,4 @@ static int __init mt8192_pinctrl_init(void) } arch_initcall(mt8192_pinctrl_init); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MediaTek MT8192 Pinctrl Driver"); diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8365.c b/drivers/pinctrl/mediatek/pinctrl-mt8365.c index db4492e9ee67..75a505035e96 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8365.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8365.c @@ -495,6 +495,5 @@ static int __init mtk_pinctrl_init(void) } arch_initcall(mtk_pinctrl_init); -MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MediaTek MT8365 Pinctrl Driver"); MODULE_AUTHOR("Zhiyong Tao "); diff --git a/drivers/pinctrl/ralink/pinctrl-ralink.c b/drivers/pinctrl/mediatek/pinctrl-mtmips.c similarity index 74% rename from drivers/pinctrl/ralink/pinctrl-ralink.c rename to drivers/pinctrl/mediatek/pinctrl-mtmips.c index 770862f45b3f..efd77b6c56a1 100644 --- a/drivers/pinctrl/ralink/pinctrl-ralink.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtmips.c @@ -19,23 +19,23 @@ #include #include -#include "pinctrl-ralink.h" +#include "pinctrl-mtmips.h" #include "../core.h" #include "../pinctrl-utils.h" #define SYSC_REG_GPIO_MODE 0x60 #define SYSC_REG_GPIO_MODE2 0x64 -struct ralink_priv { +struct mtmips_priv { struct device *dev; struct pinctrl_pin_desc *pads; struct pinctrl_desc *desc; - struct ralink_pmx_func **func; + struct mtmips_pmx_func **func; int func_count; - struct ralink_pmx_group *groups; + struct mtmips_pmx_group *groups; const char **group_names; int group_count; @@ -43,27 +43,27 @@ struct ralink_priv { int max_pins; }; -static int ralink_get_group_count(struct pinctrl_dev *pctrldev) +static int mtmips_get_group_count(struct pinctrl_dev *pctrldev) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); return p->group_count; } -static const char *ralink_get_group_name(struct pinctrl_dev *pctrldev, +static const char *mtmips_get_group_name(struct pinctrl_dev *pctrldev, unsigned int group) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); return (group >= p->group_count) ? NULL : p->group_names[group]; } -static int ralink_get_group_pins(struct pinctrl_dev *pctrldev, +static int mtmips_get_group_pins(struct pinctrl_dev *pctrldev, unsigned int group, const unsigned int **pins, unsigned int *num_pins) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); if (group >= p->group_count) return -EINVAL; @@ -74,35 +74,35 @@ static int ralink_get_group_pins(struct pinctrl_dev *pctrldev, return 0; } -static const struct pinctrl_ops ralink_pctrl_ops = { - .get_groups_count = ralink_get_group_count, - .get_group_name = ralink_get_group_name, - .get_group_pins = ralink_get_group_pins, +static const struct pinctrl_ops mtmips_pctrl_ops = { + .get_groups_count = mtmips_get_group_count, + .get_group_name = mtmips_get_group_name, + .get_group_pins = mtmips_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_all, .dt_free_map = pinconf_generic_dt_free_map, }; -static int ralink_pmx_func_count(struct pinctrl_dev *pctrldev) +static int mtmips_pmx_func_count(struct pinctrl_dev *pctrldev) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); return p->func_count; } -static const char *ralink_pmx_func_name(struct pinctrl_dev *pctrldev, +static const char *mtmips_pmx_func_name(struct pinctrl_dev *pctrldev, unsigned int func) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); return p->func[func]->name; } -static int ralink_pmx_group_get_groups(struct pinctrl_dev *pctrldev, +static int mtmips_pmx_group_get_groups(struct pinctrl_dev *pctrldev, unsigned int func, const char * const **groups, unsigned int * const num_groups) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); if (p->func[func]->group_count == 1) *groups = &p->group_names[p->func[func]->groups[0]]; @@ -114,10 +114,10 @@ static int ralink_pmx_group_get_groups(struct pinctrl_dev *pctrldev, return 0; } -static int ralink_pmx_group_enable(struct pinctrl_dev *pctrldev, +static int mtmips_pmx_group_enable(struct pinctrl_dev *pctrldev, unsigned int func, unsigned int group) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); u32 mode = 0; u32 reg = SYSC_REG_GPIO_MODE; int i; @@ -158,11 +158,11 @@ static int ralink_pmx_group_enable(struct pinctrl_dev *pctrldev, return 0; } -static int ralink_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, +static int mtmips_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, struct pinctrl_gpio_range *range, unsigned int pin) { - struct ralink_priv *p = pinctrl_dev_get_drvdata(pctrldev); + struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); if (!p->gpio[pin]) { dev_err(p->dev, "pin %d is not set to gpio mux\n", pin); @@ -172,28 +172,28 @@ static int ralink_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, return 0; } -static const struct pinmux_ops ralink_pmx_group_ops = { - .get_functions_count = ralink_pmx_func_count, - .get_function_name = ralink_pmx_func_name, - .get_function_groups = ralink_pmx_group_get_groups, - .set_mux = ralink_pmx_group_enable, - .gpio_request_enable = ralink_pmx_group_gpio_request_enable, +static const struct pinmux_ops mtmips_pmx_group_ops = { + .get_functions_count = mtmips_pmx_func_count, + .get_function_name = mtmips_pmx_func_name, + .get_function_groups = mtmips_pmx_group_get_groups, + .set_mux = mtmips_pmx_group_enable, + .gpio_request_enable = mtmips_pmx_group_gpio_request_enable, }; -static struct pinctrl_desc ralink_pctrl_desc = { +static struct pinctrl_desc mtmips_pctrl_desc = { .owner = THIS_MODULE, - .name = "ralink-pinctrl", - .pctlops = &ralink_pctrl_ops, - .pmxops = &ralink_pmx_group_ops, + .name = "mtmips-pinctrl", + .pctlops = &mtmips_pctrl_ops, + .pmxops = &mtmips_pmx_group_ops, }; -static struct ralink_pmx_func gpio_func = { +static struct mtmips_pmx_func gpio_func = { .name = "gpio", }; -static int ralink_pinctrl_index(struct ralink_priv *p) +static int mtmips_pinctrl_index(struct mtmips_priv *p) { - struct ralink_pmx_group *mux = p->groups; + struct mtmips_pmx_group *mux = p->groups; int i, j, c = 0; /* count the mux functions */ @@ -248,7 +248,7 @@ static int ralink_pinctrl_index(struct ralink_priv *p) return 0; } -static int ralink_pinctrl_pins(struct ralink_priv *p) +static int mtmips_pinctrl_pins(struct mtmips_priv *p) { int i, j; @@ -313,10 +313,10 @@ static int ralink_pinctrl_pins(struct ralink_priv *p) return 0; } -int ralink_pinctrl_init(struct platform_device *pdev, - struct ralink_pmx_group *data) +int mtmips_pinctrl_init(struct platform_device *pdev, + struct mtmips_pmx_group *data) { - struct ralink_priv *p; + struct mtmips_priv *p; struct pinctrl_dev *dev; int err; @@ -324,23 +324,23 @@ int ralink_pinctrl_init(struct platform_device *pdev, return -ENOTSUPP; /* setup the private data */ - p = devm_kzalloc(&pdev->dev, sizeof(struct ralink_priv), GFP_KERNEL); + p = devm_kzalloc(&pdev->dev, sizeof(struct mtmips_priv), GFP_KERNEL); if (!p) return -ENOMEM; p->dev = &pdev->dev; - p->desc = &ralink_pctrl_desc; + p->desc = &mtmips_pctrl_desc; p->groups = data; platform_set_drvdata(pdev, p); /* init the device */ - err = ralink_pinctrl_index(p); + err = mtmips_pinctrl_index(p); if (err) { dev_err(&pdev->dev, "failed to load index\n"); return err; } - err = ralink_pinctrl_pins(p); + err = mtmips_pinctrl_pins(p); if (err) { dev_err(&pdev->dev, "failed to load pins\n"); return err; diff --git a/drivers/pinctrl/ralink/pinctrl-ralink.h b/drivers/pinctrl/mediatek/pinctrl-mtmips.h similarity index 75% rename from drivers/pinctrl/ralink/pinctrl-ralink.h rename to drivers/pinctrl/mediatek/pinctrl-mtmips.h index e6037be1e153..a7c3dd724431 100644 --- a/drivers/pinctrl/ralink/pinctrl-ralink.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtmips.h @@ -3,8 +3,8 @@ * Copyright (C) 2012 John Crispin */ -#ifndef _PINCTRL_RALINK_H__ -#define _PINCTRL_RALINK_H__ +#ifndef _PINCTRL_MTMIPS_H__ +#define _PINCTRL_MTMIPS_H__ #define FUNC(name, value, pin_first, pin_count) \ { name, value, pin_first, pin_count } @@ -19,9 +19,9 @@ .func = _func, .gpio = _gpio, \ .func_count = ARRAY_SIZE(_func) } -struct ralink_pmx_group; +struct mtmips_pmx_group; -struct ralink_pmx_func { +struct mtmips_pmx_func { const char *name; const char value; @@ -35,7 +35,7 @@ struct ralink_pmx_func { int enabled; }; -struct ralink_pmx_group { +struct mtmips_pmx_group { const char *name; int enabled; @@ -43,11 +43,11 @@ struct ralink_pmx_group { const char mask; const char gpio; - struct ralink_pmx_func *func; + struct mtmips_pmx_func *func; int func_count; }; -int ralink_pinctrl_init(struct platform_device *pdev, - struct ralink_pmx_group *data); +int mtmips_pinctrl_init(struct platform_device *pdev, + struct mtmips_pmx_group *data); #endif diff --git a/drivers/pinctrl/ralink/pinctrl-rt2880.c b/drivers/pinctrl/mediatek/pinctrl-rt2880.c similarity index 69% rename from drivers/pinctrl/ralink/pinctrl-rt2880.c rename to drivers/pinctrl/mediatek/pinctrl-rt2880.c index 3e2f1aaaf095..e0366721a515 100644 --- a/drivers/pinctrl/ralink/pinctrl-rt2880.c +++ b/drivers/pinctrl/mediatek/pinctrl-rt2880.c @@ -4,7 +4,7 @@ #include #include #include -#include "pinctrl-ralink.h" +#include "pinctrl-mtmips.h" #define RT2880_GPIO_MODE_I2C BIT(0) #define RT2880_GPIO_MODE_UART0 BIT(1) @@ -15,15 +15,15 @@ #define RT2880_GPIO_MODE_SDRAM BIT(6) #define RT2880_GPIO_MODE_PCI BIT(7) -static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; -static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; -static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 7, 8) }; -static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; -static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; -static struct ralink_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) }; -static struct ralink_pmx_func pci_grp[] = { FUNC("pci", 0, 40, 32) }; +static struct mtmips_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct mtmips_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 7, 8) }; +static struct mtmips_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; +static struct mtmips_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct mtmips_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) }; +static struct mtmips_pmx_func pci_grp[] = { FUNC("pci", 0, 40, 32) }; -static struct ralink_pmx_group rt2880_pinmux_data_act[] = { +static struct mtmips_pmx_group rt2880_pinmux_data_act[] = { GRP("i2c", i2c_grp, 1, RT2880_GPIO_MODE_I2C), GRP("spi", spi_grp, 1, RT2880_GPIO_MODE_SPI), GRP("uartlite", uartlite_grp, 1, RT2880_GPIO_MODE_UART0), @@ -36,11 +36,12 @@ static struct ralink_pmx_group rt2880_pinmux_data_act[] = { static int rt2880_pinctrl_probe(struct platform_device *pdev) { - return ralink_pinctrl_init(pdev, rt2880_pinmux_data_act); + return mtmips_pinctrl_init(pdev, rt2880_pinmux_data_act); } static const struct of_device_id rt2880_pinctrl_match[] = { { .compatible = "ralink,rt2880-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, {} }; MODULE_DEVICE_TABLE(of, rt2880_pinctrl_match); diff --git a/drivers/pinctrl/ralink/pinctrl-rt305x.c b/drivers/pinctrl/mediatek/pinctrl-rt305x.c similarity index 73% rename from drivers/pinctrl/ralink/pinctrl-rt305x.c rename to drivers/pinctrl/mediatek/pinctrl-rt305x.c index bdaee5ce1ee0..77bd4d1f6122 100644 --- a/drivers/pinctrl/ralink/pinctrl-rt305x.c +++ b/drivers/pinctrl/mediatek/pinctrl-rt305x.c @@ -5,7 +5,7 @@ #include #include #include -#include "pinctrl-ralink.h" +#include "pinctrl-mtmips.h" #define RT305X_GPIO_MODE_UART0_SHIFT 2 #define RT305X_GPIO_MODE_UART0_MASK 0x7 @@ -31,9 +31,9 @@ #define RT3352_GPIO_MODE_LNA 18 #define RT3352_GPIO_MODE_PA 20 -static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; -static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; -static struct ralink_pmx_func uartf_grp[] = { +static struct mtmips_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct mtmips_pmx_func uartf_grp[] = { FUNC("uartf", RT305X_GPIO_MODE_UARTF, 7, 8), FUNC("pcm uartf", RT305X_GPIO_MODE_PCM_UARTF, 7, 8), FUNC("pcm i2s", RT305X_GPIO_MODE_PCM_I2S, 7, 8), @@ -42,28 +42,28 @@ static struct ralink_pmx_func uartf_grp[] = { FUNC("gpio uartf", RT305X_GPIO_MODE_GPIO_UARTF, 7, 4), FUNC("gpio i2s", RT305X_GPIO_MODE_GPIO_I2S, 7, 4), }; -static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; -static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; -static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; -static struct ralink_pmx_func rt5350_led_grp[] = { FUNC("led", 0, 22, 5) }; -static struct ralink_pmx_func rt5350_cs1_grp[] = { +static struct mtmips_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; +static struct mtmips_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; +static struct mtmips_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct mtmips_pmx_func rt5350_led_grp[] = { FUNC("led", 0, 22, 5) }; +static struct mtmips_pmx_func rt5350_cs1_grp[] = { FUNC("spi_cs1", 0, 27, 1), FUNC("wdg_cs1", 1, 27, 1), }; -static struct ralink_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) }; -static struct ralink_pmx_func rt3352_rgmii_grp[] = { +static struct mtmips_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) }; +static struct mtmips_pmx_func rt3352_rgmii_grp[] = { FUNC("rgmii", 0, 24, 12) }; -static struct ralink_pmx_func rgmii_grp[] = { FUNC("rgmii", 0, 40, 12) }; -static struct ralink_pmx_func rt3352_lna_grp[] = { FUNC("lna", 0, 36, 2) }; -static struct ralink_pmx_func rt3352_pa_grp[] = { FUNC("pa", 0, 38, 2) }; -static struct ralink_pmx_func rt3352_led_grp[] = { FUNC("led", 0, 40, 5) }; -static struct ralink_pmx_func rt3352_cs1_grp[] = { +static struct mtmips_pmx_func rgmii_grp[] = { FUNC("rgmii", 0, 40, 12) }; +static struct mtmips_pmx_func rt3352_lna_grp[] = { FUNC("lna", 0, 36, 2) }; +static struct mtmips_pmx_func rt3352_pa_grp[] = { FUNC("pa", 0, 38, 2) }; +static struct mtmips_pmx_func rt3352_led_grp[] = { FUNC("led", 0, 40, 5) }; +static struct mtmips_pmx_func rt3352_cs1_grp[] = { FUNC("spi_cs1", 0, 45, 1), FUNC("wdg_cs1", 1, 45, 1), }; -static struct ralink_pmx_group rt3050_pinmux_data[] = { +static struct mtmips_pmx_group rt3050_pinmux_data[] = { GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C), GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI), GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK, @@ -76,7 +76,7 @@ static struct ralink_pmx_group rt3050_pinmux_data[] = { { 0 } }; -static struct ralink_pmx_group rt3352_pinmux_data[] = { +static struct mtmips_pmx_group rt3352_pinmux_data[] = { GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C), GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI), GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK, @@ -92,7 +92,7 @@ static struct ralink_pmx_group rt3352_pinmux_data[] = { { 0 } }; -static struct ralink_pmx_group rt5350_pinmux_data[] = { +static struct mtmips_pmx_group rt5350_pinmux_data[] = { GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C), GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI), GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK, @@ -107,17 +107,20 @@ static struct ralink_pmx_group rt5350_pinmux_data[] = { static int rt305x_pinctrl_probe(struct platform_device *pdev) { if (soc_is_rt5350()) - return ralink_pinctrl_init(pdev, rt5350_pinmux_data); + return mtmips_pinctrl_init(pdev, rt5350_pinmux_data); else if (soc_is_rt305x() || soc_is_rt3350()) - return ralink_pinctrl_init(pdev, rt3050_pinmux_data); + return mtmips_pinctrl_init(pdev, rt3050_pinmux_data); else if (soc_is_rt3352()) - return ralink_pinctrl_init(pdev, rt3352_pinmux_data); + return mtmips_pinctrl_init(pdev, rt3352_pinmux_data); else return -EINVAL; } static const struct of_device_id rt305x_pinctrl_match[] = { { .compatible = "ralink,rt305x-pinctrl" }, + { .compatible = "ralink,rt3352-pinctrl" }, + { .compatible = "ralink,rt5350-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, {} }; MODULE_DEVICE_TABLE(of, rt305x_pinctrl_match); diff --git a/drivers/pinctrl/ralink/pinctrl-rt3883.c b/drivers/pinctrl/mediatek/pinctrl-rt3883.c similarity index 79% rename from drivers/pinctrl/ralink/pinctrl-rt3883.c rename to drivers/pinctrl/mediatek/pinctrl-rt3883.c index 392208662355..eeaf344c3647 100644 --- a/drivers/pinctrl/ralink/pinctrl-rt3883.c +++ b/drivers/pinctrl/mediatek/pinctrl-rt3883.c @@ -3,7 +3,7 @@ #include #include #include -#include "pinctrl-ralink.h" +#include "pinctrl-mtmips.h" #define RT3883_GPIO_MODE_UART0_SHIFT 2 #define RT3883_GPIO_MODE_UART0_MASK 0x7 @@ -39,9 +39,9 @@ #define RT3883_GPIO_MODE_LNA_G_GPIO 0x3 #define RT3883_GPIO_MODE_LNA_G _RT3883_GPIO_MODE_LNA_G(RT3883_GPIO_MODE_LNA_G_MASK) -static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; -static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; -static struct ralink_pmx_func uartf_grp[] = { +static struct mtmips_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct mtmips_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct mtmips_pmx_func uartf_grp[] = { FUNC("uartf", RT3883_GPIO_MODE_UARTF, 7, 8), FUNC("pcm uartf", RT3883_GPIO_MODE_PCM_UARTF, 7, 8), FUNC("pcm i2s", RT3883_GPIO_MODE_PCM_I2S, 7, 8), @@ -50,21 +50,21 @@ static struct ralink_pmx_func uartf_grp[] = { FUNC("gpio uartf", RT3883_GPIO_MODE_GPIO_UARTF, 7, 4), FUNC("gpio i2s", RT3883_GPIO_MODE_GPIO_I2S, 7, 4), }; -static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; -static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; -static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; -static struct ralink_pmx_func lna_a_grp[] = { FUNC("lna a", 0, 32, 3) }; -static struct ralink_pmx_func lna_g_grp[] = { FUNC("lna g", 0, 35, 3) }; -static struct ralink_pmx_func pci_grp[] = { +static struct mtmips_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; +static struct mtmips_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) }; +static struct mtmips_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct mtmips_pmx_func lna_a_grp[] = { FUNC("lna a", 0, 32, 3) }; +static struct mtmips_pmx_func lna_g_grp[] = { FUNC("lna g", 0, 35, 3) }; +static struct mtmips_pmx_func pci_grp[] = { FUNC("pci-dev", 0, 40, 32), FUNC("pci-host2", 1, 40, 32), FUNC("pci-host1", 2, 40, 32), FUNC("pci-fnc", 3, 40, 32) }; -static struct ralink_pmx_func ge1_grp[] = { FUNC("ge1", 0, 72, 12) }; -static struct ralink_pmx_func ge2_grp[] = { FUNC("ge2", 0, 84, 12) }; +static struct mtmips_pmx_func ge1_grp[] = { FUNC("ge1", 0, 72, 12) }; +static struct mtmips_pmx_func ge2_grp[] = { FUNC("ge2", 0, 84, 12) }; -static struct ralink_pmx_group rt3883_pinmux_data[] = { +static struct mtmips_pmx_group rt3883_pinmux_data[] = { GRP("i2c", i2c_grp, 1, RT3883_GPIO_MODE_I2C), GRP("spi", spi_grp, 1, RT3883_GPIO_MODE_SPI), GRP("uartf", uartf_grp, RT3883_GPIO_MODE_UART0_MASK, @@ -83,11 +83,12 @@ static struct ralink_pmx_group rt3883_pinmux_data[] = { static int rt3883_pinctrl_probe(struct platform_device *pdev) { - return ralink_pinctrl_init(pdev, rt3883_pinmux_data); + return mtmips_pinctrl_init(pdev, rt3883_pinmux_data); } static const struct of_device_id rt3883_pinctrl_match[] = { { .compatible = "ralink,rt3883-pinctrl" }, + { .compatible = "ralink,rt2880-pinmux" }, {} }; MODULE_DEVICE_TABLE(of, rt3883_pinctrl_match); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 261b46841b9f..67c6751a6f06 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -101,7 +102,6 @@ struct armada_37xx_pinctrl { const struct armada_37xx_pin_data *data; struct device *dev; struct gpio_chip gpio_chip; - struct irq_chip irq_chip; raw_spinlock_t irq_lock; struct pinctrl_desc pctl; struct pinctrl_dev *pctl_dev; @@ -548,6 +548,7 @@ static void armada_37xx_irq_mask(struct irq_data *d) val = readl(info->base + reg); writel(val & ~d->mask, info->base + reg); raw_spin_unlock_irqrestore(&info->irq_lock, flags); + gpiochip_disable_irq(chip, irqd_to_hwirq(d)); } static void armada_37xx_irq_unmask(struct irq_data *d) @@ -557,6 +558,7 @@ static void armada_37xx_irq_unmask(struct irq_data *d) u32 val, reg = IRQ_EN; unsigned long flags; + gpiochip_enable_irq(chip, irqd_to_hwirq(d)); armada_37xx_irq_update_reg(®, d); raw_spin_lock_irqsave(&info->irq_lock, flags); val = readl(info->base + reg); @@ -729,11 +731,30 @@ static unsigned int armada_37xx_irq_startup(struct irq_data *d) return 0; } +static void armada_37xx_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + + seq_printf(p, info->data->name); +} + +static const struct irq_chip armada_37xx_irqchip = { + .irq_ack = armada_37xx_irq_ack, + .irq_mask = armada_37xx_irq_mask, + .irq_unmask = armada_37xx_irq_unmask, + .irq_set_wake = armada_37xx_irq_set_wake, + .irq_set_type = armada_37xx_irq_set_type, + .irq_startup = armada_37xx_irq_startup, + .irq_print_chip = armada_37xx_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int armada_37xx_irqchip_register(struct platform_device *pdev, struct armada_37xx_pinctrl *info) { struct gpio_chip *gc = &info->gpio_chip; - struct irq_chip *irqchip = &info->irq_chip; struct gpio_irq_chip *girq = &gc->irq; struct device_node *np = to_of_node(gc->fwnode); struct device *dev = &pdev->dev; @@ -751,14 +772,7 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev, if (IS_ERR(info->base)) return PTR_ERR(info->base); - irqchip->irq_ack = armada_37xx_irq_ack; - irqchip->irq_mask = armada_37xx_irq_mask; - irqchip->irq_unmask = armada_37xx_irq_unmask; - irqchip->irq_set_wake = armada_37xx_irq_set_wake; - irqchip->irq_set_type = armada_37xx_irq_set_type; - irqchip->irq_startup = armada_37xx_irq_startup; - irqchip->name = info->data->name; - girq->chip = irqchip; + gpio_irq_chip_set_chip(girq, &armada_37xx_irqchip); girq->parent_handler = armada_37xx_irq_handler; /* * Many interrupts are connected to the parent interrupt diff --git a/drivers/pinctrl/nuvoton/Kconfig b/drivers/pinctrl/nuvoton/Kconfig index 852b0d0eb08e..8fe61b348181 100644 --- a/drivers/pinctrl/nuvoton/Kconfig +++ b/drivers/pinctrl/nuvoton/Kconfig @@ -11,6 +11,7 @@ config PINCTRL_WPCM450 select GPIOLIB select GPIO_GENERIC select GPIOLIB_IRQCHIP + select MFD_SYSCON help Say Y or M here to enable pin controller and GPIO support for the Nuvoton WPCM450 SoC. This is strongly recommended when diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index ff5bcea172e8..21e61c2a3798 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -82,7 +82,6 @@ struct npcm7xx_gpio { struct gpio_chip gc; int irqbase; int irq; - struct irq_chip irq_chip; u32 pinctrl_id; int (*direction_input)(struct gpio_chip *chip, unsigned int offset); int (*direction_output)(struct gpio_chip *chip, unsigned int offset, @@ -240,9 +239,9 @@ static void npcmgpio_irq_handler(struct irq_desc *desc) static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) { - struct npcm7xx_gpio *bank = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int gpio = BIT(d->hwirq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct npcm7xx_gpio *bank = gpiochip_get_data(gc); + unsigned int gpio = BIT(irqd_to_hwirq(d)); dev_dbg(bank->gc.parent, "setirqtype: %u.%u = %u\n", gpio, d->irq, type); @@ -288,9 +287,9 @@ static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) static void npcmgpio_irq_ack(struct irq_data *d) { - struct npcm7xx_gpio *bank = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int gpio = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct npcm7xx_gpio *bank = gpiochip_get_data(gc); + unsigned int gpio = irqd_to_hwirq(d); dev_dbg(bank->gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); @@ -299,23 +298,25 @@ static void npcmgpio_irq_ack(struct irq_data *d) /* Disable GPIO interrupt */ static void npcmgpio_irq_mask(struct irq_data *d) { - struct npcm7xx_gpio *bank = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int gpio = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct npcm7xx_gpio *bank = gpiochip_get_data(gc); + unsigned int gpio = irqd_to_hwirq(d); /* Clear events */ dev_dbg(bank->gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); + gpiochip_disable_irq(gc, gpio); } /* Enable GPIO interrupt */ static void npcmgpio_irq_unmask(struct irq_data *d) { - struct npcm7xx_gpio *bank = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int gpio = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct npcm7xx_gpio *bank = gpiochip_get_data(gc); + unsigned int gpio = irqd_to_hwirq(d); /* Enable events */ + gpiochip_enable_irq(gc, gpio); dev_dbg(bank->gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); } @@ -323,7 +324,7 @@ static void npcmgpio_irq_unmask(struct irq_data *d) static unsigned int npcmgpio_irq_startup(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - unsigned int gpio = d->hwirq; + unsigned int gpio = irqd_to_hwirq(d); /* active-high, input, clear interrupt, enable interrupt */ dev_dbg(gc->parent, "startup: %u.%u\n", gpio, d->irq); @@ -341,6 +342,8 @@ static const struct irq_chip npcmgpio_irqchip = { .irq_mask = npcmgpio_irq_mask, .irq_set_type = npcmgpio_set_irq_type, .irq_startup = npcmgpio_irq_startup, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; /* pinmux handing in the pinctrl driver*/ @@ -1906,7 +1909,6 @@ static int npcm7xx_gpio_of(struct npcm7xx_pinctrl *pctrl) return -EINVAL; } pctrl->gpio_bank[id].irq = ret; - pctrl->gpio_bank[id].irq_chip = npcmgpio_irqchip; pctrl->gpio_bank[id].irqbase = id * NPCM7XX_GPIO_PER_BANK; pctrl->gpio_bank[id].pinctrl_id = args.args[0]; pctrl->gpio_bank[id].gc.base = args.args[1]; @@ -1941,7 +1943,7 @@ static int npcm7xx_gpio_register(struct npcm7xx_pinctrl *pctrl) struct gpio_irq_chip *girq; girq = &pctrl->gpio_bank[id].gc.irq; - girq->chip = &pctrl->gpio_bank[id].irq_chip; + gpio_irq_chip_set_chip(girq, &npcmgpio_irqchip); girq->parent_handler = npcmgpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(pctrl->dev, 1, @@ -2046,7 +2048,6 @@ static int __init npcm7xx_pinctrl_register(void) } arch_initcall(npcm7xx_pinctrl_register); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("jordan_hargrave@dell.com"); MODULE_AUTHOR("tomer.maimon@nuvoton.com"); MODULE_DESCRIPTION("Nuvoton NPCM7XX Pinctrl and GPIO driver"); diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig new file mode 100644 index 000000000000..abca7ef97003 --- /dev/null +++ b/drivers/pinctrl/nxp/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config PINCTRL_S32CC + bool + depends on ARCH_S32 && OF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select REGMAP_MMIO + +config PINCTRL_S32G2 + depends on ARCH_S32 && OF + bool "NXP S32G2 pinctrl driver" + select PINCTRL_S32CC + help + Say Y here to enable the pinctrl driver for NXP S32G2 family SoCs diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile new file mode 100644 index 000000000000..c1cff4870b02 --- /dev/null +++ b/drivers/pinctrl/nxp/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# NXP pin control +obj-$(CONFIG_PINCTRL_S32CC) += pinctrl-s32cc.o +obj-$(CONFIG_PINCTRL_S32G2) += pinctrl-s32g2.o diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h new file mode 100644 index 000000000000..2f7aecd462e4 --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-s32.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * + * S32 pinmux core definitions + * + * Copyright 2016-2020, 2022 NXP + * Copyright (C) 2022 SUSE LLC + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + */ + +#ifndef __DRIVERS_PINCTRL_S32_H +#define __DRIVERS_PINCTRL_S32_H + +struct platform_device; + +/** + * struct s32_pin_group - describes an S32 pin group + * @data: generic data describes group name, number of pins, and a pin array in + this group. + * @pin_sss: an array of source signal select configs paired with pin array. + */ +struct s32_pin_group { + struct pingroup data; + unsigned int *pin_sss; +}; + +/** + * struct s32_pin_range - pin ID range for each memory region. + * @start: start pin ID + * @end: end pin ID + */ +struct s32_pin_range { + unsigned int start; + unsigned int end; +}; + +struct s32_pinctrl_soc_info { + struct device *dev; + const struct pinctrl_pin_desc *pins; + unsigned int npins; + struct s32_pin_group *groups; + unsigned int ngroups; + struct pinfunction *functions; + unsigned int nfunctions; + unsigned int grp_index; + const struct s32_pin_range *mem_pin_ranges; + unsigned int mem_regions; +}; + +#define S32_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) +#define S32_PIN_RANGE(_start, _end) { .start = _start, .end = _end } + +int s32_pinctrl_probe(struct platform_device *pdev, + struct s32_pinctrl_soc_info *info); +int s32_pinctrl_resume(struct device *dev); +int s32_pinctrl_suspend(struct device *dev); +#endif /* __DRIVERS_PINCTRL_S32_H */ diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c new file mode 100644 index 000000000000..8373468719b6 --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c @@ -0,0 +1,973 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Core driver for the S32 CC (Common Chassis) pin controller + * + * Copyright 2017-2022 NXP + * Copyright (C) 2022 SUSE LLC + * Copyright 2015-2016 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinconf.h" +#include "../pinctrl-utils.h" +#include "pinctrl-s32.h" + +#define S32_PIN_ID_SHIFT 4 +#define S32_PIN_ID_MASK GENMASK(31, S32_PIN_ID_SHIFT) + +#define S32_MSCR_SSS_MASK GENMASK(2, 0) +#define S32_MSCR_PUS BIT(12) +#define S32_MSCR_PUE BIT(13) +#define S32_MSCR_SRE(X) (((X) & GENMASK(3, 0)) << 14) +#define S32_MSCR_IBE BIT(19) +#define S32_MSCR_ODE BIT(20) +#define S32_MSCR_OBE BIT(21) + +static struct regmap_config s32_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static u32 get_pin_no(u32 pinmux) +{ + return (pinmux & S32_PIN_ID_MASK) >> S32_PIN_ID_SHIFT; +} + +static u32 get_pin_func(u32 pinmux) +{ + return pinmux & GENMASK(3, 0); +} + +struct s32_pinctrl_mem_region { + struct regmap *map; + const struct s32_pin_range *pin_range; + char name[8]; +}; + +/* + * Holds pin configuration for GPIO's. + * @pin_id: Pin ID for this GPIO + * @config: Pin settings + * @list: Linked list entry for each gpio pin + */ +struct gpio_pin_config { + unsigned int pin_id; + unsigned int config; + struct list_head list; +}; + +/* + * Pad config save/restore for power suspend/resume. + */ +struct s32_pinctrl_context { + unsigned int *pads; +}; + +/* + * @dev: a pointer back to containing device + * @pctl: a pointer to the pinctrl device structure + * @regions: reserved memory regions with start/end pin + * @info: structure containing information about the pin + * @gpio_configs: Saved configurations for GPIO pins + * @gpiop_configs_lock: lock for the `gpio_configs` list + * @s32_pinctrl_context: Configuration saved over system sleep + */ +struct s32_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + struct s32_pinctrl_mem_region *regions; + struct s32_pinctrl_soc_info *info; + struct list_head gpio_configs; + spinlock_t gpio_configs_lock; +#ifdef CONFIG_PM_SLEEP + struct s32_pinctrl_context saved_context; +#endif +}; + +static struct s32_pinctrl_mem_region * +s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pin_range *pin_range; + unsigned int mem_regions = ipctl->info->mem_regions; + unsigned int i; + + for (i = 0; i < mem_regions; i++) { + pin_range = ipctl->regions[i].pin_range; + if (pin >= pin_range->start && pin <= pin_range->end) + return &ipctl->regions[i]; + } + + return NULL; +} + +static inline int s32_check_pin(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + return s32_get_region(pctldev, pin) ? 0 : -EINVAL; +} + +static inline int s32_regmap_read(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned int *val) +{ + struct s32_pinctrl_mem_region *region; + unsigned int offset; + + region = s32_get_region(pctldev, pin); + if (!region) + return -EINVAL; + + offset = (pin - region->pin_range->start) * + regmap_get_reg_stride(region->map); + + return regmap_read(region->map, offset, val); +} + +static inline int s32_regmap_write(struct pinctrl_dev *pctldev, + unsigned int pin, + unsigned int val) +{ + struct s32_pinctrl_mem_region *region; + unsigned int offset; + + region = s32_get_region(pctldev, pin); + if (!region) + return -EINVAL; + + offset = (pin - region->pin_range->start) * + regmap_get_reg_stride(region->map); + + return regmap_write(region->map, offset, val); + +} + +static inline int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned int mask, unsigned int val) +{ + struct s32_pinctrl_mem_region *region; + unsigned int offset; + + region = s32_get_region(pctldev, pin); + if (!region) + return -EINVAL; + + offset = (pin - region->pin_range->start) * + regmap_get_reg_stride(region->map); + + return regmap_update_bits(region->map, offset, mask, val); +} + +static int s32_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + return info->ngroups; +} + +static const char *s32_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + return info->groups[selector].data.name; +} + +static int s32_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, const unsigned int **pins, + unsigned int *npins) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + *pins = info->groups[selector].data.pins; + *npins = info->groups[selector].data.npins; + + return 0; +} + +static void s32_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int s32_dt_group_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *reserved_maps, + unsigned int *num_maps, + const char *func_name) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = ipctl->dev; + unsigned long *cfgs = NULL; + unsigned int n_cfgs, reserve = 1; + int n_pins, ret; + + n_pins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32)); + if (n_pins < 0) { + dev_warn(dev, "Can't find 'pinmux' property in node %pOFn\n", np); + } else if (!n_pins) { + return -EINVAL; + } + + ret = pinconf_generic_parse_dt_config(np, pctldev, &cfgs, &n_cfgs); + if (ret) { + dev_err(dev, "%pOF: could not parse node property\n", np); + return ret; + } + + if (n_cfgs) + reserve++; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, + reserve); + if (ret < 0) + goto free_cfgs; + + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, + np->name, func_name); + if (ret < 0) + goto free_cfgs; + + if (n_cfgs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, reserved_maps, + num_maps, np->name, cfgs, n_cfgs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + goto free_cfgs; + } + +free_cfgs: + kfree(cfgs); + return ret; +} + +static int s32_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + unsigned int reserved_maps; + struct device_node *np; + int ret = 0; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_available_child_of_node(np_config, np) { + ret = s32_dt_group_node_to_map(pctldev, np, map, + &reserved_maps, num_maps, + np_config->name); + if (ret < 0) + break; + } + + if (ret) + pinctrl_utils_free_map(pctldev, *map, *num_maps); + + return ret; + +} + +static const struct pinctrl_ops s32_pctrl_ops = { + .get_groups_count = s32_get_groups_count, + .get_group_name = s32_get_group_name, + .get_group_pins = s32_get_group_pins, + .pin_dbg_show = s32_pin_dbg_show, + .dt_node_to_map = s32_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int s32_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned int group) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + int i, ret; + struct s32_pin_group *grp; + + /* + * Configure the mux mode for each pin in the group for a specific + * function. + */ + grp = &info->groups[group]; + + dev_dbg(ipctl->dev, "set mux for function %s group %s\n", + info->functions[selector].name, grp->data.name); + + /* Check beforehand so we don't have a partial config. */ + for (i = 0; i < grp->data.npins; i++) { + if (s32_check_pin(pctldev, grp->data.pins[i]) != 0) { + dev_err(info->dev, "invalid pin: %u in group: %u\n", + grp->data.pins[i], group); + return -EINVAL; + } + } + + for (i = 0, ret = 0; i < grp->data.npins && !ret; i++) { + ret = s32_regmap_update(pctldev, grp->data.pins[i], + S32_MSCR_SSS_MASK, grp->pin_sss[i]); + if (ret) { + dev_err(info->dev, "Failed to set pin %u\n", + grp->data.pins[i]); + return ret; + } + } + + return 0; +} + +static int s32_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + return info->nfunctions; +} + +static const char *s32_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + return info->functions[selector].name; +} + +static int s32_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +static int s32_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct gpio_pin_config *gpio_pin; + unsigned int config; + unsigned long flags; + int ret; + + ret = s32_regmap_read(pctldev, offset, &config); + if (ret) + return ret; + + /* Save current configuration */ + gpio_pin = kmalloc(sizeof(*gpio_pin), GFP_KERNEL); + if (!gpio_pin) + return -ENOMEM; + + gpio_pin->pin_id = offset; + gpio_pin->config = config; + + spin_lock_irqsave(&ipctl->gpio_configs_lock, flags); + list_add(&gpio_pin->list, &ipctl->gpio_configs); + spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags); + + /* GPIO pin means SSS = 0 */ + config &= ~S32_MSCR_SSS_MASK; + + return s32_regmap_write(pctldev, offset, config); +} + +static void s32_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct gpio_pin_config *gpio_pin, *tmp; + unsigned long flags; + int ret; + + spin_lock_irqsave(&ipctl->gpio_configs_lock, flags); + + list_for_each_entry_safe(gpio_pin, tmp, &ipctl->gpio_configs, list) { + if (gpio_pin->pin_id == offset) { + ret = s32_regmap_write(pctldev, gpio_pin->pin_id, + gpio_pin->config); + if (ret != 0) + goto unlock; + + list_del(&gpio_pin->list); + kfree(gpio_pin); + break; + } + } + +unlock: + spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags); +} + +static int s32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, + bool input) +{ + unsigned int config; + unsigned int mask = S32_MSCR_IBE | S32_MSCR_OBE; + + if (input) { + /* Disable output buffer and enable input buffer */ + config = S32_MSCR_IBE; + } else { + /* Disable input buffer and enable output buffer */ + config = S32_MSCR_OBE; + } + + return s32_regmap_update(pctldev, offset, mask, config); +} + +static const struct pinmux_ops s32_pmx_ops = { + .get_functions_count = s32_pmx_get_funcs_count, + .get_function_name = s32_pmx_get_func_name, + .get_function_groups = s32_pmx_get_groups, + .set_mux = s32_pmx_set, + .gpio_request_enable = s32_pmx_gpio_request_enable, + .gpio_disable_free = s32_pmx_gpio_disable_free, + .gpio_set_direction = s32_pmx_gpio_set_direction, +}; + +/* Set the reserved elements as -1 */ +static const int support_slew[] = {208, -1, -1, -1, 166, 150, 133, 83}; + +static int s32_get_slew_regval(int arg) +{ + unsigned int i; + + /* Translate a real slew rate (MHz) to a register value */ + for (i = 0; i < ARRAY_SIZE(support_slew); i++) { + if (arg == support_slew[i]) + return i; + } + + return -EINVAL; +} + +static inline void s32_pin_set_pull(enum pin_config_param param, + unsigned int *mask, unsigned int *config) +{ + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + *config &= ~(S32_MSCR_PUS | S32_MSCR_PUE); + break; + case PIN_CONFIG_BIAS_PULL_UP: + *config |= S32_MSCR_PUS | S32_MSCR_PUE; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + *config &= ~S32_MSCR_PUS; + *config |= S32_MSCR_PUE; + break; + default: + return; + } + + *mask |= S32_MSCR_PUS | S32_MSCR_PUE; +} + +static int s32_parse_pincfg(unsigned long pincfg, unsigned int *mask, + unsigned int *config) +{ + enum pin_config_param param; + u32 arg; + int ret; + + param = pinconf_to_config_param(pincfg); + arg = pinconf_to_config_argument(pincfg); + + switch (param) { + /* All pins are persistent over suspend */ + case PIN_CONFIG_PERSIST_STATE: + return 0; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + *config |= S32_MSCR_ODE; + *mask |= S32_MSCR_ODE; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + if (arg) + *config |= S32_MSCR_OBE; + else + *config &= ~S32_MSCR_OBE; + *mask |= S32_MSCR_OBE; + break; + case PIN_CONFIG_INPUT_ENABLE: + if (arg) + *config |= S32_MSCR_IBE; + else + *config &= ~S32_MSCR_IBE; + *mask |= S32_MSCR_IBE; + break; + case PIN_CONFIG_SLEW_RATE: + ret = s32_get_slew_regval(arg); + if (ret < 0) + return ret; + *config |= S32_MSCR_SRE((u32)ret); + *mask |= S32_MSCR_SRE(~0); + break; + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + s32_pin_set_pull(param, mask, config); + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + *config &= ~(S32_MSCR_ODE | S32_MSCR_OBE | S32_MSCR_IBE); + *mask |= S32_MSCR_ODE | S32_MSCR_OBE | S32_MSCR_IBE; + s32_pin_set_pull(param, mask, config); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int s32_pinconf_mscr_update(struct pinctrl_dev *pctldev, + unsigned int pin_id, + unsigned long *configs, + unsigned int num_configs) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + unsigned int config = 0, mask = 0; + int i, ret; + + ret = s32_check_pin(pctldev, pin_id); + if (ret) + return ret; + + dev_dbg(ipctl->dev, "pinconf set pin %s with %u configs\n", + pin_get_name(pctldev, pin_id), num_configs); + + for (i = 0; i < num_configs; i++) { + ret = s32_parse_pincfg(configs[i], &mask, &config); + if (ret) + return ret; + } + + if (!config && !mask) + return 0; + + dev_dbg(ipctl->dev, "update: pin %u cfg 0x%x\n", pin_id, config); + + return s32_regmap_update(pctldev, pin_id, mask, config); +} + +static int s32_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin_id, + unsigned long *config) +{ + return s32_regmap_read(pctldev, pin_id, (unsigned int *)config); +} + +static int s32_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin_id, unsigned long *configs, + unsigned int num_configs) +{ + return s32_pinconf_mscr_update(pctldev, pin_id, configs, + num_configs); +} + +static int s32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned long *configs, unsigned int num_configs) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + struct s32_pin_group *grp; + int i, ret; + + grp = &info->groups[selector]; + for (i = 0; i < grp->data.npins; i++) { + ret = s32_pinconf_mscr_update(pctldev, grp->data.pins[i], + configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static void s32_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin_id) +{ + unsigned int config; + int ret; + + ret = s32_regmap_read(pctldev, pin_id, &config); + if (ret) + return; + + seq_printf(s, "0x%x", config); +} + +static void s32_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int selector) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + struct s32_pin_group *grp; + unsigned int config; + const char *name; + int i, ret; + + seq_puts(s, "\n"); + grp = &info->groups[selector]; + for (i = 0; i < grp->data.npins; i++) { + name = pin_get_name(pctldev, grp->data.pins[i]); + ret = s32_regmap_read(pctldev, grp->data.pins[i], &config); + if (ret) + return; + seq_printf(s, "%s: 0x%x\n", name, config); + } +} + +static const struct pinconf_ops s32_pinconf_ops = { + .pin_config_get = s32_pinconf_get, + .pin_config_set = s32_pinconf_set, + .pin_config_group_set = s32_pconf_group_set, + .pin_config_dbg_show = s32_pinconf_dbg_show, + .pin_config_group_dbg_show = s32_pinconf_group_dbg_show, +}; + +#ifdef CONFIG_PM_SLEEP +static bool s32_pinctrl_should_save(struct s32_pinctrl *ipctl, + unsigned int pin) +{ + const struct pin_desc *pd = pin_desc_get(ipctl->pctl, pin); + + if (!pd) + return false; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). + */ + if (pd->mux_owner || pd->gpio_owner) + return true; + + return false; +} + +int s32_pinctrl_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s32_pinctrl *ipctl = platform_get_drvdata(pdev); + const struct pinctrl_pin_desc *pin; + const struct s32_pinctrl_soc_info *info = ipctl->info; + struct s32_pinctrl_context *saved_context = &ipctl->saved_context; + int i; + int ret; + unsigned int config; + + for (i = 0; i < info->npins; i++) { + pin = &info->pins[i]; + + if (!s32_pinctrl_should_save(ipctl, pin->number)) + continue; + + ret = s32_regmap_read(ipctl->pctl, pin->number, &config); + if (ret) + return -EINVAL; + + saved_context->pads[i] = config; + } + + return 0; +} + +int s32_pinctrl_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s32_pinctrl *ipctl = platform_get_drvdata(pdev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + const struct pinctrl_pin_desc *pin; + struct s32_pinctrl_context *saved_context = &ipctl->saved_context; + int ret, i; + + for (i = 0; i < info->npins; i++) { + pin = &info->pins[i]; + + if (!s32_pinctrl_should_save(ipctl, pin->number)) + continue; + + ret = s32_regmap_write(ipctl->pctl, pin->number, + saved_context->pads[i]); + if (ret) + return ret; + } + + return 0; +} +#endif + +static int s32_pinctrl_parse_groups(struct device_node *np, + struct s32_pin_group *grp, + struct s32_pinctrl_soc_info *info) +{ + const __be32 *p; + struct device *dev; + struct property *prop; + unsigned int *pins, *sss; + int i, npins; + u32 pinmux; + + dev = info->dev; + + dev_dbg(dev, "group: %pOFn\n", np); + + /* Initialise group */ + grp->data.name = np->name; + + npins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32)); + if (npins < 0) { + dev_err(dev, "Failed to read 'pinmux' property in node %s.\n", + grp->data.name); + return -EINVAL; + } + if (!npins) { + dev_err(dev, "The group %s has no pins.\n", grp->data.name); + return -EINVAL; + } + + grp->data.npins = npins; + + pins = devm_kcalloc(info->dev, npins, sizeof(*pins), GFP_KERNEL); + sss = devm_kcalloc(info->dev, npins, sizeof(*sss), GFP_KERNEL); + if (!pins || !sss) + return -ENOMEM; + + i = 0; + of_property_for_each_u32(np, "pinmux", prop, p, pinmux) { + pins[i] = get_pin_no(pinmux); + sss[i] = get_pin_func(pinmux); + + dev_dbg(info->dev, "pin: 0x%x, sss: 0x%x", pins[i], sss[i]); + i++; + } + + grp->data.pins = pins; + grp->pin_sss = sss; + + return 0; +} + +static int s32_pinctrl_parse_functions(struct device_node *np, + struct s32_pinctrl_soc_info *info, + u32 index) +{ + struct device_node *child; + struct pinfunction *func; + struct s32_pin_group *grp; + const char **groups; + u32 i = 0; + int ret = 0; + + dev_dbg(info->dev, "parse function(%u): %pOFn\n", index, np); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups == 0) { + dev_err(info->dev, "no groups defined in %pOF\n", np); + return -EINVAL; + } + + groups = devm_kcalloc(info->dev, func->ngroups, + sizeof(*func->groups), GFP_KERNEL); + if (!groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + groups[i] = child->name; + grp = &info->groups[info->grp_index++]; + ret = s32_pinctrl_parse_groups(child, grp, info); + if (ret) + return ret; + i++; + } + + func->groups = groups; + + return 0; +} + +static int s32_pinctrl_probe_dt(struct platform_device *pdev, + struct s32_pinctrl *ipctl) +{ + struct s32_pinctrl_soc_info *info = ipctl->info; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + struct resource *res; + struct regmap *map; + void __iomem *base; + int mem_regions = info->mem_regions; + int ret; + u32 nfuncs = 0; + u32 i = 0; + + if (!np) + return -ENODEV; + + if (mem_regions == 0) { + dev_err(&pdev->dev, "mem_regions is 0\n"); + return -EINVAL; + } + + ipctl->regions = devm_kcalloc(&pdev->dev, mem_regions, + sizeof(*ipctl->regions), GFP_KERNEL); + if (!ipctl->regions) + return -ENOMEM; + + for (i = 0; i < mem_regions; i++) { + base = devm_platform_get_and_ioremap_resource(pdev, i, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + snprintf(ipctl->regions[i].name, + sizeof(ipctl->regions[i].name), "map%u", i); + + s32_regmap_config.name = ipctl->regions[i].name; + s32_regmap_config.max_register = resource_size(res) - + s32_regmap_config.reg_stride; + + map = devm_regmap_init_mmio(&pdev->dev, base, + &s32_regmap_config); + if (IS_ERR(map)) { + dev_err(&pdev->dev, "Failed to init regmap[%u]\n", i); + return PTR_ERR(map); + } + + ipctl->regions[i].map = map; + ipctl->regions[i].pin_range = &info->mem_pin_ranges[i]; + } + + nfuncs = of_get_child_count(np); + if (nfuncs <= 0) { + dev_err(&pdev->dev, "no functions defined\n"); + return -EINVAL; + } + + info->nfunctions = nfuncs; + info->functions = devm_kcalloc(&pdev->dev, nfuncs, + sizeof(*info->functions), GFP_KERNEL); + if (!info->functions) + return -ENOMEM; + + info->ngroups = 0; + for_each_child_of_node(np, child) + info->ngroups += of_get_child_count(child); + + info->groups = devm_kcalloc(&pdev->dev, info->ngroups, + sizeof(*info->groups), GFP_KERNEL); + if (!info->groups) + return -ENOMEM; + + i = 0; + for_each_child_of_node(np, child) { + ret = s32_pinctrl_parse_functions(child, info, i++); + if (ret) + return ret; + } + + return 0; +} + +int s32_pinctrl_probe(struct platform_device *pdev, + struct s32_pinctrl_soc_info *info) +{ + struct s32_pinctrl *ipctl; + int ret; + struct pinctrl_desc *s32_pinctrl_desc; +#ifdef CONFIG_PM_SLEEP + struct s32_pinctrl_context *saved_context; +#endif + + if (!info || !info->pins || !info->npins) { + dev_err(&pdev->dev, "wrong pinctrl info\n"); + return -EINVAL; + } + + info->dev = &pdev->dev; + + /* Create state holders etc for this driver */ + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); + if (!ipctl) + return -ENOMEM; + + ipctl->info = info; + ipctl->dev = info->dev; + platform_set_drvdata(pdev, ipctl); + + INIT_LIST_HEAD(&ipctl->gpio_configs); + spin_lock_init(&ipctl->gpio_configs_lock); + + s32_pinctrl_desc = + devm_kmalloc(&pdev->dev, sizeof(*s32_pinctrl_desc), GFP_KERNEL); + if (!s32_pinctrl_desc) + return -ENOMEM; + + s32_pinctrl_desc->name = dev_name(&pdev->dev); + s32_pinctrl_desc->pins = info->pins; + s32_pinctrl_desc->npins = info->npins; + s32_pinctrl_desc->pctlops = &s32_pctrl_ops; + s32_pinctrl_desc->pmxops = &s32_pmx_ops; + s32_pinctrl_desc->confops = &s32_pinconf_ops; + s32_pinctrl_desc->owner = THIS_MODULE; + + ret = s32_pinctrl_probe_dt(pdev, ipctl); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + return ret; + } + + ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc, + ipctl); + if (IS_ERR(ipctl->pctl)) + return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl), + "could not register s32 pinctrl driver\n"); + +#ifdef CONFIG_PM_SLEEP + saved_context = &ipctl->saved_context; + saved_context->pads = + devm_kcalloc(&pdev->dev, info->npins, + sizeof(*saved_context->pads), + GFP_KERNEL); + if (!saved_context->pads) + return -ENOMEM; +#endif + + dev_info(&pdev->dev, "initialized s32 pinctrl driver\n"); + + return 0; +} diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c new file mode 100644 index 000000000000..d9f3ff6794ea --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c @@ -0,0 +1,770 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * NXP S32G pinctrl driver + * + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018, 2020-2022 NXP + * Copyright (C) 2022 SUSE LLC + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-s32.h" + +enum s32_pins { + S32G_MSCR_PA_00 = 0, + S32G_MSCR_PA_01 = 1, + S32G_MSCR_PA_02 = 2, + S32G_MSCR_PA_03 = 3, + S32G_MSCR_PA_04 = 4, + S32G_MSCR_PA_05 = 5, + S32G_MSCR_PA_06 = 6, + S32G_MSCR_PA_07 = 7, + S32G_MSCR_PA_08 = 8, + S32G_MSCR_PA_09 = 9, + S32G_MSCR_PA_10 = 10, + S32G_MSCR_PA_11 = 11, + S32G_MSCR_PA_12 = 12, + S32G_MSCR_PA_13 = 13, + S32G_MSCR_PA_14 = 14, + S32G_MSCR_PA_15 = 15, + S32G_MSCR_PB_00 = 16, + S32G_MSCR_PB_01 = 17, + S32G_MSCR_PB_02 = 18, + S32G_MSCR_PB_03 = 19, + S32G_MSCR_PB_04 = 20, + S32G_MSCR_PB_05 = 21, + S32G_MSCR_PB_06 = 22, + S32G_MSCR_PB_07 = 23, + S32G_MSCR_PB_08 = 24, + S32G_MSCR_PB_09 = 25, + S32G_MSCR_PB_10 = 26, + S32G_MSCR_PB_11 = 27, + S32G_MSCR_PB_12 = 28, + S32G_MSCR_PB_13 = 29, + S32G_MSCR_PB_14 = 30, + S32G_MSCR_PB_15 = 31, + S32G_MSCR_PC_00 = 32, + S32G_MSCR_PC_01 = 33, + S32G_MSCR_PC_02 = 34, + S32G_MSCR_PC_03 = 35, + S32G_MSCR_PC_04 = 36, + S32G_MSCR_PC_05 = 37, + S32G_MSCR_PC_06 = 38, + S32G_MSCR_PC_07 = 39, + S32G_MSCR_PC_08 = 40, + S32G_MSCR_PC_09 = 41, + S32G_MSCR_PC_10 = 42, + S32G_MSCR_PC_11 = 43, + S32G_MSCR_PC_12 = 44, + S32G_MSCR_PC_13 = 45, + S32G_MSCR_PC_14 = 46, + S32G_MSCR_PC_15 = 47, + S32G_MSCR_PD_00 = 48, + S32G_MSCR_PD_01 = 49, + S32G_MSCR_PD_02 = 50, + S32G_MSCR_PD_03 = 51, + S32G_MSCR_PD_04 = 52, + S32G_MSCR_PD_05 = 53, + S32G_MSCR_PD_06 = 54, + S32G_MSCR_PD_07 = 55, + S32G_MSCR_PD_08 = 56, + S32G_MSCR_PD_09 = 57, + S32G_MSCR_PD_10 = 58, + S32G_MSCR_PD_11 = 59, + S32G_MSCR_PD_12 = 60, + S32G_MSCR_PD_13 = 61, + S32G_MSCR_PD_14 = 62, + S32G_MSCR_PD_15 = 63, + S32G_MSCR_PE_00 = 64, + S32G_MSCR_PE_01 = 65, + S32G_MSCR_PE_02 = 66, + S32G_MSCR_PE_03 = 67, + S32G_MSCR_PE_04 = 68, + S32G_MSCR_PE_05 = 69, + S32G_MSCR_PE_06 = 70, + S32G_MSCR_PE_07 = 71, + S32G_MSCR_PE_08 = 72, + S32G_MSCR_PE_09 = 73, + S32G_MSCR_PE_10 = 74, + S32G_MSCR_PE_11 = 75, + S32G_MSCR_PE_12 = 76, + S32G_MSCR_PE_13 = 77, + S32G_MSCR_PE_14 = 78, + S32G_MSCR_PE_15 = 79, + S32G_MSCR_PF_00 = 80, + S32G_MSCR_PF_01 = 81, + S32G_MSCR_PF_02 = 82, + S32G_MSCR_PF_03 = 83, + S32G_MSCR_PF_04 = 84, + S32G_MSCR_PF_05 = 85, + S32G_MSCR_PF_06 = 86, + S32G_MSCR_PF_07 = 87, + S32G_MSCR_PF_08 = 88, + S32G_MSCR_PF_09 = 89, + S32G_MSCR_PF_10 = 90, + S32G_MSCR_PF_11 = 91, + S32G_MSCR_PF_12 = 92, + S32G_MSCR_PF_13 = 93, + S32G_MSCR_PF_14 = 94, + S32G_MSCR_PF_15 = 95, + S32G_MSCR_PG_00 = 96, + S32G_MSCR_PG_01 = 97, + S32G_MSCR_PG_02 = 98, + S32G_MSCR_PG_03 = 99, + S32G_MSCR_PG_04 = 100, + S32G_MSCR_PG_05 = 101, + S32G_MSCR_PH_00 = 112, + S32G_MSCR_PH_01 = 113, + S32G_MSCR_PH_02 = 114, + S32G_MSCR_PH_03 = 115, + S32G_MSCR_PH_04 = 116, + S32G_MSCR_PH_05 = 117, + S32G_MSCR_PH_06 = 118, + S32G_MSCR_PH_07 = 119, + S32G_MSCR_PH_08 = 120, + S32G_MSCR_PH_09 = 121, + S32G_MSCR_PH_10 = 122, + S32G_MSCR_PJ_00 = 144, + S32G_MSCR_PJ_01 = 145, + S32G_MSCR_PJ_02 = 146, + S32G_MSCR_PJ_03 = 147, + S32G_MSCR_PJ_04 = 148, + S32G_MSCR_PJ_05 = 149, + S32G_MSCR_PJ_06 = 150, + S32G_MSCR_PJ_07 = 151, + S32G_MSCR_PJ_08 = 152, + S32G_MSCR_PJ_09 = 153, + S32G_MSCR_PJ_10 = 154, + S32G_MSCR_PJ_11 = 155, + S32G_MSCR_PJ_12 = 156, + S32G_MSCR_PJ_13 = 157, + S32G_MSCR_PJ_14 = 158, + S32G_MSCR_PJ_15 = 159, + S32G_MSCR_PK_00 = 160, + S32G_MSCR_PK_01 = 161, + S32G_MSCR_PK_02 = 162, + S32G_MSCR_PK_03 = 163, + S32G_MSCR_PK_04 = 164, + S32G_MSCR_PK_05 = 165, + S32G_MSCR_PK_06 = 166, + S32G_MSCR_PK_07 = 167, + S32G_MSCR_PK_08 = 168, + S32G_MSCR_PK_09 = 169, + S32G_MSCR_PK_10 = 170, + S32G_MSCR_PK_11 = 171, + S32G_MSCR_PK_12 = 172, + S32G_MSCR_PK_13 = 173, + S32G_MSCR_PK_14 = 174, + S32G_MSCR_PK_15 = 175, + S32G_MSCR_PL_00 = 176, + S32G_MSCR_PL_01 = 177, + S32G_MSCR_PL_02 = 178, + S32G_MSCR_PL_03 = 179, + S32G_MSCR_PL_04 = 180, + S32G_MSCR_PL_05 = 181, + S32G_MSCR_PL_06 = 182, + S32G_MSCR_PL_07 = 183, + S32G_MSCR_PL_08 = 184, + S32G_MSCR_PL_09 = 185, + S32G_MSCR_PL_10 = 186, + S32G_MSCR_PL_11 = 187, + S32G_MSCR_PL_12 = 188, + S32G_MSCR_PL_13 = 189, + S32G_MSCR_PL_14 = 190, + + S32G_IMCR_QSPI_A_DATA0 = 540, + S32G_IMCR_QSPI_A_DATA1 = 541, + S32G_IMCR_QSPI_A_DATA2 = 542, + S32G_IMCR_QSPI_A_DATA3 = 543, + S32G_IMCR_QSPI_A_DATA4 = 544, + S32G_IMCR_QSPI_A_DATA5 = 545, + S32G_IMCR_QSPI_A_DATA6 = 546, + S32G_IMCR_QSPI_A_DATA7 = 547, + S32G_IMCR_QSPI_DQS_A = 548, + S32G_IMCR_QSPI_B_DATA0 = 552, + S32G_IMCR_QSPI_B_DATA1 = 554, + S32G_IMCR_QSPI_B_DATA2 = 551, + S32G_IMCR_QSPI_B_DATA3 = 553, + S32G_IMCR_QSPI_B_DATA4 = 557, + S32G_IMCR_QSPI_B_DATA5 = 550, + S32G_IMCR_QSPI_B_DATA6 = 556, + S32G_IMCR_QSPI_B_DATA7 = 555, + S32G_IMCR_QSPI_DQS_B = 558, + S32G_IMCR_BOOT_BOOTMOD0 = 560, + S32G_IMCR_BOOT_BOOTMOD1 = 561, + S32G_IMCR_I2C0_SCL = 566, + S32G_IMCR_I2C0_SDA = 565, + S32G_IMCR_LIN0_RX = 512, + S32G_IMCR_USDHC_CMD = 515, + S32G_IMCR_USDHC_DAT0 = 516, + S32G_IMCR_USDHC_DAT1 = 517, + S32G_IMCR_USDHC_DAT2 = 520, + S32G_IMCR_USDHC_DAT3 = 521, + S32G_IMCR_USDHC_DAT4 = 522, + S32G_IMCR_USDHC_DAT5 = 523, + S32G_IMCR_USDHC_DAT6 = 519, + S32G_IMCR_USDHC_DAT7 = 518, + S32G_IMCR_USDHC_DQS = 524, + S32G_IMCR_CAN0_RXD = 513, + S32G_IMCR_CAN1_RXD = 631, + S32G_IMCR_CAN2_RXD = 632, + S32G_IMCR_CAN3_RXD = 633, + /* GMAC0 */ + S32G_IMCR_Ethernet_MDIO = 527, + S32G_IMCR_Ethernet_CRS = 526, + S32G_IMCR_Ethernet_COL = 525, + S32G_IMCR_Ethernet_RX_D0 = 531, + S32G_IMCR_Ethernet_RX_D1 = 532, + S32G_IMCR_Ethernet_RX_D2 = 533, + S32G_IMCR_Ethernet_RX_D3 = 534, + S32G_IMCR_Ethernet_RX_ER = 528, + S32G_IMCR_Ethernet_RX_CLK = 529, + S32G_IMCR_Ethernet_RX_DV = 530, + S32G_IMCR_Ethernet_TX_CLK = 538, + S32G_IMCR_Ethernet_REF_CLK = 535, + /* PFE EMAC 0 MII */ + /* PFE EMAC 1 MII */ + S32G_IMCR_PFE_EMAC_1_MDIO = 857, + S32G_IMCR_PFE_EMAC_1_CRS = 856, + S32G_IMCR_PFE_EMAC_1_COL = 855, + S32G_IMCR_PFE_EMAC_1_RX_D0 = 861, + S32G_IMCR_PFE_EMAC_1_RX_D1 = 862, + S32G_IMCR_PFE_EMAC_1_RX_D2 = 863, + S32G_IMCR_PFE_EMAC_1_RX_D3 = 864, + S32G_IMCR_PFE_EMAC_1_RX_ER = 860, + S32G_IMCR_PFE_EMAC_1_RX_CLK = 859, + S32G_IMCR_PFE_EMAC_1_RX_DV = 865, + S32G_IMCR_PFE_EMAC_1_TX_CLK = 866, + S32G_IMCR_PFE_EMAC_1_REF_CLK = 858, + /* PFE EMAC 2 MII */ + S32G_IMCR_PFE_EMAC_2_MDIO = 877, + S32G_IMCR_PFE_EMAC_2_CRS = 876, + S32G_IMCR_PFE_EMAC_2_COL = 875, + S32G_IMCR_PFE_EMAC_2_RX_D0 = 881, + S32G_IMCR_PFE_EMAC_2_RX_D1 = 882, + S32G_IMCR_PFE_EMAC_2_RX_D2 = 883, + S32G_IMCR_PFE_EMAC_2_RX_D3 = 884, + S32G_IMCR_PFE_EMAC_2_RX_ER = 880, + S32G_IMCR_PFE_EMAC_2_RX_CLK = 879, + S32G_IMCR_PFE_EMAC_2_RX_DV = 885, + S32G_IMCR_PFE_EMAC_2_TX_CLK = 886, + S32G_IMCR_PFE_EMAC_2_REF_CLK = 878, + + S32G_IMCR_FlexRay0_A_RX = 785, + S32G_IMCR_FlexRay0_B_RX = 786, + S32G_IMCR_FlexTimer0_CH0 = 655, + S32G_IMCR_FlexTimer1_CH0 = 665, + S32G_IMCR_FlexTimer0_CH1 = 656, + S32G_IMCR_FlexTimer1_CH1 = 666, + S32G_IMCR_FlexTimer0_CH2 = 657, + S32G_IMCR_FlexTimer1_CH2 = 667, + S32G_IMCR_FlexTimer0_CH3 = 658, + S32G_IMCR_FlexTimer1_CH3 = 668, + S32G_IMCR_FlexTimer0_CH4 = 659, + S32G_IMCR_FlexTimer1_CH4 = 669, + S32G_IMCR_FlexTimer0_CH5 = 660, + S32G_IMCR_FlexTimer1_CH5 = 670, + S32G_IMCR_FlexTimer0_EXTCLK = 661, + S32G_IMCR_FlexTimer1_EXTCLK = 671, + S32G_IMCR_I2C1_SCL = 717, + S32G_IMCR_I2C1_SDA = 718, + S32G_IMCR_I2C2_SCL = 719, + S32G_IMCR_I2C2_SDA = 720, + S32G_IMCR_I2C3_SCL = 721, + S32G_IMCR_I2C3_SDA = 722, + S32G_IMCR_I2C4_SCL = 723, + S32G_IMCR_I2C4_SDA = 724, + S32G_IMCR_LIN1_RX = 736, + S32G_IMCR_LIN2_RX = 737, + S32G_IMCR_DSPI0_PCS0 = 980, + S32G_IMCR_DSPI0_SCK = 981, + S32G_IMCR_DSPI0_SIN = 982, + S32G_IMCR_DSPI1_PCS0 = 985, + S32G_IMCR_DSPI1_SCK = 986, + S32G_IMCR_DSPI1_SIN = 987, + S32G_IMCR_DSPI2_PCS0 = 990, + S32G_IMCR_DSPI2_SCK = 991, + S32G_IMCR_DSPI2_SIN = 992, + S32G_IMCR_DSPI3_PCS0 = 995, + S32G_IMCR_DSPI3_SCK = 996, + S32G_IMCR_DSPI3_SIN = 997, + S32G_IMCR_DSPI4_PCS0 = 1000, + S32G_IMCR_DSPI4_SCK = 1001, + S32G_IMCR_DSPI4_SIN = 1002, + S32G_IMCR_DSPI5_PCS0 = 1005, + S32G_IMCR_DSPI5_SCK = 1006, + S32G_IMCR_DSPI5_SIN = 1007, + S32G_IMCR_LLCE_CAN0_RXD = 745, + S32G_IMCR_LLCE_CAN1_RXD = 746, + S32G_IMCR_LLCE_CAN2_RXD = 747, + S32G_IMCR_LLCE_CAN3_RXD = 748, + S32G_IMCR_LLCE_CAN4_RXD = 749, + S32G_IMCR_LLCE_CAN5_RXD = 750, + S32G_IMCR_LLCE_CAN6_RXD = 751, + S32G_IMCR_LLCE_CAN7_RXD = 752, + S32G_IMCR_LLCE_CAN8_RXD = 753, + S32G_IMCR_LLCE_CAN9_RXD = 754, + S32G_IMCR_LLCE_CAN10_RXD = 755, + S32G_IMCR_LLCE_CAN11_RXD = 756, + S32G_IMCR_LLCE_CAN12_RXD = 757, + S32G_IMCR_LLCE_CAN13_RXD = 758, + S32G_IMCR_LLCE_CAN14_RXD = 759, + S32G_IMCR_LLCE_CAN15_RXD = 760, + S32G_IMCR_USB_CLK = 895, + S32G_IMCR_USB_DATA0 = 896, + S32G_IMCR_USB_DATA1 = 897, + S32G_IMCR_USB_DATA2 = 898, + S32G_IMCR_USB_DATA3 = 899, + S32G_IMCR_USB_DATA4 = 900, + S32G_IMCR_USB_DATA5 = 901, + S32G_IMCR_USB_DATA6 = 902, + S32G_IMCR_USB_DATA7 = 903, + S32G_IMCR_USB_DIR = 904, + S32G_IMCR_USB_NXT = 905, + + S32G_IMCR_SIUL_EIRQ0 = 910, + S32G_IMCR_SIUL_EIRQ1 = 911, + S32G_IMCR_SIUL_EIRQ2 = 912, + S32G_IMCR_SIUL_EIRQ3 = 913, + S32G_IMCR_SIUL_EIRQ4 = 914, + S32G_IMCR_SIUL_EIRQ5 = 915, + S32G_IMCR_SIUL_EIRQ6 = 916, + S32G_IMCR_SIUL_EIRQ7 = 917, + S32G_IMCR_SIUL_EIRQ8 = 918, + S32G_IMCR_SIUL_EIRQ9 = 919, + S32G_IMCR_SIUL_EIRQ10 = 920, + S32G_IMCR_SIUL_EIRQ11 = 921, + S32G_IMCR_SIUL_EIRQ12 = 922, + S32G_IMCR_SIUL_EIRQ13 = 923, + S32G_IMCR_SIUL_EIRQ14 = 924, + S32G_IMCR_SIUL_EIRQ15 = 925, + S32G_IMCR_SIUL_EIRQ16 = 926, + S32G_IMCR_SIUL_EIRQ17 = 927, + S32G_IMCR_SIUL_EIRQ18 = 928, + S32G_IMCR_SIUL_EIRQ19 = 929, + S32G_IMCR_SIUL_EIRQ20 = 930, + S32G_IMCR_SIUL_EIRQ21 = 931, + S32G_IMCR_SIUL_EIRQ22 = 932, + S32G_IMCR_SIUL_EIRQ23 = 933, + S32G_IMCR_SIUL_EIRQ24 = 934, + S32G_IMCR_SIUL_EIRQ25 = 935, + S32G_IMCR_SIUL_EIRQ26 = 936, + S32G_IMCR_SIUL_EIRQ27 = 937, + S32G_IMCR_SIUL_EIRQ28 = 938, + S32G_IMCR_SIUL_EIRQ29 = 939, + S32G_IMCR_SIUL_EIRQ30 = 940, + S32G_IMCR_SIUL_EIRQ31 = 941, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = { + + /* SIUL2_0 pins. */ + + S32_PINCTRL_PIN(S32G_MSCR_PA_00), + S32_PINCTRL_PIN(S32G_MSCR_PA_01), + S32_PINCTRL_PIN(S32G_MSCR_PA_02), + S32_PINCTRL_PIN(S32G_MSCR_PA_03), + S32_PINCTRL_PIN(S32G_MSCR_PA_04), + S32_PINCTRL_PIN(S32G_MSCR_PA_05), + S32_PINCTRL_PIN(S32G_MSCR_PA_06), + S32_PINCTRL_PIN(S32G_MSCR_PA_07), + S32_PINCTRL_PIN(S32G_MSCR_PA_08), + S32_PINCTRL_PIN(S32G_MSCR_PA_09), + S32_PINCTRL_PIN(S32G_MSCR_PA_10), + S32_PINCTRL_PIN(S32G_MSCR_PA_11), + S32_PINCTRL_PIN(S32G_MSCR_PA_12), + S32_PINCTRL_PIN(S32G_MSCR_PA_13), + S32_PINCTRL_PIN(S32G_MSCR_PA_14), + S32_PINCTRL_PIN(S32G_MSCR_PA_15), + S32_PINCTRL_PIN(S32G_MSCR_PB_00), + S32_PINCTRL_PIN(S32G_MSCR_PB_01), + S32_PINCTRL_PIN(S32G_MSCR_PB_02), + S32_PINCTRL_PIN(S32G_MSCR_PB_03), + S32_PINCTRL_PIN(S32G_MSCR_PB_04), + S32_PINCTRL_PIN(S32G_MSCR_PB_05), + S32_PINCTRL_PIN(S32G_MSCR_PB_06), + S32_PINCTRL_PIN(S32G_MSCR_PB_07), + S32_PINCTRL_PIN(S32G_MSCR_PB_08), + S32_PINCTRL_PIN(S32G_MSCR_PB_09), + S32_PINCTRL_PIN(S32G_MSCR_PB_10), + S32_PINCTRL_PIN(S32G_MSCR_PB_11), + S32_PINCTRL_PIN(S32G_MSCR_PB_12), + S32_PINCTRL_PIN(S32G_MSCR_PB_13), + S32_PINCTRL_PIN(S32G_MSCR_PB_14), + S32_PINCTRL_PIN(S32G_MSCR_PB_15), + S32_PINCTRL_PIN(S32G_MSCR_PC_00), + S32_PINCTRL_PIN(S32G_MSCR_PC_01), + S32_PINCTRL_PIN(S32G_MSCR_PC_02), + S32_PINCTRL_PIN(S32G_MSCR_PC_03), + S32_PINCTRL_PIN(S32G_MSCR_PC_04), + S32_PINCTRL_PIN(S32G_MSCR_PC_05), + S32_PINCTRL_PIN(S32G_MSCR_PC_06), + S32_PINCTRL_PIN(S32G_MSCR_PC_07), + S32_PINCTRL_PIN(S32G_MSCR_PC_08), + S32_PINCTRL_PIN(S32G_MSCR_PC_09), + S32_PINCTRL_PIN(S32G_MSCR_PC_10), + S32_PINCTRL_PIN(S32G_MSCR_PC_11), + S32_PINCTRL_PIN(S32G_MSCR_PC_12), + S32_PINCTRL_PIN(S32G_MSCR_PC_13), + S32_PINCTRL_PIN(S32G_MSCR_PC_14), + S32_PINCTRL_PIN(S32G_MSCR_PC_15), + S32_PINCTRL_PIN(S32G_MSCR_PD_00), + S32_PINCTRL_PIN(S32G_MSCR_PD_01), + S32_PINCTRL_PIN(S32G_MSCR_PD_02), + S32_PINCTRL_PIN(S32G_MSCR_PD_03), + S32_PINCTRL_PIN(S32G_MSCR_PD_04), + S32_PINCTRL_PIN(S32G_MSCR_PD_05), + S32_PINCTRL_PIN(S32G_MSCR_PD_06), + S32_PINCTRL_PIN(S32G_MSCR_PD_07), + S32_PINCTRL_PIN(S32G_MSCR_PD_08), + S32_PINCTRL_PIN(S32G_MSCR_PD_09), + S32_PINCTRL_PIN(S32G_MSCR_PD_10), + S32_PINCTRL_PIN(S32G_MSCR_PD_11), + S32_PINCTRL_PIN(S32G_MSCR_PD_12), + S32_PINCTRL_PIN(S32G_MSCR_PD_13), + S32_PINCTRL_PIN(S32G_MSCR_PD_14), + S32_PINCTRL_PIN(S32G_MSCR_PD_15), + S32_PINCTRL_PIN(S32G_MSCR_PE_00), + S32_PINCTRL_PIN(S32G_MSCR_PE_01), + S32_PINCTRL_PIN(S32G_MSCR_PE_02), + S32_PINCTRL_PIN(S32G_MSCR_PE_03), + S32_PINCTRL_PIN(S32G_MSCR_PE_04), + S32_PINCTRL_PIN(S32G_MSCR_PE_05), + S32_PINCTRL_PIN(S32G_MSCR_PE_06), + S32_PINCTRL_PIN(S32G_MSCR_PE_07), + S32_PINCTRL_PIN(S32G_MSCR_PE_08), + S32_PINCTRL_PIN(S32G_MSCR_PE_09), + S32_PINCTRL_PIN(S32G_MSCR_PE_10), + S32_PINCTRL_PIN(S32G_MSCR_PE_11), + S32_PINCTRL_PIN(S32G_MSCR_PE_12), + S32_PINCTRL_PIN(S32G_MSCR_PE_13), + S32_PINCTRL_PIN(S32G_MSCR_PE_14), + S32_PINCTRL_PIN(S32G_MSCR_PE_15), + S32_PINCTRL_PIN(S32G_MSCR_PF_00), + S32_PINCTRL_PIN(S32G_MSCR_PF_01), + S32_PINCTRL_PIN(S32G_MSCR_PF_02), + S32_PINCTRL_PIN(S32G_MSCR_PF_03), + S32_PINCTRL_PIN(S32G_MSCR_PF_04), + S32_PINCTRL_PIN(S32G_MSCR_PF_05), + S32_PINCTRL_PIN(S32G_MSCR_PF_06), + S32_PINCTRL_PIN(S32G_MSCR_PF_07), + S32_PINCTRL_PIN(S32G_MSCR_PF_08), + S32_PINCTRL_PIN(S32G_MSCR_PF_09), + S32_PINCTRL_PIN(S32G_MSCR_PF_10), + S32_PINCTRL_PIN(S32G_MSCR_PF_11), + S32_PINCTRL_PIN(S32G_MSCR_PF_12), + S32_PINCTRL_PIN(S32G_MSCR_PF_13), + S32_PINCTRL_PIN(S32G_MSCR_PF_14), + S32_PINCTRL_PIN(S32G_MSCR_PF_15), + S32_PINCTRL_PIN(S32G_MSCR_PG_00), + S32_PINCTRL_PIN(S32G_MSCR_PG_01), + S32_PINCTRL_PIN(S32G_MSCR_PG_02), + S32_PINCTRL_PIN(S32G_MSCR_PG_03), + S32_PINCTRL_PIN(S32G_MSCR_PG_04), + S32_PINCTRL_PIN(S32G_MSCR_PG_05), + + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA0), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA1), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA2), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA3), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA4), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA5), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA6), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_A_DATA7), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_DQS_A), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA0), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA1), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA2), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA3), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA4), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA5), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA6), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_B_DATA7), + S32_PINCTRL_PIN(S32G_IMCR_QSPI_DQS_B), + S32_PINCTRL_PIN(S32G_IMCR_I2C0_SCL), + S32_PINCTRL_PIN(S32G_IMCR_I2C0_SDA), + S32_PINCTRL_PIN(S32G_IMCR_LIN0_RX), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_CMD), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT0), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT1), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT2), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT3), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT4), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT5), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT6), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT7), + S32_PINCTRL_PIN(S32G_IMCR_USDHC_DQS), + S32_PINCTRL_PIN(S32G_IMCR_CAN0_RXD), + /* GMAC0 */ + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_MDIO), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_CRS), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_COL), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_D0), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_D1), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_D2), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_D3), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_ER), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_RX_DV), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_TX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_Ethernet_REF_CLK), + + /* SIUL2_1 pins. */ + + S32_PINCTRL_PIN(S32G_MSCR_PH_00), + S32_PINCTRL_PIN(S32G_MSCR_PH_01), + S32_PINCTRL_PIN(S32G_MSCR_PH_02), + S32_PINCTRL_PIN(S32G_MSCR_PH_03), + S32_PINCTRL_PIN(S32G_MSCR_PH_04), + S32_PINCTRL_PIN(S32G_MSCR_PH_05), + S32_PINCTRL_PIN(S32G_MSCR_PH_06), + S32_PINCTRL_PIN(S32G_MSCR_PH_07), + S32_PINCTRL_PIN(S32G_MSCR_PH_08), + S32_PINCTRL_PIN(S32G_MSCR_PH_09), + S32_PINCTRL_PIN(S32G_MSCR_PH_10), + S32_PINCTRL_PIN(S32G_MSCR_PJ_00), + S32_PINCTRL_PIN(S32G_MSCR_PJ_01), + S32_PINCTRL_PIN(S32G_MSCR_PJ_02), + S32_PINCTRL_PIN(S32G_MSCR_PJ_03), + S32_PINCTRL_PIN(S32G_MSCR_PJ_04), + S32_PINCTRL_PIN(S32G_MSCR_PJ_05), + S32_PINCTRL_PIN(S32G_MSCR_PJ_06), + S32_PINCTRL_PIN(S32G_MSCR_PJ_07), + S32_PINCTRL_PIN(S32G_MSCR_PJ_08), + S32_PINCTRL_PIN(S32G_MSCR_PJ_09), + S32_PINCTRL_PIN(S32G_MSCR_PJ_10), + S32_PINCTRL_PIN(S32G_MSCR_PJ_11), + S32_PINCTRL_PIN(S32G_MSCR_PJ_12), + S32_PINCTRL_PIN(S32G_MSCR_PJ_13), + S32_PINCTRL_PIN(S32G_MSCR_PJ_14), + S32_PINCTRL_PIN(S32G_MSCR_PJ_15), + S32_PINCTRL_PIN(S32G_MSCR_PK_00), + S32_PINCTRL_PIN(S32G_MSCR_PK_01), + S32_PINCTRL_PIN(S32G_MSCR_PK_02), + S32_PINCTRL_PIN(S32G_MSCR_PK_03), + S32_PINCTRL_PIN(S32G_MSCR_PK_04), + S32_PINCTRL_PIN(S32G_MSCR_PK_05), + S32_PINCTRL_PIN(S32G_MSCR_PK_06), + S32_PINCTRL_PIN(S32G_MSCR_PK_07), + S32_PINCTRL_PIN(S32G_MSCR_PK_08), + S32_PINCTRL_PIN(S32G_MSCR_PK_09), + S32_PINCTRL_PIN(S32G_MSCR_PK_10), + S32_PINCTRL_PIN(S32G_MSCR_PK_11), + S32_PINCTRL_PIN(S32G_MSCR_PK_12), + S32_PINCTRL_PIN(S32G_MSCR_PK_13), + S32_PINCTRL_PIN(S32G_MSCR_PK_14), + S32_PINCTRL_PIN(S32G_MSCR_PK_15), + S32_PINCTRL_PIN(S32G_MSCR_PL_00), + S32_PINCTRL_PIN(S32G_MSCR_PL_01), + S32_PINCTRL_PIN(S32G_MSCR_PL_02), + S32_PINCTRL_PIN(S32G_MSCR_PL_03), + S32_PINCTRL_PIN(S32G_MSCR_PL_04), + S32_PINCTRL_PIN(S32G_MSCR_PL_05), + S32_PINCTRL_PIN(S32G_MSCR_PL_06), + S32_PINCTRL_PIN(S32G_MSCR_PL_07), + S32_PINCTRL_PIN(S32G_MSCR_PL_08), + S32_PINCTRL_PIN(S32G_MSCR_PL_09), + S32_PINCTRL_PIN(S32G_MSCR_PL_10), + S32_PINCTRL_PIN(S32G_MSCR_PL_11), + S32_PINCTRL_PIN(S32G_MSCR_PL_12), + S32_PINCTRL_PIN(S32G_MSCR_PL_13), + S32_PINCTRL_PIN(S32G_MSCR_PL_14), + + S32_PINCTRL_PIN(S32G_IMCR_FlexRay0_A_RX), + S32_PINCTRL_PIN(S32G_IMCR_FlexRay0_B_RX), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH0), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH0), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH1), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH1), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH2), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH2), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH3), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH3), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH4), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH4), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_CH5), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_CH5), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer0_EXTCLK), + S32_PINCTRL_PIN(S32G_IMCR_FlexTimer1_EXTCLK), + S32_PINCTRL_PIN(S32G_IMCR_I2C1_SCL), + S32_PINCTRL_PIN(S32G_IMCR_I2C1_SDA), + S32_PINCTRL_PIN(S32G_IMCR_I2C2_SCL), + S32_PINCTRL_PIN(S32G_IMCR_I2C2_SDA), + S32_PINCTRL_PIN(S32G_IMCR_I2C3_SCL), + S32_PINCTRL_PIN(S32G_IMCR_I2C3_SDA), + S32_PINCTRL_PIN(S32G_IMCR_I2C4_SCL), + S32_PINCTRL_PIN(S32G_IMCR_I2C4_SDA), + S32_PINCTRL_PIN(S32G_IMCR_LIN1_RX), + S32_PINCTRL_PIN(S32G_IMCR_LIN2_RX), + S32_PINCTRL_PIN(S32G_IMCR_DSPI0_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI0_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI0_SIN), + S32_PINCTRL_PIN(S32G_IMCR_DSPI1_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI1_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI1_SIN), + S32_PINCTRL_PIN(S32G_IMCR_DSPI2_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI2_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI2_SIN), + S32_PINCTRL_PIN(S32G_IMCR_DSPI3_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI3_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI3_SIN), + S32_PINCTRL_PIN(S32G_IMCR_DSPI4_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI4_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI4_SIN), + S32_PINCTRL_PIN(S32G_IMCR_DSPI5_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_DSPI5_SCK), + S32_PINCTRL_PIN(S32G_IMCR_DSPI5_SIN), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN0_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN1_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN2_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN3_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN4_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN5_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN6_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN7_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN8_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN9_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN10_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN11_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN12_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN13_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN14_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_CAN15_RXD), + S32_PINCTRL_PIN(S32G_IMCR_CAN1_RXD), + S32_PINCTRL_PIN(S32G_IMCR_CAN2_RXD), + S32_PINCTRL_PIN(S32G_IMCR_CAN3_RXD), + S32_PINCTRL_PIN(S32G_IMCR_USB_CLK), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA0), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA1), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA2), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA3), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA4), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA5), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA6), + S32_PINCTRL_PIN(S32G_IMCR_USB_DATA7), + S32_PINCTRL_PIN(S32G_IMCR_USB_DIR), + S32_PINCTRL_PIN(S32G_IMCR_USB_NXT), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_MDIO), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_CRS), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_COL), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_D0), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_D1), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_D2), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_D3), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_ER), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_RX_DV), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_TX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_1_REF_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_MDIO), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_CRS), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_COL), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_D0), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_D1), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_D2), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_D3), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_ER), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_RX_DV), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_TX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_2_REF_CLK), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ0), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ1), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ2), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ3), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ4), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ5), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ6), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ7), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ8), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ9), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ10), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ11), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ12), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ13), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ14), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ15), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ16), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ17), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ18), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ19), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ20), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ21), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ22), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ23), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ24), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ25), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ26), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ27), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ28), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ29), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ30), + S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ31), +}; + +static const struct s32_pin_range s32_pin_ranges_siul2[] = { + /* MSCR pin ID ranges */ + S32_PIN_RANGE(0, 101), + S32_PIN_RANGE(112, 122), + S32_PIN_RANGE(144, 190), + /* IMCR pin ID ranges */ + S32_PIN_RANGE(512, 595), + S32_PIN_RANGE(631, 909), + S32_PIN_RANGE(942, 1007), +}; + +static struct s32_pinctrl_soc_info s32_pinctrl_info = { + .pins = s32_pinctrl_pads_siul2, + .npins = ARRAY_SIZE(s32_pinctrl_pads_siul2), + .mem_pin_ranges = s32_pin_ranges_siul2, + .mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2), +}; + +static const struct of_device_id s32_pinctrl_of_match[] = { + { + + .compatible = "nxp,s32g2-siul2-pinctrl", + .data = (void *) &s32_pinctrl_info, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s32_pinctrl_of_match); + +static int s32g_pinctrl_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(s32_pinctrl_of_match, &pdev->dev); + + if (!of_id) + return -ENODEV; + + return s32_pinctrl_probe + (pdev, (struct s32_pinctrl_soc_info *) of_id->data); +} + +static const struct dev_pm_ops s32g_pinctrl_pm_ops = { + LATE_SYSTEM_SLEEP_PM_OPS(s32_pinctrl_suspend, s32_pinctrl_resume) +}; + +static struct platform_driver s32g_pinctrl_driver = { + .driver = { + .name = "s32g-siul2-pinctrl", + .of_match_table = s32_pinctrl_of_match, + .pm = pm_sleep_ptr(&s32g_pinctrl_pm_ops), + .suppress_bind_attrs = true, + }, + .probe = s32g_pinctrl_probe, +}; +builtin_platform_driver(s32g_pinctrl_driver); + +MODULE_AUTHOR("Matthew Nunez "); +MODULE_DESCRIPTION("NXP S32G pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 9236a132c7ba..f279b360c20d 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -206,15 +206,14 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) char *level_trig; char *active_level; - char *interrupt_enable; char *interrupt_mask; char *wake_cntrl0; char *wake_cntrl1; char *wake_cntrl2; char *pin_sts; + char *interrupt_sts; + char *wake_sts; char *pull_up_sel; - char *pull_up_enable; - char *pull_down_enable; char *orientation; char debounce_value[40]; char *debounce_enable; @@ -246,6 +245,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) continue; } seq_printf(s, "GPIO bank%d\n", bank); + seq_puts(s, "gpio\t int|active|trigger|S0i3| S3|S4/S5| Z|wake|pull| orient| debounce|reg\n"); for (; i < pin_num; i++) { seq_printf(s, "#%d\t", i); raw_spin_lock_irqsave(&gpio_dev->lock, flags); @@ -255,7 +255,6 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) { u8 level = (pin_reg >> ACTIVE_LEVEL_OFF) & ACTIVE_LEVEL_MASK; - interrupt_enable = "+"; if (level == ACTIVE_LEVEL_HIGH) active_level = "↑"; @@ -272,65 +271,66 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) else level_trig = " edge"; - } else { - interrupt_enable = "∅"; - active_level = "∅"; - level_trig = " ∅"; - } + if (pin_reg & BIT(INTERRUPT_MASK_OFF)) + interrupt_mask = "😛"; + else + interrupt_mask = "😷"; - if (pin_reg & BIT(INTERRUPT_MASK_OFF)) - interrupt_mask = "😛"; - else - interrupt_mask = "😷"; - seq_printf(s, "int %s (%s)| active-%s| %s-⚡| ", - interrupt_enable, + if (pin_reg & BIT(INTERRUPT_STS_OFF)) + interrupt_sts = "🔥"; + else + interrupt_sts = " "; + + seq_printf(s, "%s %s| %s| %s|", + interrupt_sts, interrupt_mask, active_level, level_trig); + } else + seq_puts(s, " ∅| | |"); if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3)) wake_cntrl0 = "⏰"; else - wake_cntrl0 = " ∅"; - seq_printf(s, "S0i3 %s| ", wake_cntrl0); + wake_cntrl0 = " "; + seq_printf(s, " %s| ", wake_cntrl0); if (pin_reg & BIT(WAKE_CNTRL_OFF_S3)) wake_cntrl1 = "⏰"; else - wake_cntrl1 = " ∅"; - seq_printf(s, "S3 %s| ", wake_cntrl1); + wake_cntrl1 = " "; + seq_printf(s, "%s|", wake_cntrl1); if (pin_reg & BIT(WAKE_CNTRL_OFF_S4)) wake_cntrl2 = "⏰"; else - wake_cntrl2 = " ∅"; - seq_printf(s, "S4/S5 %s| ", wake_cntrl2); + wake_cntrl2 = " "; + seq_printf(s, " %s|", wake_cntrl2); if (pin_reg & BIT(WAKECNTRL_Z_OFF)) wake_cntrlz = "⏰"; else - wake_cntrlz = " ∅"; - seq_printf(s, "Z %s| ", wake_cntrlz); + wake_cntrlz = " "; + seq_printf(s, "%s|", wake_cntrlz); + + if (pin_reg & BIT(WAKE_STS_OFF)) + wake_sts = "🔥"; + else + wake_sts = " "; + seq_printf(s, " %s|", wake_sts); if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) { - pull_up_enable = "+"; if (pin_reg & BIT(PULL_UP_SEL_OFF)) pull_up_sel = "8k"; else pull_up_sel = "4k"; - } else { - pull_up_enable = "∅"; - pull_up_sel = " "; + seq_printf(s, "%s ↑|", + pull_up_sel); + } else if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF)) { + seq_puts(s, " ↓|"); + } else { + seq_puts(s, " |"); } - seq_printf(s, "pull-↑ %s (%s)| ", - pull_up_enable, - pull_up_sel); - - if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF)) - pull_down_enable = "+"; - else - pull_down_enable = "∅"; - seq_printf(s, "pull-↓ %s| ", pull_down_enable); if (pin_reg & BIT(OUTPUT_ENABLE_OFF)) { pin_sts = "output"; @@ -345,7 +345,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) else orientation = "↓"; } - seq_printf(s, "%s %s| ", pin_sts, orientation); + seq_printf(s, "%s %s|", pin_sts, orientation); db_cntrl = (DB_CNTRl_MASK << DB_CNTRL_OFF) & pin_reg; if (db_cntrl) { @@ -364,19 +364,17 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) unit = 61; } if ((DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF) == db_cntrl) - debounce_enable = "b +"; + debounce_enable = "b"; else if ((DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF) == db_cntrl) - debounce_enable = "↓ +"; + debounce_enable = "↓"; else - debounce_enable = "↑ +"; - + debounce_enable = "↑"; + snprintf(debounce_value, sizeof(debounce_value), "%06u", time * unit); + seq_printf(s, "%s (🕑 %sus)|", debounce_enable, debounce_value); } else { - debounce_enable = " ∅"; - time = 0; + seq_puts(s, " |"); } - 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); + seq_printf(s, "0x%x\n", pin_reg); } } } @@ -1213,6 +1211,5 @@ static struct platform_driver amd_gpio_driver = { module_platform_driver(amd_gpio_driver); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ken Xue , Jeff Wu "); MODULE_DESCRIPTION("AMD GPIO pinctrl driver"); diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index c775d239444a..2fe40acb6a3e 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -1067,7 +1067,6 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pinctrl_pin_desc *pin_desc; const char **group_names; - const struct of_device_id *match; int i, ret; struct atmel_pioctrl *atmel_pioctrl; const struct atmel_pioctrl_data *atmel_pioctrl_data; @@ -1079,12 +1078,10 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) atmel_pioctrl->node = dev->of_node; platform_set_drvdata(pdev, atmel_pioctrl); - match = of_match_node(atmel_pctrl_of_match, dev->of_node); - if (!match) { - dev_err(dev, "unknown compatible string\n"); - return -ENODEV; - } - atmel_pioctrl_data = match->data; + atmel_pioctrl_data = device_get_match_data(dev); + if (!atmel_pioctrl_data) + return dev_err_probe(dev, -ENODEV, "Invalid device data\n"); + atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks; atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK; /* if last bank has limited number of pins, adjust accordingly */ @@ -1098,11 +1095,9 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(atmel_pioctrl->reg_base)) return PTR_ERR(atmel_pioctrl->reg_base); - atmel_pioctrl->clk = devm_clk_get(dev, NULL); - if (IS_ERR(atmel_pioctrl->clk)) { - dev_err(dev, "failed to get clock\n"); - return PTR_ERR(atmel_pioctrl->clk); - } + atmel_pioctrl->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(atmel_pioctrl->clk)) + return dev_err_probe(dev, PTR_ERR(atmel_pioctrl->clk), "failed to get clock\n"); atmel_pioctrl->pins = devm_kcalloc(dev, atmel_pioctrl->npins, @@ -1149,7 +1144,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) pin_desc[i].number = i; /* Pin naming convention: P(bank_name)(bank_pin_number). */ - pin_desc[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "P%c%d", + pin_desc[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "P%c%u", bank + 'A', line); group->name = group_names[i] = pin_desc[i].name; @@ -1202,10 +1197,8 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node, atmel_pioctrl->gpio_chip->ngpio, &irq_domain_simple_ops, NULL); - if (!atmel_pioctrl->irq_domain) { - dev_err(dev, "can't add the irq domain\n"); - return -ENODEV; - } + if (!atmel_pioctrl->irq_domain) + return dev_err_probe(dev, -ENODEV, "can't add the irq domain\n"); for (i = 0; i < atmel_pioctrl->npins; i++) { int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i); @@ -1218,25 +1211,19 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) i, irq); } - ret = clk_prepare_enable(atmel_pioctrl->clk); - if (ret) { - dev_err(dev, "failed to prepare and enable clock\n"); - goto clk_prepare_enable_error; - } - atmel_pioctrl->pinctrl_dev = devm_pinctrl_register(&pdev->dev, &atmel_pinctrl_desc, atmel_pioctrl); if (IS_ERR(atmel_pioctrl->pinctrl_dev)) { ret = PTR_ERR(atmel_pioctrl->pinctrl_dev); dev_err(dev, "pinctrl registration failed\n"); - goto clk_unprep; + goto irq_domain_remove_error; } ret = gpiochip_add_data(atmel_pioctrl->gpio_chip, atmel_pioctrl); if (ret) { dev_err(dev, "failed to add gpiochip\n"); - goto clk_unprep; + goto irq_domain_remove_error; } ret = gpiochip_add_pin_range(atmel_pioctrl->gpio_chip, dev_name(dev), @@ -1253,10 +1240,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) gpiochip_add_pin_range_error: gpiochip_remove(atmel_pioctrl->gpio_chip); -clk_unprep: - clk_disable_unprepare(atmel_pioctrl->clk); - -clk_prepare_enable_error: +irq_domain_remove_error: irq_domain_remove(atmel_pioctrl->irq_domain); return ret; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 735c501e7a06..871209c24153 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -18,6 +18,7 @@ #include #include #include +#include /* Since we request GPIOs from ourself */ #include @@ -41,7 +42,6 @@ struct at91_pinctrl_mux_ops; * @next: bank sharing same clock * @pioc_hwirq: PIO bank interrupt identifier on AIC * @pioc_virq: PIO bank Linux virtual interrupt - * @pioc_idx: PIO bank index * @regbase: PIO bank virtual address * @clock: associated clock * @ops: at91 pinctrl mux ops @@ -55,7 +55,6 @@ struct at91_gpio_chip { struct at91_gpio_chip *next; int pioc_hwirq; int pioc_virq; - int pioc_idx; void __iomem *regbase; struct clk *clock; const struct at91_pinctrl_mux_ops *ops; @@ -1293,18 +1292,18 @@ static const struct of_device_id at91_pinctrl_of_match[] = { static int at91_pinctrl_probe_dt(struct platform_device *pdev, struct at91_pinctrl *info) { + struct device *dev = &pdev->dev; int ret = 0; int i, j, ngpio_chips_enabled = 0; uint32_t *tmp; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct device_node *child; if (!np) return -ENODEV; - info->dev = &pdev->dev; - info->ops = (const struct at91_pinctrl_mux_ops *) - of_match_device(at91_pinctrl_of_match, &pdev->dev)->data; + info->dev = dev; + info->ops = of_device_get_match_data(dev); at91_pinctrl_child_count(info, np); /* @@ -1323,35 +1322,31 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, if (ret) return ret; - dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux); + dev_dbg(dev, "nmux = %d\n", info->nmux); - dev_dbg(&pdev->dev, "mux-mask\n"); + dev_dbg(dev, "mux-mask\n"); tmp = info->mux_mask; for (i = 0; i < gpio_banks; i++) { for (j = 0; j < info->nmux; j++, tmp++) { - dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]); + dev_dbg(dev, "%d:%d\t0x%x\n", i, j, tmp[0]); } } - dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); - dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); - info->functions = devm_kcalloc(&pdev->dev, - info->nfunctions, - sizeof(struct at91_pmx_func), - GFP_KERNEL); + dev_dbg(dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(dev, "ngroups = %d\n", info->ngroups); + info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), + GFP_KERNEL); if (!info->functions) return -ENOMEM; - info->groups = devm_kcalloc(&pdev->dev, - info->ngroups, - sizeof(struct at91_pin_group), - GFP_KERNEL); + info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), + GFP_KERNEL); if (!info->groups) return -ENOMEM; - dev_dbg(&pdev->dev, "nbanks = %d\n", gpio_banks); - dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); - dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + dev_dbg(dev, "nbanks = %d\n", gpio_banks); + dev_dbg(dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(dev, "ngroups = %d\n", info->ngroups); i = 0; @@ -1360,9 +1355,8 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, continue; ret = at91_pinctrl_parse_functions(child, info, i++); if (ret) { - dev_err(&pdev->dev, "failed to parse function\n"); of_node_put(child); - return ret; + return dev_err_probe(dev, ret, "failed to parse function\n"); } } @@ -1371,11 +1365,12 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, static int at91_pinctrl_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct at91_pinctrl *info; struct pinctrl_pin_desc *pdesc; int ret, i, j, k; - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -1383,39 +1378,42 @@ static int at91_pinctrl_probe(struct platform_device *pdev) if (ret) return ret; - at91_pinctrl_desc.name = dev_name(&pdev->dev); + at91_pinctrl_desc.name = dev_name(dev); at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK; at91_pinctrl_desc.pins = pdesc = - devm_kcalloc(&pdev->dev, - at91_pinctrl_desc.npins, sizeof(*pdesc), - GFP_KERNEL); - + devm_kcalloc(dev, at91_pinctrl_desc.npins, sizeof(*pdesc), GFP_KERNEL); if (!at91_pinctrl_desc.pins) return -ENOMEM; for (i = 0, k = 0; i < gpio_banks; i++) { + char **names; + + names = devm_kasprintf_strarray(dev, "pio", MAX_NB_GPIO_PER_BANK); + if (!names) + return -ENOMEM; + for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) { + char *name = names[j]; + + strreplace(name, '-', i + 'A'); + pdesc->number = k; - pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j); + pdesc->name = name; pdesc++; } } platform_set_drvdata(pdev, info); - info->pctl = devm_pinctrl_register(&pdev->dev, &at91_pinctrl_desc, - info); - - if (IS_ERR(info->pctl)) { - dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n"); - return PTR_ERR(info->pctl); - } + info->pctl = devm_pinctrl_register(dev, &at91_pinctrl_desc, info); + if (IS_ERR(info->pctl)) + return dev_err_probe(dev, PTR_ERR(info->pctl), "could not register AT91 pinctrl driver\n"); /* We will handle a range of GPIO pins */ for (i = 0; i < gpio_banks; i++) if (gpio_chips[i]) pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); - dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n"); + dev_info(dev, "initialized AT91 pinctrl driver\n"); return 0; } @@ -1526,6 +1524,20 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define at91_gpio_dbg_show NULL #endif +static int gpio_irq_request_resources(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + + return gpiochip_lock_as_irq(&at91_gpio->chip, irqd_to_hwirq(d)); +} + +static void gpio_irq_release_resources(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + + gpiochip_unlock_as_irq(&at91_gpio->chip, irqd_to_hwirq(d)); +} + /* Several AIC controller irqs are dispatched through this GPIO handler. * To use any AT91_PIN_* as an externally triggered IRQ, first call * at91_set_gpio_input() then maybe enable its glitch filter. @@ -1545,6 +1557,9 @@ static void gpio_irq_mask(struct irq_data *d) struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); void __iomem *pio = at91_gpio->regbase; unsigned mask = 1 << d->hwirq; + unsigned gpio = irqd_to_hwirq(d); + + gpiochip_disable_irq(&at91_gpio->chip, gpio); if (pio) writel_relaxed(mask, pio + PIO_IDR); @@ -1555,6 +1570,9 @@ static void gpio_irq_unmask(struct irq_data *d) struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); void __iomem *pio = at91_gpio->regbase; unsigned mask = 1 << d->hwirq; + unsigned gpio = irqd_to_hwirq(d); + + gpiochip_enable_irq(&at91_gpio->chip, gpio); if (pio) writel_relaxed(mask, pio + PIO_IER); @@ -1706,6 +1724,7 @@ static void gpio_irq_handler(struct irq_desc *desc) static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct at91_gpio_chip *at91_gpio) { + struct device *dev = &pdev->dev; struct gpio_chip *gpiochip_prev = NULL; struct at91_gpio_chip *prev = NULL; struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); @@ -1713,20 +1732,22 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct gpio_irq_chip *girq; int i; - gpio_irqchip = devm_kzalloc(&pdev->dev, sizeof(*gpio_irqchip), - GFP_KERNEL); + gpio_irqchip = devm_kzalloc(dev, sizeof(*gpio_irqchip), GFP_KERNEL); if (!gpio_irqchip) return -ENOMEM; at91_gpio->pioc_hwirq = irqd_to_hwirq(d); gpio_irqchip->name = "GPIO"; + gpio_irqchip->irq_request_resources = gpio_irq_request_resources; + gpio_irqchip->irq_release_resources = gpio_irq_release_resources; gpio_irqchip->irq_ack = gpio_irq_ack; 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 = pm_ptr(gpio_irq_set_wake); gpio_irqchip->irq_set_type = at91_gpio->ops->irq_type; + gpio_irqchip->flags = IRQCHIP_IMMUTABLE; /* Disable irqs of this PIO controller */ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); @@ -1737,7 +1758,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, * interrupt. */ girq = &at91_gpio->chip.irq; - girq->chip = gpio_irqchip; + gpio_irq_chip_set_chip(girq, gpio_irqchip); girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_edge_irq; @@ -1750,7 +1771,7 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, if (!gpiochip_prev) { girq->parent_handler = gpio_irq_handler; girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, 1, + girq->parents = devm_kcalloc(dev, girq->num_parents, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) @@ -1797,7 +1818,8 @@ static const struct of_device_id at91_gpio_of_match[] = { static int at91_gpio_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct at91_gpio_chip *at91_chip = NULL; struct gpio_chip *chip; struct pinctrl_gpio_range *range; @@ -1808,74 +1830,51 @@ static int at91_gpio_probe(struct platform_device *pdev) char **names; BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips)); - if (gpio_chips[alias_idx]) { - ret = -EBUSY; - goto err; - } + if (gpio_chips[alias_idx]) + return dev_err_probe(dev, -EBUSY, "%d slot is occupied.\n", alias_idx); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err; - } + if (irq < 0) + return irq; - at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL); - if (!at91_chip) { - ret = -ENOMEM; - goto err; - } + at91_chip = devm_kzalloc(dev, sizeof(*at91_chip), GFP_KERNEL); + if (!at91_chip) + return -ENOMEM; at91_chip->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(at91_chip->regbase)) { - ret = PTR_ERR(at91_chip->regbase); - goto err; - } + if (IS_ERR(at91_chip->regbase)) + return PTR_ERR(at91_chip->regbase); - at91_chip->ops = (const struct at91_pinctrl_mux_ops *) - of_match_device(at91_gpio_of_match, &pdev->dev)->data; + at91_chip->ops = of_device_get_match_data(dev); at91_chip->pioc_virq = irq; - at91_chip->pioc_idx = alias_idx; - at91_chip->clock = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(at91_chip->clock)) { - dev_err(&pdev->dev, "failed to get clock, ignoring.\n"); - ret = PTR_ERR(at91_chip->clock); - goto err; - } - - ret = clk_prepare_enable(at91_chip->clock); - if (ret) { - dev_err(&pdev->dev, "failed to prepare and enable clock, ignoring.\n"); - goto clk_enable_err; - } + at91_chip->clock = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(at91_chip->clock)) + return dev_err_probe(dev, PTR_ERR(at91_chip->clock), "failed to get clock, ignoring.\n"); at91_chip->chip = at91_gpio_template; at91_chip->id = alias_idx; chip = &at91_chip->chip; - chip->label = dev_name(&pdev->dev); - chip->parent = &pdev->dev; + chip->label = dev_name(dev); + chip->parent = dev; chip->owner = THIS_MODULE; chip->base = alias_idx * MAX_NB_GPIO_PER_BANK; if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) { if (ngpio >= MAX_NB_GPIO_PER_BANK) - pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n", - alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); + dev_err(dev, "at91_gpio.%d, gpio-nb >= %d failback to %d\n", + alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); else chip->ngpio = ngpio; } - names = devm_kcalloc(&pdev->dev, chip->ngpio, sizeof(char *), - GFP_KERNEL); - - if (!names) { - ret = -ENOMEM; - goto clk_enable_err; - } + names = devm_kasprintf_strarray(dev, "pio", chip->ngpio); + if (!names) + return -ENOMEM; for (i = 0; i < chip->ngpio; i++) - names[i] = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pio%c%d", alias_idx + 'A', i); + strreplace(names[i], '-', alias_idx + 'A'); chip->names = (const char *const *)names; @@ -1889,27 +1888,19 @@ static int at91_gpio_probe(struct platform_device *pdev) ret = at91_gpio_of_irq_setup(pdev, at91_chip); if (ret) - goto gpiochip_add_err; + return ret; ret = gpiochip_add_data(chip, at91_chip); if (ret) - goto gpiochip_add_err; + return ret; gpio_chips[alias_idx] = at91_chip; platform_set_drvdata(pdev, at91_chip); gpio_banks = max(gpio_banks, alias_idx + 1); - dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase); + dev_info(dev, "at address %p\n", at91_chip->regbase); return 0; - -gpiochip_add_err: -clk_enable_err: - clk_disable_unprepare(at91_chip->clock); -err: - dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx); - - return ret; } static const struct dev_pm_ops at91_gpio_pm_ops = { diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c index 99cf24eb67ae..5b5ddf7e5d0e 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.c +++ b/drivers/pinctrl/pinctrl-equilibrium.c @@ -32,6 +32,7 @@ static void eqbr_gpio_disable_irq(struct irq_data *d) raw_spin_lock_irqsave(&gctrl->lock, flags); writel(BIT(offset), gctrl->membase + GPIO_IRNENCLR); raw_spin_unlock_irqrestore(&gctrl->lock, flags); + gpiochip_disable_irq(gc, offset); } static void eqbr_gpio_enable_irq(struct irq_data *d) @@ -42,6 +43,7 @@ static void eqbr_gpio_enable_irq(struct irq_data *d) unsigned long flags; gc->direction_input(gc, offset); + gpiochip_enable_irq(gc, offset); raw_spin_lock_irqsave(&gctrl->lock, flags); writel(BIT(offset), gctrl->membase + GPIO_IRNRNSET); raw_spin_unlock_irqrestore(&gctrl->lock, flags); @@ -161,6 +163,17 @@ static void eqbr_irq_handler(struct irq_desc *desc) chained_irq_exit(ic, desc); } +static const struct irq_chip eqbr_irq_chip = { + .name = "gpio_irq", + .irq_mask = eqbr_gpio_disable_irq, + .irq_unmask = eqbr_gpio_enable_irq, + .irq_ack = eqbr_gpio_ack_irq, + .irq_mask_ack = eqbr_gpio_mask_ack_irq, + .irq_set_type = eqbr_gpio_set_irq_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl) { struct gpio_irq_chip *girq; @@ -176,15 +189,8 @@ static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl) return 0; } - gctrl->ic.name = "gpio_irq"; - gctrl->ic.irq_mask = eqbr_gpio_disable_irq; - gctrl->ic.irq_unmask = eqbr_gpio_enable_irq; - gctrl->ic.irq_ack = eqbr_gpio_ack_irq; - gctrl->ic.irq_mask_ack = eqbr_gpio_mask_ack_irq; - gctrl->ic.irq_set_type = eqbr_gpio_set_irq_type; - girq = &gctrl->chip.irq; - girq->chip = &gctrl->ic; + gpio_irq_chip_set_chip(girq, &eqbr_irq_chip); girq->parent_handler = eqbr_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); diff --git a/drivers/pinctrl/pinctrl-equilibrium.h b/drivers/pinctrl/pinctrl-equilibrium.h index 0c635a5b79f0..83768cc8b3db 100644 --- a/drivers/pinctrl/pinctrl-equilibrium.h +++ b/drivers/pinctrl/pinctrl-equilibrium.h @@ -103,7 +103,6 @@ struct fwnode_handle; * @fwnode: firmware node of gpio controller. * @bank: pointer to corresponding pin bank. * @membase: base address of the gpio controller. - * @ic: irq chip. * @name: gpio chip name. * @virq: irq number of the gpio chip to parent's irq domain. * @lock: spin lock to protect gpio register write. @@ -113,7 +112,6 @@ struct eqbr_gpio_ctrl { struct fwnode_handle *fwnode; struct eqbr_pin_bank *bank; void __iomem *membase; - struct irq_chip ic; const char *name; unsigned int virq; raw_spinlock_t lock; /* protect gpio register */ diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 5f356edfd0fd..4551575e4e7d 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -144,10 +145,9 @@ static int mcp_write(struct mcp23s08 *mcp, unsigned int reg, unsigned int val) return regmap_write(mcp->regmap, reg << mcp->reg_shift, val); } -static int mcp_set_mask(struct mcp23s08 *mcp, unsigned int reg, - unsigned int mask, bool enabled) +static int mcp_update_bits(struct mcp23s08 *mcp, unsigned int reg, + unsigned int mask, unsigned int val) { - u16 val = enabled ? 0xffff : 0x0000; return regmap_update_bits(mcp->regmap, reg << mcp->reg_shift, mask, val); } @@ -156,7 +156,7 @@ static int mcp_set_bit(struct mcp23s08 *mcp, unsigned int reg, unsigned int pin, bool enabled) { u16 mask = BIT(pin); - return mcp_set_mask(mcp, reg, mask, enabled); + return mcp_update_bits(mcp, reg, mask, enabled ? mask : 0); } static const struct pinctrl_pin_desc mcp23x08_pins[] = { @@ -308,9 +308,31 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) return status; } +static int mcp23s08_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct mcp23s08 *mcp = gpiochip_get_data(chip); + unsigned int status; + int ret; + + mutex_lock(&mcp->lock); + + /* REVISIT reading this clears any IRQ ... */ + ret = mcp_read(mcp, MCP_GPIO, &status); + if (ret < 0) + status = 0; + else { + mcp->cached_gpio = status; + *bits = status; + } + + mutex_unlock(&mcp->lock); + return ret; +} + static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, bool value) { - return mcp_set_mask(mcp, MCP_OLAT, mask, value); + return mcp_update_bits(mcp, MCP_OLAT, mask, value ? mask : 0); } static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) @@ -323,6 +345,16 @@ static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) mutex_unlock(&mcp->lock); } +static void mcp23s08_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct mcp23s08 *mcp = gpiochip_get_data(chip); + + mutex_lock(&mcp->lock); + mcp_update_bits(mcp, MCP_OLAT, *mask, *bits); + mutex_unlock(&mcp->lock); +} + static int mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) { @@ -333,7 +365,7 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) mutex_lock(&mcp->lock); status = __mcp23s08_set(mcp, mask, value); if (status == 0) { - status = mcp_set_mask(mcp, MCP_IODIR, mask, false); + status = mcp_update_bits(mcp, MCP_IODIR, mask, 0); } mutex_unlock(&mcp->lock); return status; @@ -436,17 +468,19 @@ static void mcp23s08_irq_mask(struct irq_data *data) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mcp23s08 *mcp = gpiochip_get_data(gc); - unsigned int pos = data->hwirq; + unsigned int pos = irqd_to_hwirq(data); mcp_set_bit(mcp, MCP_GPINTEN, pos, false); + gpiochip_disable_irq(gc, pos); } static void mcp23s08_irq_unmask(struct irq_data *data) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mcp23s08 *mcp = gpiochip_get_data(gc); - unsigned int pos = data->hwirq; + unsigned int pos = irqd_to_hwirq(data); + gpiochip_enable_irq(gc, pos); mcp_set_bit(mcp, MCP_GPINTEN, pos, true); } @@ -454,7 +488,7 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); struct mcp23s08 *mcp = gpiochip_get_data(gc); - unsigned int pos = data->hwirq; + unsigned int pos = irqd_to_hwirq(data); if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { mcp_set_bit(mcp, MCP_INTCON, pos, false); @@ -523,6 +557,25 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) return 0; } +static void mcp23s08_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mcp23s08 *mcp = gpiochip_get_data(gc); + + seq_printf(p, dev_name(mcp->dev)); +} + +static const struct irq_chip mcp23s08_irq_chip = { + .irq_mask = mcp23s08_irq_mask, + .irq_unmask = mcp23s08_irq_unmask, + .irq_set_type = mcp23s08_irq_set_type, + .irq_bus_lock = mcp23s08_irq_bus_lock, + .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, + .irq_print_chip = mcp23s08_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + /*----------------------------------------------------------------------*/ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, @@ -538,17 +591,13 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, mcp->addr = addr; mcp->irq_active_high = false; - mcp->irq_chip.name = dev_name(dev); - mcp->irq_chip.irq_mask = mcp23s08_irq_mask; - mcp->irq_chip.irq_unmask = mcp23s08_irq_unmask; - mcp->irq_chip.irq_set_type = mcp23s08_irq_set_type; - mcp->irq_chip.irq_bus_lock = mcp23s08_irq_bus_lock; - mcp->irq_chip.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock; mcp->chip.direction_input = mcp23s08_direction_input; mcp->chip.get = mcp23s08_get; + mcp->chip.get_multiple = mcp23s08_get_multiple; mcp->chip.direction_output = mcp23s08_direction_output; mcp->chip.set = mcp23s08_set; + mcp->chip.set_multiple = mcp23s08_set_multiple; mcp->chip.base = base; mcp->chip.can_sleep = true; @@ -603,7 +652,7 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, if (mcp->irq && mcp->irq_controller) { struct gpio_irq_chip *girq = &mcp->chip.irq; - girq->chip = &mcp->irq_chip; + gpio_irq_chip_set_chip(girq, &mcp23s08_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/pinctrl/pinctrl-mcp23s08.h b/drivers/pinctrl/pinctrl-mcp23s08.h index b8d15939e0c2..b15516af7783 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.h +++ b/drivers/pinctrl/pinctrl-mcp23s08.h @@ -36,7 +36,6 @@ struct mcp23s08 { struct mutex lock; struct gpio_chip chip; - struct irq_chip irq_chip; struct regmap *regmap; struct device *dev; diff --git a/drivers/pinctrl/pinctrl-mlxbf3.c b/drivers/pinctrl/pinctrl-mlxbf3.c new file mode 100644 index 000000000000..d9944e6a0af9 --- /dev/null +++ b/drivers/pinctrl/pinctrl-mlxbf3.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause +/* Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MLXBF3_NGPIOS_GPIO0 32 +#define MLXBF3_MAX_GPIO_PINS 56 + +enum { + MLXBF3_GPIO_HW_MODE, + MLXBF3_GPIO_SW_MODE, +}; + +struct mlxbf3_pinctrl { + void __iomem *fw_ctrl_set0; + void __iomem *fw_ctrl_clr0; + void __iomem *fw_ctrl_set1; + void __iomem *fw_ctrl_clr1; + struct device *dev; + struct pinctrl_dev *pctl; + struct pinctrl_gpio_range gpio_range; +}; + +#define MLXBF3_GPIO_RANGE(_id, _pinbase, _gpiobase, _npins) \ + { \ + .name = "mlxbf3_gpio_range", \ + .id = _id, \ + .base = _gpiobase, \ + .pin_base = _pinbase, \ + .npins = _npins, \ + } + +static struct pinctrl_gpio_range mlxbf3_pinctrl_gpio_ranges[] = { + MLXBF3_GPIO_RANGE(0, 0, 480, 32), + MLXBF3_GPIO_RANGE(1, 32, 456, 24), +}; + +static const struct pinctrl_pin_desc mlxbf3_pins[] = { + PINCTRL_PIN(0, "gpio0"), + PINCTRL_PIN(1, "gpio1"), + PINCTRL_PIN(2, "gpio2"), + PINCTRL_PIN(3, "gpio3"), + PINCTRL_PIN(4, "gpio4"), + PINCTRL_PIN(5, "gpio5"), + PINCTRL_PIN(6, "gpio6"), + PINCTRL_PIN(7, "gpio7"), + PINCTRL_PIN(8, "gpio8"), + PINCTRL_PIN(9, "gpio9"), + PINCTRL_PIN(10, "gpio10"), + PINCTRL_PIN(11, "gpio11"), + PINCTRL_PIN(12, "gpio12"), + PINCTRL_PIN(13, "gpio13"), + PINCTRL_PIN(14, "gpio14"), + PINCTRL_PIN(15, "gpio15"), + PINCTRL_PIN(16, "gpio16"), + PINCTRL_PIN(17, "gpio17"), + PINCTRL_PIN(18, "gpio18"), + PINCTRL_PIN(19, "gpio19"), + PINCTRL_PIN(20, "gpio20"), + PINCTRL_PIN(21, "gpio21"), + PINCTRL_PIN(22, "gpio22"), + PINCTRL_PIN(23, "gpio23"), + PINCTRL_PIN(24, "gpio24"), + PINCTRL_PIN(25, "gpio25"), + PINCTRL_PIN(26, "gpio26"), + PINCTRL_PIN(27, "gpio27"), + PINCTRL_PIN(28, "gpio28"), + PINCTRL_PIN(29, "gpio29"), + PINCTRL_PIN(30, "gpio30"), + PINCTRL_PIN(31, "gpio31"), + PINCTRL_PIN(32, "gpio32"), + PINCTRL_PIN(33, "gpio33"), + PINCTRL_PIN(34, "gpio34"), + PINCTRL_PIN(35, "gpio35"), + PINCTRL_PIN(36, "gpio36"), + PINCTRL_PIN(37, "gpio37"), + PINCTRL_PIN(38, "gpio38"), + PINCTRL_PIN(39, "gpio39"), + PINCTRL_PIN(40, "gpio40"), + PINCTRL_PIN(41, "gpio41"), + PINCTRL_PIN(42, "gpio42"), + PINCTRL_PIN(43, "gpio43"), + PINCTRL_PIN(44, "gpio44"), + PINCTRL_PIN(45, "gpio45"), + PINCTRL_PIN(46, "gpio46"), + PINCTRL_PIN(47, "gpio47"), + PINCTRL_PIN(48, "gpio48"), + PINCTRL_PIN(49, "gpio49"), + PINCTRL_PIN(50, "gpio50"), + PINCTRL_PIN(51, "gpio51"), + PINCTRL_PIN(52, "gpio52"), + PINCTRL_PIN(53, "gpio53"), + PINCTRL_PIN(54, "gpio54"), + PINCTRL_PIN(55, "gpio55"), +}; + +/* + * All single-pin functions can be mapped to any GPIO, however pinmux applies + * functions to pin groups and only those groups declared as supporting that + * function. To make this work we must put each pin in its own dummy group so + * that the functions can be described as applying to all pins. + * We use the same name as in the datasheet. + */ +static const char * const mlxbf3_pinctrl_single_group_names[] = { + "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", +}; + +static int mlxbf3_get_groups_count(struct pinctrl_dev *pctldev) +{ + /* Number single-pin groups */ + return MLXBF3_MAX_GPIO_PINS; +} + +static const char *mlxbf3_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return mlxbf3_pinctrl_single_group_names[selector]; +} + +static int mlxbf3_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + /* return the dummy group for a single pin */ + *pins = &selector; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops mlxbf3_pinctrl_group_ops = { + .get_groups_count = mlxbf3_get_groups_count, + .get_group_name = mlxbf3_get_group_name, + .get_group_pins = mlxbf3_get_group_pins, +}; + +/* + * Only 2 functions are supported and they apply to all pins: + * 1) Default hardware functionality + * 2) Software controlled GPIO + */ +static const char * const mlxbf3_gpiofunc_group_names[] = { "swctrl" }; +static const char * const mlxbf3_hwfunc_group_names[] = { "hwctrl" }; + +static struct pinfunction mlxbf3_pmx_funcs[] = { + PINCTRL_PINFUNCTION("hwfunc", mlxbf3_hwfunc_group_names, 1), + PINCTRL_PINFUNCTION("gpiofunc", mlxbf3_gpiofunc_group_names, 1), +}; + +static int mlxbf3_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(mlxbf3_pmx_funcs); +} + +static const char *mlxbf3_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + return mlxbf3_pmx_funcs[selector].name; +} + +static int mlxbf3_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + *groups = mlxbf3_pmx_funcs[selector].groups; + *num_groups = MLXBF3_MAX_GPIO_PINS; + + return 0; +} + +static int mlxbf3_pmx_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned int group) +{ + struct mlxbf3_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev); + + if (selector == MLXBF3_GPIO_HW_MODE) { + if (group < MLXBF3_NGPIOS_GPIO0) + writel(BIT(group), priv->fw_ctrl_clr0); + else + writel(BIT(group % MLXBF3_NGPIOS_GPIO0), priv->fw_ctrl_clr1); + } + + if (selector == MLXBF3_GPIO_SW_MODE) { + if (group < MLXBF3_NGPIOS_GPIO0) + writel(BIT(group), priv->fw_ctrl_set0); + else + writel(BIT(group % MLXBF3_NGPIOS_GPIO0), priv->fw_ctrl_set1); + } + + return 0; +} + +static int mlxbf3_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct mlxbf3_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev); + + if (offset < MLXBF3_NGPIOS_GPIO0) + writel(BIT(offset), priv->fw_ctrl_set0); + else + writel(BIT(offset % MLXBF3_NGPIOS_GPIO0), priv->fw_ctrl_set1); + + return 0; +} + +static void mlxbf3_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct mlxbf3_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev); + + /* disable GPIO functionality by giving control back to hardware */ + if (offset < MLXBF3_NGPIOS_GPIO0) + writel(BIT(offset), priv->fw_ctrl_clr0); + else + writel(BIT(offset % MLXBF3_NGPIOS_GPIO0), priv->fw_ctrl_clr1); +} + +static const struct pinmux_ops mlxbf3_pmx_ops = { + .get_functions_count = mlxbf3_pmx_get_funcs_count, + .get_function_name = mlxbf3_pmx_get_func_name, + .get_function_groups = mlxbf3_pmx_get_groups, + .set_mux = mlxbf3_pmx_set, + .gpio_request_enable = mlxbf3_gpio_request_enable, + .gpio_disable_free = mlxbf3_gpio_disable_free, +}; + +static struct pinctrl_desc mlxbf3_pin_desc = { + .name = "pinctrl-mlxbf3", + .pins = mlxbf3_pins, + .npins = ARRAY_SIZE(mlxbf3_pins), + .pctlops = &mlxbf3_pinctrl_group_ops, + .pmxops = &mlxbf3_pmx_ops, + .owner = THIS_MODULE, +}; + +static_assert(ARRAY_SIZE(mlxbf3_pinctrl_single_group_names) == MLXBF3_MAX_GPIO_PINS); + +static int mlxbf3_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mlxbf3_pinctrl *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->fw_ctrl_set0 = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->fw_ctrl_set0)) + return PTR_ERR(priv->fw_ctrl_set0); + + priv->fw_ctrl_clr0 = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(priv->fw_ctrl_set0)) + return PTR_ERR(priv->fw_ctrl_set0); + + priv->fw_ctrl_set1 = devm_platform_ioremap_resource(pdev, 2); + if (IS_ERR(priv->fw_ctrl_set0)) + return PTR_ERR(priv->fw_ctrl_set0); + + priv->fw_ctrl_clr1 = devm_platform_ioremap_resource(pdev, 3); + if (IS_ERR(priv->fw_ctrl_set0)) + return PTR_ERR(priv->fw_ctrl_set0); + + ret = devm_pinctrl_register_and_init(dev, + &mlxbf3_pin_desc, + priv, + &priv->pctl); + if (ret) + return dev_err_probe(dev, ret, "Failed to register pinctrl\n"); + + ret = pinctrl_enable(priv->pctl); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pinctrl\n"); + + pinctrl_add_gpio_ranges(priv->pctl, mlxbf3_pinctrl_gpio_ranges, 2); + + return 0; +} + +static const struct acpi_device_id mlxbf3_pinctrl_acpi_ids[] = { + { "MLNXBF34", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, mlxbf3_pinctrl_acpi_ids); + +static struct platform_driver mlxbf3_pinctrl_driver = { + .driver = { + .name = "pinctrl-mlxbf3", + .acpi_match_table = mlxbf3_pinctrl_acpi_ids, + }, + .probe = mlxbf3_pinctrl_probe, +}; +module_platform_driver(mlxbf3_pinctrl_driver); + +MODULE_DESCRIPTION("NVIDIA pinctrl driver"); +MODULE_AUTHOR("Asmaa Mnebhi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c index 37acfdfc2cae..dad05294fa72 100644 --- a/drivers/pinctrl/pinctrl-pic32.c +++ b/drivers/pinctrl/pinctrl-pic32.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -60,8 +61,8 @@ struct pic32_desc_function { struct pic32_gpio_bank { void __iomem *reg_base; + int instance; struct gpio_chip gpio_chip; - struct irq_chip irq_chip; struct clk *clk; }; @@ -2008,12 +2009,14 @@ static void pic32_gpio_irq_mask(struct irq_data *data) struct pic32_gpio_bank *bank = irqd_to_bank(data); writel(BIT(PIC32_CNCON_ON), bank->reg_base + PIC32_CLR(CNCON_REG)); + gpiochip_disable_irq(&bank->gpio_chip, irqd_to_hwirq(data)); } static void pic32_gpio_irq_unmask(struct irq_data *data) { struct pic32_gpio_bank *bank = irqd_to_bank(data); + gpiochip_enable_irq(&bank->gpio_chip, irqd_to_hwirq(data)); writel(BIT(PIC32_CNCON_ON), bank->reg_base + PIC32_SET(CNCON_REG)); } @@ -2030,7 +2033,7 @@ static unsigned int pic32_gpio_irq_startup(struct irq_data *data) static int pic32_gpio_irq_set_type(struct irq_data *data, unsigned int type) { struct pic32_gpio_bank *bank = irqd_to_bank(data); - u32 mask = BIT(data->hwirq); + u32 mask = irqd_to_hwirq(data); switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -2122,14 +2125,7 @@ static void pic32_gpio_irq_handler(struct irq_desc *desc) .owner = THIS_MODULE, \ .can_sleep = 0, \ }, \ - .irq_chip = { \ - .name = "GPIO" #_bank, \ - .irq_startup = pic32_gpio_irq_startup, \ - .irq_ack = pic32_gpio_irq_ack, \ - .irq_mask = pic32_gpio_irq_mask, \ - .irq_unmask = pic32_gpio_irq_unmask, \ - .irq_set_type = pic32_gpio_irq_set_type, \ - }, \ + .instance = (_bank), \ } static struct pic32_gpio_bank pic32_gpio_banks[] = { @@ -2145,6 +2141,24 @@ static struct pic32_gpio_bank pic32_gpio_banks[] = { GPIO_BANK(9, PINS_PER_BANK), }; +static void pic32_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) +{ + struct pic32_gpio_bank *bank = irqd_to_bank(data); + + seq_printf(p, "GPIO%d", bank->instance); +} + +static const struct irq_chip pic32_gpio_irq_chip = { + .irq_startup = pic32_gpio_irq_startup, + .irq_ack = pic32_gpio_irq_ack, + .irq_mask = pic32_gpio_irq_mask, + .irq_unmask = pic32_gpio_irq_unmask, + .irq_set_type = pic32_gpio_irq_set_type, + .irq_print_chip = pic32_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int pic32_pinctrl_probe(struct platform_device *pdev) { struct pic32_pinctrl *pctl; @@ -2243,7 +2257,7 @@ static int pic32_gpio_probe(struct platform_device *pdev) bank->gpio_chip.parent = &pdev->dev; girq = &bank->gpio_chip.irq; - girq->chip = &bank->irq_chip; + gpio_irq_chip_set_chip(girq, &pic32_gpio_irq_chip); girq->parent_handler = pic32_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 7ca4ecb6eb8d..53408344927a 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -93,10 +94,10 @@ struct pistachio_pin_group { struct pistachio_gpio_bank { struct pistachio_pinctrl *pctl; void __iomem *base; + int instance; unsigned int pin_base; unsigned int npins; struct gpio_chip gpio_chip; - struct irq_chip irq_chip; }; struct pistachio_pinctrl { @@ -1228,12 +1229,14 @@ static void pistachio_gpio_irq_mask(struct irq_data *data) struct pistachio_gpio_bank *bank = irqd_to_bank(data); gpio_mask_writel(bank, GPIO_INTERRUPT_EN, data->hwirq, 0); + gpiochip_disable_irq(&bank->gpio_chip, irqd_to_hwirq(data)); } static void pistachio_gpio_irq_unmask(struct irq_data *data) { struct pistachio_gpio_bank *bank = irqd_to_bank(data); + gpiochip_enable_irq(&bank->gpio_chip, irqd_to_hwirq(data)); gpio_mask_writel(bank, GPIO_INTERRUPT_EN, data->hwirq, 1); } @@ -1312,6 +1315,7 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc) #define GPIO_BANK(_bank, _pin_base, _npins) \ { \ + .instance = (_bank), \ .pin_base = _pin_base, \ .npins = _npins, \ .gpio_chip = { \ @@ -1326,14 +1330,6 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc) .base = _pin_base, \ .ngpio = _npins, \ }, \ - .irq_chip = { \ - .name = "GPIO" #_bank, \ - .irq_startup = pistachio_gpio_irq_startup, \ - .irq_ack = pistachio_gpio_irq_ack, \ - .irq_mask = pistachio_gpio_irq_mask, \ - .irq_unmask = pistachio_gpio_irq_unmask, \ - .irq_set_type = pistachio_gpio_irq_set_type, \ - }, \ } static struct pistachio_gpio_bank pistachio_gpio_banks[] = { @@ -1345,6 +1341,25 @@ static struct pistachio_gpio_bank pistachio_gpio_banks[] = { GPIO_BANK(5, PISTACHIO_PIN_MFIO(80), 10), }; +static void pistachio_gpio_irq_print_chip(struct irq_data *data, + struct seq_file *p) +{ + struct pistachio_gpio_bank *bank = irqd_to_bank(data); + + seq_printf(p, "GPIO%d", bank->instance); +} + +static const struct irq_chip pistachio_gpio_irq_chip = { + .irq_startup = pistachio_gpio_irq_startup, + .irq_ack = pistachio_gpio_irq_ack, + .irq_mask = pistachio_gpio_irq_mask, + .irq_unmask = pistachio_gpio_irq_unmask, + .irq_set_type = pistachio_gpio_irq_set_type, + .irq_print_chip = pistachio_gpio_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int pistachio_gpio_register(struct pistachio_pinctrl *pctl) { struct pistachio_gpio_bank *bank; @@ -1394,7 +1409,7 @@ static int pistachio_gpio_register(struct pistachio_pinctrl *pctl) bank->gpio_chip.fwnode = child; girq = &bank->gpio_chip.irq; - girq->chip = &bank->irq_chip; + gpio_irq_chip_set_chip(girq, &pistachio_gpio_irq_chip); girq->parent_handler = pistachio_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(pctl->dev, 1, diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 190923757cda..0dabbcf68b9f 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -939,11 +939,11 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np, /* cacluate how much properties are supported in current node */ for (i = 0; i < ARRAY_SIZE(prop2); i++) { - if (of_find_property(np, prop2[i].name, NULL)) + if (of_property_present(np, prop2[i].name)) nconfs++; } for (i = 0; i < ARRAY_SIZE(prop4); i++) { - if (of_find_property(np, prop4[i].name, NULL)) + if (of_property_present(np, prop4[i].name)) nconfs++; } if (!nconfs) diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 1409339f0279..c1f36b164ea5 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1313,7 +1313,8 @@ static void st_gpio_irq_mask(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct st_gpio_bank *bank = gpiochip_get_data(gc); - writel(BIT(d->hwirq), bank->base + REG_PIO_CLR_PMASK); + writel(BIT(irqd_to_hwirq(d)), bank->base + REG_PIO_CLR_PMASK); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void st_gpio_irq_unmask(struct irq_data *d) @@ -1321,7 +1322,8 @@ static void st_gpio_irq_unmask(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct st_gpio_bank *bank = gpiochip_get_data(gc); - writel(BIT(d->hwirq), bank->base + REG_PIO_SET_PMASK); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + writel(BIT(irqd_to_hwirq(d)), bank->base + REG_PIO_SET_PMASK); } static int st_gpio_irq_request_resources(struct irq_data *d) @@ -1330,14 +1332,14 @@ static int st_gpio_irq_request_resources(struct irq_data *d) st_gpio_direction_input(gc, d->hwirq); - return gpiochip_lock_as_irq(gc, d->hwirq); + return gpiochip_reqres_irq(gc, d->hwirq); } static void st_gpio_irq_release_resources(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - gpiochip_unlock_as_irq(gc, d->hwirq); + gpiochip_relres_irq(gc, d->hwirq); } static int st_gpio_irq_set_type(struct irq_data *d, unsigned type) @@ -1492,7 +1494,7 @@ static const struct gpio_chip st_gpio_template = { .ngpio = ST_GPIO_PINS_PER_BANK, }; -static struct irq_chip st_gpio_irqchip = { +static const struct irq_chip st_gpio_irqchip = { .name = "GPIO", .irq_request_resources = st_gpio_irq_request_resources, .irq_release_resources = st_gpio_irq_release_resources, @@ -1500,7 +1502,7 @@ static struct irq_chip st_gpio_irqchip = { .irq_mask = st_gpio_irq_mask, .irq_unmask = st_gpio_irq_unmask, .irq_set_type = st_gpio_irq_set_type, - .flags = IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, }; static int st_gpiolib_register_bank(struct st_pinctrl *info, @@ -1570,7 +1572,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info, } girq = &bank->gpio_chip.irq; - girq->chip = &st_gpio_irqchip; + gpio_irq_chip_set_chip(girq, &st_gpio_irqchip); girq->parent_handler = st_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 1181c4b506b1..ab23d7ac3107 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -85,7 +85,6 @@ struct stmfx_pinctrl { struct pinctrl_dev *pctl_dev; struct pinctrl_desc pctl_desc; struct gpio_chip gpio_chip; - struct irq_chip irq_chip; struct mutex lock; /* IRQ bus lock */ unsigned long gpio_valid_mask; /* Cache of IRQ_GPI_* registers for bus_lock */ @@ -427,6 +426,7 @@ static void stmfx_pinctrl_irq_mask(struct irq_data *data) u32 mask = get_mask(data->hwirq); pctl->irq_gpi_src[reg] &= ~mask; + gpiochip_disable_irq(gpio_chip, irqd_to_hwirq(data)); } static void stmfx_pinctrl_irq_unmask(struct irq_data *data) @@ -436,6 +436,7 @@ static void stmfx_pinctrl_irq_unmask(struct irq_data *data) u32 reg = get_reg(data->hwirq); u32 mask = get_mask(data->hwirq); + gpiochip_enable_irq(gpio_chip, irqd_to_hwirq(data)); pctl->irq_gpi_src[reg] |= mask; } @@ -592,6 +593,26 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id) return IRQ_HANDLED; } +static void stmfx_pinctrl_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(d); + struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); + + seq_printf(p, dev_name(pctl->dev)); +} + +static const struct irq_chip stmfx_pinctrl_irq_chip = { + .irq_mask = stmfx_pinctrl_irq_mask, + .irq_unmask = stmfx_pinctrl_irq_unmask, + .irq_set_type = stmfx_pinctrl_irq_set_type, + .irq_bus_lock = stmfx_pinctrl_irq_bus_lock, + .irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock, + .irq_request_resources = stmfx_gpio_irq_request_resources, + .irq_release_resources = stmfx_gpio_irq_release_resources, + .irq_print_chip = stmfx_pinctrl_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, +}; + static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl) { struct pinctrl_gpio_range *gpio_range; @@ -632,7 +653,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) pctl->dev = &pdev->dev; pctl->stmfx = stmfx; - if (!of_find_property(np, "gpio-ranges", NULL)) { + if (!of_property_present(np, "gpio-ranges")) { dev_err(pctl->dev, "missing required gpio-ranges property\n"); return -EINVAL; } @@ -678,17 +699,8 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) pctl->gpio_chip.ngpio = pctl->pctl_desc.npins; pctl->gpio_chip.can_sleep = true; - pctl->irq_chip.name = dev_name(pctl->dev); - pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask; - pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask; - pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type; - pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock; - pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock; - pctl->irq_chip.irq_request_resources = stmfx_gpio_irq_request_resources; - pctl->irq_chip.irq_release_resources = stmfx_gpio_irq_release_resources; - girq = &pctl->gpio_chip.irq; - girq->chip = &pctl->irq_chip; + gpio_irq_chip_set_chip(girq, &stmfx_pinctrl_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; @@ -710,7 +722,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(pctl->dev, irq, NULL, stmfx_pinctrl_irq_thread_fn, IRQF_ONESHOT, - pctl->irq_chip.name, pctl); + dev_name(pctl->dev), pctl); if (ret) { dev_err(pctl->dev, "cannot request irq%d\n", irq); return ret; diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index 0b5ff99641e1..7632ffc3946f 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -99,7 +99,6 @@ struct sx150x_pinctrl { struct pinctrl_dev *pctldev; struct pinctrl_desc pinctrl_desc; struct gpio_chip gpio; - struct irq_chip irq_chip; struct regmap *regmap; struct { u32 sense; @@ -487,19 +486,21 @@ static int sx150x_gpio_direction_output(struct gpio_chip *chip, static void sx150x_irq_mask(struct irq_data *d) { - struct sx150x_pinctrl *pctl = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int n = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); + unsigned int n = irqd_to_hwirq(d); pctl->irq.masked |= BIT(n); + gpiochip_disable_irq(gc, n); } static void sx150x_irq_unmask(struct irq_data *d) { - struct sx150x_pinctrl *pctl = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); - unsigned int n = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); + unsigned int n = irqd_to_hwirq(d); + gpiochip_enable_irq(gc, n); pctl->irq.masked &= ~BIT(n); } @@ -520,14 +521,14 @@ static void sx150x_irq_set_sense(struct sx150x_pinctrl *pctl, static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct sx150x_pinctrl *pctl = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); unsigned int n, val = 0; if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - n = d->hwirq; + n = irqd_to_hwirq(d); if (flow_type & IRQ_TYPE_EDGE_RISING) val |= SX150X_IRQ_TYPE_EDGE_RISING; @@ -562,22 +563,42 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) static void sx150x_irq_bus_lock(struct irq_data *d) { - struct sx150x_pinctrl *pctl = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); mutex_lock(&pctl->lock); } static void sx150x_irq_bus_sync_unlock(struct irq_data *d) { - struct sx150x_pinctrl *pctl = - gpiochip_get_data(irq_data_get_irq_chip_data(d)); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); regmap_write(pctl->regmap, pctl->data->reg_irq_mask, pctl->irq.masked); regmap_write(pctl->regmap, pctl->data->reg_sense, pctl->irq.sense); mutex_unlock(&pctl->lock); } + +static void sx150x_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct sx150x_pinctrl *pctl = gpiochip_get_data(gc); + + seq_printf(p, pctl->client->name); +} + +static const struct irq_chip sx150x_irq_chip = { + .irq_mask = sx150x_irq_mask, + .irq_unmask = sx150x_irq_unmask, + .irq_set_type = sx150x_irq_set_type, + .irq_bus_lock = sx150x_irq_bus_lock, + .irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock, + .irq_print_chip = sx150x_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int sx150x_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config) { @@ -1181,19 +1202,8 @@ static int sx150x_probe(struct i2c_client *client) if (client->irq > 0) { struct gpio_irq_chip *girq; - pctl->irq_chip.irq_mask = sx150x_irq_mask; - pctl->irq_chip.irq_unmask = sx150x_irq_unmask; - pctl->irq_chip.irq_set_type = sx150x_irq_set_type; - pctl->irq_chip.irq_bus_lock = sx150x_irq_bus_lock; - pctl->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; - pctl->irq_chip.name = devm_kstrdup(dev, client->name, - GFP_KERNEL); - if (!pctl->irq_chip.name) - return -ENOMEM; - pctl->irq.masked = ~0; pctl->irq.sense = 0; - /* * Because sx150x_irq_threaded_fn invokes all of the * nested interrupt handlers via handle_nested_irq, @@ -1206,7 +1216,7 @@ static int sx150x_probe(struct i2c_client *client) * called (should not happen) */ girq = &pctl->gpio.irq; - girq->chip = &pctl->irq_chip; + gpio_irq_chip_set_chip(girq, &sx150x_irq_chip); /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; @@ -1219,7 +1229,7 @@ static int sx150x_probe(struct i2c_client *client) sx150x_irq_thread_fn, IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, - pctl->irq_chip.name, pctl); + client->name, pctl); if (ret < 0) return ret; } @@ -1250,7 +1260,7 @@ static int sx150x_probe(struct i2c_client *client) static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x-pinctrl", - .of_match_table = of_match_ptr(sx150x_of_match), + .of_match_table = sx150x_of_match, }, .probe_new = sx150x_probe, .id_table = sx150x_id, diff --git a/drivers/pinctrl/pinctrl-thunderbay.c b/drivers/pinctrl/pinctrl-thunderbay.c deleted file mode 100644 index 7a5ff955877c..000000000000 --- a/drivers/pinctrl/pinctrl-thunderbay.c +++ /dev/null @@ -1,1294 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Thunder Bay SOC pinctrl/GPIO driver - * - * Copyright (C) 2021 Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "core.h" -#include "pinconf.h" -#include "pinctrl-utils.h" -#include "pinmux.h" - -/* Bit 0:2 and 4:6 should be used for mode selection */ -#define THB_GPIO_PINMUX_MODE_0 0x00 -#define THB_GPIO_PINMUX_MODE_1 0x11 -#define THB_GPIO_PINMUX_MODE_2 0x22 -#define THB_GPIO_PINMUX_MODE_3 0x33 -#define THB_GPIO_PINMUX_MODE_4 0x44 - -#define THB_GPIO_PORT_SELECT_MASK BIT(8) -#define THB_GPIO_PAD_DIRECTION_MASK BIT(10) -#define THB_GPIO_SPU_MASK BIT(11) -#define THB_GPIO_PULL_ENABLE_MASK BIT(12) -#define THB_GPIO_PULL_UP_MASK BIT(13) -#define THB_GPIO_PULL_DOWN_MASK BIT(14) -#define THB_GPIO_ENAQ_MASK BIT(15) -/* bit 16-19: Drive Strength for the Pad */ -#define THB_GPIO_DRIVE_STRENGTH_MASK (0xF0000) -#define THB_GPIO_SLEW_RATE_MASK BIT(20) -#define THB_GPIO_SCHMITT_TRIGGER_MASK BIT(21) - -#define THB_GPIO_REG_OFFSET(pin_num) ((pin_num) * (0x4)) -#define THB_MAX_MODE_SUPPORTED (5u) -#define THB_MAX_NPINS_SUPPORTED (67u) - -/* store Pin status */ -static u32 thb_pinx_status[THB_MAX_NPINS_SUPPORTED]; - -struct thunderbay_mux_desc { - u8 mode; - const char *name; -}; - -#define THUNDERBAY_PIN_DESC(pin_number, pin_name, ...) { \ - .number = pin_number, \ - .name = pin_name, \ - .drv_data = &(struct thunderbay_mux_desc[]) { \ - __VA_ARGS__, { } }, \ -} - -#define THUNDERBAY_MUX(pin_mode, pin_function) { \ - .mode = pin_mode, \ - .name = pin_function, \ -} - -struct thunderbay_pin_soc { - const struct pinctrl_pin_desc *pins; - unsigned int npins; -}; - -/** - * struct thunderbay_pinctrl - Intel Thunderbay pinctrl structure - * @pctrl: Pointer to the pin controller device - * @base0: First register base address - * @dev: Pointer to the device structure - * @chip: GPIO chip used by this pin controller - * @soc: Pin control configuration data based on SoC - * @ngroups: Number of pin groups available - * @nfuncs: Number of pin functions available - */ -struct thunderbay_pinctrl { - struct pinctrl_dev *pctrl; - void __iomem *base0; - struct device *dev; - struct gpio_chip chip; - const struct thunderbay_pin_soc *soc; - unsigned int ngroups; - unsigned int nfuncs; -}; - -static const struct pinctrl_pin_desc thunderbay_pins[] = { - THUNDERBAY_PIN_DESC(0, "GPIO0", - THUNDERBAY_MUX(0X0, "I2C0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(1, "GPIO1", - THUNDERBAY_MUX(0X0, "I2C0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(2, "GPIO2", - THUNDERBAY_MUX(0X0, "I2C1_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(3, "GPIO3", - THUNDERBAY_MUX(0X0, "I2C1_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(4, "GPIO4", - THUNDERBAY_MUX(0X0, "I2C2_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(5, "GPIO5", - THUNDERBAY_MUX(0X0, "I2C2_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(6, "GPIO6", - THUNDERBAY_MUX(0X0, "I2C3_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(7, "GPIO7", - THUNDERBAY_MUX(0X0, "I2C3_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(8, "GPIO8", - THUNDERBAY_MUX(0X0, "I2C4_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(9, "GPIO9", - THUNDERBAY_MUX(0X0, "I2C4_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(10, "GPIO10", - THUNDERBAY_MUX(0X0, "UART0_M0"), - THUNDERBAY_MUX(0X1, "RT0_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(11, "GPIO11", - THUNDERBAY_MUX(0X0, "UART0_M0"), - THUNDERBAY_MUX(0X1, "RT0_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(12, "GPIO12", - THUNDERBAY_MUX(0X0, "UART0_M0"), - THUNDERBAY_MUX(0X1, "RT1_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(13, "GPIO13", - THUNDERBAY_MUX(0X0, "UART0_M0"), - THUNDERBAY_MUX(0X1, "RT1_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(14, "GPIO14", - THUNDERBAY_MUX(0X0, "UART1_M0"), - THUNDERBAY_MUX(0X1, "RT2_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "TRIGGER_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(15, "GPIO15", - THUNDERBAY_MUX(0X0, "UART1_M0"), - THUNDERBAY_MUX(0X1, "RT2_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "TRIGGER_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(16, "GPIO16", - THUNDERBAY_MUX(0X0, "UART1_M0"), - THUNDERBAY_MUX(0X1, "RT3_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(17, "GPIO17", - THUNDERBAY_MUX(0X0, "UART1_M0"), - THUNDERBAY_MUX(0X1, "RT3_DSU_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(18, "GPIO18", - THUNDERBAY_MUX(0X0, "SPI0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(19, "GPIO19", - THUNDERBAY_MUX(0X0, "SPI0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(20, "GPIO20", - THUNDERBAY_MUX(0X0, "SPI0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "TPIU_TRACE_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(21, "GPIO21", - THUNDERBAY_MUX(0X0, "SPI0_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "TPIU_TRACE_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(22, "GPIO22", - THUNDERBAY_MUX(0X0, "SPI1_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M0"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(23, "GPIO23", - THUNDERBAY_MUX(0X0, "SPI1_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(24, "GPIO24", - THUNDERBAY_MUX(0X0, "SPI1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_TRACE_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(25, "GPIO25", - THUNDERBAY_MUX(0X0, "SPI1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_TRACE_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(26, "GPIO26", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(27, "GPIO27", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(28, "GPIO28", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(29, "GPIO29", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(30, "GPIO30", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(31, "GPIO31", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(32, "GPIO32", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(33, "GPIO33", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(34, "GPIO34", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DIG_VIEW_0"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(35, "GPIO35", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DIG_VIEW_1"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(36, "GPIO36", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_0"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(37, "GPIO37", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_1"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(38, "GPIO38", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_2"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(39, "GPIO39", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(40, "GPIO40", - THUNDERBAY_MUX(0X0, "ETHER0_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(41, "GPIO41", - THUNDERBAY_MUX(0X0, "POWER_INTERRUPT_MAX_PLATFORM_POWER_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(42, "GPIO42", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(43, "GPIO43", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(44, "GPIO44", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(45, "GPIO45", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(46, "GPIO46", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(47, "GPIO47", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(48, "GPIO48", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(49, "GPIO49", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DEBUG_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(50, "GPIO50", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DIG_VIEW_0"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(51, "GPIO51", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "DIG_VIEW_1"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(52, "GPIO52", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_0"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(53, "GPIO53", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_1"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(54, "GPIO54", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_2"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(55, "GPIO55", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "CPR_IO_OUT_CLK_3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(56, "GPIO56", - THUNDERBAY_MUX(0X0, "ETHER1_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "POWER_INTERRUPT_ICCMAX_VDDD_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(57, "GPIO57", - THUNDERBAY_MUX(0X0, "POWER_INTERRUPT_ICCMAX_VPU_M0"), - THUNDERBAY_MUX(0X1, "TPIU_DATA_M1"), - THUNDERBAY_MUX(0X2, "TPIU_DATA_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(58, "GPIO58", - THUNDERBAY_MUX(0X0, "THERMTRIP_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(59, "GPIO59", - THUNDERBAY_MUX(0X0, "THERMTRIP_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(60, "GPIO60", - THUNDERBAY_MUX(0X0, "SMBUS_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(61, "GPIO61", - THUNDERBAY_MUX(0X0, "SMBUS_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "POWER_INTERRUPT_ICCMAX_VDDD_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(62, "GPIO62", - THUNDERBAY_MUX(0X0, "PLATFORM_RESET_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(63, "GPIO63", - THUNDERBAY_MUX(0X0, "PLATFORM_RESET_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(64, "GPIO64", - THUNDERBAY_MUX(0X0, "PLATFORM_SHUTDOWN_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(65, "GPIO65", - THUNDERBAY_MUX(0X0, "PLATFORM_SHUTDOWN_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), - THUNDERBAY_PIN_DESC(66, "GPIO66", - THUNDERBAY_MUX(0X0, "POWER_INTERRUPT_ICCMAX_MEDIA_M0"), - THUNDERBAY_MUX(0X1, "EMPTY_M1"), - THUNDERBAY_MUX(0X2, "EMPTY_M2"), - THUNDERBAY_MUX(0X3, "EMPTY_M3"), - THUNDERBAY_MUX(0X4, "GPIO_M4")), -}; - -static const struct thunderbay_pin_soc thunderbay_data = { - .pins = thunderbay_pins, - .npins = ARRAY_SIZE(thunderbay_pins), -}; - -static u32 thb_gpio_read_reg(struct gpio_chip *chip, unsigned int pinnr) -{ - struct thunderbay_pinctrl *tpc = gpiochip_get_data(chip); - - return readl(tpc->base0 + THB_GPIO_REG_OFFSET(pinnr)); -} - -static u32 thb_gpio_write_reg(struct gpio_chip *chip, unsigned int pinnr, u32 value) -{ - struct thunderbay_pinctrl *tpc = gpiochip_get_data(chip); - - writel(value, (tpc->base0 + THB_GPIO_REG_OFFSET(pinnr))); - return 0; -} - -static int thb_read_gpio_data(struct gpio_chip *chip, unsigned int offset, unsigned int pad_dir) -{ - int data_offset; - u32 data_reg; - - /* as per GPIO Spec = pad_dir 0:input, 1:output */ - data_offset = 0x2000u + (offset / 32); - if (!pad_dir) - data_offset += 4; - data_reg = thb_gpio_read_reg(chip, data_offset); - - return data_reg & BIT(offset % 32); -} - -static int thb_write_gpio_data(struct gpio_chip *chip, unsigned int offset, unsigned int value) -{ - int data_offset; - u32 data_reg; - - data_offset = 0x2000u + (offset / 32); - - data_reg = thb_gpio_read_reg(chip, data_offset); - - if (value > 0) - data_reg |= BIT(offset % 32); - else - data_reg &= ~BIT(offset % 32); - - return thb_gpio_write_reg(chip, data_offset, data_reg); -} - -static int thunderbay_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - u32 reg = thb_gpio_read_reg(chip, offset); - - /* Return direction only if configured as GPIO else negative error */ - if (reg & THB_GPIO_PORT_SELECT_MASK) - return !(reg & THB_GPIO_PAD_DIRECTION_MASK); - return -EINVAL; -} - -static int thunderbay_gpio_set_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - u32 reg = thb_gpio_read_reg(chip, offset); - - /* set pin as input only if it is GPIO else error */ - if (reg & THB_GPIO_PORT_SELECT_MASK) { - reg &= (~THB_GPIO_PAD_DIRECTION_MASK); - thb_gpio_write_reg(chip, offset, reg); - return 0; - } - return -EINVAL; -} - -static void thunderbay_gpio_set_value(struct gpio_chip *chip, unsigned int offset, int value) -{ - u32 reg = thb_gpio_read_reg(chip, offset); - - /* update pin value only if it is GPIO-output else error */ - if ((reg & THB_GPIO_PORT_SELECT_MASK) && (reg & THB_GPIO_PAD_DIRECTION_MASK)) - thb_write_gpio_data(chip, offset, value); -} - -static int thunderbay_gpio_set_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - u32 reg = thb_gpio_read_reg(chip, offset); - - /* set pin as output only if it is GPIO else error */ - if (reg & THB_GPIO_PORT_SELECT_MASK) { - reg |= THB_GPIO_PAD_DIRECTION_MASK; - thb_gpio_write_reg(chip, offset, reg); - thunderbay_gpio_set_value(chip, offset, value); - return 0; - } - return -EINVAL; -} - -static int thunderbay_gpio_get_value(struct gpio_chip *chip, unsigned int offset) -{ - u32 reg = thb_gpio_read_reg(chip, offset); - int gpio_dir = 0; - - /* Read pin value only if it is GPIO else error */ - if (reg & THB_GPIO_PORT_SELECT_MASK) { - /* 0=in, 1=out */ - gpio_dir = (reg & THB_GPIO_PAD_DIRECTION_MASK) > 0; - - /* Returns negative value when pin is configured as PORT */ - return thb_read_gpio_data(chip, offset, gpio_dir); - } - return -EINVAL; -} - -static int thunderbay_gpiochip_probe(struct thunderbay_pinctrl *tpc) -{ - struct gpio_chip *chip = &tpc->chip; - int ret; - - chip->label = dev_name(tpc->dev); - chip->parent = tpc->dev; - chip->request = gpiochip_generic_request; - chip->free = gpiochip_generic_free; - chip->get_direction = thunderbay_gpio_get_direction; - chip->direction_input = thunderbay_gpio_set_direction_input; - chip->direction_output = thunderbay_gpio_set_direction_output; - chip->get = thunderbay_gpio_get_value; - chip->set = thunderbay_gpio_set_value; - chip->set_config = gpiochip_generic_config; - /* identifies the first GPIO number handled by this chip; or, - * if negative during registration, requests dynamic ID allocation. - * Please pass -1 as base to let gpiolib select the chip base in all possible cases. - * We want to get rid of the static GPIO number space in the long run. - */ - chip->base = -1; - /* Number of GPIOs handled by this controller; the last GPIO handled is (base + ngpio - 1)*/ - chip->ngpio = THB_MAX_NPINS_SUPPORTED; - - /* Register/add Thunder Bay GPIO chip with Linux framework */ - ret = gpiochip_add_data(chip, tpc); - if (ret) - dev_err(tpc->dev, "Failed to add gpiochip\n"); - return ret; -} - -static int thunderbay_request_gpio(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned int pin) -{ - struct thunderbay_pinctrl *tpc = pinctrl_dev_get_drvdata(pctldev); - struct gpio_chip *chip = &tpc->chip; - u32 reg = 0; - - if (thb_pinx_status[pin] == 0u) { - reg = thb_gpio_read_reg(chip, pin); - /* Updates PIN configuration as GPIO and sets GPIO to MODE-4*/ - reg |= (THB_GPIO_PORT_SELECT_MASK | THB_GPIO_PINMUX_MODE_4); - thb_gpio_write_reg(chip, pin, reg); - - /* update pin status as busy */ - thb_pinx_status[pin] = 1u; - - return 0; - } - return -EINVAL; -} - -static void thunderbay_free_gpio(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned int pin) -{ - struct thunderbay_pinctrl *tpc = pinctrl_dev_get_drvdata(pctldev); - struct gpio_chip *chip = &tpc->chip; - u32 reg = 0; - - if (thb_pinx_status[pin] == 1u) { - reg = thb_gpio_read_reg(chip, pin); - - /* Updates PIN configuration from GPIO to PORT */ - reg &= (~THB_GPIO_PORT_SELECT_MASK); - - /* Change Port/gpio mode to default mode-0 */ - reg &= (~THB_GPIO_PINMUX_MODE_4); - - thb_gpio_write_reg(chip, pin, reg); - - /* update pin status as free */ - thb_pinx_status[pin] = 0u; - } -} - -static int thb_pinctrl_set_mux(struct pinctrl_dev *pctldev, - unsigned int func_select, unsigned int group_select) -{ - struct thunderbay_pinctrl *tpc = pinctrl_dev_get_drvdata(pctldev); - struct gpio_chip *chip = &tpc->chip; - struct function_desc *function; - unsigned int i, pin_mode; - struct group_desc *group; - int ret = -EINVAL; - u32 reg = 0u; - - group = pinctrl_generic_get_group(pctldev, group_select); - if (!group) - return -EINVAL; - - function = pinmux_generic_get_function(pctldev, func_select); - if (!function) - return -EINVAL; - - pin_mode = *(unsigned int *)(function->data); - - /* Change modes for pins in the selected group */ - for (i = 0; i < group->num_pins; i++) { - reg = thb_gpio_read_reg(chip, group->pins[i]); - - switch (pin_mode) { - case 0u: - reg |= THB_GPIO_PINMUX_MODE_0; - break; - case 1u: - reg |= THB_GPIO_PINMUX_MODE_1; - break; - case 2u: - reg |= THB_GPIO_PINMUX_MODE_2; - break; - case 3u: - reg |= THB_GPIO_PINMUX_MODE_3; - break; - case 4u: - reg |= THB_GPIO_PINMUX_MODE_4; - break; - default: - return -EINVAL; - } - - ret = thb_gpio_write_reg(chip, group->pins[i], reg); - if (~ret) { - /* update pin status as busy */ - thb_pinx_status[group->pins[i]] = 1u; - } - } - return ret; -} - -static int thunderbay_build_groups(struct thunderbay_pinctrl *tpc) -{ - struct group_desc *thunderbay_groups; - int i; - - tpc->ngroups = tpc->soc->npins; - thunderbay_groups = devm_kcalloc(tpc->dev, tpc->ngroups, - sizeof(*thunderbay_groups), GFP_KERNEL); - if (!thunderbay_groups) - return -ENOMEM; - - for (i = 0; i < tpc->ngroups; i++) { - struct group_desc *group = thunderbay_groups + i; - const struct pinctrl_pin_desc *pin_info = thunderbay_pins + i; - - group->name = pin_info->name; - group->pins = (int *)&pin_info->number; - pinctrl_generic_add_group(tpc->pctrl, group->name, - group->pins, 1, NULL); - } - return 0; -} - -static int thunderbay_add_functions(struct thunderbay_pinctrl *tpc, struct function_desc *funcs) -{ - int i; - - /* Assign the groups for each function */ - for (i = 0; i < tpc->nfuncs; i++) { - struct function_desc *func = &funcs[i]; - const char **group_names; - unsigned int grp_idx = 0; - int j; - - group_names = devm_kcalloc(tpc->dev, func->num_group_names, - sizeof(*group_names), GFP_KERNEL); - if (!group_names) - return -ENOMEM; - - for (j = 0; j < tpc->soc->npins; j++) { - const struct pinctrl_pin_desc *pin_info = &thunderbay_pins[j]; - struct thunderbay_mux_desc *pin_mux; - - for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) { - if (!strcmp(pin_mux->name, func->name)) - group_names[grp_idx++] = pin_info->name; - } - } - - func->group_names = group_names; - } - - /* Add all functions */ - for (i = 0; i < tpc->nfuncs; i++) { - pinmux_generic_add_function(tpc->pctrl, - funcs[i].name, - funcs[i].group_names, - funcs[i].num_group_names, - funcs[i].data); - } - - return 0; -} - -static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc) -{ - struct function_desc *thunderbay_funcs; - void *ptr; - int pin; - int ret; - - /* - * Allocate maximum possible number of functions. Assume every pin - * being part of 8 (hw maximum) globally unique muxes. - */ - tpc->nfuncs = 0; - thunderbay_funcs = kcalloc(tpc->soc->npins * 8, - sizeof(*thunderbay_funcs), GFP_KERNEL); - if (!thunderbay_funcs) - return -ENOMEM; - - /* Setup 1 function for each unique mux */ - for (pin = 0; pin < tpc->soc->npins; pin++) { - const struct pinctrl_pin_desc *pin_info = thunderbay_pins + pin; - struct thunderbay_mux_desc *pin_mux; - - for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) { - struct function_desc *func; - - /* Check if we already have function for this mux */ - for (func = thunderbay_funcs; func->name; func++) { - if (!strcmp(pin_mux->name, func->name)) { - func->num_group_names++; - break; - } - } - - if (!func->name) { - func->name = pin_mux->name; - func->num_group_names = 1; - func->data = (int *)&pin_mux->mode; - tpc->nfuncs++; - } - } - } - - /* Reallocate memory based on actual number of functions */ - ptr = krealloc(thunderbay_funcs, - tpc->nfuncs * sizeof(*thunderbay_funcs), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - thunderbay_funcs = ptr; - ret = thunderbay_add_functions(tpc, thunderbay_funcs); - - kfree(thunderbay_funcs); - return ret; -} - -static int thunderbay_pinconf_set_tristate(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg |= THB_GPIO_ENAQ_MASK; - else - reg &= ~THB_GPIO_ENAQ_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_tristate(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = (reg & THB_GPIO_ENAQ_MASK) > 0; - - return 0; -} - -static int thunderbay_pinconf_set_pulldown(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg |= THB_GPIO_PULL_DOWN_MASK; - else - reg &= ~THB_GPIO_PULL_DOWN_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_pulldown(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg = 0; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_PULL_DOWN_MASK) > 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_set_pullup(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg &= ~THB_GPIO_PULL_UP_MASK; - else - reg |= THB_GPIO_PULL_UP_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_pullup(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_PULL_UP_MASK) == 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_set_opendrain(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg &= ~THB_GPIO_PULL_ENABLE_MASK; - else - reg |= THB_GPIO_PULL_ENABLE_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_opendrain(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_PULL_ENABLE_MASK) == 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_set_pushpull(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg |= THB_GPIO_PULL_ENABLE_MASK; - else - reg &= ~THB_GPIO_PULL_ENABLE_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_pushpull(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_PULL_ENABLE_MASK) > 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_set_drivestrength(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - - /* Drive Strength: 0x0 to 0xF */ - if (config <= 0xF) { - reg = (reg | config); - return thb_gpio_write_reg(chip, pin, reg); - } - - return -EINVAL; -} - -static int thunderbay_pinconf_get_drivestrength(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - reg = (reg & THB_GPIO_DRIVE_STRENGTH_MASK) >> 16; - *config = (reg > 0) ? reg : 0; - - return 0; -} - -static int thunderbay_pinconf_set_schmitt(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg |= THB_GPIO_SCHMITT_TRIGGER_MASK; - else - reg &= ~THB_GPIO_SCHMITT_TRIGGER_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_schmitt(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_SCHMITT_TRIGGER_MASK) > 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_set_slew_rate(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg = 0; - - reg = thb_gpio_read_reg(chip, pin); - if (config > 0) - reg |= THB_GPIO_SLEW_RATE_MASK; - else - reg &= ~THB_GPIO_SLEW_RATE_MASK; - - return thb_gpio_write_reg(chip, pin, reg); -} - -static int thunderbay_pinconf_get_slew_rate(struct thunderbay_pinctrl *tpc, - unsigned int pin, u32 *config) -{ - struct gpio_chip *chip = &tpc->chip; - u32 reg; - - reg = thb_gpio_read_reg(chip, pin); - *config = ((reg & THB_GPIO_SLEW_RATE_MASK) > 0) ? 1 : 0; - - return 0; -} - -static int thunderbay_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *config) -{ - struct thunderbay_pinctrl *tpc = pinctrl_dev_get_drvdata(pctldev); - enum pin_config_param param = pinconf_to_config_param(*config); - u32 arg; - int ret; - - switch (param) { - case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - ret = thunderbay_pinconf_get_tristate(tpc, pin, &arg); - break; - - case PIN_CONFIG_BIAS_PULL_DOWN: - ret = thunderbay_pinconf_get_pulldown(tpc, pin, &arg); - break; - - case PIN_CONFIG_BIAS_PULL_UP: - ret = thunderbay_pinconf_get_pullup(tpc, pin, &arg); - break; - - case PIN_CONFIG_DRIVE_OPEN_DRAIN: - ret = thunderbay_pinconf_get_opendrain(tpc, pin, &arg); - break; - - case PIN_CONFIG_DRIVE_PUSH_PULL: - ret = thunderbay_pinconf_get_pushpull(tpc, pin, &arg); - break; - - case PIN_CONFIG_DRIVE_STRENGTH: - ret = thunderbay_pinconf_get_drivestrength(tpc, pin, &arg); - break; - - case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - ret = thunderbay_pinconf_get_schmitt(tpc, pin, &arg); - break; - - case PIN_CONFIG_SLEW_RATE: - ret = thunderbay_pinconf_get_slew_rate(tpc, pin, &arg); - break; - - default: - return -ENOTSUPP; - } - - *config = pinconf_to_config_packed(param, arg); - - return ret; -} - -static int thunderbay_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *configs, unsigned int num_configs) -{ - struct thunderbay_pinctrl *tpc = pinctrl_dev_get_drvdata(pctldev); - enum pin_config_param param; - unsigned int pinconf; - int ret = 0; - u32 arg; - - for (pinconf = 0; pinconf < num_configs; pinconf++) { - param = pinconf_to_config_param(configs[pinconf]); - arg = pinconf_to_config_argument(configs[pinconf]); - - switch (param) { - case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - ret = thunderbay_pinconf_set_tristate(tpc, pin, arg); - break; - - case PIN_CONFIG_BIAS_PULL_DOWN: - ret = thunderbay_pinconf_set_pulldown(tpc, pin, arg); - break; - - case PIN_CONFIG_BIAS_PULL_UP: - ret = thunderbay_pinconf_set_pullup(tpc, pin, arg); - break; - - case PIN_CONFIG_DRIVE_OPEN_DRAIN: - ret = thunderbay_pinconf_set_opendrain(tpc, pin, arg); - break; - - case PIN_CONFIG_DRIVE_PUSH_PULL: - ret = thunderbay_pinconf_set_pushpull(tpc, pin, arg); - break; - - case PIN_CONFIG_DRIVE_STRENGTH: - ret = thunderbay_pinconf_set_drivestrength(tpc, pin, arg); - break; - - case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - ret = thunderbay_pinconf_set_schmitt(tpc, pin, arg); - break; - - case PIN_CONFIG_SLEW_RATE: - ret = thunderbay_pinconf_set_slew_rate(tpc, pin, arg); - break; - - default: - return -ENOTSUPP; - } - } - return ret; -} - -static const struct pinctrl_ops thunderbay_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 = pinconf_generic_dt_node_to_map_all, - .dt_free_map = pinconf_generic_dt_free_map, -}; - -static const struct pinmux_ops thunderbay_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 = thb_pinctrl_set_mux, - .gpio_request_enable = thunderbay_request_gpio, - .gpio_disable_free = thunderbay_free_gpio, -}; - -static const struct pinconf_ops thunderbay_confops = { - .is_generic = true, - .pin_config_get = thunderbay_pinconf_get, - .pin_config_set = thunderbay_pinconf_set, -}; - -static struct pinctrl_desc thunderbay_pinctrl_desc = { - .name = "thunderbay-pinmux", - .pctlops = &thunderbay_pctlops, - .pmxops = &thunderbay_pmxops, - .confops = &thunderbay_confops, - .owner = THIS_MODULE, -}; - -static const struct of_device_id thunderbay_pinctrl_match[] = { - { - .compatible = "intel,thunderbay-pinctrl", - .data = &thunderbay_data - }, - {} -}; - -static int thunderbay_pinctrl_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id; - struct device *dev = &pdev->dev; - struct thunderbay_pinctrl *tpc; - int ret; - - of_id = of_match_node(thunderbay_pinctrl_match, pdev->dev.of_node); - if (!of_id) - return -ENODEV; - - tpc = devm_kzalloc(dev, sizeof(*tpc), GFP_KERNEL); - if (!tpc) - return -ENOMEM; - - tpc->dev = dev; - tpc->soc = of_id->data; - - tpc->base0 = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(tpc->base0)) - return PTR_ERR(tpc->base0); - - thunderbay_pinctrl_desc.pins = tpc->soc->pins; - thunderbay_pinctrl_desc.npins = tpc->soc->npins; - - /* Register pinctrl */ - tpc->pctrl = devm_pinctrl_register(dev, &thunderbay_pinctrl_desc, tpc); - if (IS_ERR(tpc->pctrl)) - return PTR_ERR(tpc->pctrl); - - /* Setup pinmux groups */ - ret = thunderbay_build_groups(tpc); - if (ret) - return ret; - - /* Setup pinmux functions */ - ret = thunderbay_build_functions(tpc); - if (ret) - return ret; - - /* Setup GPIO */ - ret = thunderbay_gpiochip_probe(tpc); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, tpc); - - return 0; -} - -static struct platform_driver thunderbay_pinctrl_driver = { - .driver = { - .name = "thunderbay-pinctrl", - .of_match_table = thunderbay_pinctrl_match, - }, - .probe = thunderbay_pinctrl_probe, -}; - -builtin_platform_driver(thunderbay_pinctrl_driver); - -MODULE_AUTHOR("Lakshmi Sowjanya D "); -MODULE_AUTHOR("Kiran Kumar S "); -MODULE_DESCRIPTION("Intel Thunder Bay Pinctrl/GPIO Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index 3a03beb8a755..858abb23b337 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -107,243 +107,6 @@ enum xway_mux { XWAY_MUX_NONE = 0xffff, }; -/* --------- DEPRECATED: xr9 related code --------- */ -/* ---------- use xrx100/xrx200 instead ---------- */ -#define XR9_MAX_PIN 56 - -static const struct ltq_mfp_pin xway_mfp[] = { - /* pin f0 f1 f2 f3 */ - MFP_XWAY(GPIO0, GPIO, EXIN, NONE, TDM), - MFP_XWAY(GPIO1, GPIO, EXIN, NONE, NONE), - MFP_XWAY(GPIO2, GPIO, CGU, EXIN, GPHY), - MFP_XWAY(GPIO3, GPIO, CGU, NONE, PCI), - MFP_XWAY(GPIO4, GPIO, STP, NONE, ASC), - MFP_XWAY(GPIO5, GPIO, STP, GPHY, NONE), - MFP_XWAY(GPIO6, GPIO, STP, GPT, ASC), - MFP_XWAY(GPIO7, GPIO, CGU, PCI, GPHY), - MFP_XWAY(GPIO8, GPIO, CGU, NMI, NONE), - MFP_XWAY(GPIO9, GPIO, ASC, SPI, EXIN), - MFP_XWAY(GPIO10, GPIO, ASC, SPI, NONE), - MFP_XWAY(GPIO11, GPIO, ASC, PCI, SPI), - MFP_XWAY(GPIO12, GPIO, ASC, NONE, NONE), - MFP_XWAY(GPIO13, GPIO, EBU, SPI, NONE), - MFP_XWAY(GPIO14, GPIO, CGU, PCI, NONE), - MFP_XWAY(GPIO15, GPIO, SPI, JTAG, NONE), - MFP_XWAY(GPIO16, GPIO, SPI, NONE, JTAG), - MFP_XWAY(GPIO17, GPIO, SPI, NONE, JTAG), - MFP_XWAY(GPIO18, GPIO, SPI, NONE, JTAG), - MFP_XWAY(GPIO19, GPIO, PCI, NONE, NONE), - MFP_XWAY(GPIO20, GPIO, JTAG, NONE, NONE), - MFP_XWAY(GPIO21, GPIO, PCI, EBU, GPT), - MFP_XWAY(GPIO22, GPIO, SPI, NONE, NONE), - MFP_XWAY(GPIO23, GPIO, EBU, PCI, STP), - MFP_XWAY(GPIO24, GPIO, EBU, TDM, PCI), - MFP_XWAY(GPIO25, GPIO, TDM, NONE, ASC), - MFP_XWAY(GPIO26, GPIO, EBU, NONE, TDM), - MFP_XWAY(GPIO27, GPIO, TDM, NONE, ASC), - MFP_XWAY(GPIO28, GPIO, GPT, NONE, NONE), - MFP_XWAY(GPIO29, GPIO, PCI, NONE, NONE), - MFP_XWAY(GPIO30, GPIO, PCI, NONE, NONE), - MFP_XWAY(GPIO31, GPIO, EBU, PCI, NONE), - MFP_XWAY(GPIO32, GPIO, NONE, NONE, EBU), - MFP_XWAY(GPIO33, GPIO, NONE, NONE, EBU), - MFP_XWAY(GPIO34, GPIO, NONE, NONE, EBU), - MFP_XWAY(GPIO35, GPIO, NONE, NONE, EBU), - MFP_XWAY(GPIO36, GPIO, SIN, NONE, EBU), - MFP_XWAY(GPIO37, GPIO, PCI, NONE, NONE), - MFP_XWAY(GPIO38, GPIO, PCI, NONE, NONE), - MFP_XWAY(GPIO39, GPIO, EXIN, NONE, NONE), - MFP_XWAY(GPIO40, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO41, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE), - MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE), - MFP_XWAY(GPIO44, GPIO, MII, SIN, GPHY), - MFP_XWAY(GPIO45, GPIO, NONE, GPHY, SIN), - MFP_XWAY(GPIO46, GPIO, NONE, NONE, EXIN), - MFP_XWAY(GPIO47, GPIO, MII, GPHY, SIN), - MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE), - MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE), - MFP_XWAY(GPIO50, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO51, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO52, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO53, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO54, GPIO, NONE, NONE, NONE), - MFP_XWAY(GPIO55, GPIO, NONE, NONE, NONE), -}; - -static const unsigned pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO19, GPIO35}; -static const unsigned pins_asc0[] = {GPIO11, GPIO12}; -static const unsigned pins_asc0_cts_rts[] = {GPIO9, GPIO10}; -static const unsigned pins_stp[] = {GPIO4, GPIO5, GPIO6}; -static const unsigned pins_nmi[] = {GPIO8}; -static const unsigned pins_mdio[] = {GPIO42, GPIO43}; - -static const unsigned pins_gphy0_led0[] = {GPIO5}; -static const unsigned pins_gphy0_led1[] = {GPIO7}; -static const unsigned pins_gphy0_led2[] = {GPIO2}; -static const unsigned pins_gphy1_led0[] = {GPIO44}; -static const unsigned pins_gphy1_led1[] = {GPIO45}; -static const unsigned pins_gphy1_led2[] = {GPIO47}; - -static const unsigned pins_ebu_a24[] = {GPIO13}; -static const unsigned pins_ebu_clk[] = {GPIO21}; -static const unsigned pins_ebu_cs1[] = {GPIO23}; -static const unsigned pins_ebu_a23[] = {GPIO24}; -static const unsigned pins_ebu_wait[] = {GPIO26}; -static const unsigned pins_ebu_a25[] = {GPIO31}; -static const unsigned pins_ebu_rdy[] = {GPIO48}; -static const unsigned pins_ebu_rd[] = {GPIO49}; - -static const unsigned pins_nand_ale[] = {GPIO13}; -static const unsigned pins_nand_cs1[] = {GPIO23}; -static const unsigned pins_nand_cle[] = {GPIO24}; -static const unsigned pins_nand_rdy[] = {GPIO48}; -static const unsigned pins_nand_rd[] = {GPIO49}; - -static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9}; - -static const unsigned pins_exin0[] = {GPIO0}; -static const unsigned pins_exin1[] = {GPIO1}; -static const unsigned pins_exin2[] = {GPIO2}; -static const unsigned pins_exin3[] = {GPIO39}; -static const unsigned pins_exin4[] = {GPIO46}; -static const unsigned pins_exin5[] = {GPIO9}; - -static const unsigned pins_spi[] = {GPIO16, GPIO17, GPIO18}; -static const unsigned pins_spi_cs1[] = {GPIO15}; -static const unsigned pins_spi_cs2[] = {GPIO22}; -static const unsigned pins_spi_cs3[] = {GPIO13}; -static const unsigned pins_spi_cs4[] = {GPIO10}; -static const unsigned pins_spi_cs5[] = {GPIO9}; -static const unsigned pins_spi_cs6[] = {GPIO11}; - -static const unsigned pins_gpt1[] = {GPIO28}; -static const unsigned pins_gpt2[] = {GPIO21}; -static const unsigned pins_gpt3[] = {GPIO6}; - -static const unsigned pins_clkout0[] = {GPIO8}; -static const unsigned pins_clkout1[] = {GPIO7}; -static const unsigned pins_clkout2[] = {GPIO3}; -static const unsigned pins_clkout3[] = {GPIO2}; - -static const unsigned pins_pci_gnt1[] = {GPIO30}; -static const unsigned pins_pci_gnt2[] = {GPIO23}; -static const unsigned pins_pci_gnt3[] = {GPIO19}; -static const unsigned pins_pci_gnt4[] = {GPIO38}; -static const unsigned pins_pci_req1[] = {GPIO29}; -static const unsigned pins_pci_req2[] = {GPIO31}; -static const unsigned pins_pci_req3[] = {GPIO3}; -static const unsigned pins_pci_req4[] = {GPIO37}; - -static const struct ltq_pin_group xway_grps[] = { - GRP_MUX("exin0", EXIN, pins_exin0), - GRP_MUX("exin1", EXIN, pins_exin1), - GRP_MUX("exin2", EXIN, pins_exin2), - GRP_MUX("jtag", JTAG, pins_jtag), - GRP_MUX("ebu a23", EBU, pins_ebu_a23), - GRP_MUX("ebu a24", EBU, pins_ebu_a24), - GRP_MUX("ebu a25", EBU, pins_ebu_a25), - GRP_MUX("ebu clk", EBU, pins_ebu_clk), - GRP_MUX("ebu cs1", EBU, pins_ebu_cs1), - GRP_MUX("ebu wait", EBU, pins_ebu_wait), - GRP_MUX("nand ale", EBU, pins_nand_ale), - GRP_MUX("nand cs1", EBU, pins_nand_cs1), - GRP_MUX("nand cle", EBU, pins_nand_cle), - GRP_MUX("spi", SPI, pins_spi), - GRP_MUX("spi_cs1", SPI, pins_spi_cs1), - GRP_MUX("spi_cs2", SPI, pins_spi_cs2), - GRP_MUX("spi_cs3", SPI, pins_spi_cs3), - GRP_MUX("spi_cs4", SPI, pins_spi_cs4), - GRP_MUX("spi_cs5", SPI, pins_spi_cs5), - GRP_MUX("spi_cs6", SPI, pins_spi_cs6), - GRP_MUX("asc0", ASC, pins_asc0), - GRP_MUX("asc0 cts rts", ASC, pins_asc0_cts_rts), - GRP_MUX("stp", STP, pins_stp), - GRP_MUX("nmi", NMI, pins_nmi), - GRP_MUX("gpt1", GPT, pins_gpt1), - GRP_MUX("gpt2", GPT, pins_gpt2), - GRP_MUX("gpt3", GPT, pins_gpt3), - GRP_MUX("clkout0", CGU, pins_clkout0), - GRP_MUX("clkout1", CGU, pins_clkout1), - GRP_MUX("clkout2", CGU, pins_clkout2), - GRP_MUX("clkout3", CGU, pins_clkout3), - GRP_MUX("gnt1", PCI, pins_pci_gnt1), - GRP_MUX("gnt2", PCI, pins_pci_gnt2), - GRP_MUX("gnt3", PCI, pins_pci_gnt3), - GRP_MUX("req1", PCI, pins_pci_req1), - GRP_MUX("req2", PCI, pins_pci_req2), - GRP_MUX("req3", PCI, pins_pci_req3), -/* xrx only */ - GRP_MUX("nand rdy", EBU, pins_nand_rdy), - GRP_MUX("nand rd", EBU, pins_nand_rd), - GRP_MUX("exin3", EXIN, pins_exin3), - GRP_MUX("exin4", EXIN, pins_exin4), - GRP_MUX("exin5", EXIN, pins_exin5), - GRP_MUX("gnt4", PCI, pins_pci_gnt4), - GRP_MUX("req4", PCI, pins_pci_gnt4), - GRP_MUX("mdio", MDIO, pins_mdio), - GRP_MUX("gphy0 led0", GPHY, pins_gphy0_led0), - GRP_MUX("gphy0 led1", GPHY, pins_gphy0_led1), - GRP_MUX("gphy0 led2", GPHY, pins_gphy0_led2), - GRP_MUX("gphy1 led0", GPHY, pins_gphy1_led0), - GRP_MUX("gphy1 led1", GPHY, pins_gphy1_led1), - GRP_MUX("gphy1 led2", GPHY, pins_gphy1_led2), -}; - -static const char * const xway_pci_grps[] = {"gnt1", "gnt2", - "gnt3", "req1", - "req2", "req3"}; -static const char * const xway_spi_grps[] = {"spi", "spi_cs1", - "spi_cs2", "spi_cs3", - "spi_cs4", "spi_cs5", - "spi_cs6"}; -static const char * const xway_cgu_grps[] = {"clkout0", "clkout1", - "clkout2", "clkout3"}; -static const char * const xway_ebu_grps[] = {"ebu a23", "ebu a24", - "ebu a25", "ebu cs1", - "ebu wait", "ebu clk", - "nand ale", "nand cs1", - "nand cle"}; -static const char * const xway_exin_grps[] = {"exin0", "exin1", "exin2"}; -static const char * const xway_gpt_grps[] = {"gpt1", "gpt2", "gpt3"}; -static const char * const xway_asc_grps[] = {"asc0", "asc0 cts rts"}; -static const char * const xway_jtag_grps[] = {"jtag"}; -static const char * const xway_stp_grps[] = {"stp"}; -static const char * const xway_nmi_grps[] = {"nmi"}; - -/* ar9/vr9/gr9 */ -static const char * const xrx_mdio_grps[] = {"mdio"}; -static const char * const xrx_gphy_grps[] = {"gphy0 led0", "gphy0 led1", - "gphy0 led2", "gphy1 led0", - "gphy1 led1", "gphy1 led2"}; -static const char * const xrx_ebu_grps[] = {"ebu a23", "ebu a24", - "ebu a25", "ebu cs1", - "ebu wait", "ebu clk", - "nand ale", "nand cs1", - "nand cle", "nand rdy", - "nand rd"}; -static const char * const xrx_exin_grps[] = {"exin0", "exin1", "exin2", - "exin3", "exin4", "exin5"}; -static const char * const xrx_pci_grps[] = {"gnt1", "gnt2", - "gnt3", "gnt4", - "req1", "req2", - "req3", "req4"}; - -static const struct ltq_pmx_func xrx_funcs[] = { - {"spi", ARRAY_AND_SIZE(xway_spi_grps)}, - {"asc", ARRAY_AND_SIZE(xway_asc_grps)}, - {"cgu", ARRAY_AND_SIZE(xway_cgu_grps)}, - {"jtag", ARRAY_AND_SIZE(xway_jtag_grps)}, - {"exin", ARRAY_AND_SIZE(xrx_exin_grps)}, - {"stp", ARRAY_AND_SIZE(xway_stp_grps)}, - {"gpt", ARRAY_AND_SIZE(xway_gpt_grps)}, - {"nmi", ARRAY_AND_SIZE(xway_nmi_grps)}, - {"pci", ARRAY_AND_SIZE(xrx_pci_grps)}, - {"ebu", ARRAY_AND_SIZE(xrx_ebu_grps)}, - {"mdio", ARRAY_AND_SIZE(xrx_mdio_grps)}, - {"gphy", ARRAY_AND_SIZE(xrx_gphy_grps)}, -}; - /* --------- ase related code --------- */ #define ASE_MAX_PIN 32 @@ -1611,18 +1374,6 @@ struct pinctrl_xway_soc { unsigned int num_exin; }; -/* xway xr9 series (DEPRECATED: Use XWAY xRX100/xRX200 Family) */ -static struct pinctrl_xway_soc xr9_pinctrl = { - .pin_count = XR9_MAX_PIN, - .mfp = xway_mfp, - .grps = xway_grps, - .num_grps = ARRAY_SIZE(xway_grps), - .funcs = xrx_funcs, - .num_funcs = ARRAY_SIZE(xrx_funcs), - .exin = xway_exin_pin_map, - .num_exin = 6 -}; - /* XWAY AMAZON Family */ static struct pinctrl_xway_soc ase_pinctrl = { .pin_count = ASE_MAX_PIN, @@ -1689,9 +1440,6 @@ static struct pinctrl_gpio_range xway_gpio_range = { }; static const struct of_device_id xway_match[] = { - { .compatible = "lantiq,pinctrl-xway", .data = &danube_pinctrl}, /*DEPRECATED*/ - { .compatible = "lantiq,pinctrl-xr9", .data = &xr9_pinctrl}, /*DEPRECATED*/ - { .compatible = "lantiq,pinctrl-ase", .data = &ase_pinctrl}, /*DEPRECATED*/ { .compatible = "lantiq,ase-pinctrl", .data = &ase_pinctrl}, { .compatible = "lantiq,danube-pinctrl", .data = &danube_pinctrl}, { .compatible = "lantiq,xrx100-pinctrl", .data = &xrx100_pinctrl}, diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 62d4810cfee1..e52cfab8d5ae 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -80,6 +80,17 @@ config PINCTRL_IPQ6018 Qualcomm Technologies Inc. IPQ6018 platform. Select this for IPQ6018. +config PINCTRL_IPQ9574 + tristate "Qualcomm Technologies, Inc. IPQ9574 pin controller driver" + depends on OF || COMPILE_TEST + depends on ARM64 || COMPILE_TEST + 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. IPQ9574 platform. Select this for + IPQ9574. + config PINCTRL_MSM8226 tristate "Qualcomm 8226 pin controller driver" depends on OF @@ -417,6 +428,16 @@ config PINCTRL_SDX65 Qualcomm Technologies Inc TLMM block found on the Qualcomm Technologies Inc SDX65 platform. +config PINCTRL_SM7150 + tristate "Qualcomm Technologies Inc SM7150 pin controller driver" + depends on OF + depends on ARM64 || COMPILE_TEST + 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 SM7150 platform. + config PINCTRL_SM8150 tristate "Qualcomm Technologies Inc SM8150 pin controller driver" depends on OF diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index bea53b52275b..521b021b74ba 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_IPQ5332) += pinctrl-ipq5332.o obj-$(CONFIG_PINCTRL_IPQ8074) += pinctrl-ipq8074.o obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o +obj-$(CONFIG_PINCTRL_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o @@ -44,6 +45,7 @@ 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_SM7150) += pinctrl-sm7150.o obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_SM8250_LPASS_LPI) += pinctrl-sm8250-lpass-lpi.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c new file mode 100644 index 000000000000..7f057b62475f --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c @@ -0,0 +1,826 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright (c) 2023 The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#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 = (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 = 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 = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +static const struct pinctrl_pin_desc ipq9574_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"), +}; + +#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); + +enum ipq9574_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_audio_pdm0, + msm_mux_audio_pdm1, + msm_mux_audio_pri, + msm_mux_audio_sec, + msm_mux_blsp0_spi, + msm_mux_blsp0_uart, + msm_mux_blsp1_i2c, + msm_mux_blsp1_spi, + msm_mux_blsp1_uart, + msm_mux_blsp2_i2c, + msm_mux_blsp2_spi, + msm_mux_blsp2_uart, + msm_mux_blsp3_i2c, + msm_mux_blsp3_spi, + msm_mux_blsp3_uart, + msm_mux_blsp4_i2c, + msm_mux_blsp4_spi, + msm_mux_blsp4_uart, + msm_mux_blsp5_i2c, + msm_mux_blsp5_uart, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_cxc0, + msm_mux_cxc1, + msm_mux_dbg_out, + msm_mux_dwc_ddrphy, + msm_mux_gcc_plltest, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_mac, + msm_mux_mdc, + msm_mux_mdio, + msm_mux_pcie0_clk, + msm_mux_pcie0_wake, + msm_mux_pcie1_clk, + msm_mux_pcie1_wake, + msm_mux_pcie2_clk, + msm_mux_pcie2_wake, + msm_mux_pcie3_clk, + msm_mux_pcie3_wake, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_pta, + msm_mux_pwm, + 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_traceclk_b, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracectl_b, + msm_mux_qdss_tracedata_a, + msm_mux_qdss_tracedata_b, + msm_mux_qspi_data, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_rx0, + msm_mux_rx1, + msm_mux_sdc_data, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_rclk, + msm_mux_tsens_max, + msm_mux_wci20, + msm_mux_wci21, + msm_mux_wsa_swrm, + msm_mux__, +}; + +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", +}; + +static const char * const sdc_data_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio6", + "gpio7", + "gpio8", + "gpio9", +}; + +static const char * const qspi_data_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", +}; + +static const char * const qdss_traceclk_b_groups[] = { + "gpio0", +}; + +static const char * const qdss_tracectl_b_groups[] = { + "gpio1", +}; + +static const char * const qdss_tracedata_b_groups[] = { + "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", "gpio9", + "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", + "gpio17", +}; + +static const char * const sdc_cmd_groups[] = { + "gpio4", +}; + +static const char * const qspi_cs_groups[] = { + "gpio4", +}; + +static const char * const sdc_clk_groups[] = { + "gpio5", +}; + +static const char * const qspi_clk_groups[] = { + "gpio5", +}; + +static const char * const sdc_rclk_groups[] = { + "gpio10", +}; + +static const char * const blsp0_spi_groups[] = { + "gpio11", "gpio12", "gpio13", "gpio14", +}; + +static const char * const blsp0_uart_groups[] = { + "gpio11", "gpio12", "gpio13", "gpio14", +}; + +static const char * const blsp3_spi_groups[] = { + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", +}; + +static const char * const blsp3_i2c_groups[] = { + "gpio15", "gpio16", +}; + +static const char * const blsp3_uart_groups[] = { + "gpio15", "gpio16", "gpio17", "gpio18", +}; + +static const char * const dbg_out_groups[] = { + "gpio17", +}; + +static const char * const cri_trng0_groups[] = { + "gpio20", "gpio38", +}; + +static const char * const cri_trng1_groups[] = { + "gpio21", "gpio34", +}; + +static const char * const pcie0_clk_groups[] = { + "gpio22", +}; + +static const char * const pta_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio54", "gpio55", "gpio56", "gpio61", + "gpio62", "gpio63", +}; + +static const char * const wci21_groups[] = { + "gpio23", "gpio24", +}; + +static const char * const cxc0_groups[] = { + "gpio23", "gpio24", +}; + +static const char * const pcie0_wake_groups[] = { + "gpio24", +}; + +static const char * const qdss_cti_trig_out_b0_groups[] = { + "gpio24", +}; + +static const char * const pcie1_clk_groups[] = { + "gpio25", +}; + +static const char * const qdss_cti_trig_in_b0_groups[] = { + "gpio25", +}; + +static const char * const atest_char0_groups[] = { + "gpio26", +}; + +static const char * const qdss_cti_trig_out_b1_groups[] = { + "gpio26", +}; + +static const char * const pcie1_wake_groups[] = { + "gpio27", +}; + +static const char * const atest_char1_groups[] = { + "gpio27", +}; + +static const char * const qdss_cti_trig_in_b1_groups[] = { + "gpio27", +}; + +static const char * const pcie2_clk_groups[] = { + "gpio28", +}; + +static const char * const atest_char2_groups[] = { + "gpio28", +}; + +static const char * const atest_char3_groups[] = { + "gpio29", +}; + +static const char * const pcie2_wake_groups[] = { + "gpio30", +}; + +static const char * const pwm_groups[] = { + "gpio30", "gpio31", "gpio32", "gpio33", "gpio44", "gpio45", "gpio46", + "gpio47", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", + "gpio56", "gpio57", "gpio58", "gpio59", "gpio60", +}; + +static const char * const atest_char_groups[] = { + "gpio30", +}; + +static const char * const pcie3_clk_groups[] = { + "gpio31", +}; + +static const char * const qdss_cti_trig_in_a1_groups[] = { + "gpio31", +}; + +static const char * const qdss_cti_trig_out_a1_groups[] = { + "gpio32", +}; + +static const char * const pcie3_wake_groups[] = { + "gpio33", +}; + +static const char * const qdss_cti_trig_in_a0_groups[] = { + "gpio33", +}; + +static const char * const blsp2_uart_groups[] = { + "gpio34", "gpio35", +}; + +static const char * const blsp2_i2c_groups[] = { + "gpio34", "gpio35", +}; + +static const char * const blsp2_spi_groups[] = { + "gpio34", "gpio35", "gpio36", "gpio37", +}; + +static const char * const blsp1_uart_groups[] = { + "gpio34", "gpio35", "gpio36", "gpio37", +}; + +static const char * const qdss_cti_trig_out_a0_groups[] = { + "gpio34", +}; + +static const char * const cri_trng2_groups[] = { + "gpio35", +}; + +static const char * const blsp1_i2c_groups[] = { + "gpio36", "gpio37", +}; + +static const char * const cri_trng3_groups[] = { + "gpio36", +}; + +static const char * const dwc_ddrphy_groups[] = { + "gpio37", +}; + +static const char * const mdc_groups[] = { + "gpio38", +}; + +static const char * const mdio_groups[] = { + "gpio39", +}; + +static const char * const audio_pri_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio61", "gpio61", +}; + +static const char * const audio_pdm0_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", +}; + +static const char * const qdss_traceclk_a_groups[] = { + "gpio43", +}; + +static const char * const audio_sec_groups[] = { + "gpio44", "gpio45", "gpio46", "gpio47", "gpio62", "gpio62", +}; + +static const char * const wsa_swrm_groups[] = { + "gpio44", "gpio45", +}; + +static const char * const qdss_tracectl_a_groups[] = { + "gpio44", +}; + +static const char * const qdss_tracedata_a_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", "gpio50", "gpio51", + "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", + "gpio59", "gpio60", +}; + +static const char * const rx1_groups[] = { + "gpio46", +}; + +static const char * const mac_groups[] = { + "gpio46", "gpio47", "gpio57", "gpio58", +}; + +static const char * const blsp5_i2c_groups[] = { + "gpio48", "gpio49", +}; + +static const char * const blsp5_uart_groups[] = { + "gpio48", "gpio49", +}; + +static const char * const blsp4_uart_groups[] = { + "gpio50", "gpio51", "gpio52", "gpio53", +}; + +static const char * const blsp4_i2c_groups[] = { + "gpio50", "gpio51", +}; + +static const char * const blsp4_spi_groups[] = { + "gpio50", "gpio51", "gpio52", "gpio53", +}; + +static const char * const wci20_groups[] = { + "gpio57", "gpio58", +}; + +static const char * const cxc1_groups[] = { + "gpio57", "gpio58", +}; + +static const char * const rx0_groups[] = { + "gpio59", +}; + +static const char * const prng_rosc0_groups[] = { + "gpio60", +}; + +static const char * const gcc_plltest_groups[] = { + "gpio60", "gpio62", +}; + +static const char * const blsp1_spi_groups[] = { + "gpio61", "gpio62", "gpio63", "gpio64", +}; + +static const char * const audio_pdm1_groups[] = { + "gpio61", "gpio62", "gpio63", "gpio64", +}; + +static const char * const prng_rosc1_groups[] = { + "gpio61", +}; + +static const char * const gcc_tlmm_groups[] = { + "gpio61", +}; + +static const char * const prng_rosc2_groups[] = { + "gpio62", +}; + +static const char * const prng_rosc3_groups[] = { + "gpio63", +}; + +static const char * const tsens_max_groups[] = { + "gpio64", +}; + +static const struct msm_function ipq9574_functions[] = { + FUNCTION(atest_char), + FUNCTION(atest_char0), + FUNCTION(atest_char1), + FUNCTION(atest_char2), + FUNCTION(atest_char3), + FUNCTION(audio_pdm0), + FUNCTION(audio_pdm1), + FUNCTION(audio_pri), + FUNCTION(audio_sec), + FUNCTION(blsp0_spi), + FUNCTION(blsp0_uart), + FUNCTION(blsp1_i2c), + FUNCTION(blsp1_spi), + FUNCTION(blsp1_uart), + FUNCTION(blsp2_i2c), + FUNCTION(blsp2_spi), + FUNCTION(blsp2_uart), + FUNCTION(blsp3_i2c), + FUNCTION(blsp3_spi), + FUNCTION(blsp3_uart), + FUNCTION(blsp4_i2c), + FUNCTION(blsp4_spi), + FUNCTION(blsp4_uart), + FUNCTION(blsp5_i2c), + FUNCTION(blsp5_uart), + FUNCTION(cri_trng0), + FUNCTION(cri_trng1), + FUNCTION(cri_trng2), + FUNCTION(cri_trng3), + FUNCTION(cxc0), + FUNCTION(cxc1), + FUNCTION(dbg_out), + FUNCTION(dwc_ddrphy), + FUNCTION(gcc_plltest), + FUNCTION(gcc_tlmm), + FUNCTION(gpio), + FUNCTION(mac), + FUNCTION(mdc), + FUNCTION(mdio), + FUNCTION(pcie0_clk), + FUNCTION(pcie0_wake), + FUNCTION(pcie1_clk), + FUNCTION(pcie1_wake), + FUNCTION(pcie2_clk), + FUNCTION(pcie2_wake), + FUNCTION(pcie3_clk), + FUNCTION(pcie3_wake), + FUNCTION(prng_rosc0), + FUNCTION(prng_rosc1), + FUNCTION(prng_rosc2), + FUNCTION(prng_rosc3), + FUNCTION(pta), + FUNCTION(pwm), + 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_traceclk_b), + FUNCTION(qdss_tracectl_a), + FUNCTION(qdss_tracectl_b), + FUNCTION(qdss_tracedata_a), + FUNCTION(qdss_tracedata_b), + FUNCTION(qspi_data), + FUNCTION(qspi_clk), + FUNCTION(qspi_cs), + FUNCTION(rx0), + FUNCTION(rx1), + FUNCTION(sdc_data), + FUNCTION(sdc_clk), + FUNCTION(sdc_cmd), + FUNCTION(sdc_rclk), + FUNCTION(tsens_max), + FUNCTION(wci20), + FUNCTION(wci21), + FUNCTION(wsa_swrm), +}; + +static const struct msm_pingroup ipq9574_groups[] = { + PINGROUP(0, sdc_data, qspi_data, qdss_traceclk_b, _, _, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, qdss_tracectl_b, _, _, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(6, sdc_data, qdss_tracedata_b, _, _, _, _, _, _, _), + PINGROUP(7, sdc_data, qdss_tracedata_b, _, _, _, _, _, _, _), + PINGROUP(8, sdc_data, qdss_tracedata_b, _, _, _, _, _, _, _), + PINGROUP(9, sdc_data, qdss_tracedata_b, _, _, _, _, _, _, _), + PINGROUP(10, sdc_rclk, qdss_tracedata_b, _, _, _, _, _, _, _), + PINGROUP(11, blsp0_spi, blsp0_uart, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(12, blsp0_spi, blsp0_uart, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(13, blsp0_spi, blsp0_uart, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(14, blsp0_spi, blsp0_uart, qdss_tracedata_b, _, _, _, _, _, _), + PINGROUP(15, blsp3_spi, blsp3_i2c, blsp3_uart, qdss_tracedata_b, _, _, _, _, _), + PINGROUP(16, blsp3_spi, blsp3_i2c, blsp3_uart, qdss_tracedata_b, _, _, _, _, _), + PINGROUP(17, blsp3_spi, blsp3_uart, dbg_out, qdss_tracedata_b, _, _, _, _, _), + PINGROUP(18, blsp3_spi, blsp3_uart, _, _, _, _, _, _, _), + PINGROUP(19, blsp3_spi, _, _, _, _, _, _, _, _), + PINGROUP(20, blsp3_spi, _, cri_trng0, _, _, _, _, _, _), + PINGROUP(21, blsp3_spi, _, cri_trng1, _, _, _, _, _, _), + PINGROUP(22, pcie0_clk, _, pta, _, _, _, _, _, _), + PINGROUP(23, _, pta, wci21, cxc0, _, _, _, _, _), + PINGROUP(24, pcie0_wake, _, pta, wci21, cxc0, _, qdss_cti_trig_out_b0, _, _), + PINGROUP(25, pcie1_clk, _, _, qdss_cti_trig_in_b0, _, _, _, _, _), + PINGROUP(26, _, atest_char0, _, qdss_cti_trig_out_b1, _, _, _, _, _), + PINGROUP(27, pcie1_wake, _, atest_char1, qdss_cti_trig_in_b1, _, _, _, _, _), + PINGROUP(28, pcie2_clk, atest_char2, _, _, _, _, _, _, _), + PINGROUP(29, atest_char3, _, _, _, _, _, _, _, _), + PINGROUP(30, pcie2_wake, pwm, atest_char, _, _, _, _, _, _), + PINGROUP(31, pcie3_clk, pwm, _, qdss_cti_trig_in_a1, _, _, _, _, _), + PINGROUP(32, pwm, _, qdss_cti_trig_out_a1, _, _, _, _, _, _), + PINGROUP(33, pcie3_wake, pwm, _, qdss_cti_trig_in_a0, _, _, _, _, _), + PINGROUP(34, blsp2_uart, blsp2_i2c, blsp2_spi, blsp1_uart, _, cri_trng1, qdss_cti_trig_out_a0, _, _), + PINGROUP(35, blsp2_uart, blsp2_i2c, blsp2_spi, blsp1_uart, _, cri_trng2, _, _, _), + PINGROUP(36, blsp1_uart, blsp1_i2c, blsp2_spi, _, cri_trng3, _, _, _, _), + PINGROUP(37, blsp1_uart, blsp1_i2c, blsp2_spi, _, dwc_ddrphy, _, _, _, _), + PINGROUP(38, mdc, _, cri_trng0, _, _, _, _, _, _), + PINGROUP(39, mdio, _, _, _, _, _, _, _, _), + PINGROUP(40, audio_pri, audio_pdm0, _, _, _, _, _, _, _), + PINGROUP(41, audio_pri, audio_pdm0, _, _, _, _, _, _, _), + PINGROUP(42, audio_pri, audio_pdm0, _, _, _, _, _, _, _), + PINGROUP(43, audio_pri, audio_pdm0, _, qdss_traceclk_a, _, _, _, _, _), + PINGROUP(44, pwm, audio_sec, wsa_swrm, _, qdss_tracectl_a, _, _, _, _), + PINGROUP(45, pwm, audio_sec, wsa_swrm, _, qdss_tracedata_a, _, _, _, _), + PINGROUP(46, pwm, audio_sec, rx1, mac, _, qdss_tracedata_a, _, _, _), + PINGROUP(47, pwm, audio_sec, mac, _, qdss_tracedata_a, _, _, _, _), + PINGROUP(48, blsp5_i2c, blsp5_uart, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(49, blsp5_i2c, blsp5_uart, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(50, blsp4_uart, blsp4_i2c, blsp4_spi, pwm, qdss_tracedata_a, _, _, _, _), + PINGROUP(51, blsp4_uart, blsp4_i2c, blsp4_spi, pwm, qdss_tracedata_a, _, _, _, _), + PINGROUP(52, blsp4_uart, blsp4_spi, pwm, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(53, blsp4_uart, blsp4_spi, pwm, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(54, pta, pwm, qdss_tracedata_a, _, _, _, _, _, _), + PINGROUP(55, pta, pwm, qdss_tracedata_a, _, _, _, _, _, _), + PINGROUP(56, pta, pwm, qdss_tracedata_a, _, _, _, _, _, _), + PINGROUP(57, wci20, cxc1, mac, pwm, qdss_tracedata_a, _, _, _, _), + PINGROUP(58, wci20, cxc1, mac, pwm, qdss_tracedata_a, _, _, _, _), + PINGROUP(59, rx0, pwm, qdss_tracedata_a, _, _, _, _, _, _), + PINGROUP(60, pwm, prng_rosc0, qdss_tracedata_a, _, gcc_plltest, _, _, _, _), + PINGROUP(61, blsp1_spi, audio_pri, audio_pdm1, audio_pri, pta, prng_rosc1, gcc_tlmm, _, _), + PINGROUP(62, blsp1_spi, audio_sec, audio_pdm1, audio_sec, pta, prng_rosc2, gcc_plltest, _, _), + PINGROUP(63, blsp1_spi, audio_pdm1, pta, prng_rosc3, _, _, _, _, _), + PINGROUP(64, blsp1_spi, audio_pdm1, tsens_max, _, _, _, _, _, _), +}; + +/* Reserving GPIO59 for controlling the QFPROM LDO regulator */ +static const int ipq9574_reserved_gpios[] = { + 59, -1 +}; + +static const struct msm_pinctrl_soc_data ipq9574_pinctrl = { + .pins = ipq9574_pins, + .npins = ARRAY_SIZE(ipq9574_pins), + .functions = ipq9574_functions, + .nfunctions = ARRAY_SIZE(ipq9574_functions), + .groups = ipq9574_groups, + .ngroups = ARRAY_SIZE(ipq9574_groups), + .reserved_gpios = ipq9574_reserved_gpios, + .ngpios = 65, +}; + +static int ipq9574_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &ipq9574_pinctrl); +} + +static const struct of_device_id ipq9574_pinctrl_of_match[] = { + { .compatible = "qcom,ipq9574-tlmm", }, + { } +}; +MODULE_DEVICE_TABLE(of, ipq9574_pinctrl_of_match); + +static struct platform_driver ipq9574_pinctrl_driver = { + .driver = { + .name = "ipq9574-tlmm", + .of_match_table = ipq9574_pinctrl_of_match, + }, + .probe = ipq9574_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init ipq9574_pinctrl_init(void) +{ + return platform_driver_register(&ipq9574_pinctrl_driver); +} +arch_initcall(ipq9574_pinctrl_init); + +static void __exit ipq9574_pinctrl_exit(void) +{ + platform_driver_unregister(&ipq9574_pinctrl_driver); +} +module_exit(ipq9574_pinctrl_exit); + +MODULE_DESCRIPTION("QTI IPQ9574 TLMM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 87920257bb73..fdb6585a9234 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -19,6 +19,8 @@ #include "pinctrl-lpass-lpi.h" +#define MAX_NR_GPIO 23 +#define GPIO_FUNC 0 #define MAX_LPI_NUM_CLKS 2 struct lpi_pinctrl { @@ -30,6 +32,7 @@ struct lpi_pinctrl { char __iomem *slew_base; struct clk_bulk_data clks[MAX_LPI_NUM_CLKS]; struct mutex slew_access_lock; + DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO); const struct lpi_pinctrl_variant_data *data; }; @@ -84,10 +87,10 @@ static int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev, } static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, - unsigned int group_num) + unsigned int group) { struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct lpi_pingroup *g = &pctrl->data->groups[group_num]; + const struct lpi_pingroup *g = &pctrl->data->groups[group]; u32 val; int i, pin = g->pin; @@ -100,6 +103,28 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, return -EINVAL; val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG); + + /* + * If this is the first time muxing to GPIO and the direction is + * output, make sure that we're not going to be glitching the pin + * by reading the current state of the pin and setting it as the + * output. + */ + if (i == GPIO_FUNC && (val & LPI_GPIO_OE_MASK) && + !test_and_set_bit(group, pctrl->ever_gpio)) { + u32 io_val = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG); + + if (io_val & LPI_GPIO_VALUE_IN_MASK) { + if (!(io_val & LPI_GPIO_VALUE_OUT_MASK)) + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, + io_val | LPI_GPIO_VALUE_OUT_MASK); + } else { + if (io_val & LPI_GPIO_VALUE_OUT_MASK) + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, + io_val & ~LPI_GPIO_VALUE_OUT_MASK); + } + } + u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK); lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); @@ -221,6 +246,15 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, } } + /* + * As per Hardware Programming Guide, when configuring pin as output, + * set the pin value before setting output-enable (OE). + */ + if (output_enabled) { + val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); + } + val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG); u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK); @@ -230,11 +264,6 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - if (output_enabled) { - val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); - } - return 0; } @@ -390,6 +419,9 @@ int lpi_pinctrl_probe(struct platform_device *pdev) if (!data) return -EINVAL; + if (WARN_ON(data->npins > MAX_NR_GPIO)) + return -EINVAL; + pctrl->data = data; pctrl->dev = &pdev->dev; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 4515f375c5e8..c5f52d4f7781 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -517,7 +517,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, * The points above, explain why this _should_ be a * no-op. However, for historical reasons and to * support old device trees, we'll violate the docs - * still affect the output. + * and still affect the output. * * It should further be noted that this old historical * behavior actually overrides arg to 0. That means @@ -1506,8 +1506,7 @@ int msm_pinctrl_probe(struct platform_device *pdev, return PTR_ERR(pctrl->regs[i]); } } else { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); + pctrl->regs[0] = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(pctrl->regs[0])) return PTR_ERR(pctrl->regs[0]); diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c index a05f41fe2706..1a061bc9b8fa 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8998.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c @@ -1503,6 +1503,18 @@ static const struct msm_pingroup msm8998_groups[] = { UFS_RESET(ufs_reset, 0x19d000), }; +static const struct msm_gpio_wakeirq_map msm8998_mpm_map[] = { + { 1, 3 }, { 5, 4 }, { 9, 5 }, { 11, 6 }, { 22, 8 }, { 24, 9 }, { 26, 10 }, + { 34, 11 }, { 36, 12 }, { 37, 13 }, { 38, 14 }, { 40, 15 }, { 42, 16 }, { 46, 17 }, + { 50, 18 }, { 53, 19 }, { 54, 20 }, { 56, 21 }, { 57, 22 }, { 58, 23 }, { 59, 24 }, + { 60, 25 }, { 61, 26 }, { 62, 27 }, { 63, 28 }, { 64, 29 }, { 66, 7 }, { 71, 30 }, + { 73, 31 }, { 77, 32 }, { 78, 33 }, { 79, 34 }, { 80, 35 }, { 82, 36 }, { 86, 37 }, + { 91, 38 }, { 92, 39 }, { 95, 40 }, { 97, 41 }, { 101, 42 }, { 104, 43 }, { 106, 44 }, + { 108, 45 }, { 110, 48 }, { 112, 46 }, { 113, 47 }, { 115, 51 }, { 116, 54 }, { 117, 55 }, + { 118, 56 }, { 119, 57 }, { 120, 58 }, { 121, 59 }, { 122, 60 }, { 123, 61 }, { 124, 62 }, + { 125, 63 }, { 126, 64 }, { 127, 50 }, { 129, 65 }, { 131, 66 }, { 132, 67 }, { 133, 68 }, +}; + static const struct msm_pinctrl_soc_data msm8998_pinctrl = { .pins = msm8998_pins, .npins = ARRAY_SIZE(msm8998_pins), @@ -1511,6 +1523,8 @@ static const struct msm_pinctrl_soc_data msm8998_pinctrl = { .groups = msm8998_groups, .ngroups = ARRAY_SIZE(msm8998_groups), .ngpios = 150, + .wakeirq_map = msm8998_mpm_map, + .nwakeirq_map = ARRAY_SIZE(msm8998_mpm_map), }; static int msm8998_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c new file mode 100644 index 000000000000..2a87e3f144fd --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c @@ -0,0 +1,1280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Danila Tikhonov + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static const char * const sm7150_tiles[] = { + "north", + "south", + "west", +}; + +enum { + NORTH, + SOUTH, + WEST +}; + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define REG_SIZE 0x1000 + +#define PINGROUP(id, _tile, 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, /* 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 = 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, \ + .tile = _tile, \ + .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 = 3, \ + .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, \ + .tile = SOUTH, \ + .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 = ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .tile = SOUTH, \ + .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 sm7150_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, "UFS_RESET"), + PINCTRL_PIN(120, "SDC1_RCLK"), + PINCTRL_PIN(121, "SDC1_CLK"), + PINCTRL_PIN(122, "SDC1_CMD"), + PINCTRL_PIN(123, "SDC1_DATA"), + PINCTRL_PIN(124, "SDC2_CLK"), + PINCTRL_PIN(125, "SDC2_CMD"), + PINCTRL_PIN(126, "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); + +static const unsigned int ufs_reset_pins[] = { 119 }; +static const unsigned int sdc1_rclk_pins[] = { 120 }; +static const unsigned int sdc1_clk_pins[] = { 121 }; +static const unsigned int sdc1_cmd_pins[] = { 122 }; +static const unsigned int sdc1_data_pins[] = { 123 }; +static const unsigned int sdc2_clk_pins[] = { 124 }; +static const unsigned int sdc2_cmd_pins[] = { 125 }; +static const unsigned int sdc2_data_pins[] = { 126 }; + +enum sm7150_functions { + msm_mux_gpio, + msm_mux_adsp_ext, + msm_mux_agera_pll, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_tsens, + msm_mux_atest_tsens2, + msm_mux_atest_usb1, + msm_mux_atest_usb2, + 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_dbg_out, + msm_mux_ddr_bist, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_edp_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_gps_tx, + msm_mux_jitter_bist, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_m_voc, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_mss_lte, + msm_mux_nav_pps_in, + msm_mux_nav_pps_out, + msm_mux_pa_indicator, + msm_mux_pci_e, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_bypassnl, + msm_mux_pll_reset, + msm_mux_pri_mi2s, + msm_mux_pri_mi2s_ws, + msm_mux_prng_rosc, + msm_mux_qdss, + msm_mux_qdss_cti, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qua_mi2s, + msm_mux_qup00, + msm_mux_qup01, + msm_mux_qup02, + msm_mux_qup03, + msm_mux_qup04, + msm_mux_qup10, + msm_mux_qup11, + msm_mux_qup12, + msm_mux_qup13, + msm_mux_qup14, + msm_mux_qup15, + msm_mux_sd_write, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_sec_mi2s, + msm_mux_ter_mi2s, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tgu_ch2, + msm_mux_tgu_ch3, + msm_mux_tsif1_clk, + msm_mux_tsif1_data, + msm_mux_tsif1_en, + msm_mux_tsif1_error, + msm_mux_tsif1_sync, + msm_mux_tsif2_clk, + msm_mux_tsif2_data, + msm_mux_tsif2_en, + msm_mux_tsif2_error, + msm_mux_tsif2_sync, + 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_uim_batt, + 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_wsa_clk, + msm_mux_wsa_data, + msm_mux__, +}; + +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", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", +}; + +static const char * const adsp_ext_groups[] = { + "gpio87", +}; + +static const char * const agera_pll_groups[] = { + "gpio28", +}; + +static const char * const aoss_cti_groups[] = { + "gpio85", +}; + +static const char * const atest_char_groups[] = { + "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", +}; + +static const char * const atest_tsens_groups[] = { + "gpio29", +}; + +static const char * const atest_tsens2_groups[] = { + "gpio7", +}; + +static const char * const atest_usb1_groups[] = { + "gpio7", "gpio10", "gpio11", "gpio39", "gpio44", +}; + +static const char * const atest_usb2_groups[] = { + "gpio51", "gpio52", "gpio53", "gpio54", "gpio55" +}; + +static const char * const cam_mclk_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", +}; + +static const char * const cci_async_groups[] = { + "gpio24", "gpio25", "gpio26", +}; + +static const char * const cci_i2c_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", "gpio27", "gpio28", +}; + +static const char * const cci_timer0_groups[] = { + "gpio21", +}; + +static const char * const cci_timer1_groups[] = { + "gpio22", +}; + +static const char * const cci_timer2_groups[] = { + "gpio23", +}; + +static const char * const cci_timer3_groups[] = { + "gpio24", +}; + +static const char * const cci_timer4_groups[] = { + "gpio25", +}; + +static const char * const dbg_out_groups[] = { + "gpio3", +}; + +static const char * const ddr_bist_groups[] = { + "gpio7", "gpio8", "gpio9", "gpio10", +}; + +static const char * const ddr_pxi0_groups[] = { + "gpio6", "gpio7", +}; + +static const char * const ddr_pxi1_groups[] = { + "gpio39", "gpio44", +}; + +static const char * const ddr_pxi2_groups[] = { + "gpio10", "gpio11", +}; + +static const char * const ddr_pxi3_groups[] = { + "gpio12", "gpio13", +}; + +static const char * const edp_hot_groups[] = { + "gpio85", +}; + +static const char * const edp_lcd_groups[] = { + "gpio11", +}; + +static const char * const gcc_gp1_groups[] = { + "gpio48", "gpio56", +}; + +static const char * const gcc_gp2_groups[] = { + "gpio21", +}; + +static const char * const gcc_gp3_groups[] = { + "gpio22", +}; + +static const char * const gp_pdm0_groups[] = { + "gpio37", "gpio68", +}; + +static const char * const gp_pdm1_groups[] = { + "gpio8", "gpio50", +}; + +static const char * const gp_pdm2_groups[] = { + "gpio57", +}; + +static const char * const gps_tx_groups[] = { + "gpio83", "gpio84", "gpio107", "gpio109", +}; + +static const char * const jitter_bist_groups[] = { + "gpio26", +}; + +static const char * const ldo_en_groups[] = { + "gpio70", +}; + +static const char * const ldo_update_groups[] = { + "gpio71", +}; + +static const char * const m_voc_groups[] = { + "gpio12", +}; + +static const char * const mdp_vsync_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio70", "gpio71", +}; + +static const char * const mdp_vsync0_groups[] = { + "gpio63", +}; + +static const char * const mdp_vsync1_groups[] = { + "gpio63", +}; + +static const char * const mdp_vsync2_groups[] = { + "gpio63", +}; + +static const char * const mdp_vsync3_groups[] = { + "gpio63", +}; + +static const char * const mss_lte_groups[] = { + "gpio108", "gpio109", +}; + +static const char * const nav_pps_in_groups[] = { + "gpio83", "gpio84", "gpio107", +}; + +static const char * const nav_pps_out_groups[] = { + "gpio83", "gpio84", "gpio107", +}; + +static const char * const pa_indicator_groups[] = { + "gpio99", +}; + +static const char * const pci_e_groups[] = { + "gpio66", "gpio67", "gpio68", +}; + +static const char * const phase_flag_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio6", "gpio7", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio24", + "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio43", "gpio44", "gpio56", + "gpio57", "gpio60", "gpio61", "gpio62", +}; + +static const char * const pll_bist_groups[] = { + "gpio27", +}; + +static const char * const pll_bypassnl_groups[] = { + "gpio13", +}; + +static const char * const pll_reset_groups[] = { + "gpio14", +}; + +static const char * const pri_mi2s_groups[] = { + "gpio49", "gpio51", "gpio52", +}; + +static const char * const pri_mi2s_ws_groups[] = { + "gpio50", +}; + +static const char * const prng_rosc_groups[] = { + "gpio72", +}; + +static const char * const qdss_groups[] = { + "gpio13", "gpio86", "gpio14", "gpio87", "gpio15", "gpio88", "gpio16", + "gpio89", "gpio17", "gpio90", "gpio18", "gpio91", "gpio19", "gpio34", + "gpio20", "gpio35", "gpio21", "gpio53", "gpio22", "gpio30", "gpio23", + "gpio54", "gpio24", "gpio55", "gpio25", "gpio57", "gpio26", "gpio31", + "gpio27", "gpio56", "gpio28", "gpio36", "gpio29", "gpio37", "gpio93", + "gpio104", +}; + +static const char * const qdss_cti_groups[] = { + "gpio4", "gpio5", "gpio32", "gpio44", "gpio45", "gpio63", +}; + +static const char * const qlink_enable_groups[] = { + "gpio97", +}; + +static const char * const qlink_request_groups[] = { + "gpio96", +}; + +static const char * const qua_mi2s_groups[] = { + "gpio58", +}; + +static const char * const qup00_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", "gpio57", "gpio58", +}; + +static const char * const qup01_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio12", "gpio37", +}; + +static const char * const qup02_groups[] = { + "gpio34", "gpio35", +}; + +static const char * const qup03_groups[] = { + "gpio38", "gpio39", "gpio40", "gpio41", +}; + +static const char * const qup04_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; + +static const char * const qup10_groups[] = { + "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", +}; + +static const char * const qup11_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", +}; + +static const char * const qup12_groups[] = { + "gpio42", "gpio43", "gpio44", "gpio45", +}; + +static const char * const qup13_groups[] = { + "gpio46", "gpio47", +}; + +static const char * const qup14_groups[] = { + "gpio110", "gpio111", "gpio112", "gpio113", +}; + +static const char * const qup15_groups[] = { + "gpio92", "gpio101", "gpio102", "gpio103", +}; + +static const char * const sd_write_groups[] = { + "gpio33", +}; + +static const char * const sdc40_groups[] = { + "gpio69", +}; + +static const char * const sdc41_groups[] = { + "gpio68", +}; + +static const char * const sdc42_groups[] = { + "gpio67", +}; + +static const char * const sdc43_groups[] = { + "gpio65", +}; + +static const char * const sdc4_clk_groups[] = { + "gpio66", +}; + +static const char * const sdc4_cmd_groups[] = { + "gpio64", +}; + +static const char * const sec_mi2s_groups[] = { + "gpio57", +}; + +static const char * const ter_mi2s_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; + +static const char * const tgu_ch0_groups[] = { + "gpio63", +}; + +static const char * const tgu_ch1_groups[] = { + "gpio64", +}; + +static const char * const tgu_ch2_groups[] = { + "gpio65", +}; + +static const char * const tgu_ch3_groups[] = { + "gpio62", +}; + +static const char * const tsif1_clk_groups[] = { + "gpio62", +}; + +static const char * const tsif1_data_groups[] = { + "gpio64", +}; + +static const char * const tsif1_en_groups[] = { + "gpio63", +}; + +static const char * const tsif1_error_groups[] = { + "gpio60", +}; + +static const char * const tsif1_sync_groups[] = { + "gpio61", +}; + +static const char * const tsif2_clk_groups[] = { + "gpio66", +}; + +static const char * const tsif2_data_groups[] = { + "gpio68", +}; + +static const char * const tsif2_en_groups[] = { + "gpio67", +}; + +static const char * const tsif2_error_groups[] = { + "gpio65", +}; + +static const char * const tsif2_sync_groups[] = { + "gpio69", +}; + +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 uim_batt_groups[] = { + "gpio85", +}; + +static const char * const usb_phy_groups[] = { + "gpio104", +}; + +static const char * const vfr_1_groups[] = { + "gpio65", +}; + +static const char * const vsense_trigger_groups[] = { + "gpio7", +}; + +static const char * const wlan1_adc0_groups[] = { + "gpio39", +}; + +static const char * const wlan1_adc1_groups[] = { + "gpio44", +}; + +static const char * const wlan2_adc0_groups[] = { + "gpio11", +}; + +static const char * const wlan2_adc1_groups[] = { + "gpio10", +}; + +static const char * const wsa_clk_groups[] = { + "gpio49", +}; + +static const char * const wsa_data_groups[] = { + "gpio50", +}; + +static const struct msm_function sm7150_functions[] = { + FUNCTION(gpio), + FUNCTION(adsp_ext), + FUNCTION(agera_pll), + FUNCTION(aoss_cti), + FUNCTION(atest_char), + FUNCTION(atest_tsens), + FUNCTION(atest_tsens2), + FUNCTION(atest_usb1), + FUNCTION(atest_usb2), + 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(dbg_out), + FUNCTION(ddr_bist), + FUNCTION(ddr_pxi0), + FUNCTION(ddr_pxi1), + FUNCTION(ddr_pxi2), + FUNCTION(ddr_pxi3), + FUNCTION(edp_hot), + FUNCTION(edp_lcd), + FUNCTION(gcc_gp1), + FUNCTION(gcc_gp2), + FUNCTION(gcc_gp3), + FUNCTION(gp_pdm0), + FUNCTION(gp_pdm1), + FUNCTION(gp_pdm2), + FUNCTION(gps_tx), + FUNCTION(jitter_bist), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(m_voc), + FUNCTION(mdp_vsync), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(mss_lte), + FUNCTION(nav_pps_in), + FUNCTION(nav_pps_out), + FUNCTION(pa_indicator), + FUNCTION(pci_e), + FUNCTION(phase_flag), + FUNCTION(pll_bist), + FUNCTION(pll_bypassnl), + FUNCTION(pll_reset), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(prng_rosc), + FUNCTION(qdss_cti), + FUNCTION(qdss), + FUNCTION(qlink_enable), + FUNCTION(qlink_request), + FUNCTION(qua_mi2s), + FUNCTION(qup00), + FUNCTION(qup01), + FUNCTION(qup02), + FUNCTION(qup03), + FUNCTION(qup04), + FUNCTION(qup10), + FUNCTION(qup11), + FUNCTION(qup12), + FUNCTION(qup13), + FUNCTION(qup14), + FUNCTION(qup15), + FUNCTION(sd_write), + FUNCTION(sdc40), + FUNCTION(sdc41), + FUNCTION(sdc42), + FUNCTION(sdc43), + FUNCTION(sdc4_clk), + FUNCTION(sdc4_cmd), + FUNCTION(sec_mi2s), + FUNCTION(ter_mi2s), + FUNCTION(tgu_ch0), + FUNCTION(tgu_ch1), + FUNCTION(tgu_ch2), + FUNCTION(tgu_ch3), + FUNCTION(tsif1_clk), + FUNCTION(tsif1_data), + FUNCTION(tsif1_en), + FUNCTION(tsif1_error), + FUNCTION(tsif1_sync), + FUNCTION(tsif2_clk), + FUNCTION(tsif2_data), + FUNCTION(tsif2_en), + FUNCTION(tsif2_error), + FUNCTION(tsif2_sync), + 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(uim_batt), + FUNCTION(usb_phy), + FUNCTION(vfr_1), + FUNCTION(vsense_trigger), + FUNCTION(wlan1_adc0), + FUNCTION(wlan1_adc1), + FUNCTION(wlan2_adc0), + FUNCTION(wlan2_adc1), + FUNCTION(wsa_clk), + FUNCTION(wsa_data), +}; + +/* + * 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 sm7150_groups[] = { + [0] = PINGROUP(0, SOUTH, qup01, _, phase_flag, _, _, _, _, _, _), + [1] = PINGROUP(1, SOUTH, qup01, _, phase_flag, _, _, _, _, _, _), + [2] = PINGROUP(2, SOUTH, qup01, _, phase_flag, _, _, _, _, _, _), + [3] = PINGROUP(3, SOUTH, qup01, dbg_out, _, _, _, _, _, _, _), + [4] = PINGROUP(4, NORTH, _, qdss_cti, _, _, _, _, _, _, _), + [5] = PINGROUP(5, NORTH, _, qdss_cti, _, _, _, _, _, _, _), + [6] = PINGROUP(6, NORTH, qup11, _, phase_flag, ddr_pxi0, _, _, _, _, _), + [7] = PINGROUP(7, NORTH, qup11, ddr_bist, _, phase_flag, atest_tsens2, vsense_trigger, atest_usb1, ddr_pxi0, _), + [8] = PINGROUP(8, NORTH, qup11, gp_pdm1, ddr_bist, _, _, _, _, _, _), + [9] = PINGROUP(9, NORTH, qup11, ddr_bist, _, _, _, _, _, _, _), + [10] = PINGROUP(10, NORTH, mdp_vsync, ddr_bist, _, phase_flag, wlan2_adc1, atest_usb1, ddr_pxi2, _, _), + [11] = PINGROUP(11, NORTH, mdp_vsync, edp_lcd, _, phase_flag, wlan2_adc0, atest_usb1, ddr_pxi2, _, _), + [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, qup01, _, phase_flag, ddr_pxi3, _, _, _), + [13] = PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, _, phase_flag, qdss, ddr_pxi3, _, _, _), + [14] = PINGROUP(14, SOUTH, cam_mclk, pll_reset, _, phase_flag, qdss, _, _, _, _), + [15] = PINGROUP(15, SOUTH, cam_mclk, _, phase_flag, qdss, _, _, _, _, _), + [16] = PINGROUP(16, SOUTH, cam_mclk, _, phase_flag, qdss, _, _, _, _, _), + [17] = PINGROUP(17, SOUTH, cci_i2c, _, phase_flag, qdss, _, _, _, _, _), + [18] = PINGROUP(18, SOUTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [19] = PINGROUP(19, SOUTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [20] = PINGROUP(20, SOUTH, cci_i2c, qdss, _, _, _, _, _, _, _), + [21] = PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, _, qdss, _, _, _, _, _), + [22] = PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, _, qdss, _, _, _, _, _), + [23] = PINGROUP(23, SOUTH, cci_timer2, qdss, _, _, _, _, _, _, _), + [24] = PINGROUP(24, SOUTH, cci_timer3, cci_async, _, phase_flag, qdss, _, _, _, _), + [25] = PINGROUP(25, SOUTH, cci_timer4, cci_async, _, phase_flag, qdss, _, _, _, _), + [26] = PINGROUP(26, SOUTH, cci_async, jitter_bist, _, phase_flag, qdss, _, _, _, _), + [27] = PINGROUP(27, SOUTH, cci_i2c, pll_bist, _, phase_flag, qdss, _, _, _, _), + [28] = PINGROUP(28, SOUTH, cci_i2c, agera_pll, _, phase_flag, qdss, _, _, _, _), + [29] = PINGROUP(29, NORTH, _, _, phase_flag, qdss, atest_tsens, _, _, _, _), + [30] = PINGROUP(30, SOUTH, _, phase_flag, qdss, _, _, _, _, _, _), + [31] = PINGROUP(31, WEST, _, qdss, _, _, _, _, _, _, _), + [32] = PINGROUP(32, NORTH, qdss_cti, _, _, _, _, _, _, _, _), + [33] = PINGROUP(33, NORTH, sd_write, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, SOUTH, qup02, qdss, _, _, _, _, _, _, _), + [35] = PINGROUP(35, SOUTH, qup02, _, phase_flag, qdss, _, _, _, _, _), + [36] = PINGROUP(36, SOUTH, _, phase_flag, qdss, _, _, _, _, _, _), + [37] = PINGROUP(37, SOUTH, qup01, gp_pdm0, _, phase_flag, qdss, _, _, _, _), + [38] = PINGROUP(38, SOUTH, qup03, _, phase_flag, _, _, _, _, _, _), + [39] = PINGROUP(39, SOUTH, qup03, _, phase_flag, _, wlan1_adc0, atest_usb1, ddr_pxi1, _, _), + [40] = PINGROUP(40, SOUTH, qup03, _, _, _, _, _, _, _, _), + [41] = PINGROUP(41, SOUTH, qup03, _, _, _, _, _, _, _, _), + [42] = PINGROUP(42, NORTH, qup12, _, _, _, _, _, _, _, _), + [43] = PINGROUP(43, NORTH, qup12, _, phase_flag, _, _, _, _, _, _), + [44] = PINGROUP(44, NORTH, qup12, _, phase_flag, qdss_cti, _, wlan1_adc1, atest_usb1, ddr_pxi1, _), + [45] = PINGROUP(45, NORTH, qup12, qdss_cti, _, _, _, _, _, _, _), + [46] = PINGROUP(46, NORTH, qup13, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, NORTH, qup13, _, _, _, _, _, _, _, _), + [48] = PINGROUP(48, WEST, gcc_gp1, _, _, _, _, _, _, _, _), + [49] = PINGROUP(49, WEST, pri_mi2s, qup00, wsa_clk, _, _, _, _, _, _), + [50] = PINGROUP(50, WEST, pri_mi2s_ws, qup00, wsa_data, gp_pdm1, _, _, _, _, _), + [51] = PINGROUP(51, WEST, pri_mi2s, qup00, atest_usb2, _, _, _, _, _, _), + [52] = PINGROUP(52, WEST, pri_mi2s, qup00, atest_usb2, _, _, _, _, _, _), + [53] = PINGROUP(53, WEST, ter_mi2s, qup04, qdss, atest_usb2, _, _, _, _, _), + [54] = PINGROUP(54, WEST, ter_mi2s, qup04, qdss, atest_usb2, _, _, _, _, _), + [55] = PINGROUP(55, WEST, ter_mi2s, qup04, qdss, atest_usb2, _, _, _, _, _), + [56] = PINGROUP(56, WEST, ter_mi2s, qup04, gcc_gp1, _, phase_flag, qdss, _, _, _), + [57] = PINGROUP(57, WEST, sec_mi2s, qup00, gp_pdm2, _, phase_flag, qdss, _, _, _), + [58] = PINGROUP(58, WEST, qua_mi2s, qup00, _, _, _, _, _, _, _), + [59] = PINGROUP(59, NORTH, qup10, _, _, _, _, _, _, _, _), + [60] = PINGROUP(60, NORTH, qup10, tsif1_error, _, phase_flag, _, _, _, _, _), + [61] = PINGROUP(61, NORTH, qup10, tsif1_sync, _, phase_flag, _, _, _, _, _), + [62] = PINGROUP(62, NORTH, qup10, tsif1_clk, tgu_ch3, _, phase_flag, _, _, _, _), + [63] = PINGROUP(63, NORTH, tsif1_en, mdp_vsync0, qup10, mdp_vsync1, mdp_vsync2, mdp_vsync3, tgu_ch0, qdss_cti, _), + [64] = PINGROUP(64, NORTH, tsif1_data, sdc4_cmd, qup10, tgu_ch1, _, _, _, _, _), + [65] = PINGROUP(65, NORTH, tsif2_error, sdc43, qup10, vfr_1, tgu_ch2, _, _, _, _), + [66] = PINGROUP(66, NORTH, tsif2_clk, sdc4_clk, pci_e, _, _, _, _, _, _), + [67] = PINGROUP(67, NORTH, tsif2_en, sdc42, pci_e, _, _, _, _, _, _), + [68] = PINGROUP(68, NORTH, tsif2_data, sdc41, pci_e, gp_pdm0, _, _, _, _, _), + [69] = PINGROUP(69, NORTH, tsif2_sync, sdc40, _, _, _, _, _, _, _), + [70] = PINGROUP(70, NORTH, _, _, mdp_vsync, ldo_en, _, _, _, _, _), + [71] = PINGROUP(71, NORTH, _, mdp_vsync, ldo_update, _, _, _, _, _, _), + [72] = PINGROUP(72, NORTH, prng_rosc, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, NORTH, _, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, WEST, _, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, WEST, uim2_data, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, WEST, uim2_clk, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, WEST, uim2_reset, _, _, _, _, _, _, _, _), + [78] = PINGROUP(78, WEST, uim2_present, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, WEST, uim1_data, _, _, _, _, _, _, _, _), + [80] = PINGROUP(80, WEST, uim1_clk, _, _, _, _, _, _, _, _), + [81] = PINGROUP(81, WEST, uim1_reset, _, _, _, _, _, _, _, _), + [82] = PINGROUP(82, WEST, uim1_present, _, _, _, _, _, _, _, _), + [83] = PINGROUP(83, WEST, _, nav_pps_in, nav_pps_out, gps_tx, _, _, _, _, _), + [84] = PINGROUP(84, WEST, _, nav_pps_in, nav_pps_out, gps_tx, _, _, _, _, _), + [85] = PINGROUP(85, WEST, uim_batt, edp_hot, aoss_cti, _, _, _, _, _, _), + [86] = PINGROUP(86, NORTH, qdss, atest_char, _, _, _, _, _, _, _), + [87] = PINGROUP(87, NORTH, adsp_ext, qdss, atest_char, _, _, _, _, _, _), + [88] = PINGROUP(88, NORTH, qdss, atest_char, _, _, _, _, _, _, _), + [89] = PINGROUP(89, NORTH, qdss, atest_char, _, _, _, _, _, _, _), + [90] = PINGROUP(90, NORTH, qdss, atest_char, _, _, _, _, _, _, _), + [91] = PINGROUP(91, NORTH, qdss, _, _, _, _, _, _, _, _), + [92] = PINGROUP(92, NORTH, _, _, qup15, _, _, _, _, _, _), + [93] = PINGROUP(93, NORTH, qdss, _, _, _, _, _, _, _, _), + [94] = PINGROUP(94, SOUTH, _, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, WEST, _, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, WEST, qlink_request, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, WEST, qlink_enable, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, WEST, _, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, WEST, _, pa_indicator, _, _, _, _, _, _, _), + [100] = PINGROUP(100, WEST, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, NORTH, _, _, qup15, _, _, _, _, _, _), + [102] = PINGROUP(102, NORTH, _, _, qup15, _, _, _, _, _, _), + [103] = PINGROUP(103, NORTH, _, qup15, _, _, _, _, _, _, _), + [104] = PINGROUP(104, WEST, usb_phy, _, qdss, _, _, _, _, _, _), + [105] = PINGROUP(105, NORTH, _, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, NORTH, _, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, WEST, _, nav_pps_in, nav_pps_out, gps_tx, _, _, _, _, _), + [108] = PINGROUP(108, SOUTH, mss_lte, _, _, _, _, _, _, _, _), + [109] = PINGROUP(109, SOUTH, mss_lte, gps_tx, _, _, _, _, _, _, _), + [110] = PINGROUP(110, NORTH, _, _, qup14, _, _, _, _, _, _), + [111] = PINGROUP(111, NORTH, _, _, qup14, _, _, _, _, _, _), + [112] = PINGROUP(112, NORTH, _, qup14, _, _, _, _, _, _, _), + [113] = PINGROUP(113, NORTH, _, qup14, _, _, _, _, _, _, _), + [114] = PINGROUP(114, NORTH, _, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, NORTH, _, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, NORTH, _, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, NORTH, _, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, NORTH, _, _, _, _, _, _, _, _, _), + [119] = UFS_RESET(ufs_reset, 0x9f000), + [120] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9a000, 15, 0), + [121] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6), + [122] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3), + [123] = SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0), + [124] = SDC_QDSD_PINGROUP(sdc2_clk, 0x98000, 14, 6), + [125] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x98000, 11, 3), + [126] = SDC_QDSD_PINGROUP(sdc2_data, 0x98000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map sm7150_pdc_map[] = { + {0, 40}, {3, 50}, {4, 42}, {5, 70}, {6, 41}, {9, 57}, + {10, 80}, {11, 51}, {22, 90}, {24, 61}, {26, 52}, {30, 56}, + {31, 33}, {32, 81}, {33, 62}, {34, 43}, {36, 91}, {37, 53}, + {38, 63}, {39, 72}, {41, 101}, {42, 35}, {43, 34}, {45, 73}, + {47, 82}, {48, 36}, {49, 37}, {50, 38}, {52, 39}, {53, 102}, + {55, 92}, {56, 45}, {57, 46}, {58, 83}, {59, 47}, {62, 48}, + {64, 74}, {65, 44}, {66, 93}, {67, 49}, {68, 55}, {69, 32}, + {70, 54}, {73, 64}, {74, 71}, {78, 31}, {82, 30}, {84, 58}, + {85, 103}, {86, 59}, {87, 60}, {88, 65}, {89, 66}, {90, 67}, + {91, 68}, {92, 69}, {93, 75}, {94, 84}, {95, 94}, {96, 76}, + {98, 77}, {101, 78}, {104, 99}, {109, 104}, {110, 79}, {113, 85}, +}; + +static const struct msm_pinctrl_soc_data sm7150_tlmm = { + .pins = sm7150_pins, + .npins = ARRAY_SIZE(sm7150_pins), + .functions = sm7150_functions, + .nfunctions = ARRAY_SIZE(sm7150_functions), + .groups = sm7150_groups, + .ngroups = ARRAY_SIZE(sm7150_groups), + .ngpios = 120, + .tiles = sm7150_tiles, + .ntiles = ARRAY_SIZE(sm7150_tiles), + .wakeirq_map = sm7150_pdc_map, + .nwakeirq_map = ARRAY_SIZE(sm7150_pdc_map), + .wakeirq_dual_edge_errata = true, +}; + +static int sm7150_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sm7150_tlmm); +} + +static const struct of_device_id sm7150_tlmm_of_match[] = { + { .compatible = "qcom,sm7150-tlmm", }, + { }, +}; + +static struct platform_driver sm7150_tlmm_driver = { + .driver = { + .name = "sm7150-tlmm", + .pm = &msm_pinctrl_dev_pm_ops, + .of_match_table = sm7150_tlmm_of_match, + }, + .probe = sm7150_tlmm_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sm7150_tlmm_init(void) +{ + return platform_driver_register(&sm7150_tlmm_driver); +} +arch_initcall(sm7150_tlmm_init); + +static void __exit sm7150_tlmm_exit(void) +{ + platform_driver_unregister(&sm7150_tlmm_driver); +} +module_exit(sm7150_tlmm_exit); + +MODULE_DESCRIPTION("Qualcomm SM7150 TLMM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c index c2bdd936d27f..db1a46fee9c6 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c @@ -102,6 +102,13 @@ static const struct pinctrl_pin_desc sm8550_lpi_pins[] = { PINCTRL_PIN(22, "gpio22"), }; +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", +}; + static const char * const dmic1_clk_groups[] = { "gpio6" }; static const char * const dmic1_data_groups[] = { "gpio7" }; static const char * const dmic2_clk_groups[] = { "gpio8" }; @@ -168,6 +175,7 @@ static const struct lpi_pingroup sm8550_groups[] = { }; static const struct lpi_function sm8550_functions[] = { + LPI_FUNCTION(gpio), LPI_FUNCTION(dmic1_clk), LPI_FUNCTION(dmic1_data), LPI_FUNCTION(dmic2_clk), diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index ea3485344f06..43c7857c06a5 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1232,12 +1232,14 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8994-gpio", .data = (void *) 22 }, { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, + { .compatible = "qcom,pmi632-gpio", .data = (void *) 8 }, { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 }, { .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 }, { .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 }, { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 }, { .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 }, + { .compatible = "qcom,pmm8654au-gpio", .data = (void *) 12 }, /* pmp8074 has 12 GPIOs with holes on 1 and 12 */ { .compatible = "qcom,pmp8074-gpio", .data = (void *) 12 }, { .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 }, diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 644fb4a0e72a..fe0393829c20 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -143,7 +143,6 @@ struct pmic_mpp_state { struct regmap *map; struct pinctrl_dev *ctrl; struct gpio_chip chip; - struct irq_chip irq; }; static const struct pinconf_generic_params pmic_mpp_bindings[] = { @@ -823,6 +822,33 @@ static int pmic_mpp_child_to_parent_hwirq(struct gpio_chip *chip, return 0; } +static void pmic_mpp_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + irq_chip_mask_parent(d); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); +} + +static void pmic_mpp_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + irq_chip_unmask_parent(d); +} + +static const struct irq_chip pmic_mpp_irq_chip = { + .name = "spmi-mpp", + .irq_ack = irq_chip_ack_parent, + .irq_mask = pmic_mpp_irq_mask, + .irq_unmask = pmic_mpp_irq_unmask, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_wake = irq_chip_set_wake_parent, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static int pmic_mpp_probe(struct platform_device *pdev) { struct irq_domain *parent_domain; @@ -915,16 +941,8 @@ static int pmic_mpp_probe(struct platform_device *pdev) if (!parent_domain) return -ENXIO; - state->irq.name = "spmi-mpp", - state->irq.irq_ack = irq_chip_ack_parent, - state->irq.irq_mask = irq_chip_mask_parent, - state->irq.irq_unmask = irq_chip_unmask_parent, - state->irq.irq_set_type = irq_chip_set_type_parent, - state->irq.irq_set_wake = irq_chip_set_wake_parent, - state->irq.flags = IRQCHIP_MASK_ON_SUSPEND, - girq = &state->chip.irq; - girq->chip = &state->irq; + gpio_irq_chip_set_chip(girq, &pmic_mpp_irq_chip); girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; girq->fwnode = dev_fwnode(state->dev); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index e973001e5c88..dec1ffc49ffd 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -652,12 +652,30 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, return 0; } -static struct irq_chip pm8xxx_irq_chip = { +static void pm8xxx_irq_disable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); +} + +static void pm8xxx_irq_enable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); +} + +static const struct irq_chip pm8xxx_irq_chip = { .name = "ssbi-gpio", .irq_mask_ack = irq_chip_mask_ack_parent, .irq_unmask = irq_chip_unmask_parent, + .irq_disable = pm8xxx_irq_disable, + .irq_enable = pm8xxx_irq_enable, .irq_set_type = irq_chip_set_type_parent, - .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static int pm8xxx_domain_translate(struct irq_domain *domain, @@ -788,7 +806,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) return -ENXIO; girq = &pctrl->chip.irq; - girq->chip = &pm8xxx_irq_chip; + gpio_irq_chip_set_chip(girq, &pm8xxx_irq_chip); girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; girq->fwnode = dev_fwnode(pctrl->dev); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c index 86f66cb8bf30..b5aed540f07e 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -126,7 +126,6 @@ struct pm8xxx_mpp { struct regmap *regmap; struct pinctrl_dev *pctrl; struct gpio_chip chip; - struct irq_chip irq; struct pinctrl_desc desc; unsigned npins; @@ -778,6 +777,32 @@ static int pm8xxx_mpp_child_to_parent_hwirq(struct gpio_chip *chip, return 0; } +static void pm8xxx_mpp_irq_disable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); +} + +static void pm8xxx_mpp_irq_enable(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); +} + +static const struct irq_chip pm8xxx_mpp_irq_chip = { + .name = "ssbi-mpp", + .irq_mask_ack = irq_chip_mask_ack_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_disable = pm8xxx_mpp_irq_disable, + .irq_enable = pm8xxx_mpp_irq_enable, + .irq_set_type = irq_chip_set_type_parent, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static const struct of_device_id pm8xxx_mpp_of_match[] = { { .compatible = "qcom,pm8018-mpp", .data = (void *) 6 }, { .compatible = "qcom,pm8038-mpp", .data = (void *) 6 }, @@ -871,14 +896,8 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev) if (!parent_domain) return -ENXIO; - pctrl->irq.name = "ssbi-mpp"; - pctrl->irq.irq_mask_ack = irq_chip_mask_ack_parent; - pctrl->irq.irq_unmask = irq_chip_unmask_parent; - pctrl->irq.irq_set_type = irq_chip_set_type_parent; - pctrl->irq.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; - girq = &pctrl->chip.irq; - girq->chip = &pctrl->irq; + gpio_irq_chip_set_chip(girq, &pm8xxx_mpp_irq_chip); girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; girq->fwnode = dev_fwnode(pctrl->dev); diff --git a/drivers/pinctrl/ralink/Kconfig b/drivers/pinctrl/ralink/Kconfig deleted file mode 100644 index 1e4c5e43d69b..000000000000 --- a/drivers/pinctrl/ralink/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menu "Ralink pinctrl drivers" - depends on RALINK - -config PINCTRL_RALINK - bool "Ralink pinctrl driver" - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_MT7620 - bool "MT7620 pinctrl subdriver" - depends on RALINK && SOC_MT7620 - select PINCTRL_RALINK - -config PINCTRL_MT7621 - bool "MT7621 pinctrl subdriver" - depends on RALINK && SOC_MT7621 - select PINCTRL_RALINK - -config PINCTRL_RT2880 - bool "RT2880 pinctrl subdriver" - depends on RALINK && SOC_RT288X - select PINCTRL_RALINK - -config PINCTRL_RT305X - bool "RT305X pinctrl subdriver" - depends on RALINK && SOC_RT305X - select PINCTRL_RALINK - -config PINCTRL_RT3883 - bool "RT3883 pinctrl subdriver" - depends on RALINK && SOC_RT3883 - select PINCTRL_RALINK - -endmenu diff --git a/drivers/pinctrl/ralink/Makefile b/drivers/pinctrl/ralink/Makefile deleted file mode 100644 index 0ebbe552526d..000000000000 --- a/drivers/pinctrl/ralink/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PINCTRL_RALINK) += pinctrl-ralink.o - -obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o -obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o -obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o -obj-$(CONFIG_PINCTRL_RT305X) += pinctrl-rt305x.o -obj-$(CONFIG_PINCTRL_RT3883) += pinctrl-rt3883.o diff --git a/drivers/pinctrl/ralink/pinctrl-mt7620.c b/drivers/pinctrl/ralink/pinctrl-mt7620.c deleted file mode 100644 index 4e8d26bb3430..000000000000 --- a/drivers/pinctrl/ralink/pinctrl-mt7620.c +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include -#include -#include -#include "pinctrl-ralink.h" - -#define MT7620_GPIO_MODE_UART0_SHIFT 2 -#define MT7620_GPIO_MODE_UART0_MASK 0x7 -#define MT7620_GPIO_MODE_UART0(x) ((x) << MT7620_GPIO_MODE_UART0_SHIFT) -#define MT7620_GPIO_MODE_UARTF 0x0 -#define MT7620_GPIO_MODE_PCM_UARTF 0x1 -#define MT7620_GPIO_MODE_PCM_I2S 0x2 -#define MT7620_GPIO_MODE_I2S_UARTF 0x3 -#define MT7620_GPIO_MODE_PCM_GPIO 0x4 -#define MT7620_GPIO_MODE_GPIO_UARTF 0x5 -#define MT7620_GPIO_MODE_GPIO_I2S 0x6 -#define MT7620_GPIO_MODE_GPIO 0x7 - -#define MT7620_GPIO_MODE_NAND 0 -#define MT7620_GPIO_MODE_SD 1 -#define MT7620_GPIO_MODE_ND_SD_GPIO 2 -#define MT7620_GPIO_MODE_ND_SD_MASK 0x3 -#define MT7620_GPIO_MODE_ND_SD_SHIFT 18 - -#define MT7620_GPIO_MODE_PCIE_RST 0 -#define MT7620_GPIO_MODE_PCIE_REF 1 -#define MT7620_GPIO_MODE_PCIE_GPIO 2 -#define MT7620_GPIO_MODE_PCIE_MASK 0x3 -#define MT7620_GPIO_MODE_PCIE_SHIFT 16 - -#define MT7620_GPIO_MODE_WDT_RST 0 -#define MT7620_GPIO_MODE_WDT_REF 1 -#define MT7620_GPIO_MODE_WDT_GPIO 2 -#define MT7620_GPIO_MODE_WDT_MASK 0x3 -#define MT7620_GPIO_MODE_WDT_SHIFT 21 - -#define MT7620_GPIO_MODE_MDIO 0 -#define MT7620_GPIO_MODE_MDIO_REFCLK 1 -#define MT7620_GPIO_MODE_MDIO_GPIO 2 -#define MT7620_GPIO_MODE_MDIO_MASK 0x3 -#define MT7620_GPIO_MODE_MDIO_SHIFT 7 - -#define MT7620_GPIO_MODE_I2C 0 -#define MT7620_GPIO_MODE_UART1 5 -#define MT7620_GPIO_MODE_RGMII1 9 -#define MT7620_GPIO_MODE_RGMII2 10 -#define MT7620_GPIO_MODE_SPI 11 -#define MT7620_GPIO_MODE_SPI_REF_CLK 12 -#define MT7620_GPIO_MODE_WLED 13 -#define MT7620_GPIO_MODE_JTAG 15 -#define MT7620_GPIO_MODE_EPHY 15 -#define MT7620_GPIO_MODE_PA 20 - -static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; -static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; -static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; -static struct ralink_pmx_func mdio_grp[] = { - FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2), - FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2), -}; -static struct ralink_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) }; -static struct ralink_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) }; -static struct ralink_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) }; -static struct ralink_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) }; -static struct ralink_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) }; -static struct ralink_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) }; -static struct ralink_pmx_func uartf_grp[] = { - FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8), - FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8), - FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8), - FUNC("i2s uartf", MT7620_GPIO_MODE_I2S_UARTF, 7, 8), - FUNC("pcm gpio", MT7620_GPIO_MODE_PCM_GPIO, 11, 4), - FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4), - FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4), -}; -static struct ralink_pmx_func wdt_grp[] = { - FUNC("wdt rst", 0, 17, 1), - FUNC("wdt refclk", 0, 17, 1), - }; -static struct ralink_pmx_func pcie_rst_grp[] = { - FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1), - FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1) -}; -static struct ralink_pmx_func nd_sd_grp[] = { - FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15), - FUNC("sd", MT7620_GPIO_MODE_SD, 47, 13) -}; - -static struct ralink_pmx_group mt7620a_pinmux_data[] = { - GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C), - GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK, - MT7620_GPIO_MODE_UART0_SHIFT), - GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI), - GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1), - GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK, - MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT), - GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK, - MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT), - GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1), - GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK), - GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK, - MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT), - GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK, - MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT), - GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2), - GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED), - GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY), - GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA), - { 0 } -}; - -static struct ralink_pmx_func pwm1_grp_mt76x8[] = { - FUNC("sdxc d6", 3, 19, 1), - FUNC("utif", 2, 19, 1), - FUNC("gpio", 1, 19, 1), - FUNC("pwm1", 0, 19, 1), -}; - -static struct ralink_pmx_func pwm0_grp_mt76x8[] = { - FUNC("sdxc d7", 3, 18, 1), - FUNC("utif", 2, 18, 1), - FUNC("gpio", 1, 18, 1), - FUNC("pwm0", 0, 18, 1), -}; - -static struct ralink_pmx_func uart2_grp_mt76x8[] = { - FUNC("sdxc d5 d4", 3, 20, 2), - FUNC("pwm", 2, 20, 2), - FUNC("gpio", 1, 20, 2), - FUNC("uart2", 0, 20, 2), -}; - -static struct ralink_pmx_func uart1_grp_mt76x8[] = { - FUNC("sw_r", 3, 45, 2), - FUNC("pwm", 2, 45, 2), - FUNC("gpio", 1, 45, 2), - FUNC("uart1", 0, 45, 2), -}; - -static struct ralink_pmx_func i2c_grp_mt76x8[] = { - FUNC("-", 3, 4, 2), - FUNC("debug", 2, 4, 2), - FUNC("gpio", 1, 4, 2), - FUNC("i2c", 0, 4, 2), -}; - -static struct ralink_pmx_func refclk_grp_mt76x8[] = { FUNC("refclk", 0, 37, 1) }; -static struct ralink_pmx_func perst_grp_mt76x8[] = { FUNC("perst", 0, 36, 1) }; -static struct ralink_pmx_func wdt_grp_mt76x8[] = { FUNC("wdt", 0, 38, 1) }; -static struct ralink_pmx_func spi_grp_mt76x8[] = { FUNC("spi", 0, 7, 4) }; - -static struct ralink_pmx_func sd_mode_grp_mt76x8[] = { - FUNC("jtag", 3, 22, 8), - FUNC("utif", 2, 22, 8), - FUNC("gpio", 1, 22, 8), - FUNC("sdxc", 0, 22, 8), -}; - -static struct ralink_pmx_func uart0_grp_mt76x8[] = { - FUNC("-", 3, 12, 2), - FUNC("-", 2, 12, 2), - FUNC("gpio", 1, 12, 2), - FUNC("uart0", 0, 12, 2), -}; - -static struct ralink_pmx_func i2s_grp_mt76x8[] = { - FUNC("antenna", 3, 0, 4), - FUNC("pcm", 2, 0, 4), - FUNC("gpio", 1, 0, 4), - FUNC("i2s", 0, 0, 4), -}; - -static struct ralink_pmx_func spi_cs1_grp_mt76x8[] = { - FUNC("-", 3, 6, 1), - FUNC("refclk", 2, 6, 1), - FUNC("gpio", 1, 6, 1), - FUNC("spi cs1", 0, 6, 1), -}; - -static struct ralink_pmx_func spis_grp_mt76x8[] = { - FUNC("pwm_uart2", 3, 14, 4), - FUNC("utif", 2, 14, 4), - FUNC("gpio", 1, 14, 4), - FUNC("spis", 0, 14, 4), -}; - -static struct ralink_pmx_func gpio_grp_mt76x8[] = { - FUNC("pcie", 3, 11, 1), - FUNC("refclk", 2, 11, 1), - FUNC("gpio", 1, 11, 1), - FUNC("gpio", 0, 11, 1), -}; - -static struct ralink_pmx_func p4led_kn_grp_mt76x8[] = { - FUNC("jtag", 3, 30, 1), - FUNC("utif", 2, 30, 1), - FUNC("gpio", 1, 30, 1), - FUNC("p4led_kn", 0, 30, 1), -}; - -static struct ralink_pmx_func p3led_kn_grp_mt76x8[] = { - FUNC("jtag", 3, 31, 1), - FUNC("utif", 2, 31, 1), - FUNC("gpio", 1, 31, 1), - FUNC("p3led_kn", 0, 31, 1), -}; - -static struct ralink_pmx_func p2led_kn_grp_mt76x8[] = { - FUNC("jtag", 3, 32, 1), - FUNC("utif", 2, 32, 1), - FUNC("gpio", 1, 32, 1), - FUNC("p2led_kn", 0, 32, 1), -}; - -static struct ralink_pmx_func p1led_kn_grp_mt76x8[] = { - FUNC("jtag", 3, 33, 1), - FUNC("utif", 2, 33, 1), - FUNC("gpio", 1, 33, 1), - FUNC("p1led_kn", 0, 33, 1), -}; - -static struct ralink_pmx_func p0led_kn_grp_mt76x8[] = { - FUNC("jtag", 3, 34, 1), - FUNC("rsvd", 2, 34, 1), - FUNC("gpio", 1, 34, 1), - FUNC("p0led_kn", 0, 34, 1), -}; - -static struct ralink_pmx_func wled_kn_grp_mt76x8[] = { - FUNC("rsvd", 3, 35, 1), - FUNC("rsvd", 2, 35, 1), - FUNC("gpio", 1, 35, 1), - FUNC("wled_kn", 0, 35, 1), -}; - -static struct ralink_pmx_func p4led_an_grp_mt76x8[] = { - FUNC("jtag", 3, 39, 1), - FUNC("utif", 2, 39, 1), - FUNC("gpio", 1, 39, 1), - FUNC("p4led_an", 0, 39, 1), -}; - -static struct ralink_pmx_func p3led_an_grp_mt76x8[] = { - FUNC("jtag", 3, 40, 1), - FUNC("utif", 2, 40, 1), - FUNC("gpio", 1, 40, 1), - FUNC("p3led_an", 0, 40, 1), -}; - -static struct ralink_pmx_func p2led_an_grp_mt76x8[] = { - FUNC("jtag", 3, 41, 1), - FUNC("utif", 2, 41, 1), - FUNC("gpio", 1, 41, 1), - FUNC("p2led_an", 0, 41, 1), -}; - -static struct ralink_pmx_func p1led_an_grp_mt76x8[] = { - FUNC("jtag", 3, 42, 1), - FUNC("utif", 2, 42, 1), - FUNC("gpio", 1, 42, 1), - FUNC("p1led_an", 0, 42, 1), -}; - -static struct ralink_pmx_func p0led_an_grp_mt76x8[] = { - FUNC("jtag", 3, 43, 1), - FUNC("rsvd", 2, 43, 1), - FUNC("gpio", 1, 43, 1), - FUNC("p0led_an", 0, 43, 1), -}; - -static struct ralink_pmx_func wled_an_grp_mt76x8[] = { - FUNC("rsvd", 3, 44, 1), - FUNC("rsvd", 2, 44, 1), - FUNC("gpio", 1, 44, 1), - FUNC("wled_an", 0, 44, 1), -}; - -#define MT76X8_GPIO_MODE_MASK 0x3 - -#define MT76X8_GPIO_MODE_P4LED_KN 58 -#define MT76X8_GPIO_MODE_P3LED_KN 56 -#define MT76X8_GPIO_MODE_P2LED_KN 54 -#define MT76X8_GPIO_MODE_P1LED_KN 52 -#define MT76X8_GPIO_MODE_P0LED_KN 50 -#define MT76X8_GPIO_MODE_WLED_KN 48 -#define MT76X8_GPIO_MODE_P4LED_AN 42 -#define MT76X8_GPIO_MODE_P3LED_AN 40 -#define MT76X8_GPIO_MODE_P2LED_AN 38 -#define MT76X8_GPIO_MODE_P1LED_AN 36 -#define MT76X8_GPIO_MODE_P0LED_AN 34 -#define MT76X8_GPIO_MODE_WLED_AN 32 -#define MT76X8_GPIO_MODE_PWM1 30 -#define MT76X8_GPIO_MODE_PWM0 28 -#define MT76X8_GPIO_MODE_UART2 26 -#define MT76X8_GPIO_MODE_UART1 24 -#define MT76X8_GPIO_MODE_I2C 20 -#define MT76X8_GPIO_MODE_REFCLK 18 -#define MT76X8_GPIO_MODE_PERST 16 -#define MT76X8_GPIO_MODE_WDT 14 -#define MT76X8_GPIO_MODE_SPI 12 -#define MT76X8_GPIO_MODE_SDMODE 10 -#define MT76X8_GPIO_MODE_UART0 8 -#define MT76X8_GPIO_MODE_I2S 6 -#define MT76X8_GPIO_MODE_CS1 4 -#define MT76X8_GPIO_MODE_SPIS 2 -#define MT76X8_GPIO_MODE_GPIO 0 - -static struct ralink_pmx_group mt76x8_pinmux_data[] = { - GRP_G("pwm1", pwm1_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_PWM1), - GRP_G("pwm0", pwm0_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_PWM0), - GRP_G("uart2", uart2_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_UART2), - GRP_G("uart1", uart1_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_UART1), - GRP_G("i2c", i2c_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_I2C), - GRP("refclk", refclk_grp_mt76x8, 1, MT76X8_GPIO_MODE_REFCLK), - GRP("perst", perst_grp_mt76x8, 1, MT76X8_GPIO_MODE_PERST), - GRP("wdt", wdt_grp_mt76x8, 1, MT76X8_GPIO_MODE_WDT), - GRP("spi", spi_grp_mt76x8, 1, MT76X8_GPIO_MODE_SPI), - GRP_G("sdmode", sd_mode_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_SDMODE), - GRP_G("uart0", uart0_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_UART0), - GRP_G("i2s", i2s_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_I2S), - GRP_G("spi cs1", spi_cs1_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_CS1), - GRP_G("spis", spis_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_SPIS), - GRP_G("gpio", gpio_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_GPIO), - GRP_G("wled_an", wled_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_WLED_AN), - GRP_G("p0led_an", p0led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P0LED_AN), - GRP_G("p1led_an", p1led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P1LED_AN), - GRP_G("p2led_an", p2led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P2LED_AN), - GRP_G("p3led_an", p3led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P3LED_AN), - GRP_G("p4led_an", p4led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P4LED_AN), - GRP_G("wled_kn", wled_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_WLED_KN), - GRP_G("p0led_kn", p0led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P0LED_KN), - GRP_G("p1led_kn", p1led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P1LED_KN), - GRP_G("p2led_kn", p2led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P2LED_KN), - GRP_G("p3led_kn", p3led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P3LED_KN), - GRP_G("p4led_kn", p4led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK, - 1, MT76X8_GPIO_MODE_P4LED_KN), - { 0 } -}; - -static int mt7620_pinctrl_probe(struct platform_device *pdev) -{ - if (is_mt76x8()) - return ralink_pinctrl_init(pdev, mt76x8_pinmux_data); - else - return ralink_pinctrl_init(pdev, mt7620a_pinmux_data); -} - -static const struct of_device_id mt7620_pinctrl_match[] = { - { .compatible = "ralink,mt7620-pinctrl" }, - {} -}; -MODULE_DEVICE_TABLE(of, mt7620_pinctrl_match); - -static struct platform_driver mt7620_pinctrl_driver = { - .probe = mt7620_pinctrl_probe, - .driver = { - .name = "mt7620-pinctrl", - .of_match_table = mt7620_pinctrl_match, - }, -}; - -static int __init mt7620_pinctrl_init(void) -{ - return platform_driver_register(&mt7620_pinctrl_driver); -} -core_initcall_sync(mt7620_pinctrl_init); diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 0903a0a41831..77730dc548ed 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -27,7 +27,6 @@ config PINCTRL_RENESAS select PINCTRL_PFC_R8A7792 if ARCH_R8A7792 select PINCTRL_PFC_R8A7793 if ARCH_R8A7793 select PINCTRL_PFC_R8A7794 if ARCH_R8A7794 - select PINCTRL_PFC_R8A77950 if ARCH_R8A77950 select PINCTRL_PFC_R8A77951 if ARCH_R8A77951 select PINCTRL_PFC_R8A77960 if ARCH_R8A77960 select PINCTRL_PFC_R8A77961 if ARCH_R8A77961 @@ -103,10 +102,6 @@ config PINCTRL_PFC_R8A7790 bool "pin control support for R-Car H2" if COMPILE_TEST select PINCTRL_SH_PFC -config PINCTRL_PFC_R8A77950 - bool "pin control support for R-Car H3 ES1.x" if COMPILE_TEST - select PINCTRL_SH_PFC - config PINCTRL_PFC_R8A77951 bool "pin control support for R-Car H3 ES2.0+" if COMPILE_TEST select PINCTRL_SH_PFC diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile index 558b30ce0dec..3e776955bd4b 100644 --- a/drivers/pinctrl/renesas/Makefile +++ b/drivers/pinctrl/renesas/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_R8A7792) += pfc-r8a7792.o obj-$(CONFIG_PINCTRL_PFC_R8A7793) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_R8A7794) += pfc-r8a7794.o -obj-$(CONFIG_PINCTRL_PFC_R8A77950) += pfc-r8a77950.o obj-$(CONFIG_PINCTRL_PFC_R8A77951) += pfc-r8a77951.o obj-$(CONFIG_PINCTRL_PFC_R8A77960) += pfc-r8a7796.o obj-$(CONFIG_PINCTRL_PFC_R8A77961) += pfc-r8a7796.o diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c index c91102d3f1d1..0c8d081da6a8 100644 --- a/drivers/pinctrl/renesas/core.c +++ b/drivers/pinctrl/renesas/core.c @@ -573,23 +573,12 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a7794_pinmux_info, }, #endif -/* - * Both r8a7795 entries must be present to make sanity checks work, but only - * the first entry is actually used. - * R-Car H3 ES1.x is matched using soc_device_match() instead. - */ #ifdef CONFIG_PINCTRL_PFC_R8A77951 { .compatible = "renesas,pfc-r8a7795", .data = &r8a77951_pinmux_info, }, #endif -#ifdef CONFIG_PINCTRL_PFC_R8A77950 - { - .compatible = "renesas,pfc-r8a7795", - .data = &r8a77950_pinmux_info, - }, -#endif #ifdef CONFIG_PINCTRL_PFC_R8A77960 { .compatible = "renesas,pfc-r8a7796", @@ -656,7 +645,7 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &sh73a0_pinmux_info, }, #endif - { }, + { /* sentinel */ } }; #endif @@ -1125,9 +1114,9 @@ static void __init sh_pfc_check_info(const struct sh_pfc_soc_info *info) } } - if (pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE) { + if (pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE_MASK) { if (!info->ops || !info->ops->pin_to_pocctrl) - sh_pfc_err_once(power, "SH_PFC_PIN_CFG_IO_VOLTAGE flag set but .pin_to_pocctrl() not implemented\n"); + sh_pfc_err_once(power, "SH_PFC_PIN_CFG_IO_VOLTAGE set but .pin_to_pocctrl() not implemented\n"); else if (info->ops->pin_to_pocctrl(pin->pin, &x) < 0) sh_pfc_err("pin %s: SH_PFC_PIN_CFG_IO_VOLTAGE set but invalid pin_to_pocctrl()\n", pin->name); @@ -1309,41 +1298,15 @@ free_regs: static inline void sh_pfc_check_driver(struct platform_driver *pdrv) {} #endif /* !DEBUG */ -#ifdef CONFIG_OF -static const void *sh_pfc_quirk_match(void) -{ -#ifdef CONFIG_PINCTRL_PFC_R8A77950 - const struct soc_device_attribute *match; - static const struct soc_device_attribute quirks[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = &r8a77950_pinmux_info, - }, - { /* sentinel */ } - }; - - match = soc_device_match(quirks); - if (match) - return match->data; -#endif /* CONFIG_PINCTRL_PFC_R8A77950 */ - - return NULL; -} -#endif /* CONFIG_OF */ - static int sh_pfc_probe(struct platform_device *pdev) { const struct sh_pfc_soc_info *info; struct sh_pfc *pfc; int ret; -#ifdef CONFIG_OF - if (pdev->dev.of_node) { - info = sh_pfc_quirk_match(); - if (!info) - info = of_device_get_match_data(&pdev->dev); - } else -#endif + if (pdev->dev.of_node) + info = of_device_get_match_data(&pdev->dev); + else info = (const void *)platform_get_device_id(pdev)->driver_data; pfc = devm_kzalloc(&pdev->dev, sizeof(*pfc), GFP_KERNEL); @@ -1446,7 +1409,7 @@ static const struct platform_device_id sh_pfc_id_table[] = { #ifdef CONFIG_PINCTRL_PFC_SHX3 { "pfc-shx3", (kernel_ulong_t)&shx3_pinmux_info }, #endif - { }, + { /* sentinel */ } }; static struct platform_driver sh_pfc_driver = { diff --git a/drivers/pinctrl/renesas/pfc-emev2.c b/drivers/pinctrl/renesas/pfc-emev2.c index 1d8b540110f2..86d18b03668e 100644 --- a/drivers/pinctrl/renesas/pfc-emev2.c +++ b/drivers/pinctrl/renesas/pfc-emev2.c @@ -1644,7 +1644,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_SEL_HSI_1_0_00, FN_SEL_HSI_1_0_01, 0, 0, )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info emev2_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a73a4.c b/drivers/pinctrl/renesas/pfc-r8a73a4.c index dbfc46fe2f27..be0a4914eab3 100644 --- a/drivers/pinctrl/renesas/pfc-r8a73a4.c +++ b/drivers/pinctrl/renesas/pfc-r8a73a4.c @@ -2384,7 +2384,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MSEL8CR_00_0, MSEL8CR_00_1, )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2510,7 +2510,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PORT323_DATA, PORT322_DATA, PORT321_DATA, PORT320_DATA, )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_irq pinmux_irqs[] = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7740.c b/drivers/pinctrl/renesas/pfc-r8a7740.c index 6dcd39918daf..9ee3b700a3d3 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7740.c +++ b/drivers/pinctrl/renesas/pfc-r8a7740.c @@ -3348,7 +3348,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MSEL5CR_0_0, MSEL5CR_0_1, )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -3452,7 +3452,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { 0, 0, 0, 0, 0, 0, 0, 0 )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_irq pinmux_irqs[] = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77470.c b/drivers/pinctrl/renesas/pfc-r8a77470.c index b5725c3ed2b6..ed48b043763f 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77470.c +++ b/drivers/pinctrl/renesas/pfc-r8a77470.c @@ -13,24 +13,24 @@ #define CPU_ALL_GP(fn, sfx) \ PORT_GP_CFG_4(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(0, 4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(0, 11, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(0, 12, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(0, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(0, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_23(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ @@ -38,12 +38,12 @@ PORT_GP_CFG_1(3, 28, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(3, 29, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_14(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(4, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(4, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(4, 20, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(4, 21, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(4, 22, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ @@ -3252,7 +3252,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* SEL_SSI0 [2] */ FN_SEL_SSI0_0, FN_SEL_SSI0_1, 0, 0, )) }, - { }, + { /* sentinel */ } }; static int r8a77470_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) diff --git a/drivers/pinctrl/renesas/pfc-r8a7778.c b/drivers/pinctrl/renesas/pfc-r8a7778.c index 35bdb9af8160..c52761d80f7b 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7778.c +++ b/drivers/pinctrl/renesas/pfc-r8a7778.c @@ -2832,7 +2832,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_SEL_I2C1_A, FN_SEL_I2C1_B, )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_bias_reg pinmux_bias_regs[] = { @@ -3040,7 +3040,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a7778_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7779.c b/drivers/pinctrl/renesas/pfc-r8a7779.c index fcc8ea48881f..1172a359384d 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7779.c +++ b/drivers/pinctrl/renesas/pfc-r8a7779.c @@ -12,13 +12,76 @@ #include "sh_pfc.h" #define CPU_ALL_GP(fn, sfx) \ - PORT_GP_32(0, fn, sfx), \ - PORT_GP_32(1, fn, sfx), \ - PORT_GP_32(2, fn, sfx), \ - PORT_GP_32(3, fn, sfx), \ - PORT_GP_32(4, fn, sfx), \ - PORT_GP_32(5, fn, sfx), \ - PORT_GP_9(6, fn, sfx) + PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_32(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(2, 0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_1(2, 1, fn, sfx), \ + PORT_GP_1(2, 2, fn, sfx), \ + PORT_GP_1(2, 3, fn, sfx), \ + PORT_GP_1(2, 4, fn, sfx), \ + PORT_GP_1(2, 5, fn, sfx), \ + PORT_GP_1(2, 6, fn, sfx), \ + PORT_GP_1(2, 7, fn, sfx), \ + PORT_GP_1(2, 8, fn, sfx), \ + PORT_GP_1(2, 9, fn, sfx), \ + PORT_GP_1(2, 10, fn, sfx), \ + PORT_GP_1(2, 11, fn, sfx), \ + PORT_GP_1(2, 12, fn, sfx), \ + PORT_GP_1(2, 13, fn, sfx), \ + PORT_GP_1(2, 14, fn, sfx), \ + PORT_GP_1(2, 15, fn, sfx), \ + PORT_GP_1(2, 16, fn, sfx), \ + PORT_GP_1(2, 17, fn, sfx), \ + PORT_GP_1(2, 18, fn, sfx), \ + PORT_GP_1(2, 19, fn, sfx), \ + PORT_GP_1(2, 20, fn, sfx), \ + PORT_GP_1(2, 21, fn, sfx), \ + PORT_GP_1(2, 22, fn, sfx), \ + PORT_GP_1(2, 23, fn, sfx), \ + PORT_GP_1(2, 24, fn, sfx), \ + PORT_GP_1(2, 25, fn, sfx), \ + PORT_GP_1(2, 26, fn, sfx), \ + PORT_GP_1(2, 27, fn, sfx), \ + PORT_GP_1(2, 28, fn, sfx), \ + PORT_GP_1(2, 29, fn, sfx), \ + PORT_GP_CFG_1(2, 30, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(2, 31, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_25(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_1(3, 25, fn, sfx), \ + PORT_GP_1(3, 26, fn, sfx), \ + PORT_GP_1(3, 27, fn, sfx), \ + PORT_GP_CFG_1(3, 28, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(3, 29, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(3, 30, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(3, 31, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_32(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_9(6, fn, sfx, SH_PFC_PIN_CFG_PULL_UP) + +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(ASEBRK_N_ACK, "ASEBRK#/ACK", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D0, "D0", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D1, "D1", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D2, "D2", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D3, "D3", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D4, "D4", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D5, "D5", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D6, "D6", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D7, "D7", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D8, "D8", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D9, "D9", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D10, "D10", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D11, "D11", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D12, "D12", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D13, "D13", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D14, "D14", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(D15, "D15", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP) enum { PINMUX_RESERVED = 0, @@ -1390,8 +1453,17 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MSEL(IP12_17_15, SCK4_B, SEL_SCIF4_1), }; +/* + * Pins not associated with a GPIO port. + */ +enum { + GP_ASSIGN_LAST(), + NOGP_ALL(), +}; + static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), + PINMUX_NOGP_ALL(), }; /* - DU0 -------------------------------------------------------------------- */ @@ -1962,6 +2034,67 @@ static const unsigned int mmc1_ctrl_pins[] = { static const unsigned int mmc1_ctrl_mux[] = { MMC1_CMD_MARK, MMC1_CLK_MARK, }; +/* - PWM -------------------------------------------------------------------- */ +static const unsigned int pwm0_pins[] = { + RCAR_GP_PIN(1, 3), +}; +static const unsigned int pwm0_mux[] = { + PWM0_MARK, +}; +static const unsigned int pwm0_b_pins[] = { + RCAR_GP_PIN(0, 12), +}; +static const unsigned int pwm0_b_mux[] = { + PWM0_B_MARK, +}; +static const unsigned int pwm0_c_pins[] = { + RCAR_GP_PIN(4, 5), +}; +static const unsigned int pwm0_c_mux[] = { + PWM0_C_MARK, +}; +static const unsigned int pwm0_d_pins[] = { + RCAR_GP_PIN(4, 18), +}; +static const unsigned int pwm0_d_mux[] = { + PWM0_D_MARK, +}; +static const unsigned int pwm1_pins[] = { + RCAR_GP_PIN(4, 28), +}; +static const unsigned int pwm1_mux[] = { + PWM1_MARK, +}; +static const unsigned int pwm2_pins[] = { + RCAR_GP_PIN(3, 25), +}; +static const unsigned int pwm2_mux[] = { + PWM2_MARK, +}; +static const unsigned int pwm3_pins[] = { + RCAR_GP_PIN(3, 26), +}; +static const unsigned int pwm3_mux[] = { + PWM3_MARK, +}; +static const unsigned int pwm4_pins[] = { + RCAR_GP_PIN(3, 27), +}; +static const unsigned int pwm4_mux[] = { + PWM4_MARK, +}; +static const unsigned int pwm5_pins[] = { + RCAR_GP_PIN(4, 17), +}; +static const unsigned int pwm5_mux[] = { + PWM5_MARK, +}; +static const unsigned int pwm6_pins[] = { + RCAR_GP_PIN(1, 2), +}; +static const unsigned int pwm6_mux[] = { + PWM6_MARK, +}; /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { /* RXD, TXD */ @@ -2699,6 +2832,16 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { BUS_DATA_PIN_GROUP(mmc1_data, 4), BUS_DATA_PIN_GROUP(mmc1_data, 8), SH_PFC_PIN_GROUP(mmc1_ctrl), + SH_PFC_PIN_GROUP(pwm0), + SH_PFC_PIN_GROUP(pwm0_b), + SH_PFC_PIN_GROUP(pwm0_c), + SH_PFC_PIN_GROUP(pwm0_d), + SH_PFC_PIN_GROUP(pwm1), + SH_PFC_PIN_GROUP(pwm2), + SH_PFC_PIN_GROUP(pwm3), + SH_PFC_PIN_GROUP(pwm4), + SH_PFC_PIN_GROUP(pwm5), + SH_PFC_PIN_GROUP(pwm6), SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), @@ -2912,6 +3055,37 @@ static const char * const mmc1_groups[] = { "mmc1_ctrl", }; +static const char * const pwm0_groups[] = { + "pwm0", + "pwm0_b", + "pwm0_c", + "pwm0_d", +}; + +static const char * const pwm1_groups[] = { + "pwm1", +}; + +static const char * const pwm2_groups[] = { + "pwm2", +}; + +static const char * const pwm3_groups[] = { + "pwm3", +}; + +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 scif0_groups[] = { "scif0_data", "scif0_clk", @@ -3075,6 +3249,13 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(lbsc), SH_PFC_FUNCTION(mmc0), SH_PFC_FUNCTION(mmc1), + 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(scif0), SH_PFC_FUNCTION(scif1), SH_PFC_FUNCTION(scif2), @@ -3919,11 +4100,259 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* SEL_I2C1 [2] */ FN_SEL_I2C1_0, FN_SEL_I2C1_1, FN_SEL_I2C1_2, FN_SEL_I2C1_3 )) }, - { }, + { /* sentinel */ } +}; + +static const struct pinmux_bias_reg pinmux_bias_regs[] = { + { PINMUX_BIAS_REG("PUPR0", 0xfffc0100, "N/A", 0) { + [ 0] = RCAR_GP_PIN(0, 2), /* A0 */ + [ 1] = RCAR_GP_PIN(5, 0), /* A1 */ + [ 2] = RCAR_GP_PIN(5, 1), /* A2 */ + [ 3] = RCAR_GP_PIN(5, 2), /* A3 */ + [ 4] = RCAR_GP_PIN(5, 3), /* A4 */ + [ 5] = RCAR_GP_PIN(5, 4), /* A5 */ + [ 6] = RCAR_GP_PIN(5, 5), /* A6 */ + [ 7] = RCAR_GP_PIN(5, 6), /* A7 */ + [ 8] = RCAR_GP_PIN(5, 7), /* A8 */ + [ 9] = RCAR_GP_PIN(5, 8), /* A9 */ + [10] = RCAR_GP_PIN(5, 9), /* A10 */ + [11] = RCAR_GP_PIN(5, 10), /* A11 */ + [12] = RCAR_GP_PIN(5, 11), /* A12 */ + [13] = RCAR_GP_PIN(5, 12), /* A13 */ + [14] = RCAR_GP_PIN(5, 13), /* A14 */ + [15] = RCAR_GP_PIN(5, 14), /* A15 */ + [16] = RCAR_GP_PIN(5, 15), /* A16 */ + [17] = RCAR_GP_PIN(0, 3), /* A17 */ + [18] = RCAR_GP_PIN(0, 4), /* A18 */ + [19] = RCAR_GP_PIN(0, 5), /* A19 */ + [20] = RCAR_GP_PIN(0, 6), /* A20 */ + [21] = RCAR_GP_PIN(0, 7), /* A21 */ + [22] = RCAR_GP_PIN(0, 8), /* A22 */ + [23] = RCAR_GP_PIN(0, 9), /* A23 */ + [24] = RCAR_GP_PIN(0, 10), /* A24 */ + [25] = RCAR_GP_PIN(0, 11), /* A25 */ + [26] = RCAR_GP_PIN(0, 15), /* EX_CS0# */ + [27] = RCAR_GP_PIN(0, 16), /* EX_CS1# */ + [28] = RCAR_GP_PIN(0, 17), /* EX_CS2# */ + [29] = RCAR_GP_PIN(0, 18), /* EX_CS3# */ + [30] = RCAR_GP_PIN(0, 19), /* EX_CS4# */ + [31] = RCAR_GP_PIN(0, 20), /* EX_CS5# */ + } }, + { PINMUX_BIAS_REG("PUPR1", 0xfffc0104, "N/A", 0) { + [ 0] = PIN_PRESETOUT_N, /* PRESETOUT# */ + [ 1] = RCAR_GP_PIN(0, 21), /* BS# */ + [ 2] = RCAR_GP_PIN(0, 22), /* RD/WR# */ + [ 3] = RCAR_GP_PIN(5, 17), /* WE0# */ + [ 4] = RCAR_GP_PIN(5, 18), /* WE1# */ + [ 5] = RCAR_GP_PIN(5, 19), /* EX_WAIT0 */ + [ 6] = RCAR_GP_PIN(0, 0), /* AVS1 */ + [ 7] = RCAR_GP_PIN(0, 1), /* AVS2 */ + [ 8] = SH_PFC_PIN_NONE, + [ 9] = SH_PFC_PIN_NONE, + [10] = PIN_TRST_N, /* TRST# */ + [11] = PIN_TCK, /* TCK */ + [12] = PIN_TMS, /* TMS */ + [13] = PIN_TDI, /* TDI */ + [14] = PIN_TDO, /* TDO */ + [15] = PIN_ASEBRK_N_ACK, /* ASEBRK#/ACK */ + [16] = PIN_D0, /* D0 */ + [17] = PIN_D1, /* D1 */ + [18] = PIN_D2, /* D2 */ + [19] = PIN_D3, /* D3 */ + [20] = PIN_D4, /* D4 */ + [21] = PIN_D5, /* D5 */ + [22] = PIN_D6, /* D6 */ + [23] = PIN_D7, /* D7 */ + [24] = PIN_D8, /* D8 */ + [25] = PIN_D9, /* D9 */ + [26] = PIN_D10, /* D10 */ + [27] = PIN_D11, /* D11 */ + [28] = PIN_D12, /* D12 */ + [29] = PIN_D13, /* D13 */ + [30] = PIN_D14, /* D14 */ + [31] = PIN_D15, /* D15 */ + } }, + { PINMUX_BIAS_REG("PUPR2", 0xfffc0108, "N/A", 0) { + [ 0] = RCAR_GP_PIN(0, 23), /* DU0_DR0 */ + [ 1] = RCAR_GP_PIN(0, 24), /* DU0_DR1 */ + [ 2] = RCAR_GP_PIN(5, 23), /* DU0_DR2 */ + [ 3] = RCAR_GP_PIN(5, 24), /* DU0_DR3 */ + [ 4] = RCAR_GP_PIN(5, 25), /* DU0_DR4 */ + [ 5] = RCAR_GP_PIN(5, 26), /* DU0_DR5 */ + [ 6] = RCAR_GP_PIN(5, 27), /* DU0_DR6 */ + [ 7] = RCAR_GP_PIN(5, 28), /* DU0_DR7 */ + [ 8] = RCAR_GP_PIN(0, 25), /* DU0_DG0 */ + [ 9] = RCAR_GP_PIN(0, 26), /* DU0_DG1 */ + [10] = RCAR_GP_PIN(5, 29), /* DU0_DG2 */ + [11] = RCAR_GP_PIN(5, 30), /* DU0_DG3 */ + [12] = RCAR_GP_PIN(5, 31), /* DU0_DG4 */ + [13] = RCAR_GP_PIN(6, 0), /* DU0_DG5 */ + [14] = RCAR_GP_PIN(6, 1), /* DU0_DG6 */ + [15] = RCAR_GP_PIN(6, 2), /* DU0_DG7 */ + [16] = RCAR_GP_PIN(0, 27), /* DU0_DB0 */ + [17] = RCAR_GP_PIN(0, 28), /* DU0_DB1 */ + [18] = RCAR_GP_PIN(6, 3), /* DU0_DB2 */ + [19] = RCAR_GP_PIN(6, 4), /* DU0_DB3 */ + [20] = RCAR_GP_PIN(6, 5), /* DU0_DB4 */ + [21] = RCAR_GP_PIN(6, 6), /* DU0_DB5 */ + [22] = RCAR_GP_PIN(6, 7), /* DU0_DB6 */ + [23] = RCAR_GP_PIN(6, 8), /* DU0_DB7 */ + [24] = RCAR_GP_PIN(0, 29), /* DU0_DOTCLKIN */ + [25] = RCAR_GP_PIN(5, 20), /* DU0_DOTCLKOUT0 */ + [26] = RCAR_GP_PIN(5, 21), /* DU0_HSYNC */ + [27] = RCAR_GP_PIN(5, 22), /* DU0_VSYNC */ + [28] = RCAR_GP_PIN(0, 31), /* DU0_EXODDF */ + [29] = RCAR_GP_PIN(1, 0), /* DU0_DISP */ + [30] = RCAR_GP_PIN(1, 1), /* DU0_CDE */ + [31] = RCAR_GP_PIN(0, 30), /* DU0_DOTCLKOUT1 */ + } }, + { PINMUX_BIAS_REG("PUPR3", 0xfffc010c, "N/A", 0) { + [ 0] = RCAR_GP_PIN(1, 2), /* DU1_DR0 */ + [ 1] = RCAR_GP_PIN(1, 3), /* DU1_DR1 */ + [ 2] = RCAR_GP_PIN(1, 4), /* DU1_DR2 */ + [ 3] = RCAR_GP_PIN(1, 5), /* DU1_DR3 */ + [ 4] = RCAR_GP_PIN(1, 6), /* DU1_DR4 */ + [ 5] = RCAR_GP_PIN(1, 7), /* DU1_DR5 */ + [ 6] = RCAR_GP_PIN(1, 8), /* DU1_DR6 */ + [ 7] = RCAR_GP_PIN(1, 9), /* DU1_DR7 */ + [ 8] = RCAR_GP_PIN(1, 10), /* DU1_DG0 */ + [ 9] = RCAR_GP_PIN(1, 11), /* DU1_DG1 */ + [10] = RCAR_GP_PIN(1, 12), /* DU1_DG2 */ + [11] = RCAR_GP_PIN(1, 13), /* DU1_DG3 */ + [12] = RCAR_GP_PIN(1, 14), /* DU1_DG4 */ + [13] = RCAR_GP_PIN(1, 15), /* DU1_DG5 */ + [14] = RCAR_GP_PIN(1, 16), /* DU1_DG6 */ + [15] = RCAR_GP_PIN(1, 17), /* DU1_DG7 */ + [16] = RCAR_GP_PIN(1, 18), /* DU1_DB0 */ + [17] = RCAR_GP_PIN(1, 19), /* DU1_DB1 */ + [18] = RCAR_GP_PIN(1, 20), /* DU1_DB2 */ + [19] = RCAR_GP_PIN(1, 21), /* DU1_DB3 */ + [20] = RCAR_GP_PIN(1, 22), /* DU1_DB4 */ + [21] = RCAR_GP_PIN(1, 23), /* DU1_DB5 */ + [22] = RCAR_GP_PIN(1, 24), /* DU1_DB6 */ + [23] = RCAR_GP_PIN(1, 25), /* DU1_DB7 */ + [24] = RCAR_GP_PIN(1, 26), /* DU1_DOTCLKIN */ + [25] = RCAR_GP_PIN(1, 27), /* DU1_DOTCLKOUT */ + [26] = RCAR_GP_PIN(1, 28), /* DU1_HSYNC */ + [27] = RCAR_GP_PIN(1, 29), /* DU1_VSYNC */ + [28] = RCAR_GP_PIN(1, 30), /* DU1_EXODDF */ + [29] = RCAR_GP_PIN(1, 31), /* DU1_DISP */ + [30] = RCAR_GP_PIN(2, 0), /* DU1_CDE */ + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("PUPR4", 0xfffc0110, "N/A", 0) { + [ 0] = RCAR_GP_PIN(2, 30), /* VI1_CLK */ + [ 1] = SH_PFC_PIN_NONE, + [ 2] = SH_PFC_PIN_NONE, + [ 3] = RCAR_GP_PIN(2, 31), /* VI1_HSYNC# */ + [ 4] = RCAR_GP_PIN(3, 0), /* VI1_VSYNC# */ + [ 5] = RCAR_GP_PIN(3, 1), /* VI1_DATA0 */ + [ 6] = RCAR_GP_PIN(3, 2), /* VI1_DATA1 */ + [ 7] = RCAR_GP_PIN(3, 3), /* VI1_DATA2 */ + [ 8] = RCAR_GP_PIN(3, 4), /* VI1_DATA3 */ + [ 9] = RCAR_GP_PIN(3, 5), /* VI1_DATA4 */ + [10] = RCAR_GP_PIN(3, 6), /* VI1_DATA5 */ + [11] = RCAR_GP_PIN(3, 7), /* VI1_DATA6 */ + [12] = RCAR_GP_PIN(3, 8), /* VI1_DATA7 */ + [13] = RCAR_GP_PIN(3, 9), /* VI1_G0 */ + [14] = RCAR_GP_PIN(3, 10), /* VI1_G1 */ + [15] = RCAR_GP_PIN(3, 11), /* VI1_G2 */ + [16] = RCAR_GP_PIN(3, 12), /* VI1_G3 */ + [17] = RCAR_GP_PIN(3, 13), /* VI1_G4 */ + [18] = RCAR_GP_PIN(3, 14), /* VI1_G5 */ + [19] = RCAR_GP_PIN(3, 15), /* VI1_G6 */ + [20] = RCAR_GP_PIN(3, 16), /* VI1_G7 */ + [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("PUPR5", 0xfffc0114, "N/A", 0) { + [ 0] = RCAR_GP_PIN(3, 30), /* SSI_SCK0129 */ + [ 1] = RCAR_GP_PIN(3, 31), /* SSI_WS0129 */ + [ 2] = RCAR_GP_PIN(4, 0), /* SSI_SDATA0 */ + [ 3] = RCAR_GP_PIN(4, 1), /* SSI_SDATA1 */ + [ 4] = RCAR_GP_PIN(4, 2), /* SSI_SDATA2 */ + [ 5] = RCAR_GP_PIN(4, 3), /* SSI_SCK34 */ + [ 6] = RCAR_GP_PIN(4, 4), /* SSI_WS34 */ + [ 7] = RCAR_GP_PIN(4, 5), /* SSI_SDATA3 */ + [ 8] = RCAR_GP_PIN(4, 6), /* SSI_SDATA4 */ + [ 9] = RCAR_GP_PIN(4, 7), /* SSI_SCK5 */ + [10] = RCAR_GP_PIN(4, 8), /* SSI_WS5 */ + [11] = RCAR_GP_PIN(4, 9), /* SSI_SDATA5 */ + [12] = RCAR_GP_PIN(4, 10), /* SSI_SCK6 */ + [13] = RCAR_GP_PIN(4, 11), /* SSI_WS6 */ + [14] = RCAR_GP_PIN(4, 12), /* SSI_SDATA6 */ + [15] = RCAR_GP_PIN(4, 13), /* SSI_SCK78 */ + [16] = RCAR_GP_PIN(4, 14), /* SSI_WS78 */ + [17] = RCAR_GP_PIN(4, 15), /* SSI_SDATA7 */ + [18] = RCAR_GP_PIN(4, 16), /* SSI_SDATA8 */ + [19] = SH_PFC_PIN_NONE, + [20] = RCAR_GP_PIN(3, 17), /* SD0_CLK */ + [21] = RCAR_GP_PIN(3, 18), /* SD0_CMD */ + [22] = RCAR_GP_PIN(3, 21), /* SD0_DAT0 */ + [23] = RCAR_GP_PIN(3, 22), /* SD0_DAT1 */ + [24] = RCAR_GP_PIN(3, 23), /* SD0_DAT2 */ + [25] = RCAR_GP_PIN(3, 24), /* SD0_DAT3 */ + [26] = RCAR_GP_PIN(3, 19), /* SD0_CD */ + [27] = RCAR_GP_PIN(3, 20), /* SD0_WP */ + [28] = RCAR_GP_PIN(3, 28), /* AUDIO_CLKA */ + [29] = RCAR_GP_PIN(3, 29), /* AUDIO_CLKB */ + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("PUPR6", 0xfffc0118, "N/A", 0) { + [ 0] = RCAR_GP_PIN(4, 26), /* PENC0 */ + [ 1] = RCAR_GP_PIN(4, 27), /* PENC1 */ + [ 2] = RCAR_GP_PIN(4, 28), /* PENC2 */ + [ 3] = SH_PFC_PIN_NONE, + [ 4] = SH_PFC_PIN_NONE, + [ 5] = RCAR_GP_PIN(4, 20), /* HTX0 */ + [ 6] = RCAR_GP_PIN(4, 21), /* HRX0 */ + [ 7] = RCAR_GP_PIN(4, 17), /* HSCK0 */ + [ 8] = RCAR_GP_PIN(4, 18), /* HCTS0# */ + [ 9] = RCAR_GP_PIN(4, 19), /* HRTS0# */ + [10] = RCAR_GP_PIN(4, 22), /* HSPI_CLK0 */ + [11] = RCAR_GP_PIN(4, 23), /* HSPI_CS0# */ + [12] = RCAR_GP_PIN(4, 24), /* HSPI_TX0 */ + [13] = RCAR_GP_PIN(4, 25), /* HSPI_RX0 */ + [14] = RCAR_GP_PIN(4, 29), /* FMCLK */ + [15] = RCAR_GP_PIN(4, 30), /* BPFCLK */ + [16] = RCAR_GP_PIN(4, 31), /* FMIN */ + [17] = RCAR_GP_PIN(0, 12), /* CLKOUT */ + [18] = RCAR_GP_PIN(0, 13), /* CS0# */ + [19] = RCAR_GP_PIN(0, 14), /* CS1#/A26 */ + [20] = RCAR_GP_PIN(5, 16), /* RD# */ + [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 r8a7779_pfc_ops = { + .get_bias = rcar_pinmux_get_bias, + .set_bias = rcar_pinmux_set_bias, }; const struct sh_pfc_soc_info r8a7779_pinmux_info = { .name = "r8a7779_pfc", + .ops = &r8a7779_pfc_ops, .unlock_reg = 0xfffc0000, /* PMMR */ @@ -3937,6 +4366,7 @@ const struct sh_pfc_soc_info r8a7779_pinmux_info = { .nr_functions = ARRAY_SIZE(pinmux_functions), .cfg_regs = pinmux_config_regs, + .bias_regs = pinmux_bias_regs, .pinmux_data = pinmux_data, .pinmux_data_size = ARRAY_SIZE(pinmux_data), diff --git a/drivers/pinctrl/renesas/pfc-r8a7790.c b/drivers/pinctrl/renesas/pfc-r8a7790.c index ee21d650991b..791e089d47db 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7790.c +++ b/drivers/pinctrl/renesas/pfc-r8a7790.c @@ -24,7 +24,7 @@ PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_30(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP) @@ -5824,7 +5824,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* SEL_I2C1 [2] */ FN_SEL_I2C1_0, FN_SEL_I2C1_1, FN_SEL_I2C1_2, 0, )) }, - { }, + { /* sentinel */ } }; static int r8a7790_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) diff --git a/drivers/pinctrl/renesas/pfc-r8a7791.c b/drivers/pinctrl/renesas/pfc-r8a7791.c index d57458504117..d9e5ce0dfb5b 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7791.c +++ b/drivers/pinctrl/renesas/pfc-r8a7791.c @@ -22,7 +22,7 @@ PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_32(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_24(6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_24(6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(6, 24, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(6, 25, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(6, 26, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ @@ -6552,7 +6552,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_SEL_SSP_0, FN_SEL_SSP_1, FN_SEL_SSP_2, 0, /* RESERVED [6] */ )) }, - { }, + { /* sentinel */ } }; static int r8a7791_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -6874,7 +6874,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a7791_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7792.c b/drivers/pinctrl/renesas/pfc-r8a7792.c index 808a85d62415..2c51c32b8e09 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7792.c +++ b/drivers/pinctrl/renesas/pfc-r8a7792.c @@ -2625,7 +2625,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* IP7_1_0 [2] */ FN_PWM0, FN_TCLK1, FN_FSO_CFE_0, 0 )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_bias_reg pinmux_bias_regs[] = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7794.c b/drivers/pinctrl/renesas/pfc-r8a7794.c index 668643553a70..e800fef91ddb 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7794.c +++ b/drivers/pinctrl/renesas/pfc-r8a7794.c @@ -42,30 +42,30 @@ PORT_GP_1(5, 25, fn, sfx), \ PORT_GP_1(5, 26, fn, sfx), \ PORT_GP_1(5, 27, fn, sfx), \ - PORT_GP_CFG_1(6, 0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_CFG_1(6, 1, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_CFG_1(6, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 11, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 12, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_CFG_1(6, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ - PORT_GP_CFG_1(6, 23, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ + PORT_GP_CFG_1(6, 1, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ + PORT_GP_CFG_1(6, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 11, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 12, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ + PORT_GP_CFG_1(6, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ + PORT_GP_CFG_1(6, 23, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(6, 24, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ PORT_GP_CFG_1(6, 25, fn, sfx, SH_PFC_PIN_CFG_PULL_UP) @@ -5512,7 +5512,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_SEL_SSI9_0, FN_SEL_SSI9_1, /* RESERVED [12] */ )) }, - { }, + { /* sentinel */ } }; static int r8a7794_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) diff --git a/drivers/pinctrl/renesas/pfc-r8a77950.c b/drivers/pinctrl/renesas/pfc-r8a77950.c deleted file mode 100644 index cc66c6de045c..000000000000 --- a/drivers/pinctrl/renesas/pfc-r8a77950.c +++ /dev/null @@ -1,5947 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * R8A77950 processor support - PFC hardware block. - * - * Copyright (C) 2015-2017 Renesas Electronics Corporation - */ - -#include -#include - -#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_16(0, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_28(1, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ - 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_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ - PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) - -#define CPU_ALL_NOGP(fn) \ - PIN_NOGP_CFG(ASEBRK, "ASEBRK", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_MDIO, "AVB_MDIO", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RD0, "AVB_RD0", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RD1, "AVB_RD1", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RD2, "AVB_RD2", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RD3, "AVB_RD3", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RXC, "AVB_RXC", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_RX_CTL, "AVB_RX_CTL", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TD0, "AVB_TD0", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TD1, "AVB_TD1", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TD2, "AVB_TD2", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TD3, "AVB_TD3", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TXC, "AVB_TXC", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TXCREFCLK, "AVB_TXCREFCLK", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(AVB_TX_CTL, "AVB_TX_CTL", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(CLKOUT, "CLKOUT", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(DU_DOTCLKIN0, "DU_DOTCLKIN0", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(DU_DOTCLKIN1, "DU_DOTCLKIN1", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(DU_DOTCLKIN2, "DU_DOTCLKIN2", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(DU_DOTCLKIN3, "DU_DOTCLKIN3", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN),\ - PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(MLB_REF, "MLB_REF", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_IO2, "QSPI0_IO2", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_IO3, "QSPI0_IO3", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_MISO_IO1, "QSPI0_MISO_IO1", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_MOSI_IO0, "QSPI0_MOSI_IO0", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_SPCLK, "QSPI0_SPCLK", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI0_SSL, "QSPI0_SSL", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_IO2, "QSPI1_IO2", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_IO3, "QSPI1_IO3", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_MISO_IO1, "QSPI1_MISO_IO1", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_MOSI_IO0, "QSPI1_MOSI_IO0", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_SPCLK, "QSPI1_SPCLK", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(QSPI1_SSL, "QSPI1_SSL", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(RPC_INT_N, "RPC_INT#", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(RPC_RESET_N, "RPC_RESET#", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(RPC_WP_N, "RPC_WP#", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ - PIN_NOGP_CFG(TMS, "TMS", fn, CFG_FLAGS), \ - PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) - -/* - * F_() : just information - * FM() : macro for FN_xxx / xxx_MARK - */ - -/* GPSR0 */ -#define GPSR0_15 F_(D15, IP7_11_8) -#define GPSR0_14 F_(D14, IP7_7_4) -#define GPSR0_13 F_(D13, IP7_3_0) -#define GPSR0_12 F_(D12, IP6_31_28) -#define GPSR0_11 F_(D11, IP6_27_24) -#define GPSR0_10 F_(D10, IP6_23_20) -#define GPSR0_9 F_(D9, IP6_19_16) -#define GPSR0_8 F_(D8, IP6_15_12) -#define GPSR0_7 F_(D7, IP6_11_8) -#define GPSR0_6 F_(D6, IP6_7_4) -#define GPSR0_5 F_(D5, IP6_3_0) -#define GPSR0_4 F_(D4, IP5_31_28) -#define GPSR0_3 F_(D3, IP5_27_24) -#define GPSR0_2 F_(D2, IP5_23_20) -#define GPSR0_1 F_(D1, IP5_19_16) -#define GPSR0_0 F_(D0, IP5_15_12) - -/* GPSR1 */ -#define GPSR1_27 F_(EX_WAIT0_A, IP5_11_8) -#define GPSR1_26 F_(WE1_N, IP5_7_4) -#define GPSR1_25 F_(WE0_N, IP5_3_0) -#define GPSR1_24 F_(RD_WR_N, IP4_31_28) -#define GPSR1_23 F_(RD_N, IP4_27_24) -#define GPSR1_22 F_(BS_N, IP4_23_20) -#define GPSR1_21 F_(CS1_N_A26, IP4_19_16) -#define GPSR1_20 F_(CS0_N, IP4_15_12) -#define GPSR1_19 F_(A19, IP4_11_8) -#define GPSR1_18 F_(A18, IP4_7_4) -#define GPSR1_17 F_(A17, IP4_3_0) -#define GPSR1_16 F_(A16, IP3_31_28) -#define GPSR1_15 F_(A15, IP3_27_24) -#define GPSR1_14 F_(A14, IP3_23_20) -#define GPSR1_13 F_(A13, IP3_19_16) -#define GPSR1_12 F_(A12, IP3_15_12) -#define GPSR1_11 F_(A11, IP3_11_8) -#define GPSR1_10 F_(A10, IP3_7_4) -#define GPSR1_9 F_(A9, IP3_3_0) -#define GPSR1_8 F_(A8, IP2_31_28) -#define GPSR1_7 F_(A7, IP2_27_24) -#define GPSR1_6 F_(A6, IP2_23_20) -#define GPSR1_5 F_(A5, IP2_19_16) -#define GPSR1_4 F_(A4, IP2_15_12) -#define GPSR1_3 F_(A3, IP2_11_8) -#define GPSR1_2 F_(A2, IP2_7_4) -#define GPSR1_1 F_(A1, IP2_3_0) -#define GPSR1_0 F_(A0, IP1_31_28) - -/* GPSR2 */ -#define GPSR2_14 F_(AVB_AVTP_CAPTURE_A, IP0_23_20) -#define GPSR2_13 F_(AVB_AVTP_MATCH_A, IP0_19_16) -#define GPSR2_12 F_(AVB_LINK, IP0_15_12) -#define GPSR2_11 F_(AVB_PHY_INT, IP0_11_8) -#define GPSR2_10 F_(AVB_MAGIC, IP0_7_4) -#define GPSR2_9 F_(AVB_MDC, IP0_3_0) -#define GPSR2_8 F_(PWM2_A, IP1_27_24) -#define GPSR2_7 F_(PWM1_A, IP1_23_20) -#define GPSR2_6 F_(PWM0, IP1_19_16) -#define GPSR2_5 F_(IRQ5, IP1_15_12) -#define GPSR2_4 F_(IRQ4, IP1_11_8) -#define GPSR2_3 F_(IRQ3, IP1_7_4) -#define GPSR2_2 F_(IRQ2, IP1_3_0) -#define GPSR2_1 F_(IRQ1, IP0_31_28) -#define GPSR2_0 F_(IRQ0, IP0_27_24) - -/* GPSR3 */ -#define GPSR3_15 F_(SD1_WP, IP10_23_20) -#define GPSR3_14 F_(SD1_CD, IP10_19_16) -#define GPSR3_13 F_(SD0_WP, IP10_15_12) -#define GPSR3_12 F_(SD0_CD, IP10_11_8) -#define GPSR3_11 F_(SD1_DAT3, IP8_31_28) -#define GPSR3_10 F_(SD1_DAT2, IP8_27_24) -#define GPSR3_9 F_(SD1_DAT1, IP8_23_20) -#define GPSR3_8 F_(SD1_DAT0, IP8_19_16) -#define GPSR3_7 F_(SD1_CMD, IP8_15_12) -#define GPSR3_6 F_(SD1_CLK, IP8_11_8) -#define GPSR3_5 F_(SD0_DAT3, IP8_7_4) -#define GPSR3_4 F_(SD0_DAT2, IP8_3_0) -#define GPSR3_3 F_(SD0_DAT1, IP7_31_28) -#define GPSR3_2 F_(SD0_DAT0, IP7_27_24) -#define GPSR3_1 F_(SD0_CMD, IP7_23_20) -#define GPSR3_0 F_(SD0_CLK, IP7_19_16) - -/* GPSR4 */ -#define GPSR4_17 FM(SD3_DS) -#define GPSR4_16 F_(SD3_DAT7, IP10_7_4) -#define GPSR4_15 F_(SD3_DAT6, IP10_3_0) -#define GPSR4_14 F_(SD3_DAT5, IP9_31_28) -#define GPSR4_13 F_(SD3_DAT4, IP9_27_24) -#define GPSR4_12 FM(SD3_DAT3) -#define GPSR4_11 FM(SD3_DAT2) -#define GPSR4_10 FM(SD3_DAT1) -#define GPSR4_9 FM(SD3_DAT0) -#define GPSR4_8 FM(SD3_CMD) -#define GPSR4_7 FM(SD3_CLK) -#define GPSR4_6 F_(SD2_DS, IP9_23_20) -#define GPSR4_5 F_(SD2_DAT3, IP9_19_16) -#define GPSR4_4 F_(SD2_DAT2, IP9_15_12) -#define GPSR4_3 F_(SD2_DAT1, IP9_11_8) -#define GPSR4_2 F_(SD2_DAT0, IP9_7_4) -#define GPSR4_1 FM(SD2_CMD) -#define GPSR4_0 F_(SD2_CLK, IP9_3_0) - -/* GPSR5 */ -#define GPSR5_25 F_(MLB_DAT, IP13_19_16) -#define GPSR5_24 F_(MLB_SIG, IP13_15_12) -#define GPSR5_23 F_(MLB_CLK, IP13_11_8) -#define GPSR5_22 FM(MSIOF0_RXD) -#define GPSR5_21 F_(MSIOF0_SS2, IP13_7_4) -#define GPSR5_20 FM(MSIOF0_TXD) -#define GPSR5_19 F_(MSIOF0_SS1, IP13_3_0) -#define GPSR5_18 F_(MSIOF0_SYNC, IP12_31_28) -#define GPSR5_17 FM(MSIOF0_SCK) -#define GPSR5_16 F_(HRTS0_N, IP12_27_24) -#define GPSR5_15 F_(HCTS0_N, IP12_23_20) -#define GPSR5_14 F_(HTX0, IP12_19_16) -#define GPSR5_13 F_(HRX0, IP12_15_12) -#define GPSR5_12 F_(HSCK0, IP12_11_8) -#define GPSR5_11 F_(RX2_A, IP12_7_4) -#define GPSR5_10 F_(TX2_A, IP12_3_0) -#define GPSR5_9 F_(SCK2, IP11_31_28) -#define GPSR5_8 F_(RTS1_N, IP11_27_24) -#define GPSR5_7 F_(CTS1_N, IP11_23_20) -#define GPSR5_6 F_(TX1_A, IP11_19_16) -#define GPSR5_5 F_(RX1_A, IP11_15_12) -#define GPSR5_4 F_(RTS0_N, IP11_11_8) -#define GPSR5_3 F_(CTS0_N, IP11_7_4) -#define GPSR5_2 F_(TX0, IP11_3_0) -#define GPSR5_1 F_(RX0, IP10_31_28) -#define GPSR5_0 F_(SCK0, IP10_27_24) - -/* GPSR6 */ -#define GPSR6_31 F_(USB31_OVC, IP17_7_4) -#define GPSR6_30 F_(USB31_PWEN, IP17_3_0) -#define GPSR6_29 F_(USB30_OVC, IP16_31_28) -#define GPSR6_28 F_(USB30_PWEN, IP16_27_24) -#define GPSR6_27 F_(USB1_OVC, IP16_23_20) -#define GPSR6_26 F_(USB1_PWEN, IP16_19_16) -#define GPSR6_25 F_(USB0_OVC, IP16_15_12) -#define GPSR6_24 F_(USB0_PWEN, IP16_11_8) -#define GPSR6_23 F_(AUDIO_CLKB_B, IP16_7_4) -#define GPSR6_22 F_(AUDIO_CLKA_A, IP16_3_0) -#define GPSR6_21 F_(SSI_SDATA9_A, IP15_31_28) -#define GPSR6_20 F_(SSI_SDATA8, IP15_27_24) -#define GPSR6_19 F_(SSI_SDATA7, IP15_23_20) -#define GPSR6_18 F_(SSI_WS78, IP15_19_16) -#define GPSR6_17 F_(SSI_SCK78, IP15_15_12) -#define GPSR6_16 F_(SSI_SDATA6, IP15_11_8) -#define GPSR6_15 F_(SSI_WS6, IP15_7_4) -#define GPSR6_14 F_(SSI_SCK6, IP15_3_0) -#define GPSR6_13 FM(SSI_SDATA5) -#define GPSR6_12 FM(SSI_WS5) -#define GPSR6_11 FM(SSI_SCK5) -#define GPSR6_10 F_(SSI_SDATA4, IP14_31_28) -#define GPSR6_9 F_(SSI_WS4, IP14_27_24) -#define GPSR6_8 F_(SSI_SCK4, IP14_23_20) -#define GPSR6_7 F_(SSI_SDATA3, IP14_19_16) -#define GPSR6_6 F_(SSI_WS349, IP14_15_12) -#define GPSR6_5 F_(SSI_SCK349, IP14_11_8) -#define GPSR6_4 F_(SSI_SDATA2_A, IP14_7_4) -#define GPSR6_3 F_(SSI_SDATA1_A, IP14_3_0) -#define GPSR6_2 F_(SSI_SDATA0, IP13_31_28) -#define GPSR6_1 F_(SSI_WS01239, IP13_27_24) -#define GPSR6_0 F_(SSI_SCK01239, IP13_23_20) - -/* GPSR7 */ -#define GPSR7_3 FM(GP7_03) -#define GPSR7_2 FM(GP7_02) -#define GPSR7_1 FM(AVS2) -#define GPSR7_0 FM(AVS1) - - -/* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ -#define IP0_3_0 FM(AVB_MDC) F_(0, 0) FM(MSIOF2_SS2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0_7_4 FM(AVB_MAGIC) F_(0, 0) FM(MSIOF2_SS1_C) FM(SCK4_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 IP0_11_8 FM(AVB_PHY_INT) F_(0, 0) FM(MSIOF2_SYNC_C) FM(RX4_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 IP0_15_12 FM(AVB_LINK) F_(0, 0) FM(MSIOF2_SCK_C) FM(TX4_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 IP0_19_16 FM(AVB_AVTP_MATCH_A) F_(0, 0) FM(MSIOF2_RXD_C) FM(CTS4_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0_23_20 FM(AVB_AVTP_CAPTURE_A) F_(0, 0) FM(MSIOF2_TXD_C) FM(RTS4_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0_27_24 FM(IRQ0) FM(QPOLB) F_(0, 0) FM(DU_CDE) FM(VI4_DATA0_B) FM(CAN0_TX_B) FM(CANFD0_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) -#define IP0_31_28 FM(IRQ1) FM(QPOLA) F_(0, 0) FM(DU_DISP) FM(VI4_DATA1_B) FM(CAN0_RX_B) FM(CANFD0_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) -#define IP1_3_0 FM(IRQ2) FM(QCPV_QDE) F_(0, 0) FM(DU_EXODDF_DU_ODDF_DISP_CDE) FM(VI4_DATA2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_7_4 FM(IRQ3) FM(QSTVB_QVE) FM(A25) FM(DU_DOTCLKOUT1) FM(VI4_DATA3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(PWM4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_11_8 FM(IRQ4) FM(QSTH_QHS) FM(A24) FM(DU_EXHSYNC_DU_HSYNC) FM(VI4_DATA4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(PWM5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_15_12 FM(IRQ5) FM(QSTB_QHE) FM(A23) FM(DU_EXVSYNC_DU_VSYNC) FM(VI4_DATA5_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_19_16 FM(PWM0) FM(AVB_AVTP_PPS)FM(A22) F_(0, 0) FM(VI4_DATA6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IECLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_23_20 FM(PWM1_A) F_(0, 0) FM(A21) FM(HRX3_D) FM(VI4_DATA7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IERX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_27_24 FM(PWM2_A) F_(0, 0) FM(A20) FM(HTX3_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(IETX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1_31_28 FM(A0) FM(LCDOUT16) FM(MSIOF3_SYNC_B) F_(0, 0) FM(VI4_DATA8) F_(0, 0) FM(DU_DB0) F_(0, 0) F_(0, 0) FM(PWM3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2_3_0 FM(A1) FM(LCDOUT17) FM(MSIOF3_TXD_B) F_(0, 0) FM(VI4_DATA9) F_(0, 0) FM(DU_DB1) F_(0, 0) F_(0, 0) FM(PWM4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2_7_4 FM(A2) FM(LCDOUT18) FM(MSIOF3_SCK_B) F_(0, 0) FM(VI4_DATA10) F_(0, 0) FM(DU_DB2) F_(0, 0) F_(0, 0) FM(PWM5_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2_11_8 FM(A3) FM(LCDOUT19) FM(MSIOF3_RXD_B) F_(0, 0) FM(VI4_DATA11) F_(0, 0) FM(DU_DB3) F_(0, 0) F_(0, 0) FM(PWM6_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) - -/* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ -#define IP2_15_12 FM(A4) FM(LCDOUT20) FM(MSIOF3_SS1_B) F_(0, 0) FM(VI4_DATA12) FM(VI5_DATA12) FM(DU_DB4) F_(0, 0) 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 IP2_19_16 FM(A5) FM(LCDOUT21) FM(MSIOF3_SS2_B) FM(SCK4_B) FM(VI4_DATA13) FM(VI5_DATA13) FM(DU_DB5) F_(0, 0) 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 IP2_23_20 FM(A6) FM(LCDOUT22) FM(MSIOF2_SS1_A) FM(RX4_B) FM(VI4_DATA14) FM(VI5_DATA14) FM(DU_DB6) F_(0, 0) 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 IP2_27_24 FM(A7) FM(LCDOUT23) FM(MSIOF2_SS2_A) FM(TX4_B) FM(VI4_DATA15) FM(VI5_DATA15) FM(DU_DB7) F_(0, 0) 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 IP2_31_28 FM(A8) FM(RX3_B) FM(MSIOF2_SYNC_A) FM(HRX4_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(SDA6_A) FM(AVB_AVTP_MATCH_B) FM(PWM1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3_3_0 FM(A9) F_(0, 0) FM(MSIOF2_SCK_A) FM(CTS4_N_B) F_(0, 0) FM(VI5_VSYNC_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) -#define IP3_7_4 FM(A10) F_(0, 0) FM(MSIOF2_RXD_A) FM(RTS4_N_B) F_(0, 0) FM(VI5_HSYNC_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) -#define IP3_11_8 FM(A11) FM(TX3_B) FM(MSIOF2_TXD_A) FM(HTX4_B) FM(HSCK4) FM(VI5_FIELD) F_(0, 0) FM(SCL6_A) FM(AVB_AVTP_CAPTURE_B) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3_15_12 FM(A12) FM(LCDOUT12) FM(MSIOF3_SCK_C) F_(0, 0) FM(HRX4_A) FM(VI5_DATA8) FM(DU_DG4) F_(0, 0) 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 IP3_19_16 FM(A13) FM(LCDOUT13) FM(MSIOF3_SYNC_C) F_(0, 0) FM(HTX4_A) FM(VI5_DATA9) FM(DU_DG5) F_(0, 0) 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 IP3_23_20 FM(A14) FM(LCDOUT14) FM(MSIOF3_RXD_C) F_(0, 0) FM(HCTS4_N) FM(VI5_DATA10) FM(DU_DG6) F_(0, 0) 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 IP3_27_24 FM(A15) FM(LCDOUT15) FM(MSIOF3_TXD_C) F_(0, 0) FM(HRTS4_N) FM(VI5_DATA11) FM(DU_DG7) F_(0, 0) 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 IP3_31_28 FM(A16) FM(LCDOUT8) F_(0, 0) F_(0, 0) FM(VI4_FIELD) F_(0, 0) FM(DU_DG0) F_(0, 0) 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 IP4_3_0 FM(A17) FM(LCDOUT9) F_(0, 0) F_(0, 0) FM(VI4_VSYNC_N) F_(0, 0) FM(DU_DG1) F_(0, 0) 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 IP4_7_4 FM(A18) FM(LCDOUT10) F_(0, 0) F_(0, 0) FM(VI4_HSYNC_N) F_(0, 0) FM(DU_DG2) F_(0, 0) 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 IP4_11_8 FM(A19) FM(LCDOUT11) F_(0, 0) F_(0, 0) FM(VI4_CLKENB) F_(0, 0) FM(DU_DG3) F_(0, 0) 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 IP4_15_12 FM(CS0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(VI5_CLKENB) F_(0, 0) F_(0, 0) 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 IP4_19_16 FM(CS1_N_A26) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(VI5_CLK) F_(0, 0) FM(EX_WAIT0_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) -#define IP4_23_20 FM(BS_N) FM(QSTVA_QVS) FM(MSIOF3_SCK_D) FM(SCK3) FM(HSCK3) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN1_TX) FM(CANFD1_TX) FM(IETX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP4_27_24 FM(RD_N) F_(0, 0) FM(MSIOF3_SYNC_D) FM(RX3_A) FM(HRX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_TX_A) FM(CANFD0_TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP4_31_28 FM(RD_WR_N) F_(0, 0) FM(MSIOF3_RXD_D) FM(TX3_A) FM(HTX3_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(CAN0_RX_A) FM(CANFD0_RX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP5_3_0 FM(WE0_N) F_(0, 0) FM(MSIOF3_TXD_D) FM(CTS3_N) FM(HCTS3_N) F_(0, 0) F_(0, 0) FM(SCL6_B) FM(CAN_CLK) F_(0, 0) FM(IECLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP5_7_4 FM(WE1_N) F_(0, 0) FM(MSIOF3_SS1_D) FM(RTS3_N) FM(HRTS3_N) F_(0, 0) F_(0, 0) FM(SDA6_B) FM(CAN1_RX) FM(CANFD1_RX) FM(IERX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP5_11_8 FM(EX_WAIT0_A) FM(QCLK) F_(0, 0) F_(0, 0) FM(VI4_CLK) F_(0, 0) FM(DU_DOTCLKOUT0) F_(0, 0) 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 IP5_15_12 FM(D0) FM(MSIOF2_SS1_B)FM(MSIOF3_SCK_A) F_(0, 0) FM(VI4_DATA16) FM(VI5_DATA0) F_(0, 0) F_(0, 0) 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 IP5_19_16 FM(D1) FM(MSIOF2_SS2_B)FM(MSIOF3_SYNC_A) F_(0, 0) FM(VI4_DATA17) FM(VI5_DATA1) F_(0, 0) F_(0, 0) 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 IP5_23_20 FM(D2) F_(0, 0) FM(MSIOF3_RXD_A) F_(0, 0) FM(VI4_DATA18) FM(VI5_DATA2) F_(0, 0) F_(0, 0) 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 IP5_27_24 FM(D3) F_(0, 0) FM(MSIOF3_TXD_A) F_(0, 0) FM(VI4_DATA19) FM(VI5_DATA3) F_(0, 0) F_(0, 0) 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 IP5_31_28 FM(D4) FM(MSIOF2_SCK_B)F_(0, 0) F_(0, 0) FM(VI4_DATA20) FM(VI5_DATA4) F_(0, 0) F_(0, 0) 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 IP6_3_0 FM(D5) FM(MSIOF2_SYNC_B)F_(0, 0) F_(0, 0) FM(VI4_DATA21) FM(VI5_DATA5) F_(0, 0) F_(0, 0) 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 IP6_7_4 FM(D6) FM(MSIOF2_RXD_B)F_(0, 0) F_(0, 0) FM(VI4_DATA22) FM(VI5_DATA6) F_(0, 0) F_(0, 0) 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 IP6_11_8 FM(D7) FM(MSIOF2_TXD_B)F_(0, 0) F_(0, 0) FM(VI4_DATA23) FM(VI5_DATA7) F_(0, 0) F_(0, 0) 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 IP6_15_12 FM(D8) FM(LCDOUT0) FM(MSIOF2_SCK_D) FM(SCK4_C) FM(VI4_DATA0_A) F_(0, 0) FM(DU_DR0) F_(0, 0) 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 IP6_19_16 FM(D9) FM(LCDOUT1) FM(MSIOF2_SYNC_D) F_(0, 0) FM(VI4_DATA1_A) F_(0, 0) FM(DU_DR1) F_(0, 0) 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 IP6_23_20 FM(D10) FM(LCDOUT2) FM(MSIOF2_RXD_D) FM(HRX3_B) FM(VI4_DATA2_A) FM(CTS4_N_C) FM(DU_DR2) F_(0, 0) 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 IP6_27_24 FM(D11) FM(LCDOUT3) FM(MSIOF2_TXD_D) FM(HTX3_B) FM(VI4_DATA3_A) FM(RTS4_N_C) FM(DU_DR3) F_(0, 0) 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 IP6_31_28 FM(D12) FM(LCDOUT4) FM(MSIOF2_SS1_D) FM(RX4_C) FM(VI4_DATA4_A) F_(0, 0) FM(DU_DR4) F_(0, 0) 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 IP7_3_0 FM(D13) FM(LCDOUT5) FM(MSIOF2_SS2_D) FM(TX4_C) FM(VI4_DATA5_A) F_(0, 0) FM(DU_DR5) F_(0, 0) 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 IP7_7_4 FM(D14) FM(LCDOUT6) FM(MSIOF3_SS1_A) FM(HRX3_C) FM(VI4_DATA6_A) F_(0, 0) FM(DU_DR6) FM(SCL6_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP7_11_8 FM(D15) FM(LCDOUT7) FM(MSIOF3_SS2_A) FM(HTX3_C) FM(VI4_DATA7_A) F_(0, 0) FM(DU_DR7) FM(SDA6_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP7_15_12 FM(FSCLKST) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP7_19_16 FM(SD0_CLK) F_(0, 0) FM(MSIOF1_SCK_E) F_(0, 0) F_(0, 0) F_(0, 0) FM(STP_OPWM_0_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) - -/* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ -#define IP7_23_20 FM(SD0_CMD) F_(0, 0) FM(MSIOF1_SYNC_E) F_(0, 0) F_(0, 0) F_(0, 0) FM(STP_IVCXO27_0_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) -#define IP7_27_24 FM(SD0_DAT0) F_(0, 0) FM(MSIOF1_RXD_E) F_(0, 0) F_(0, 0) FM(TS_SCK0_B) FM(STP_ISCLK_0_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) -#define IP7_31_28 FM(SD0_DAT1) F_(0, 0) FM(MSIOF1_TXD_E) F_(0, 0) F_(0, 0) FM(TS_SPSYNC0_B)FM(STP_ISSYNC_0_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) -#define IP8_3_0 FM(SD0_DAT2) F_(0, 0) FM(MSIOF1_SS1_E) F_(0, 0) F_(0, 0) FM(TS_SDAT0_B) FM(STP_ISD_0_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) -#define IP8_7_4 FM(SD0_DAT3) F_(0, 0) FM(MSIOF1_SS2_E) F_(0, 0) F_(0, 0) FM(TS_SDEN0_B) FM(STP_ISEN_0_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) -#define IP8_11_8 FM(SD1_CLK) F_(0, 0) FM(MSIOF1_SCK_G) F_(0, 0) F_(0, 0) FM(SIM0_CLK_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) -#define IP8_15_12 FM(SD1_CMD) F_(0, 0) FM(MSIOF1_SYNC_G) F_(0, 0) F_(0, 0) FM(SIM0_D_A) FM(STP_IVCXO27_1_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) -#define IP8_19_16 FM(SD1_DAT0) FM(SD2_DAT4) FM(MSIOF1_RXD_G) F_(0, 0) F_(0, 0) FM(TS_SCK1_B) FM(STP_ISCLK_1_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) -#define IP8_23_20 FM(SD1_DAT1) FM(SD2_DAT5) FM(MSIOF1_TXD_G) F_(0, 0) F_(0, 0) FM(TS_SPSYNC1_B)FM(STP_ISSYNC_1_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) -#define IP8_27_24 FM(SD1_DAT2) FM(SD2_DAT6) FM(MSIOF1_SS1_G) F_(0, 0) F_(0, 0) FM(TS_SDAT1_B) FM(STP_ISD_1_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) -#define IP8_31_28 FM(SD1_DAT3) FM(SD2_DAT7) FM(MSIOF1_SS2_G) F_(0, 0) F_(0, 0) FM(TS_SDEN1_B) FM(STP_ISEN_1_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) -#define IP9_3_0 FM(SD2_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 IP9_7_4 FM(SD2_DAT0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP9_11_8 FM(SD2_DAT1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP9_15_12 FM(SD2_DAT2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP9_19_16 FM(SD2_DAT3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP9_23_20 FM(SD2_DS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(SATA_DEVSLP_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP9_27_24 FM(SD3_DAT4) FM(SD2_CD_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 IP9_31_28 FM(SD3_DAT5) FM(SD2_WP_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 IP10_3_0 FM(SD3_DAT6) FM(SD3_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) -#define IP10_7_4 FM(SD3_DAT7) FM(SD3_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) -#define IP10_11_8 FM(SD0_CD) F_(0, 0) F_(0, 0) F_(0, 0) FM(SCL2_B) FM(SIM0_RST_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) -#define IP10_15_12 FM(SD0_WP) F_(0, 0) F_(0, 0) F_(0, 0) FM(SDA2_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) -#define IP10_19_16 FM(SD1_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(SIM0_CLK_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) -#define IP10_23_20 FM(SD1_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(SIM0_D_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) -#define IP10_27_24 FM(SCK0) FM(HSCK1_B) FM(MSIOF1_SS2_B) FM(AUDIO_CLKC_B) FM(SDA2_A) FM(SIM0_RST_B) FM(STP_OPWM_0_C) FM(RIF0_CLK_B) F_(0, 0) FM(ADICHS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP10_31_28 FM(RX0) FM(HRX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SCK0_C) FM(STP_ISCLK_0_C) FM(RIF0_D0_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) -#define IP11_3_0 FM(TX0) FM(HTX1_B) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SPSYNC0_C)FM(STP_ISSYNC_0_C) FM(RIF0_D1_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) -#define IP11_7_4 FM(CTS0_N) FM(HCTS1_N_B) FM(MSIOF1_SYNC_B) F_(0, 0) F_(0, 0) FM(TS_SPSYNC1_C)FM(STP_ISSYNC_1_C) FM(RIF1_SYNC_B) FM(AUDIO_CLKOUT_C) FM(ADICS_SAMP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_11_8 FM(RTS0_N) FM(HRTS1_N_B) FM(MSIOF1_SS1_B) FM(AUDIO_CLKA_B) FM(SCL2_A) F_(0, 0) FM(STP_IVCXO27_1_C) FM(RIF0_SYNC_B) F_(0, 0) FM(ADICHS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_15_12 FM(RX1_A) FM(HRX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDAT0_C) FM(STP_ISD_0_C) FM(RIF1_CLK_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_19_16 FM(TX1_A) FM(HTX1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(TS_SDEN0_C) FM(STP_ISEN_0_C) FM(RIF1_D0_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_23_20 FM(CTS1_N) FM(HCTS1_N_A) FM(MSIOF1_RXD_B) F_(0, 0) F_(0, 0) FM(TS_SDEN1_C) FM(STP_ISEN_1_C) FM(RIF1_D0_B) F_(0, 0) FM(ADIDATA) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_27_24 FM(RTS1_N) FM(HRTS1_N_A) FM(MSIOF1_TXD_B) F_(0, 0) F_(0, 0) FM(TS_SDAT1_C) FM(STP_ISD_1_C) FM(RIF1_D1_B) F_(0, 0) FM(ADICHS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP11_31_28 FM(SCK2) FM(SCIF_CLK_B) FM(MSIOF1_SCK_B) F_(0, 0) F_(0, 0) FM(TS_SCK1_C) FM(STP_ISCLK_1_C) FM(RIF1_CLK_B) F_(0, 0) FM(ADICLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_3_0 FM(TX2_A) F_(0, 0) F_(0, 0) FM(SD2_CD_B) FM(SCL1_A) F_(0, 0) FM(FMCLK_A) FM(RIF1_D1_C) F_(0, 0) FM(FSO_CFE_0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_7_4 FM(RX2_A) F_(0, 0) F_(0, 0) FM(SD2_WP_B) FM(SDA1_A) F_(0, 0) FM(FMIN_A) FM(RIF1_SYNC_C) F_(0, 0) FM(FSO_CFE_1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_11_8 FM(HSCK0) F_(0, 0) FM(MSIOF1_SCK_D) FM(AUDIO_CLKB_A) FM(SSI_SDATA1_B)FM(TS_SCK0_D) FM(STP_ISCLK_0_D) FM(RIF0_CLK_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_15_12 FM(HRX0) F_(0, 0) FM(MSIOF1_RXD_D) F_(0, 0) FM(SSI_SDATA2_B)FM(TS_SDEN0_D) FM(STP_ISEN_0_D) FM(RIF0_D0_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_19_16 FM(HTX0) F_(0, 0) FM(MSIOF1_TXD_D) F_(0, 0) FM(SSI_SDATA9_B)FM(TS_SDAT0_D) FM(STP_ISD_0_D) FM(RIF0_D1_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_23_20 FM(HCTS0_N) FM(RX2_B) FM(MSIOF1_SYNC_D) F_(0, 0) FM(SSI_SCK9_A) FM(TS_SPSYNC0_D)FM(STP_ISSYNC_0_D) FM(RIF0_SYNC_C) FM(AUDIO_CLKOUT1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP12_27_24 FM(HRTS0_N) FM(TX2_B) FM(MSIOF1_SS1_D) F_(0, 0) FM(SSI_WS9_A) F_(0, 0) FM(STP_IVCXO27_0_D) FM(BPFCLK_A) FM(AUDIO_CLKOUT2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) - -/* IPSRx */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ /* 8 */ /* 9 */ /* A */ /* B */ /* C - F */ -#define IP12_31_28 FM(MSIOF0_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(AUDIO_CLKOUT_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP13_3_0 FM(MSIOF0_SS1) FM(RX5) F_(0, 0) FM(AUDIO_CLKA_C) FM(SSI_SCK2_A) F_(0, 0) FM(STP_IVCXO27_0_C) F_(0, 0) FM(AUDIO_CLKOUT3_A) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP13_7_4 FM(MSIOF0_SS2) FM(TX5) FM(MSIOF1_SS2_D) FM(AUDIO_CLKC_A) FM(SSI_WS2_A) F_(0, 0) FM(STP_OPWM_0_D) F_(0, 0) FM(AUDIO_CLKOUT_D) F_(0, 0) FM(SPEEDIN_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP13_11_8 FM(MLB_CLK) F_(0, 0) FM(MSIOF1_SCK_F) F_(0, 0) FM(SCL1_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) -#define IP13_15_12 FM(MLB_SIG) FM(RX1_B) FM(MSIOF1_SYNC_F) F_(0, 0) FM(SDA1_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) -#define IP13_19_16 FM(MLB_DAT) FM(TX1_B) FM(MSIOF1_RXD_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP13_23_20 FM(SSI_SCK01239) F_(0, 0) FM(MSIOF1_TXD_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP13_27_24 FM(SSI_WS01239) F_(0, 0) FM(MSIOF1_SS1_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP13_31_28 FM(SSI_SDATA0) F_(0, 0) FM(MSIOF1_SS2_F) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP14_3_0 FM(SSI_SDATA1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP14_7_4 FM(SSI_SDATA2_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(SSI_SCK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP14_11_8 FM(SSI_SCK349) F_(0, 0) FM(MSIOF1_SS1_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(STP_OPWM_0_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) -#define IP14_15_12 FM(SSI_WS349) FM(HCTS2_N_A) FM(MSIOF1_SS2_A) F_(0, 0) F_(0, 0) F_(0, 0) FM(STP_IVCXO27_0_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) -#define IP14_19_16 FM(SSI_SDATA3) FM(HRTS2_N_A) FM(MSIOF1_TXD_A) F_(0, 0) F_(0, 0) FM(TS_SCK0_A) FM(STP_ISCLK_0_A) FM(RIF0_D1_A) FM(RIF2_D0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP14_23_20 FM(SSI_SCK4) FM(HRX2_A) FM(MSIOF1_SCK_A) F_(0, 0) F_(0, 0) FM(TS_SDAT0_A) FM(STP_ISD_0_A) FM(RIF0_CLK_A) FM(RIF2_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP14_27_24 FM(SSI_WS4) FM(HTX2_A) FM(MSIOF1_SYNC_A) F_(0, 0) F_(0, 0) FM(TS_SDEN0_A) FM(STP_ISEN_0_A) FM(RIF0_SYNC_A) FM(RIF2_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP14_31_28 FM(SSI_SDATA4) FM(HSCK2_A) FM(MSIOF1_RXD_A) F_(0, 0) F_(0, 0) FM(TS_SPSYNC0_A)FM(STP_ISSYNC_0_A) FM(RIF0_D0_A) FM(RIF2_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_3_0 FM(SSI_SCK6) FM(USB2_PWEN) F_(0, 0) FM(SIM0_RST_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP15_7_4 FM(SSI_WS6) FM(USB2_OVC) F_(0, 0) FM(SIM0_D_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP15_11_8 FM(SSI_SDATA6) F_(0, 0) F_(0, 0) FM(SIM0_CLK_D) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(SATA_DEVSLP_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_15_12 FM(SSI_SCK78) FM(HRX2_B) FM(MSIOF1_SCK_C) F_(0, 0) F_(0, 0) FM(TS_SCK1_A) FM(STP_ISCLK_1_A) FM(RIF1_CLK_A) FM(RIF3_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_19_16 FM(SSI_WS78) FM(HTX2_B) FM(MSIOF1_SYNC_C) F_(0, 0) F_(0, 0) FM(TS_SDAT1_A) FM(STP_ISD_1_A) FM(RIF1_SYNC_A) FM(RIF3_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_23_20 FM(SSI_SDATA7) FM(HCTS2_N_B) FM(MSIOF1_RXD_C) F_(0, 0) F_(0, 0) FM(TS_SDEN1_A) FM(STP_ISEN_1_A) FM(RIF1_D0_A) FM(RIF3_D0_A) F_(0, 0) FM(TCLK2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_27_24 FM(SSI_SDATA8) FM(HRTS2_N_B) FM(MSIOF1_TXD_C) F_(0, 0) F_(0, 0) FM(TS_SPSYNC1_A)FM(STP_ISSYNC_1_A) FM(RIF1_D1_A) FM(RIF3_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP15_31_28 FM(SSI_SDATA9_A) FM(HSCK2_B) FM(MSIOF1_SS1_C) FM(HSCK1_A) FM(SSI_WS1_B) FM(SCK1) FM(STP_IVCXO27_1_A) FM(SCK5) 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 IP16_3_0 FM(AUDIO_CLKA_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_7_4 FM(AUDIO_CLKB_B) FM(SCIF_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) FM(STP_IVCXO27_1_D) FM(REMOCON_A) F_(0, 0) F_(0, 0) FM(TCLK1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_11_8 FM(USB0_PWEN) F_(0, 0) F_(0, 0) FM(SIM0_RST_C) F_(0, 0) FM(TS_SCK1_D) FM(STP_ISCLK_1_D) FM(BPFCLK_B) FM(RIF3_CLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_15_12 FM(USB0_OVC) F_(0, 0) F_(0, 0) FM(SIM0_D_C) F_(0, 0) FM(TS_SDAT1_D) FM(STP_ISD_1_D) F_(0, 0) FM(RIF3_SYNC_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_19_16 FM(USB1_PWEN) F_(0, 0) F_(0, 0) FM(SIM0_CLK_C) FM(SSI_SCK1_A) FM(TS_SCK0_E) FM(STP_ISCLK_0_E) FM(FMCLK_B) FM(RIF2_CLK_B) F_(0, 0) FM(SPEEDIN_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_23_20 FM(USB1_OVC) F_(0, 0) FM(MSIOF1_SS2_C) F_(0, 0) FM(SSI_WS1_A) FM(TS_SDAT0_E) FM(STP_ISD_0_E) FM(FMIN_B) FM(RIF2_SYNC_B) F_(0, 0) FM(REMOCON_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_27_24 FM(USB30_PWEN) F_(0, 0) F_(0, 0) FM(AUDIO_CLKOUT_B) FM(SSI_SCK2_B) FM(TS_SDEN1_D) FM(STP_ISEN_1_D) FM(STP_OPWM_0_E)FM(RIF3_D0_B) F_(0, 0) FM(TCLK2_B) FM(TPU0TO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP16_31_28 FM(USB30_OVC) F_(0, 0) F_(0, 0) FM(AUDIO_CLKOUT1_B) FM(SSI_WS2_B) FM(TS_SPSYNC1_D)FM(STP_ISSYNC_1_D) FM(STP_IVCXO27_0_E)FM(RIF3_D1_B) F_(0, 0) FM(FSO_TOE_B) FM(TPU0TO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP17_3_0 FM(USB31_PWEN) F_(0, 0) F_(0, 0) FM(AUDIO_CLKOUT2_B) FM(SSI_SCK9_B) FM(TS_SDEN0_E) FM(STP_ISEN_0_E) F_(0, 0) FM(RIF2_D0_B) F_(0, 0) F_(0, 0) FM(TPU0TO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP17_7_4 FM(USB31_OVC) F_(0, 0) F_(0, 0) FM(AUDIO_CLKOUT3_B) FM(SSI_WS9_B) FM(TS_SPSYNC0_E)FM(STP_ISSYNC_0_E) F_(0, 0) FM(RIF2_D1_B) F_(0, 0) F_(0, 0) FM(TPU0TO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) - -#define PINMUX_GPSR \ -\ - GPSR6_31 \ - GPSR6_30 \ - GPSR6_29 \ - GPSR6_28 \ - GPSR1_27 GPSR6_27 \ - GPSR1_26 GPSR6_26 \ - GPSR1_25 GPSR5_25 GPSR6_25 \ - GPSR1_24 GPSR5_24 GPSR6_24 \ - GPSR1_23 GPSR5_23 GPSR6_23 \ - GPSR1_22 GPSR5_22 GPSR6_22 \ - GPSR1_21 GPSR5_21 GPSR6_21 \ - GPSR1_20 GPSR5_20 GPSR6_20 \ - GPSR1_19 GPSR5_19 GPSR6_19 \ - GPSR1_18 GPSR5_18 GPSR6_18 \ - GPSR1_17 GPSR4_17 GPSR5_17 GPSR6_17 \ - GPSR1_16 GPSR4_16 GPSR5_16 GPSR6_16 \ -GPSR0_15 GPSR1_15 GPSR3_15 GPSR4_15 GPSR5_15 GPSR6_15 \ -GPSR0_14 GPSR1_14 GPSR2_14 GPSR3_14 GPSR4_14 GPSR5_14 GPSR6_14 \ -GPSR0_13 GPSR1_13 GPSR2_13 GPSR3_13 GPSR4_13 GPSR5_13 GPSR6_13 \ -GPSR0_12 GPSR1_12 GPSR2_12 GPSR3_12 GPSR4_12 GPSR5_12 GPSR6_12 \ -GPSR0_11 GPSR1_11 GPSR2_11 GPSR3_11 GPSR4_11 GPSR5_11 GPSR6_11 \ -GPSR0_10 GPSR1_10 GPSR2_10 GPSR3_10 GPSR4_10 GPSR5_10 GPSR6_10 \ -GPSR0_9 GPSR1_9 GPSR2_9 GPSR3_9 GPSR4_9 GPSR5_9 GPSR6_9 \ -GPSR0_8 GPSR1_8 GPSR2_8 GPSR3_8 GPSR4_8 GPSR5_8 GPSR6_8 \ -GPSR0_7 GPSR1_7 GPSR2_7 GPSR3_7 GPSR4_7 GPSR5_7 GPSR6_7 \ -GPSR0_6 GPSR1_6 GPSR2_6 GPSR3_6 GPSR4_6 GPSR5_6 GPSR6_6 \ -GPSR0_5 GPSR1_5 GPSR2_5 GPSR3_5 GPSR4_5 GPSR5_5 GPSR6_5 \ -GPSR0_4 GPSR1_4 GPSR2_4 GPSR3_4 GPSR4_4 GPSR5_4 GPSR6_4 \ -GPSR0_3 GPSR1_3 GPSR2_3 GPSR3_3 GPSR4_3 GPSR5_3 GPSR6_3 GPSR7_3 \ -GPSR0_2 GPSR1_2 GPSR2_2 GPSR3_2 GPSR4_2 GPSR5_2 GPSR6_2 GPSR7_2 \ -GPSR0_1 GPSR1_1 GPSR2_1 GPSR3_1 GPSR4_1 GPSR5_1 GPSR6_1 GPSR7_1 \ -GPSR0_0 GPSR1_0 GPSR2_0 GPSR3_0 GPSR4_0 GPSR5_0 GPSR6_0 GPSR7_0 - -#define PINMUX_IPSR \ -\ -FM(IP0_3_0) IP0_3_0 FM(IP1_3_0) IP1_3_0 FM(IP2_3_0) IP2_3_0 FM(IP3_3_0) IP3_3_0 \ -FM(IP0_7_4) IP0_7_4 FM(IP1_7_4) IP1_7_4 FM(IP2_7_4) IP2_7_4 FM(IP3_7_4) IP3_7_4 \ -FM(IP0_11_8) IP0_11_8 FM(IP1_11_8) IP1_11_8 FM(IP2_11_8) IP2_11_8 FM(IP3_11_8) IP3_11_8 \ -FM(IP0_15_12) IP0_15_12 FM(IP1_15_12) IP1_15_12 FM(IP2_15_12) IP2_15_12 FM(IP3_15_12) IP3_15_12 \ -FM(IP0_19_16) IP0_19_16 FM(IP1_19_16) IP1_19_16 FM(IP2_19_16) IP2_19_16 FM(IP3_19_16) IP3_19_16 \ -FM(IP0_23_20) IP0_23_20 FM(IP1_23_20) IP1_23_20 FM(IP2_23_20) IP2_23_20 FM(IP3_23_20) IP3_23_20 \ -FM(IP0_27_24) IP0_27_24 FM(IP1_27_24) IP1_27_24 FM(IP2_27_24) IP2_27_24 FM(IP3_27_24) IP3_27_24 \ -FM(IP0_31_28) IP0_31_28 FM(IP1_31_28) IP1_31_28 FM(IP2_31_28) IP2_31_28 FM(IP3_31_28) IP3_31_28 \ -\ -FM(IP4_3_0) IP4_3_0 FM(IP5_3_0) IP5_3_0 FM(IP6_3_0) IP6_3_0 FM(IP7_3_0) IP7_3_0 \ -FM(IP4_7_4) IP4_7_4 FM(IP5_7_4) IP5_7_4 FM(IP6_7_4) IP6_7_4 FM(IP7_7_4) IP7_7_4 \ -FM(IP4_11_8) IP4_11_8 FM(IP5_11_8) IP5_11_8 FM(IP6_11_8) IP6_11_8 FM(IP7_11_8) IP7_11_8 \ -FM(IP4_15_12) IP4_15_12 FM(IP5_15_12) IP5_15_12 FM(IP6_15_12) IP6_15_12 FM(IP7_15_12) IP7_15_12 \ -FM(IP4_19_16) IP4_19_16 FM(IP5_19_16) IP5_19_16 FM(IP6_19_16) IP6_19_16 FM(IP7_19_16) IP7_19_16 \ -FM(IP4_23_20) IP4_23_20 FM(IP5_23_20) IP5_23_20 FM(IP6_23_20) IP6_23_20 FM(IP7_23_20) IP7_23_20 \ -FM(IP4_27_24) IP4_27_24 FM(IP5_27_24) IP5_27_24 FM(IP6_27_24) IP6_27_24 FM(IP7_27_24) IP7_27_24 \ -FM(IP4_31_28) IP4_31_28 FM(IP5_31_28) IP5_31_28 FM(IP6_31_28) IP6_31_28 FM(IP7_31_28) IP7_31_28 \ -\ -FM(IP8_3_0) IP8_3_0 FM(IP9_3_0) IP9_3_0 FM(IP10_3_0) IP10_3_0 FM(IP11_3_0) IP11_3_0 \ -FM(IP8_7_4) IP8_7_4 FM(IP9_7_4) IP9_7_4 FM(IP10_7_4) IP10_7_4 FM(IP11_7_4) IP11_7_4 \ -FM(IP8_11_8) IP8_11_8 FM(IP9_11_8) IP9_11_8 FM(IP10_11_8) IP10_11_8 FM(IP11_11_8) IP11_11_8 \ -FM(IP8_15_12) IP8_15_12 FM(IP9_15_12) IP9_15_12 FM(IP10_15_12) IP10_15_12 FM(IP11_15_12) IP11_15_12 \ -FM(IP8_19_16) IP8_19_16 FM(IP9_19_16) IP9_19_16 FM(IP10_19_16) IP10_19_16 FM(IP11_19_16) IP11_19_16 \ -FM(IP8_23_20) IP8_23_20 FM(IP9_23_20) IP9_23_20 FM(IP10_23_20) IP10_23_20 FM(IP11_23_20) IP11_23_20 \ -FM(IP8_27_24) IP8_27_24 FM(IP9_27_24) IP9_27_24 FM(IP10_27_24) IP10_27_24 FM(IP11_27_24) IP11_27_24 \ -FM(IP8_31_28) IP8_31_28 FM(IP9_31_28) IP9_31_28 FM(IP10_31_28) IP10_31_28 FM(IP11_31_28) IP11_31_28 \ -\ -FM(IP12_3_0) IP12_3_0 FM(IP13_3_0) IP13_3_0 FM(IP14_3_0) IP14_3_0 FM(IP15_3_0) IP15_3_0 \ -FM(IP12_7_4) IP12_7_4 FM(IP13_7_4) IP13_7_4 FM(IP14_7_4) IP14_7_4 FM(IP15_7_4) IP15_7_4 \ -FM(IP12_11_8) IP12_11_8 FM(IP13_11_8) IP13_11_8 FM(IP14_11_8) IP14_11_8 FM(IP15_11_8) IP15_11_8 \ -FM(IP12_15_12) IP12_15_12 FM(IP13_15_12) IP13_15_12 FM(IP14_15_12) IP14_15_12 FM(IP15_15_12) IP15_15_12 \ -FM(IP12_19_16) IP12_19_16 FM(IP13_19_16) IP13_19_16 FM(IP14_19_16) IP14_19_16 FM(IP15_19_16) IP15_19_16 \ -FM(IP12_23_20) IP12_23_20 FM(IP13_23_20) IP13_23_20 FM(IP14_23_20) IP14_23_20 FM(IP15_23_20) IP15_23_20 \ -FM(IP12_27_24) IP12_27_24 FM(IP13_27_24) IP13_27_24 FM(IP14_27_24) IP14_27_24 FM(IP15_27_24) IP15_27_24 \ -FM(IP12_31_28) IP12_31_28 FM(IP13_31_28) IP13_31_28 FM(IP14_31_28) IP14_31_28 FM(IP15_31_28) IP15_31_28 \ -\ -FM(IP16_3_0) IP16_3_0 FM(IP17_3_0) IP17_3_0 \ -FM(IP16_7_4) IP16_7_4 FM(IP17_7_4) IP17_7_4 \ -FM(IP16_11_8) IP16_11_8 \ -FM(IP16_15_12) IP16_15_12 \ -FM(IP16_19_16) IP16_19_16 \ -FM(IP16_23_20) IP16_23_20 \ -FM(IP16_27_24) IP16_27_24 \ -FM(IP16_31_28) IP16_31_28 - -/* MOD_SEL0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ -#define MOD_SEL0_30_29 FM(SEL_MSIOF3_0) FM(SEL_MSIOF3_1) FM(SEL_MSIOF3_2) FM(SEL_MSIOF3_3) -#define MOD_SEL0_28_27 FM(SEL_MSIOF2_0) FM(SEL_MSIOF2_1) FM(SEL_MSIOF2_2) FM(SEL_MSIOF2_3) -#define MOD_SEL0_26_25_24 FM(SEL_MSIOF1_0) FM(SEL_MSIOF1_1) FM(SEL_MSIOF1_2) FM(SEL_MSIOF1_3) FM(SEL_MSIOF1_4) FM(SEL_MSIOF1_5) FM(SEL_MSIOF1_6) F_(0, 0) -#define MOD_SEL0_23 FM(SEL_LBSC_0) FM(SEL_LBSC_1) -#define MOD_SEL0_22 FM(SEL_IEBUS_0) FM(SEL_IEBUS_1) -#define MOD_SEL0_21_20 FM(SEL_I2C6_0) FM(SEL_I2C6_1) FM(SEL_I2C6_2) F_(0, 0) -#define MOD_SEL0_19 FM(SEL_I2C2_0) FM(SEL_I2C2_1) -#define MOD_SEL0_18 FM(SEL_I2C1_0) FM(SEL_I2C1_1) -#define MOD_SEL0_17 FM(SEL_HSCIF4_0) FM(SEL_HSCIF4_1) -#define MOD_SEL0_16_15 FM(SEL_HSCIF3_0) FM(SEL_HSCIF3_1) FM(SEL_HSCIF3_2) FM(SEL_HSCIF3_3) -#define MOD_SEL0_14 FM(SEL_HSCIF2_0) FM(SEL_HSCIF2_1) -#define MOD_SEL0_13 FM(SEL_HSCIF1_0) FM(SEL_HSCIF1_1) -#define MOD_SEL0_12 FM(SEL_FSO_0) FM(SEL_FSO_1) -#define MOD_SEL0_11 FM(SEL_FM_0) FM(SEL_FM_1) -#define MOD_SEL0_10 FM(SEL_ETHERAVB_0) FM(SEL_ETHERAVB_1) -#define MOD_SEL0_9 FM(SEL_DRIF3_0) FM(SEL_DRIF3_1) -#define MOD_SEL0_8 FM(SEL_DRIF2_0) FM(SEL_DRIF2_1) -#define MOD_SEL0_7_6 FM(SEL_DRIF1_0) FM(SEL_DRIF1_1) FM(SEL_DRIF1_2) F_(0, 0) -#define MOD_SEL0_5_4 FM(SEL_DRIF0_0) FM(SEL_DRIF0_1) FM(SEL_DRIF0_2) F_(0, 0) -#define MOD_SEL0_3 FM(SEL_CANFD0_0) FM(SEL_CANFD0_1) -#define MOD_SEL0_2_1 FM(SEL_ADG_0) FM(SEL_ADG_1) FM(SEL_ADG_2) FM(SEL_ADG_3) - -/* MOD_SEL1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 7 */ -#define MOD_SEL1_31_30 FM(SEL_TSIF1_0) FM(SEL_TSIF1_1) FM(SEL_TSIF1_2) FM(SEL_TSIF1_3) -#define MOD_SEL1_29_28_27 FM(SEL_TSIF0_0) FM(SEL_TSIF0_1) FM(SEL_TSIF0_2) FM(SEL_TSIF0_3) FM(SEL_TSIF0_4) F_(0, 0) F_(0, 0) F_(0, 0) -#define MOD_SEL1_26 FM(SEL_TIMER_TMU_0) FM(SEL_TIMER_TMU_1) -#define MOD_SEL1_25_24 FM(SEL_SSP1_1_0) FM(SEL_SSP1_1_1) FM(SEL_SSP1_1_2) FM(SEL_SSP1_1_3) -#define MOD_SEL1_23_22_21 FM(SEL_SSP1_0_0) FM(SEL_SSP1_0_1) FM(SEL_SSP1_0_2) FM(SEL_SSP1_0_3) FM(SEL_SSP1_0_4) F_(0, 0) F_(0, 0) F_(0, 0) -#define MOD_SEL1_20 FM(SEL_SSI_0) FM(SEL_SSI_1) -#define MOD_SEL1_19 FM(SEL_SPEED_PULSE_0) FM(SEL_SPEED_PULSE_1) -#define MOD_SEL1_18_17 FM(SEL_SIMCARD_0) FM(SEL_SIMCARD_1) FM(SEL_SIMCARD_2) FM(SEL_SIMCARD_3) -#define MOD_SEL1_16 FM(SEL_SDHI2_0) FM(SEL_SDHI2_1) -#define MOD_SEL1_15_14 FM(SEL_SCIF4_0) FM(SEL_SCIF4_1) FM(SEL_SCIF4_2) F_(0, 0) -#define MOD_SEL1_13 FM(SEL_SCIF3_0) FM(SEL_SCIF3_1) -#define MOD_SEL1_12 FM(SEL_SCIF2_0) FM(SEL_SCIF2_1) -#define MOD_SEL1_11 FM(SEL_SCIF1_0) FM(SEL_SCIF1_1) -#define MOD_SEL1_10 FM(SEL_SATA_0) FM(SEL_SATA_1) -#define MOD_SEL1_9 FM(SEL_REMOCON_0) FM(SEL_REMOCON_1) -#define MOD_SEL1_6 FM(SEL_RCAN0_0) FM(SEL_RCAN0_1) -#define MOD_SEL1_5 FM(SEL_PWM6_0) FM(SEL_PWM6_1) -#define MOD_SEL1_4 FM(SEL_PWM5_0) FM(SEL_PWM5_1) -#define MOD_SEL1_3 FM(SEL_PWM4_0) FM(SEL_PWM4_1) -#define MOD_SEL1_2 FM(SEL_PWM3_0) FM(SEL_PWM3_1) -#define MOD_SEL1_1 FM(SEL_PWM2_0) FM(SEL_PWM2_1) -#define MOD_SEL1_0 FM(SEL_PWM1_0) FM(SEL_PWM1_1) - -/* MOD_SEL2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 */ -#define MOD_SEL2_31 FM(I2C_SEL_5_0) FM(I2C_SEL_5_1) -#define MOD_SEL2_30 FM(I2C_SEL_3_0) FM(I2C_SEL_3_1) -#define MOD_SEL2_29 FM(I2C_SEL_0_0) FM(I2C_SEL_0_1) -#define MOD_SEL2_0 FM(SEL_VIN4_0) FM(SEL_VIN4_1) - -#define PINMUX_MOD_SELS\ -\ - MOD_SEL1_31_30 MOD_SEL2_31 \ -MOD_SEL0_30_29 MOD_SEL2_30 \ - MOD_SEL1_29_28_27 MOD_SEL2_29 \ -MOD_SEL0_28_27 \ -\ -MOD_SEL0_26_25_24 MOD_SEL1_26 \ - MOD_SEL1_25_24 \ -\ -MOD_SEL0_23 MOD_SEL1_23_22_21 \ -MOD_SEL0_22 \ -MOD_SEL0_21_20 \ - MOD_SEL1_20 \ -MOD_SEL0_19 MOD_SEL1_19 \ -MOD_SEL0_18 MOD_SEL1_18_17 \ -MOD_SEL0_17 \ -MOD_SEL0_16_15 MOD_SEL1_16 \ - MOD_SEL1_15_14 \ -MOD_SEL0_14 \ -MOD_SEL0_13 MOD_SEL1_13 \ -MOD_SEL0_12 MOD_SEL1_12 \ -MOD_SEL0_11 MOD_SEL1_11 \ -MOD_SEL0_10 MOD_SEL1_10 \ -MOD_SEL0_9 MOD_SEL1_9 \ -MOD_SEL0_8 \ -MOD_SEL0_7_6 \ - MOD_SEL1_6 \ -MOD_SEL0_5_4 MOD_SEL1_5 \ - MOD_SEL1_4 \ -MOD_SEL0_3 MOD_SEL1_3 \ -MOD_SEL0_2_1 MOD_SEL1_2 \ - MOD_SEL1_1 \ - MOD_SEL1_0 MOD_SEL2_0 - -/* - * These pins are not able to be muxed but have other properties - * that can be set, such as drive-strength or pull-up/pull-down enable. - */ -#define PINMUX_STATIC \ - FM(QSPI0_SPCLK) FM(QSPI0_SSL) FM(QSPI0_MOSI_IO0) FM(QSPI0_MISO_IO1) \ - FM(QSPI0_IO2) FM(QSPI0_IO3) \ - FM(QSPI1_SPCLK) FM(QSPI1_SSL) FM(QSPI1_MOSI_IO0) FM(QSPI1_MISO_IO1) \ - FM(QSPI1_IO2) FM(QSPI1_IO3) \ - FM(RPC_INT) FM(RPC_WP) FM(RPC_RESET) \ - FM(AVB_TX_CTL) FM(AVB_TXC) FM(AVB_TD0) FM(AVB_TD1) FM(AVB_TD2) FM(AVB_TD3) \ - FM(AVB_RX_CTL) FM(AVB_RXC) FM(AVB_RD0) FM(AVB_RD1) FM(AVB_RD2) FM(AVB_RD3) \ - FM(AVB_TXCREFCLK) FM(AVB_MDIO) \ - FM(CLKOUT) FM(PRESETOUT) \ - FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) FM(DU_DOTCLKIN3) \ - FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR) - -#define PINMUX_PHYS \ - FM(SCL0) FM(SDA0) FM(SCL3) FM(SDA3) FM(SCL5) FM(SDA5) - -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_STATIC - PINMUX_PHYS - PINMUX_MARK_END, -#undef F_ -#undef FM -}; - -static const u16 pinmux_data[] = { - PINMUX_DATA_GP_ALL(), - - PINMUX_SINGLE(AVS1), - PINMUX_SINGLE(AVS2), - PINMUX_SINGLE(GP7_02), - PINMUX_SINGLE(GP7_03), - PINMUX_SINGLE(MSIOF0_RXD), - PINMUX_SINGLE(MSIOF0_SCK), - PINMUX_SINGLE(MSIOF0_TXD), - PINMUX_SINGLE(SD2_CMD), - PINMUX_SINGLE(SD3_CLK), - PINMUX_SINGLE(SD3_CMD), - PINMUX_SINGLE(SD3_DAT0), - PINMUX_SINGLE(SD3_DAT1), - PINMUX_SINGLE(SD3_DAT2), - PINMUX_SINGLE(SD3_DAT3), - PINMUX_SINGLE(SD3_DS), - PINMUX_SINGLE(SSI_SCK5), - PINMUX_SINGLE(SSI_SDATA5), - PINMUX_SINGLE(SSI_WS5), - - /* IPSR0 */ - PINMUX_IPSR_GPSR(IP0_3_0, AVB_MDC), - PINMUX_IPSR_MSEL(IP0_3_0, MSIOF2_SS2_C, SEL_MSIOF2_2), - - PINMUX_IPSR_GPSR(IP0_7_4, AVB_MAGIC), - PINMUX_IPSR_MSEL(IP0_7_4, MSIOF2_SS1_C, SEL_MSIOF2_2), - PINMUX_IPSR_MSEL(IP0_7_4, SCK4_A, SEL_SCIF4_0), - - PINMUX_IPSR_GPSR(IP0_11_8, AVB_PHY_INT), - PINMUX_IPSR_MSEL(IP0_11_8, MSIOF2_SYNC_C, SEL_MSIOF2_2), - PINMUX_IPSR_MSEL(IP0_11_8, RX4_A, SEL_SCIF4_0), - - PINMUX_IPSR_GPSR(IP0_15_12, AVB_LINK), - PINMUX_IPSR_MSEL(IP0_15_12, MSIOF2_SCK_C, SEL_MSIOF2_2), - PINMUX_IPSR_MSEL(IP0_15_12, TX4_A, SEL_SCIF4_0), - - PINMUX_IPSR_PHYS_MSEL(IP0_19_16, AVB_AVTP_MATCH_A, I2C_SEL_5_0, SEL_ETHERAVB_0), - PINMUX_IPSR_PHYS_MSEL(IP0_19_16, MSIOF2_RXD_C, I2C_SEL_5_0, SEL_MSIOF2_2), - PINMUX_IPSR_PHYS_MSEL(IP0_19_16, CTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0), - PINMUX_IPSR_PHYS(IP0_19_16, SCL5, I2C_SEL_5_1), - - PINMUX_IPSR_PHYS_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, I2C_SEL_5_0, SEL_ETHERAVB_0), - PINMUX_IPSR_PHYS_MSEL(IP0_23_20, MSIOF2_TXD_C, I2C_SEL_5_0, SEL_MSIOF2_2), - PINMUX_IPSR_PHYS_MSEL(IP0_23_20, RTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0), - PINMUX_IPSR_PHYS(IP0_23_20, SDA5, I2C_SEL_5_1), - - PINMUX_IPSR_GPSR(IP0_27_24, IRQ0), - PINMUX_IPSR_GPSR(IP0_27_24, QPOLB), - PINMUX_IPSR_GPSR(IP0_27_24, DU_CDE), - PINMUX_IPSR_MSEL(IP0_27_24, VI4_DATA0_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP0_27_24, CAN0_TX_B, SEL_RCAN0_1), - PINMUX_IPSR_MSEL(IP0_27_24, CANFD0_TX_B, SEL_CANFD0_1), - - PINMUX_IPSR_GPSR(IP0_31_28, IRQ1), - PINMUX_IPSR_GPSR(IP0_31_28, QPOLA), - PINMUX_IPSR_GPSR(IP0_31_28, DU_DISP), - PINMUX_IPSR_MSEL(IP0_31_28, VI4_DATA1_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP0_31_28, CAN0_RX_B, SEL_RCAN0_1), - PINMUX_IPSR_MSEL(IP0_31_28, CANFD0_RX_B, SEL_CANFD0_1), - - /* IPSR1 */ - PINMUX_IPSR_GPSR(IP1_3_0, IRQ2), - PINMUX_IPSR_GPSR(IP1_3_0, QCPV_QDE), - PINMUX_IPSR_GPSR(IP1_3_0, DU_EXODDF_DU_ODDF_DISP_CDE), - PINMUX_IPSR_MSEL(IP1_3_0, VI4_DATA2_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP1_3_0, PWM3_B, SEL_PWM3_1), - - PINMUX_IPSR_GPSR(IP1_7_4, IRQ3), - PINMUX_IPSR_GPSR(IP1_7_4, QSTVB_QVE), - PINMUX_IPSR_GPSR(IP1_7_4, A25), - PINMUX_IPSR_GPSR(IP1_7_4, DU_DOTCLKOUT1), - PINMUX_IPSR_MSEL(IP1_7_4, VI4_DATA3_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP1_7_4, PWM4_B, SEL_PWM4_1), - - PINMUX_IPSR_GPSR(IP1_11_8, IRQ4), - PINMUX_IPSR_GPSR(IP1_11_8, QSTH_QHS), - PINMUX_IPSR_GPSR(IP1_11_8, A24), - PINMUX_IPSR_GPSR(IP1_11_8, DU_EXHSYNC_DU_HSYNC), - PINMUX_IPSR_MSEL(IP1_11_8, VI4_DATA4_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP1_11_8, PWM5_B, SEL_PWM5_1), - - PINMUX_IPSR_GPSR(IP1_15_12, IRQ5), - PINMUX_IPSR_GPSR(IP1_15_12, QSTB_QHE), - PINMUX_IPSR_GPSR(IP1_15_12, A23), - PINMUX_IPSR_GPSR(IP1_15_12, DU_EXVSYNC_DU_VSYNC), - PINMUX_IPSR_MSEL(IP1_15_12, VI4_DATA5_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP1_15_12, PWM6_B, SEL_PWM6_1), - - PINMUX_IPSR_GPSR(IP1_19_16, PWM0), - PINMUX_IPSR_GPSR(IP1_19_16, AVB_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1_19_16, A22), - PINMUX_IPSR_MSEL(IP1_19_16, VI4_DATA6_B, SEL_VIN4_1), - PINMUX_IPSR_MSEL(IP1_19_16, IECLK_B, SEL_IEBUS_1), - - PINMUX_IPSR_PHYS_MSEL(IP1_23_20, PWM1_A, I2C_SEL_3_0, SEL_PWM1_0), - PINMUX_IPSR_MSEL(IP1_23_20, A21, I2C_SEL_3_0), - PINMUX_IPSR_PHYS_MSEL(IP1_23_20, HRX3_D, I2C_SEL_3_0, SEL_HSCIF3_3), - PINMUX_IPSR_PHYS_MSEL(IP1_23_20, VI4_DATA7_B, I2C_SEL_3_0, SEL_VIN4_1), - PINMUX_IPSR_PHYS_MSEL(IP1_23_20, IERX_B, I2C_SEL_3_0, SEL_IEBUS_1), - PINMUX_IPSR_PHYS(IP1_23_20, SCL3, I2C_SEL_3_1), - - PINMUX_IPSR_PHYS_MSEL(IP1_27_24, PWM2_A, I2C_SEL_3_0, SEL_PWM2_0), - PINMUX_IPSR_MSEL(IP1_27_24, A20, I2C_SEL_3_0), - PINMUX_IPSR_PHYS_MSEL(IP1_27_24, HTX3_D, I2C_SEL_3_0, SEL_HSCIF3_3), - PINMUX_IPSR_PHYS_MSEL(IP1_27_24, IETX_B, I2C_SEL_3_0, SEL_IEBUS_1), - PINMUX_IPSR_PHYS(IP1_27_24, SDA3, I2C_SEL_3_1), - - PINMUX_IPSR_GPSR(IP1_31_28, A0), - PINMUX_IPSR_GPSR(IP1_31_28, LCDOUT16), - PINMUX_IPSR_MSEL(IP1_31_28, MSIOF3_SYNC_B, SEL_MSIOF3_1), - PINMUX_IPSR_GPSR(IP1_31_28, VI4_DATA8), - PINMUX_IPSR_GPSR(IP1_31_28, DU_DB0), - PINMUX_IPSR_MSEL(IP1_31_28, PWM3_A, SEL_PWM3_0), - - /* IPSR2 */ - PINMUX_IPSR_GPSR(IP2_3_0, A1), - PINMUX_IPSR_GPSR(IP2_3_0, LCDOUT17), - PINMUX_IPSR_MSEL(IP2_3_0, MSIOF3_TXD_B, SEL_MSIOF3_1), - PINMUX_IPSR_GPSR(IP2_3_0, VI4_DATA9), - PINMUX_IPSR_GPSR(IP2_3_0, DU_DB1), - PINMUX_IPSR_MSEL(IP2_3_0, PWM4_A, SEL_PWM4_0), - - PINMUX_IPSR_GPSR(IP2_7_4, A2), - PINMUX_IPSR_GPSR(IP2_7_4, LCDOUT18), - PINMUX_IPSR_MSEL(IP2_7_4, MSIOF3_SCK_B, SEL_MSIOF3_1), - PINMUX_IPSR_GPSR(IP2_7_4, VI4_DATA10), - PINMUX_IPSR_GPSR(IP2_7_4, DU_DB2), - PINMUX_IPSR_MSEL(IP2_7_4, PWM5_A, SEL_PWM5_0), - - PINMUX_IPSR_GPSR(IP2_11_8, A3), - PINMUX_IPSR_GPSR(IP2_11_8, LCDOUT19), - PINMUX_IPSR_MSEL(IP2_11_8, MSIOF3_RXD_B, SEL_MSIOF3_1), - PINMUX_IPSR_GPSR(IP2_11_8, VI4_DATA11), - PINMUX_IPSR_GPSR(IP2_11_8, DU_DB3), - PINMUX_IPSR_MSEL(IP2_11_8, PWM6_A, SEL_PWM6_0), - - PINMUX_IPSR_GPSR(IP2_15_12, A4), - PINMUX_IPSR_GPSR(IP2_15_12, LCDOUT20), - PINMUX_IPSR_MSEL(IP2_15_12, MSIOF3_SS1_B, SEL_MSIOF3_1), - PINMUX_IPSR_GPSR(IP2_15_12, VI4_DATA12), - PINMUX_IPSR_GPSR(IP2_15_12, VI5_DATA12), - PINMUX_IPSR_GPSR(IP2_15_12, DU_DB4), - - PINMUX_IPSR_GPSR(IP2_19_16, A5), - PINMUX_IPSR_GPSR(IP2_19_16, LCDOUT21), - PINMUX_IPSR_MSEL(IP2_19_16, MSIOF3_SS2_B, SEL_MSIOF3_1), - PINMUX_IPSR_MSEL(IP2_19_16, SCK4_B, SEL_SCIF4_1), - PINMUX_IPSR_GPSR(IP2_19_16, VI4_DATA13), - PINMUX_IPSR_GPSR(IP2_19_16, VI5_DATA13), - PINMUX_IPSR_GPSR(IP2_19_16, DU_DB5), - - PINMUX_IPSR_GPSR(IP2_23_20, A6), - PINMUX_IPSR_GPSR(IP2_23_20, LCDOUT22), - PINMUX_IPSR_MSEL(IP2_23_20, MSIOF2_SS1_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP2_23_20, RX4_B, SEL_SCIF4_1), - PINMUX_IPSR_GPSR(IP2_23_20, VI4_DATA14), - PINMUX_IPSR_GPSR(IP2_23_20, VI5_DATA14), - PINMUX_IPSR_GPSR(IP2_23_20, DU_DB6), - - PINMUX_IPSR_GPSR(IP2_27_24, A7), - PINMUX_IPSR_GPSR(IP2_27_24, LCDOUT23), - PINMUX_IPSR_MSEL(IP2_27_24, MSIOF2_SS2_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP2_27_24, TX4_B, SEL_SCIF4_1), - PINMUX_IPSR_GPSR(IP2_27_24, VI4_DATA15), - PINMUX_IPSR_GPSR(IP2_27_24, VI5_DATA15), - PINMUX_IPSR_GPSR(IP2_27_24, DU_DB7), - - PINMUX_IPSR_GPSR(IP2_31_28, A8), - PINMUX_IPSR_MSEL(IP2_31_28, RX3_B, SEL_SCIF3_1), - PINMUX_IPSR_MSEL(IP2_31_28, MSIOF2_SYNC_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP2_31_28, HRX4_B, SEL_HSCIF4_1), - PINMUX_IPSR_MSEL(IP2_31_28, SDA6_A, SEL_I2C6_0), - PINMUX_IPSR_MSEL(IP2_31_28, AVB_AVTP_MATCH_B, SEL_ETHERAVB_1), - PINMUX_IPSR_MSEL(IP2_31_28, PWM1_B, SEL_PWM1_1), - - /* IPSR3 */ - PINMUX_IPSR_GPSR(IP3_3_0, A9), - PINMUX_IPSR_MSEL(IP3_3_0, MSIOF2_SCK_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP3_3_0, CTS4_N_B, SEL_SCIF4_1), - PINMUX_IPSR_GPSR(IP3_3_0, VI5_VSYNC_N), - - PINMUX_IPSR_GPSR(IP3_7_4, A10), - PINMUX_IPSR_MSEL(IP3_7_4, MSIOF2_RXD_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP3_7_4, RTS4_N_B, SEL_SCIF4_1), - PINMUX_IPSR_GPSR(IP3_7_4, VI5_HSYNC_N), - - PINMUX_IPSR_GPSR(IP3_11_8, A11), - PINMUX_IPSR_MSEL(IP3_11_8, TX3_B, SEL_SCIF3_1), - PINMUX_IPSR_MSEL(IP3_11_8, MSIOF2_TXD_A, SEL_MSIOF2_0), - PINMUX_IPSR_MSEL(IP3_11_8, HTX4_B, SEL_HSCIF4_1), - PINMUX_IPSR_GPSR(IP3_11_8, HSCK4), - PINMUX_IPSR_GPSR(IP3_11_8, VI5_FIELD), - PINMUX_IPSR_MSEL(IP3_11_8, SCL6_A, SEL_I2C6_0), - PINMUX_IPSR_MSEL(IP3_11_8, AVB_AVTP_CAPTURE_B, SEL_ETHERAVB_1), - PINMUX_IPSR_MSEL(IP3_11_8, PWM2_B, SEL_PWM2_1), - - PINMUX_IPSR_GPSR(IP3_15_12, A12), - PINMUX_IPSR_GPSR(IP3_15_12, LCDOUT12), - PINMUX_IPSR_MSEL(IP3_15_12, MSIOF3_SCK_C, SEL_MSIOF3_2), - PINMUX_IPSR_MSEL(IP3_15_12, HRX4_A, SEL_HSCIF4_0), - PINMUX_IPSR_GPSR(IP3_15_12, VI5_DATA8), - PINMUX_IPSR_GPSR(IP3_15_12, DU_DG4), - - PINMUX_IPSR_GPSR(IP3_19_16, A13), - PINMUX_IPSR_GPSR(IP3_19_16, LCDOUT13), - PINMUX_IPSR_MSEL(IP3_19_16, MSIOF3_SYNC_C, SEL_MSIOF3_2), - PINMUX_IPSR_MSEL(IP3_19_16, HTX4_A, SEL_HSCIF4_0), - PINMUX_IPSR_GPSR(IP3_19_16, VI5_DATA9), - PINMUX_IPSR_GPSR(IP3_19_16, DU_DG5), - - PINMUX_IPSR_GPSR(IP3_23_20, A14), - PINMUX_IPSR_GPSR(IP3_23_20, LCDOUT14), - PINMUX_IPSR_MSEL(IP3_23_20, MSIOF3_RXD_C, SEL_MSIOF3_2), - PINMUX_IPSR_GPSR(IP3_23_20, HCTS4_N), - PINMUX_IPSR_GPSR(IP3_23_20, VI5_DATA10), - PINMUX_IPSR_GPSR(IP3_23_20, DU_DG6), - - PINMUX_IPSR_GPSR(IP3_27_24, A15), - PINMUX_IPSR_GPSR(IP3_27_24, LCDOUT15), - PINMUX_IPSR_MSEL(IP3_27_24, MSIOF3_TXD_C, SEL_MSIOF3_2), - PINMUX_IPSR_GPSR(IP3_27_24, HRTS4_N), - PINMUX_IPSR_GPSR(IP3_27_24, VI5_DATA11), - PINMUX_IPSR_GPSR(IP3_27_24, DU_DG7), - - PINMUX_IPSR_GPSR(IP3_31_28, A16), - PINMUX_IPSR_GPSR(IP3_31_28, LCDOUT8), - PINMUX_IPSR_GPSR(IP3_31_28, VI4_FIELD), - PINMUX_IPSR_GPSR(IP3_31_28, DU_DG0), - - /* IPSR4 */ - PINMUX_IPSR_GPSR(IP4_3_0, A17), - PINMUX_IPSR_GPSR(IP4_3_0, LCDOUT9), - PINMUX_IPSR_GPSR(IP4_3_0, VI4_VSYNC_N), - PINMUX_IPSR_GPSR(IP4_3_0, DU_DG1), - - PINMUX_IPSR_GPSR(IP4_7_4, A18), - PINMUX_IPSR_GPSR(IP4_7_4, LCDOUT10), - PINMUX_IPSR_GPSR(IP4_7_4, VI4_HSYNC_N), - PINMUX_IPSR_GPSR(IP4_7_4, DU_DG2), - - PINMUX_IPSR_GPSR(IP4_11_8, A19), - PINMUX_IPSR_GPSR(IP4_11_8, LCDOUT11), - PINMUX_IPSR_GPSR(IP4_11_8, VI4_CLKENB), - PINMUX_IPSR_GPSR(IP4_11_8, DU_DG3), - - PINMUX_IPSR_GPSR(IP4_15_12, CS0_N), - PINMUX_IPSR_GPSR(IP4_15_12, VI5_CLKENB), - - PINMUX_IPSR_GPSR(IP4_19_16, CS1_N_A26), - PINMUX_IPSR_GPSR(IP4_19_16, VI5_CLK), - PINMUX_IPSR_MSEL(IP4_19_16, EX_WAIT0_B, SEL_LBSC_1), - - PINMUX_IPSR_GPSR(IP4_23_20, BS_N), - PINMUX_IPSR_GPSR(IP4_23_20, QSTVA_QVS), - PINMUX_IPSR_MSEL(IP4_23_20, MSIOF3_SCK_D, SEL_MSIOF3_3), - PINMUX_IPSR_GPSR(IP4_23_20, SCK3), - PINMUX_IPSR_GPSR(IP4_23_20, HSCK3), - PINMUX_IPSR_GPSR(IP4_23_20, CAN1_TX), - PINMUX_IPSR_GPSR(IP4_23_20, CANFD1_TX), - PINMUX_IPSR_MSEL(IP4_23_20, IETX_A, SEL_IEBUS_0), - - PINMUX_IPSR_GPSR(IP4_27_24, RD_N), - PINMUX_IPSR_MSEL(IP4_27_24, MSIOF3_SYNC_D, SEL_MSIOF3_3), - PINMUX_IPSR_MSEL(IP4_27_24, RX3_A, SEL_SCIF3_0), - PINMUX_IPSR_MSEL(IP4_27_24, HRX3_A, SEL_HSCIF3_0), - PINMUX_IPSR_MSEL(IP4_27_24, CAN0_TX_A, SEL_RCAN0_0), - PINMUX_IPSR_MSEL(IP4_27_24, CANFD0_TX_A, SEL_CANFD0_0), - - PINMUX_IPSR_GPSR(IP4_31_28, RD_WR_N), - PINMUX_IPSR_MSEL(IP4_31_28, MSIOF3_RXD_D, SEL_MSIOF3_3), - PINMUX_IPSR_MSEL(IP4_31_28, TX3_A, SEL_SCIF3_0), - PINMUX_IPSR_MSEL(IP4_31_28, HTX3_A, SEL_HSCIF3_0), - PINMUX_IPSR_MSEL(IP4_31_28, CAN0_RX_A, SEL_RCAN0_0), - PINMUX_IPSR_MSEL(IP4_31_28, CANFD0_RX_A, SEL_CANFD0_0), - - /* IPSR5 */ - PINMUX_IPSR_GPSR(IP5_3_0, WE0_N), - PINMUX_IPSR_MSEL(IP5_3_0, MSIOF3_TXD_D, SEL_MSIOF3_3), - PINMUX_IPSR_GPSR(IP5_3_0, CTS3_N), - PINMUX_IPSR_GPSR(IP5_3_0, HCTS3_N), - PINMUX_IPSR_MSEL(IP5_3_0, SCL6_B, SEL_I2C6_1), - PINMUX_IPSR_GPSR(IP5_3_0, CAN_CLK), - PINMUX_IPSR_MSEL(IP5_3_0, IECLK_A, SEL_IEBUS_0), - - PINMUX_IPSR_GPSR(IP5_7_4, WE1_N), - PINMUX_IPSR_MSEL(IP5_7_4, MSIOF3_SS1_D, SEL_MSIOF3_3), - PINMUX_IPSR_GPSR(IP5_7_4, RTS3_N), - PINMUX_IPSR_GPSR(IP5_7_4, HRTS3_N), - PINMUX_IPSR_MSEL(IP5_7_4, SDA6_B, SEL_I2C6_1), - PINMUX_IPSR_GPSR(IP5_7_4, CAN1_RX), - PINMUX_IPSR_GPSR(IP5_7_4, CANFD1_RX), - PINMUX_IPSR_MSEL(IP5_7_4, IERX_A, SEL_IEBUS_0), - - PINMUX_IPSR_MSEL(IP5_11_8, EX_WAIT0_A, SEL_LBSC_0), - PINMUX_IPSR_GPSR(IP5_11_8, QCLK), - PINMUX_IPSR_GPSR(IP5_11_8, VI4_CLK), - PINMUX_IPSR_GPSR(IP5_11_8, DU_DOTCLKOUT0), - - PINMUX_IPSR_GPSR(IP5_15_12, D0), - PINMUX_IPSR_MSEL(IP5_15_12, MSIOF2_SS1_B, SEL_MSIOF2_1), - PINMUX_IPSR_MSEL(IP5_15_12, MSIOF3_SCK_A, SEL_MSIOF3_0), - PINMUX_IPSR_GPSR(IP5_15_12, VI4_DATA16), - PINMUX_IPSR_GPSR(IP5_15_12, VI5_DATA0), - - PINMUX_IPSR_GPSR(IP5_19_16, D1), - PINMUX_IPSR_MSEL(IP5_19_16, MSIOF2_SS2_B, SEL_MSIOF2_1), - PINMUX_IPSR_MSEL(IP5_19_16, MSIOF3_SYNC_A, SEL_MSIOF3_0), - PINMUX_IPSR_GPSR(IP5_19_16, VI4_DATA17), - PINMUX_IPSR_GPSR(IP5_19_16, VI5_DATA1), - - PINMUX_IPSR_GPSR(IP5_23_20, D2), - PINMUX_IPSR_MSEL(IP5_23_20, MSIOF3_RXD_A, SEL_MSIOF3_0), - PINMUX_IPSR_GPSR(IP5_23_20, VI4_DATA18), - PINMUX_IPSR_GPSR(IP5_23_20, VI5_DATA2), - - PINMUX_IPSR_GPSR(IP5_27_24, D3), - PINMUX_IPSR_MSEL(IP5_27_24, MSIOF3_TXD_A, SEL_MSIOF3_0), - PINMUX_IPSR_GPSR(IP5_27_24, VI4_DATA19), - PINMUX_IPSR_GPSR(IP5_27_24, VI5_DATA3), - - PINMUX_IPSR_GPSR(IP5_31_28, D4), - PINMUX_IPSR_MSEL(IP5_31_28, MSIOF2_SCK_B, SEL_MSIOF2_1), - PINMUX_IPSR_GPSR(IP5_31_28, VI4_DATA20), - PINMUX_IPSR_GPSR(IP5_31_28, VI5_DATA4), - - /* IPSR6 */ - PINMUX_IPSR_GPSR(IP6_3_0, D5), - PINMUX_IPSR_MSEL(IP6_3_0, MSIOF2_SYNC_B, SEL_MSIOF2_1), - PINMUX_IPSR_GPSR(IP6_3_0, VI4_DATA21), - PINMUX_IPSR_GPSR(IP6_3_0, VI5_DATA5), - - PINMUX_IPSR_GPSR(IP6_7_4, D6), - PINMUX_IPSR_MSEL(IP6_7_4, MSIOF2_RXD_B, SEL_MSIOF2_1), - PINMUX_IPSR_GPSR(IP6_7_4, VI4_DATA22), - PINMUX_IPSR_GPSR(IP6_7_4, VI5_DATA6), - - PINMUX_IPSR_GPSR(IP6_11_8, D7), - PINMUX_IPSR_MSEL(IP6_11_8, MSIOF2_TXD_B, SEL_MSIOF2_1), - PINMUX_IPSR_GPSR(IP6_11_8, VI4_DATA23), - PINMUX_IPSR_GPSR(IP6_11_8, VI5_DATA7), - - PINMUX_IPSR_GPSR(IP6_15_12, D8), - PINMUX_IPSR_GPSR(IP6_15_12, LCDOUT0), - PINMUX_IPSR_MSEL(IP6_15_12, MSIOF2_SCK_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP6_15_12, SCK4_C, SEL_SCIF4_2), - PINMUX_IPSR_MSEL(IP6_15_12, VI4_DATA0_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP6_15_12, DU_DR0), - - PINMUX_IPSR_GPSR(IP6_19_16, D9), - PINMUX_IPSR_GPSR(IP6_19_16, LCDOUT1), - PINMUX_IPSR_MSEL(IP6_19_16, MSIOF2_SYNC_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP6_19_16, VI4_DATA1_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP6_19_16, DU_DR1), - - PINMUX_IPSR_GPSR(IP6_23_20, D10), - PINMUX_IPSR_GPSR(IP6_23_20, LCDOUT2), - PINMUX_IPSR_MSEL(IP6_23_20, MSIOF2_RXD_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP6_23_20, HRX3_B, SEL_HSCIF3_1), - PINMUX_IPSR_MSEL(IP6_23_20, VI4_DATA2_A, SEL_VIN4_0), - PINMUX_IPSR_MSEL(IP6_23_20, CTS4_N_C, SEL_SCIF4_2), - PINMUX_IPSR_GPSR(IP6_23_20, DU_DR2), - - PINMUX_IPSR_GPSR(IP6_27_24, D11), - PINMUX_IPSR_GPSR(IP6_27_24, LCDOUT3), - PINMUX_IPSR_MSEL(IP6_27_24, MSIOF2_TXD_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP6_27_24, HTX3_B, SEL_HSCIF3_1), - PINMUX_IPSR_MSEL(IP6_27_24, VI4_DATA3_A, SEL_VIN4_0), - PINMUX_IPSR_MSEL(IP6_27_24, RTS4_N_C, SEL_SCIF4_2), - PINMUX_IPSR_GPSR(IP6_27_24, DU_DR3), - - PINMUX_IPSR_GPSR(IP6_31_28, D12), - PINMUX_IPSR_GPSR(IP6_31_28, LCDOUT4), - PINMUX_IPSR_MSEL(IP6_31_28, MSIOF2_SS1_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP6_31_28, RX4_C, SEL_SCIF4_2), - PINMUX_IPSR_MSEL(IP6_31_28, VI4_DATA4_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP6_31_28, DU_DR4), - - /* IPSR7 */ - PINMUX_IPSR_GPSR(IP7_3_0, D13), - PINMUX_IPSR_GPSR(IP7_3_0, LCDOUT5), - PINMUX_IPSR_MSEL(IP7_3_0, MSIOF2_SS2_D, SEL_MSIOF2_3), - PINMUX_IPSR_MSEL(IP7_3_0, TX4_C, SEL_SCIF4_2), - PINMUX_IPSR_MSEL(IP7_3_0, VI4_DATA5_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP7_3_0, DU_DR5), - - PINMUX_IPSR_GPSR(IP7_7_4, D14), - PINMUX_IPSR_GPSR(IP7_7_4, LCDOUT6), - PINMUX_IPSR_MSEL(IP7_7_4, MSIOF3_SS1_A, SEL_MSIOF3_0), - PINMUX_IPSR_MSEL(IP7_7_4, HRX3_C, SEL_HSCIF3_2), - PINMUX_IPSR_MSEL(IP7_7_4, VI4_DATA6_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP7_7_4, DU_DR6), - PINMUX_IPSR_MSEL(IP7_7_4, SCL6_C, SEL_I2C6_2), - - PINMUX_IPSR_GPSR(IP7_11_8, D15), - PINMUX_IPSR_GPSR(IP7_11_8, LCDOUT7), - PINMUX_IPSR_MSEL(IP7_11_8, MSIOF3_SS2_A, SEL_MSIOF3_0), - PINMUX_IPSR_MSEL(IP7_11_8, HTX3_C, SEL_HSCIF3_2), - PINMUX_IPSR_MSEL(IP7_11_8, VI4_DATA7_A, SEL_VIN4_0), - PINMUX_IPSR_GPSR(IP7_11_8, DU_DR7), - PINMUX_IPSR_MSEL(IP7_11_8, SDA6_C, SEL_I2C6_2), - - PINMUX_IPSR_GPSR(IP7_15_12, FSCLKST), - - PINMUX_IPSR_GPSR(IP7_19_16, SD0_CLK), - PINMUX_IPSR_MSEL(IP7_19_16, MSIOF1_SCK_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP7_19_16, STP_OPWM_0_B, SEL_SSP1_0_1), - - PINMUX_IPSR_GPSR(IP7_23_20, SD0_CMD), - PINMUX_IPSR_MSEL(IP7_23_20, MSIOF1_SYNC_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP7_23_20, STP_IVCXO27_0_B, SEL_SSP1_0_1), - - PINMUX_IPSR_GPSR(IP7_27_24, SD0_DAT0), - PINMUX_IPSR_MSEL(IP7_27_24, MSIOF1_RXD_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP7_27_24, TS_SCK0_B, SEL_TSIF0_1), - PINMUX_IPSR_MSEL(IP7_27_24, STP_ISCLK_0_B, SEL_SSP1_0_1), - - PINMUX_IPSR_GPSR(IP7_31_28, SD0_DAT1), - PINMUX_IPSR_MSEL(IP7_31_28, MSIOF1_TXD_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP7_31_28, TS_SPSYNC0_B, SEL_TSIF0_1), - PINMUX_IPSR_MSEL(IP7_31_28, STP_ISSYNC_0_B, SEL_SSP1_0_1), - - /* IPSR8 */ - PINMUX_IPSR_GPSR(IP8_3_0, SD0_DAT2), - PINMUX_IPSR_MSEL(IP8_3_0, MSIOF1_SS1_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP8_3_0, TS_SDAT0_B, SEL_TSIF0_1), - PINMUX_IPSR_MSEL(IP8_3_0, STP_ISD_0_B, SEL_SSP1_0_1), - - PINMUX_IPSR_GPSR(IP8_7_4, SD0_DAT3), - PINMUX_IPSR_MSEL(IP8_7_4, MSIOF1_SS2_E, SEL_MSIOF1_4), - PINMUX_IPSR_MSEL(IP8_7_4, TS_SDEN0_B, SEL_TSIF0_1), - PINMUX_IPSR_MSEL(IP8_7_4, STP_ISEN_0_B, SEL_SSP1_0_1), - - PINMUX_IPSR_GPSR(IP8_11_8, SD1_CLK), - PINMUX_IPSR_MSEL(IP8_11_8, MSIOF1_SCK_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_11_8, SIM0_CLK_A, SEL_SIMCARD_0), - - PINMUX_IPSR_GPSR(IP8_15_12, SD1_CMD), - PINMUX_IPSR_MSEL(IP8_15_12, MSIOF1_SYNC_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_15_12, SIM0_D_A, SEL_SIMCARD_0), - PINMUX_IPSR_MSEL(IP8_15_12, STP_IVCXO27_1_B, SEL_SSP1_1_1), - - PINMUX_IPSR_GPSR(IP8_19_16, SD1_DAT0), - PINMUX_IPSR_GPSR(IP8_19_16, SD2_DAT4), - PINMUX_IPSR_MSEL(IP8_19_16, MSIOF1_RXD_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_19_16, TS_SCK1_B, SEL_TSIF1_1), - PINMUX_IPSR_MSEL(IP8_19_16, STP_ISCLK_1_B, SEL_SSP1_1_1), - - PINMUX_IPSR_GPSR(IP8_23_20, SD1_DAT1), - PINMUX_IPSR_GPSR(IP8_23_20, SD2_DAT5), - PINMUX_IPSR_MSEL(IP8_23_20, MSIOF1_TXD_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_23_20, TS_SPSYNC1_B, SEL_TSIF1_1), - PINMUX_IPSR_MSEL(IP8_23_20, STP_ISSYNC_1_B, SEL_SSP1_1_1), - - PINMUX_IPSR_GPSR(IP8_27_24, SD1_DAT2), - PINMUX_IPSR_GPSR(IP8_27_24, SD2_DAT6), - PINMUX_IPSR_MSEL(IP8_27_24, MSIOF1_SS1_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_27_24, TS_SDAT1_B, SEL_TSIF1_1), - PINMUX_IPSR_MSEL(IP8_27_24, STP_ISD_1_B, SEL_SSP1_1_1), - - PINMUX_IPSR_GPSR(IP8_31_28, SD1_DAT3), - PINMUX_IPSR_GPSR(IP8_31_28, SD2_DAT7), - PINMUX_IPSR_MSEL(IP8_31_28, MSIOF1_SS2_G, SEL_MSIOF1_6), - PINMUX_IPSR_MSEL(IP8_31_28, TS_SDEN1_B, SEL_TSIF1_1), - PINMUX_IPSR_MSEL(IP8_31_28, STP_ISEN_1_B, SEL_SSP1_1_1), - - /* IPSR9 */ - PINMUX_IPSR_GPSR(IP9_3_0, SD2_CLK), - - PINMUX_IPSR_GPSR(IP9_7_4, SD2_DAT0), - - PINMUX_IPSR_GPSR(IP9_11_8, SD2_DAT1), - - PINMUX_IPSR_GPSR(IP9_15_12, SD2_DAT2), - - PINMUX_IPSR_GPSR(IP9_19_16, SD2_DAT3), - - PINMUX_IPSR_GPSR(IP9_23_20, SD2_DS), - PINMUX_IPSR_MSEL(IP9_23_20, SATA_DEVSLP_B, SEL_SATA_1), - - PINMUX_IPSR_GPSR(IP9_27_24, SD3_DAT4), - PINMUX_IPSR_MSEL(IP9_27_24, SD2_CD_A, SEL_SDHI2_0), - - PINMUX_IPSR_GPSR(IP9_31_28, SD3_DAT5), - PINMUX_IPSR_MSEL(IP9_31_28, SD2_WP_A, SEL_SDHI2_0), - - /* IPSR10 */ - PINMUX_IPSR_GPSR(IP10_3_0, SD3_DAT6), - PINMUX_IPSR_GPSR(IP10_3_0, SD3_CD), - - PINMUX_IPSR_GPSR(IP10_7_4, SD3_DAT7), - PINMUX_IPSR_GPSR(IP10_7_4, SD3_WP), - - PINMUX_IPSR_GPSR(IP10_11_8, SD0_CD), - PINMUX_IPSR_MSEL(IP10_11_8, SCL2_B, SEL_I2C2_1), - PINMUX_IPSR_MSEL(IP10_11_8, SIM0_RST_A, SEL_SIMCARD_0), - - PINMUX_IPSR_GPSR(IP10_15_12, SD0_WP), - PINMUX_IPSR_MSEL(IP10_15_12, SDA2_B, SEL_I2C2_1), - - PINMUX_IPSR_MSEL(IP10_19_16, SD1_CD, I2C_SEL_0_0), - PINMUX_IPSR_PHYS_MSEL(IP10_19_16, SIM0_CLK_B, I2C_SEL_0_0, SEL_SIMCARD_1), - PINMUX_IPSR_PHYS(IP10_19_16, SCL0, I2C_SEL_0_1), - - PINMUX_IPSR_MSEL(IP10_23_20, SD1_WP, I2C_SEL_0_0), - PINMUX_IPSR_PHYS_MSEL(IP10_23_20, SIM0_D_B, I2C_SEL_0_0, SEL_SIMCARD_1), - PINMUX_IPSR_PHYS(IP10_23_20, SDA0, I2C_SEL_0_1), - - PINMUX_IPSR_GPSR(IP10_27_24, SCK0), - PINMUX_IPSR_MSEL(IP10_27_24, HSCK1_B, SEL_HSCIF1_1), - PINMUX_IPSR_MSEL(IP10_27_24, MSIOF1_SS2_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP10_27_24, AUDIO_CLKC_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP10_27_24, SDA2_A, SEL_I2C2_0), - PINMUX_IPSR_MSEL(IP10_27_24, SIM0_RST_B, SEL_SIMCARD_1), - PINMUX_IPSR_MSEL(IP10_27_24, STP_OPWM_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP10_27_24, RIF0_CLK_B, SEL_DRIF0_1), - PINMUX_IPSR_GPSR(IP10_27_24, ADICHS2), - - PINMUX_IPSR_GPSR(IP10_31_28, RX0), - PINMUX_IPSR_MSEL(IP10_31_28, HRX1_B, SEL_HSCIF1_1), - PINMUX_IPSR_MSEL(IP10_31_28, TS_SCK0_C, SEL_TSIF0_2), - PINMUX_IPSR_MSEL(IP10_31_28, STP_ISCLK_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP10_31_28, RIF0_D0_B, SEL_DRIF0_1), - - /* IPSR11 */ - PINMUX_IPSR_GPSR(IP11_3_0, TX0), - PINMUX_IPSR_MSEL(IP11_3_0, HTX1_B, SEL_HSCIF1_1), - PINMUX_IPSR_MSEL(IP11_3_0, TS_SPSYNC0_C, SEL_TSIF0_2), - PINMUX_IPSR_MSEL(IP11_3_0, STP_ISSYNC_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP11_3_0, RIF0_D1_B, SEL_DRIF0_1), - - PINMUX_IPSR_GPSR(IP11_7_4, CTS0_N), - PINMUX_IPSR_MSEL(IP11_7_4, HCTS1_N_B, SEL_HSCIF1_1), - PINMUX_IPSR_MSEL(IP11_7_4, MSIOF1_SYNC_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP11_7_4, TS_SPSYNC1_C, SEL_TSIF1_2), - PINMUX_IPSR_MSEL(IP11_7_4, STP_ISSYNC_1_C, SEL_SSP1_1_2), - PINMUX_IPSR_MSEL(IP11_7_4, RIF1_SYNC_B, SEL_DRIF1_1), - PINMUX_IPSR_MSEL(IP11_7_4, AUDIO_CLKOUT_C, SEL_ADG_2), - PINMUX_IPSR_GPSR(IP11_7_4, ADICS_SAMP), - - PINMUX_IPSR_GPSR(IP11_11_8, RTS0_N), - PINMUX_IPSR_MSEL(IP11_11_8, HRTS1_N_B, SEL_HSCIF1_1), - PINMUX_IPSR_MSEL(IP11_11_8, MSIOF1_SS1_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP11_11_8, AUDIO_CLKA_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP11_11_8, SCL2_A, SEL_I2C2_0), - PINMUX_IPSR_MSEL(IP11_11_8, STP_IVCXO27_1_C, SEL_SSP1_1_2), - PINMUX_IPSR_MSEL(IP11_11_8, RIF0_SYNC_B, SEL_DRIF0_1), - PINMUX_IPSR_GPSR(IP11_11_8, ADICHS1), - - PINMUX_IPSR_MSEL(IP11_15_12, RX1_A, SEL_SCIF1_0), - PINMUX_IPSR_MSEL(IP11_15_12, HRX1_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP11_15_12, TS_SDAT0_C, SEL_TSIF0_2), - PINMUX_IPSR_MSEL(IP11_15_12, STP_ISD_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP11_15_12, RIF1_CLK_C, SEL_DRIF1_2), - - PINMUX_IPSR_MSEL(IP11_19_16, TX1_A, SEL_SCIF1_0), - PINMUX_IPSR_MSEL(IP11_19_16, HTX1_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP11_19_16, TS_SDEN0_C, SEL_TSIF0_2), - PINMUX_IPSR_MSEL(IP11_19_16, STP_ISEN_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP11_19_16, RIF1_D0_C, SEL_DRIF1_2), - - PINMUX_IPSR_GPSR(IP11_23_20, CTS1_N), - PINMUX_IPSR_MSEL(IP11_23_20, HCTS1_N_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP11_23_20, MSIOF1_RXD_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP11_23_20, TS_SDEN1_C, SEL_TSIF1_2), - PINMUX_IPSR_MSEL(IP11_23_20, STP_ISEN_1_C, SEL_SSP1_1_2), - PINMUX_IPSR_MSEL(IP11_23_20, RIF1_D0_B, SEL_DRIF1_1), - PINMUX_IPSR_GPSR(IP11_23_20, ADIDATA), - - PINMUX_IPSR_GPSR(IP11_27_24, RTS1_N), - PINMUX_IPSR_MSEL(IP11_27_24, HRTS1_N_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP11_27_24, MSIOF1_TXD_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP11_27_24, TS_SDAT1_C, SEL_TSIF1_2), - PINMUX_IPSR_MSEL(IP11_27_24, STP_ISD_1_C, SEL_SSP1_1_2), - PINMUX_IPSR_MSEL(IP11_27_24, RIF1_D1_B, SEL_DRIF1_1), - PINMUX_IPSR_GPSR(IP11_27_24, ADICHS0), - - PINMUX_IPSR_GPSR(IP11_31_28, SCK2), - PINMUX_IPSR_MSEL(IP11_31_28, SCIF_CLK_B, SEL_SCIF1_1), - PINMUX_IPSR_MSEL(IP11_31_28, MSIOF1_SCK_B, SEL_MSIOF1_1), - PINMUX_IPSR_MSEL(IP11_31_28, TS_SCK1_C, SEL_TSIF1_2), - PINMUX_IPSR_MSEL(IP11_31_28, STP_ISCLK_1_C, SEL_SSP1_1_2), - PINMUX_IPSR_MSEL(IP11_31_28, RIF1_CLK_B, SEL_DRIF1_1), - PINMUX_IPSR_GPSR(IP11_31_28, ADICLK), - - /* IPSR12 */ - PINMUX_IPSR_MSEL(IP12_3_0, TX2_A, SEL_SCIF2_0), - PINMUX_IPSR_MSEL(IP12_3_0, SD2_CD_B, SEL_SDHI2_1), - PINMUX_IPSR_MSEL(IP12_3_0, SCL1_A, SEL_I2C1_0), - PINMUX_IPSR_MSEL(IP12_3_0, FMCLK_A, SEL_FM_0), - PINMUX_IPSR_MSEL(IP12_3_0, RIF1_D1_C, SEL_DRIF1_2), - PINMUX_IPSR_MSEL(IP12_3_0, FSO_CFE_0_B, SEL_FSO_1), - - PINMUX_IPSR_MSEL(IP12_7_4, RX2_A, SEL_SCIF2_0), - PINMUX_IPSR_MSEL(IP12_7_4, SD2_WP_B, SEL_SDHI2_1), - PINMUX_IPSR_MSEL(IP12_7_4, SDA1_A, SEL_I2C1_0), - PINMUX_IPSR_MSEL(IP12_7_4, FMIN_A, SEL_FM_0), - PINMUX_IPSR_MSEL(IP12_7_4, RIF1_SYNC_C, SEL_DRIF1_2), - PINMUX_IPSR_MSEL(IP12_7_4, FSO_CFE_1_B, SEL_FSO_1), - - PINMUX_IPSR_GPSR(IP12_11_8, HSCK0), - PINMUX_IPSR_MSEL(IP12_11_8, MSIOF1_SCK_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP12_11_8, AUDIO_CLKB_A, SEL_ADG_0), - PINMUX_IPSR_MSEL(IP12_11_8, SSI_SDATA1_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP12_11_8, TS_SCK0_D, SEL_TSIF0_3), - PINMUX_IPSR_MSEL(IP12_11_8, STP_ISCLK_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP12_11_8, RIF0_CLK_C, SEL_DRIF0_2), - - PINMUX_IPSR_GPSR(IP12_15_12, HRX0), - PINMUX_IPSR_MSEL(IP12_15_12, MSIOF1_RXD_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP12_15_12, SSI_SDATA2_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP12_15_12, TS_SDEN0_D, SEL_TSIF0_3), - PINMUX_IPSR_MSEL(IP12_15_12, STP_ISEN_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP12_15_12, RIF0_D0_C, SEL_DRIF0_2), - - PINMUX_IPSR_GPSR(IP12_19_16, HTX0), - PINMUX_IPSR_MSEL(IP12_19_16, MSIOF1_TXD_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP12_19_16, SSI_SDATA9_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP12_19_16, TS_SDAT0_D, SEL_TSIF0_3), - PINMUX_IPSR_MSEL(IP12_19_16, STP_ISD_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP12_19_16, RIF0_D1_C, SEL_DRIF0_2), - - PINMUX_IPSR_GPSR(IP12_23_20, HCTS0_N), - PINMUX_IPSR_MSEL(IP12_23_20, RX2_B, SEL_SCIF2_1), - PINMUX_IPSR_MSEL(IP12_23_20, MSIOF1_SYNC_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP12_23_20, SSI_SCK9_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP12_23_20, TS_SPSYNC0_D, SEL_TSIF0_3), - PINMUX_IPSR_MSEL(IP12_23_20, STP_ISSYNC_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP12_23_20, RIF0_SYNC_C, SEL_DRIF0_2), - PINMUX_IPSR_MSEL(IP12_23_20, AUDIO_CLKOUT1_A, SEL_ADG_0), - - PINMUX_IPSR_GPSR(IP12_27_24, HRTS0_N), - PINMUX_IPSR_MSEL(IP12_27_24, TX2_B, SEL_SCIF2_1), - PINMUX_IPSR_MSEL(IP12_27_24, MSIOF1_SS1_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP12_27_24, SSI_WS9_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP12_27_24, STP_IVCXO27_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP12_27_24, BPFCLK_A, SEL_FM_0), - PINMUX_IPSR_MSEL(IP12_27_24, AUDIO_CLKOUT2_A, SEL_ADG_0), - - PINMUX_IPSR_GPSR(IP12_31_28, MSIOF0_SYNC), - PINMUX_IPSR_MSEL(IP12_31_28, AUDIO_CLKOUT_A, SEL_ADG_0), - - /* IPSR13 */ - PINMUX_IPSR_GPSR(IP13_3_0, MSIOF0_SS1), - PINMUX_IPSR_GPSR(IP13_3_0, RX5), - PINMUX_IPSR_MSEL(IP13_3_0, AUDIO_CLKA_C, SEL_ADG_2), - PINMUX_IPSR_MSEL(IP13_3_0, SSI_SCK2_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP13_3_0, STP_IVCXO27_0_C, SEL_SSP1_0_2), - PINMUX_IPSR_MSEL(IP13_3_0, AUDIO_CLKOUT3_A, SEL_ADG_0), - PINMUX_IPSR_MSEL(IP13_3_0, TCLK1_B, SEL_TIMER_TMU_1), - - PINMUX_IPSR_GPSR(IP13_7_4, MSIOF0_SS2), - PINMUX_IPSR_GPSR(IP13_7_4, TX5), - PINMUX_IPSR_MSEL(IP13_7_4, MSIOF1_SS2_D, SEL_MSIOF1_3), - PINMUX_IPSR_MSEL(IP13_7_4, AUDIO_CLKC_A, SEL_ADG_0), - PINMUX_IPSR_MSEL(IP13_7_4, SSI_WS2_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP13_7_4, STP_OPWM_0_D, SEL_SSP1_0_3), - PINMUX_IPSR_MSEL(IP13_7_4, AUDIO_CLKOUT_D, SEL_ADG_3), - PINMUX_IPSR_MSEL(IP13_7_4, SPEEDIN_B, SEL_SPEED_PULSE_1), - - PINMUX_IPSR_GPSR(IP13_11_8, MLB_CLK), - PINMUX_IPSR_MSEL(IP13_11_8, MSIOF1_SCK_F, SEL_MSIOF1_5), - PINMUX_IPSR_MSEL(IP13_11_8, SCL1_B, SEL_I2C1_1), - - PINMUX_IPSR_GPSR(IP13_15_12, MLB_SIG), - PINMUX_IPSR_MSEL(IP13_15_12, RX1_B, SEL_SCIF1_1), - PINMUX_IPSR_MSEL(IP13_15_12, MSIOF1_SYNC_F, SEL_MSIOF1_5), - PINMUX_IPSR_MSEL(IP13_15_12, SDA1_B, SEL_I2C1_1), - - PINMUX_IPSR_GPSR(IP13_19_16, MLB_DAT), - PINMUX_IPSR_MSEL(IP13_19_16, TX1_B, SEL_SCIF1_1), - PINMUX_IPSR_MSEL(IP13_19_16, MSIOF1_RXD_F, SEL_MSIOF1_5), - - PINMUX_IPSR_GPSR(IP13_23_20, SSI_SCK01239), - PINMUX_IPSR_MSEL(IP13_23_20, MSIOF1_TXD_F, SEL_MSIOF1_5), - - PINMUX_IPSR_GPSR(IP13_27_24, SSI_WS01239), - PINMUX_IPSR_MSEL(IP13_27_24, MSIOF1_SS1_F, SEL_MSIOF1_5), - - PINMUX_IPSR_GPSR(IP13_31_28, SSI_SDATA0), - PINMUX_IPSR_MSEL(IP13_31_28, MSIOF1_SS2_F, SEL_MSIOF1_5), - - /* IPSR14 */ - PINMUX_IPSR_MSEL(IP14_3_0, SSI_SDATA1_A, SEL_SSI_0), - - PINMUX_IPSR_MSEL(IP14_7_4, SSI_SDATA2_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP14_7_4, SSI_SCK1_B, SEL_SSI_1), - - PINMUX_IPSR_GPSR(IP14_11_8, SSI_SCK349), - PINMUX_IPSR_MSEL(IP14_11_8, MSIOF1_SS1_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_11_8, STP_OPWM_0_A, SEL_SSP1_0_0), - - PINMUX_IPSR_GPSR(IP14_15_12, SSI_WS349), - PINMUX_IPSR_MSEL(IP14_15_12, HCTS2_N_A, SEL_HSCIF2_0), - PINMUX_IPSR_MSEL(IP14_15_12, MSIOF1_SS2_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_15_12, STP_IVCXO27_0_A, SEL_SSP1_0_0), - - PINMUX_IPSR_GPSR(IP14_19_16, SSI_SDATA3), - PINMUX_IPSR_MSEL(IP14_19_16, HRTS2_N_A, SEL_HSCIF2_0), - PINMUX_IPSR_MSEL(IP14_19_16, MSIOF1_TXD_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_19_16, TS_SCK0_A, SEL_TSIF0_0), - PINMUX_IPSR_MSEL(IP14_19_16, STP_ISCLK_0_A, SEL_SSP1_0_0), - PINMUX_IPSR_MSEL(IP14_19_16, RIF0_D1_A, SEL_DRIF0_0), - PINMUX_IPSR_MSEL(IP14_19_16, RIF2_D0_A, SEL_DRIF2_0), - - PINMUX_IPSR_GPSR(IP14_23_20, SSI_SCK4), - PINMUX_IPSR_MSEL(IP14_23_20, HRX2_A, SEL_HSCIF2_0), - PINMUX_IPSR_MSEL(IP14_23_20, MSIOF1_SCK_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_23_20, TS_SDAT0_A, SEL_TSIF0_0), - PINMUX_IPSR_MSEL(IP14_23_20, STP_ISD_0_A, SEL_SSP1_0_0), - PINMUX_IPSR_MSEL(IP14_23_20, RIF0_CLK_A, SEL_DRIF0_0), - PINMUX_IPSR_MSEL(IP14_23_20, RIF2_CLK_A, SEL_DRIF2_0), - - PINMUX_IPSR_GPSR(IP14_27_24, SSI_WS4), - PINMUX_IPSR_MSEL(IP14_27_24, HTX2_A, SEL_HSCIF2_0), - PINMUX_IPSR_MSEL(IP14_27_24, MSIOF1_SYNC_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_27_24, TS_SDEN0_A, SEL_TSIF0_0), - PINMUX_IPSR_MSEL(IP14_27_24, STP_ISEN_0_A, SEL_SSP1_0_0), - PINMUX_IPSR_MSEL(IP14_27_24, RIF0_SYNC_A, SEL_DRIF0_0), - PINMUX_IPSR_MSEL(IP14_27_24, RIF2_SYNC_A, SEL_DRIF2_0), - - PINMUX_IPSR_GPSR(IP14_31_28, SSI_SDATA4), - PINMUX_IPSR_MSEL(IP14_31_28, HSCK2_A, SEL_HSCIF2_0), - PINMUX_IPSR_MSEL(IP14_31_28, MSIOF1_RXD_A, SEL_MSIOF1_0), - PINMUX_IPSR_MSEL(IP14_31_28, TS_SPSYNC0_A, SEL_TSIF0_0), - PINMUX_IPSR_MSEL(IP14_31_28, STP_ISSYNC_0_A, SEL_SSP1_0_0), - PINMUX_IPSR_MSEL(IP14_31_28, RIF0_D0_A, SEL_DRIF0_0), - PINMUX_IPSR_MSEL(IP14_31_28, RIF2_D1_A, SEL_DRIF2_0), - - /* IPSR15 */ - PINMUX_IPSR_GPSR(IP15_3_0, SSI_SCK6), - PINMUX_IPSR_GPSR(IP15_3_0, USB2_PWEN), - PINMUX_IPSR_MSEL(IP15_3_0, SIM0_RST_D, SEL_SIMCARD_3), - - PINMUX_IPSR_GPSR(IP15_7_4, SSI_WS6), - PINMUX_IPSR_GPSR(IP15_7_4, USB2_OVC), - PINMUX_IPSR_MSEL(IP15_7_4, SIM0_D_D, SEL_SIMCARD_3), - - PINMUX_IPSR_GPSR(IP15_11_8, SSI_SDATA6), - PINMUX_IPSR_MSEL(IP15_11_8, SIM0_CLK_D, SEL_SIMCARD_3), - PINMUX_IPSR_MSEL(IP15_11_8, SATA_DEVSLP_A, SEL_SATA_0), - - PINMUX_IPSR_GPSR(IP15_15_12, SSI_SCK78), - PINMUX_IPSR_MSEL(IP15_15_12, HRX2_B, SEL_HSCIF2_1), - PINMUX_IPSR_MSEL(IP15_15_12, MSIOF1_SCK_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP15_15_12, TS_SCK1_A, SEL_TSIF1_0), - PINMUX_IPSR_MSEL(IP15_15_12, STP_ISCLK_1_A, SEL_SSP1_1_0), - PINMUX_IPSR_MSEL(IP15_15_12, RIF1_CLK_A, SEL_DRIF1_0), - PINMUX_IPSR_MSEL(IP15_15_12, RIF3_CLK_A, SEL_DRIF3_0), - - PINMUX_IPSR_GPSR(IP15_19_16, SSI_WS78), - PINMUX_IPSR_MSEL(IP15_19_16, HTX2_B, SEL_HSCIF2_1), - PINMUX_IPSR_MSEL(IP15_19_16, MSIOF1_SYNC_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP15_19_16, TS_SDAT1_A, SEL_TSIF1_0), - PINMUX_IPSR_MSEL(IP15_19_16, STP_ISD_1_A, SEL_SSP1_1_0), - PINMUX_IPSR_MSEL(IP15_19_16, RIF1_SYNC_A, SEL_DRIF1_0), - PINMUX_IPSR_MSEL(IP15_19_16, RIF3_SYNC_A, SEL_DRIF3_0), - - PINMUX_IPSR_GPSR(IP15_23_20, SSI_SDATA7), - PINMUX_IPSR_MSEL(IP15_23_20, HCTS2_N_B, SEL_HSCIF2_1), - PINMUX_IPSR_MSEL(IP15_23_20, MSIOF1_RXD_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP15_23_20, TS_SDEN1_A, SEL_TSIF1_0), - PINMUX_IPSR_MSEL(IP15_23_20, STP_ISEN_1_A, SEL_SSP1_1_0), - PINMUX_IPSR_MSEL(IP15_23_20, RIF1_D0_A, SEL_DRIF1_0), - PINMUX_IPSR_MSEL(IP15_23_20, RIF3_D0_A, SEL_DRIF3_0), - PINMUX_IPSR_MSEL(IP15_23_20, TCLK2_A, SEL_TIMER_TMU_0), - - PINMUX_IPSR_GPSR(IP15_27_24, SSI_SDATA8), - PINMUX_IPSR_MSEL(IP15_27_24, HRTS2_N_B, SEL_HSCIF2_1), - PINMUX_IPSR_MSEL(IP15_27_24, MSIOF1_TXD_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP15_27_24, TS_SPSYNC1_A, SEL_TSIF1_0), - PINMUX_IPSR_MSEL(IP15_27_24, STP_ISSYNC_1_A, SEL_SSP1_1_0), - PINMUX_IPSR_MSEL(IP15_27_24, RIF1_D1_A, SEL_DRIF1_0), - PINMUX_IPSR_MSEL(IP15_27_24, RIF3_D1_A, SEL_DRIF3_0), - - PINMUX_IPSR_MSEL(IP15_31_28, SSI_SDATA9_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP15_31_28, HSCK2_B, SEL_HSCIF2_1), - PINMUX_IPSR_MSEL(IP15_31_28, MSIOF1_SS1_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP15_31_28, HSCK1_A, SEL_HSCIF1_0), - PINMUX_IPSR_MSEL(IP15_31_28, SSI_WS1_B, SEL_SSI_1), - PINMUX_IPSR_GPSR(IP15_31_28, SCK1), - PINMUX_IPSR_MSEL(IP15_31_28, STP_IVCXO27_1_A, SEL_SSP1_1_0), - PINMUX_IPSR_GPSR(IP15_31_28, SCK5), - - /* IPSR16 */ - PINMUX_IPSR_MSEL(IP16_3_0, AUDIO_CLKA_A, SEL_ADG_0), - - PINMUX_IPSR_MSEL(IP16_7_4, AUDIO_CLKB_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP16_7_4, SCIF_CLK_A, SEL_SCIF1_0), - PINMUX_IPSR_MSEL(IP16_7_4, STP_IVCXO27_1_D, SEL_SSP1_1_3), - PINMUX_IPSR_MSEL(IP16_7_4, REMOCON_A, SEL_REMOCON_0), - PINMUX_IPSR_MSEL(IP16_7_4, TCLK1_A, SEL_TIMER_TMU_0), - - PINMUX_IPSR_GPSR(IP16_11_8, USB0_PWEN), - PINMUX_IPSR_MSEL(IP16_11_8, SIM0_RST_C, SEL_SIMCARD_2), - PINMUX_IPSR_MSEL(IP16_11_8, TS_SCK1_D, SEL_TSIF1_3), - PINMUX_IPSR_MSEL(IP16_11_8, STP_ISCLK_1_D, SEL_SSP1_1_3), - PINMUX_IPSR_MSEL(IP16_11_8, BPFCLK_B, SEL_FM_1), - PINMUX_IPSR_MSEL(IP16_11_8, RIF3_CLK_B, SEL_DRIF3_1), - - PINMUX_IPSR_GPSR(IP16_15_12, USB0_OVC), - PINMUX_IPSR_MSEL(IP16_11_8, SIM0_D_C, SEL_SIMCARD_2), - PINMUX_IPSR_MSEL(IP16_11_8, TS_SDAT1_D, SEL_TSIF1_3), - PINMUX_IPSR_MSEL(IP16_11_8, STP_ISD_1_D, SEL_SSP1_1_3), - PINMUX_IPSR_MSEL(IP16_11_8, RIF3_SYNC_B, SEL_DRIF3_1), - - PINMUX_IPSR_GPSR(IP16_19_16, USB1_PWEN), - PINMUX_IPSR_MSEL(IP16_19_16, SIM0_CLK_C, SEL_SIMCARD_2), - PINMUX_IPSR_MSEL(IP16_19_16, SSI_SCK1_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP16_19_16, TS_SCK0_E, SEL_TSIF0_4), - PINMUX_IPSR_MSEL(IP16_19_16, STP_ISCLK_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP16_19_16, FMCLK_B, SEL_FM_1), - PINMUX_IPSR_MSEL(IP16_19_16, RIF2_CLK_B, SEL_DRIF2_1), - PINMUX_IPSR_MSEL(IP16_19_16, SPEEDIN_A, SEL_SPEED_PULSE_0), - - PINMUX_IPSR_GPSR(IP16_23_20, USB1_OVC), - PINMUX_IPSR_MSEL(IP16_23_20, MSIOF1_SS2_C, SEL_MSIOF1_2), - PINMUX_IPSR_MSEL(IP16_23_20, SSI_WS1_A, SEL_SSI_0), - PINMUX_IPSR_MSEL(IP16_23_20, TS_SDAT0_E, SEL_TSIF0_4), - PINMUX_IPSR_MSEL(IP16_23_20, STP_ISD_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP16_23_20, FMIN_B, SEL_FM_1), - PINMUX_IPSR_MSEL(IP16_23_20, RIF2_SYNC_B, SEL_DRIF2_1), - PINMUX_IPSR_MSEL(IP16_23_20, REMOCON_B, SEL_REMOCON_1), - - PINMUX_IPSR_GPSR(IP16_27_24, USB30_PWEN), - PINMUX_IPSR_MSEL(IP16_27_24, AUDIO_CLKOUT_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP16_27_24, SSI_SCK2_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP16_27_24, TS_SDEN1_D, SEL_TSIF1_3), - PINMUX_IPSR_MSEL(IP16_27_24, STP_ISEN_1_D, SEL_SSP1_1_3), - PINMUX_IPSR_MSEL(IP16_27_24, STP_OPWM_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP16_27_24, RIF3_D0_B, SEL_DRIF3_1), - PINMUX_IPSR_MSEL(IP16_27_24, TCLK2_B, SEL_TIMER_TMU_1), - PINMUX_IPSR_GPSR(IP16_27_24, TPU0TO0), - - PINMUX_IPSR_GPSR(IP16_31_28, USB30_OVC), - PINMUX_IPSR_MSEL(IP16_31_28, AUDIO_CLKOUT1_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP16_31_28, SSI_WS2_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP16_31_28, TS_SPSYNC1_D, SEL_TSIF1_3), - PINMUX_IPSR_MSEL(IP16_31_28, STP_ISSYNC_1_D, SEL_SSP1_1_3), - PINMUX_IPSR_MSEL(IP16_31_28, STP_IVCXO27_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP16_31_28, RIF3_D1_B, SEL_DRIF3_1), - PINMUX_IPSR_MSEL(IP16_31_28, FSO_TOE_B, SEL_FSO_1), - PINMUX_IPSR_GPSR(IP16_31_28, TPU0TO1), - - /* IPSR17 */ - PINMUX_IPSR_GPSR(IP17_3_0, USB31_PWEN), - PINMUX_IPSR_MSEL(IP17_3_0, AUDIO_CLKOUT2_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP17_3_0, SSI_SCK9_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP17_3_0, TS_SDEN0_E, SEL_TSIF0_4), - PINMUX_IPSR_MSEL(IP17_3_0, STP_ISEN_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP17_3_0, RIF2_D0_B, SEL_DRIF2_1), - PINMUX_IPSR_GPSR(IP17_3_0, TPU0TO2), - - PINMUX_IPSR_GPSR(IP17_7_4, USB31_OVC), - PINMUX_IPSR_MSEL(IP17_7_4, AUDIO_CLKOUT3_B, SEL_ADG_1), - PINMUX_IPSR_MSEL(IP17_7_4, SSI_WS9_B, SEL_SSI_1), - PINMUX_IPSR_MSEL(IP17_7_4, TS_SPSYNC0_E, SEL_TSIF0_4), - PINMUX_IPSR_MSEL(IP17_7_4, STP_ISSYNC_0_E, SEL_SSP1_0_4), - PINMUX_IPSR_MSEL(IP17_7_4, RIF2_D1_B, SEL_DRIF2_1), - PINMUX_IPSR_GPSR(IP17_7_4, TPU0TO3), - -/* - * Static pins can not be muxed between different functions but - * still need mark entries in the pinmux list. Add each static - * pin to the list without an associated function. The sh-pfc - * core will do the right thing and skip trying to mux the pin - * while still applying configuration to it. - */ -#define FM(x) PINMUX_DATA(x##_MARK, 0), - PINMUX_STATIC -#undef FM -}; - -/* - * Pins not associated with a GPIO port. - */ -enum { - GP_ASSIGN_LAST(), - NOGP_ALL(), -}; - -static const struct sh_pfc_pin pinmux_pins[] = { - PINMUX_GPIO_GP_ALL(), - PINMUX_NOGP_ALL(), -}; - -/* - AUDIO CLOCK ------------------------------------------------------------ */ -static const unsigned int audio_clk_a_a_pins[] = { - /* CLK A */ - RCAR_GP_PIN(6, 22), -}; -static const unsigned int audio_clk_a_a_mux[] = { - AUDIO_CLKA_A_MARK, -}; -static const unsigned int audio_clk_a_b_pins[] = { - /* CLK A */ - RCAR_GP_PIN(5, 4), -}; -static const unsigned int audio_clk_a_b_mux[] = { - AUDIO_CLKA_B_MARK, -}; -static const unsigned int audio_clk_a_c_pins[] = { - /* CLK A */ - RCAR_GP_PIN(5, 19), -}; -static const unsigned int audio_clk_a_c_mux[] = { - AUDIO_CLKA_C_MARK, -}; -static const unsigned int audio_clk_b_a_pins[] = { - /* CLK B */ - RCAR_GP_PIN(5, 12), -}; -static const unsigned int audio_clk_b_a_mux[] = { - AUDIO_CLKB_A_MARK, -}; -static const unsigned int audio_clk_b_b_pins[] = { - /* CLK B */ - RCAR_GP_PIN(6, 23), -}; -static const unsigned int audio_clk_b_b_mux[] = { - AUDIO_CLKB_B_MARK, -}; -static const unsigned int audio_clk_c_a_pins[] = { - /* CLK C */ - RCAR_GP_PIN(5, 21), -}; -static const unsigned int audio_clk_c_a_mux[] = { - AUDIO_CLKC_A_MARK, -}; -static const unsigned int audio_clk_c_b_pins[] = { - /* CLK C */ - RCAR_GP_PIN(5, 0), -}; -static const unsigned int audio_clk_c_b_mux[] = { - AUDIO_CLKC_B_MARK, -}; -static const unsigned int audio_clkout_a_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(5, 18), -}; -static const unsigned int audio_clkout_a_mux[] = { - AUDIO_CLKOUT_A_MARK, -}; -static const unsigned int audio_clkout_b_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(6, 28), -}; -static const unsigned int audio_clkout_b_mux[] = { - AUDIO_CLKOUT_B_MARK, -}; -static const unsigned int audio_clkout_c_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(5, 3), -}; -static const unsigned int audio_clkout_c_mux[] = { - AUDIO_CLKOUT_C_MARK, -}; -static const unsigned int audio_clkout_d_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(5, 21), -}; -static const unsigned int audio_clkout_d_mux[] = { - AUDIO_CLKOUT_D_MARK, -}; -static const unsigned int audio_clkout1_a_pins[] = { - /* CLKOUT1 */ - RCAR_GP_PIN(5, 15), -}; -static const unsigned int audio_clkout1_a_mux[] = { - AUDIO_CLKOUT1_A_MARK, -}; -static const unsigned int audio_clkout1_b_pins[] = { - /* CLKOUT1 */ - RCAR_GP_PIN(6, 29), -}; -static const unsigned int audio_clkout1_b_mux[] = { - AUDIO_CLKOUT1_B_MARK, -}; -static const unsigned int audio_clkout2_a_pins[] = { - /* CLKOUT2 */ - RCAR_GP_PIN(5, 16), -}; -static const unsigned int audio_clkout2_a_mux[] = { - AUDIO_CLKOUT2_A_MARK, -}; -static const unsigned int audio_clkout2_b_pins[] = { - /* CLKOUT2 */ - RCAR_GP_PIN(6, 30), -}; -static const unsigned int audio_clkout2_b_mux[] = { - AUDIO_CLKOUT2_B_MARK, -}; - -static const unsigned int audio_clkout3_a_pins[] = { - /* CLKOUT3 */ - RCAR_GP_PIN(5, 19), -}; -static const unsigned int audio_clkout3_a_mux[] = { - AUDIO_CLKOUT3_A_MARK, -}; -static const unsigned int audio_clkout3_b_pins[] = { - /* CLKOUT3 */ - RCAR_GP_PIN(6, 31), -}; -static const unsigned int audio_clkout3_b_mux[] = { - AUDIO_CLKOUT3_B_MARK, -}; - -/* - EtherAVB --------------------------------------------------------------- */ -static const unsigned int avb_link_pins[] = { - /* AVB_LINK */ - RCAR_GP_PIN(2, 12), -}; -static const unsigned int avb_link_mux[] = { - AVB_LINK_MARK, -}; -static const unsigned int avb_magic_pins[] = { - /* AVB_MAGIC_ */ - RCAR_GP_PIN(2, 10), -}; -static const unsigned int avb_magic_mux[] = { - AVB_MAGIC_MARK, -}; -static const unsigned int avb_phy_int_pins[] = { - /* AVB_PHY_INT */ - RCAR_GP_PIN(2, 11), -}; -static const unsigned int avb_phy_int_mux[] = { - AVB_PHY_INT_MARK, -}; -static const unsigned int avb_mdio_pins[] = { - /* AVB_MDC, AVB_MDIO */ - RCAR_GP_PIN(2, 9), PIN_AVB_MDIO, -}; -static const unsigned int avb_mdio_mux[] = { - AVB_MDC_MARK, AVB_MDIO_MARK, -}; -static const unsigned int avb_mii_pins[] = { - /* - * AVB_TX_CTL, AVB_TXC, AVB_TD0, - * AVB_TD1, AVB_TD2, AVB_TD3, - * AVB_RX_CTL, AVB_RXC, AVB_RD0, - * AVB_RD1, AVB_RD2, AVB_RD3, - * AVB_TXCREFCLK - */ - PIN_AVB_TX_CTL, PIN_AVB_TXC, PIN_AVB_TD0, - PIN_AVB_TD1, PIN_AVB_TD2, PIN_AVB_TD3, - PIN_AVB_RX_CTL, PIN_AVB_RXC, PIN_AVB_RD0, - PIN_AVB_RD1, PIN_AVB_RD2, PIN_AVB_RD3, - PIN_AVB_TXCREFCLK, -}; -static const unsigned int avb_mii_mux[] = { - AVB_TX_CTL_MARK, AVB_TXC_MARK, AVB_TD0_MARK, - AVB_TD1_MARK, AVB_TD2_MARK, AVB_TD3_MARK, - AVB_RX_CTL_MARK, AVB_RXC_MARK, AVB_RD0_MARK, - AVB_RD1_MARK, AVB_RD2_MARK, AVB_RD3_MARK, - AVB_TXCREFCLK_MARK, -}; -static const unsigned int avb_avtp_pps_pins[] = { - /* AVB_AVTP_PPS */ - RCAR_GP_PIN(2, 6), -}; -static const unsigned int avb_avtp_pps_mux[] = { - AVB_AVTP_PPS_MARK, -}; -static const unsigned int avb_avtp_match_a_pins[] = { - /* AVB_AVTP_MATCH_A */ - RCAR_GP_PIN(2, 13), -}; -static const unsigned int avb_avtp_match_a_mux[] = { - AVB_AVTP_MATCH_A_MARK, -}; -static const unsigned int avb_avtp_capture_a_pins[] = { - /* AVB_AVTP_CAPTURE_A */ - RCAR_GP_PIN(2, 14), -}; -static const unsigned int avb_avtp_capture_a_mux[] = { - AVB_AVTP_CAPTURE_A_MARK, -}; -static const unsigned int avb_avtp_match_b_pins[] = { - /* AVB_AVTP_MATCH_B */ - RCAR_GP_PIN(1, 8), -}; -static const unsigned int avb_avtp_match_b_mux[] = { - AVB_AVTP_MATCH_B_MARK, -}; -static const unsigned int avb_avtp_capture_b_pins[] = { - /* AVB_AVTP_CAPTURE_B */ - RCAR_GP_PIN(1, 11), -}; -static const unsigned int avb_avtp_capture_b_mux[] = { - AVB_AVTP_CAPTURE_B_MARK, -}; - -/* - CAN ------------------------------------------------------------------ */ -static const unsigned int can0_data_a_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), -}; -static const unsigned int can0_data_a_mux[] = { - CAN0_TX_A_MARK, CAN0_RX_A_MARK, -}; -static const unsigned int can0_data_b_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), -}; -static const unsigned int can0_data_b_mux[] = { - CAN0_TX_B_MARK, CAN0_RX_B_MARK, -}; -static const unsigned int can1_data_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), -}; -static const unsigned int can1_data_mux[] = { - CAN1_TX_MARK, CAN1_RX_MARK, -}; - -/* - CAN Clock -------------------------------------------------------------- */ -static const unsigned int can_clk_pins[] = { - /* CLK */ - RCAR_GP_PIN(1, 25), -}; -static const unsigned int can_clk_mux[] = { - CAN_CLK_MARK, -}; - -/* - CAN FD --------------------------------------------------------------- */ -static const unsigned int canfd0_data_a_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), -}; -static const unsigned int canfd0_data_a_mux[] = { - CANFD0_TX_A_MARK, CANFD0_RX_A_MARK, -}; -static const unsigned int canfd0_data_b_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), -}; -static const unsigned int canfd0_data_b_mux[] = { - CANFD0_TX_B_MARK, CANFD0_RX_B_MARK, -}; -static const unsigned int canfd1_data_pins[] = { - /* TX, RX */ - RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 26), -}; -static const unsigned int canfd1_data_mux[] = { - CANFD1_TX_MARK, CANFD1_RX_MARK, -}; - -/* - DRIF0 --------------------------------------------------------------- */ -static const unsigned int drif0_ctrl_a_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), -}; -static const unsigned int drif0_ctrl_a_mux[] = { - RIF0_CLK_A_MARK, RIF0_SYNC_A_MARK, -}; -static const unsigned int drif0_data0_a_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 10), -}; -static const unsigned int drif0_data0_a_mux[] = { - RIF0_D0_A_MARK, -}; -static const unsigned int drif0_data1_a_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 7), -}; -static const unsigned int drif0_data1_a_mux[] = { - RIF0_D1_A_MARK, -}; -static const unsigned int drif0_ctrl_b_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 4), -}; -static const unsigned int drif0_ctrl_b_mux[] = { - RIF0_CLK_B_MARK, RIF0_SYNC_B_MARK, -}; -static const unsigned int drif0_data0_b_pins[] = { - /* D0 */ - RCAR_GP_PIN(5, 1), -}; -static const unsigned int drif0_data0_b_mux[] = { - RIF0_D0_B_MARK, -}; -static const unsigned int drif0_data1_b_pins[] = { - /* D1 */ - RCAR_GP_PIN(5, 2), -}; -static const unsigned int drif0_data1_b_mux[] = { - RIF0_D1_B_MARK, -}; -static const unsigned int drif0_ctrl_c_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 15), -}; -static const unsigned int drif0_ctrl_c_mux[] = { - RIF0_CLK_C_MARK, RIF0_SYNC_C_MARK, -}; -static const unsigned int drif0_data0_c_pins[] = { - /* D0 */ - RCAR_GP_PIN(5, 13), -}; -static const unsigned int drif0_data0_c_mux[] = { - RIF0_D0_C_MARK, -}; -static const unsigned int drif0_data1_c_pins[] = { - /* D1 */ - RCAR_GP_PIN(5, 14), -}; -static const unsigned int drif0_data1_c_mux[] = { - RIF0_D1_C_MARK, -}; -/* - DRIF1 --------------------------------------------------------------- */ -static const unsigned int drif1_ctrl_a_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), -}; -static const unsigned int drif1_ctrl_a_mux[] = { - RIF1_CLK_A_MARK, RIF1_SYNC_A_MARK, -}; -static const unsigned int drif1_data0_a_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 19), -}; -static const unsigned int drif1_data0_a_mux[] = { - RIF1_D0_A_MARK, -}; -static const unsigned int drif1_data1_a_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 20), -}; -static const unsigned int drif1_data1_a_mux[] = { - RIF1_D1_A_MARK, -}; -static const unsigned int drif1_ctrl_b_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(5, 9), RCAR_GP_PIN(5, 3), -}; -static const unsigned int drif1_ctrl_b_mux[] = { - RIF1_CLK_B_MARK, RIF1_SYNC_B_MARK, -}; -static const unsigned int drif1_data0_b_pins[] = { - /* D0 */ - RCAR_GP_PIN(5, 7), -}; -static const unsigned int drif1_data0_b_mux[] = { - RIF1_D0_B_MARK, -}; -static const unsigned int drif1_data1_b_pins[] = { - /* D1 */ - RCAR_GP_PIN(5, 8), -}; -static const unsigned int drif1_data1_b_mux[] = { - RIF1_D1_B_MARK, -}; -static const unsigned int drif1_ctrl_c_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 11), -}; -static const unsigned int drif1_ctrl_c_mux[] = { - RIF1_CLK_C_MARK, RIF1_SYNC_C_MARK, -}; -static const unsigned int drif1_data0_c_pins[] = { - /* D0 */ - RCAR_GP_PIN(5, 6), -}; -static const unsigned int drif1_data0_c_mux[] = { - RIF1_D0_C_MARK, -}; -static const unsigned int drif1_data1_c_pins[] = { - /* D1 */ - RCAR_GP_PIN(5, 10), -}; -static const unsigned int drif1_data1_c_mux[] = { - RIF1_D1_C_MARK, -}; -/* - DRIF2 --------------------------------------------------------------- */ -static const unsigned int drif2_ctrl_a_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), -}; -static const unsigned int drif2_ctrl_a_mux[] = { - RIF2_CLK_A_MARK, RIF2_SYNC_A_MARK, -}; -static const unsigned int drif2_data0_a_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 7), -}; -static const unsigned int drif2_data0_a_mux[] = { - RIF2_D0_A_MARK, -}; -static const unsigned int drif2_data1_a_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 10), -}; -static const unsigned int drif2_data1_a_mux[] = { - RIF2_D1_A_MARK, -}; -static const unsigned int drif2_ctrl_b_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27), -}; -static const unsigned int drif2_ctrl_b_mux[] = { - RIF2_CLK_B_MARK, RIF2_SYNC_B_MARK, -}; -static const unsigned int drif2_data0_b_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 30), -}; -static const unsigned int drif2_data0_b_mux[] = { - RIF2_D0_B_MARK, -}; -static const unsigned int drif2_data1_b_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 31), -}; -static const unsigned int drif2_data1_b_mux[] = { - RIF2_D1_B_MARK, -}; -/* - DRIF3 --------------------------------------------------------------- */ -static const unsigned int drif3_ctrl_a_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), -}; -static const unsigned int drif3_ctrl_a_mux[] = { - RIF3_CLK_A_MARK, RIF3_SYNC_A_MARK, -}; -static const unsigned int drif3_data0_a_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 19), -}; -static const unsigned int drif3_data0_a_mux[] = { - RIF3_D0_A_MARK, -}; -static const unsigned int drif3_data1_a_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 20), -}; -static const unsigned int drif3_data1_a_mux[] = { - RIF3_D1_A_MARK, -}; -static const unsigned int drif3_ctrl_b_pins[] = { - /* CLK, SYNC */ - RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25), -}; -static const unsigned int drif3_ctrl_b_mux[] = { - RIF3_CLK_B_MARK, RIF3_SYNC_B_MARK, -}; -static const unsigned int drif3_data0_b_pins[] = { - /* D0 */ - RCAR_GP_PIN(6, 28), -}; -static const unsigned int drif3_data0_b_mux[] = { - RIF3_D0_B_MARK, -}; -static const unsigned int drif3_data1_b_pins[] = { - /* D1 */ - RCAR_GP_PIN(6, 29), -}; -static const unsigned int drif3_data1_b_mux[] = { - RIF3_D1_B_MARK, -}; - -/* - DU --------------------------------------------------------------------- */ -static const unsigned int du_rgb666_pins[] = { - /* R[7:2], G[7:2], B[7:2] */ - RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 13), - RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), - RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13), - RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 19), RCAR_GP_PIN(1, 18), - RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 3), RCAR_GP_PIN(1, 2), -}; -static const unsigned int du_rgb666_mux[] = { - DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK, - DU_DR3_MARK, DU_DR2_MARK, - DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK, - DU_DG3_MARK, DU_DG2_MARK, - DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK, - DU_DB3_MARK, DU_DB2_MARK, -}; -static const unsigned int du_rgb888_pins[] = { - /* R[7:0], G[7:0], B[7:0] */ - RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 13), - RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), - RCAR_GP_PIN(0, 9), RCAR_GP_PIN(0, 8), - RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 13), - RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 19), RCAR_GP_PIN(1, 18), - RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 16), - RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 3), RCAR_GP_PIN(1, 2), - RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), -}; -static const unsigned int du_rgb888_mux[] = { - DU_DR7_MARK, DU_DR6_MARK, DU_DR5_MARK, DU_DR4_MARK, - DU_DR3_MARK, DU_DR2_MARK, DU_DR1_MARK, DU_DR0_MARK, - DU_DG7_MARK, DU_DG6_MARK, DU_DG5_MARK, DU_DG4_MARK, - DU_DG3_MARK, DU_DG2_MARK, DU_DG1_MARK, DU_DG0_MARK, - DU_DB7_MARK, DU_DB6_MARK, DU_DB5_MARK, DU_DB4_MARK, - DU_DB3_MARK, DU_DB2_MARK, DU_DB1_MARK, DU_DB0_MARK, -}; -static const unsigned int du_clk_out_0_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(1, 27), -}; -static const unsigned int du_clk_out_0_mux[] = { - DU_DOTCLKOUT0_MARK -}; -static const unsigned int du_clk_out_1_pins[] = { - /* CLKOUT */ - RCAR_GP_PIN(2, 3), -}; -static const unsigned int du_clk_out_1_mux[] = { - DU_DOTCLKOUT1_MARK -}; -static const unsigned int du_sync_pins[] = { - /* EXVSYNC/VSYNC, EXHSYNC/HSYNC */ - RCAR_GP_PIN(2, 5), RCAR_GP_PIN(2, 4), -}; -static const unsigned int du_sync_mux[] = { - DU_EXVSYNC_DU_VSYNC_MARK, DU_EXHSYNC_DU_HSYNC_MARK -}; -static const unsigned int du_oddf_pins[] = { - /* EXDISP/EXODDF/EXCDE */ - RCAR_GP_PIN(2, 2), -}; -static const unsigned int du_oddf_mux[] = { - DU_EXODDF_DU_ODDF_DISP_CDE_MARK, -}; -static const unsigned int du_cde_pins[] = { - /* CDE */ - RCAR_GP_PIN(2, 0), -}; -static const unsigned int du_cde_mux[] = { - DU_CDE_MARK, -}; -static const unsigned int du_disp_pins[] = { - /* DISP */ - RCAR_GP_PIN(2, 1), -}; -static const unsigned int du_disp_mux[] = { - DU_DISP_MARK, -}; -/* - HSCIF0 ----------------------------------------------------------------- */ -static const unsigned int hscif0_data_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14), -}; -static const unsigned int hscif0_data_mux[] = { - HRX0_MARK, HTX0_MARK, -}; -static const unsigned int hscif0_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 12), -}; -static const unsigned int hscif0_clk_mux[] = { - HSCK0_MARK, -}; -static const unsigned int hscif0_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 15), -}; -static const unsigned int hscif0_ctrl_mux[] = { - HRTS0_N_MARK, HCTS0_N_MARK, -}; -/* - HSCIF1 ----------------------------------------------------------------- */ -static const unsigned int hscif1_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6), -}; -static const unsigned int hscif1_data_a_mux[] = { - HRX1_A_MARK, HTX1_A_MARK, -}; -static const unsigned int hscif1_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int hscif1_clk_a_mux[] = { - HSCK1_A_MARK, -}; -static const unsigned int hscif1_ctrl_a_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7), -}; -static const unsigned int hscif1_ctrl_a_mux[] = { - HRTS1_N_A_MARK, HCTS1_N_A_MARK, -}; - -static const unsigned int hscif1_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2), -}; -static const unsigned int hscif1_data_b_mux[] = { - HRX1_B_MARK, HTX1_B_MARK, -}; -static const unsigned int hscif1_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 0), -}; -static const unsigned int hscif1_clk_b_mux[] = { - HSCK1_B_MARK, -}; -static const unsigned int hscif1_ctrl_b_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3), -}; -static const unsigned int hscif1_ctrl_b_mux[] = { - HRTS1_N_B_MARK, HCTS1_N_B_MARK, -}; -/* - HSCIF2 ----------------------------------------------------------------- */ -static const unsigned int hscif2_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), -}; -static const unsigned int hscif2_data_a_mux[] = { - HRX2_A_MARK, HTX2_A_MARK, -}; -static const unsigned int hscif2_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 10), -}; -static const unsigned int hscif2_clk_a_mux[] = { - HSCK2_A_MARK, -}; -static const unsigned int hscif2_ctrl_a_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6), -}; -static const unsigned int hscif2_ctrl_a_mux[] = { - HRTS2_N_A_MARK, HCTS2_N_A_MARK, -}; - -static const unsigned int hscif2_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), -}; -static const unsigned int hscif2_data_b_mux[] = { - HRX2_B_MARK, HTX2_B_MARK, -}; -static const unsigned int hscif2_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int hscif2_clk_b_mux[] = { - HSCK2_B_MARK, -}; -static const unsigned int hscif2_ctrl_b_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 19), -}; -static const unsigned int hscif2_ctrl_b_mux[] = { - HRTS2_N_B_MARK, HCTS2_N_B_MARK, -}; -/* - HSCIF3 ----------------------------------------------------------------- */ -static const unsigned int hscif3_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), -}; -static const unsigned int hscif3_data_a_mux[] = { - HRX3_A_MARK, HTX3_A_MARK, -}; -static const unsigned int hscif3_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 22), -}; -static const unsigned int hscif3_clk_mux[] = { - HSCK3_MARK, -}; -static const unsigned int hscif3_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), -}; -static const unsigned int hscif3_ctrl_mux[] = { - HRTS3_N_MARK, HCTS3_N_MARK, -}; - -static const unsigned int hscif3_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11), -}; -static const unsigned int hscif3_data_b_mux[] = { - HRX3_B_MARK, HTX3_B_MARK, -}; -static const unsigned int hscif3_data_c_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15), -}; -static const unsigned int hscif3_data_c_mux[] = { - HRX3_C_MARK, HTX3_C_MARK, -}; -static const unsigned int hscif3_data_d_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8), -}; -static const unsigned int hscif3_data_d_mux[] = { - HRX3_D_MARK, HTX3_D_MARK, -}; -/* - HSCIF4 ----------------------------------------------------------------- */ -static const unsigned int hscif4_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13), -}; -static const unsigned int hscif4_data_a_mux[] = { - HRX4_A_MARK, HTX4_A_MARK, -}; -static const unsigned int hscif4_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 11), -}; -static const unsigned int hscif4_clk_mux[] = { - HSCK4_MARK, -}; -static const unsigned int hscif4_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14), -}; -static const unsigned int hscif4_ctrl_mux[] = { - HRTS4_N_MARK, HCTS4_N_MARK, -}; - -static const unsigned int hscif4_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11), -}; -static const unsigned int hscif4_data_b_mux[] = { - HRX4_B_MARK, HTX4_B_MARK, -}; - -/* - I2C -------------------------------------------------------------------- */ -static const unsigned int i2c0_pins[] = { - /* SCL, SDA */ - RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), -}; - -static const unsigned int i2c0_mux[] = { - SCL0_MARK, SDA0_MARK, -}; - -static const unsigned int i2c1_a_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 10), -}; -static const unsigned int i2c1_a_mux[] = { - SDA1_A_MARK, SCL1_A_MARK, -}; -static const unsigned int i2c1_b_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 23), -}; -static const unsigned int i2c1_b_mux[] = { - SDA1_B_MARK, SCL1_B_MARK, -}; -static const unsigned int i2c2_a_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 4), -}; -static const unsigned int i2c2_a_mux[] = { - SDA2_A_MARK, SCL2_A_MARK, -}; -static const unsigned int i2c2_b_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(3, 13), RCAR_GP_PIN(3, 12), -}; -static const unsigned int i2c2_b_mux[] = { - SDA2_B_MARK, SCL2_B_MARK, -}; - -static const unsigned int i2c3_pins[] = { - /* SCL, SDA */ - RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8), -}; - -static const unsigned int i2c3_mux[] = { - SCL3_MARK, SDA3_MARK, -}; - -static const unsigned int i2c5_pins[] = { - /* SCL, SDA */ - RCAR_GP_PIN(2, 13), RCAR_GP_PIN(2, 14), -}; - -static const unsigned int i2c5_mux[] = { - SCL5_MARK, SDA5_MARK, -}; - -static const unsigned int i2c6_a_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11), -}; -static const unsigned int i2c6_a_mux[] = { - SDA6_A_MARK, SCL6_A_MARK, -}; -static const unsigned int i2c6_b_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), -}; -static const unsigned int i2c6_b_mux[] = { - SDA6_B_MARK, SCL6_B_MARK, -}; -static const unsigned int i2c6_c_pins[] = { - /* SDA, SCL */ - RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), -}; -static const unsigned int i2c6_c_mux[] = { - SDA6_C_MARK, SCL6_C_MARK, -}; - -/* - INTC-EX ---------------------------------------------------------------- */ -static const unsigned int intc_ex_irq0_pins[] = { - /* IRQ0 */ - RCAR_GP_PIN(2, 0), -}; -static const unsigned int intc_ex_irq0_mux[] = { - IRQ0_MARK, -}; -static const unsigned int intc_ex_irq1_pins[] = { - /* IRQ1 */ - RCAR_GP_PIN(2, 1), -}; -static const unsigned int intc_ex_irq1_mux[] = { - IRQ1_MARK, -}; -static const unsigned int intc_ex_irq2_pins[] = { - /* IRQ2 */ - RCAR_GP_PIN(2, 2), -}; -static const unsigned int intc_ex_irq2_mux[] = { - IRQ2_MARK, -}; -static const unsigned int intc_ex_irq3_pins[] = { - /* IRQ3 */ - RCAR_GP_PIN(2, 3), -}; -static const unsigned int intc_ex_irq3_mux[] = { - IRQ3_MARK, -}; -static const unsigned int intc_ex_irq4_pins[] = { - /* IRQ4 */ - RCAR_GP_PIN(2, 4), -}; -static const unsigned int intc_ex_irq4_mux[] = { - IRQ4_MARK, -}; -static const unsigned int intc_ex_irq5_pins[] = { - /* IRQ5 */ - RCAR_GP_PIN(2, 5), -}; -static const unsigned int intc_ex_irq5_mux[] = { - IRQ5_MARK, -}; - -/* - MLB+ ------------------------------------------------------------------- */ -static const unsigned int mlb_3pin_pins[] = { - RCAR_GP_PIN(5, 23), RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 25), -}; -static const unsigned int mlb_3pin_mux[] = { - MLB_CLK_MARK, MLB_SIG_MARK, MLB_DAT_MARK, -}; - -/* - MSIOF0 ----------------------------------------------------------------- */ -static const unsigned int msiof0_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 17), -}; -static const unsigned int msiof0_clk_mux[] = { - MSIOF0_SCK_MARK, -}; -static const unsigned int msiof0_sync_pins[] = { - /* SYNC */ - RCAR_GP_PIN(5, 18), -}; -static const unsigned int msiof0_sync_mux[] = { - MSIOF0_SYNC_MARK, -}; -static const unsigned int msiof0_ss1_pins[] = { - /* SS1 */ - RCAR_GP_PIN(5, 19), -}; -static const unsigned int msiof0_ss1_mux[] = { - MSIOF0_SS1_MARK, -}; -static const unsigned int msiof0_ss2_pins[] = { - /* SS2 */ - RCAR_GP_PIN(5, 21), -}; -static const unsigned int msiof0_ss2_mux[] = { - MSIOF0_SS2_MARK, -}; -static const unsigned int msiof0_txd_pins[] = { - /* TXD */ - RCAR_GP_PIN(5, 20), -}; -static const unsigned int msiof0_txd_mux[] = { - MSIOF0_TXD_MARK, -}; -static const unsigned int msiof0_rxd_pins[] = { - /* RXD */ - RCAR_GP_PIN(5, 22), -}; -static const unsigned int msiof0_rxd_mux[] = { - MSIOF0_RXD_MARK, -}; -/* - MSIOF1 ----------------------------------------------------------------- */ -static const unsigned int msiof1_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 8), -}; -static const unsigned int msiof1_clk_a_mux[] = { - MSIOF1_SCK_A_MARK, -}; -static const unsigned int msiof1_sync_a_pins[] = { - /* SYNC */ - RCAR_GP_PIN(6, 9), -}; -static const unsigned int msiof1_sync_a_mux[] = { - MSIOF1_SYNC_A_MARK, -}; -static const unsigned int msiof1_ss1_a_pins[] = { - /* SS1 */ - RCAR_GP_PIN(6, 5), -}; -static const unsigned int msiof1_ss1_a_mux[] = { - MSIOF1_SS1_A_MARK, -}; -static const unsigned int msiof1_ss2_a_pins[] = { - /* SS2 */ - RCAR_GP_PIN(6, 6), -}; -static const unsigned int msiof1_ss2_a_mux[] = { - MSIOF1_SS2_A_MARK, -}; -static const unsigned int msiof1_txd_a_pins[] = { - /* TXD */ - RCAR_GP_PIN(6, 7), -}; -static const unsigned int msiof1_txd_a_mux[] = { - MSIOF1_TXD_A_MARK, -}; -static const unsigned int msiof1_rxd_a_pins[] = { - /* RXD */ - RCAR_GP_PIN(6, 10), -}; -static const unsigned int msiof1_rxd_a_mux[] = { - MSIOF1_RXD_A_MARK, -}; -static const unsigned int msiof1_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 9), -}; -static const unsigned int msiof1_clk_b_mux[] = { - MSIOF1_SCK_B_MARK, -}; -static const unsigned int msiof1_sync_b_pins[] = { - /* SYNC */ - RCAR_GP_PIN(5, 3), -}; -static const unsigned int msiof1_sync_b_mux[] = { - MSIOF1_SYNC_B_MARK, -}; -static const unsigned int msiof1_ss1_b_pins[] = { - /* SS1 */ - RCAR_GP_PIN(5, 4), -}; -static const unsigned int msiof1_ss1_b_mux[] = { - MSIOF1_SS1_B_MARK, -}; -static const unsigned int msiof1_ss2_b_pins[] = { - /* SS2 */ - RCAR_GP_PIN(5, 0), -}; -static const unsigned int msiof1_ss2_b_mux[] = { - MSIOF1_SS2_B_MARK, -}; -static const unsigned int msiof1_txd_b_pins[] = { - /* TXD */ - RCAR_GP_PIN(5, 8), -}; -static const unsigned int msiof1_txd_b_mux[] = { - MSIOF1_TXD_B_MARK, -}; -static const unsigned int msiof1_rxd_b_pins[] = { - /* RXD */ - RCAR_GP_PIN(5, 7), -}; -static const unsigned int msiof1_rxd_b_mux[] = { - MSIOF1_RXD_B_MARK, -}; -static const unsigned int msiof1_clk_c_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 17), -}; -static const unsigned int msiof1_clk_c_mux[] = { - MSIOF1_SCK_C_MARK, -}; -static const unsigned int msiof1_sync_c_pins[] = { - /* SYNC */ - RCAR_GP_PIN(6, 18), -}; -static const unsigned int msiof1_sync_c_mux[] = { - MSIOF1_SYNC_C_MARK, -}; -static const unsigned int msiof1_ss1_c_pins[] = { - /* SS1 */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int msiof1_ss1_c_mux[] = { - MSIOF1_SS1_C_MARK, -}; -static const unsigned int msiof1_ss2_c_pins[] = { - /* SS2 */ - RCAR_GP_PIN(6, 27), -}; -static const unsigned int msiof1_ss2_c_mux[] = { - MSIOF1_SS2_C_MARK, -}; -static const unsigned int msiof1_txd_c_pins[] = { - /* TXD */ - RCAR_GP_PIN(6, 20), -}; -static const unsigned int msiof1_txd_c_mux[] = { - MSIOF1_TXD_C_MARK, -}; -static const unsigned int msiof1_rxd_c_pins[] = { - /* RXD */ - RCAR_GP_PIN(6, 19), -}; -static const unsigned int msiof1_rxd_c_mux[] = { - MSIOF1_RXD_C_MARK, -}; -static const unsigned int msiof1_clk_d_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 12), -}; -static const unsigned int msiof1_clk_d_mux[] = { - MSIOF1_SCK_D_MARK, -}; -static const unsigned int msiof1_sync_d_pins[] = { - /* SYNC */ - RCAR_GP_PIN(5, 15), -}; -static const unsigned int msiof1_sync_d_mux[] = { - MSIOF1_SYNC_D_MARK, -}; -static const unsigned int msiof1_ss1_d_pins[] = { - /* SS1 */ - RCAR_GP_PIN(5, 16), -}; -static const unsigned int msiof1_ss1_d_mux[] = { - MSIOF1_SS1_D_MARK, -}; -static const unsigned int msiof1_ss2_d_pins[] = { - /* SS2 */ - RCAR_GP_PIN(5, 21), -}; -static const unsigned int msiof1_ss2_d_mux[] = { - MSIOF1_SS2_D_MARK, -}; -static const unsigned int msiof1_txd_d_pins[] = { - /* TXD */ - RCAR_GP_PIN(5, 14), -}; -static const unsigned int msiof1_txd_d_mux[] = { - MSIOF1_TXD_D_MARK, -}; -static const unsigned int msiof1_rxd_d_pins[] = { - /* RXD */ - RCAR_GP_PIN(5, 13), -}; -static const unsigned int msiof1_rxd_d_mux[] = { - MSIOF1_RXD_D_MARK, -}; -static const unsigned int msiof1_clk_e_pins[] = { - /* SCK */ - RCAR_GP_PIN(3, 0), -}; -static const unsigned int msiof1_clk_e_mux[] = { - MSIOF1_SCK_E_MARK, -}; -static const unsigned int msiof1_sync_e_pins[] = { - /* SYNC */ - RCAR_GP_PIN(3, 1), -}; -static const unsigned int msiof1_sync_e_mux[] = { - MSIOF1_SYNC_E_MARK, -}; -static const unsigned int msiof1_ss1_e_pins[] = { - /* SS1 */ - RCAR_GP_PIN(3, 4), -}; -static const unsigned int msiof1_ss1_e_mux[] = { - MSIOF1_SS1_E_MARK, -}; -static const unsigned int msiof1_ss2_e_pins[] = { - /* SS2 */ - RCAR_GP_PIN(3, 5), -}; -static const unsigned int msiof1_ss2_e_mux[] = { - MSIOF1_SS2_E_MARK, -}; -static const unsigned int msiof1_txd_e_pins[] = { - /* TXD */ - RCAR_GP_PIN(3, 3), -}; -static const unsigned int msiof1_txd_e_mux[] = { - MSIOF1_TXD_E_MARK, -}; -static const unsigned int msiof1_rxd_e_pins[] = { - /* RXD */ - RCAR_GP_PIN(3, 2), -}; -static const unsigned int msiof1_rxd_e_mux[] = { - MSIOF1_RXD_E_MARK, -}; -static const unsigned int msiof1_clk_f_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 23), -}; -static const unsigned int msiof1_clk_f_mux[] = { - MSIOF1_SCK_F_MARK, -}; -static const unsigned int msiof1_sync_f_pins[] = { - /* SYNC */ - RCAR_GP_PIN(5, 24), -}; -static const unsigned int msiof1_sync_f_mux[] = { - MSIOF1_SYNC_F_MARK, -}; -static const unsigned int msiof1_ss1_f_pins[] = { - /* SS1 */ - RCAR_GP_PIN(6, 1), -}; -static const unsigned int msiof1_ss1_f_mux[] = { - MSIOF1_SS1_F_MARK, -}; -static const unsigned int msiof1_ss2_f_pins[] = { - /* SS2 */ - RCAR_GP_PIN(6, 2), -}; -static const unsigned int msiof1_ss2_f_mux[] = { - MSIOF1_SS2_F_MARK, -}; -static const unsigned int msiof1_txd_f_pins[] = { - /* TXD */ - RCAR_GP_PIN(6, 0), -}; -static const unsigned int msiof1_txd_f_mux[] = { - MSIOF1_TXD_F_MARK, -}; -static const unsigned int msiof1_rxd_f_pins[] = { - /* RXD */ - RCAR_GP_PIN(5, 25), -}; -static const unsigned int msiof1_rxd_f_mux[] = { - MSIOF1_RXD_F_MARK, -}; -static const unsigned int msiof1_clk_g_pins[] = { - /* SCK */ - RCAR_GP_PIN(3, 6), -}; -static const unsigned int msiof1_clk_g_mux[] = { - MSIOF1_SCK_G_MARK, -}; -static const unsigned int msiof1_sync_g_pins[] = { - /* SYNC */ - RCAR_GP_PIN(3, 7), -}; -static const unsigned int msiof1_sync_g_mux[] = { - MSIOF1_SYNC_G_MARK, -}; -static const unsigned int msiof1_ss1_g_pins[] = { - /* SS1 */ - RCAR_GP_PIN(3, 10), -}; -static const unsigned int msiof1_ss1_g_mux[] = { - MSIOF1_SS1_G_MARK, -}; -static const unsigned int msiof1_ss2_g_pins[] = { - /* SS2 */ - RCAR_GP_PIN(3, 11), -}; -static const unsigned int msiof1_ss2_g_mux[] = { - MSIOF1_SS2_G_MARK, -}; -static const unsigned int msiof1_txd_g_pins[] = { - /* TXD */ - RCAR_GP_PIN(3, 9), -}; -static const unsigned int msiof1_txd_g_mux[] = { - MSIOF1_TXD_G_MARK, -}; -static const unsigned int msiof1_rxd_g_pins[] = { - /* RXD */ - RCAR_GP_PIN(3, 8), -}; -static const unsigned int msiof1_rxd_g_mux[] = { - MSIOF1_RXD_G_MARK, -}; -/* - MSIOF2 ----------------------------------------------------------------- */ -static const unsigned int msiof2_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 9), -}; -static const unsigned int msiof2_clk_a_mux[] = { - MSIOF2_SCK_A_MARK, -}; -static const unsigned int msiof2_sync_a_pins[] = { - /* SYNC */ - RCAR_GP_PIN(1, 8), -}; -static const unsigned int msiof2_sync_a_mux[] = { - MSIOF2_SYNC_A_MARK, -}; -static const unsigned int msiof2_ss1_a_pins[] = { - /* SS1 */ - RCAR_GP_PIN(1, 6), -}; -static const unsigned int msiof2_ss1_a_mux[] = { - MSIOF2_SS1_A_MARK, -}; -static const unsigned int msiof2_ss2_a_pins[] = { - /* SS2 */ - RCAR_GP_PIN(1, 7), -}; -static const unsigned int msiof2_ss2_a_mux[] = { - MSIOF2_SS2_A_MARK, -}; -static const unsigned int msiof2_txd_a_pins[] = { - /* TXD */ - RCAR_GP_PIN(1, 11), -}; -static const unsigned int msiof2_txd_a_mux[] = { - MSIOF2_TXD_A_MARK, -}; -static const unsigned int msiof2_rxd_a_pins[] = { - /* RXD */ - RCAR_GP_PIN(1, 10), -}; -static const unsigned int msiof2_rxd_a_mux[] = { - MSIOF2_RXD_A_MARK, -}; -static const unsigned int msiof2_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(0, 4), -}; -static const unsigned int msiof2_clk_b_mux[] = { - MSIOF2_SCK_B_MARK, -}; -static const unsigned int msiof2_sync_b_pins[] = { - /* SYNC */ - RCAR_GP_PIN(0, 5), -}; -static const unsigned int msiof2_sync_b_mux[] = { - MSIOF2_SYNC_B_MARK, -}; -static const unsigned int msiof2_ss1_b_pins[] = { - /* SS1 */ - RCAR_GP_PIN(0, 0), -}; -static const unsigned int msiof2_ss1_b_mux[] = { - MSIOF2_SS1_B_MARK, -}; -static const unsigned int msiof2_ss2_b_pins[] = { - /* SS2 */ - RCAR_GP_PIN(0, 1), -}; -static const unsigned int msiof2_ss2_b_mux[] = { - MSIOF2_SS2_B_MARK, -}; -static const unsigned int msiof2_txd_b_pins[] = { - /* TXD */ - RCAR_GP_PIN(0, 7), -}; -static const unsigned int msiof2_txd_b_mux[] = { - MSIOF2_TXD_B_MARK, -}; -static const unsigned int msiof2_rxd_b_pins[] = { - /* RXD */ - RCAR_GP_PIN(0, 6), -}; -static const unsigned int msiof2_rxd_b_mux[] = { - MSIOF2_RXD_B_MARK, -}; -static const unsigned int msiof2_clk_c_pins[] = { - /* SCK */ - RCAR_GP_PIN(2, 12), -}; -static const unsigned int msiof2_clk_c_mux[] = { - MSIOF2_SCK_C_MARK, -}; -static const unsigned int msiof2_sync_c_pins[] = { - /* SYNC */ - RCAR_GP_PIN(2, 11), -}; -static const unsigned int msiof2_sync_c_mux[] = { - MSIOF2_SYNC_C_MARK, -}; -static const unsigned int msiof2_ss1_c_pins[] = { - /* SS1 */ - RCAR_GP_PIN(2, 10), -}; -static const unsigned int msiof2_ss1_c_mux[] = { - MSIOF2_SS1_C_MARK, -}; -static const unsigned int msiof2_ss2_c_pins[] = { - /* SS2 */ - RCAR_GP_PIN(2, 9), -}; -static const unsigned int msiof2_ss2_c_mux[] = { - MSIOF2_SS2_C_MARK, -}; -static const unsigned int msiof2_txd_c_pins[] = { - /* TXD */ - RCAR_GP_PIN(2, 14), -}; -static const unsigned int msiof2_txd_c_mux[] = { - MSIOF2_TXD_C_MARK, -}; -static const unsigned int msiof2_rxd_c_pins[] = { - /* RXD */ - RCAR_GP_PIN(2, 13), -}; -static const unsigned int msiof2_rxd_c_mux[] = { - MSIOF2_RXD_C_MARK, -}; -static const unsigned int msiof2_clk_d_pins[] = { - /* SCK */ - RCAR_GP_PIN(0, 8), -}; -static const unsigned int msiof2_clk_d_mux[] = { - MSIOF2_SCK_D_MARK, -}; -static const unsigned int msiof2_sync_d_pins[] = { - /* SYNC */ - RCAR_GP_PIN(0, 9), -}; -static const unsigned int msiof2_sync_d_mux[] = { - MSIOF2_SYNC_D_MARK, -}; -static const unsigned int msiof2_ss1_d_pins[] = { - /* SS1 */ - RCAR_GP_PIN(0, 12), -}; -static const unsigned int msiof2_ss1_d_mux[] = { - MSIOF2_SS1_D_MARK, -}; -static const unsigned int msiof2_ss2_d_pins[] = { - /* SS2 */ - RCAR_GP_PIN(0, 13), -}; -static const unsigned int msiof2_ss2_d_mux[] = { - MSIOF2_SS2_D_MARK, -}; -static const unsigned int msiof2_txd_d_pins[] = { - /* TXD */ - RCAR_GP_PIN(0, 11), -}; -static const unsigned int msiof2_txd_d_mux[] = { - MSIOF2_TXD_D_MARK, -}; -static const unsigned int msiof2_rxd_d_pins[] = { - /* RXD */ - RCAR_GP_PIN(0, 10), -}; -static const unsigned int msiof2_rxd_d_mux[] = { - MSIOF2_RXD_D_MARK, -}; -/* - MSIOF3 ----------------------------------------------------------------- */ -static const unsigned int msiof3_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(0, 0), -}; -static const unsigned int msiof3_clk_a_mux[] = { - MSIOF3_SCK_A_MARK, -}; -static const unsigned int msiof3_sync_a_pins[] = { - /* SYNC */ - RCAR_GP_PIN(0, 1), -}; -static const unsigned int msiof3_sync_a_mux[] = { - MSIOF3_SYNC_A_MARK, -}; -static const unsigned int msiof3_ss1_a_pins[] = { - /* SS1 */ - RCAR_GP_PIN(0, 14), -}; -static const unsigned int msiof3_ss1_a_mux[] = { - MSIOF3_SS1_A_MARK, -}; -static const unsigned int msiof3_ss2_a_pins[] = { - /* SS2 */ - RCAR_GP_PIN(0, 15), -}; -static const unsigned int msiof3_ss2_a_mux[] = { - MSIOF3_SS2_A_MARK, -}; -static const unsigned int msiof3_txd_a_pins[] = { - /* TXD */ - RCAR_GP_PIN(0, 3), -}; -static const unsigned int msiof3_txd_a_mux[] = { - MSIOF3_TXD_A_MARK, -}; -static const unsigned int msiof3_rxd_a_pins[] = { - /* RXD */ - RCAR_GP_PIN(0, 2), -}; -static const unsigned int msiof3_rxd_a_mux[] = { - MSIOF3_RXD_A_MARK, -}; -static const unsigned int msiof3_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 2), -}; -static const unsigned int msiof3_clk_b_mux[] = { - MSIOF3_SCK_B_MARK, -}; -static const unsigned int msiof3_sync_b_pins[] = { - /* SYNC */ - RCAR_GP_PIN(1, 0), -}; -static const unsigned int msiof3_sync_b_mux[] = { - MSIOF3_SYNC_B_MARK, -}; -static const unsigned int msiof3_ss1_b_pins[] = { - /* SS1 */ - RCAR_GP_PIN(1, 4), -}; -static const unsigned int msiof3_ss1_b_mux[] = { - MSIOF3_SS1_B_MARK, -}; -static const unsigned int msiof3_ss2_b_pins[] = { - /* SS2 */ - RCAR_GP_PIN(1, 5), -}; -static const unsigned int msiof3_ss2_b_mux[] = { - MSIOF3_SS2_B_MARK, -}; -static const unsigned int msiof3_txd_b_pins[] = { - /* TXD */ - RCAR_GP_PIN(1, 1), -}; -static const unsigned int msiof3_txd_b_mux[] = { - MSIOF3_TXD_B_MARK, -}; -static const unsigned int msiof3_rxd_b_pins[] = { - /* RXD */ - RCAR_GP_PIN(1, 3), -}; -static const unsigned int msiof3_rxd_b_mux[] = { - MSIOF3_RXD_B_MARK, -}; -static const unsigned int msiof3_clk_c_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 12), -}; -static const unsigned int msiof3_clk_c_mux[] = { - MSIOF3_SCK_C_MARK, -}; -static const unsigned int msiof3_sync_c_pins[] = { - /* SYNC */ - RCAR_GP_PIN(1, 13), -}; -static const unsigned int msiof3_sync_c_mux[] = { - MSIOF3_SYNC_C_MARK, -}; -static const unsigned int msiof3_txd_c_pins[] = { - /* TXD */ - RCAR_GP_PIN(1, 15), -}; -static const unsigned int msiof3_txd_c_mux[] = { - MSIOF3_TXD_C_MARK, -}; -static const unsigned int msiof3_rxd_c_pins[] = { - /* RXD */ - RCAR_GP_PIN(1, 14), -}; -static const unsigned int msiof3_rxd_c_mux[] = { - MSIOF3_RXD_C_MARK, -}; -static const unsigned int msiof3_clk_d_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 22), -}; -static const unsigned int msiof3_clk_d_mux[] = { - MSIOF3_SCK_D_MARK, -}; -static const unsigned int msiof3_sync_d_pins[] = { - /* SYNC */ - RCAR_GP_PIN(1, 23), -}; -static const unsigned int msiof3_sync_d_mux[] = { - MSIOF3_SYNC_D_MARK, -}; -static const unsigned int msiof3_ss1_d_pins[] = { - /* SS1 */ - RCAR_GP_PIN(1, 26), -}; -static const unsigned int msiof3_ss1_d_mux[] = { - MSIOF3_SS1_D_MARK, -}; -static const unsigned int msiof3_txd_d_pins[] = { - /* TXD */ - RCAR_GP_PIN(1, 25), -}; -static const unsigned int msiof3_txd_d_mux[] = { - MSIOF3_TXD_D_MARK, -}; -static const unsigned int msiof3_rxd_d_pins[] = { - /* RXD */ - RCAR_GP_PIN(1, 24), -}; -static const unsigned int msiof3_rxd_d_mux[] = { - MSIOF3_RXD_D_MARK, -}; - -/* - PWM0 --------------------------------------------------------------------*/ -static const unsigned int pwm0_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 6), -}; -static const unsigned int pwm0_mux[] = { - PWM0_MARK, -}; -/* - PWM1 --------------------------------------------------------------------*/ -static const unsigned int pwm1_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 7), -}; -static const unsigned int pwm1_a_mux[] = { - PWM1_A_MARK, -}; -static const unsigned int pwm1_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 8), -}; -static const unsigned int pwm1_b_mux[] = { - PWM1_B_MARK, -}; -/* - PWM2 --------------------------------------------------------------------*/ -static const unsigned int pwm2_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 8), -}; -static const unsigned int pwm2_a_mux[] = { - PWM2_A_MARK, -}; -static const unsigned int pwm2_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 11), -}; -static const unsigned int pwm2_b_mux[] = { - PWM2_B_MARK, -}; -/* - PWM3 --------------------------------------------------------------------*/ -static const unsigned int pwm3_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 0), -}; -static const unsigned int pwm3_a_mux[] = { - PWM3_A_MARK, -}; -static const unsigned int pwm3_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 2), -}; -static const unsigned int pwm3_b_mux[] = { - PWM3_B_MARK, -}; -/* - PWM4 --------------------------------------------------------------------*/ -static const unsigned int pwm4_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 1), -}; -static const unsigned int pwm4_a_mux[] = { - PWM4_A_MARK, -}; -static const unsigned int pwm4_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 3), -}; -static const unsigned int pwm4_b_mux[] = { - PWM4_B_MARK, -}; -/* - PWM5 --------------------------------------------------------------------*/ -static const unsigned int pwm5_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 2), -}; -static const unsigned int pwm5_a_mux[] = { - PWM5_A_MARK, -}; -static const unsigned int pwm5_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 4), -}; -static const unsigned int pwm5_b_mux[] = { - PWM5_B_MARK, -}; -/* - PWM6 --------------------------------------------------------------------*/ -static const unsigned int pwm6_a_pins[] = { - /* PWM */ - RCAR_GP_PIN(1, 3), -}; -static const unsigned int pwm6_a_mux[] = { - PWM6_A_MARK, -}; -static const unsigned int pwm6_b_pins[] = { - /* PWM */ - RCAR_GP_PIN(2, 5), -}; -static const unsigned int pwm6_b_mux[] = { - PWM6_B_MARK, -}; - -/* - QSPI0 ------------------------------------------------------------------ */ -static const unsigned int qspi0_ctrl_pins[] = { - /* QSPI0_SPCLK, QSPI0_SSL */ - PIN_QSPI0_SPCLK, PIN_QSPI0_SSL, -}; -static const unsigned int qspi0_ctrl_mux[] = { - QSPI0_SPCLK_MARK, QSPI0_SSL_MARK, -}; -static const unsigned int qspi0_data_pins[] = { - /* QSPI0_MOSI_IO0, QSPI0_MISO_IO1, QSPI0_IO2, QSPI0_IO3 */ - PIN_QSPI0_MOSI_IO0, PIN_QSPI0_MISO_IO1, PIN_QSPI0_IO2, PIN_QSPI0_IO3, -}; -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[] = { - /* QSPI1_SPCLK, QSPI1_SSL */ - PIN_QSPI1_SPCLK, PIN_QSPI1_SSL, -}; -static const unsigned int qspi1_ctrl_mux[] = { - QSPI1_SPCLK_MARK, QSPI1_SSL_MARK, -}; -static const unsigned int qspi1_data_pins[] = { - /* QSPI1_MOSI_IO0, QSPI1_MISO_IO1, QSPI1_IO2, QSPI1_IO3 */ - PIN_QSPI1_MOSI_IO0, PIN_QSPI1_MISO_IO1, PIN_QSPI1_IO2, PIN_QSPI1_IO3, -}; -static const unsigned int qspi1_data_mux[] = { - QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK, - QSPI1_IO2_MARK, QSPI1_IO3_MARK, -}; - -/* - SATA --------------------------------------------------------------------*/ -static const unsigned int sata0_devslp_a_pins[] = { - /* DEVSLP */ - RCAR_GP_PIN(6, 16), -}; -static const unsigned int sata0_devslp_a_mux[] = { - SATA_DEVSLP_A_MARK, -}; -static const unsigned int sata0_devslp_b_pins[] = { - /* DEVSLP */ - RCAR_GP_PIN(4, 6), -}; -static const unsigned int sata0_devslp_b_mux[] = { - SATA_DEVSLP_B_MARK, -}; - -/* - SCIF0 ------------------------------------------------------------------ */ -static const unsigned int scif0_data_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2), -}; -static const unsigned int scif0_data_mux[] = { - RX0_MARK, TX0_MARK, -}; -static const unsigned int scif0_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 0), -}; -static const unsigned int scif0_clk_mux[] = { - SCK0_MARK, -}; -static const unsigned int scif0_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3), -}; -static const unsigned int scif0_ctrl_mux[] = { - RTS0_N_MARK, CTS0_N_MARK, -}; -/* - SCIF1 ------------------------------------------------------------------ */ -static const unsigned int scif1_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6), -}; -static const unsigned int scif1_data_a_mux[] = { - RX1_A_MARK, TX1_A_MARK, -}; -static const unsigned int scif1_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int scif1_clk_mux[] = { - SCK1_MARK, -}; -static const unsigned int scif1_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7), -}; -static const unsigned int scif1_ctrl_mux[] = { - RTS1_N_MARK, CTS1_N_MARK, -}; - -static const unsigned int scif1_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 25), -}; -static const unsigned int scif1_data_b_mux[] = { - RX1_B_MARK, TX1_B_MARK, -}; -/* - SCIF2 ------------------------------------------------------------------ */ -static const unsigned int scif2_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 10), -}; -static const unsigned int scif2_data_a_mux[] = { - RX2_A_MARK, TX2_A_MARK, -}; -static const unsigned int scif2_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(5, 9), -}; -static const unsigned int scif2_clk_mux[] = { - SCK2_MARK, -}; -static const unsigned int scif2_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16), -}; -static const unsigned int scif2_data_b_mux[] = { - RX2_B_MARK, TX2_B_MARK, -}; -/* - SCIF3 ------------------------------------------------------------------ */ -static const unsigned int scif3_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24), -}; -static const unsigned int scif3_data_a_mux[] = { - RX3_A_MARK, TX3_A_MARK, -}; -static const unsigned int scif3_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 22), -}; -static const unsigned int scif3_clk_mux[] = { - SCK3_MARK, -}; -static const unsigned int scif3_ctrl_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25), -}; -static const unsigned int scif3_ctrl_mux[] = { - RTS3_N_MARK, CTS3_N_MARK, -}; -static const unsigned int scif3_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11), -}; -static const unsigned int scif3_data_b_mux[] = { - RX3_B_MARK, TX3_B_MARK, -}; -/* - SCIF4 ------------------------------------------------------------------ */ -static const unsigned int scif4_data_a_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 12), -}; -static const unsigned int scif4_data_a_mux[] = { - RX4_A_MARK, TX4_A_MARK, -}; -static const unsigned int scif4_clk_a_pins[] = { - /* SCK */ - RCAR_GP_PIN(2, 10), -}; -static const unsigned int scif4_clk_a_mux[] = { - SCK4_A_MARK, -}; -static const unsigned int scif4_ctrl_a_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 13), -}; -static const unsigned int scif4_ctrl_a_mux[] = { - RTS4_N_A_MARK, CTS4_N_A_MARK, -}; -static const unsigned int scif4_data_b_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), -}; -static const unsigned int scif4_data_b_mux[] = { - RX4_B_MARK, TX4_B_MARK, -}; -static const unsigned int scif4_clk_b_pins[] = { - /* SCK */ - RCAR_GP_PIN(1, 5), -}; -static const unsigned int scif4_clk_b_mux[] = { - SCK4_B_MARK, -}; -static const unsigned int scif4_ctrl_b_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 9), -}; -static const unsigned int scif4_ctrl_b_mux[] = { - RTS4_N_B_MARK, CTS4_N_B_MARK, -}; -static const unsigned int scif4_data_c_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13), -}; -static const unsigned int scif4_data_c_mux[] = { - RX4_C_MARK, TX4_C_MARK, -}; -static const unsigned int scif4_clk_c_pins[] = { - /* SCK */ - RCAR_GP_PIN(0, 8), -}; -static const unsigned int scif4_clk_c_mux[] = { - SCK4_C_MARK, -}; -static const unsigned int scif4_ctrl_c_pins[] = { - /* RTS, CTS */ - RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 10), -}; -static const unsigned int scif4_ctrl_c_mux[] = { - RTS4_N_C_MARK, CTS4_N_C_MARK, -}; -/* - SCIF5 ------------------------------------------------------------------ */ -static const unsigned int scif5_data_pins[] = { - /* RX, TX */ - RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 21), -}; -static const unsigned int scif5_data_mux[] = { - RX5_MARK, TX5_MARK, -}; -static const unsigned int scif5_clk_pins[] = { - /* SCK */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int scif5_clk_mux[] = { - SCK5_MARK, -}; - -/* - SCIF Clock ------------------------------------------------------------- */ -static const unsigned int scif_clk_a_pins[] = { - /* SCIF_CLK */ - RCAR_GP_PIN(6, 23), -}; -static const unsigned int scif_clk_a_mux[] = { - SCIF_CLK_A_MARK, -}; -static const unsigned int scif_clk_b_pins[] = { - /* SCIF_CLK */ - RCAR_GP_PIN(5, 9), -}; -static const unsigned int scif_clk_b_mux[] = { - SCIF_CLK_B_MARK, -}; - -/* - SDHI0 ------------------------------------------------------------------ */ -static const unsigned int sdhi0_data_pins[] = { - /* D[0:3] */ - RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), - RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5), -}; -static const unsigned int sdhi0_data_mux[] = { - SD0_DAT0_MARK, SD0_DAT1_MARK, - SD0_DAT2_MARK, SD0_DAT3_MARK, -}; -static const unsigned int sdhi0_ctrl_pins[] = { - /* CLK, CMD */ - RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 1), -}; -static const unsigned int sdhi0_ctrl_mux[] = { - SD0_CLK_MARK, SD0_CMD_MARK, -}; -static const unsigned int sdhi0_cd_pins[] = { - /* CD */ - RCAR_GP_PIN(3, 12), -}; -static const unsigned int sdhi0_cd_mux[] = { - SD0_CD_MARK, -}; -static const unsigned int sdhi0_wp_pins[] = { - /* WP */ - RCAR_GP_PIN(3, 13), -}; -static const unsigned int sdhi0_wp_mux[] = { - SD0_WP_MARK, -}; -/* - SDHI1 ------------------------------------------------------------------ */ -static const unsigned int sdhi1_data_pins[] = { - /* D[0:3] */ - RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), - RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), -}; -static const unsigned int sdhi1_data_mux[] = { - SD1_DAT0_MARK, SD1_DAT1_MARK, - SD1_DAT2_MARK, SD1_DAT3_MARK, -}; -static const unsigned int sdhi1_ctrl_pins[] = { - /* CLK, CMD */ - RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), -}; -static const unsigned int sdhi1_ctrl_mux[] = { - SD1_CLK_MARK, SD1_CMD_MARK, -}; -static const unsigned int sdhi1_cd_pins[] = { - /* CD */ - RCAR_GP_PIN(3, 14), -}; -static const unsigned int sdhi1_cd_mux[] = { - SD1_CD_MARK, -}; -static const unsigned int sdhi1_wp_pins[] = { - /* WP */ - RCAR_GP_PIN(3, 15), -}; -static const unsigned int sdhi1_wp_mux[] = { - SD1_WP_MARK, -}; -/* - SDHI2 ------------------------------------------------------------------ */ -static const unsigned int sdhi2_data_pins[] = { - /* D[0:7] */ - RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3), - RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5), - RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9), - RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), -}; -static const unsigned int sdhi2_data_mux[] = { - SD2_DAT0_MARK, SD2_DAT1_MARK, - SD2_DAT2_MARK, SD2_DAT3_MARK, - SD2_DAT4_MARK, SD2_DAT5_MARK, - SD2_DAT6_MARK, SD2_DAT7_MARK, -}; -static const unsigned int sdhi2_ctrl_pins[] = { - /* CLK, CMD */ - RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), -}; -static const unsigned int sdhi2_ctrl_mux[] = { - SD2_CLK_MARK, SD2_CMD_MARK, -}; -static const unsigned int sdhi2_cd_a_pins[] = { - /* CD */ - RCAR_GP_PIN(4, 13), -}; -static const unsigned int sdhi2_cd_a_mux[] = { - SD2_CD_A_MARK, -}; -static const unsigned int sdhi2_cd_b_pins[] = { - /* CD */ - RCAR_GP_PIN(5, 10), -}; -static const unsigned int sdhi2_cd_b_mux[] = { - SD2_CD_B_MARK, -}; -static const unsigned int sdhi2_wp_a_pins[] = { - /* WP */ - RCAR_GP_PIN(4, 14), -}; -static const unsigned int sdhi2_wp_a_mux[] = { - SD2_WP_A_MARK, -}; -static const unsigned int sdhi2_wp_b_pins[] = { - /* WP */ - RCAR_GP_PIN(5, 11), -}; -static const unsigned int sdhi2_wp_b_mux[] = { - SD2_WP_B_MARK, -}; -static const unsigned int sdhi2_ds_pins[] = { - /* DS */ - RCAR_GP_PIN(4, 6), -}; -static const unsigned int sdhi2_ds_mux[] = { - SD2_DS_MARK, -}; -/* - SDHI3 ------------------------------------------------------------------ */ -static const unsigned int sdhi3_data_pins[] = { - /* D[0:7] */ - RCAR_GP_PIN(4, 9), RCAR_GP_PIN(4, 10), - RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12), - RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14), - RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 16), -}; -static const unsigned int sdhi3_data_mux[] = { - SD3_DAT0_MARK, SD3_DAT1_MARK, - SD3_DAT2_MARK, SD3_DAT3_MARK, - SD3_DAT4_MARK, SD3_DAT5_MARK, - SD3_DAT6_MARK, SD3_DAT7_MARK, -}; -static const unsigned int sdhi3_ctrl_pins[] = { - /* CLK, CMD */ - RCAR_GP_PIN(4, 7), RCAR_GP_PIN(4, 8), -}; -static const unsigned int sdhi3_ctrl_mux[] = { - SD3_CLK_MARK, SD3_CMD_MARK, -}; -static const unsigned int sdhi3_cd_pins[] = { - /* CD */ - RCAR_GP_PIN(4, 15), -}; -static const unsigned int sdhi3_cd_mux[] = { - SD3_CD_MARK, -}; -static const unsigned int sdhi3_wp_pins[] = { - /* WP */ - RCAR_GP_PIN(4, 16), -}; -static const unsigned int sdhi3_wp_mux[] = { - SD3_WP_MARK, -}; -static const unsigned int sdhi3_ds_pins[] = { - /* DS */ - RCAR_GP_PIN(4, 17), -}; -static const unsigned int sdhi3_ds_mux[] = { - SD3_DS_MARK, -}; - -/* - SSI -------------------------------------------------------------------- */ -static const unsigned int ssi0_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 2), -}; -static const unsigned int ssi0_data_mux[] = { - SSI_SDATA0_MARK, -}; -static const unsigned int ssi01239_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1), -}; -static const unsigned int ssi01239_ctrl_mux[] = { - SSI_SCK01239_MARK, SSI_WS01239_MARK, -}; -static const unsigned int ssi1_data_a_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 3), -}; -static const unsigned int ssi1_data_a_mux[] = { - SSI_SDATA1_A_MARK, -}; -static const unsigned int ssi1_data_b_pins[] = { - /* SDATA */ - RCAR_GP_PIN(5, 12), -}; -static const unsigned int ssi1_data_b_mux[] = { - SSI_SDATA1_B_MARK, -}; -static const unsigned int ssi1_ctrl_a_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27), -}; -static const unsigned int ssi1_ctrl_a_mux[] = { - SSI_SCK1_A_MARK, SSI_WS1_A_MARK, -}; -static const unsigned int ssi1_ctrl_b_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 21), -}; -static const unsigned int ssi1_ctrl_b_mux[] = { - SSI_SCK1_B_MARK, SSI_WS1_B_MARK, -}; -static const unsigned int ssi2_data_a_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 4), -}; -static const unsigned int ssi2_data_a_mux[] = { - SSI_SDATA2_A_MARK, -}; -static const unsigned int ssi2_data_b_pins[] = { - /* SDATA */ - RCAR_GP_PIN(5, 13), -}; -static const unsigned int ssi2_data_b_mux[] = { - SSI_SDATA2_B_MARK, -}; -static const unsigned int ssi2_ctrl_a_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 21), -}; -static const unsigned int ssi2_ctrl_a_mux[] = { - SSI_SCK2_A_MARK, SSI_WS2_A_MARK, -}; -static const unsigned int ssi2_ctrl_b_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29), -}; -static const unsigned int ssi2_ctrl_b_mux[] = { - SSI_SCK2_B_MARK, SSI_WS2_B_MARK, -}; -static const unsigned int ssi3_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 7), -}; -static const unsigned int ssi3_data_mux[] = { - SSI_SDATA3_MARK, -}; -static const unsigned int ssi349_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 5), RCAR_GP_PIN(6, 6), -}; -static const unsigned int ssi349_ctrl_mux[] = { - SSI_SCK349_MARK, SSI_WS349_MARK, -}; -static const unsigned int ssi4_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 10), -}; -static const unsigned int ssi4_data_mux[] = { - SSI_SDATA4_MARK, -}; -static const unsigned int ssi4_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), -}; -static const unsigned int ssi4_ctrl_mux[] = { - SSI_SCK4_MARK, SSI_WS4_MARK, -}; -static const unsigned int ssi5_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 13), -}; -static const unsigned int ssi5_data_mux[] = { - SSI_SDATA5_MARK, -}; -static const unsigned int ssi5_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 11), RCAR_GP_PIN(6, 12), -}; -static const unsigned int ssi5_ctrl_mux[] = { - SSI_SCK5_MARK, SSI_WS5_MARK, -}; -static const unsigned int ssi6_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 16), -}; -static const unsigned int ssi6_data_mux[] = { - SSI_SDATA6_MARK, -}; -static const unsigned int ssi6_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 14), RCAR_GP_PIN(6, 15), -}; -static const unsigned int ssi6_ctrl_mux[] = { - SSI_SCK6_MARK, SSI_WS6_MARK, -}; -static const unsigned int ssi7_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 19), -}; -static const unsigned int ssi7_data_mux[] = { - SSI_SDATA7_MARK, -}; -static const unsigned int ssi78_ctrl_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18), -}; -static const unsigned int ssi78_ctrl_mux[] = { - SSI_SCK78_MARK, SSI_WS78_MARK, -}; -static const unsigned int ssi8_data_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 20), -}; -static const unsigned int ssi8_data_mux[] = { - SSI_SDATA8_MARK, -}; -static const unsigned int ssi9_data_a_pins[] = { - /* SDATA */ - RCAR_GP_PIN(6, 21), -}; -static const unsigned int ssi9_data_a_mux[] = { - SSI_SDATA9_A_MARK, -}; -static const unsigned int ssi9_data_b_pins[] = { - /* SDATA */ - RCAR_GP_PIN(5, 14), -}; -static const unsigned int ssi9_data_b_mux[] = { - SSI_SDATA9_B_MARK, -}; -static const unsigned int ssi9_ctrl_a_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 16), -}; -static const unsigned int ssi9_ctrl_a_mux[] = { - SSI_SCK9_A_MARK, SSI_WS9_A_MARK, -}; -static const unsigned int ssi9_ctrl_b_pins[] = { - /* SCK, WS */ - RCAR_GP_PIN(6, 30), RCAR_GP_PIN(6, 31), -}; -static const unsigned int ssi9_ctrl_b_mux[] = { - SSI_SCK9_B_MARK, SSI_WS9_B_MARK, -}; - -/* - TMU -------------------------------------------------------------------- */ -static const unsigned int tmu_tclk1_a_pins[] = { - /* TCLK */ - RCAR_GP_PIN(6, 23), -}; -static const unsigned int tmu_tclk1_a_mux[] = { - TCLK1_A_MARK, -}; -static const unsigned int tmu_tclk1_b_pins[] = { - /* TCLK */ - RCAR_GP_PIN(5, 19), -}; -static const unsigned int tmu_tclk1_b_mux[] = { - TCLK1_B_MARK, -}; -static const unsigned int tmu_tclk2_a_pins[] = { - /* TCLK */ - RCAR_GP_PIN(6, 19), -}; -static const unsigned int tmu_tclk2_a_mux[] = { - TCLK2_A_MARK, -}; -static const unsigned int tmu_tclk2_b_pins[] = { - /* TCLK */ - RCAR_GP_PIN(6, 28), -}; -static const unsigned int tmu_tclk2_b_mux[] = { - TCLK2_B_MARK, -}; - -/* - TPU ------------------------------------------------------------------- */ -static const unsigned int tpu_to0_pins[] = { - /* TPU0TO0 */ - RCAR_GP_PIN(6, 28), -}; -static const unsigned int tpu_to0_mux[] = { - TPU0TO0_MARK, -}; -static const unsigned int tpu_to1_pins[] = { - /* TPU0TO1 */ - RCAR_GP_PIN(6, 29), -}; -static const unsigned int tpu_to1_mux[] = { - TPU0TO1_MARK, -}; -static const unsigned int tpu_to2_pins[] = { - /* TPU0TO2 */ - RCAR_GP_PIN(6, 30), -}; -static const unsigned int tpu_to2_mux[] = { - TPU0TO2_MARK, -}; -static const unsigned int tpu_to3_pins[] = { - /* TPU0TO3 */ - RCAR_GP_PIN(6, 31), -}; -static const unsigned int tpu_to3_mux[] = { - TPU0TO3_MARK, -}; - -/* - USB0 ------------------------------------------------------------------- */ -static const unsigned int usb0_pins[] = { - /* PWEN, OVC */ - RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25), -}; -static const unsigned int usb0_mux[] = { - USB0_PWEN_MARK, USB0_OVC_MARK, -}; -/* - USB1 ------------------------------------------------------------------- */ -static const unsigned int usb1_pins[] = { - /* PWEN, OVC */ - RCAR_GP_PIN(6, 26), RCAR_GP_PIN(6, 27), -}; -static const unsigned int usb1_mux[] = { - USB1_PWEN_MARK, USB1_OVC_MARK, -}; -/* - USB2 ------------------------------------------------------------------- */ -static const unsigned int usb2_pins[] = { - /* PWEN, OVC */ - RCAR_GP_PIN(6, 14), RCAR_GP_PIN(6, 15), -}; -static const unsigned int usb2_mux[] = { - USB2_PWEN_MARK, USB2_OVC_MARK, -}; - -/* - USB30 ------------------------------------------------------------------ */ -static const unsigned int usb30_pins[] = { - /* PWEN, OVC */ - RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29), -}; -static const unsigned int usb30_mux[] = { - USB30_PWEN_MARK, USB30_OVC_MARK, -}; -/* - USB31 ------------------------------------------------------------------ */ -static const unsigned int usb31_pins[] = { - /* PWEN, OVC */ - RCAR_GP_PIN(6, 30), RCAR_GP_PIN(6, 31), -}; -static const unsigned int usb31_mux[] = { - USB31_PWEN_MARK, USB31_OVC_MARK, -}; - -/* - VIN4 ------------------------------------------------------------------- */ -static const unsigned int vin4_data18_a_pins[] = { - RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11), - RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13), - RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15), - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), - RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3), - RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), - RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), -}; -static const unsigned int vin4_data18_a_mux[] = { - VI4_DATA2_A_MARK, VI4_DATA3_A_MARK, - VI4_DATA4_A_MARK, VI4_DATA5_A_MARK, - VI4_DATA6_A_MARK, VI4_DATA7_A_MARK, - VI4_DATA10_MARK, VI4_DATA11_MARK, - VI4_DATA12_MARK, VI4_DATA13_MARK, - VI4_DATA14_MARK, VI4_DATA15_MARK, - VI4_DATA18_MARK, VI4_DATA19_MARK, - VI4_DATA20_MARK, VI4_DATA21_MARK, - VI4_DATA22_MARK, VI4_DATA23_MARK, -}; -static const unsigned int vin4_data18_b_pins[] = { - RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3), - RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), - RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), - RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3), - RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), - RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), -}; -static const unsigned int vin4_data18_b_mux[] = { - VI4_DATA2_B_MARK, VI4_DATA3_B_MARK, - VI4_DATA4_B_MARK, VI4_DATA5_B_MARK, - VI4_DATA6_B_MARK, VI4_DATA7_B_MARK, - VI4_DATA10_MARK, VI4_DATA11_MARK, - VI4_DATA12_MARK, VI4_DATA13_MARK, - VI4_DATA14_MARK, VI4_DATA15_MARK, - VI4_DATA18_MARK, VI4_DATA19_MARK, - VI4_DATA20_MARK, VI4_DATA21_MARK, - VI4_DATA22_MARK, VI4_DATA23_MARK, -}; -static const unsigned int vin4_data_a_pins[] = { - RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 9), - RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11), - RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13), - RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15), - RCAR_GP_PIN(1, 0), RCAR_GP_PIN(1, 1), - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), - RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1), - RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3), - RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), - RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), -}; -static const unsigned int vin4_data_a_mux[] = { - VI4_DATA0_A_MARK, VI4_DATA1_A_MARK, - VI4_DATA2_A_MARK, VI4_DATA3_A_MARK, - VI4_DATA4_A_MARK, VI4_DATA5_A_MARK, - VI4_DATA6_A_MARK, VI4_DATA7_A_MARK, - VI4_DATA8_MARK, VI4_DATA9_MARK, - VI4_DATA10_MARK, VI4_DATA11_MARK, - VI4_DATA12_MARK, VI4_DATA13_MARK, - VI4_DATA14_MARK, VI4_DATA15_MARK, - VI4_DATA16_MARK, VI4_DATA17_MARK, - VI4_DATA18_MARK, VI4_DATA19_MARK, - VI4_DATA20_MARK, VI4_DATA21_MARK, - VI4_DATA22_MARK, VI4_DATA23_MARK, -}; -static const unsigned int vin4_data_b_pins[] = { - RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), - RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3), - RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), - RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7), - RCAR_GP_PIN(1, 0), RCAR_GP_PIN(1, 1), - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), - RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1), - RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3), - RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), - RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), -}; -static const unsigned int vin4_data_b_mux[] = { - VI4_DATA0_B_MARK, VI4_DATA1_B_MARK, - VI4_DATA2_B_MARK, VI4_DATA3_B_MARK, - VI4_DATA4_B_MARK, VI4_DATA5_B_MARK, - VI4_DATA6_B_MARK, VI4_DATA7_B_MARK, - VI4_DATA8_MARK, VI4_DATA9_MARK, - VI4_DATA10_MARK, VI4_DATA11_MARK, - VI4_DATA12_MARK, VI4_DATA13_MARK, - VI4_DATA14_MARK, VI4_DATA15_MARK, - VI4_DATA16_MARK, VI4_DATA17_MARK, - VI4_DATA18_MARK, VI4_DATA19_MARK, - VI4_DATA20_MARK, VI4_DATA21_MARK, - VI4_DATA22_MARK, VI4_DATA23_MARK, -}; -static const unsigned int vin4_sync_pins[] = { - /* HSYNC#, VSYNC# */ - RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 17), -}; -static const unsigned int vin4_sync_mux[] = { - VI4_HSYNC_N_MARK, VI4_VSYNC_N_MARK, -}; -static const unsigned int vin4_field_pins[] = { - /* FIELD */ - RCAR_GP_PIN(1, 16), -}; -static const unsigned int vin4_field_mux[] = { - VI4_FIELD_MARK, -}; -static const unsigned int vin4_clkenb_pins[] = { - /* CLKENB */ - RCAR_GP_PIN(1, 19), -}; -static const unsigned int vin4_clkenb_mux[] = { - VI4_CLKENB_MARK, -}; -static const unsigned int vin4_clk_pins[] = { - /* CLK */ - RCAR_GP_PIN(1, 27), -}; -static const unsigned int vin4_clk_mux[] = { - VI4_CLK_MARK, -}; - -/* - VIN5 ------------------------------------------------------------------- */ -static const unsigned int vin5_data_pins[] = { - RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1), - RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3), - RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), - RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), - RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13), - RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 15), - RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5), - RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7), -}; -static const unsigned int vin5_data_mux[] = { - VI5_DATA0_MARK, VI5_DATA1_MARK, - VI5_DATA2_MARK, VI5_DATA3_MARK, - VI5_DATA4_MARK, VI5_DATA5_MARK, - VI5_DATA6_MARK, VI5_DATA7_MARK, - VI5_DATA8_MARK, VI5_DATA9_MARK, - VI5_DATA10_MARK, VI5_DATA11_MARK, - VI5_DATA12_MARK, VI5_DATA13_MARK, - VI5_DATA14_MARK, VI5_DATA15_MARK, -}; -static const unsigned int vin5_sync_pins[] = { - /* HSYNC#, VSYNC# */ - RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 9), -}; -static const unsigned int vin5_sync_mux[] = { - VI5_HSYNC_N_MARK, VI5_VSYNC_N_MARK, -}; -static const unsigned int vin5_field_pins[] = { - RCAR_GP_PIN(1, 11), -}; -static const unsigned int vin5_field_mux[] = { - /* FIELD */ - VI5_FIELD_MARK, -}; -static const unsigned int vin5_clkenb_pins[] = { - RCAR_GP_PIN(1, 20), -}; -static const unsigned int vin5_clkenb_mux[] = { - /* CLKENB */ - VI5_CLKENB_MARK, -}; -static const unsigned int vin5_clk_pins[] = { - RCAR_GP_PIN(1, 21), -}; -static const unsigned int vin5_clk_mux[] = { - /* CLK */ - VI5_CLK_MARK, -}; - -static const struct sh_pfc_pin_group pinmux_groups[] = { - SH_PFC_PIN_GROUP(audio_clk_a_a), - SH_PFC_PIN_GROUP(audio_clk_a_b), - SH_PFC_PIN_GROUP(audio_clk_a_c), - SH_PFC_PIN_GROUP(audio_clk_b_a), - SH_PFC_PIN_GROUP(audio_clk_b_b), - SH_PFC_PIN_GROUP(audio_clk_c_a), - SH_PFC_PIN_GROUP(audio_clk_c_b), - SH_PFC_PIN_GROUP(audio_clkout_a), - SH_PFC_PIN_GROUP(audio_clkout_b), - SH_PFC_PIN_GROUP(audio_clkout_c), - SH_PFC_PIN_GROUP(audio_clkout_d), - SH_PFC_PIN_GROUP(audio_clkout1_a), - SH_PFC_PIN_GROUP(audio_clkout1_b), - SH_PFC_PIN_GROUP(audio_clkout2_a), - SH_PFC_PIN_GROUP(audio_clkout2_b), - SH_PFC_PIN_GROUP(audio_clkout3_a), - SH_PFC_PIN_GROUP(audio_clkout3_b), - SH_PFC_PIN_GROUP(avb_link), - SH_PFC_PIN_GROUP(avb_magic), - SH_PFC_PIN_GROUP(avb_phy_int), - SH_PFC_PIN_GROUP_ALIAS(avb_mdc, avb_mdio), /* Deprecated */ - SH_PFC_PIN_GROUP(avb_mdio), - SH_PFC_PIN_GROUP(avb_mii), - SH_PFC_PIN_GROUP(avb_avtp_pps), - SH_PFC_PIN_GROUP(avb_avtp_match_a), - SH_PFC_PIN_GROUP(avb_avtp_capture_a), - SH_PFC_PIN_GROUP(avb_avtp_match_b), - SH_PFC_PIN_GROUP(avb_avtp_capture_b), - SH_PFC_PIN_GROUP(can0_data_a), - SH_PFC_PIN_GROUP(can0_data_b), - SH_PFC_PIN_GROUP(can1_data), - SH_PFC_PIN_GROUP(can_clk), - SH_PFC_PIN_GROUP(canfd0_data_a), - SH_PFC_PIN_GROUP(canfd0_data_b), - SH_PFC_PIN_GROUP(canfd1_data), - SH_PFC_PIN_GROUP(drif0_ctrl_a), - SH_PFC_PIN_GROUP(drif0_data0_a), - SH_PFC_PIN_GROUP(drif0_data1_a), - SH_PFC_PIN_GROUP(drif0_ctrl_b), - SH_PFC_PIN_GROUP(drif0_data0_b), - SH_PFC_PIN_GROUP(drif0_data1_b), - SH_PFC_PIN_GROUP(drif0_ctrl_c), - SH_PFC_PIN_GROUP(drif0_data0_c), - SH_PFC_PIN_GROUP(drif0_data1_c), - SH_PFC_PIN_GROUP(drif1_ctrl_a), - SH_PFC_PIN_GROUP(drif1_data0_a), - SH_PFC_PIN_GROUP(drif1_data1_a), - SH_PFC_PIN_GROUP(drif1_ctrl_b), - SH_PFC_PIN_GROUP(drif1_data0_b), - SH_PFC_PIN_GROUP(drif1_data1_b), - SH_PFC_PIN_GROUP(drif1_ctrl_c), - SH_PFC_PIN_GROUP(drif1_data0_c), - SH_PFC_PIN_GROUP(drif1_data1_c), - SH_PFC_PIN_GROUP(drif2_ctrl_a), - SH_PFC_PIN_GROUP(drif2_data0_a), - SH_PFC_PIN_GROUP(drif2_data1_a), - SH_PFC_PIN_GROUP(drif2_ctrl_b), - SH_PFC_PIN_GROUP(drif2_data0_b), - SH_PFC_PIN_GROUP(drif2_data1_b), - SH_PFC_PIN_GROUP(drif3_ctrl_a), - SH_PFC_PIN_GROUP(drif3_data0_a), - SH_PFC_PIN_GROUP(drif3_data1_a), - SH_PFC_PIN_GROUP(drif3_ctrl_b), - SH_PFC_PIN_GROUP(drif3_data0_b), - SH_PFC_PIN_GROUP(drif3_data1_b), - SH_PFC_PIN_GROUP(du_rgb666), - SH_PFC_PIN_GROUP(du_rgb888), - SH_PFC_PIN_GROUP(du_clk_out_0), - SH_PFC_PIN_GROUP(du_clk_out_1), - SH_PFC_PIN_GROUP(du_sync), - SH_PFC_PIN_GROUP(du_oddf), - SH_PFC_PIN_GROUP(du_cde), - SH_PFC_PIN_GROUP(du_disp), - SH_PFC_PIN_GROUP(hscif0_data), - SH_PFC_PIN_GROUP(hscif0_clk), - SH_PFC_PIN_GROUP(hscif0_ctrl), - SH_PFC_PIN_GROUP(hscif1_data_a), - SH_PFC_PIN_GROUP(hscif1_clk_a), - SH_PFC_PIN_GROUP(hscif1_ctrl_a), - SH_PFC_PIN_GROUP(hscif1_data_b), - SH_PFC_PIN_GROUP(hscif1_clk_b), - SH_PFC_PIN_GROUP(hscif1_ctrl_b), - SH_PFC_PIN_GROUP(hscif2_data_a), - SH_PFC_PIN_GROUP(hscif2_clk_a), - SH_PFC_PIN_GROUP(hscif2_ctrl_a), - SH_PFC_PIN_GROUP(hscif2_data_b), - SH_PFC_PIN_GROUP(hscif2_clk_b), - SH_PFC_PIN_GROUP(hscif2_ctrl_b), - SH_PFC_PIN_GROUP(hscif3_data_a), - SH_PFC_PIN_GROUP(hscif3_clk), - SH_PFC_PIN_GROUP(hscif3_ctrl), - SH_PFC_PIN_GROUP(hscif3_data_b), - SH_PFC_PIN_GROUP(hscif3_data_c), - SH_PFC_PIN_GROUP(hscif3_data_d), - SH_PFC_PIN_GROUP(hscif4_data_a), - SH_PFC_PIN_GROUP(hscif4_clk), - SH_PFC_PIN_GROUP(hscif4_ctrl), - SH_PFC_PIN_GROUP(hscif4_data_b), - SH_PFC_PIN_GROUP(i2c0), - SH_PFC_PIN_GROUP(i2c1_a), - SH_PFC_PIN_GROUP(i2c1_b), - SH_PFC_PIN_GROUP(i2c2_a), - SH_PFC_PIN_GROUP(i2c2_b), - SH_PFC_PIN_GROUP(i2c3), - SH_PFC_PIN_GROUP(i2c5), - SH_PFC_PIN_GROUP(i2c6_a), - SH_PFC_PIN_GROUP(i2c6_b), - SH_PFC_PIN_GROUP(i2c6_c), - SH_PFC_PIN_GROUP(intc_ex_irq0), - SH_PFC_PIN_GROUP(intc_ex_irq1), - SH_PFC_PIN_GROUP(intc_ex_irq2), - SH_PFC_PIN_GROUP(intc_ex_irq3), - SH_PFC_PIN_GROUP(intc_ex_irq4), - SH_PFC_PIN_GROUP(intc_ex_irq5), - SH_PFC_PIN_GROUP(mlb_3pin), - 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_a), - SH_PFC_PIN_GROUP(msiof1_sync_a), - SH_PFC_PIN_GROUP(msiof1_ss1_a), - SH_PFC_PIN_GROUP(msiof1_ss2_a), - SH_PFC_PIN_GROUP(msiof1_txd_a), - SH_PFC_PIN_GROUP(msiof1_rxd_a), - SH_PFC_PIN_GROUP(msiof1_clk_b), - SH_PFC_PIN_GROUP(msiof1_sync_b), - SH_PFC_PIN_GROUP(msiof1_ss1_b), - SH_PFC_PIN_GROUP(msiof1_ss2_b), - SH_PFC_PIN_GROUP(msiof1_txd_b), - SH_PFC_PIN_GROUP(msiof1_rxd_b), - SH_PFC_PIN_GROUP(msiof1_clk_c), - SH_PFC_PIN_GROUP(msiof1_sync_c), - SH_PFC_PIN_GROUP(msiof1_ss1_c), - SH_PFC_PIN_GROUP(msiof1_ss2_c), - SH_PFC_PIN_GROUP(msiof1_txd_c), - SH_PFC_PIN_GROUP(msiof1_rxd_c), - SH_PFC_PIN_GROUP(msiof1_clk_d), - SH_PFC_PIN_GROUP(msiof1_sync_d), - SH_PFC_PIN_GROUP(msiof1_ss1_d), - SH_PFC_PIN_GROUP(msiof1_ss2_d), - SH_PFC_PIN_GROUP(msiof1_txd_d), - SH_PFC_PIN_GROUP(msiof1_rxd_d), - SH_PFC_PIN_GROUP(msiof1_clk_e), - SH_PFC_PIN_GROUP(msiof1_sync_e), - SH_PFC_PIN_GROUP(msiof1_ss1_e), - SH_PFC_PIN_GROUP(msiof1_ss2_e), - SH_PFC_PIN_GROUP(msiof1_txd_e), - SH_PFC_PIN_GROUP(msiof1_rxd_e), - SH_PFC_PIN_GROUP(msiof1_clk_f), - SH_PFC_PIN_GROUP(msiof1_sync_f), - SH_PFC_PIN_GROUP(msiof1_ss1_f), - SH_PFC_PIN_GROUP(msiof1_ss2_f), - SH_PFC_PIN_GROUP(msiof1_txd_f), - SH_PFC_PIN_GROUP(msiof1_rxd_f), - SH_PFC_PIN_GROUP(msiof1_clk_g), - SH_PFC_PIN_GROUP(msiof1_sync_g), - SH_PFC_PIN_GROUP(msiof1_ss1_g), - SH_PFC_PIN_GROUP(msiof1_ss2_g), - SH_PFC_PIN_GROUP(msiof1_txd_g), - SH_PFC_PIN_GROUP(msiof1_rxd_g), - SH_PFC_PIN_GROUP(msiof2_clk_a), - SH_PFC_PIN_GROUP(msiof2_sync_a), - SH_PFC_PIN_GROUP(msiof2_ss1_a), - SH_PFC_PIN_GROUP(msiof2_ss2_a), - SH_PFC_PIN_GROUP(msiof2_txd_a), - SH_PFC_PIN_GROUP(msiof2_rxd_a), - SH_PFC_PIN_GROUP(msiof2_clk_b), - SH_PFC_PIN_GROUP(msiof2_sync_b), - SH_PFC_PIN_GROUP(msiof2_ss1_b), - SH_PFC_PIN_GROUP(msiof2_ss2_b), - SH_PFC_PIN_GROUP(msiof2_txd_b), - SH_PFC_PIN_GROUP(msiof2_rxd_b), - SH_PFC_PIN_GROUP(msiof2_clk_c), - SH_PFC_PIN_GROUP(msiof2_sync_c), - SH_PFC_PIN_GROUP(msiof2_ss1_c), - SH_PFC_PIN_GROUP(msiof2_ss2_c), - SH_PFC_PIN_GROUP(msiof2_txd_c), - SH_PFC_PIN_GROUP(msiof2_rxd_c), - SH_PFC_PIN_GROUP(msiof2_clk_d), - SH_PFC_PIN_GROUP(msiof2_sync_d), - SH_PFC_PIN_GROUP(msiof2_ss1_d), - SH_PFC_PIN_GROUP(msiof2_ss2_d), - SH_PFC_PIN_GROUP(msiof2_txd_d), - SH_PFC_PIN_GROUP(msiof2_rxd_d), - SH_PFC_PIN_GROUP(msiof3_clk_a), - SH_PFC_PIN_GROUP(msiof3_sync_a), - SH_PFC_PIN_GROUP(msiof3_ss1_a), - SH_PFC_PIN_GROUP(msiof3_ss2_a), - SH_PFC_PIN_GROUP(msiof3_txd_a), - SH_PFC_PIN_GROUP(msiof3_rxd_a), - SH_PFC_PIN_GROUP(msiof3_clk_b), - SH_PFC_PIN_GROUP(msiof3_sync_b), - SH_PFC_PIN_GROUP(msiof3_ss1_b), - SH_PFC_PIN_GROUP(msiof3_ss2_b), - SH_PFC_PIN_GROUP(msiof3_txd_b), - SH_PFC_PIN_GROUP(msiof3_rxd_b), - SH_PFC_PIN_GROUP(msiof3_clk_c), - SH_PFC_PIN_GROUP(msiof3_sync_c), - SH_PFC_PIN_GROUP(msiof3_txd_c), - SH_PFC_PIN_GROUP(msiof3_rxd_c), - SH_PFC_PIN_GROUP(msiof3_clk_d), - SH_PFC_PIN_GROUP(msiof3_sync_d), - SH_PFC_PIN_GROUP(msiof3_ss1_d), - SH_PFC_PIN_GROUP(msiof3_txd_d), - SH_PFC_PIN_GROUP(msiof3_rxd_d), - SH_PFC_PIN_GROUP(pwm0), - SH_PFC_PIN_GROUP(pwm1_a), - SH_PFC_PIN_GROUP(pwm1_b), - SH_PFC_PIN_GROUP(pwm2_a), - SH_PFC_PIN_GROUP(pwm2_b), - SH_PFC_PIN_GROUP(pwm3_a), - SH_PFC_PIN_GROUP(pwm3_b), - SH_PFC_PIN_GROUP(pwm4_a), - SH_PFC_PIN_GROUP(pwm4_b), - SH_PFC_PIN_GROUP(pwm5_a), - SH_PFC_PIN_GROUP(pwm5_b), - SH_PFC_PIN_GROUP(pwm6_a), - SH_PFC_PIN_GROUP(pwm6_b), - 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(sata0_devslp_a), - SH_PFC_PIN_GROUP(sata0_devslp_b), - SH_PFC_PIN_GROUP(scif0_data), - SH_PFC_PIN_GROUP(scif0_clk), - SH_PFC_PIN_GROUP(scif0_ctrl), - SH_PFC_PIN_GROUP(scif1_data_a), - SH_PFC_PIN_GROUP(scif1_clk), - SH_PFC_PIN_GROUP(scif1_ctrl), - SH_PFC_PIN_GROUP(scif1_data_b), - SH_PFC_PIN_GROUP(scif2_data_a), - SH_PFC_PIN_GROUP(scif2_clk), - SH_PFC_PIN_GROUP(scif2_data_b), - SH_PFC_PIN_GROUP(scif3_data_a), - SH_PFC_PIN_GROUP(scif3_clk), - SH_PFC_PIN_GROUP(scif3_ctrl), - SH_PFC_PIN_GROUP(scif3_data_b), - SH_PFC_PIN_GROUP(scif4_data_a), - SH_PFC_PIN_GROUP(scif4_clk_a), - SH_PFC_PIN_GROUP(scif4_ctrl_a), - SH_PFC_PIN_GROUP(scif4_data_b), - SH_PFC_PIN_GROUP(scif4_clk_b), - SH_PFC_PIN_GROUP(scif4_ctrl_b), - SH_PFC_PIN_GROUP(scif4_data_c), - SH_PFC_PIN_GROUP(scif4_clk_c), - SH_PFC_PIN_GROUP(scif4_ctrl_c), - SH_PFC_PIN_GROUP(scif5_data), - SH_PFC_PIN_GROUP(scif5_clk), - SH_PFC_PIN_GROUP(scif_clk_a), - SH_PFC_PIN_GROUP(scif_clk_b), - BUS_DATA_PIN_GROUP(sdhi0_data, 1), - BUS_DATA_PIN_GROUP(sdhi0_data, 4), - SH_PFC_PIN_GROUP(sdhi0_ctrl), - SH_PFC_PIN_GROUP(sdhi0_cd), - SH_PFC_PIN_GROUP(sdhi0_wp), - BUS_DATA_PIN_GROUP(sdhi1_data, 1), - BUS_DATA_PIN_GROUP(sdhi1_data, 4), - SH_PFC_PIN_GROUP(sdhi1_ctrl), - SH_PFC_PIN_GROUP(sdhi1_cd), - SH_PFC_PIN_GROUP(sdhi1_wp), - BUS_DATA_PIN_GROUP(sdhi2_data, 1), - BUS_DATA_PIN_GROUP(sdhi2_data, 4), - BUS_DATA_PIN_GROUP(sdhi2_data, 8), - SH_PFC_PIN_GROUP(sdhi2_ctrl), - SH_PFC_PIN_GROUP(sdhi2_cd_a), - SH_PFC_PIN_GROUP(sdhi2_wp_a), - SH_PFC_PIN_GROUP(sdhi2_cd_b), - SH_PFC_PIN_GROUP(sdhi2_wp_b), - SH_PFC_PIN_GROUP(sdhi2_ds), - BUS_DATA_PIN_GROUP(sdhi3_data, 1), - BUS_DATA_PIN_GROUP(sdhi3_data, 4), - BUS_DATA_PIN_GROUP(sdhi3_data, 8), - SH_PFC_PIN_GROUP(sdhi3_ctrl), - SH_PFC_PIN_GROUP(sdhi3_cd), - SH_PFC_PIN_GROUP(sdhi3_wp), - SH_PFC_PIN_GROUP(sdhi3_ds), - SH_PFC_PIN_GROUP(ssi0_data), - SH_PFC_PIN_GROUP(ssi01239_ctrl), - SH_PFC_PIN_GROUP(ssi1_data_a), - SH_PFC_PIN_GROUP(ssi1_data_b), - SH_PFC_PIN_GROUP(ssi1_ctrl_a), - SH_PFC_PIN_GROUP(ssi1_ctrl_b), - SH_PFC_PIN_GROUP(ssi2_data_a), - SH_PFC_PIN_GROUP(ssi2_data_b), - SH_PFC_PIN_GROUP(ssi2_ctrl_a), - SH_PFC_PIN_GROUP(ssi2_ctrl_b), - SH_PFC_PIN_GROUP(ssi3_data), - SH_PFC_PIN_GROUP(ssi349_ctrl), - SH_PFC_PIN_GROUP(ssi4_data), - SH_PFC_PIN_GROUP(ssi4_ctrl), - SH_PFC_PIN_GROUP(ssi5_data), - SH_PFC_PIN_GROUP(ssi5_ctrl), - SH_PFC_PIN_GROUP(ssi6_data), - SH_PFC_PIN_GROUP(ssi6_ctrl), - SH_PFC_PIN_GROUP(ssi7_data), - SH_PFC_PIN_GROUP(ssi78_ctrl), - SH_PFC_PIN_GROUP(ssi8_data), - SH_PFC_PIN_GROUP(ssi9_data_a), - SH_PFC_PIN_GROUP(ssi9_data_b), - SH_PFC_PIN_GROUP(ssi9_ctrl_a), - SH_PFC_PIN_GROUP(ssi9_ctrl_b), - SH_PFC_PIN_GROUP(tmu_tclk1_a), - SH_PFC_PIN_GROUP(tmu_tclk1_b), - SH_PFC_PIN_GROUP(tmu_tclk2_a), - SH_PFC_PIN_GROUP(tmu_tclk2_b), - SH_PFC_PIN_GROUP(tpu_to0), - SH_PFC_PIN_GROUP(tpu_to1), - SH_PFC_PIN_GROUP(tpu_to2), - SH_PFC_PIN_GROUP(tpu_to3), - SH_PFC_PIN_GROUP(usb0), - SH_PFC_PIN_GROUP(usb1), - SH_PFC_PIN_GROUP(usb2), - SH_PFC_PIN_GROUP(usb30), - SH_PFC_PIN_GROUP(usb31), - BUS_DATA_PIN_GROUP(vin4_data, 8, _a), - BUS_DATA_PIN_GROUP(vin4_data, 10, _a), - BUS_DATA_PIN_GROUP(vin4_data, 12, _a), - BUS_DATA_PIN_GROUP(vin4_data, 16, _a), - SH_PFC_PIN_GROUP(vin4_data18_a), - BUS_DATA_PIN_GROUP(vin4_data, 20, _a), - BUS_DATA_PIN_GROUP(vin4_data, 24, _a), - BUS_DATA_PIN_GROUP(vin4_data, 8, _b), - BUS_DATA_PIN_GROUP(vin4_data, 10, _b), - BUS_DATA_PIN_GROUP(vin4_data, 12, _b), - BUS_DATA_PIN_GROUP(vin4_data, 16, _b), - SH_PFC_PIN_GROUP(vin4_data18_b), - BUS_DATA_PIN_GROUP(vin4_data, 20, _b), - BUS_DATA_PIN_GROUP(vin4_data, 24, _b), - SH_PFC_PIN_GROUP_SUBSET(vin4_g8, vin4_data_a, 8, 8), - SH_PFC_PIN_GROUP(vin4_sync), - SH_PFC_PIN_GROUP(vin4_field), - SH_PFC_PIN_GROUP(vin4_clkenb), - SH_PFC_PIN_GROUP(vin4_clk), - BUS_DATA_PIN_GROUP(vin5_data, 8), - BUS_DATA_PIN_GROUP(vin5_data, 10), - BUS_DATA_PIN_GROUP(vin5_data, 12), - BUS_DATA_PIN_GROUP(vin5_data, 16), - SH_PFC_PIN_GROUP_SUBSET(vin5_high8, vin5_data, 8, 8), - SH_PFC_PIN_GROUP(vin5_sync), - SH_PFC_PIN_GROUP(vin5_field), - SH_PFC_PIN_GROUP(vin5_clkenb), - SH_PFC_PIN_GROUP(vin5_clk), -}; - -static const char * const audio_clk_groups[] = { - "audio_clk_a_a", - "audio_clk_a_b", - "audio_clk_a_c", - "audio_clk_b_a", - "audio_clk_b_b", - "audio_clk_c_a", - "audio_clk_c_b", - "audio_clkout_a", - "audio_clkout_b", - "audio_clkout_c", - "audio_clkout_d", - "audio_clkout1_a", - "audio_clkout1_b", - "audio_clkout2_a", - "audio_clkout2_b", - "audio_clkout3_a", - "audio_clkout3_b", -}; - -static const char * const avb_groups[] = { - "avb_link", - "avb_magic", - "avb_phy_int", - "avb_mdc", /* Deprecated, please use "avb_mdio" instead */ - "avb_mdio", - "avb_mii", - "avb_avtp_pps", - "avb_avtp_match_a", - "avb_avtp_capture_a", - "avb_avtp_match_b", - "avb_avtp_capture_b", -}; - -static const char * const can0_groups[] = { - "can0_data_a", - "can0_data_b", -}; - -static const char * const can1_groups[] = { - "can1_data", -}; - -static const char * const can_clk_groups[] = { - "can_clk", -}; - -static const char * const canfd0_groups[] = { - "canfd0_data_a", - "canfd0_data_b", -}; - -static const char * const canfd1_groups[] = { - "canfd1_data", -}; - -static const char * const drif0_groups[] = { - "drif0_ctrl_a", - "drif0_data0_a", - "drif0_data1_a", - "drif0_ctrl_b", - "drif0_data0_b", - "drif0_data1_b", - "drif0_ctrl_c", - "drif0_data0_c", - "drif0_data1_c", -}; - -static const char * const drif1_groups[] = { - "drif1_ctrl_a", - "drif1_data0_a", - "drif1_data1_a", - "drif1_ctrl_b", - "drif1_data0_b", - "drif1_data1_b", - "drif1_ctrl_c", - "drif1_data0_c", - "drif1_data1_c", -}; - -static const char * const drif2_groups[] = { - "drif2_ctrl_a", - "drif2_data0_a", - "drif2_data1_a", - "drif2_ctrl_b", - "drif2_data0_b", - "drif2_data1_b", -}; - -static const char * const drif3_groups[] = { - "drif3_ctrl_a", - "drif3_data0_a", - "drif3_data1_a", - "drif3_ctrl_b", - "drif3_data0_b", - "drif3_data1_b", -}; - -static const char * const du_groups[] = { - "du_rgb666", - "du_rgb888", - "du_clk_out_0", - "du_clk_out_1", - "du_sync", - "du_oddf", - "du_cde", - "du_disp", -}; - -static const char * const hscif0_groups[] = { - "hscif0_data", - "hscif0_clk", - "hscif0_ctrl", -}; - -static const char * const hscif1_groups[] = { - "hscif1_data_a", - "hscif1_clk_a", - "hscif1_ctrl_a", - "hscif1_data_b", - "hscif1_clk_b", - "hscif1_ctrl_b", -}; - -static const char * const hscif2_groups[] = { - "hscif2_data_a", - "hscif2_clk_a", - "hscif2_ctrl_a", - "hscif2_data_b", - "hscif2_clk_b", - "hscif2_ctrl_b", -}; - -static const char * const hscif3_groups[] = { - "hscif3_data_a", - "hscif3_clk", - "hscif3_ctrl", - "hscif3_data_b", - "hscif3_data_c", - "hscif3_data_d", -}; - -static const char * const hscif4_groups[] = { - "hscif4_data_a", - "hscif4_clk", - "hscif4_ctrl", - "hscif4_data_b", -}; - -static const char * const i2c0_groups[] = { - "i2c0", -}; - -static const char * const i2c1_groups[] = { - "i2c1_a", - "i2c1_b", -}; - -static const char * const i2c2_groups[] = { - "i2c2_a", - "i2c2_b", -}; - -static const char * const i2c3_groups[] = { - "i2c3", -}; - -static const char * const i2c5_groups[] = { - "i2c5", -}; - -static const char * const i2c6_groups[] = { - "i2c6_a", - "i2c6_b", - "i2c6_c", -}; - -static const char * const intc_ex_groups[] = { - "intc_ex_irq0", - "intc_ex_irq1", - "intc_ex_irq2", - "intc_ex_irq3", - "intc_ex_irq4", - "intc_ex_irq5", -}; - -static const char * const mlb_3pin_groups[] = { - "mlb_3pin", -}; - -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_a", - "msiof1_sync_a", - "msiof1_ss1_a", - "msiof1_ss2_a", - "msiof1_txd_a", - "msiof1_rxd_a", - "msiof1_clk_b", - "msiof1_sync_b", - "msiof1_ss1_b", - "msiof1_ss2_b", - "msiof1_txd_b", - "msiof1_rxd_b", - "msiof1_clk_c", - "msiof1_sync_c", - "msiof1_ss1_c", - "msiof1_ss2_c", - "msiof1_txd_c", - "msiof1_rxd_c", - "msiof1_clk_d", - "msiof1_sync_d", - "msiof1_ss1_d", - "msiof1_ss2_d", - "msiof1_txd_d", - "msiof1_rxd_d", - "msiof1_clk_e", - "msiof1_sync_e", - "msiof1_ss1_e", - "msiof1_ss2_e", - "msiof1_txd_e", - "msiof1_rxd_e", - "msiof1_clk_f", - "msiof1_sync_f", - "msiof1_ss1_f", - "msiof1_ss2_f", - "msiof1_txd_f", - "msiof1_rxd_f", - "msiof1_clk_g", - "msiof1_sync_g", - "msiof1_ss1_g", - "msiof1_ss2_g", - "msiof1_txd_g", - "msiof1_rxd_g", -}; - -static const char * const msiof2_groups[] = { - "msiof2_clk_a", - "msiof2_sync_a", - "msiof2_ss1_a", - "msiof2_ss2_a", - "msiof2_txd_a", - "msiof2_rxd_a", - "msiof2_clk_b", - "msiof2_sync_b", - "msiof2_ss1_b", - "msiof2_ss2_b", - "msiof2_txd_b", - "msiof2_rxd_b", - "msiof2_clk_c", - "msiof2_sync_c", - "msiof2_ss1_c", - "msiof2_ss2_c", - "msiof2_txd_c", - "msiof2_rxd_c", - "msiof2_clk_d", - "msiof2_sync_d", - "msiof2_ss1_d", - "msiof2_ss2_d", - "msiof2_txd_d", - "msiof2_rxd_d", -}; - -static const char * const msiof3_groups[] = { - "msiof3_clk_a", - "msiof3_sync_a", - "msiof3_ss1_a", - "msiof3_ss2_a", - "msiof3_txd_a", - "msiof3_rxd_a", - "msiof3_clk_b", - "msiof3_sync_b", - "msiof3_ss1_b", - "msiof3_ss2_b", - "msiof3_txd_b", - "msiof3_rxd_b", - "msiof3_clk_c", - "msiof3_sync_c", - "msiof3_txd_c", - "msiof3_rxd_c", - "msiof3_clk_d", - "msiof3_sync_d", - "msiof3_ss1_d", - "msiof3_txd_d", - "msiof3_rxd_d", -}; - -static const char * const pwm0_groups[] = { - "pwm0", -}; - -static const char * const pwm1_groups[] = { - "pwm1_a", - "pwm1_b", -}; - -static const char * const pwm2_groups[] = { - "pwm2_a", - "pwm2_b", -}; - -static const char * const pwm3_groups[] = { - "pwm3_a", - "pwm3_b", -}; - -static const char * const pwm4_groups[] = { - "pwm4_a", - "pwm4_b", -}; - -static const char * const pwm5_groups[] = { - "pwm5_a", - "pwm5_b", -}; - -static const char * const pwm6_groups[] = { - "pwm6_a", - "pwm6_b", -}; - -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 sata0_groups[] = { - "sata0_devslp_a", - "sata0_devslp_b", -}; - -static const char * const scif0_groups[] = { - "scif0_data", - "scif0_clk", - "scif0_ctrl", -}; - -static const char * const scif1_groups[] = { - "scif1_data_a", - "scif1_clk", - "scif1_ctrl", - "scif1_data_b", -}; - -static const char * const scif2_groups[] = { - "scif2_data_a", - "scif2_clk", - "scif2_data_b", -}; - -static const char * const scif3_groups[] = { - "scif3_data_a", - "scif3_clk", - "scif3_ctrl", - "scif3_data_b", -}; - -static const char * const scif4_groups[] = { - "scif4_data_a", - "scif4_clk_a", - "scif4_ctrl_a", - "scif4_data_b", - "scif4_clk_b", - "scif4_ctrl_b", - "scif4_data_c", - "scif4_clk_c", - "scif4_ctrl_c", -}; - -static const char * const scif5_groups[] = { - "scif5_data", - "scif5_clk", -}; - -static const char * const scif_clk_groups[] = { - "scif_clk_a", - "scif_clk_b", -}; - -static const char * const sdhi0_groups[] = { - "sdhi0_data1", - "sdhi0_data4", - "sdhi0_ctrl", - "sdhi0_cd", - "sdhi0_wp", -}; - -static const char * const sdhi1_groups[] = { - "sdhi1_data1", - "sdhi1_data4", - "sdhi1_ctrl", - "sdhi1_cd", - "sdhi1_wp", -}; - -static const char * const sdhi2_groups[] = { - "sdhi2_data1", - "sdhi2_data4", - "sdhi2_data8", - "sdhi2_ctrl", - "sdhi2_cd_a", - "sdhi2_wp_a", - "sdhi2_cd_b", - "sdhi2_wp_b", - "sdhi2_ds", -}; - -static const char * const sdhi3_groups[] = { - "sdhi3_data1", - "sdhi3_data4", - "sdhi3_data8", - "sdhi3_ctrl", - "sdhi3_cd", - "sdhi3_wp", - "sdhi3_ds", -}; - -static const char * const ssi_groups[] = { - "ssi0_data", - "ssi01239_ctrl", - "ssi1_data_a", - "ssi1_data_b", - "ssi1_ctrl_a", - "ssi1_ctrl_b", - "ssi2_data_a", - "ssi2_data_b", - "ssi2_ctrl_a", - "ssi2_ctrl_b", - "ssi3_data", - "ssi349_ctrl", - "ssi4_data", - "ssi4_ctrl", - "ssi5_data", - "ssi5_ctrl", - "ssi6_data", - "ssi6_ctrl", - "ssi7_data", - "ssi78_ctrl", - "ssi8_data", - "ssi9_data_a", - "ssi9_data_b", - "ssi9_ctrl_a", - "ssi9_ctrl_b", -}; - -static const char * const tmu_groups[] = { - "tmu_tclk1_a", - "tmu_tclk1_b", - "tmu_tclk2_a", - "tmu_tclk2_b", -}; - -static const char * const tpu_groups[] = { - "tpu_to0", - "tpu_to1", - "tpu_to2", - "tpu_to3", -}; - -static const char * const usb0_groups[] = { - "usb0", -}; - -static const char * const usb1_groups[] = { - "usb1", -}; - -static const char * const usb2_groups[] = { - "usb2", -}; - -static const char * const usb30_groups[] = { - "usb30", -}; - -static const char * const usb31_groups[] = { - "usb31", -}; - -static const char * const vin4_groups[] = { - "vin4_data8_a", - "vin4_data10_a", - "vin4_data12_a", - "vin4_data16_a", - "vin4_data18_a", - "vin4_data20_a", - "vin4_data24_a", - "vin4_data8_b", - "vin4_data10_b", - "vin4_data12_b", - "vin4_data16_b", - "vin4_data18_b", - "vin4_data20_b", - "vin4_data24_b", - "vin4_g8", - "vin4_sync", - "vin4_field", - "vin4_clkenb", - "vin4_clk", -}; - -static const char * const vin5_groups[] = { - "vin5_data8", - "vin5_data10", - "vin5_data12", - "vin5_data16", - "vin5_high8", - "vin5_sync", - "vin5_field", - "vin5_clkenb", - "vin5_clk", -}; - -static const struct sh_pfc_function pinmux_functions[] = { - SH_PFC_FUNCTION(audio_clk), - SH_PFC_FUNCTION(avb), - SH_PFC_FUNCTION(can0), - SH_PFC_FUNCTION(can1), - SH_PFC_FUNCTION(can_clk), - SH_PFC_FUNCTION(canfd0), - SH_PFC_FUNCTION(canfd1), - SH_PFC_FUNCTION(drif0), - SH_PFC_FUNCTION(drif1), - SH_PFC_FUNCTION(drif2), - SH_PFC_FUNCTION(drif3), - SH_PFC_FUNCTION(du), - SH_PFC_FUNCTION(hscif0), - SH_PFC_FUNCTION(hscif1), - SH_PFC_FUNCTION(hscif2), - SH_PFC_FUNCTION(hscif3), - SH_PFC_FUNCTION(hscif4), - SH_PFC_FUNCTION(i2c0), - SH_PFC_FUNCTION(i2c1), - SH_PFC_FUNCTION(i2c2), - SH_PFC_FUNCTION(i2c3), - SH_PFC_FUNCTION(i2c5), - SH_PFC_FUNCTION(i2c6), - SH_PFC_FUNCTION(intc_ex), - SH_PFC_FUNCTION(mlb_3pin), - SH_PFC_FUNCTION(msiof0), - SH_PFC_FUNCTION(msiof1), - SH_PFC_FUNCTION(msiof2), - SH_PFC_FUNCTION(msiof3), - 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(qspi0), - SH_PFC_FUNCTION(qspi1), - SH_PFC_FUNCTION(sata0), - SH_PFC_FUNCTION(scif0), - SH_PFC_FUNCTION(scif1), - SH_PFC_FUNCTION(scif2), - SH_PFC_FUNCTION(scif3), - SH_PFC_FUNCTION(scif4), - SH_PFC_FUNCTION(scif5), - SH_PFC_FUNCTION(scif_clk), - SH_PFC_FUNCTION(sdhi0), - SH_PFC_FUNCTION(sdhi1), - SH_PFC_FUNCTION(sdhi2), - SH_PFC_FUNCTION(sdhi3), - SH_PFC_FUNCTION(ssi), - SH_PFC_FUNCTION(tmu), - SH_PFC_FUNCTION(tpu), - SH_PFC_FUNCTION(usb0), - SH_PFC_FUNCTION(usb1), - SH_PFC_FUNCTION(usb2), - SH_PFC_FUNCTION(usb30), - SH_PFC_FUNCTION(usb31), - SH_PFC_FUNCTION(vin4), - SH_PFC_FUNCTION(vin5), -}; - -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", 0xe6060100, 32, - GROUP(-16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1), - GROUP( - /* GP0_31_16 RESERVED */ - 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", 0xe6060104, 32, 1, GROUP( - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 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", 0xe6060108, 32, - GROUP(-17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1), - GROUP( - /* GP2_31_15 RESERVED */ - 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_VAR("GPSR3", 0xe606010c, 32, - GROUP(-16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1), - GROUP( - /* GP3_31_16 RESERVED */ - 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_VAR("GPSR4", 0xe6060110, 32, - GROUP(-14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1), - GROUP( - /* GP4_31_18 RESERVED */ - 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("GPSR5", 0xe6060114, 32, 1, GROUP( - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0, - GP_5_25_FN, GPSR5_25, - GP_5_24_FN, GPSR5_24, - GP_5_23_FN, GPSR5_23, - GP_5_22_FN, GPSR5_22, - GP_5_21_FN, GPSR5_21, - 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("GPSR6", 0xe6060118, 32, 1, GROUP( - GP_6_31_FN, GPSR6_31, - GP_6_30_FN, GPSR6_30, - GP_6_29_FN, GPSR6_29, - GP_6_28_FN, GPSR6_28, - GP_6_27_FN, GPSR6_27, - GP_6_26_FN, GPSR6_26, - GP_6_25_FN, GPSR6_25, - GP_6_24_FN, GPSR6_24, - GP_6_23_FN, GPSR6_23, - GP_6_22_FN, GPSR6_22, - GP_6_21_FN, GPSR6_21, - 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", 0xe606011c, 32, - GROUP(-28, 1, 1, 1, 1), - GROUP( - /* GP7_31_4 RESERVED */ - GP_7_3_FN, GPSR7_3, - GP_7_2_FN, GPSR7_2, - GP_7_1_FN, GPSR7_1, - GP_7_0_FN, GPSR7_0, )) - }, -#undef F_ -#undef FM - -#define F_(x, y) x, -#define FM(x) FN_##x, - { PINMUX_CFG_REG("IPSR0", 0xe6060200, 32, 4, GROUP( - IP0_31_28 - IP0_27_24 - IP0_23_20 - IP0_19_16 - IP0_15_12 - IP0_11_8 - IP0_7_4 - IP0_3_0 )) - }, - { PINMUX_CFG_REG("IPSR1", 0xe6060204, 32, 4, GROUP( - IP1_31_28 - IP1_27_24 - IP1_23_20 - IP1_19_16 - IP1_15_12 - IP1_11_8 - IP1_7_4 - IP1_3_0 )) - }, - { PINMUX_CFG_REG("IPSR2", 0xe6060208, 32, 4, GROUP( - IP2_31_28 - IP2_27_24 - IP2_23_20 - IP2_19_16 - IP2_15_12 - IP2_11_8 - IP2_7_4 - IP2_3_0 )) - }, - { PINMUX_CFG_REG("IPSR3", 0xe606020c, 32, 4, GROUP( - IP3_31_28 - IP3_27_24 - IP3_23_20 - IP3_19_16 - IP3_15_12 - IP3_11_8 - IP3_7_4 - IP3_3_0 )) - }, - { PINMUX_CFG_REG("IPSR4", 0xe6060210, 32, 4, GROUP( - IP4_31_28 - IP4_27_24 - IP4_23_20 - IP4_19_16 - IP4_15_12 - IP4_11_8 - IP4_7_4 - IP4_3_0 )) - }, - { PINMUX_CFG_REG("IPSR5", 0xe6060214, 32, 4, GROUP( - IP5_31_28 - IP5_27_24 - IP5_23_20 - IP5_19_16 - IP5_15_12 - IP5_11_8 - IP5_7_4 - IP5_3_0 )) - }, - { PINMUX_CFG_REG("IPSR6", 0xe6060218, 32, 4, GROUP( - IP6_31_28 - IP6_27_24 - IP6_23_20 - IP6_19_16 - IP6_15_12 - IP6_11_8 - IP6_7_4 - IP6_3_0 )) - }, - { PINMUX_CFG_REG("IPSR7", 0xe606021c, 32, 4, GROUP( - IP7_31_28 - IP7_27_24 - IP7_23_20 - IP7_19_16 - IP7_15_12 - IP7_11_8 - IP7_7_4 - IP7_3_0 )) - }, - { PINMUX_CFG_REG("IPSR8", 0xe6060220, 32, 4, GROUP( - IP8_31_28 - IP8_27_24 - IP8_23_20 - IP8_19_16 - IP8_15_12 - IP8_11_8 - IP8_7_4 - IP8_3_0 )) - }, - { PINMUX_CFG_REG("IPSR9", 0xe6060224, 32, 4, GROUP( - IP9_31_28 - IP9_27_24 - IP9_23_20 - IP9_19_16 - IP9_15_12 - IP9_11_8 - IP9_7_4 - IP9_3_0 )) - }, - { PINMUX_CFG_REG("IPSR10", 0xe6060228, 32, 4, GROUP( - IP10_31_28 - IP10_27_24 - IP10_23_20 - IP10_19_16 - IP10_15_12 - IP10_11_8 - IP10_7_4 - IP10_3_0 )) - }, - { PINMUX_CFG_REG("IPSR11", 0xe606022c, 32, 4, GROUP( - IP11_31_28 - IP11_27_24 - IP11_23_20 - IP11_19_16 - IP11_15_12 - IP11_11_8 - IP11_7_4 - IP11_3_0 )) - }, - { PINMUX_CFG_REG("IPSR12", 0xe6060230, 32, 4, GROUP( - IP12_31_28 - IP12_27_24 - IP12_23_20 - IP12_19_16 - IP12_15_12 - IP12_11_8 - IP12_7_4 - IP12_3_0 )) - }, - { PINMUX_CFG_REG("IPSR13", 0xe6060234, 32, 4, GROUP( - IP13_31_28 - IP13_27_24 - IP13_23_20 - IP13_19_16 - IP13_15_12 - IP13_11_8 - IP13_7_4 - IP13_3_0 )) - }, - { PINMUX_CFG_REG("IPSR14", 0xe6060238, 32, 4, GROUP( - IP14_31_28 - IP14_27_24 - IP14_23_20 - IP14_19_16 - IP14_15_12 - IP14_11_8 - IP14_7_4 - IP14_3_0 )) - }, - { PINMUX_CFG_REG("IPSR15", 0xe606023c, 32, 4, GROUP( - IP15_31_28 - IP15_27_24 - IP15_23_20 - IP15_19_16 - IP15_15_12 - IP15_11_8 - IP15_7_4 - IP15_3_0 )) - }, - { PINMUX_CFG_REG("IPSR16", 0xe6060240, 32, 4, GROUP( - IP16_31_28 - IP16_27_24 - IP16_23_20 - IP16_19_16 - IP16_15_12 - IP16_11_8 - IP16_7_4 - IP16_3_0 )) - }, - { PINMUX_CFG_REG_VAR("IPSR17", 0xe6060244, 32, - GROUP(-24, 4, 4), - GROUP( - /* IP17_31_8 RESERVED */ - IP17_7_4 - IP17_3_0 )) - }, -#undef F_ -#undef FM - -#define F_(x, y) x, -#define FM(x) FN_##x, - { PINMUX_CFG_REG_VAR("MOD_SEL0", 0xe6060500, 32, - GROUP(-1, 2, 2, 3, 1, 1, 2, 1, 1, 1, 2, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, -1), - GROUP( - /* RESERVED 31 */ - MOD_SEL0_30_29 - MOD_SEL0_28_27 - MOD_SEL0_26_25_24 - MOD_SEL0_23 - MOD_SEL0_22 - MOD_SEL0_21_20 - MOD_SEL0_19 - MOD_SEL0_18 - MOD_SEL0_17 - MOD_SEL0_16_15 - MOD_SEL0_14 - MOD_SEL0_13 - MOD_SEL0_12 - MOD_SEL0_11 - MOD_SEL0_10 - MOD_SEL0_9 - MOD_SEL0_8 - MOD_SEL0_7_6 - MOD_SEL0_5_4 - MOD_SEL0_3 - MOD_SEL0_2_1 - /* RESERVED 0 */ )) - }, - { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xe6060504, 32, - GROUP(2, 3, 1, 2, 3, 1, 1, 2, 1, 2, 1, 1, - 1, 1, 1, -2, 1, 1, 1, 1, 1, 1, 1), - GROUP( - MOD_SEL1_31_30 - MOD_SEL1_29_28_27 - MOD_SEL1_26 - MOD_SEL1_25_24 - MOD_SEL1_23_22_21 - MOD_SEL1_20 - MOD_SEL1_19 - MOD_SEL1_18_17 - MOD_SEL1_16 - MOD_SEL1_15_14 - MOD_SEL1_13 - MOD_SEL1_12 - MOD_SEL1_11 - MOD_SEL1_10 - MOD_SEL1_9 - /* RESERVED 8, 7 */ - MOD_SEL1_6 - MOD_SEL1_5 - MOD_SEL1_4 - MOD_SEL1_3 - MOD_SEL1_2 - MOD_SEL1_1 - MOD_SEL1_0 )) - }, - { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xe6060508, 32, - GROUP(1, 1, 1, -28, 1), - GROUP( - MOD_SEL2_31 - MOD_SEL2_30 - MOD_SEL2_29 - /* RESERVED 28-1 */ - MOD_SEL2_0 )) - }, - { }, -}; - -static const struct pinmux_drive_reg pinmux_drive_regs[] = { - { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) { - { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ - { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ - { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ - { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ - { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ - { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ - { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ - { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) { - { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ - { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ - { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ - { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ - { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ - { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ - { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ - { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) { - { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ - { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ - { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ - { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ - { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ - { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ - { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ - { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) { - { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ - { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ - { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ - { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ - { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ - { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ - { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ - { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) { - { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ - { RCAR_GP_PIN(2, 13), 24, 3 }, /* AVB_AVTP_MATCH */ - { RCAR_GP_PIN(2, 14), 20, 3 }, /* AVB_AVTP_CAPTURE */ - { RCAR_GP_PIN(2, 0), 16, 3 }, /* IRQ0 */ - { RCAR_GP_PIN(2, 1), 12, 3 }, /* IRQ1 */ - { RCAR_GP_PIN(2, 2), 8, 3 }, /* IRQ2 */ - { RCAR_GP_PIN(2, 3), 4, 3 }, /* IRQ3 */ - { RCAR_GP_PIN(2, 4), 0, 3 }, /* IRQ4 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL5", 0xe6060314) { - { RCAR_GP_PIN(2, 5), 28, 3 }, /* IRQ5 */ - { RCAR_GP_PIN(2, 6), 24, 3 }, /* PWM0 */ - { RCAR_GP_PIN(2, 7), 20, 3 }, /* PWM1 */ - { RCAR_GP_PIN(2, 8), 16, 3 }, /* PWM2 */ - { RCAR_GP_PIN(1, 0), 12, 3 }, /* A0 */ - { RCAR_GP_PIN(1, 1), 8, 3 }, /* A1 */ - { RCAR_GP_PIN(1, 2), 4, 3 }, /* A2 */ - { RCAR_GP_PIN(1, 3), 0, 3 }, /* A3 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL6", 0xe6060318) { - { RCAR_GP_PIN(1, 4), 28, 3 }, /* A4 */ - { RCAR_GP_PIN(1, 5), 24, 3 }, /* A5 */ - { RCAR_GP_PIN(1, 6), 20, 3 }, /* A6 */ - { RCAR_GP_PIN(1, 7), 16, 3 }, /* A7 */ - { RCAR_GP_PIN(1, 8), 12, 3 }, /* A8 */ - { RCAR_GP_PIN(1, 9), 8, 3 }, /* A9 */ - { RCAR_GP_PIN(1, 10), 4, 3 }, /* A10 */ - { RCAR_GP_PIN(1, 11), 0, 3 }, /* A11 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL7", 0xe606031c) { - { RCAR_GP_PIN(1, 12), 28, 3 }, /* A12 */ - { RCAR_GP_PIN(1, 13), 24, 3 }, /* A13 */ - { RCAR_GP_PIN(1, 14), 20, 3 }, /* A14 */ - { RCAR_GP_PIN(1, 15), 16, 3 }, /* A15 */ - { RCAR_GP_PIN(1, 16), 12, 3 }, /* A16 */ - { RCAR_GP_PIN(1, 17), 8, 3 }, /* A17 */ - { RCAR_GP_PIN(1, 18), 4, 3 }, /* A18 */ - { RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) { - { PIN_CLKOUT, 28, 3 }, /* CLKOUT */ - { RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */ - { RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */ - { RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */ - { RCAR_GP_PIN(1, 23), 12, 3 }, /* RD */ - { RCAR_GP_PIN(1, 24), 8, 3 }, /* RD_WR */ - { RCAR_GP_PIN(1, 25), 4, 3 }, /* WE0 */ - { RCAR_GP_PIN(1, 26), 0, 3 }, /* WE1 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) { - { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ - { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ - { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ - { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ - { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ - { RCAR_GP_PIN(0, 3), 8, 3 }, /* D3 */ - { RCAR_GP_PIN(0, 4), 4, 3 }, /* D4 */ - { RCAR_GP_PIN(0, 5), 0, 3 }, /* D5 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL10", 0xe6060328) { - { RCAR_GP_PIN(0, 6), 28, 3 }, /* D6 */ - { RCAR_GP_PIN(0, 7), 24, 3 }, /* D7 */ - { RCAR_GP_PIN(0, 8), 20, 3 }, /* D8 */ - { RCAR_GP_PIN(0, 9), 16, 3 }, /* D9 */ - { RCAR_GP_PIN(0, 10), 12, 3 }, /* D10 */ - { RCAR_GP_PIN(0, 11), 8, 3 }, /* D11 */ - { RCAR_GP_PIN(0, 12), 4, 3 }, /* D12 */ - { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) { - { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ - { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ - { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ - { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ - { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ - { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ - { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ - { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) { - { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */ - { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */ - { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */ - { PIN_TMS, 4, 2 }, /* TMS */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) { - { PIN_TDO, 28, 2 }, /* TDO */ - { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ - { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ - { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ - { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ - { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ - { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ - { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) { - { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ - { RCAR_GP_PIN(3, 7), 24, 3 }, /* SD1_CMD */ - { RCAR_GP_PIN(3, 8), 20, 3 }, /* SD1_DAT0 */ - { RCAR_GP_PIN(3, 9), 16, 3 }, /* SD1_DAT1 */ - { RCAR_GP_PIN(3, 10), 12, 3 }, /* SD1_DAT2 */ - { RCAR_GP_PIN(3, 11), 8, 3 }, /* SD1_DAT3 */ - { RCAR_GP_PIN(4, 0), 4, 3 }, /* SD2_CLK */ - { RCAR_GP_PIN(4, 1), 0, 3 }, /* SD2_CMD */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL15", 0xe606033c) { - { RCAR_GP_PIN(4, 2), 28, 3 }, /* SD2_DAT0 */ - { RCAR_GP_PIN(4, 3), 24, 3 }, /* SD2_DAT1 */ - { RCAR_GP_PIN(4, 4), 20, 3 }, /* SD2_DAT2 */ - { RCAR_GP_PIN(4, 5), 16, 3 }, /* SD2_DAT3 */ - { RCAR_GP_PIN(4, 6), 12, 3 }, /* SD2_DS */ - { RCAR_GP_PIN(4, 7), 8, 3 }, /* SD3_CLK */ - { RCAR_GP_PIN(4, 8), 4, 3 }, /* SD3_CMD */ - { RCAR_GP_PIN(4, 9), 0, 3 }, /* SD3_DAT0 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL16", 0xe6060340) { - { RCAR_GP_PIN(4, 10), 28, 3 }, /* SD3_DAT1 */ - { RCAR_GP_PIN(4, 11), 24, 3 }, /* SD3_DAT2 */ - { RCAR_GP_PIN(4, 12), 20, 3 }, /* SD3_DAT3 */ - { RCAR_GP_PIN(4, 13), 16, 3 }, /* SD3_DAT4 */ - { RCAR_GP_PIN(4, 14), 12, 3 }, /* SD3_DAT5 */ - { RCAR_GP_PIN(4, 15), 8, 3 }, /* SD3_DAT6 */ - { RCAR_GP_PIN(4, 16), 4, 3 }, /* SD3_DAT7 */ - { RCAR_GP_PIN(4, 17), 0, 3 }, /* SD3_DS */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL17", 0xe6060344) { - { RCAR_GP_PIN(3, 12), 28, 3 }, /* SD0_CD */ - { RCAR_GP_PIN(3, 13), 24, 3 }, /* SD0_WP */ - { RCAR_GP_PIN(3, 14), 20, 3 }, /* SD1_CD */ - { RCAR_GP_PIN(3, 15), 16, 3 }, /* SD1_WP */ - { RCAR_GP_PIN(5, 0), 12, 3 }, /* SCK0 */ - { RCAR_GP_PIN(5, 1), 8, 3 }, /* RX0 */ - { RCAR_GP_PIN(5, 2), 4, 3 }, /* TX0 */ - { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL18", 0xe6060348) { - { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0 */ - { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ - { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ - { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ - { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1 */ - { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ - { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ - { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL19", 0xe606034c) { - { RCAR_GP_PIN(5, 12), 28, 3 }, /* HSCK0 */ - { RCAR_GP_PIN(5, 13), 24, 3 }, /* HRX0 */ - { RCAR_GP_PIN(5, 14), 20, 3 }, /* HTX0 */ - { RCAR_GP_PIN(5, 15), 16, 3 }, /* HCTS0 */ - { RCAR_GP_PIN(5, 16), 12, 3 }, /* HRTS0 */ - { RCAR_GP_PIN(5, 17), 8, 3 }, /* MSIOF0_SCK */ - { RCAR_GP_PIN(5, 18), 4, 3 }, /* MSIOF0_SYNC */ - { RCAR_GP_PIN(5, 19), 0, 3 }, /* MSIOF0_SS1 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL20", 0xe6060350) { - { RCAR_GP_PIN(5, 20), 28, 3 }, /* MSIOF0_TXD */ - { RCAR_GP_PIN(5, 21), 24, 3 }, /* MSIOF0_SS2 */ - { RCAR_GP_PIN(5, 22), 20, 3 }, /* MSIOF0_RXD */ - { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ - { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ - { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ - { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ - { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) { - { RCAR_GP_PIN(6, 1), 28, 3 }, /* SSI_WS01239 */ - { RCAR_GP_PIN(6, 2), 24, 3 }, /* SSI_SDATA0 */ - { RCAR_GP_PIN(6, 3), 20, 3 }, /* SSI_SDATA1 */ - { RCAR_GP_PIN(6, 4), 16, 3 }, /* SSI_SDATA2 */ - { RCAR_GP_PIN(6, 5), 12, 3 }, /* SSI_SCK349 */ - { RCAR_GP_PIN(6, 6), 8, 3 }, /* SSI_WS349 */ - { RCAR_GP_PIN(6, 7), 4, 3 }, /* SSI_SDATA3 */ - { RCAR_GP_PIN(6, 8), 0, 3 }, /* SSI_SCK4 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL22", 0xe6060358) { - { RCAR_GP_PIN(6, 9), 28, 3 }, /* SSI_WS4 */ - { RCAR_GP_PIN(6, 10), 24, 3 }, /* SSI_SDATA4 */ - { RCAR_GP_PIN(6, 11), 20, 3 }, /* SSI_SCK5 */ - { RCAR_GP_PIN(6, 12), 16, 3 }, /* SSI_WS5 */ - { RCAR_GP_PIN(6, 13), 12, 3 }, /* SSI_SDATA5 */ - { RCAR_GP_PIN(6, 14), 8, 3 }, /* SSI_SCK6 */ - { RCAR_GP_PIN(6, 15), 4, 3 }, /* SSI_WS6 */ - { RCAR_GP_PIN(6, 16), 0, 3 }, /* SSI_SDATA6 */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL23", 0xe606035c) { - { RCAR_GP_PIN(6, 17), 28, 3 }, /* SSI_SCK78 */ - { RCAR_GP_PIN(6, 18), 24, 3 }, /* SSI_WS78 */ - { RCAR_GP_PIN(6, 19), 20, 3 }, /* SSI_SDATA7 */ - { RCAR_GP_PIN(6, 20), 16, 3 }, /* SSI_SDATA8 */ - { RCAR_GP_PIN(6, 21), 12, 3 }, /* SSI_SDATA9 */ - { RCAR_GP_PIN(6, 22), 8, 3 }, /* AUDIO_CLKA */ - { RCAR_GP_PIN(6, 23), 4, 3 }, /* AUDIO_CLKB */ - { RCAR_GP_PIN(6, 24), 0, 3 }, /* USB0_PWEN */ - } }, - { PINMUX_DRIVE_REG("DRVCTRL24", 0xe6060360) { - { RCAR_GP_PIN(6, 25), 28, 3 }, /* USB0_OVC */ - { RCAR_GP_PIN(6, 26), 24, 3 }, /* USB1_PWEN */ - { RCAR_GP_PIN(6, 27), 20, 3 }, /* USB1_OVC */ - { RCAR_GP_PIN(6, 28), 16, 3 }, /* USB30_PWEN */ - { RCAR_GP_PIN(6, 29), 12, 3 }, /* USB30_OVC */ - { RCAR_GP_PIN(6, 30), 8, 3 }, /* USB31_PWEN */ - { RCAR_GP_PIN(6, 31), 4, 3 }, /* USB31_OVC */ - } }, - { }, -}; - -enum ioctrl_regs { - POCCTRL, - TDSELCTRL, -}; - -static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { - [POCCTRL] = { 0xe6060380, }, - [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, -}; - -static int r8a77950_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) -{ - int bit = -EINVAL; - - *pocctrl = pinmux_ioctrl_regs[POCCTRL].reg; - - if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 11)) - bit = pin & 0x1f; - - if (pin >= RCAR_GP_PIN(4, 0) && pin <= RCAR_GP_PIN(4, 17)) - bit = (pin & 0x1f) + 12; - - return bit; -} - -static const struct pinmux_bias_reg pinmux_bias_regs[] = { - { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) { - [ 0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ - [ 1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ - [ 2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ - [ 3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ - [ 4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ - [ 5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ - [ 6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ - [ 7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ - [ 8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ - [ 9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ - [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ - [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ - [12] = PIN_RPC_INT_N, /* RPC_INT# */ - [13] = PIN_RPC_WP_N, /* RPC_WP# */ - [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ - [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ - [16] = PIN_AVB_RXC, /* AVB_RXC */ - [17] = PIN_AVB_RD0, /* AVB_RD0 */ - [18] = PIN_AVB_RD1, /* AVB_RD1 */ - [19] = PIN_AVB_RD2, /* AVB_RD2 */ - [20] = PIN_AVB_RD3, /* AVB_RD3 */ - [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ - [22] = PIN_AVB_TXC, /* AVB_TXC */ - [23] = PIN_AVB_TD0, /* AVB_TD0 */ - [24] = PIN_AVB_TD1, /* AVB_TD1 */ - [25] = PIN_AVB_TD2, /* AVB_TD2 */ - [26] = PIN_AVB_TD3, /* AVB_TD3 */ - [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ - [28] = PIN_AVB_MDIO, /* AVB_MDIO */ - [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ - [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ - [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ - } }, - { PINMUX_BIAS_REG("PUEN1", 0xe6060404, "PUD1", 0xe6060444) { - [ 0] = RCAR_GP_PIN(2, 12), /* AVB_LINK */ - [ 1] = RCAR_GP_PIN(2, 13), /* AVB_AVTP_MATCH_A */ - [ 2] = RCAR_GP_PIN(2, 14), /* AVB_AVTP_CAPTURE_A */ - [ 3] = RCAR_GP_PIN(2, 0), /* IRQ0 */ - [ 4] = RCAR_GP_PIN(2, 1), /* IRQ1 */ - [ 5] = RCAR_GP_PIN(2, 2), /* IRQ2 */ - [ 6] = RCAR_GP_PIN(2, 3), /* IRQ3 */ - [ 7] = RCAR_GP_PIN(2, 4), /* IRQ4 */ - [ 8] = RCAR_GP_PIN(2, 5), /* IRQ5 */ - [ 9] = RCAR_GP_PIN(2, 6), /* PWM0 */ - [10] = RCAR_GP_PIN(2, 7), /* PWM1_A */ - [11] = RCAR_GP_PIN(2, 8), /* PWM2_A */ - [12] = RCAR_GP_PIN(1, 0), /* A0 */ - [13] = RCAR_GP_PIN(1, 1), /* A1 */ - [14] = RCAR_GP_PIN(1, 2), /* A2 */ - [15] = RCAR_GP_PIN(1, 3), /* A3 */ - [16] = RCAR_GP_PIN(1, 4), /* A4 */ - [17] = RCAR_GP_PIN(1, 5), /* A5 */ - [18] = RCAR_GP_PIN(1, 6), /* A6 */ - [19] = RCAR_GP_PIN(1, 7), /* A7 */ - [20] = RCAR_GP_PIN(1, 8), /* A8 */ - [21] = RCAR_GP_PIN(1, 9), /* A9 */ - [22] = RCAR_GP_PIN(1, 10), /* A10 */ - [23] = RCAR_GP_PIN(1, 11), /* A11 */ - [24] = RCAR_GP_PIN(1, 12), /* A12 */ - [25] = RCAR_GP_PIN(1, 13), /* A13 */ - [26] = RCAR_GP_PIN(1, 14), /* A14 */ - [27] = RCAR_GP_PIN(1, 15), /* A15 */ - [28] = RCAR_GP_PIN(1, 16), /* A16 */ - [29] = RCAR_GP_PIN(1, 17), /* A17 */ - [30] = RCAR_GP_PIN(1, 18), /* A18 */ - [31] = RCAR_GP_PIN(1, 19), /* A19 */ - } }, - { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) { - [ 0] = PIN_CLKOUT, /* CLKOUT */ - [ 1] = RCAR_GP_PIN(1, 20), /* CS0_N */ - [ 2] = RCAR_GP_PIN(1, 21), /* CS1_N_A26 */ - [ 3] = RCAR_GP_PIN(1, 22), /* BS_N */ - [ 4] = RCAR_GP_PIN(1, 23), /* RD_N */ - [ 5] = RCAR_GP_PIN(1, 24), /* RD_WR_N */ - [ 6] = RCAR_GP_PIN(1, 25), /* WE0_N */ - [ 7] = RCAR_GP_PIN(1, 26), /* WE1_N */ - [ 8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ - [ 9] = PIN_PRESETOUT_N, /* PRESETOUT# */ - [10] = RCAR_GP_PIN(0, 0), /* D0 */ - [11] = RCAR_GP_PIN(0, 1), /* D1 */ - [12] = RCAR_GP_PIN(0, 2), /* D2 */ - [13] = RCAR_GP_PIN(0, 3), /* D3 */ - [14] = RCAR_GP_PIN(0, 4), /* D4 */ - [15] = RCAR_GP_PIN(0, 5), /* D5 */ - [16] = RCAR_GP_PIN(0, 6), /* D6 */ - [17] = RCAR_GP_PIN(0, 7), /* D7 */ - [18] = RCAR_GP_PIN(0, 8), /* D8 */ - [19] = RCAR_GP_PIN(0, 9), /* D9 */ - [20] = RCAR_GP_PIN(0, 10), /* D10 */ - [21] = RCAR_GP_PIN(0, 11), /* D11 */ - [22] = RCAR_GP_PIN(0, 12), /* D12 */ - [23] = RCAR_GP_PIN(0, 13), /* D13 */ - [24] = RCAR_GP_PIN(0, 14), /* D14 */ - [25] = RCAR_GP_PIN(0, 15), /* D15 */ - [26] = RCAR_GP_PIN(7, 0), /* AVS1 */ - [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ - [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ - [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ - [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ - [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ - } }, - { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) { - [ 0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */ - [ 1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */ - [ 2] = PIN_FSCLKST_N, /* FSCLKST# */ - [ 3] = PIN_EXTALR, /* EXTALR*/ - [ 4] = PIN_TRST_N, /* TRST# */ - [ 5] = PIN_TCK, /* TCK */ - [ 6] = PIN_TMS, /* TMS */ - [ 7] = PIN_TDI, /* TDI */ - [ 8] = SH_PFC_PIN_NONE, - [ 9] = PIN_ASEBRK, /* ASEBRK */ - [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ - [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ - [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ - [13] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ - [14] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ - [15] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ - [16] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ - [17] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ - [18] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ - [19] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ - [20] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ - [21] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ - [22] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ - [23] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ - [24] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ - [25] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ - [26] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ - [27] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ - [28] = RCAR_GP_PIN(4, 6), /* SD2_DS */ - [29] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ - [30] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ - [31] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ - } }, - { PINMUX_BIAS_REG("PUEN4", 0xe6060410, "PUD4", 0xe6060450) { - [ 0] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ - [ 1] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ - [ 2] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ - [ 3] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ - [ 4] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ - [ 5] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ - [ 6] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ - [ 7] = RCAR_GP_PIN(4, 17), /* SD3_DS */ - [ 8] = RCAR_GP_PIN(3, 12), /* SD0_CD */ - [ 9] = RCAR_GP_PIN(3, 13), /* SD0_WP */ - [10] = RCAR_GP_PIN(3, 14), /* SD1_CD */ - [11] = RCAR_GP_PIN(3, 15), /* SD1_WP */ - [12] = RCAR_GP_PIN(5, 0), /* SCK0 */ - [13] = RCAR_GP_PIN(5, 1), /* RX0 */ - [14] = RCAR_GP_PIN(5, 2), /* TX0 */ - [15] = RCAR_GP_PIN(5, 3), /* CTS0_N */ - [16] = RCAR_GP_PIN(5, 4), /* RTS0_N */ - [17] = RCAR_GP_PIN(5, 5), /* RX1_A */ - [18] = RCAR_GP_PIN(5, 6), /* TX1_A */ - [19] = RCAR_GP_PIN(5, 7), /* CTS1_N */ - [20] = RCAR_GP_PIN(5, 8), /* RTS1_N */ - [21] = RCAR_GP_PIN(5, 9), /* SCK2 */ - [22] = RCAR_GP_PIN(5, 10), /* TX2_A */ - [23] = RCAR_GP_PIN(5, 11), /* RX2_A */ - [24] = RCAR_GP_PIN(5, 12), /* HSCK0 */ - [25] = RCAR_GP_PIN(5, 13), /* HRX0 */ - [26] = RCAR_GP_PIN(5, 14), /* HTX0 */ - [27] = RCAR_GP_PIN(5, 15), /* HCTS0_N */ - [28] = RCAR_GP_PIN(5, 16), /* HRTS0_N */ - [29] = RCAR_GP_PIN(5, 17), /* MSIOF0_SCK */ - [30] = RCAR_GP_PIN(5, 18), /* MSIOF0_SYNC */ - [31] = RCAR_GP_PIN(5, 19), /* MSIOF0_SS1 */ - } }, - { PINMUX_BIAS_REG("PUEN5", 0xe6060414, "PUD5", 0xe6060454) { - [ 0] = RCAR_GP_PIN(5, 20), /* MSIOF0_TXD */ - [ 1] = RCAR_GP_PIN(5, 21), /* MSIOF0_SS2 */ - [ 2] = RCAR_GP_PIN(5, 22), /* MSIOF0_RXD */ - [ 3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ - [ 4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ - [ 5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ - [ 6] = PIN_MLB_REF, /* MLB_REF */ - [ 7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ - [ 8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ - [ 9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ - [10] = RCAR_GP_PIN(6, 3), /* SSI_SDATA1_A */ - [11] = RCAR_GP_PIN(6, 4), /* SSI_SDATA2_A */ - [12] = RCAR_GP_PIN(6, 5), /* SSI_SCK349 */ - [13] = RCAR_GP_PIN(6, 6), /* SSI_WS349 */ - [14] = RCAR_GP_PIN(6, 7), /* SSI_SDATA3 */ - [15] = RCAR_GP_PIN(6, 8), /* SSI_SCK4 */ - [16] = RCAR_GP_PIN(6, 9), /* SSI_WS4 */ - [17] = RCAR_GP_PIN(6, 10), /* SSI_SDATA4 */ - [18] = RCAR_GP_PIN(6, 11), /* SSI_SCK5 */ - [19] = RCAR_GP_PIN(6, 12), /* SSI_WS5 */ - [20] = RCAR_GP_PIN(6, 13), /* SSI_SDATA5 */ - [21] = RCAR_GP_PIN(6, 14), /* SSI_SCK6 */ - [22] = RCAR_GP_PIN(6, 15), /* SSI_WS6 */ - [23] = RCAR_GP_PIN(6, 16), /* SSI_SDATA6 */ - [24] = RCAR_GP_PIN(6, 17), /* SSI_SCK78 */ - [25] = RCAR_GP_PIN(6, 18), /* SSI_WS78 */ - [26] = RCAR_GP_PIN(6, 19), /* SSI_SDATA7 */ - [27] = RCAR_GP_PIN(6, 20), /* SSI_SDATA8 */ - [28] = RCAR_GP_PIN(6, 21), /* SSI_SDATA9_A */ - [29] = RCAR_GP_PIN(6, 22), /* AUDIO_CLKA_A */ - [30] = RCAR_GP_PIN(6, 23), /* AUDIO_CLKB_B */ - [31] = RCAR_GP_PIN(6, 24), /* USB0_PWEN */ - } }, - { PINMUX_BIAS_REG("PUEN6", 0xe6060418, "PUD6", 0xe6060458) { - [ 0] = RCAR_GP_PIN(6, 25), /* USB0_OVC */ - [ 1] = RCAR_GP_PIN(6, 26), /* USB1_PWEN */ - [ 2] = RCAR_GP_PIN(6, 27), /* USB1_OVC */ - [ 3] = RCAR_GP_PIN(6, 28), /* USB30_PWEN */ - [ 4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ - [ 5] = RCAR_GP_PIN(6, 30), /* USB31_PWEN */ - [ 6] = RCAR_GP_PIN(6, 31), /* USB31_OVC */ - [ 7] = SH_PFC_PIN_NONE, - [ 8] = SH_PFC_PIN_NONE, - [ 9] = SH_PFC_PIN_NONE, - [10] = SH_PFC_PIN_NONE, - [11] = SH_PFC_PIN_NONE, - [12] = SH_PFC_PIN_NONE, - [13] = SH_PFC_PIN_NONE, - [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 r8a77950_pfc_ops = { - .pin_to_pocctrl = r8a77950_pin_to_pocctrl, - .get_bias = rcar_pinmux_get_bias, - .set_bias = rcar_pinmux_set_bias, -}; - -const struct sh_pfc_soc_info r8a77950_pinmux_info = { - .name = "r8a77950_pfc", - .ops = &r8a77950_pfc_ops, - .unlock_reg = 0xe6060000, /* PMMR */ - - .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), -}; diff --git a/drivers/pinctrl/renesas/pfc-r8a77951.c b/drivers/pinctrl/renesas/pfc-r8a77951.c index d4d271dff055..a1d74f61fd8c 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77951.c +++ b/drivers/pinctrl/renesas/pfc-r8a77951.c @@ -17,12 +17,12 @@ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ 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_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) @@ -5610,7 +5610,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* RESERVED 16-1 */ MOD_SEL2_0 )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -5861,7 +5861,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(6, 30), 8, 3 }, /* GP6_30/USB2_CH3_PWEN */ { RCAR_GP_PIN(6, 31), 4, 3 }, /* GP6_31/USB2_CH3_OVC */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -5872,7 +5872,7 @@ enum ioctrl_regs { static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL] = { 0xe6060380, }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a77951_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -6129,7 +6129,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a77951_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7796.c b/drivers/pinctrl/renesas/pfc-r8a7796.c index a0096ef5e68d..807834f319f0 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7796.c +++ b/drivers/pinctrl/renesas/pfc-r8a7796.c @@ -22,12 +22,12 @@ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ 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_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) @@ -5565,7 +5565,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* RESERVED 16-1 */ MOD_SEL2_0 )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -5813,7 +5813,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(6, 30), 8, 3 }, /* GP6_30 */ { RCAR_GP_PIN(6, 31), 4, 3 }, /* GP6_31 */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -5824,7 +5824,7 @@ enum ioctrl_regs { static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL] = { 0xe6060380, }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a7796_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -6081,7 +6081,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a7796_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77965.c b/drivers/pinctrl/renesas/pfc-r8a77965.c index acd0bdf13018..e7c88a5d983f 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77965.c +++ b/drivers/pinctrl/renesas/pfc-r8a77965.c @@ -23,12 +23,12 @@ PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ 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_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE), \ + PORT_GP_CFG_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33), \ PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS) @@ -5806,7 +5806,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* RESERVED 16-1 */ MOD_SEL2_0 )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -6054,7 +6054,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(6, 30), 8, 3 }, /* GP6_30 */ { RCAR_GP_PIN(6, 31), 4, 3 }, /* GP6_31 */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -6065,7 +6065,7 @@ enum ioctrl_regs { static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL] = { 0xe6060380, }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a77965_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -6322,7 +6322,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a77965_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77970.c b/drivers/pinctrl/renesas/pfc-r8a77970.c index 4a7803eaafaa..5b66d7b1af95 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77970.c +++ b/drivers/pinctrl/renesas/pfc-r8a77970.c @@ -19,10 +19,10 @@ #include "sh_pfc.h" #define CPU_ALL_GP(fn, sfx) \ - PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_6(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_15(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN) @@ -34,7 +34,8 @@ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \ - PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP) + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(VDDQ_AVB0, "VDDQ_AVB0", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_25_33) /* * F_() : just information @@ -2342,7 +2343,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL0_1 MOD_SEL0_0 )) }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -2357,26 +2358,37 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL1] = { 0xe6060384 }, [POCCTRL2] = { 0xe6060388 }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a77970_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) { int bit = pin & 0x1f; - *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; - if (pin >= RCAR_GP_PIN(0, 0) && pin <= RCAR_GP_PIN(0, 21)) + switch (pin) { + case RCAR_GP_PIN(0, 0) ... RCAR_GP_PIN(0, 21): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; return bit; - if (pin >= RCAR_GP_PIN(2, 0) && pin <= RCAR_GP_PIN(2, 9)) + + case RCAR_GP_PIN(2, 0) ... RCAR_GP_PIN(2, 9): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; return bit + 22; - *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; - if (pin >= RCAR_GP_PIN(2, 10) && pin <= RCAR_GP_PIN(2, 16)) + case RCAR_GP_PIN(2, 10) ... RCAR_GP_PIN(2, 16): + *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; return bit - 10; - if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 16)) + + case RCAR_GP_PIN(3, 0) ... RCAR_GP_PIN(3, 16): + *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; return bit + 7; - return -EINVAL; + case PIN_VDDQ_AVB0: + *pocctrl = pinmux_ioctrl_regs[POCCTRL2].reg; + return 0; + + default: + return -EINVAL; + } } static const struct pinmux_bias_reg pinmux_bias_regs[] = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77980.c b/drivers/pinctrl/renesas/pfc-r8a77980.c index ac03309c5c0c..384faa0d6937 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77980.c +++ b/drivers/pinctrl/renesas/pfc-r8a77980.c @@ -19,10 +19,10 @@ #include "sh_pfc.h" #define CPU_ALL_GP(fn, sfx) \ - PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_25(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_15(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN) @@ -35,7 +35,9 @@ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN) + PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PIN_NOGP_CFG(VDDQ_AVB, "VDDQ_AVB", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_25_33), \ + PIN_NOGP_CFG(VDDQ_GE, "VDDQ_GE", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_25_33) /* * F_() : just information @@ -2813,7 +2815,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL0_1 MOD_SEL0_0 )) }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -2830,31 +2832,46 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL2] = { 0xe6060388, }, [POCCTRL3] = { 0xe606038c, }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a77980_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) { int bit = pin & 0x1f; - *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; - if (pin >= RCAR_GP_PIN(0, 0) && pin <= RCAR_GP_PIN(0, 21)) + switch (pin) { + case RCAR_GP_PIN(0, 0) ... RCAR_GP_PIN(0, 21): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; return bit; - else if (pin >= RCAR_GP_PIN(2, 0) && pin <= RCAR_GP_PIN(2, 9)) + + case RCAR_GP_PIN(2, 0) ... RCAR_GP_PIN(2, 9): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; return bit + 22; - *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; - if (pin >= RCAR_GP_PIN(2, 10) && pin <= RCAR_GP_PIN(2, 16)) + case RCAR_GP_PIN(2, 10) ... RCAR_GP_PIN(2, 16): + *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; return bit - 10; - if ((pin >= RCAR_GP_PIN(2, 17) && pin <= RCAR_GP_PIN(2, 24)) || - (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 16))) + + case RCAR_GP_PIN(2, 17) ... RCAR_GP_PIN(2, 24): + case RCAR_GP_PIN(3, 0) ... RCAR_GP_PIN(3, 16): + *pocctrl = pinmux_ioctrl_regs[POCCTRL1].reg; return bit + 7; - *pocctrl = pinmux_ioctrl_regs[POCCTRL2].reg; - if (pin >= RCAR_GP_PIN(2, 25) && pin <= RCAR_GP_PIN(2, 29)) + case RCAR_GP_PIN(2, 25) ... RCAR_GP_PIN(2, 29): + *pocctrl = pinmux_ioctrl_regs[POCCTRL2].reg; return pin - 25; - return -EINVAL; + case PIN_VDDQ_AVB: + *pocctrl = pinmux_ioctrl_regs[POCCTRL3].reg; + return 0; + + case PIN_VDDQ_GE: + *pocctrl = pinmux_ioctrl_regs[POCCTRL3].reg; + return 1; + + default: + return -EINVAL; + } } static const struct pinmux_bias_reg pinmux_bias_regs[] = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77990.c b/drivers/pinctrl/renesas/pfc-r8a77990.c index b0936962fad7..262390dd7d67 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77990.c +++ b/drivers/pinctrl/renesas/pfc-r8a77990.c @@ -22,12 +22,12 @@ PORT_GP_CFG_18(0, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_23(1, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_26(2, fn, sfx, CFG_FLAGS), \ - PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS), \ 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_11(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ + PORT_GP_CFG_11(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_DRIVE_STRENGTH), \ PORT_GP_CFG_20(5, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_9(6, fn, sfx, CFG_FLAGS), \ PORT_GP_CFG_1(6, 9, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \ @@ -56,7 +56,8 @@ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \ - PIN_NOGP_CFG(TRST_N, "TRST_N", fn, SH_PFC_PIN_CFG_PULL_UP) + PIN_NOGP_CFG(TRST_N, "TRST_N", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(VDDQ_AVB0, "VDDQ_AVB0", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_25_33) /* * F_() : just information @@ -507,7 +508,8 @@ MOD_SEL0_1_0 FM(AVB_TD3) \ FM(PRESETOUT_N) FM(FSCLKST_N) FM(TRST_N) FM(TCK) FM(TMS) FM(TDI) \ FM(ASEBRK) \ - FM(MLB_REF) + FM(MLB_REF) \ + FM(VDDQ_AVB0) enum { PINMUX_RESERVED = 0, @@ -5002,7 +5004,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL1_4 /* RESERVED 3, 2, 1, 0 */ )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -5035,33 +5037,40 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(4, 9), 17, 2 }, /* SD3_DAT7 */ { RCAR_GP_PIN(4, 10), 14, 2 }, /* SD3_DS */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { POCCTRL0, + POCCTRL2, TDSELCTRL, }; static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POCCTRL0] = { 0xe6060380, }, + [POCCTRL2] = { 0xe6060388, }, [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a77990_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) { - int bit = -EINVAL; + switch (pin) { + case RCAR_GP_PIN(3, 0) ... RCAR_GP_PIN(3, 11): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; + return pin & 0x1f; - *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; + case RCAR_GP_PIN(4, 0) ... RCAR_GP_PIN(4, 10): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; + return (pin & 0x1f) + 19; - if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 11)) - bit = pin & 0x1f; + case PIN_VDDQ_AVB0: + *pocctrl = pinmux_ioctrl_regs[POCCTRL2].reg; + return 0; - if (pin >= RCAR_GP_PIN(4, 0) && pin <= RCAR_GP_PIN(4, 10)) - bit = (pin & 0x1f) + 19; - - return bit; + default: + return -EINVAL; + } } static const struct pinmux_bias_reg pinmux_bias_regs[] = { @@ -5269,7 +5278,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = RCAR_GP_PIN(6, 9), /* USB30_OVC */ [31] = RCAR_GP_PIN(6, 17), /* USB30_PWEN */ } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a77990_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77995.c b/drivers/pinctrl/renesas/pfc-r8a77995.c index d949ae59c757..298e7a07e493 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77995.c +++ b/drivers/pinctrl/renesas/pfc-r8a77995.c @@ -21,7 +21,7 @@ PORT_GP_CFG_9(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_32(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_32(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ - PORT_GP_CFG_10(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ + PORT_GP_CFG_10(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 | SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_21(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \ PORT_GP_CFG_14(6, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN) @@ -34,7 +34,8 @@ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \ - PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP) + PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP), \ + PIN_NOGP_CFG(VDDQ_AVB0, "VDDQ_AVB0", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_25_33) /* * F_() : just information @@ -2852,19 +2853,37 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL1_26 /* RESERVED 25-0 */ )) }, - { }, + { /* sentinel */ } }; +enum ioctrl_regs { + POCCTRL0, + POCCTRL2, + TDSELCTRL, +}; + +static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { + [POCCTRL0] = { 0xe6060380, }, + [POCCTRL2] = { 0xe6060388, }, + [TDSELCTRL] = { 0xe60603c0, }, + { /* sentinel */ } +}; + + static int r8a77995_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) { - int bit = -EINVAL; + switch (pin) { + case RCAR_GP_PIN(3, 0) ... RCAR_GP_PIN(3, 9): + *pocctrl = pinmux_ioctrl_regs[POCCTRL0].reg; + return 29 - (pin - RCAR_GP_PIN(3, 0)); - *pocctrl = 0xe6060380; + case PIN_VDDQ_AVB0: + *pocctrl = pinmux_ioctrl_regs[POCCTRL2].reg; + return 0; - if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 9)) - bit = 29 - (pin - RCAR_GP_PIN(3, 0)); - - return bit; + default: + return -EINVAL; + } } static const struct pinmux_bias_reg pinmux_bias_regs[] = { @@ -3075,15 +3094,6 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { { /* sentinel */ } }; -enum ioctrl_regs { - TDSELCTRL, -}; - -static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { - [TDSELCTRL] = { 0xe60603c0, }, - { /* sentinel */ }, -}; - static const struct pinmux_bias_reg * r8a77995_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin, unsigned int *puen_bit, unsigned int *pud_bit) diff --git a/drivers/pinctrl/renesas/pfc-r8a779a0.c b/drivers/pinctrl/renesas/pfc-r8a779a0.c index 760c83a8740b..a01bc197d706 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779a0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779a0.c @@ -696,16 +696,8 @@ static const u16 pinmux_data[] = { PINMUX_SINGLE(PCIE0_CLKREQ_N), PINMUX_SINGLE(AVB0_PHY_INT), - PINMUX_SINGLE(AVB0_MAGIC), - PINMUX_SINGLE(AVB0_MDC), - PINMUX_SINGLE(AVB0_MDIO), - PINMUX_SINGLE(AVB0_TXCREFCLK), PINMUX_SINGLE(AVB1_PHY_INT), - PINMUX_SINGLE(AVB1_MAGIC), - PINMUX_SINGLE(AVB1_MDC), - PINMUX_SINGLE(AVB1_MDIO), - PINMUX_SINGLE(AVB1_TXCREFCLK), PINMUX_SINGLE(AVB2_AVTP_PPS), PINMUX_SINGLE(AVB2_AVTP_CAPTURE), @@ -3638,7 +3630,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL2_3_2 /* RESERVED 1-0 */ )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -3943,7 +3935,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(9, 17), 4, 3 }, /* AVB5_LINK */ { RCAR_GP_PIN(9, 16), 0, 3 }, /* AVB5_PHY_INT */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -3970,7 +3962,7 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POC8] = { 0xe60690a0, }, [POC9] = { 0xe60698a0, }, [TD1SEL0] = { 0xe6058124, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a779a0_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -4357,7 +4349,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a779a0_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779f0.c b/drivers/pinctrl/renesas/pfc-r8a779f0.c index 417c357f16b1..16e722a4d18f 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779f0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779f0.c @@ -1213,7 +1213,7 @@ static const unsigned int tsn1_avtp_pps_pins[] = { RCAR_GP_PIN(3, 13), }; static const unsigned int tsn1_avtp_pps_mux[] = { - TSN0_AVTP_PPS_MARK, + TSN1_AVTP_PPS_MARK, }; static const unsigned int tsn1_avtp_capture_a_pins[] = { /* TSN1_AVTP_CAPTURE_A */ @@ -1784,7 +1784,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL1_3_2 MOD_SEL1_1_0)) }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -1896,7 +1896,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(3, 17), 4, 3 }, /* TSN0_AVTP_MATCH_B */ { RCAR_GP_PIN(3, 16), 0, 3 }, /* TSN0_AVTP_PPS */ } }, - { /* sentinel */ }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -1911,7 +1911,7 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POC1] = { 0xe60508a0, }, [POC3] = { 0xe60518a0, }, [TD0SEL1] = { 0xe6050920, }, - { /* sentinel */ }, + { /* sentinel */ } }; static int r8a779f0_pin_to_pocctrl(unsigned int pin, u32 *pocctrl) @@ -2070,7 +2070,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a779f0_pfc_ops = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index bf7fcce2d9c6..acdea6ac1525 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -49,6 +49,12 @@ 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) +#define CPU_ALL_NOGP(fn) \ + PIN_NOGP_CFG(VDDQ_AVB0, "VDDQ_AVB0", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_18_25), \ + PIN_NOGP_CFG(VDDQ_AVB1, "VDDQ_AVB1", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_18_25), \ + PIN_NOGP_CFG(VDDQ_AVB2, "VDDQ_AVB2", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_18_25), \ + PIN_NOGP_CFG(VDDQ_TSN0, "VDDQ_TSN0", fn, SH_PFC_PIN_CFG_IO_VOLTAGE_18_25) + /* GPSR0 */ #define GPSR0_18 F_(MSIOF2_RXD, IP2SR0_11_8) #define GPSR0_17 F_(MSIOF2_SCK, IP2SR0_7_4) @@ -156,54 +162,54 @@ #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) +#define GPSR4_24 F_(AVS1, IP3SR4_3_0) +#define GPSR4_23 F_(AVS0, IP2SR4_31_28) +#define GPSR4_22 F_(PCIE1_CLKREQ_N, IP2SR4_27_24) +#define GPSR4_21 F_(PCIE0_CLKREQ_N, IP2SR4_23_20) +#define GPSR4_20 F_(TSN0_TXCREFCLK, IP2SR4_19_16) +#define GPSR4_19 F_(TSN0_TD2, IP2SR4_15_12) +#define GPSR4_18 F_(TSN0_TD3, IP2SR4_11_8) +#define GPSR4_17 F_(TSN0_RD2, IP2SR4_7_4) +#define GPSR4_16 F_(TSN0_RD3, IP2SR4_3_0) +#define GPSR4_15 F_(TSN0_TD0, IP1SR4_31_28) +#define GPSR4_14 F_(TSN0_TD1, IP1SR4_27_24) +#define GPSR4_13 F_(TSN0_RD1, IP1SR4_23_20) +#define GPSR4_12 F_(TSN0_TXC, IP1SR4_19_16) +#define GPSR4_11 F_(TSN0_RXC, IP1SR4_15_12) +#define GPSR4_10 F_(TSN0_RD0, IP1SR4_11_8) +#define GPSR4_9 F_(TSN0_TX_CTL, IP1SR4_7_4) +#define GPSR4_8 F_(TSN0_AVTP_PPS0, IP1SR4_3_0) +#define GPSR4_7 F_(TSN0_RX_CTL, IP0SR4_31_28) +#define GPSR4_6 F_(TSN0_AVTP_CAPTURE, IP0SR4_27_24) +#define GPSR4_5 F_(TSN0_AVTP_MATCH, IP0SR4_23_20) +#define GPSR4_4 F_(TSN0_LINK, IP0SR4_19_16) +#define GPSR4_3 F_(TSN0_PHY_INT, IP0SR4_15_12) +#define GPSR4_2 F_(TSN0_AVTP_PPS1, IP0SR4_11_8) +#define GPSR4_1 F_(TSN0_MDC, IP0SR4_7_4) +#define GPSR4_0 F_(TSN0_MDIO, IP0SR4_3_0) /* 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) +#define GPSR5_20 F_(AVB2_RX_CTL, IP2SR5_19_16) +#define GPSR5_19 F_(AVB2_TX_CTL, IP2SR5_15_12) +#define GPSR5_18 F_(AVB2_RXC, IP2SR5_11_8) +#define GPSR5_17 F_(AVB2_RD0, IP2SR5_7_4) +#define GPSR5_16 F_(AVB2_TXC, IP2SR5_3_0) +#define GPSR5_15 F_(AVB2_TD0, IP1SR5_31_28) +#define GPSR5_14 F_(AVB2_RD1, IP1SR5_27_24) +#define GPSR5_13 F_(AVB2_RD2, IP1SR5_23_20) +#define GPSR5_12 F_(AVB2_TD1, IP1SR5_19_16) +#define GPSR5_11 F_(AVB2_TD2, IP1SR5_15_12) +#define GPSR5_10 F_(AVB2_MDIO, IP1SR5_11_8) +#define GPSR5_9 F_(AVB2_RD3, IP1SR5_7_4) +#define GPSR5_8 F_(AVB2_TD3, IP1SR5_3_0) +#define GPSR5_7 F_(AVB2_TXCREFCLK, IP0SR5_31_28) +#define GPSR5_6 F_(AVB2_MDC, IP0SR5_27_24) +#define GPSR5_5 F_(AVB2_MAGIC, IP0SR5_23_20) +#define GPSR5_4 F_(AVB2_PHY_INT, IP0SR5_19_16) +#define GPSR5_3 F_(AVB2_LINK, IP0SR5_15_12) +#define GPSR5_2 F_(AVB2_AVTP_MATCH, IP0SR5_11_8) +#define GPSR5_1 F_(AVB2_AVTP_CAPTURE, IP0SR5_7_4) +#define GPSR5_0 F_(AVB2_AVTP_PPS, IP0SR5_3_0) /* GPSR 6 */ #define GPSR6_20 F_(AVB1_TXCREFCLK, IP2SR6_19_16) @@ -268,209 +274,271 @@ #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) +/* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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_N_A) FM(TCLK4_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR3_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) +/* 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) +/* 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) + +/* SR4 */ +/* IP0SR4 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP0SR4_3_0 FM(TSN0_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 IP0SR4_7_4 FM(TSN0_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 IP0SR4_11_8 FM(TSN0_AVTP_PPS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR4_15_12 FM(TSN0_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 IP0SR4_19_16 FM(TSN0_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR4_23_20 FM(TSN0_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR4_27_24 FM(TSN0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR4_31_28 FM(TSN0_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* IP1SR4 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP1SR4_3_0 FM(TSN0_AVTP_PPS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR4_7_4 FM(TSN0_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP1SR4_11_8 FM(TSN0_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) F_(0, 0) +#define IP1SR4_15_12 FM(TSN0_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) F_(0, 0) +#define IP1SR4_19_16 FM(TSN0_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) F_(0, 0) +#define IP1SR4_23_20 FM(TSN0_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) F_(0, 0) +#define IP1SR4_27_24 FM(TSN0_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) F_(0, 0) +#define IP1SR4_31_28 FM(TSN0_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) F_(0, 0) + +/* IP2SR4 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP2SR4_3_0 FM(TSN0_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) F_(0, 0) +#define IP2SR4_7_4 FM(TSN0_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) F_(0, 0) +#define IP2SR4_11_8 FM(TSN0_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) F_(0, 0) +#define IP2SR4_15_12 FM(TSN0_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) F_(0, 0) +#define IP2SR4_19_16 FM(TSN0_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 IP2SR4_23_20 FM(PCIE0_CLKREQ_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 IP2SR4_27_24 FM(PCIE1_CLKREQ_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 IP2SR4_31_28 FM(AVS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* IP3SR4 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP3SR4_3_0 FM(AVS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* SR5 */ +/* IP0SR5 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP0SR5_3_0 FM(AVB2_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR5_7_4 FM(AVB2_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR5_11_8 FM(AVB2_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR5_15_12 FM(AVB2_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP0SR5_19_16 FM(AVB2_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 IP0SR5_23_20 FM(AVB2_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 IP0SR5_27_24 FM(AVB2_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 IP0SR5_31_28 FM(AVB2_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) + +/* IP1SR5 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP1SR5_3_0 FM(AVB2_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) F_(0, 0) +#define IP1SR5_7_4 FM(AVB2_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) F_(0, 0) +#define IP1SR5_11_8 FM(AVB2_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 IP1SR5_15_12 FM(AVB2_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) F_(0, 0) +#define IP1SR5_19_16 FM(AVB2_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) F_(0, 0) +#define IP1SR5_23_20 FM(AVB2_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) F_(0, 0) +#define IP1SR5_27_24 FM(AVB2_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) F_(0, 0) +#define IP1SR5_31_28 FM(AVB2_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) F_(0, 0) + +/* IP2SR5 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define IP2SR5_3_0 FM(AVB2_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) F_(0, 0) +#define IP2SR5_7_4 FM(AVB2_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) F_(0, 0) +#define IP2SR5_11_8 FM(AVB2_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) F_(0, 0) +#define IP2SR5_15_12 FM(AVB2_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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 IP2SR5_19_16 FM(AVB2_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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) +/* 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 \ @@ -542,6 +610,24 @@ FM(IP0SR3_23_20) IP0SR3_23_20 FM(IP1SR3_23_20) IP1SR3_23_20 FM(IP2SR3_23_20) IP2 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(IP0SR4_3_0) IP0SR4_3_0 FM(IP1SR4_3_0) IP1SR4_3_0 FM(IP2SR4_3_0) IP2SR4_3_0 FM(IP3SR4_3_0) IP3SR4_3_0 \ +FM(IP0SR4_7_4) IP0SR4_7_4 FM(IP1SR4_7_4) IP1SR4_7_4 FM(IP2SR4_7_4) IP2SR4_7_4 \ +FM(IP0SR4_11_8) IP0SR4_11_8 FM(IP1SR4_11_8) IP1SR4_11_8 FM(IP2SR4_11_8) IP2SR4_11_8 \ +FM(IP0SR4_15_12) IP0SR4_15_12 FM(IP1SR4_15_12) IP1SR4_15_12 FM(IP2SR4_15_12) IP2SR4_15_12 \ +FM(IP0SR4_19_16) IP0SR4_19_16 FM(IP1SR4_19_16) IP1SR4_19_16 FM(IP2SR4_19_16) IP2SR4_19_16 \ +FM(IP0SR4_23_20) IP0SR4_23_20 FM(IP1SR4_23_20) IP1SR4_23_20 FM(IP2SR4_23_20) IP2SR4_23_20 \ +FM(IP0SR4_27_24) IP0SR4_27_24 FM(IP1SR4_27_24) IP1SR4_27_24 FM(IP2SR4_27_24) IP2SR4_27_24 \ +FM(IP0SR4_31_28) IP0SR4_31_28 FM(IP1SR4_31_28) IP1SR4_31_28 FM(IP2SR4_31_28) IP2SR4_31_28 \ +\ +FM(IP0SR5_3_0) IP0SR5_3_0 FM(IP1SR5_3_0) IP1SR5_3_0 FM(IP2SR5_3_0) IP2SR5_3_0 \ +FM(IP0SR5_7_4) IP0SR5_7_4 FM(IP1SR5_7_4) IP1SR5_7_4 FM(IP2SR5_7_4) IP2SR5_7_4 \ +FM(IP0SR5_11_8) IP0SR5_11_8 FM(IP1SR5_11_8) IP1SR5_11_8 FM(IP2SR5_11_8) IP2SR5_11_8 \ +FM(IP0SR5_15_12) IP0SR5_15_12 FM(IP1SR5_15_12) IP1SR5_15_12 FM(IP2SR5_15_12) IP2SR5_15_12 \ +FM(IP0SR5_19_16) IP0SR5_19_16 FM(IP1SR5_19_16) IP1SR5_19_16 FM(IP2SR5_19_16) IP2SR5_19_16 \ +FM(IP0SR5_23_20) IP0SR5_23_20 FM(IP1SR5_23_20) IP1SR5_23_20 \ +FM(IP0SR5_27_24) IP0SR5_27_24 FM(IP1SR5_27_24) IP1SR5_27_24 \ +FM(IP0SR5_31_28) IP0SR5_31_28 FM(IP1SR5_31_28) IP1SR5_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 \ @@ -569,54 +655,6 @@ 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) @@ -633,26 +671,18 @@ FM(IP0SR8_31_28) IP0SR8_31_28 #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 +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 enum { PINMUX_RESERVED = 0, @@ -686,61 +716,8 @@ enum { 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, ERROROUTC_N_B), PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_A), PINMUX_IPSR_GPSR(IP0SR0_7_4, MSIOF3_SS1), @@ -1006,7 +983,7 @@ static const u16 pinmux_data[] = { 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, ERROROUTC_N_A), PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_X), PINMUX_IPSR_GPSR(IP1SR3_31_28, QSPI0_SSL), @@ -1029,26 +1006,86 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP3SR3_19_16, RPC_WP_N), PINMUX_IPSR_GPSR(IP3SR3_23_20, RPC_INT_N), + /* IP0SR4 */ + PINMUX_IPSR_GPSR(IP0SR4_3_0, TSN0_MDIO), + PINMUX_IPSR_GPSR(IP0SR4_7_4, TSN0_MDC), + PINMUX_IPSR_GPSR(IP0SR4_11_8, TSN0_AVTP_PPS1), + PINMUX_IPSR_GPSR(IP0SR4_15_12, TSN0_PHY_INT), + PINMUX_IPSR_GPSR(IP0SR4_19_16, TSN0_LINK), + PINMUX_IPSR_GPSR(IP0SR4_23_20, TSN0_AVTP_MATCH), + PINMUX_IPSR_GPSR(IP0SR4_27_24, TSN0_AVTP_CAPTURE), + PINMUX_IPSR_GPSR(IP0SR4_31_28, TSN0_RX_CTL), + + /* IP1SR4 */ + PINMUX_IPSR_GPSR(IP1SR4_3_0, TSN0_AVTP_PPS0), + PINMUX_IPSR_GPSR(IP1SR4_7_4, TSN0_TX_CTL), + PINMUX_IPSR_GPSR(IP1SR4_11_8, TSN0_RD0), + PINMUX_IPSR_GPSR(IP1SR4_15_12, TSN0_RXC), + PINMUX_IPSR_GPSR(IP1SR4_19_16, TSN0_TXC), + PINMUX_IPSR_GPSR(IP1SR4_23_20, TSN0_RD1), + PINMUX_IPSR_GPSR(IP1SR4_27_24, TSN0_TD1), + PINMUX_IPSR_GPSR(IP1SR4_31_28, TSN0_TD0), + + /* IP2SR4 */ + PINMUX_IPSR_GPSR(IP2SR4_3_0, TSN0_RD3), + PINMUX_IPSR_GPSR(IP2SR4_7_4, TSN0_RD2), + PINMUX_IPSR_GPSR(IP2SR4_11_8, TSN0_TD3), + PINMUX_IPSR_GPSR(IP2SR4_15_12, TSN0_TD2), + PINMUX_IPSR_GPSR(IP2SR4_19_16, TSN0_TXCREFCLK), + PINMUX_IPSR_GPSR(IP2SR4_23_20, PCIE0_CLKREQ_N), + PINMUX_IPSR_GPSR(IP2SR4_27_24, PCIE1_CLKREQ_N), + PINMUX_IPSR_GPSR(IP2SR4_31_28, AVS0), + + /* IP3SR4 */ + PINMUX_IPSR_GPSR(IP3SR4_3_0, AVS1), + + /* IP0SR5 */ + PINMUX_IPSR_GPSR(IP0SR5_3_0, AVB2_AVTP_PPS), + PINMUX_IPSR_GPSR(IP0SR5_7_4, AVB2_AVTP_CAPTURE), + PINMUX_IPSR_GPSR(IP0SR5_11_8, AVB2_AVTP_MATCH), + PINMUX_IPSR_GPSR(IP0SR5_15_12, AVB2_LINK), + PINMUX_IPSR_GPSR(IP0SR5_19_16, AVB2_PHY_INT), + PINMUX_IPSR_GPSR(IP0SR5_23_20, AVB2_MAGIC), + PINMUX_IPSR_GPSR(IP0SR5_27_24, AVB2_MDC), + PINMUX_IPSR_GPSR(IP0SR5_31_28, AVB2_TXCREFCLK), + + /* IP1SR5 */ + PINMUX_IPSR_GPSR(IP1SR5_3_0, AVB2_TD3), + PINMUX_IPSR_GPSR(IP1SR5_7_4, AVB2_RD3), + PINMUX_IPSR_GPSR(IP1SR5_11_8, AVB2_MDIO), + PINMUX_IPSR_GPSR(IP1SR5_15_12, AVB2_TD2), + PINMUX_IPSR_GPSR(IP1SR5_19_16, AVB2_TD1), + PINMUX_IPSR_GPSR(IP1SR5_23_20, AVB2_RD2), + PINMUX_IPSR_GPSR(IP1SR5_27_24, AVB2_RD1), + PINMUX_IPSR_GPSR(IP1SR5_31_28, AVB2_TD0), + + /* IP2SR5 */ + PINMUX_IPSR_GPSR(IP2SR5_3_0, AVB2_TXC), + PINMUX_IPSR_GPSR(IP2SR5_7_4, AVB2_RD0), + PINMUX_IPSR_GPSR(IP2SR5_11_8, AVB2_RXC), + PINMUX_IPSR_GPSR(IP2SR5_15_12, AVB2_TX_CTL), + PINMUX_IPSR_GPSR(IP2SR5_19_16, AVB2_RX_CTL), + /* IP0SR6 */ PINMUX_IPSR_GPSR(IP0SR6_3_0, AVB1_MDIO), - PINMUX_IPSR_MSEL(IP0SR6_7_4, AVB1_MAGIC, SEL_AVB1_MAGIC_1), + PINMUX_IPSR_GPSR(IP0SR6_7_4, AVB1_MAGIC), - PINMUX_IPSR_MSEL(IP0SR6_11_8, AVB1_MDC, SEL_AVB1_MDC_1), + PINMUX_IPSR_GPSR(IP0SR6_11_8, AVB1_MDC), 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_GPSR(IP0SR6_23_20, AVB1_AVTP_MATCH), + PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_MII_RX_ER), - 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_GPSR(IP0SR6_27_24, AVB1_TXC), + PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_MII_TXC), - 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), + PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_TX_CTL), + PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_MII_TX_EN), /* IP1SR6 */ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC), @@ -1057,17 +1094,17 @@ static const u16 pinmux_data[] = { 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_11_8, AVB1_AVTP_PPS), + PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_MII_COL), 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_GPSR(IP1SR6_19_16, AVB1_TD1), + PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_MII_TD1), - 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_23_20, AVB1_TD0), + PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_MII_TD0), PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1), PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1), @@ -1076,14 +1113,14 @@ static const u16 pinmux_data[] = { 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_3_0, AVB1_TD2), + PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_MII_TD2), 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_11_8, AVB1_TD3), + PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_MII_TD3), PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3), PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3), @@ -1091,29 +1128,29 @@ static const u16 pinmux_data[] = { 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_3_0, AVB0_AVTP_PPS), + PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_MII_COL), 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_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), + PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), + PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), - 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_15_12, AVB0_TD3), + PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), 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_GPSR(IP0SR7_27_24, AVB0_TD2), + PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_MII_TD2), - 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), + PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_TD1), + PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_MII_TD1), /* IP1SR7 */ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3), @@ -1121,24 +1158,24 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK), - PINMUX_IPSR_MSEL(IP1SR7_11_8, AVB0_MAGIC, SEL_AVB0_MAGIC_1), + PINMUX_IPSR_GPSR(IP1SR7_11_8, AVB0_MAGIC), - 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_15_12, AVB0_TD0), + PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_MII_TD0), 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_23_20, AVB0_MDC), 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), + PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_TXC), + PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_MII_TXC), /* 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_3_0, AVB0_TX_CTL), + PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_MII_TX_EN), PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1), PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1), @@ -1190,10 +1227,28 @@ static const u16 pinmux_data[] = { */ enum { GP_ASSIGN_LAST(), + NOGP_ALL(), }; static const struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), + PINMUX_NOGP_ALL(), +}; + +/* - AUDIO CLOCK ----------------------------------------- */ +static const unsigned int audio_clkin_pins[] = { + /* CLK IN */ + RCAR_GP_PIN(1, 22), +}; +static const unsigned int audio_clkin_mux[] = { + AUDIO_CLKIN_MARK, +}; +static const unsigned int audio_clkout_pins[] = { + /* CLK OUT */ + RCAR_GP_PIN(1, 21), +}; +static const unsigned int audio_clkout_mux[] = { + AUDIO_CLKOUT_MARK, }; /* - AVB0 ------------------------------------------------ */ @@ -2329,6 +2384,22 @@ static const unsigned int scif_clk_mux[] = { SCIF_CLK_MARK, }; +/* - SSI ------------------------------------------------- */ +static const unsigned int ssi_data_pins[] = { + /* SSI_SD */ + RCAR_GP_PIN(1, 20), +}; +static const unsigned int ssi_data_mux[] = { + SSI_SD_MARK, +}; +static const unsigned int ssi_ctrl_pins[] = { + /* SSI_SCK, SSI_WS */ + RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 19), +}; +static const unsigned int ssi_ctrl_mux[] = { + SSI_SCK_MARK, SSI_WS_MARK, +}; + /* - TPU ------------------------------------------------------------------- */ static const unsigned int tpu_to0_pins[] = { /* TPU0TO0 */ @@ -2461,6 +2532,9 @@ static const unsigned int tsn0_avtp_match_mux[] = { }; static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(audio_clkin), + SH_PFC_PIN_GROUP(audio_clkout), + SH_PFC_PIN_GROUP(avb0_link), SH_PFC_PIN_GROUP(avb0_magic), SH_PFC_PIN_GROUP(avb0_phy_int), @@ -2621,6 +2695,9 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(scif4_ctrl), SH_PFC_PIN_GROUP(scif_clk), + SH_PFC_PIN_GROUP(ssi_data), + SH_PFC_PIN_GROUP(ssi_ctrl), + SH_PFC_PIN_GROUP(tpu_to0), /* suffix might be updated */ SH_PFC_PIN_GROUP(tpu_to0_a), /* suffix might be updated */ SH_PFC_PIN_GROUP(tpu_to1), /* suffix might be updated */ @@ -2640,6 +2717,11 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(tsn0_avtp_match), }; +static const char * const audio_clk_groups[] = { + "audio_clkin", + "audio_clkout", +}; + static const char * const avb0_groups[] = { "avb0_link", "avb0_magic", @@ -2933,6 +3015,11 @@ static const char * const scif_clk_groups[] = { "scif_clk", }; +static const char * const ssi_groups[] = { + "ssi_data", + "ssi_ctrl", +}; + static const char * const tpu_groups[] = { /* suffix might be updated */ "tpu_to0", @@ -2957,6 +3044,8 @@ static const char * const tsn0_groups[] = { }; static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(audio_clk), + SH_PFC_FUNCTION(avb0), SH_PFC_FUNCTION(avb1), SH_PFC_FUNCTION(avb2), @@ -3014,6 +3103,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(scif4), SH_PFC_FUNCTION(scif_clk), + SH_PFC_FUNCTION(ssi), + SH_PFC_FUNCTION(tpu), SH_PFC_FUNCTION(tsn0), @@ -3419,6 +3510,82 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { IP3SR3_7_4 IP3SR3_3_0)) }, + { PINMUX_CFG_REG_VAR("IP0SR4", 0xE6060060, 32, + GROUP(4, 4, 4, 4, 4, 4, 4, 4), + GROUP( + IP0SR4_31_28 + IP0SR4_27_24 + IP0SR4_23_20 + IP0SR4_19_16 + IP0SR4_15_12 + IP0SR4_11_8 + IP0SR4_7_4 + IP0SR4_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP1SR4", 0xE6060064, 32, + GROUP(4, 4, 4, 4, 4, 4, 4, 4), + GROUP( + IP1SR4_31_28 + IP1SR4_27_24 + IP1SR4_23_20 + IP1SR4_19_16 + IP1SR4_15_12 + IP1SR4_11_8 + IP1SR4_7_4 + IP1SR4_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP2SR4", 0xE6060068, 32, + GROUP(4, 4, 4, 4, 4, 4, 4, 4), + GROUP( + IP2SR4_31_28 + IP2SR4_27_24 + IP2SR4_23_20 + IP2SR4_19_16 + IP2SR4_15_12 + IP2SR4_11_8 + IP2SR4_7_4 + IP2SR4_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP3SR4", 0xE606006C, 32, + GROUP(-28, 4), + GROUP( + /* IP3SR4_31_4 RESERVED */ + IP3SR4_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP0SR5", 0xE6060860, 32, + GROUP(4, 4, 4, 4, 4, 4, 4, 4), + GROUP( + IP0SR5_31_28 + IP0SR5_27_24 + IP0SR5_23_20 + IP0SR5_19_16 + IP0SR5_15_12 + IP0SR5_11_8 + IP0SR5_7_4 + IP0SR5_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP1SR5", 0xE6060864, 32, + GROUP(4, 4, 4, 4, 4, 4, 4, 4), + GROUP( + IP1SR5_31_28 + IP1SR5_27_24 + IP1SR5_23_20 + IP1SR5_19_16 + IP1SR5_15_12 + IP1SR5_11_8 + IP1SR5_7_4 + IP1SR5_3_0)) + }, + { PINMUX_CFG_REG_VAR("IP2SR5", 0xE6060868, 32, + GROUP(-12, 4, 4, 4, 4, 4), + GROUP( + /* IP2SR5_31_20 RESERVED */ + IP2SR5_19_16 + IP2SR5_15_12 + IP2SR5_11_8 + IP2SR5_7_4 + IP2SR5_3_0)) + }, { PINMUX_CFG_REG("IP0SR6", 0xE6061060, 32, 4, GROUP( IP0SR6_31_28 IP0SR6_27_24 @@ -3505,95 +3672,6 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { #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( @@ -3611,7 +3689,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MOD_SEL8_1 MOD_SEL8_0)) }, - { }, + { /* sentinel */ } }; static const struct pinmux_drive_reg pinmux_drive_regs[] = { @@ -3873,7 +3951,7 @@ static const struct pinmux_drive_reg pinmux_drive_regs[] = { { RCAR_GP_PIN(8, 9), 4, 3 }, /* SDA4 */ { RCAR_GP_PIN(8, 8), 0, 3 }, /* SCL4 */ } }, - { }, + { /* sentinel */ } }; enum ioctrl_regs { @@ -3896,30 +3974,49 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { [POC6] = { 0xE60610A0, }, [POC7] = { 0xE60618A0, }, [POC8] = { 0xE60680A0, }, - { /* sentinel */ }, + { /* 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)) + switch (pin) { + case RCAR_GP_PIN(0, 0) ... RCAR_GP_PIN(0, 18): + *pocctrl = pinmux_ioctrl_regs[POC0].reg; return bit; - *pocctrl = pinmux_ioctrl_regs[POC1].reg; - if (pin >= RCAR_GP_PIN(1, 0) && pin <= RCAR_GP_PIN(1, 22)) + case RCAR_GP_PIN(1, 0) ... RCAR_GP_PIN(1, 22): + *pocctrl = pinmux_ioctrl_regs[POC1].reg; return bit; - *pocctrl = pinmux_ioctrl_regs[POC3].reg; - if (pin >= RCAR_GP_PIN(3, 0) && pin <= RCAR_GP_PIN(3, 12)) + case RCAR_GP_PIN(3, 0) ... RCAR_GP_PIN(3, 12): + *pocctrl = pinmux_ioctrl_regs[POC3].reg; return bit; - *pocctrl = pinmux_ioctrl_regs[POC8].reg; - if (pin >= RCAR_GP_PIN(8, 0) && pin <= RCAR_GP_PIN(8, 13)) + case PIN_VDDQ_TSN0: + *pocctrl = pinmux_ioctrl_regs[POC4].reg; + return 0; + + case PIN_VDDQ_AVB2: + *pocctrl = pinmux_ioctrl_regs[POC5].reg; + return 0; + + case PIN_VDDQ_AVB1: + *pocctrl = pinmux_ioctrl_regs[POC6].reg; + return 0; + + case PIN_VDDQ_AVB0: + *pocctrl = pinmux_ioctrl_regs[POC7].reg; + return 0; + + case RCAR_GP_PIN(8, 0) ... RCAR_GP_PIN(8, 13): + *pocctrl = pinmux_ioctrl_regs[POC8].reg; return bit; - return -EINVAL; + default: + return -EINVAL; + } } static const struct pinmux_bias_reg pinmux_bias_regs[] = { @@ -4229,7 +4326,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { [30] = SH_PFC_PIN_NONE, [31] = SH_PFC_PIN_NONE, } }, - { /* sentinel */ }, + { /* sentinel */ } }; static const struct sh_pfc_soc_operations r8a779g0_pin_ops = { diff --git a/drivers/pinctrl/renesas/pfc-sh7203.c b/drivers/pinctrl/renesas/pfc-sh7203.c index 19735746b1bb..640564db2c0b 100644 --- a/drivers/pinctrl/renesas/pfc-sh7203.c +++ b/drivers/pinctrl/renesas/pfc-sh7203.c @@ -1509,7 +1509,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PF0MD_00, PF0MD_01, PF0MD_10, PF0MD_11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -1555,7 +1555,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA, PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7203_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7264.c b/drivers/pinctrl/renesas/pfc-sh7264.c index 30096925a70c..8417c4243dda 100644 --- a/drivers/pinctrl/renesas/pfc-sh7264.c +++ b/drivers/pinctrl/renesas/pfc-sh7264.c @@ -2031,7 +2031,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PK1_IN, PK1_OUT, PK0_IN, PK0_OUT )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2109,7 +2109,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA, PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA )) }, - { } + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7264_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7269.c b/drivers/pinctrl/renesas/pfc-sh7269.c index f59f558d75ae..3569093f17ae 100644 --- a/drivers/pinctrl/renesas/pfc-sh7269.c +++ b/drivers/pinctrl/renesas/pfc-sh7269.c @@ -2749,8 +2749,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PJ1_IN, PJ1_OUT, PJ0_IN, PJ0_OUT )) }, - - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2828,8 +2827,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA, PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA )) }, - - { } + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7269_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh73a0.c b/drivers/pinctrl/renesas/pfc-sh73a0.c index 4f54dfd5a967..ca5adf2095be 100644 --- a/drivers/pinctrl/renesas/pfc-sh73a0.c +++ b/drivers/pinctrl/renesas/pfc-sh73a0.c @@ -3876,7 +3876,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* RESERVED [1] */ )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -3980,7 +3980,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PORT295_DATA, PORT294_DATA, PORT293_DATA, PORT292_DATA, PORT291_DATA, PORT290_DATA, PORT289_DATA, PORT288_DATA )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_irq pinmux_irqs[] = { diff --git a/drivers/pinctrl/renesas/pfc-sh7720.c b/drivers/pinctrl/renesas/pfc-sh7720.c index 6eedcc5bbb4d..91434743fb1c 100644 --- a/drivers/pinctrl/renesas/pfc-sh7720.c +++ b/drivers/pinctrl/renesas/pfc-sh7720.c @@ -1103,7 +1103,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PTV1_FN, PTV1_OUT, 0, PTV1_IN, PTV0_FN, PTV0_OUT, 0, PTV0_IN )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -1179,7 +1179,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { 0, 0, 0, PTV4_DATA, PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7720_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7722.c b/drivers/pinctrl/renesas/pfc-sh7722.c index 4b82ac2c5e91..54b4625b52cf 100644 --- a/drivers/pinctrl/renesas/pfc-sh7722.c +++ b/drivers/pinctrl/renesas/pfc-sh7722.c @@ -1585,7 +1585,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { MSELB8_RGB, MSELB8_SYS, /* RESERVED [8] */ )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -1681,7 +1681,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { 0, 0, PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7722_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7723.c b/drivers/pinctrl/renesas/pfc-sh7723.c index 95344281966e..c1abdec9bf1d 100644 --- a/drivers/pinctrl/renesas/pfc-sh7723.c +++ b/drivers/pinctrl/renesas/pfc-sh7723.c @@ -1784,7 +1784,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PSD3_PSD2_FN1, PSD3_PSD2_FN2, 0, 0, PSD1_PSD0_FN1, PSD1_PSD0_FN2, 0, 0 )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -1880,7 +1880,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7723_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7724.c b/drivers/pinctrl/renesas/pfc-sh7724.c index 26517ad26a0f..5148a3460cc6 100644 --- a/drivers/pinctrl/renesas/pfc-sh7724.c +++ b/drivers/pinctrl/renesas/pfc-sh7724.c @@ -2059,7 +2059,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PSE1_0, PSE1_1, PSE0_0, PSE0_1)) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2155,7 +2155,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7724_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7734.c b/drivers/pinctrl/renesas/pfc-sh7734.c index 106a500ad13d..a0a5d8b94086 100644 --- a/drivers/pinctrl/renesas/pfc-sh7734.c +++ b/drivers/pinctrl/renesas/pfc-sh7734.c @@ -2366,7 +2366,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { GP_5_1_IN, GP_5_1_OUT, GP_5_0_IN, GP_5_0_OUT )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2383,7 +2383,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA, GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7734_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7757.c b/drivers/pinctrl/renesas/pfc-sh7757.c index 0d7857d7efef..817b22c3e639 100644 --- a/drivers/pinctrl/renesas/pfc-sh7757.c +++ b/drivers/pinctrl/renesas/pfc-sh7757.c @@ -2089,7 +2089,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PS8_8_FN1, PS8_8_FN2, /* RESERVED [8] */ )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -2197,7 +2197,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7757_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7785.c b/drivers/pinctrl/renesas/pfc-sh7785.c index 126b663bb6eb..0b6fbbac7c6d 100644 --- a/drivers/pinctrl/renesas/pfc-sh7785.c +++ b/drivers/pinctrl/renesas/pfc-sh7785.c @@ -1168,7 +1168,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { P2MSEL1_0, P2MSEL1_1, P2MSEL0_0, P2MSEL0_1 )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -1236,7 +1236,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { 0, 0, 0, 0, PR3_DATA, PR2_DATA, PR1_DATA, PR0_DATA )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7785_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-sh7786.c b/drivers/pinctrl/renesas/pfc-sh7786.c index f09f4a769010..a1ff39c5424d 100644 --- a/drivers/pinctrl/renesas/pfc-sh7786.c +++ b/drivers/pinctrl/renesas/pfc-sh7786.c @@ -747,7 +747,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { P2MSEL1_0, P2MSEL1_1, P2MSEL0_0, P2MSEL0_1 )) }, - {} + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -787,7 +787,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA, PJ3_DATA, PJ2_DATA, PJ1_DATA, 0 )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info sh7786_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-shx3.c b/drivers/pinctrl/renesas/pfc-shx3.c index 96a65d83774f..e2ba5e3b9ec3 100644 --- a/drivers/pinctrl/renesas/pfc-shx3.c +++ b/drivers/pinctrl/renesas/pfc-shx3.c @@ -502,7 +502,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { PH1_FN, PH1_OUT, PH1_IN, 0, PH0_FN, PH0_OUT, PH0_IN, 0, )) }, - { }, + { /* sentinel */ } }; static const struct pinmux_data_reg pinmux_data_regs[] = { @@ -538,7 +538,7 @@ static const struct pinmux_data_reg pinmux_data_regs[] = { 0, 0, PH5_DATA, PH4_DATA, PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, )) }, - { }, + { /* sentinel */ } }; const struct sh_pfc_soc_info shx3_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index 529c0fc4ec06..68c7af5d86bc 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -1388,7 +1388,7 @@ static const struct of_device_id rza1_pinctrl_of_match[] = { .compatible = "renesas,r7s72102-ports", .data = &rza1l_pmx_conf, }, - { } + { /* sentinel */ } }; static struct platform_driver rza1_pinctrl_driver = { @@ -1407,4 +1407,3 @@ core_initcall(rza1_pinctrl_init); MODULE_AUTHOR("Jacopo Mondi "); MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/A2 SoC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 04b31f0c6b34..9511d920565e 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -1570,4 +1570,3 @@ core_initcall(rzg2l_pinctrl_init); MODULE_AUTHOR("Lad Prabhakar "); MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/G2L family"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/renesas/pinctrl-rzn1.c b/drivers/pinctrl/renesas/pinctrl-rzn1.c index 9158c1757492..374b9f281324 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzn1.c +++ b/drivers/pinctrl/renesas/pinctrl-rzn1.c @@ -931,7 +931,7 @@ static int rzn1_pinctrl_remove(struct platform_device *pdev) static const struct of_device_id rzn1_pinctrl_match[] = { { .compatible = "renesas,rzn1-pinctrl", }, - {} + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rzn1_pinctrl_match); @@ -952,4 +952,3 @@ subsys_initcall(_pinctrl_drv_register); MODULE_AUTHOR("Phil Edworthy "); MODULE_DESCRIPTION("Renesas RZ/N1 pinctrl driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c index 3b65a71abd9a..e5472293bc7f 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c +++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c @@ -1117,4 +1117,3 @@ core_initcall(rzv2m_pinctrl_init); MODULE_AUTHOR("Phil Edworthy "); MODULE_DESCRIPTION("Pin and gpio controller driver for RZ/V2M"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/renesas/pinctrl.c b/drivers/pinctrl/renesas/pinctrl.c index b74147800319..4d9d58fc1356 100644 --- a/drivers/pinctrl/renesas/pinctrl.c +++ b/drivers/pinctrl/renesas/pinctrl.c @@ -40,10 +40,6 @@ struct sh_pfc_pinctrl { struct pinctrl_pin_desc *pins; struct sh_pfc_pin_config *configs; - - const char *func_prop_name; - const char *groups_prop_name; - const char *pins_prop_name; }; static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev) @@ -120,27 +116,10 @@ static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, const char *pin; int ret; - /* Support both the old Renesas-specific properties and the new standard - * properties. Mixing old and new properties isn't allowed, neither - * inside a subnode nor across subnodes. - */ - if (!pmx->func_prop_name) { - if (of_find_property(np, "groups", NULL) || - of_find_property(np, "pins", NULL)) { - pmx->func_prop_name = "function"; - pmx->groups_prop_name = "groups"; - pmx->pins_prop_name = "pins"; - } else { - pmx->func_prop_name = "renesas,function"; - pmx->groups_prop_name = "renesas,groups"; - pmx->pins_prop_name = "renesas,pins"; - } - } - /* Parse the function and configuration properties. At least a function * or one configuration must be specified. */ - ret = of_property_read_string(np, pmx->func_prop_name, &function); + ret = of_property_read_string(np, "function", &function); if (ret < 0 && ret != -EINVAL) { dev_err(dev, "Invalid function in DT\n"); return ret; @@ -158,7 +137,7 @@ static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, } /* Count the number of pins and groups and reallocate mappings. */ - ret = of_property_count_strings(np, pmx->pins_prop_name); + ret = of_property_count_strings(np, "pins"); if (ret == -EINVAL) { num_pins = 0; } else if (ret < 0) { @@ -168,7 +147,7 @@ static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, num_pins = ret; } - ret = of_property_count_strings(np, pmx->groups_prop_name); + ret = of_property_count_strings(np, "groups"); if (ret == -EINVAL) { num_groups = 0; } else if (ret < 0) { @@ -199,7 +178,7 @@ static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, *num_maps = nmaps; /* Iterate over pins and groups and create the mappings. */ - of_property_for_each_string(np, pmx->groups_prop_name, prop, group) { + of_property_for_each_string(np, "groups", prop, group) { if (function) { maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; maps[idx].data.mux.group = group; @@ -223,7 +202,7 @@ static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, goto done; } - of_property_for_each_string(np, pmx->pins_prop_name, prop, pin) { + of_property_for_each_string(np, "pins", prop, pin) { ret = sh_pfc_map_add_config(&maps[idx], pin, PIN_MAP_TYPE_CONFIGS_PIN, configs, num_configs); @@ -580,7 +559,7 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, return pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH; case PIN_CONFIG_POWER_SOURCE: - return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE; + return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE_MASK; default: return false; @@ -633,7 +612,7 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, case PIN_CONFIG_POWER_SOURCE: { int idx = sh_pfc_get_pin_index(pfc, _pin); const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; - unsigned int lower_voltage; + unsigned int mode, lo, hi; u32 pocctrl, val; int bit; @@ -646,10 +625,11 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, val = sh_pfc_read(pfc, pocctrl); - lower_voltage = (pin->configs & SH_PFC_PIN_VOLTAGE_25_33) ? - 2500 : 1800; + mode = pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE_MASK; + lo = mode <= SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 ? 1800 : 2500; + hi = mode >= SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 ? 3300 : 2500; - arg = (val & BIT(bit)) ? 3300 : lower_voltage; + arg = (val & BIT(bit)) ? hi : lo; break; } @@ -705,7 +685,7 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin, unsigned int mV = pinconf_to_config_argument(configs[i]); int idx = sh_pfc_get_pin_index(pfc, _pin); const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; - unsigned int lower_voltage; + unsigned int mode, lo, hi; u32 pocctrl, val; int bit; @@ -716,15 +696,16 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin, if (WARN(bit < 0, "invalid pin %#x", _pin)) return bit; - lower_voltage = (pin->configs & SH_PFC_PIN_VOLTAGE_25_33) ? - 2500 : 1800; + mode = pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE_MASK; + lo = mode <= SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 ? 1800 : 2500; + hi = mode >= SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 ? 3300 : 2500; - if (mV != lower_voltage && mV != 3300) + if (mV != lo && mV != hi) return -EINVAL; spin_lock_irqsave(&pfc->lock, flags); val = sh_pfc_read(pfc, pocctrl); - if (mV == 3300) + if (mV == hi) val |= BIT(bit); else val &= ~BIT(bit); diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h index 0fcb29ab0c84..8dc7a66009ad 100644 --- a/drivers/pinctrl/renesas/sh_pfc.h +++ b/drivers/pinctrl/renesas/sh_pfc.h @@ -29,16 +29,13 @@ enum { #define SH_PFC_PIN_CFG_PULL_DOWN (1 << 3) #define SH_PFC_PIN_CFG_PULL_UP_DOWN (SH_PFC_PIN_CFG_PULL_UP | \ SH_PFC_PIN_CFG_PULL_DOWN) -#define SH_PFC_PIN_CFG_IO_VOLTAGE (1 << 4) -#define SH_PFC_PIN_CFG_DRIVE_STRENGTH (1 << 5) -#define SH_PFC_PIN_VOLTAGE_18_33 (0 << 6) -#define SH_PFC_PIN_VOLTAGE_25_33 (1 << 6) +#define SH_PFC_PIN_CFG_IO_VOLTAGE_MASK GENMASK(5, 4) +#define SH_PFC_PIN_CFG_IO_VOLTAGE_18_25 (1 << 4) +#define SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 (2 << 4) +#define SH_PFC_PIN_CFG_IO_VOLTAGE_25_33 (3 << 4) -#define SH_PFC_PIN_CFG_IO_VOLTAGE_18_33 (SH_PFC_PIN_CFG_IO_VOLTAGE | \ - SH_PFC_PIN_VOLTAGE_18_33) -#define SH_PFC_PIN_CFG_IO_VOLTAGE_25_33 (SH_PFC_PIN_CFG_IO_VOLTAGE | \ - SH_PFC_PIN_VOLTAGE_25_33) +#define SH_PFC_PIN_CFG_DRIVE_STRENGTH (1 << 6) #define SH_PFC_PIN_CFG_NO_GPIO (1 << 31) @@ -314,7 +311,6 @@ extern const struct sh_pfc_soc_info r8a7791_pinmux_info; extern const struct sh_pfc_soc_info r8a7792_pinmux_info; extern const struct sh_pfc_soc_info r8a7793_pinmux_info; extern const struct sh_pfc_soc_info r8a7794_pinmux_info; -extern const struct sh_pfc_soc_info r8a77950_pinmux_info; extern const struct sh_pfc_soc_info r8a77951_pinmux_info; extern const struct sh_pfc_soc_info r8a77960_pinmux_info; extern const struct sh_pfc_soc_info r8a77961_pinmux_info; diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index ada401ef4342..722681e0b89b 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -301,6 +301,7 @@ static void plgpio_irq_disable(struct irq_data *d) spin_lock_irqsave(&plgpio->lock, flags); plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.ie); spin_unlock_irqrestore(&plgpio->lock, flags); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void plgpio_irq_enable(struct irq_data *d) @@ -317,6 +318,7 @@ static void plgpio_irq_enable(struct irq_data *d) return; } + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); spin_lock_irqsave(&plgpio->lock, flags); plgpio_reg_reset(plgpio->regmap, offset, plgpio->regs.ie); spin_unlock_irqrestore(&plgpio->lock, flags); @@ -356,11 +358,13 @@ static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) return 0; } -static struct irq_chip plgpio_irqchip = { +static const struct irq_chip plgpio_irqchip = { .name = "PLGPIO", .irq_enable = plgpio_irq_enable, .irq_disable = plgpio_irq_disable, .irq_set_type = plgpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static void plgpio_irq_handler(struct irq_desc *desc) @@ -595,7 +599,7 @@ static int plgpio_probe(struct platform_device *pdev) struct gpio_irq_chip *girq; girq = &plgpio->chip.irq; - girq->chip = &plgpio_irqchip; + gpio_irq_chip_set_chip(girq, &plgpio_irqchip); girq->parent_handler = plgpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, 1, diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 04ace4c7bd58..4b97bd00191b 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -1374,7 +1374,7 @@ static struct irq_domain *stm32_pctrl_get_irq_domain(struct platform_device *pde struct device_node *parent; struct irq_domain *domain; - if (!of_find_property(np, "interrupt-parent", NULL)) + if (!of_property_present(np, "interrupt-parent")) return NULL; parent = of_irq_find_parent(np); diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index f35179eceb4e..1dc1882cbdd7 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -224,16 +224,16 @@ static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev, static bool sunxi_pctrl_has_bias_prop(struct device_node *node) { - return of_find_property(node, "bias-pull-up", NULL) || - of_find_property(node, "bias-pull-down", NULL) || - of_find_property(node, "bias-disable", NULL) || - of_find_property(node, "allwinner,pull", NULL); + return of_property_present(node, "bias-pull-up") || + of_property_present(node, "bias-pull-down") || + of_property_present(node, "bias-disable") || + of_property_present(node, "allwinner,pull"); } static bool sunxi_pctrl_has_drive_prop(struct device_node *node) { - return of_find_property(node, "drive-strength", NULL) || - of_find_property(node, "allwinner,drive", NULL); + return of_property_present(node, "drive-strength") || + of_property_present(node, "allwinner,drive"); } static int sunxi_pctrl_parse_bias_prop(struct device_node *node) @@ -241,13 +241,13 @@ static int sunxi_pctrl_parse_bias_prop(struct device_node *node) u32 val; /* Try the new style binding */ - if (of_find_property(node, "bias-pull-up", NULL)) + if (of_property_present(node, "bias-pull-up")) return PIN_CONFIG_BIAS_PULL_UP; - if (of_find_property(node, "bias-pull-down", NULL)) + if (of_property_present(node, "bias-pull-down")) return PIN_CONFIG_BIAS_PULL_DOWN; - if (of_find_property(node, "bias-disable", NULL)) + if (of_property_present(node, "bias-disable")) return PIN_CONFIG_BIAS_DISABLE; /* And fall back to the old binding */ @@ -1424,7 +1424,7 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, return 0; /* If we don't have any setup, bail out */ - if (!of_find_property(node, "input-debounce", NULL)) + if (!of_property_present(node, "input-debounce")) return 0; losc = devm_clk_get(pctl->dev, "losc"); diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c index 69ceead8cdaa..a40f60bcefb6 100644 --- a/drivers/platform/chrome/wilco_ec/event.c +++ b/drivers/platform/chrome/wilco_ec/event.c @@ -58,7 +58,6 @@ #define DRV_NAME EVENT_DEV_NAME #define EVENT_DEV_NAME_FMT (EVENT_DEV_NAME "%d") static struct class event_class = { - .owner = THIS_MODULE, .name = EVENT_CLASS_NAME, }; diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c index 60da7a29f2ff..54708aa6c700 100644 --- a/drivers/platform/chrome/wilco_ec/telemetry.c +++ b/drivers/platform/chrome/wilco_ec/telemetry.c @@ -42,7 +42,6 @@ #define DRV_NAME TELEM_DEV_NAME #define TELEM_DEV_NAME_FMT (TELEM_DEV_NAME "%d") static struct class telem_class = { - .owner = THIS_MODULE, .name = TELEM_CLASS_NAME, }; diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index c2c9b0d3244c..be967d797c28 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -1348,9 +1348,8 @@ static int mlxbf_pmc_map_counters(struct device *dev) for (i = 0; i < pmc->total_blocks; ++i) { if (strstr(pmc->block_name[i], "tile")) { - ret = sscanf(pmc->block_name[i], "tile%d", &tile_num); - if (ret < 0) - return ret; + if (sscanf(pmc->block_name[i], "tile%d", &tile_num) != 1) + return -EINVAL; if (tile_num >= pmc->tile_count) continue; diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index 91a077c35b8b..a79318e90a13 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -784,7 +784,7 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) fifo = vring->fifo; /* Return if vdev is not ready. */ - if (!fifo->vdev[devid]) + if (!fifo || !fifo->vdev[devid]) return; /* Return if another vring is running. */ @@ -980,9 +980,13 @@ static int mlxbf_tmfifo_virtio_find_vqs(struct virtio_device *vdev, vq->num_max = vring->num; + vq->priv = vring; + + /* Make vq update visible before using it. */ + virtio_mb(false); + vqs[i] = vq; vring->vq = vq; - vq->priv = vring; } return 0; @@ -1302,6 +1306,9 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL); + /* Make all updates visible before setting the 'is_ready' flag. */ + virtio_mb(false); + fifo->is_ready = true; return 0; diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index d5bb775dadcf..ee5f124f78b6 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -245,24 +245,29 @@ static const struct pci_device_id pmf_pci_ids[] = { { } }; -int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) +static void amd_pmf_set_dram_addr(struct amd_pmf_dev *dev) { u64 phys_addr; u32 hi, low; - INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); - - /* Get Metrics Table Address */ - dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL); - if (!dev->buf) - return -ENOMEM; - phys_addr = virt_to_phys(dev->buf); hi = phys_addr >> 32; low = phys_addr & GENMASK(31, 0); amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL); amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL); +} + +int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) +{ + /* Get Metrics Table Address */ + dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + + INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); + + amd_pmf_set_dram_addr(dev); /* * Start collecting the metrics data after a small delay @@ -273,6 +278,18 @@ int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) return 0; } +static int amd_pmf_resume_handler(struct device *dev) +{ + struct amd_pmf_dev *pdev = dev_get_drvdata(dev); + + if (pdev->buf) + amd_pmf_set_dram_addr(pdev); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(amd_pmf_pm, NULL, amd_pmf_resume_handler); + static void amd_pmf_init_features(struct amd_pmf_dev *dev) { int ret; @@ -413,6 +430,7 @@ static struct platform_driver amd_pmf_driver = { .name = "amd-pmf", .acpi_match_table = amd_pmf_acpi_ids, .dev_groups = amd_pmf_driver_groups, + .pm = pm_sleep_ptr(&amd_pmf_pm), }, .probe = amd_pmf_probe, .remove_new = amd_pmf_remove, diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index e2c9a68d12df..fdf7da06af30 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -555,6 +555,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */ { KE_IGNORE, 0x79, }, /* Charger type dectection notification */ { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */ + { KE_IGNORE, 0x7B, }, /* Charger connect/disconnect notification */ { KE_KEY, 0x7c, { KEY_MICMUTE } }, { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ @@ -584,6 +585,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */ { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ { KE_KEY, 0xB5, { KEY_CALC } }, + { KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */ { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 873f59c3e280..6364ae262705 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -211,6 +211,7 @@ struct bios_rfkill2_state { static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x270, { KEY_MICMUTE } }, { KE_KEY, 0x20e6, { KEY_PROG1 } }, { KE_KEY, 0x20e8, { KEY_MEDIA } }, { KE_KEY, 0x2142, { KEY_MEDIA } }, diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 5fc665f7d9b3..2ab7d9ac542d 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -199,16 +199,26 @@ static int rtl_setup_sysfs(void) { ret = subsys_system_register(&rtl_subsys, NULL); if (!ret) { - for (i = 0; rtl_attributes[i]; i ++) - device_create_file(rtl_subsys.dev_root, rtl_attributes[i]); + struct device *dev_root = bus_get_dev_root(&rtl_subsys); + + if (dev_root) { + for (i = 0; rtl_attributes[i]; i ++) + device_create_file(dev_root, rtl_attributes[i]); + put_device(dev_root); + } } return ret; } static void rtl_teardown_sysfs(void) { + struct device *dev_root = bus_get_dev_root(&rtl_subsys); int i; - for (i = 0; rtl_attributes[i]; i ++) - device_remove_file(rtl_subsys.dev_root, rtl_attributes[i]); + + if (dev_root) { + for (i = 0; rtl_attributes[i]; i ++) + device_remove_file(dev_root, rtl_attributes[i]); + put_device(dev_root); + } bus_unregister(&rtl_subsys); } diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 61dffb4c8a1d..e6ae8265f3a3 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -208,7 +208,7 @@ static int scan_chunks_sanity_check(struct device *dev) continue; reinit_completion(&ifs_done); local_work.dev = dev; - INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks); + INIT_WORK_ONSTACK(&local_work.w, copy_hashes_authenticate_chunks); schedule_work_on(cpu, &local_work.w); wait_for_completion(&ifs_done); if (ifsd->loading_error) { diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c index d856d6b8fc03..01b7502f46b0 100644 --- a/drivers/platform/x86/intel/ifs/sysfs.c +++ b/drivers/platform/x86/intel/ifs/sysfs.c @@ -13,7 +13,7 @@ * Protects against simultaneous tests on multiple cores, or * reloading can file while a test is in progress */ -static DEFINE_SEMAPHORE(ifs_sem); +static DEFINE_SEMAPHORE(ifs_sem, 1); /* * The sysfs interface to check additional details of last test diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 0b96d75f5924..f32a233470de 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -155,7 +155,6 @@ ATTRIBUTE_GROUPS(intel_pmt); static struct class intel_pmt_class = { .name = "intel_pmt", - .owner = THIS_MODULE, .dev_groups = intel_pmt_groups, }; diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c index e0572a29212e..02fe360a59c7 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c @@ -304,14 +304,13 @@ struct isst_if_pkg_info { static struct isst_if_cpu_info *isst_cpu_info; static struct isst_if_pkg_info *isst_pkg_info; -#define ISST_MAX_PCI_DOMAINS 8 - static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn) { struct pci_dev *matched_pci_dev = NULL; struct pci_dev *pci_dev = NULL; + struct pci_dev *_pci_dev = NULL; int no_matches = 0, pkg_id; - int i, bus_number; + int bus_number; if (bus_no < 0 || bus_no >= ISST_MAX_BUS_NUMBER || cpu < 0 || cpu >= nr_cpu_ids || cpu >= num_possible_cpus()) @@ -323,12 +322,11 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn if (bus_number < 0) return NULL; - for (i = 0; i < ISST_MAX_PCI_DOMAINS; ++i) { - struct pci_dev *_pci_dev; + for_each_pci_dev(_pci_dev) { int node; - _pci_dev = pci_get_domain_bus_and_slot(i, bus_number, PCI_DEVFN(dev, fn)); - if (!_pci_dev) + if (_pci_dev->bus->number != bus_number || + _pci_dev->devfn != PCI_DEVFN(dev, fn)) continue; ++no_matches; diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c index cb24de9e97dc..064f186ae81b 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -44,14 +44,18 @@ static ssize_t store_min_max_freq_khz(struct uncore_data *data, int min_max) { unsigned int input; + int ret; if (kstrtouint(buf, 10, &input)) return -EINVAL; mutex_lock(&uncore_lock); - uncore_write(data, input, min_max); + ret = uncore_write(data, input, min_max); mutex_unlock(&uncore_lock); + if (ret) + return ret; + return count; } @@ -224,9 +228,15 @@ int uncore_freq_common_init(int (*read_control_freq)(struct uncore_data *data, u uncore_write = write_control_freq; uncore_read_freq = read_freq; - if (!uncore_root_kobj) - uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency", - &cpu_subsys.dev_root->kobj); + if (!uncore_root_kobj) { + struct device *dev_root = bus_get_dev_root(&cpu_subsys); + + if (dev_root) { + uncore_root_kobj = kobject_create_and_add("intel_uncore_frequency", + &dev_root->kobj); + put_device(dev_root); + } + } if (uncore_root_kobj) ++uncore_instance_count; mutex_unlock(&uncore_lock); diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index e7a3e3402817..6851d10d6582 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -82,7 +82,6 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ static struct class intel_scu_ipc_class = { .name = "intel_scu_ipc", - .owner = THIS_MODULE, }; /** diff --git a/drivers/platform/x86/intel_scu_pcidrv.c b/drivers/platform/x86/intel_scu_pcidrv.c index 80abc708e4f2..d904fad499aa 100644 --- a/drivers/platform/x86/intel_scu_pcidrv.c +++ b/drivers/platform/x86/intel_scu_pcidrv.c @@ -34,6 +34,7 @@ static int intel_scu_pci_probe(struct pci_dev *pdev, static const struct pci_device_id pci_ids[] = { { PCI_VDEVICE(INTEL, 0x080e) }, + { PCI_VDEVICE(INTEL, 0x082a) }, { PCI_VDEVICE(INTEL, 0x08ea) }, { PCI_VDEVICE(INTEL, 0x0a94) }, { PCI_VDEVICE(INTEL, 0x11a0) }, diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 6fe82f805ea8..b3808ad77278 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10318,6 +10318,7 @@ static atomic_t dytc_ignore_event = ATOMIC_INIT(0); static DEFINE_MUTEX(dytc_mutex); static int dytc_capabilities; static bool dytc_mmc_get_available; +static int profile_force; static int convert_dytc_to_profile(int funcmode, int dytcmode, enum platform_profile_option *profile) @@ -10580,6 +10581,21 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) if (err) return err; + /* Check if user wants to override the profile selection */ + if (profile_force) { + switch (profile_force) { + case -1: + dytc_capabilities = 0; + break; + case 1: + dytc_capabilities = BIT(DYTC_FC_MMC); + break; + case 2: + dytc_capabilities = BIT(DYTC_FC_PSC); + break; + } + pr_debug("Profile selection forced: 0x%x\n", dytc_capabilities); + } if (dytc_capabilities & BIT(DYTC_FC_MMC)) { /* MMC MODE */ pr_debug("MMC is supported\n"); /* @@ -10593,11 +10609,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) dytc_mmc_get_available = true; } } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { /* PSC MODE */ - /* Support for this only works on AMD platforms */ - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { - dbg_printk(TPACPI_DBG_INIT, "PSC not support on Intel platforms\n"); - return -ENODEV; - } pr_debug("PSC is supported\n"); } else { dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n"); @@ -11646,6 +11657,9 @@ MODULE_PARM_DESC(uwb_state, "Initial state of the emulated UWB switch"); #endif +module_param(profile_force, int, 0444); +MODULE_PARM_DESC(profile_force, "Force profile mode. -1=off, 1=MMC, 2=PSC"); + static void thinkpad_acpi_module_exit(void) { struct ibm_struct *ibm, *itmp; diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 13802a3c3591..68e66b60445c 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -336,6 +336,22 @@ static const struct ts_dmi_data dexp_ursus_7w_data = { .properties = dexp_ursus_7w_props, }; +static const struct property_entry dexp_ursus_kx210i_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 5), + PROPERTY_ENTRY_U32("touchscreen-min-y", 2), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1720), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1137), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-dexp-ursus-kx210i.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data dexp_ursus_kx210i_data = { + .acpi_name = "MSSL1680:00", + .properties = dexp_ursus_kx210i_props, +}; + static const struct property_entry digma_citi_e200_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), @@ -378,6 +394,11 @@ static const struct ts_dmi_data gdix1001_01_upside_down_data = { .properties = gdix1001_upside_down_props, }; +static const struct ts_dmi_data gdix1002_00_upside_down_data = { + .acpi_name = "GDIX1002:00", + .properties = gdix1001_upside_down_props, +}; + static const struct property_entry gp_electronic_t701_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 960), PROPERTY_ENTRY_U32("touchscreen-size-y", 640), @@ -1185,6 +1206,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "7W"), }, }, + { + /* DEXP Ursus KX210i */ + .driver_data = (void *)&dexp_ursus_kx210i_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "INSYDE Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "S107I"), + }, + }, { /* Digma Citi E200 */ .driver_data = (void *)&digma_citi_e200_data, @@ -1295,6 +1324,18 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), }, }, + { + /* Juno Tablet */ + .driver_data = (void *)&gdix1002_00_upside_down_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Default string"), + /* Both product- and board-name being "Default string" is somewhat rare */ + DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), + DMI_MATCH(DMI_BOARD_NAME, "Default string"), + /* Above matches are too generic, add partial bios-version match */ + DMI_MATCH(DMI_BIOS_VERSION, "JP2V1."), + }, + }, { /* Mediacom WinPad 7.0 W700 (same hw as Wintron surftab 7") */ .driver_data = (void *)&trekstor_surftab_wintron70_data, diff --git a/drivers/power/reset/as3722-poweroff.c b/drivers/power/reset/as3722-poweroff.c index 661e1c67f82e..80edff1a556f 100644 --- a/drivers/power/reset/as3722-poweroff.c +++ b/drivers/power/reset/as3722-poweroff.c @@ -84,4 +84,3 @@ module_platform_driver(as3722_poweroff_driver); MODULE_DESCRIPTION("Power off driver for ams AS3722 PMIC Device"); MODULE_ALIAS("platform:as3722-power-off"); MODULE_AUTHOR("Laxman Dewangan "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index 1c5af2fef142..84b3c3528afa 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -105,5 +105,4 @@ module_platform_driver(gpio_poweroff_driver); MODULE_AUTHOR("Jamie Lentin "); MODULE_DESCRIPTION("GPIO poweroff driver"); -MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:poweroff-gpio"); diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c index 5466eeea261c..35d981d5e6c8 100644 --- a/drivers/power/reset/gpio-restart.c +++ b/drivers/power/reset/gpio-restart.c @@ -139,4 +139,3 @@ module_platform_driver(gpio_restart_driver); MODULE_AUTHOR("David Riley "); MODULE_DESCRIPTION("GPIO restart driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c index c720112db704..83a4e1c9bf94 100644 --- a/drivers/power/reset/keystone-reset.c +++ b/drivers/power/reset/keystone-reset.c @@ -169,5 +169,4 @@ module_platform_driver(rsctrl_driver); MODULE_AUTHOR("Ivan Khoronzhuk "); MODULE_DESCRIPTION("Texas Instruments keystone reset driver"); -MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" KBUILD_MODNAME); diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 65d9528cc989..eea05921a054 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -317,4 +317,3 @@ module_platform_driver(ltc2952_poweroff_driver); MODULE_AUTHOR("René Moll "); MODULE_DESCRIPTION("LTC PowerPath power-off driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/mt6323-poweroff.c b/drivers/power/reset/mt6323-poweroff.c index d90e76fcb938..108167f7738b 100644 --- a/drivers/power/reset/mt6323-poweroff.c +++ b/drivers/power/reset/mt6323-poweroff.c @@ -97,4 +97,3 @@ module_platform_driver(mt6323_pwrc_driver); MODULE_DESCRIPTION("Poweroff driver for MT6323 PMIC"); MODULE_AUTHOR("Sean Wang "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c index 16bc01738be9..ebdcfb28c4a0 100644 --- a/drivers/power/reset/qcom-pon.c +++ b/drivers/power/reset/qcom-pon.c @@ -91,7 +91,7 @@ static struct platform_driver pm8916_pon_driver = { .probe = pm8916_pon_probe, .driver = { .name = "pm8916-pon", - .of_match_table = of_match_ptr(pm8916_pon_id_table), + .of_match_table = pm8916_pon_id_table, }, }; module_platform_driver(pm8916_pon_driver); diff --git a/drivers/power/reset/regulator-poweroff.c b/drivers/power/reset/regulator-poweroff.c index 20701203935f..7f87fbb8b051 100644 --- a/drivers/power/reset/regulator-poweroff.c +++ b/drivers/power/reset/regulator-poweroff.c @@ -79,5 +79,4 @@ module_platform_driver(regulator_poweroff_driver); MODULE_AUTHOR("Michael Klein "); MODULE_DESCRIPTION("Regulator poweroff driver"); -MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:poweroff-regulator"); diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index 04d4228119b2..28f1822db162 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c @@ -59,5 +59,4 @@ module_platform_driver(restart_poweroff_driver); MODULE_AUTHOR("Andrew Lunn "); MODULE_DESCRIPTION("TPS65086 restart driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 307ee6f71042..6f83e99d2eb7 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -624,10 +624,8 @@ static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data) */ static void ab8500_btemp_external_power_changed(struct power_supply *psy) { - struct ab8500_btemp *di = power_supply_get_drvdata(psy); - - class_for_each_device(power_supply_class, NULL, - di->btemp_psy, ab8500_btemp_get_ext_psy_data); + class_for_each_device(power_supply_class, NULL, psy, + ab8500_btemp_get_ext_psy_data); } /* ab8500 btemp driver interrupts and their respective isr */ diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 41a7bff9ac37..53560fbb6dcd 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2407,10 +2407,8 @@ out: */ static void ab8500_fg_external_power_changed(struct power_supply *psy) { - struct ab8500_fg *di = power_supply_get_drvdata(psy); - - class_for_each_device(power_supply_class, NULL, - di->fg_psy, ab8500_fg_get_ext_psy_data); + class_for_each_device(power_supply_class, NULL, psy, + ab8500_fg_get_ext_psy_data); } /** diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 15219ed43ce9..b5903193e2f9 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -836,6 +836,7 @@ static int axp288_charger_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct power_supply_config charger_cfg = {}; + const char *extcon_name = NULL; unsigned int val; /* @@ -872,8 +873,18 @@ static int axp288_charger_probe(struct platform_device *pdev) return PTR_ERR(info->cable.edev); } - if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) { - info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_NAME); + /* + * On devices with broken ACPI GPIO event handlers there also is no ACPI + * "INT3496" (USB_HOST_EXTCON_HID) device. x86-android-tablets.ko + * instantiates an "intel-int3496" extcon on these devs as a workaround. + */ + if (acpi_quirk_skip_gpio_event_handlers()) + extcon_name = "intel-int3496"; + else if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) + extcon_name = USB_HOST_EXTCON_NAME; + + if (extcon_name) { + info->otg.cable = extcon_get_extcon_dev(extcon_name); if (IS_ERR(info->otg.cable)) { dev_err_probe(dev, PTR_ERR(info->otg.cable), "extcon_get_extcon_dev(%s) failed\n", diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 05f413178462..3be6f3b10ea4 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -507,7 +507,7 @@ static void fuel_gauge_external_power_changed(struct power_supply *psy) mutex_lock(&info->lock); info->valid = 0; /* Force updating of the cached registers */ mutex_unlock(&info->lock); - power_supply_changed(info->bat); + power_supply_changed(psy); } static struct power_supply_desc fuel_gauge_desc = { diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index de67b985f0a9..dc33f00fcc06 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1262,6 +1262,7 @@ static void bq24190_input_current_limit_work(struct work_struct *work) bq24190_charger_set_property(bdi->charger, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); + power_supply_changed(bdi->charger); } /* Sync the input-current-limit with our parent supply (if we have one) */ diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index 103ddc2b3def..45e4ba30da98 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c @@ -1140,7 +1140,7 @@ static const struct i2c_device_id bq24257_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids); -static const struct of_device_id bq24257_of_match[] = { +static const struct of_device_id bq24257_of_match[] __maybe_unused = { { .compatible = "ti,bq24250", }, { .compatible = "ti,bq24251", }, { .compatible = "ti,bq24257", }, diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index 9cf4936440c9..e624834ae66c 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -70,6 +70,9 @@ #define BQ25611D_VBATREG_THRESH_uV 4290000 #define BQ25618_VBATREG_THRESH_uV 4300000 +#define BQ256XX_CHG_CONFIG_MASK BIT(4) +#define BQ256XX_CHG_CONFIG_BIT_SHIFT 4 + #define BQ256XX_ITERM_MASK GENMASK(3, 0) #define BQ256XX_ITERM_STEP_uA 60000 #define BQ256XX_ITERM_OFFSET_uA 60000 @@ -259,6 +262,7 @@ struct bq256xx_device { * @bq256xx_set_iterm: pointer to instance specific set_iterm function * @bq256xx_set_iprechg: pointer to instance specific set_iprechg function * @bq256xx_set_vindpm: pointer to instance specific set_vindpm function + * @bq256xx_set_charge_type: pointer to instance specific set_charge_type function * * @bq256xx_def_ichg: default ichg value in microamps * @bq256xx_def_iindpm: default iindpm value in microamps @@ -290,6 +294,7 @@ struct bq256xx_chip_info { int (*bq256xx_set_iterm)(struct bq256xx_device *bq, int iterm); int (*bq256xx_set_iprechg)(struct bq256xx_device *bq, int iprechg); int (*bq256xx_set_vindpm)(struct bq256xx_device *bq, int vindpm); + int (*bq256xx_set_charge_type)(struct bq256xx_device *bq, int type); int bq256xx_def_ichg; int bq256xx_def_iindpm; @@ -449,6 +454,27 @@ static int bq256xx_get_state(struct bq256xx_device *bq, return 0; } +static int bq256xx_set_charge_type(struct bq256xx_device *bq, int type) +{ + int chg_config = 0; + + switch (type) { + case POWER_SUPPLY_CHARGE_TYPE_NONE: + chg_config = 0x0; + break; + case POWER_SUPPLY_CHARGE_TYPE_TRICKLE: + case POWER_SUPPLY_CHARGE_TYPE_FAST: + chg_config = 0x1; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(bq->regmap, BQ256XX_CHARGER_CONTROL_0, + BQ256XX_CHG_CONFIG_MASK, + (chg_config ? 1 : 0) << BQ256XX_CHG_CONFIG_BIT_SHIFT); +} + static int bq256xx_get_ichg_curr(struct bq256xx_device *bq) { unsigned int charge_current_limit; @@ -915,6 +941,12 @@ static int bq256xx_set_charger_property(struct power_supply *psy, return ret; break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = bq->chip_info->bq256xx_set_charge_type(bq, val->intval); + if (ret) + return ret; + break; + default: break; } @@ -1197,6 +1229,7 @@ static int bq256xx_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_CHARGE_TYPE: return true; default: return false; @@ -1286,6 +1319,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq256xx_set_term_curr, .bq256xx_set_iprechg = bq256xx_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ2560X_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1316,6 +1350,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq256xx_set_term_curr, .bq256xx_set_iprechg = bq256xx_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ2560X_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1346,6 +1381,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq256xx_set_term_curr, .bq256xx_set_iprechg = bq256xx_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ2560X_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1376,6 +1412,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq256xx_set_term_curr, .bq256xx_set_iprechg = bq256xx_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ2560X_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1406,6 +1443,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq256xx_set_term_curr, .bq256xx_set_iprechg = bq256xx_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ25611D_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1436,6 +1474,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq25618_619_set_term_curr, .bq256xx_set_iprechg = bq25618_619_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ25618_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, @@ -1466,6 +1505,7 @@ static const struct bq256xx_chip_info bq256xx_chip_info_tbl[] = { .bq256xx_set_iterm = bq25618_619_set_term_curr, .bq256xx_set_iprechg = bq25618_619_set_prechrg_curr, .bq256xx_set_vindpm = bq256xx_set_input_volt_lim, + .bq256xx_set_charge_type = bq256xx_set_charge_type, .bq256xx_def_ichg = BQ25618_ICHG_DEF_uA, .bq256xx_def_iindpm = BQ256XX_IINDPM_DEF_uA, diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index bfe08d7bfaf3..f8636cf86505 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -750,7 +750,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy) if (bq->chip_version != BQ25892) return; - ret = power_supply_get_property_from_supplier(bq->charger, + ret = power_supply_get_property_from_supplier(psy, POWER_SUPPLY_PROP_USB_TYPE, &val); if (ret) @@ -775,6 +775,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy) } bq25890_field_write(bq, F_IINLIM, input_current_limit); + power_supply_changed(psy); } static int bq25890_get_chip_state(struct bq25890_device *bq, @@ -1106,6 +1107,8 @@ static void bq25890_pump_express_work(struct work_struct *data) dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n", voltage); + power_supply_changed(bq->charger); + return; error_print: bq25890_field_write(bq, F_PUMPX_EN, 0); @@ -1622,7 +1625,7 @@ static const struct i2c_device_id bq25890_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids); -static const struct of_device_id bq25890_of_match[] = { +static const struct of_device_id bq25890_of_match[] __maybe_unused = { { .compatible = "ti,bq25890", }, { .compatible = "ti,bq25892", }, { .compatible = "ti,bq25895", }, diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 5ff6f44fd47b..4296600e8912 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1083,10 +1083,8 @@ static int poll_interval_param_set(const char *val, const struct kernel_param *k return ret; mutex_lock(&bq27xxx_list_lock); - list_for_each_entry(di, &bq27xxx_battery_devices, list) { - cancel_delayed_work_sync(&di->work); - schedule_delayed_work(&di->work, 0); - } + list_for_each_entry(di, &bq27xxx_battery_devices, list) + mod_delayed_work(system_wq, &di->work, 0); mutex_unlock(&bq27xxx_list_lock); return ret; @@ -1761,60 +1759,6 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) return POWER_SUPPLY_HEALTH_GOOD; } -void bq27xxx_battery_update(struct bq27xxx_device_info *di) -{ - struct bq27xxx_reg_cache cache = {0, }; - bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; - - cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); - if ((cache.flags & 0xff) == 0xff) - cache.flags = -1; /* read error */ - if (cache.flags >= 0) { - cache.temperature = bq27xxx_battery_read_temperature(di); - if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) - cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); - if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) - cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); - if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) - cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); - - cache.charge_full = bq27xxx_battery_read_fcc(di); - cache.capacity = bq27xxx_battery_read_soc(di); - if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) - cache.energy = bq27xxx_battery_read_energy(di); - di->cache.flags = cache.flags; - cache.health = bq27xxx_battery_read_health(di); - if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) - cache.cycle_count = bq27xxx_battery_read_cyct(di); - - /* We only have to read charge design full once */ - if (di->charge_design_full <= 0) - di->charge_design_full = bq27xxx_battery_read_dcap(di); - } - - if ((di->cache.capacity != cache.capacity) || - (di->cache.flags != cache.flags)) - power_supply_changed(di->bat); - - if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) - di->cache = cache; - - di->last_update = jiffies; -} -EXPORT_SYMBOL_GPL(bq27xxx_battery_update); - -static void bq27xxx_battery_poll(struct work_struct *work) -{ - struct bq27xxx_device_info *di = - container_of(work, struct bq27xxx_device_info, - work.work); - - bq27xxx_battery_update(di); - - if (poll_interval > 0) - schedule_delayed_work(&di->work, poll_interval * HZ); -} - static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags) { if (di->opts & BQ27XXX_O_ZERO) @@ -1833,7 +1777,8 @@ static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags) static int bq27xxx_battery_current_and_status( struct bq27xxx_device_info *di, union power_supply_propval *val_curr, - union power_supply_propval *val_status) + union power_supply_propval *val_status, + struct bq27xxx_reg_cache *cache) { bool single_flags = (di->opts & BQ27XXX_O_ZERO); int curr; @@ -1845,10 +1790,14 @@ static int bq27xxx_battery_current_and_status( return curr; } - flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags); - if (flags < 0) { - dev_err(di->dev, "error reading flags\n"); - return flags; + if (cache) { + flags = cache->flags; + } else { + flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags); + if (flags < 0) { + dev_err(di->dev, "error reading flags\n"); + return flags; + } } if (di->opts & BQ27XXX_O_ZERO) { @@ -1883,6 +1832,78 @@ static int bq27xxx_battery_current_and_status( return 0; } +static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) +{ + union power_supply_propval status = di->last_status; + struct bq27xxx_reg_cache cache = {0, }; + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; + + cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); + if ((cache.flags & 0xff) == 0xff) + cache.flags = -1; /* read error */ + if (cache.flags >= 0) { + cache.temperature = bq27xxx_battery_read_temperature(di); + if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) + cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); + if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) + cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); + if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) + cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); + + cache.charge_full = bq27xxx_battery_read_fcc(di); + cache.capacity = bq27xxx_battery_read_soc(di); + if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) + cache.energy = bq27xxx_battery_read_energy(di); + di->cache.flags = cache.flags; + cache.health = bq27xxx_battery_read_health(di); + if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) + cache.cycle_count = bq27xxx_battery_read_cyct(di); + + /* + * On gauges with signed current reporting the current must be + * checked to detect charging <-> discharging status changes. + */ + if (!(di->opts & BQ27XXX_O_ZERO)) + bq27xxx_battery_current_and_status(di, NULL, &status, &cache); + + /* We only have to read charge design full once */ + if (di->charge_design_full <= 0) + di->charge_design_full = bq27xxx_battery_read_dcap(di); + } + + if ((di->cache.capacity != cache.capacity) || + (di->cache.flags != cache.flags) || + (di->last_status.intval != status.intval)) { + di->last_status.intval = status.intval; + power_supply_changed(di->bat); + } + + if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) + di->cache = cache; + + di->last_update = jiffies; + + if (!di->removed && poll_interval > 0) + mod_delayed_work(system_wq, &di->work, poll_interval * HZ); +} + +void bq27xxx_battery_update(struct bq27xxx_device_info *di) +{ + mutex_lock(&di->lock); + bq27xxx_battery_update_unlocked(di); + mutex_unlock(&di->lock); +} +EXPORT_SYMBOL_GPL(bq27xxx_battery_update); + +static void bq27xxx_battery_poll(struct work_struct *work) +{ + struct bq27xxx_device_info *di = + container_of(work, struct bq27xxx_device_info, + work.work); + + bq27xxx_battery_update(di); +} + /* * Get the average power in µW * Return < 0 if something fails. @@ -1985,10 +2006,8 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); mutex_lock(&di->lock); - if (time_is_before_jiffies(di->last_update + 5 * HZ)) { - cancel_delayed_work_sync(&di->work); - bq27xxx_battery_poll(&di->work.work); - } + if (time_is_before_jiffies(di->last_update + 5 * HZ)) + bq27xxx_battery_update_unlocked(di); mutex_unlock(&di->lock); if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) @@ -1996,7 +2015,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: - ret = bq27xxx_battery_current_and_status(di, NULL, val); + ret = bq27xxx_battery_current_and_status(di, NULL, val, NULL); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = bq27xxx_battery_voltage(di, val); @@ -2005,7 +2024,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, val->intval = di->cache.flags < 0 ? 0 : 1; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - ret = bq27xxx_battery_current_and_status(di, val, NULL); + ret = bq27xxx_battery_current_and_status(di, val, NULL, NULL); break; case POWER_SUPPLY_PROP_CAPACITY: ret = bq27xxx_simple_value(di->cache.capacity, val); @@ -2078,8 +2097,8 @@ static void bq27xxx_external_power_changed(struct power_supply *psy) { struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); - cancel_delayed_work_sync(&di->work); - schedule_delayed_work(&di->work, 0); + /* After charger plug in/out wait 0.5s for things to stabilize */ + mod_delayed_work(system_wq, &di->work, HZ / 2); } int bq27xxx_battery_setup(struct bq27xxx_device_info *di) @@ -2127,22 +2146,18 @@ EXPORT_SYMBOL_GPL(bq27xxx_battery_setup); void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) { - /* - * power_supply_unregister call bq27xxx_battery_get_property which - * call bq27xxx_battery_poll. - * Make sure that bq27xxx_battery_poll will not call - * schedule_delayed_work again after unregister (which cause OOPS). - */ - poll_interval = 0; - - cancel_delayed_work_sync(&di->work); - - power_supply_unregister(di->bat); - mutex_lock(&bq27xxx_list_lock); list_del(&di->list); mutex_unlock(&bq27xxx_list_lock); + /* Set removed to avoid bq27xxx_battery_update() re-queuing the work */ + mutex_lock(&di->lock); + di->removed = true; + mutex_unlock(&di->lock); + + cancel_delayed_work_sync(&di->work); + + power_supply_unregister(di->bat); mutex_destroy(&di->lock); } EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index f8768997333b..6d3c74876339 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -179,7 +179,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, di); if (client->irq) { - ret = devm_request_threaded_irq(&client->dev, client->irq, + ret = request_threaded_irq(client->irq, NULL, bq27xxx_battery_irq_handler_thread, IRQF_ONESHOT, di->name, di); @@ -209,6 +209,7 @@ static void bq27xxx_battery_i2c_remove(struct i2c_client *client) { struct bq27xxx_device_info *di = i2c_get_clientdata(client); + free_irq(client->irq, di); bq27xxx_battery_teardown(di); mutex_lock(&battery_mutex); diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index c9e8450c646f..5fa6ba7f41e1 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1331,7 +1331,7 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) of_property_read_string(np, "cm-thermal-zone", &desc->thermal_zone); of_property_read_u32(np, "cm-battery-cold", &desc->temp_min); - if (of_get_property(np, "cm-battery-cold-in-minus", NULL)) + if (of_property_read_bool(np, "cm-battery-cold-in-minus")) desc->temp_min *= -1; of_property_read_u32(np, "cm-battery-hot", &desc->temp_max); of_property_read_u32(np, "cm-battery-temp-diff", &desc->temp_diff); diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 66039c665dd1..7bdc6b263609 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -1,13 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Generic battery driver code using IIO + * Generic battery driver using IIO * Copyright (C) 2012, Anish Kumar - * based on jz4740-battery.c - * based on s3c_adc_battery.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * + * Copyright (c) 2023, Sebastian Reichel */ #include #include @@ -22,7 +17,8 @@ #include #include #include -#include +#include +#include #define JITTER_DEFAULT 10 /* hope 10ms is enough */ @@ -30,6 +26,7 @@ enum gab_chan_type { GAB_VOLTAGE = 0, GAB_CURRENT, GAB_POWER, + GAB_TEMP, GAB_MAX_CHAN_TYPE }; @@ -40,18 +37,16 @@ enum gab_chan_type { static const char *const gab_chan_name[] = { [GAB_VOLTAGE] = "voltage", [GAB_CURRENT] = "current", - [GAB_POWER] = "power", + [GAB_POWER] = "power", + [GAB_TEMP] = "temperature", }; struct gab { - struct power_supply *psy; - struct power_supply_desc psy_desc; - struct iio_channel *channel[GAB_MAX_CHAN_TYPE]; - struct gab_platform_data *pdata; + struct power_supply *psy; + struct power_supply_desc psy_desc; + struct iio_channel *channel[GAB_MAX_CHAN_TYPE]; struct delayed_work bat_work; - int level; - int status; - bool cable_plugged; + int status; struct gpio_desc *charge_finished; }; @@ -69,15 +64,6 @@ static void gab_ext_power_changed(struct power_supply *psy) static const enum power_supply_property gab_props[] = { POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_TECHNOLOGY, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_MODEL_NAME, }; /* @@ -88,6 +74,7 @@ static const enum power_supply_property gab_dyn_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_POWER_NOW, + POWER_SUPPLY_PROP_TEMP, }; static bool gab_charge_finished(struct gab *adc_bat) @@ -97,119 +84,53 @@ static bool gab_charge_finished(struct gab *adc_bat) return gpiod_get_value(adc_bat->charge_finished); } -static int gab_get_status(struct gab *adc_bat) -{ - struct gab_platform_data *pdata = adc_bat->pdata; - struct power_supply_info *bat_info; - - bat_info = &pdata->battery_info; - if (adc_bat->level == bat_info->charge_full_design) - return POWER_SUPPLY_STATUS_FULL; - return adc_bat->status; -} - -static enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp) -{ - switch (psp) { - case POWER_SUPPLY_PROP_POWER_NOW: - return GAB_POWER; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - return GAB_VOLTAGE; - case POWER_SUPPLY_PROP_CURRENT_NOW: - return GAB_CURRENT; - default: - WARN_ON(1); - break; - } - return GAB_POWER; -} - -static int read_channel(struct gab *adc_bat, enum power_supply_property psp, +static int gab_read_channel(struct gab *adc_bat, enum gab_chan_type channel, int *result) { int ret; - int chan_index; - chan_index = gab_prop_to_chan(psp); - ret = iio_read_channel_processed(adc_bat->channel[chan_index], - result); + ret = iio_read_channel_processed(adc_bat->channel[channel], result); if (ret < 0) - pr_err("read channel error\n"); + dev_err(&adc_bat->psy->dev, "read channel error: %d\n", ret); + else + *result *= 1000; + return ret; } static int gab_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - struct gab *adc_bat; - struct gab_platform_data *pdata; - struct power_supply_info *bat_info; - int result = 0; - int ret = 0; - - adc_bat = to_generic_bat(psy); - if (!adc_bat) { - dev_err(&psy->dev, "no battery infos ?!\n"); - return -EINVAL; - } - pdata = adc_bat->pdata; - bat_info = &pdata->battery_info; + struct gab *adc_bat = to_generic_bat(psy); switch (psp) { case POWER_SUPPLY_PROP_STATUS: - val->intval = gab_get_status(adc_bat); - break; - case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: - val->intval = 0; - break; - case POWER_SUPPLY_PROP_CHARGE_NOW: - val->intval = pdata->cal_charge(result); - break; + val->intval = adc_bat->status; + return 0; case POWER_SUPPLY_PROP_VOLTAGE_NOW: + return gab_read_channel(adc_bat, GAB_VOLTAGE, &val->intval); case POWER_SUPPLY_PROP_CURRENT_NOW: + return gab_read_channel(adc_bat, GAB_CURRENT, &val->intval); case POWER_SUPPLY_PROP_POWER_NOW: - ret = read_channel(adc_bat, psp, &result); - if (ret < 0) - goto err; - val->intval = result; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = bat_info->technology; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - val->intval = bat_info->voltage_min_design; - break; - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = bat_info->voltage_max_design; - break; - case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - val->intval = bat_info->charge_full_design; - break; - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = bat_info->name; - break; + return gab_read_channel(adc_bat, GAB_POWER, &val->intval); + case POWER_SUPPLY_PROP_TEMP: + return gab_read_channel(adc_bat, GAB_TEMP, &val->intval); default: return -EINVAL; } -err: - return ret; } static void gab_work(struct work_struct *work) { struct gab *adc_bat; struct delayed_work *delayed_work; - bool is_plugged; int status; delayed_work = to_delayed_work(work); adc_bat = container_of(delayed_work, struct gab, bat_work); status = adc_bat->status; - is_plugged = power_supply_am_i_supplied(adc_bat->psy); - adc_bat->cable_plugged = is_plugged; - - if (!is_plugged) + if (!power_supply_am_i_supplied(adc_bat->psy)) adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; else if (gab_charge_finished(adc_bat)) adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; @@ -223,12 +144,10 @@ static void gab_work(struct work_struct *work) static irqreturn_t gab_charged(int irq, void *dev_id) { struct gab *adc_bat = dev_id; - struct gab_platform_data *pdata = adc_bat->pdata; - int delay; - delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; schedule_delayed_work(&adc_bat->bat_work, - msecs_to_jiffies(delay)); + msecs_to_jiffies(JITTER_DEFAULT)); + return IRQ_HANDLED; } @@ -237,7 +156,6 @@ static int gab_probe(struct platform_device *pdev) struct gab *adc_bat; struct power_supply_desc *psy_desc; struct power_supply_config psy_cfg = {}; - struct gab_platform_data *pdata = pdev->dev.platform_data; enum power_supply_property *properties; int ret = 0; int chan; @@ -245,35 +163,31 @@ static int gab_probe(struct platform_device *pdev) bool any = false; adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); - if (!adc_bat) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + if (!adc_bat) return -ENOMEM; - } + psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = adc_bat; psy_desc = &adc_bat->psy_desc; - psy_desc->name = pdata->battery_info.name; + psy_desc->name = dev_name(&pdev->dev); /* bootup default values for the battery */ - adc_bat->cable_plugged = false; adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; psy_desc->get_property = gab_get_property; psy_desc->external_power_changed = gab_ext_power_changed; - adc_bat->pdata = pdata; /* * copying the static properties and allocating extra memory for holding * the extra configurable properties received from platform data. */ - properties = kcalloc(ARRAY_SIZE(gab_props) + - ARRAY_SIZE(gab_chan_name), - sizeof(*properties), - GFP_KERNEL); - if (!properties) { - ret = -ENOMEM; - goto first_mem_fail; - } + properties = devm_kcalloc(&pdev->dev, + ARRAY_SIZE(gab_props) + + ARRAY_SIZE(gab_chan_name), + sizeof(*properties), + GFP_KERNEL); + if (!properties) + return -ENOMEM; memcpy(properties, gab_props, sizeof(gab_props)); @@ -282,12 +196,13 @@ static int gab_probe(struct platform_device *pdev) * based on the channel supported by consumer device. */ for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { - adc_bat->channel[chan] = iio_channel_get(&pdev->dev, - gab_chan_name[chan]); + adc_bat->channel[chan] = devm_iio_channel_get(&pdev->dev, gab_chan_name[chan]); if (IS_ERR(adc_bat->channel[chan])) { ret = PTR_ERR(adc_bat->channel[chan]); + if (ret != -ENODEV) + return dev_err_probe(&pdev->dev, ret, "Failed to get ADC channel %s\n", gab_chan_name[chan]); adc_bat->channel[chan] = NULL; - } else { + } else if (adc_bat->channel[chan]) { /* copying properties for supported channels only */ int index2; @@ -302,10 +217,8 @@ static int gab_probe(struct platform_device *pdev) } /* none of the channels are supported so let's bail out */ - if (!any) { - ret = -ENODEV; - goto second_mem_fail; - } + if (!any) + return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get any ADC channel\n"); /* * Total number of properties is equal to static properties @@ -316,25 +229,24 @@ static int gab_probe(struct platform_device *pdev) psy_desc->properties = properties; psy_desc->num_properties = index; - adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); - if (IS_ERR(adc_bat->psy)) { - ret = PTR_ERR(adc_bat->psy); - goto err_reg_fail; - } + adc_bat->psy = devm_power_supply_register(&pdev->dev, psy_desc, &psy_cfg); + if (IS_ERR(adc_bat->psy)) + return dev_err_probe(&pdev->dev, PTR_ERR(adc_bat->psy), "Failed to register power-supply device\n"); - INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work); + ret = devm_delayed_work_autocancel(&pdev->dev, &adc_bat->bat_work, gab_work); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to register delayed work\n"); - adc_bat->charge_finished = devm_gpiod_get_optional(&pdev->dev, - "charged", GPIOD_IN); + adc_bat->charge_finished = devm_gpiod_get_optional(&pdev->dev, "charged", GPIOD_IN); if (adc_bat->charge_finished) { int irq; irq = gpiod_to_irq(adc_bat->charge_finished); - ret = request_any_context_irq(irq, gab_charged, + ret = devm_request_any_context_irq(&pdev->dev, irq, gab_charged, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "battery charged", adc_bat); if (ret < 0) - goto gpio_req_fail; + return dev_err_probe(&pdev->dev, ret, "Failed to register irq\n"); } platform_set_drvdata(pdev, adc_bat); @@ -343,38 +255,6 @@ static int gab_probe(struct platform_device *pdev) schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0)); return 0; - -gpio_req_fail: - power_supply_unregister(adc_bat->psy); -err_reg_fail: - for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { - if (adc_bat->channel[chan]) - iio_channel_release(adc_bat->channel[chan]); - } -second_mem_fail: - kfree(properties); -first_mem_fail: - return ret; -} - -static int gab_remove(struct platform_device *pdev) -{ - int chan; - struct gab *adc_bat = platform_get_drvdata(pdev); - - power_supply_unregister(adc_bat->psy); - - if (adc_bat->charge_finished) - free_irq(gpiod_to_irq(adc_bat->charge_finished), adc_bat); - - for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { - if (adc_bat->channel[chan]) - iio_channel_release(adc_bat->channel[chan]); - } - - kfree(adc_bat->psy_desc.properties); - cancel_delayed_work_sync(&adc_bat->bat_work); - return 0; } static int __maybe_unused gab_suspend(struct device *dev) @@ -389,26 +269,29 @@ static int __maybe_unused gab_suspend(struct device *dev) static int __maybe_unused gab_resume(struct device *dev) { struct gab *adc_bat = dev_get_drvdata(dev); - struct gab_platform_data *pdata = adc_bat->pdata; - int delay; - - delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; /* Schedule timer to check current status */ schedule_delayed_work(&adc_bat->bat_work, - msecs_to_jiffies(delay)); + msecs_to_jiffies(JITTER_DEFAULT)); + return 0; } static SIMPLE_DEV_PM_OPS(gab_pm_ops, gab_suspend, gab_resume); +static const struct of_device_id gab_match[] = { + { .compatible = "adc-battery" }, + { } +}; +MODULE_DEVICE_TABLE(of, gab_match); + static struct platform_driver gab_driver = { .driver = { .name = "generic-adc-battery", .pm = &gab_pm_ops, + .of_match_table = gab_match, }, .probe = gab_probe, - .remove = gab_remove, }; module_platform_driver(gab_driver); diff --git a/drivers/power/supply/lp8727_charger.c b/drivers/power/supply/lp8727_charger.c index e6c21377d53c..dc42d354b892 100644 --- a/drivers/power/supply/lp8727_charger.c +++ b/drivers/power/supply/lp8727_charger.c @@ -598,7 +598,7 @@ static void lp8727_remove(struct i2c_client *cl) lp8727_unregister_psy(pchg); } -static const struct of_device_id lp8727_dt_ids[] = { +static const struct of_device_id lp8727_dt_ids[] __maybe_unused = { { .compatible = "ti,lp8727", }, { } }; diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c index 0e95c65369b8..285580845e2f 100644 --- a/drivers/power/supply/ltc4162-l-charger.c +++ b/drivers/power/supply/ltc4162-l-charger.c @@ -908,7 +908,7 @@ static const struct i2c_device_id ltc4162l_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table); -static const struct of_device_id ltc4162l_of_match[] = { +static const struct of_device_id ltc4162l_of_match[] __maybe_unused = { { .compatible = "lltc,ltc4162-l", }, { }, }; diff --git a/drivers/power/supply/mt6360_charger.c b/drivers/power/supply/mt6360_charger.c index 92e48e3a4853..1305cba61edd 100644 --- a/drivers/power/supply/mt6360_charger.c +++ b/drivers/power/supply/mt6360_charger.c @@ -796,7 +796,9 @@ static int mt6360_charger_probe(struct platform_device *pdev) mci->vinovp = 6500000; mutex_init(&mci->chgdet_lock); platform_set_drvdata(pdev, mci); - devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work); + ret = devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to set delayed work\n"); ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp); if (ret) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 5bf35025cd90..3791aec69ddc 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -348,6 +348,10 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data) struct power_supply *psy = dev_get_drvdata(dev); unsigned int *count = data; + if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_SCOPE, &ret)) + if (ret.intval == POWER_SUPPLY_SCOPE_DEVICE) + return 0; + (*count)++; if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY) if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE, @@ -366,8 +370,8 @@ int power_supply_is_system_supplied(void) __power_supply_is_system_supplied); /* - * If no power class device was found at all, most probably we are - * running on a desktop system, so assume we are on mains power. + * If no system scope power class device was found at all, most probably we + * are running on a desktop system, so assume we are on mains power. */ if (count == 0) return 1; @@ -388,7 +392,7 @@ static int __power_supply_get_supplier_property(struct device *dev, void *_data) struct psy_get_supplier_prop_data *data = _data; if (__power_supply_is_supplied_by(epsy, data->psy)) - if (!epsy->desc->get_property(epsy, data->psp, data->val)) + if (!power_supply_get_property(epsy, data->psp, data->val)) return 1; /* Success */ return 0; /* Continue iterating */ @@ -573,7 +577,7 @@ int power_supply_get_battery_info(struct power_supply *psy, struct power_supply_battery_info *info; struct device_node *battery_np = NULL; struct fwnode_reference_args args; - struct fwnode_handle *fwnode; + struct fwnode_handle *fwnode = NULL; const char *value; int err, len, index; const __be32 *list; @@ -585,7 +589,7 @@ int power_supply_get_battery_info(struct power_supply *psy, return -ENODEV; fwnode = fwnode_handle_get(of_fwnode_handle(battery_np)); - } else { + } else if (psy->dev.parent) { err = fwnode_property_get_reference_args( dev_fwnode(psy->dev.parent), "monitored-battery", NULL, 0, 0, &args); @@ -595,6 +599,9 @@ int power_supply_get_battery_info(struct power_supply *psy, fwnode = args.fwnode; } + if (!fwnode) + return -ENOENT; + err = fwnode_property_read_string(fwnode, "compatible", &value); if (err) goto out_put_node; @@ -832,6 +839,133 @@ void power_supply_put_battery_info(struct power_supply *psy, } EXPORT_SYMBOL_GPL(power_supply_put_battery_info); +const enum power_supply_property power_supply_battery_info_properties[] = { + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN, + POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX, + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, + POWER_SUPPLY_PROP_TEMP_MIN, + POWER_SUPPLY_PROP_TEMP_MAX, +}; +EXPORT_SYMBOL_GPL(power_supply_battery_info_properties); + +const size_t power_supply_battery_info_properties_size = ARRAY_SIZE(power_supply_battery_info_properties); +EXPORT_SYMBOL_GPL(power_supply_battery_info_properties_size); + +bool power_supply_battery_info_has_prop(struct power_supply_battery_info *info, + enum power_supply_property psp) +{ + if (!info) + return false; + + switch (psp) { + case POWER_SUPPLY_PROP_TECHNOLOGY: + return info->technology != POWER_SUPPLY_TECHNOLOGY_UNKNOWN; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + return info->energy_full_design_uwh >= 0; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + return info->charge_full_design_uah >= 0; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + return info->voltage_min_design_uv >= 0; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + return info->voltage_max_design_uv >= 0; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + return info->precharge_current_ua >= 0; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return info->charge_term_current_ua >= 0; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + return info->constant_charge_current_max_ua >= 0; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + return info->constant_charge_voltage_max_uv >= 0; + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: + return info->temp_ambient_alert_min > INT_MIN; + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: + return info->temp_ambient_alert_max < INT_MAX; + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + return info->temp_alert_min > INT_MIN; + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + return info->temp_alert_max < INT_MAX; + case POWER_SUPPLY_PROP_TEMP_MIN: + return info->temp_min > INT_MIN; + case POWER_SUPPLY_PROP_TEMP_MAX: + return info->temp_max < INT_MAX; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(power_supply_battery_info_has_prop); + +int power_supply_battery_info_get_prop(struct power_supply_battery_info *info, + enum power_supply_property psp, + union power_supply_propval *val) +{ + if (!info) + return -EINVAL; + + if (!power_supply_battery_info_has_prop(info, psp)) + return -EINVAL; + + switch (psp) { + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = info->technology; + return 0; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = info->energy_full_design_uwh; + return 0; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = info->charge_full_design_uah; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = info->voltage_min_design_uv; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = info->voltage_max_design_uv; + return 0; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + val->intval = info->precharge_current_ua; + return 0; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + val->intval = info->charge_term_current_ua; + return 0; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + val->intval = info->constant_charge_current_max_ua; + return 0; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + val->intval = info->constant_charge_voltage_max_uv; + return 0; + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN: + val->intval = info->temp_ambient_alert_min; + return 0; + case POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX: + val->intval = info->temp_ambient_alert_max; + return 0; + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: + val->intval = info->temp_alert_min; + return 0; + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: + val->intval = info->temp_alert_max; + return 0; + case POWER_SUPPLY_PROP_TEMP_MIN: + val->intval = info->temp_min; + return 0; + case POWER_SUPPLY_PROP_TEMP_MAX: + val->intval = info->temp_max; + return 0; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(power_supply_battery_info_get_prop); + /** * power_supply_temp2resist_simple() - find the battery internal resistance * percent from temperature @@ -1046,6 +1180,22 @@ bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info, } EXPORT_SYMBOL_GPL(power_supply_battery_bti_in_range); +static bool psy_has_property(const struct power_supply_desc *psy_desc, + enum power_supply_property psp) +{ + bool found = false; + int i; + + for (i = 0; i < psy_desc->num_properties; i++) { + if (psy_desc->properties[i] == psp) { + found = true; + break; + } + } + + return found; +} + int power_supply_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -1056,7 +1206,12 @@ int power_supply_get_property(struct power_supply *psy, return -ENODEV; } - return psy->desc->get_property(psy, psp, val); + if (psy_has_property(psy->desc, psp)) + return psy->desc->get_property(psy, psp, val); + else if (power_supply_battery_info_has_prop(psy->battery_info, psp)) + return power_supply_battery_info_get_prop(psy->battery_info, psp, val); + else + return -EINVAL; } EXPORT_SYMBOL_GPL(power_supply_get_property); @@ -1117,22 +1272,6 @@ void power_supply_unreg_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); -static bool psy_has_property(const struct power_supply_desc *psy_desc, - enum power_supply_property psp) -{ - bool found = false; - int i; - - for (i = 0; i < psy_desc->num_properties; i++) { - if (psy_desc->properties[i] == psp) { - found = true; - break; - } - } - - return found; -} - #ifdef CONFIG_THERMAL static int power_supply_read_temp(struct thermal_zone_device *tzd, int *temp) @@ -1255,6 +1394,17 @@ __power_supply_register(struct device *parent, goto check_supplies_failed; } + /* + * Expose constant battery info, if it is available. While there are + * some chargers accessing constant battery data, we only want to + * expose battery data to userspace for battery devices. + */ + if (desc->type == POWER_SUPPLY_TYPE_BATTERY) { + rc = power_supply_get_battery_info(psy, &psy->battery_info); + if (rc && rc != -ENODEV && rc != -ENOENT) + goto check_supplies_failed; + } + spin_lock_init(&psy->changed_lock); rc = device_add(dev); if (rc) @@ -1462,7 +1612,7 @@ EXPORT_SYMBOL_GPL(power_supply_get_drvdata); static int __init power_supply_class_init(void) { - power_supply_class = class_create(THIS_MODULE, "power_supply"); + power_supply_class = class_create("power_supply"); if (IS_ERR(power_supply_class)) return PTR_ERR(power_supply_class); @@ -1485,4 +1635,3 @@ MODULE_DESCRIPTION("Universal power supply monitor class"); MODULE_AUTHOR("Ian Molton , " "Szabolcs Gyurko, " "Anton Vorontsov "); -MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c index 702bf83f6e6d..0674483279d7 100644 --- a/drivers/power/supply/power_supply_leds.c +++ b/drivers/power/supply/power_supply_leds.c @@ -35,8 +35,9 @@ static void power_supply_update_bat_leds(struct power_supply *psy) led_trigger_event(psy->charging_full_trig, LED_FULL); led_trigger_event(psy->charging_trig, LED_OFF); led_trigger_event(psy->full_trig, LED_FULL); - led_trigger_event(psy->charging_blink_full_solid_trig, - LED_FULL); + /* Going from blink to LED on requires a LED_OFF event to stop blink */ + led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF); + led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL); break; case POWER_SUPPLY_STATUS_CHARGING: led_trigger_event(psy->charging_full_trig, LED_FULL); diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index c228205e0953..06e5b6b0e255 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -221,9 +221,10 @@ static struct power_supply_attr power_supply_attrs[] = { POWER_SUPPLY_ATTR(MANUFACTURER), POWER_SUPPLY_ATTR(SERIAL_NUMBER), }; +#define POWER_SUPPLY_ATTR_CNT ARRAY_SIZE(power_supply_attrs) static struct attribute * -__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1]; +__power_supply_attrs[POWER_SUPPLY_ATTR_CNT + 1]; static struct power_supply_attr *to_ps_attr(struct device_attribute *attr) { @@ -285,7 +286,8 @@ static ssize_t power_supply_show_property(struct device *dev, if (ret < 0) { if (ret == -ENODATA) - dev_dbg(dev, "driver has no data for `%s' property\n", + dev_dbg_ratelimited(dev, + "driver has no data for `%s' property\n", attr->attr.name); else if (ret != -ENODEV && ret != -EAGAIN) dev_err_ratelimited(dev, @@ -380,6 +382,9 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj, } } + if (power_supply_battery_info_has_prop(psy->battery_info, attrno)) + return mode; + return 0; } @@ -461,6 +466,10 @@ static int add_prop_uevent(const struct device *dev, struct kobj_uevent_env *env int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env) { const struct power_supply *psy = dev_get_drvdata(dev); + const enum power_supply_property *battery_props = + power_supply_battery_info_properties; + unsigned long psy_drv_properties[POWER_SUPPLY_ATTR_CNT / + sizeof(unsigned long) + 1] = {0}; int ret = 0, j; char *prop_buf; @@ -482,12 +491,25 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env) goto out; for (j = 0; j < psy->desc->num_properties; j++) { + set_bit(psy->desc->properties[j], psy_drv_properties); ret = add_prop_uevent(dev, env, psy->desc->properties[j], prop_buf); if (ret) goto out; } + for (j = 0; j < power_supply_battery_info_properties_size; j++) { + if (test_bit(battery_props[j], psy_drv_properties)) + continue; + if (!power_supply_battery_info_has_prop(psy->battery_info, + battery_props[j])) + continue; + ret = add_prop_uevent(dev, env, battery_props[j], + prop_buf); + if (ret) + goto out; + } + out: free_page((unsigned long)prop_buf); diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index 36f807b5ec44..1a2143641e66 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -335,6 +335,20 @@ static int rk817_bat_calib_cap(struct rk817_charger *charger) charger->fcc_mah * 1000); } + /* + * Set the SOC to 0 if we are below the minimum system voltage. + */ + if (volt_avg <= charger->bat_voltage_min_design_uv) { + charger->soc = 0; + charge_now_adc = CHARGE_TO_ADC(0, charger->res_div); + put_unaligned_be32(charge_now_adc, bulk_reg); + regmap_bulk_write(rk808->regmap, + RK817_GAS_GAUGE_Q_INIT_H3, bulk_reg, 4); + dev_warn(charger->dev, + "Battery voltage %d below minimum voltage %d\n", + volt_avg, charger->bat_voltage_min_design_uv); + } + rk817_record_battery_nvram_values(charger); return 0; @@ -710,9 +724,10 @@ static int rk817_read_battery_nvram_values(struct rk817_charger *charger) /* * Read the nvram for state of charge. Sanity check for values greater - * than 100 (10000). If the value is off it should get corrected - * automatically when the voltage drops to the min (soc is 0) or when - * the battery is full (soc is 100). + * than 100 (10000) or less than 0, because other things (BSP kernels, + * U-Boot, or even i2cset) can write to this register. If the value is + * off it should get corrected automatically when the voltage drops to + * the min (soc is 0) or when the battery is full (soc is 100). */ ret = regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_R1, bulk_reg, 3); @@ -721,6 +736,8 @@ static int rk817_read_battery_nvram_values(struct rk817_charger *charger) charger->soc = get_unaligned_le24(bulk_reg); if (charger->soc > 10000) charger->soc = 10000; + if (charger->soc < 0) + charger->soc = 0; return 0; } @@ -731,8 +748,8 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger, { struct rk808 *rk808 = charger->rk808; u8 bulk_reg[4]; - u32 boot_voltage, boot_charge_mah, tmp; - int ret, reg, off_time; + u32 boot_voltage, boot_charge_mah; + int ret, reg, off_time, tmp; bool first_boot; /* @@ -785,10 +802,12 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger, regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3, bulk_reg, 4); tmp = get_unaligned_be32(bulk_reg); + if (tmp < 0) + tmp = 0; boot_charge_mah = ADC_TO_CHARGE_UAH(tmp, charger->res_div) / 1000; /* - * Check if the columb counter has been off for more than 300 + * Check if the columb counter has been off for more than 30 * minutes as it tends to drift downward. If so, re-init soc * with the boot voltage instead. Note the unit values for the * OFF_CNT register appear to be in decaminutes and stops @@ -799,7 +818,7 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger, * than 0 on a reboot anyway. */ regmap_read(rk808->regmap, RK817_GAS_GAUGE_OFF_CNT, &off_time); - if (off_time >= 30) { + if (off_time >= 3) { regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H, bulk_reg, 2); @@ -816,19 +835,6 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger, } } - regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H, - bulk_reg, 2); - tmp = get_unaligned_be16(bulk_reg); - boot_voltage = (charger->voltage_k * tmp) + 1000 * charger->voltage_b; - regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3, - bulk_reg, 4); - tmp = get_unaligned_be32(bulk_reg); - boot_charge_mah = ADC_TO_CHARGE_UAH(tmp, charger->res_div) / 1000; - regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_OCV_VOL_H, - bulk_reg, 2); - tmp = get_unaligned_be16(bulk_reg); - boot_voltage = (charger->voltage_k * tmp) + 1000 * charger->voltage_b; - /* * Now we have our full charge capacity and soc, init the columb * counter. diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c index 31fb6526a1fd..0149e00f2bf8 100644 --- a/drivers/power/supply/rt9455_charger.c +++ b/drivers/power/supply/rt9455_charger.c @@ -1722,7 +1722,7 @@ static const struct i2c_device_id rt9455_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, rt9455_i2c_id_table); -static const struct of_device_id rt9455_of_match[] = { +static const struct of_device_id rt9455_of_match[] __maybe_unused = { { .compatible = "richtek,rt9455", }, { }, }; diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index 73f744a3155d..ea33693b6977 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -1023,7 +1023,7 @@ static int rt9467_request_interrupt(struct rt9467_chg_data *data) for (i = 0; i < num_chg_irqs; i++) { virq = regmap_irq_get_virq(data->irq_chip_data, chg_irqs[i].hwirq); if (virq <= 0) - return dev_err_probe(dev, virq, "Failed to get (%s) irq\n", + return dev_err_probe(dev, -EINVAL, "Failed to get (%s) irq\n", chg_irqs[i].name); ret = devm_request_threaded_irq(dev, virq, NULL, chg_irqs[i].handler, diff --git a/drivers/power/supply/sbs-charger.c b/drivers/power/supply/sbs-charger.c index 75ebcbf0a788..a14e89ac0369 100644 --- a/drivers/power/supply/sbs-charger.c +++ b/drivers/power/supply/sbs-charger.c @@ -24,7 +24,7 @@ #define SBS_CHARGER_REG_STATUS 0x13 #define SBS_CHARGER_REG_ALARM_WARNING 0x16 -#define SBS_CHARGER_STATUS_CHARGE_INHIBITED BIT(1) +#define SBS_CHARGER_STATUS_CHARGE_INHIBITED BIT(0) #define SBS_CHARGER_STATUS_RES_COLD BIT(9) #define SBS_CHARGER_STATUS_RES_HOT BIT(10) #define SBS_CHARGER_STATUS_BATTERY_PRESENT BIT(14) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 632977f84b95..bd23c4d9fed4 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -733,13 +733,6 @@ static int sc27xx_fgu_set_property(struct power_supply *psy, return ret; } -static void sc27xx_fgu_external_power_changed(struct power_supply *psy) -{ - struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy); - - power_supply_changed(data->battery); -} - static int sc27xx_fgu_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { @@ -774,7 +767,7 @@ static const struct power_supply_desc sc27xx_fgu_desc = { .num_properties = ARRAY_SIZE(sc27xx_fgu_props), .get_property = sc27xx_fgu_get_property, .set_property = sc27xx_fgu_set_property, - .external_power_changed = sc27xx_fgu_external_power_changed, + .external_power_changed = power_supply_changed, .property_is_writeable = sc27xx_fgu_property_is_writeable, .no_thermal = true, }; diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 53a0ea5a61da..7adfd69fe649 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -1126,7 +1126,7 @@ static int twl4030_bci_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id twl_bci_of_match[] = { +static const struct of_device_id twl_bci_of_match[] __maybe_unused = { {.compatible = "ti,twl4030-bci", }, { } }; diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index a0e1eaa25d93..f4b190adb335 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -271,6 +271,5 @@ static struct platform_driver wm97xx_bat_driver = { module_platform_driver(wm97xx_bat_driver); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marek Vasut "); MODULE_DESCRIPTION("WM97xx battery driver"); diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 22a65ad4e46e..5d19baae6a38 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -456,7 +456,7 @@ static int __init pps_init(void) { int err; - pps_class = class_create(THIS_MODULE, "pps"); + pps_class = class_create("pps"); if (IS_ERR(pps_class)) { pr_err("failed to allocate class\n"); return PTR_ERR(pps_class); diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 62d4d29e7c05..790f9250b381 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -460,7 +460,7 @@ static int __init ptp_init(void) { int err; - ptp_class = class_create(THIS_MODULE, "ptp"); + ptp_class = class_create("ptp"); if (IS_ERR(ptp_class)) { pr_err("ptp: failed to allocate class\n"); return PTR_ERR(ptp_class); diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 2b63f3487645..ab8cab4d1560 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -34,7 +34,6 @@ #define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000 static struct class timecard_class = { - .owner = THIS_MODULE, .name = "timecard", }; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index dae023d783a2..8df861b1f4a3 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -51,6 +51,18 @@ config PWM_AB8500 To compile this driver as a module, choose M here: the module will be called pwm-ab8500. +config PWM_APPLE + tristate "Apple SoC PWM support" + depends on ARCH_APPLE || COMPILE_TEST + help + Generic PWM framework driver for PWM controller present on + Apple SoCs + + Say Y here if you have an ARM Apple laptop, otherwise say N + + To compile this driver as a module, choose M here: the module + will be called pwm-apple. + config PWM_ATMEL tristate "Atmel PWM support" depends on ARCH_AT91 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 7bf1a29f02b8..19899b912e00 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o +obj-$(CONFIG_PWM_APPLE) += pwm-apple.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 474725714a05..3dacceaef4a9 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -28,17 +28,11 @@ static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); -/* protects access to pwm_chips, allocated_pwms, and pwm_tree */ +/* protects access to pwm_chips and allocated_pwms */ static DEFINE_MUTEX(pwm_lock); static LIST_HEAD(pwm_chips); static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); -static RADIX_TREE(pwm_tree, GFP_KERNEL); - -static struct pwm_device *pwm_to_device(unsigned int pwm) -{ - return radix_tree_lookup(&pwm_tree, pwm); -} /* Called with pwm_lock held */ static int alloc_pwms(unsigned int count) @@ -59,14 +53,6 @@ static int alloc_pwms(unsigned int count) /* Called with pwm_lock held */ static void free_pwms(struct pwm_chip *chip) { - unsigned int i; - - for (i = 0; i < chip->npwm; i++) { - struct pwm_device *pwm = &chip->pwms[i]; - - radix_tree_delete(&pwm_tree, pwm->pwm); - } - bitmap_clear(allocated_pwms, chip->base, chip->npwm); kfree(chip->pwms); @@ -307,8 +293,6 @@ int pwmchip_add(struct pwm_chip *chip) pwm->chip = chip; pwm->pwm = chip->base + i; pwm->hwpwm = i; - - radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } list_add(&chip->list, &pwm_chips); @@ -369,43 +353,6 @@ int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip) } EXPORT_SYMBOL_GPL(devm_pwmchip_add); -/** - * pwm_request() - request a PWM device - * @pwm: global PWM device index - * @label: PWM device label - * - * This function is deprecated, use pwm_get() instead. - * - * Returns: A pointer to a PWM device or an ERR_PTR()-encoded error code on - * failure. - */ -struct pwm_device *pwm_request(int pwm, const char *label) -{ - struct pwm_device *dev; - int err; - - if (pwm < 0 || pwm >= MAX_PWMS) - return ERR_PTR(-EINVAL); - - mutex_lock(&pwm_lock); - - dev = pwm_to_device(pwm); - if (!dev) { - dev = ERR_PTR(-EPROBE_DEFER); - goto out; - } - - err = pwm_device_request(dev, label); - if (err < 0) - dev = ERR_PTR(err); - -out: - mutex_unlock(&pwm_lock); - - return dev; -} -EXPORT_SYMBOL_GPL(pwm_request); - /** * pwm_request_from_chip() - request a PWM device relative to a PWM chip * @chip: PWM chip @@ -438,18 +385,6 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, } EXPORT_SYMBOL_GPL(pwm_request_from_chip); -/** - * pwm_free() - free a PWM device - * @pwm: PWM device - * - * This function is deprecated, use pwm_put() instead. - */ -void pwm_free(struct pwm_device *pwm) -{ - pwm_put(pwm); -} -EXPORT_SYMBOL_GPL(pwm_free); - static void pwm_apply_state_debug(struct pwm_device *pwm, const struct pwm_state *state) { @@ -790,7 +725,7 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, dl = pwm_device_link_add(dev, pwm); if (IS_ERR(dl)) { /* of_xlate ended up calling pwm_request_from_chip() */ - pwm_free(pwm); + pwm_put(pwm); pwm = ERR_CAST(dl); goto put; } @@ -1014,7 +949,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) dl = pwm_device_link_add(dev, pwm); if (IS_ERR(dl)) { - pwm_free(pwm); + pwm_put(pwm); return ERR_CAST(dl); } diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c new file mode 100644 index 000000000000..a38a62edd713 --- /dev/null +++ b/drivers/pwm/pwm-apple.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Driver for the Apple SoC PWM controller + * + * Copyright The Asahi Linux Contributors + * + * Limitations: + * - The writes to cycle registers are shadowed until a write to + * the control register. + * - If both OFF_CYCLES and ON_CYCLES are set to 0, the output + * is a constant off signal. + * - When APPLE_PWM_CTRL is set to 0, the output is constant low + */ + +#include +#include +#include +#include +#include +#include + +#define APPLE_PWM_CTRL 0x00 +#define APPLE_PWM_ON_CYCLES 0x1c +#define APPLE_PWM_OFF_CYCLES 0x18 + +#define APPLE_PWM_CTRL_ENABLE BIT(0) +#define APPLE_PWM_CTRL_MODE BIT(2) +#define APPLE_PWM_CTRL_UPDATE BIT(5) +#define APPLE_PWM_CTRL_TRIGGER BIT(9) +#define APPLE_PWM_CTRL_INVERT BIT(10) +#define APPLE_PWM_CTRL_OUTPUT_ENABLE BIT(14) + +struct apple_pwm { + struct pwm_chip chip; + void __iomem *base; + u64 clkrate; +}; + +static inline struct apple_pwm *to_apple_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct apple_pwm, chip); +} + +static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct apple_pwm *fpwm; + + if (state->polarity == PWM_POLARITY_INVERSED) + return -EINVAL; + + fpwm = to_apple_pwm(chip); + if (state->enabled) { + u64 on_cycles, off_cycles; + + on_cycles = mul_u64_u64_div_u64(fpwm->clkrate, + state->duty_cycle, NSEC_PER_SEC); + if (on_cycles > 0xFFFFFFFF) + on_cycles = 0xFFFFFFFF; + + off_cycles = mul_u64_u64_div_u64(fpwm->clkrate, + state->period, NSEC_PER_SEC) - on_cycles; + if (off_cycles > 0xFFFFFFFF) + off_cycles = 0xFFFFFFFF; + + writel(on_cycles, fpwm->base + APPLE_PWM_ON_CYCLES); + writel(off_cycles, fpwm->base + APPLE_PWM_OFF_CYCLES); + writel(APPLE_PWM_CTRL_ENABLE | APPLE_PWM_CTRL_OUTPUT_ENABLE | APPLE_PWM_CTRL_UPDATE, + fpwm->base + APPLE_PWM_CTRL); + } else { + writel(0, fpwm->base + APPLE_PWM_CTRL); + } + return 0; +} + +static int apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct apple_pwm *fpwm; + u32 on_cycles, off_cycles, ctrl; + + fpwm = to_apple_pwm(chip); + + ctrl = readl(fpwm->base + APPLE_PWM_CTRL); + on_cycles = readl(fpwm->base + APPLE_PWM_ON_CYCLES); + off_cycles = readl(fpwm->base + APPLE_PWM_OFF_CYCLES); + + state->enabled = (ctrl & APPLE_PWM_CTRL_ENABLE) && (ctrl & APPLE_PWM_CTRL_OUTPUT_ENABLE); + state->polarity = PWM_POLARITY_NORMAL; + // on_cycles + off_cycles is 33 bits, NSEC_PER_SEC is 30, there is no overflow + state->duty_cycle = DIV64_U64_ROUND_UP((u64)on_cycles * NSEC_PER_SEC, fpwm->clkrate); + state->period = DIV64_U64_ROUND_UP(((u64)off_cycles + (u64)on_cycles) * + NSEC_PER_SEC, fpwm->clkrate); + + return 0; +} + +static const struct pwm_ops apple_pwm_ops = { + .apply = apple_pwm_apply, + .get_state = apple_pwm_get_state, + .owner = THIS_MODULE, +}; + +static int apple_pwm_probe(struct platform_device *pdev) +{ + struct apple_pwm *fpwm; + struct clk *clk; + int ret; + + fpwm = devm_kzalloc(&pdev->dev, sizeof(*fpwm), GFP_KERNEL); + if (!fpwm) + return -ENOMEM; + + fpwm->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(fpwm->base)) + return PTR_ERR(fpwm->base); + + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), "unable to get the clock"); + + /* + * Uses the 24MHz system clock on all existing devices, can only + * happen if the device tree is broken + * + * This check is done to prevent an overflow in .apply + */ + fpwm->clkrate = clk_get_rate(clk); + if (fpwm->clkrate > NSEC_PER_SEC) + return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock out of range"); + + fpwm->chip.dev = &pdev->dev; + fpwm->chip.npwm = 1; + fpwm->chip.ops = &apple_pwm_ops; + + ret = devm_pwmchip_add(&pdev->dev, &fpwm->chip); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "unable to add pwm chip"); + + return 0; +} + +static const struct of_device_id apple_pwm_of_match[] = { + { .compatible = "apple,s5l-fpwm" }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_pwm_of_match); + +static struct platform_driver apple_pwm_driver = { + .probe = apple_pwm_probe, + .driver = { + .name = "apple-pwm", + .of_match_table = apple_pwm_of_match, + }, +}; +module_platform_driver(apple_pwm_driver); + +MODULE_DESCRIPTION("Apple SoC PWM driver"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index a43b2babc809..96a709a9d49a 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -278,15 +278,13 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) return 0; } -static int atmel_hlcdc_pwm_remove(struct platform_device *pdev) +static void atmel_hlcdc_pwm_remove(struct platform_device *pdev) { struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev); pwmchip_remove(&chip->chip); clk_disable_unprepare(chip->hlcdc->periph_clk); - - return 0; } static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = { @@ -301,7 +299,7 @@ static struct platform_driver atmel_hlcdc_pwm_driver = { .pm = &atmel_hlcdc_pwm_pm_ops, }, .probe = atmel_hlcdc_pwm_probe, - .remove = atmel_hlcdc_pwm_remove, + .remove_new = atmel_hlcdc_pwm_remove, }; module_platform_driver(atmel_hlcdc_pwm_driver); diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 2837b4ce8053..4a116dc44f6e 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -500,7 +500,7 @@ err_slow_clk: return err; } -static int atmel_tcb_pwm_remove(struct platform_device *pdev) +static void atmel_tcb_pwm_remove(struct platform_device *pdev) { struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); @@ -509,8 +509,6 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev) clk_disable_unprepare(tcbpwm->slow_clk); clk_put(tcbpwm->slow_clk); clk_put(tcbpwm->clk); - - return 0; } static const struct of_device_id atmel_tcb_pwm_dt_ids[] = { @@ -564,7 +562,7 @@ static struct platform_driver atmel_tcb_pwm_driver = { .pm = &atmel_tcb_pwm_pm_ops, }, .probe = atmel_tcb_pwm_probe, - .remove = atmel_tcb_pwm_remove, + .remove_new = atmel_tcb_pwm_remove, }; module_platform_driver(atmel_tcb_pwm_driver); diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index cdbc23649032..0c567d9623cd 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -511,15 +511,13 @@ unprepare_clk: return ret; } -static int atmel_pwm_remove(struct platform_device *pdev) +static void atmel_pwm_remove(struct platform_device *pdev) { struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev); pwmchip_remove(&atmel_pwm->chip); clk_unprepare(atmel_pwm->clk); - - return 0; } static struct platform_driver atmel_pwm_driver = { @@ -528,7 +526,7 @@ static struct platform_driver atmel_pwm_driver = { .of_match_table = of_match_ptr(atmel_pwm_dt_ids), }, .probe = atmel_pwm_probe, - .remove = atmel_pwm_remove, + .remove_new = atmel_pwm_remove, }; module_platform_driver(atmel_pwm_driver); diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 97ec131eb7c1..7d70b6f186a6 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -239,15 +239,13 @@ static int iproc_pwmc_probe(struct platform_device *pdev) return ret; } -static int iproc_pwmc_remove(struct platform_device *pdev) +static void iproc_pwmc_remove(struct platform_device *pdev) { struct iproc_pwmc *ip = platform_get_drvdata(pdev); pwmchip_remove(&ip->chip); clk_disable_unprepare(ip->clk); - - return 0; } static const struct of_device_id bcm_iproc_pwmc_dt[] = { @@ -262,7 +260,7 @@ static struct platform_driver iproc_pwmc_driver = { .of_match_table = bcm_iproc_pwmc_dt, }, .probe = iproc_pwmc_probe, - .remove = iproc_pwmc_remove, + .remove_new = iproc_pwmc_remove, }; module_platform_driver(iproc_pwmc_driver); diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 50b8594be31d..bdfc2a5ec0d6 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -173,15 +173,13 @@ add_fail: return ret; } -static int bcm2835_pwm_remove(struct platform_device *pdev) +static void bcm2835_pwm_remove(struct platform_device *pdev) { struct bcm2835_pwm *pc = platform_get_drvdata(pdev); pwmchip_remove(&pc->chip); clk_disable_unprepare(pc->clk); - - return 0; } static const struct of_device_id bcm2835_pwm_of_match[] = { @@ -196,7 +194,7 @@ static struct platform_driver bcm2835_pwm_driver = { .of_match_table = bcm2835_pwm_of_match, }, .probe = bcm2835_pwm_probe, - .remove = bcm2835_pwm_remove, + .remove_new = bcm2835_pwm_remove, }; module_platform_driver(bcm2835_pwm_driver); diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index e157273fd2f7..0c5992a046b2 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -250,15 +250,13 @@ static int berlin_pwm_probe(struct platform_device *pdev) return 0; } -static int berlin_pwm_remove(struct platform_device *pdev) +static void berlin_pwm_remove(struct platform_device *pdev) { struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev); pwmchip_remove(&bpc->chip); clk_disable_unprepare(bpc->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -317,7 +315,7 @@ static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend, static struct platform_driver berlin_pwm_driver = { .probe = berlin_pwm_probe, - .remove = berlin_pwm_remove, + .remove_new = berlin_pwm_remove, .driver = { .name = "berlin-pwm", .of_match_table = berlin_pwm_match, diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index 3db3f96edf78..a3faa9a3de7c 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -275,14 +275,12 @@ out_clk: return ret; } -static int brcmstb_pwm_remove(struct platform_device *pdev) +static void brcmstb_pwm_remove(struct platform_device *pdev) { struct brcmstb_pwm *p = platform_get_drvdata(pdev); pwmchip_remove(&p->chip); clk_disable_unprepare(p->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -310,7 +308,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend, static struct platform_driver brcmstb_pwm_driver = { .probe = brcmstb_pwm_probe, - .remove = brcmstb_pwm_remove, + .remove_new = brcmstb_pwm_remove, .driver = { .name = "pwm-brcmstb", .of_match_table = brcmstb_pwm_of_match, diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c index c2a503d684a7..f1da99881adf 100644 --- a/drivers/pwm/pwm-clk.c +++ b/drivers/pwm/pwm-clk.c @@ -112,7 +112,7 @@ static int pwm_clk_probe(struct platform_device *pdev) return 0; } -static int pwm_clk_remove(struct platform_device *pdev) +static void pwm_clk_remove(struct platform_device *pdev) { struct pwm_clk_chip *pcchip = platform_get_drvdata(pdev); @@ -122,8 +122,6 @@ static int pwm_clk_remove(struct platform_device *pdev) clk_disable(pcchip->clk); clk_unprepare(pcchip->clk); - - return 0; } static const struct of_device_id pwm_clk_dt_ids[] = { @@ -138,7 +136,7 @@ static struct platform_driver pwm_clk_driver = { .of_match_table = pwm_clk_dt_ids, }, .probe = pwm_clk_probe, - .remove = pwm_clk_remove, + .remove_new = pwm_clk_remove, }; module_platform_driver(pwm_clk_driver); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index ad18b0ebe3f1..74e863aa1d8d 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -329,14 +329,12 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) return ret; } -static int cros_ec_pwm_remove(struct platform_device *dev) +static void cros_ec_pwm_remove(struct platform_device *dev) { struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev); struct pwm_chip *chip = &ec_pwm->chip; pwmchip_remove(chip); - - return 0; } #ifdef CONFIG_OF @@ -350,7 +348,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match); static struct platform_driver cros_ec_pwm_driver = { .probe = cros_ec_pwm_probe, - .remove = cros_ec_pwm_remove, + .remove_new = cros_ec_pwm_remove, .driver = { .name = "cros-ec-pwm", .of_match_table = of_match_ptr(cros_ec_pwm_of_match), diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 1b9274c5ad87..b95df1a96127 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -245,7 +245,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev) return 0; } -static int hibvt_pwm_remove(struct platform_device *pdev) +static void hibvt_pwm_remove(struct platform_device *pdev) { struct hibvt_pwm_chip *pwm_chip; @@ -258,8 +258,6 @@ static int hibvt_pwm_remove(struct platform_device *pdev) reset_control_deassert(pwm_chip->rstc); clk_disable_unprepare(pwm_chip->clk); - - return 0; } static const struct of_device_id hibvt_pwm_of_match[] = { @@ -281,7 +279,7 @@ static struct platform_driver hibvt_pwm_driver = { .of_match_table = hibvt_pwm_of_match, }, .probe = hibvt_pwm_probe, - .remove = hibvt_pwm_remove, + .remove_new = hibvt_pwm_remove, }; module_platform_driver(hibvt_pwm_driver); diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 89362afe3c91..326af85888e7 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -343,7 +343,7 @@ err_pm_disable: return ret; } -static int img_pwm_remove(struct platform_device *pdev) +static void img_pwm_remove(struct platform_device *pdev) { struct img_pwm_chip *imgchip = platform_get_drvdata(pdev); @@ -352,8 +352,6 @@ static int img_pwm_remove(struct platform_device *pdev) img_pwm_runtime_suspend(&pdev->dev); pwmchip_remove(&imgchip->chip); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -423,7 +421,7 @@ static struct platform_driver img_pwm_driver = { .of_match_table = img_pwm_of_match, }, .probe = img_pwm_probe, - .remove = img_pwm_remove, + .remove_new = img_pwm_remove, }; module_platform_driver(img_pwm_driver); diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index ed1aad96fff0..5e2b452ee5f2 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -381,15 +381,13 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev) return ret; } -static int pwm_imx_tpm_remove(struct platform_device *pdev) +static void pwm_imx_tpm_remove(struct platform_device *pdev) { struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev); pwmchip_remove(&tpm->chip); clk_disable_unprepare(tpm->clk); - - return 0; } static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev) @@ -432,7 +430,7 @@ static struct platform_driver imx_tpm_pwm_driver = { .pm = &imx_tpm_pwm_pm, }, .probe = pwm_imx_tpm_probe, - .remove = pwm_imx_tpm_remove, + .remove_new = pwm_imx_tpm_remove, }; module_platform_driver(imx_tpm_pwm_driver); diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 378e1df944dc..b9bf5b366f4b 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -449,7 +449,7 @@ disable_pwmclk: return ret; } -static int lpc18xx_pwm_remove(struct platform_device *pdev) +static void lpc18xx_pwm_remove(struct platform_device *pdev) { struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev); u32 val; @@ -461,8 +461,6 @@ static int lpc18xx_pwm_remove(struct platform_device *pdev) val | LPC18XX_PWM_CTRL_HALT); clk_disable_unprepare(lpc18xx_pwm->pwm_clk); - - return 0; } static struct platform_driver lpc18xx_pwm_driver = { @@ -471,7 +469,7 @@ static struct platform_driver lpc18xx_pwm_driver = { .of_match_table = lpc18xx_pwm_of_match, }, .probe = lpc18xx_pwm_probe, - .remove = lpc18xx_pwm_remove, + .remove_new = lpc18xx_pwm_remove, }; module_platform_driver(lpc18xx_pwm_driver); diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index f350607e28bd..319809aac2c4 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -62,10 +62,9 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev) return 0; } -static int pwm_lpss_remove_platform(struct platform_device *pdev) +static void pwm_lpss_remove_platform(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static const struct acpi_device_id pwm_lpss_acpi_match[] = { @@ -83,7 +82,7 @@ static struct platform_driver pwm_lpss_driver_platform = { .acpi_match_table = pwm_lpss_acpi_match, }, .probe = pwm_lpss_probe_platform, - .remove = pwm_lpss_remove_platform, + .remove_new = pwm_lpss_remove_platform, }; module_platform_driver(pwm_lpss_driver_platform); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 5cd7b90872c6..5732300eb004 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -418,7 +418,7 @@ static const struct meson_pwm_data pwm_axg_ee_data = { }; static const char * const pwm_axg_ao_parent_names[] = { - "aoclk81", "xtal", "fclk_div4", "fclk_div5" + "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5" }; static const struct meson_pwm_data pwm_axg_ao_data = { @@ -427,7 +427,7 @@ static const struct meson_pwm_data pwm_axg_ao_data = { }; static const char * const pwm_g12a_ao_ab_parent_names[] = { - "xtal", "aoclk81", "fclk_div4", "fclk_div5" + "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5" }; static const struct meson_pwm_data pwm_g12a_ao_ab_data = { @@ -436,7 +436,7 @@ static const struct meson_pwm_data pwm_g12a_ao_ab_data = { }; static const char * const pwm_g12a_ao_cd_parent_names[] = { - "xtal", "aoclk81", + "xtal", "g12a_ao_clk81", }; static const struct meson_pwm_data pwm_g12a_ao_cd_data = { diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 692a06121b28..79e321e96f56 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -138,6 +138,19 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, high_width = mul_u64_u64_div_u64(state->duty_cycle, rate, div); value = period | (high_width << PWM_HIGH_WIDTH_SHIFT); + if (mdp->data->bls_debug && !mdp->data->has_commit) { + /* + * For MT2701, disable double buffer before writing register + * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH. + */ + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, + mdp->data->bls_debug_mask, + mdp->data->bls_debug_mask); + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, + mdp->data->con0_sel, + mdp->data->con0_sel); + } + mtk_disp_pwm_update_bits(mdp, mdp->data->con0, PWM_CLKDIV_MASK, clk_div << PWM_CLKDIV_SHIFT); @@ -152,17 +165,6 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, mtk_disp_pwm_update_bits(mdp, mdp->data->commit, mdp->data->commit_mask, 0x0); - } else { - /* - * For MT2701, disable double buffer before writing register - * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH. - */ - mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, - mdp->data->bls_debug_mask, - mdp->data->bls_debug_mask); - mtk_disp_pwm_update_bits(mdp, mdp->data->con0, - mdp->data->con0_sel, - mdp->data->con0_sel); } mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask, @@ -194,6 +196,16 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip, return err; } + /* + * Apply DISP_PWM_DEBUG settings to choose whether to enable or disable + * registers double buffer and manual commit to working register before + * performing any read/write operation + */ + if (mdp->data->bls_debug) + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, + mdp->data->bls_debug_mask, + mdp->data->bls_debug_mask); + rate = clk_get_rate(mdp->clk_main); con0 = readl(mdp->base + mdp->data->con0); con1 = readl(mdp->base + mdp->data->con1); @@ -260,13 +272,11 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) return 0; } -static int mtk_disp_pwm_remove(struct platform_device *pdev) +static void mtk_disp_pwm_remove(struct platform_device *pdev) { struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev); pwmchip_remove(&mdp->chip); - - return 0; } static const struct mtk_pwm_data mt2701_pwm_data = { @@ -314,7 +324,7 @@ static struct platform_driver mtk_disp_pwm_driver = { .of_match_table = mtk_disp_pwm_of_match, }, .probe = mtk_disp_pwm_probe, - .remove = mtk_disp_pwm_remove, + .remove_new = mtk_disp_pwm_remove, }; module_platform_driver(mtk_disp_pwm_driver); diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index fa800fcf31d4..4889fbd8a431 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -441,7 +441,7 @@ err_find_timer_pdev: return ret; } -static int pwm_omap_dmtimer_remove(struct platform_device *pdev) +static void pwm_omap_dmtimer_remove(struct platform_device *pdev) { struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev); @@ -455,8 +455,6 @@ static int pwm_omap_dmtimer_remove(struct platform_device *pdev) put_device(&omap->dm_timer_pdev->dev); mutex_destroy(&omap->mutex); - - return 0; } static const struct of_device_id pwm_omap_dmtimer_of_match[] = { @@ -471,7 +469,7 @@ static struct platform_driver pwm_omap_dmtimer_driver = { .of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match), }, .probe = pwm_omap_dmtimer_probe, - .remove = pwm_omap_dmtimer_remove, + .remove_new = pwm_omap_dmtimer_remove, }; module_platform_driver(pwm_omap_dmtimer_driver); diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 55f46d09602b..5b5f357c44de 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -238,15 +238,13 @@ static int rcar_pwm_probe(struct platform_device *pdev) return 0; } -static int rcar_pwm_remove(struct platform_device *pdev) +static void rcar_pwm_remove(struct platform_device *pdev) { struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); pwmchip_remove(&rcar_pwm->chip); pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id rcar_pwm_of_table[] = { @@ -257,10 +255,10 @@ MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); static struct platform_driver rcar_pwm_driver = { .probe = rcar_pwm_probe, - .remove = rcar_pwm_remove, + .remove_new = rcar_pwm_remove, .driver = { .name = "pwm-rcar", - .of_match_table = of_match_ptr(rcar_pwm_of_table), + .of_match_table = rcar_pwm_of_table, } }; module_platform_driver(rcar_pwm_driver); diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 7f084eb34092..c1a1f2d864b5 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -376,7 +376,7 @@ err_clk: return ret; } -static int rockchip_pwm_remove(struct platform_device *pdev) +static void rockchip_pwm_remove(struct platform_device *pdev) { struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev); @@ -384,8 +384,6 @@ static int rockchip_pwm_remove(struct platform_device *pdev) clk_unprepare(pc->pclk); clk_unprepare(pc->clk); - - return 0; } static struct platform_driver rockchip_pwm_driver = { @@ -394,7 +392,7 @@ static struct platform_driver rockchip_pwm_driver = { .of_match_table = rockchip_pwm_dt_ids, }, .probe = rockchip_pwm_probe, - .remove = rockchip_pwm_remove, + .remove_new = rockchip_pwm_remove, }; module_platform_driver(rockchip_pwm_driver); diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 9c5b4f515641..e8828f57ab15 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -621,15 +621,13 @@ static int pwm_samsung_probe(struct platform_device *pdev) return 0; } -static int pwm_samsung_remove(struct platform_device *pdev) +static void pwm_samsung_remove(struct platform_device *pdev) { struct samsung_pwm_chip *chip = platform_get_drvdata(pdev); pwmchip_remove(&chip->chip); clk_disable_unprepare(chip->base_clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -676,7 +674,7 @@ static struct platform_driver pwm_samsung_driver = { .of_match_table = of_match_ptr(samsung_pwm_matches), }, .probe = pwm_samsung_probe, - .remove = pwm_samsung_remove, + .remove_new = pwm_samsung_remove, }; module_platform_driver(pwm_samsung_driver); diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 393a4b97fc19..5b0574f635f6 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -313,7 +313,7 @@ disable_clk: return ret; } -static int pwm_sifive_remove(struct platform_device *dev) +static void pwm_sifive_remove(struct platform_device *dev) { struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev); struct pwm_device *pwm; @@ -329,8 +329,6 @@ static int pwm_sifive_remove(struct platform_device *dev) } clk_unprepare(ddata->clk); - - return 0; } static const struct of_device_id pwm_sifive_of_match[] = { @@ -341,7 +339,7 @@ MODULE_DEVICE_TABLE(of, pwm_sifive_of_match); static struct platform_driver pwm_sifive_driver = { .probe = pwm_sifive_probe, - .remove = pwm_sifive_remove, + .remove_new = pwm_sifive_remove, .driver = { .name = "pwm-sifive", .of_match_table = pwm_sifive_of_match, diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 54c7990967dd..4e1cfd8d7c03 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -247,7 +247,7 @@ static int spear_pwm_probe(struct platform_device *pdev) return ret; } -static int spear_pwm_remove(struct platform_device *pdev) +static void spear_pwm_remove(struct platform_device *pdev) { struct spear_pwm_chip *pc = platform_get_drvdata(pdev); @@ -255,8 +255,6 @@ static int spear_pwm_remove(struct platform_device *pdev) /* clk was prepared in probe, hence unprepare it here */ clk_unprepare(pc->clk); - - return 0; } static const struct of_device_id spear_pwm_of_match[] = { @@ -273,7 +271,7 @@ static struct platform_driver spear_pwm_driver = { .of_match_table = spear_pwm_of_match, }, .probe = spear_pwm_probe, - .remove = spear_pwm_remove, + .remove_new = spear_pwm_remove, }; module_platform_driver(spear_pwm_driver); diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index bde579a338c2..d43a6fa3f4e0 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -280,13 +280,11 @@ static int sprd_pwm_probe(struct platform_device *pdev) return ret; } -static int sprd_pwm_remove(struct platform_device *pdev) +static void sprd_pwm_remove(struct platform_device *pdev) { struct sprd_pwm_chip *spc = platform_get_drvdata(pdev); pwmchip_remove(&spc->chip); - - return 0; } static const struct of_device_id sprd_pwm_of_match[] = { @@ -301,7 +299,7 @@ static struct platform_driver sprd_pwm_driver = { .of_match_table = sprd_pwm_of_match, }, .probe = sprd_pwm_probe, - .remove = sprd_pwm_remove, + .remove_new = sprd_pwm_remove, }; module_platform_driver(sprd_pwm_driver); diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 44b1f93256b3..b1d1373648a3 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -669,7 +669,7 @@ static int sti_pwm_probe(struct platform_device *pdev) return 0; } -static int sti_pwm_remove(struct platform_device *pdev) +static void sti_pwm_remove(struct platform_device *pdev) { struct sti_pwm_chip *pc = platform_get_drvdata(pdev); @@ -677,8 +677,6 @@ static int sti_pwm_remove(struct platform_device *pdev) clk_unprepare(pc->pwm_clk); clk_unprepare(pc->cpt_clk); - - return 0; } static const struct of_device_id sti_pwm_of_match[] = { @@ -693,7 +691,7 @@ static struct platform_driver sti_pwm_driver = { .of_match_table = sti_pwm_of_match, }, .probe = sti_pwm_probe, - .remove = sti_pwm_remove, + .remove_new = sti_pwm_remove, }; module_platform_driver(sti_pwm_driver); diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index f315fa106be8..bb3a045a7334 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -252,7 +252,7 @@ static struct platform_driver stm32_pwm_lp_driver = { .probe = stm32_pwm_lp_probe, .driver = { .name = "stm32-pwm-lp", - .of_match_table = of_match_ptr(stm32_pwm_lp_of_match), + .of_match_table = stm32_pwm_lp_of_match, .pm = &stm32_pwm_lp_pm_ops, }, }; diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 21e4a34dfff3..62e397aeb9aa 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -207,6 +207,10 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, regmap_write(priv->regmap, TIM_ARR, priv->max_arr); regmap_write(priv->regmap, TIM_PSC, psc); + /* Reset input selector to its default input and disable slave mode */ + regmap_write(priv->regmap, TIM_TISEL, 0x0); + regmap_write(priv->regmap, TIM_SMCR, 0x0); + /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ regmap_update_bits(priv->regmap, pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, @@ -642,7 +646,7 @@ static int stm32_pwm_probe(struct platform_device *pdev) return 0; } -static int stm32_pwm_remove(struct platform_device *pdev) +static void stm32_pwm_remove(struct platform_device *pdev) { struct stm32_pwm *priv = platform_get_drvdata(pdev); unsigned int i; @@ -651,8 +655,6 @@ static int stm32_pwm_remove(struct platform_device *pdev) pwm_disable(&priv->chip.pwms[i]); pwmchip_remove(&priv->chip); - - return 0; } static int __maybe_unused stm32_pwm_suspend(struct device *dev) @@ -699,7 +701,7 @@ MODULE_DEVICE_TABLE(of, stm32_pwm_of_match); static struct platform_driver stm32_pwm_driver = { .probe = stm32_pwm_probe, - .remove = stm32_pwm_remove, + .remove_new = stm32_pwm_remove, .driver = { .name = "stm32-pwm", .of_match_table = stm32_pwm_of_match, diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index b973da73e9ab..a8790a8fc53e 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -477,7 +477,7 @@ err_bus: return ret; } -static int sun4i_pwm_remove(struct platform_device *pdev) +static void sun4i_pwm_remove(struct platform_device *pdev) { struct sun4i_pwm_chip *sun4ichip = platform_get_drvdata(pdev); @@ -485,8 +485,6 @@ static int sun4i_pwm_remove(struct platform_device *pdev) clk_disable_unprepare(sun4ichip->bus_clk); reset_control_assert(sun4ichip->rst); - - return 0; } static struct platform_driver sun4i_pwm_driver = { @@ -495,7 +493,7 @@ static struct platform_driver sun4i_pwm_driver = { .of_match_table = sun4i_pwm_dt_ids, }, .probe = sun4i_pwm_probe, - .remove = sun4i_pwm_remove, + .remove_new = sun4i_pwm_remove, }; module_platform_driver(sun4i_pwm_driver); diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 249dc0193297..5810abf66e2a 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -350,7 +350,7 @@ put_pm: return ret; } -static int tegra_pwm_remove(struct platform_device *pdev) +static void tegra_pwm_remove(struct platform_device *pdev) { struct tegra_pwm_chip *pc = platform_get_drvdata(pdev); @@ -359,8 +359,6 @@ static int tegra_pwm_remove(struct platform_device *pdev) reset_control_assert(pc->rst); pm_runtime_force_suspend(&pdev->dev); - - return 0; } static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev) @@ -434,7 +432,7 @@ static struct platform_driver tegra_pwm_driver = { .pm = &tegra_pwm_pm_ops, }, .probe = tegra_pwm_probe, - .remove = tegra_pwm_remove, + .remove_new = tegra_pwm_remove, }; module_platform_driver(tegra_pwm_driver); diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 4701f0c9b921..109449956307 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -265,11 +265,9 @@ static int ecap_pwm_probe(struct platform_device *pdev) return 0; } -static int ecap_pwm_remove(struct platform_device *pdev) +static void ecap_pwm_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -326,7 +324,7 @@ static struct platform_driver ecap_pwm_driver = { .pm = &ecap_pwm_pm_ops, }, .probe = ecap_pwm_probe, - .remove = ecap_pwm_remove, + .remove_new = ecap_pwm_remove, }; module_platform_driver(ecap_pwm_driver); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 48ca0ff690ae..bb3959ace6b4 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -511,7 +511,7 @@ err_clk_unprepare: return ret; } -static int ehrpwm_pwm_remove(struct platform_device *pdev) +static void ehrpwm_pwm_remove(struct platform_device *pdev) { struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); @@ -520,8 +520,6 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev) clk_unprepare(pc->tbclk); pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -604,7 +602,7 @@ static struct platform_driver ehrpwm_pwm_driver = { .pm = &ehrpwm_pwm_pm_ops, }, .probe = ehrpwm_pwm_probe, - .remove = ehrpwm_pwm_remove, + .remove_new = ehrpwm_pwm_remove, }; module_platform_driver(ehrpwm_pwm_driver); diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index f1ff9940b37c..d2c48fd98706 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -279,20 +279,18 @@ static int vt8500_pwm_probe(struct platform_device *pdev) return ret; } -static int vt8500_pwm_remove(struct platform_device *pdev) +static void vt8500_pwm_remove(struct platform_device *pdev) { struct vt8500_chip *vt8500 = platform_get_drvdata(pdev); pwmchip_remove(&vt8500->chip); clk_unprepare(vt8500->clk); - - return 0; } static struct platform_driver vt8500_pwm_driver = { .probe = vt8500_pwm_probe, - .remove = vt8500_pwm_remove, + .remove_new = vt8500_pwm_remove, .driver = { .name = "vt8500-pwm", .of_match_table = vt8500_pwm_dt_ids, diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c index f7a50fdcd9a5..85153ee90809 100644 --- a/drivers/pwm/pwm-xilinx.c +++ b/drivers/pwm/pwm-xilinx.c @@ -292,14 +292,13 @@ static int xilinx_pwm_probe(struct platform_device *pdev) return 0; } -static int xilinx_pwm_remove(struct platform_device *pdev) +static void xilinx_pwm_remove(struct platform_device *pdev) { struct xilinx_pwm_device *xilinx_pwm = platform_get_drvdata(pdev); pwmchip_remove(&xilinx_pwm->chip); clk_rate_exclusive_put(xilinx_pwm->priv.clk); clk_disable_unprepare(xilinx_pwm->priv.clk); - return 0; } static const struct of_device_id xilinx_pwm_of_match[] = { @@ -310,7 +309,7 @@ MODULE_DEVICE_TABLE(of, xilinx_pwm_of_match); static struct platform_driver xilinx_pwm_driver = { .probe = xilinx_pwm_probe, - .remove = xilinx_pwm_remove, + .remove_new = xilinx_pwm_remove, .driver = { .name = "xilinx-pwm", .of_match_table = of_match_ptr(xilinx_pwm_of_match), diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index e7db8e45001c..1a106ec32939 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -475,7 +475,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_r static struct class pwm_class = { .name = "pwm", - .owner = THIS_MODULE, .dev_groups = pwm_chip_groups, .pm = pm_sleep_ptr(&pwm_class_pm_ops), }; diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 43db495f1986..a115730ebf14 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -2536,10 +2536,8 @@ static void mport_cdev_remove(struct mport_dev *md) /* * mport_add_mport() - Add rio_mport from LDM device struct * @dev: Linux device model struct - * @class_intf: Linux class_interface */ -static int mport_add_mport(struct device *dev, - struct class_interface *class_intf) +static int mport_add_mport(struct device *dev) { struct rio_mport *mport = NULL; struct mport_dev *chdev = NULL; @@ -2559,8 +2557,7 @@ static int mport_add_mport(struct device *dev, * mport_remove_mport() - Remove rio_mport from global list * TODO remove device from global mport_dev list */ -static void mport_remove_mport(struct device *dev, - struct class_interface *class_intf) +static void mport_remove_mport(struct device *dev) { struct rio_mport *mport = NULL; struct mport_dev *chdev; @@ -2603,7 +2600,7 @@ static int __init mport_init(void) int ret; /* Create device class needed by udev */ - dev_class = class_create(THIS_MODULE, DRV_NAME); + dev_class = class_create(DRV_NAME); if (IS_ERR(dev_class)) { rmcd_error("Unable to create " DRV_NAME " class"); return PTR_ERR(dev_class); diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 0a42d6a2af24..83323c3d10af 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -2924,7 +2924,6 @@ err_unmap_bars: iounmap(priv->odb_base); err_free_res: pci_release_regions(pdev); - pci_clear_master(pdev); err_disable_pdev: pci_disable_device(pdev); err_clean: @@ -2962,7 +2961,6 @@ static void tsi721_remove(struct pci_dev *pdev) pci_disable_msi(priv->pdev); #endif pci_release_regions(pdev); - pci_clear_master(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(priv); @@ -2977,7 +2975,6 @@ static void tsi721_shutdown(struct pci_dev *pdev) tsi721_disable_ints(priv); tsi721_dma_stop_all(priv); - pci_clear_master(pdev); pci_disable_device(pdev); } diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index e60e49769bed..1b3b4c2e015d 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c @@ -223,7 +223,6 @@ static int rio_uevent(const struct device *dev, struct kobj_uevent_env *env) struct class rio_mport_class = { .name = "rapidio_port", - .owner = THIS_MODULE, .dev_groups = rio_mport_groups, }; EXPORT_SYMBOL_GPL(rio_mport_class); diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index f7679602498e..90d391210533 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -286,7 +286,7 @@ const struct attribute_group *rio_dev_groups[] = { NULL, }; -static ssize_t scan_store(struct bus_type *bus, const char *buf, size_t count) +static ssize_t scan_store(const struct bus_type *bus, const char *buf, size_t count) { long val; int rc; diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c index db4c265287ae..49f8d111e546 100644 --- a/drivers/rapidio/rio_cm.c +++ b/drivers/rapidio/rio_cm.c @@ -2087,13 +2087,11 @@ static int riocm_cdev_add(dev_t devno) /* * riocm_add_mport - add new local mport device into channel management core * @dev: device object associated with mport - * @class_intf: class interface * * When a new mport device is added, CM immediately reserves inbound and * outbound RapidIO mailboxes that will be used. */ -static int riocm_add_mport(struct device *dev, - struct class_interface *class_intf) +static int riocm_add_mport(struct device *dev) { int rc; int i; @@ -2166,14 +2164,12 @@ static int riocm_add_mport(struct device *dev, /* * riocm_remove_mport - remove local mport device from channel management core * @dev: device object associated with mport - * @class_intf: class interface * * Removes a local mport device from the list of registered devices that provide * channel management services. Returns an error if the specified mport is not * registered with the CM core. */ -static void riocm_remove_mport(struct device *dev, - struct class_interface *class_intf) +static void riocm_remove_mport(struct device *dev) { struct rio_mport *mport = to_rio_mport(dev); struct cm_dev *cm; @@ -2297,7 +2293,7 @@ static int __init riocm_init(void) int ret; /* Create device class needed by udev */ - dev_class = class_create(THIS_MODULE, DRV_NAME); + dev_class = class_create(DRV_NAME); if (IS_ERR(dev_class)) { riocm_error("Cannot create " DRV_NAME " class"); return PTR_ERR(dev_class); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dc741ac156c3..698ab7f5004b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -5256,7 +5256,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) } rdev->debugfs = debugfs_create_dir(rname, debugfs_root); - if (!rdev->debugfs) { + if (IS_ERR(rdev->debugfs)) { rdev_warn(rdev, "Failed to create debugfs directory\n"); return; } @@ -6178,7 +6178,7 @@ static int __init regulator_init(void) ret = class_register(®ulator_class); debugfs_root = debugfs_create_dir("regulator", NULL); - if (!debugfs_root) + if (IS_ERR(debugfs_root)) pr_warn("regulator: Failed to create debugfs directory\n"); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index 1849566784ab..3eb86ec21d08 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -951,9 +951,12 @@ static int mt6359_regulator_probe(struct platform_device *pdev) struct regulator_config config = {}; struct regulator_dev *rdev; struct mt6359_regulator_info *mt6359_info; - int i, hw_ver; + int i, hw_ver, ret; + + ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); + if (ret) + return ret; - regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); if (hw_ver >= MT6359P_CHIP_VER) mt6359_info = mt6359p_regulators; else diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 87a746dcb516..e75dd92f86ca 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -264,7 +264,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0, .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, - .enable_mask = BUCK1_ENMODE_MASK, + .enable_mask = BUCK2_ENMODE_MASK, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -502,7 +502,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0, .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, - .enable_mask = BUCK1_ENMODE_MASK, + .enable_mask = BUCK2_ENMODE_MASK, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c index 68aa9d92953d..0e101dff6dda 100644 --- a/drivers/regulator/stm32-pwr.c +++ b/drivers/regulator/stm32-pwr.c @@ -183,4 +183,3 @@ module_platform_driver(stm32_pwr_driver); MODULE_DESCRIPTION("STM32MP1 PWR voltage regulator driver"); MODULE_AUTHOR("Pascal Paillet "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 80072b6b6283..695cce218e8c 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2766,5 +2766,4 @@ static void __exit remoteproc_exit(void) } module_exit(remoteproc_exit); -MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Generic Remote Processor Framework"); diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index 4b093420d98a..bc0e1603a7a3 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -249,7 +249,7 @@ void rproc_coredump(struct rproc *rproc) return; if (class == ELFCLASSNONE) { - dev_err(&rproc->dev, "Elf class is not set\n"); + dev_err(&rproc->dev, "ELF class is not set\n"); return; } @@ -361,7 +361,7 @@ void rproc_coredump_using_sections(struct rproc *rproc) return; if (class == ELFCLASSNONE) { - dev_err(&rproc->dev, "Elf class is not set\n"); + dev_err(&rproc->dev, "ELF class is not set\n"); return; } diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 5a412d7b6e0b..94177e416047 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Remote Processor Framework Elf loader + * Remote Processor Framework ELF loader * * Copyright (C) 2011 Texas Instruments, Inc. * Copyright (C) 2011 Google, Inc. @@ -39,7 +39,7 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw) const char *name = rproc->firmware; struct device *dev = &rproc->dev; /* - * Elf files are beginning with the same structure. Thus, to simplify + * ELF files are beginning with the same structure. Thus, to simplify * header parsing, we can use the elf32_hdr one for both elf64 and * elf32. */ diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 2a52c990d4fe..6aa8f243b30c 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -232,13 +232,6 @@ config RESET_SOCFPGA This enables the reset driver for the SoCFPGA ARMv7 platforms. This driver gets initialized early during platform init calls. -config RESET_STARFIVE_JH7100 - bool "StarFive JH7100 Reset Driver" - depends on SOC_STARFIVE || COMPILE_TEST - default SOC_STARFIVE - help - This enables the reset controller driver for the StarFive JH7100 SoC. - config RESET_SUNPLUS bool "Sunplus SoCs Reset Driver" if COMPILE_TEST default ARCH_SUNPLUS @@ -320,6 +313,7 @@ config RESET_ZYNQ help This enables the reset controller driver for Xilinx Zynq SoCs. +source "drivers/reset/starfive/Kconfig" source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" source "drivers/reset/tegra/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 3e7e5fd633a8..7fec5af6c964 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core.o obj-y += hisilicon/ +obj-y += starfive/ obj-$(CONFIG_ARCH_STI) += sti/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o @@ -30,7 +31,6 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o -obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c index b936cfe85641..549ba45d8597 100644 --- a/drivers/reset/reset-lantiq.c +++ b/drivers/reset/reset-lantiq.c @@ -207,4 +207,3 @@ module_platform_driver(lantiq_rcu_reset_driver); MODULE_AUTHOR("Martin Blumenstingl "); MODULE_DESCRIPTION("Lantiq XWAY RCU Reset Controller Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c index f3528dd1d084..ead25942061d 100644 --- a/drivers/reset/reset-microchip-sparx5.c +++ b/drivers/reset/reset-microchip-sparx5.c @@ -179,4 +179,3 @@ postcore_initcall(mchp_sparx5_reset_init); MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver"); MODULE_AUTHOR("Steen Hegelund "); -MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c index e003e50590ec..e71ab73092ab 100644 --- a/drivers/reset/reset-mpfs.c +++ b/drivers/reset/reset-mpfs.c @@ -153,5 +153,4 @@ module_auxiliary_driver(mpfs_reset_driver); MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver"); MODULE_AUTHOR("Conor Dooley "); -MODULE_LICENSE("GPL"); MODULE_IMPORT_NS(MCHP_CLK_MPFS); diff --git a/drivers/reset/reset-starfive-jh7100.c b/drivers/reset/reset-starfive-jh7100.c deleted file mode 100644 index fc44b2fb3e03..000000000000 --- a/drivers/reset/reset-starfive-jh7100.c +++ /dev/null @@ -1,173 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Reset driver for the StarFive JH7100 SoC - * - * Copyright (C) 2021 Emil Renner Berthing - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* register offsets */ -#define JH7100_RESET_ASSERT0 0x00 -#define JH7100_RESET_ASSERT1 0x04 -#define JH7100_RESET_ASSERT2 0x08 -#define JH7100_RESET_ASSERT3 0x0c -#define JH7100_RESET_STATUS0 0x10 -#define JH7100_RESET_STATUS1 0x14 -#define JH7100_RESET_STATUS2 0x18 -#define JH7100_RESET_STATUS3 0x1c - -/* - * Writing a 1 to the n'th bit of the m'th ASSERT register asserts - * line 32m + n, and writing a 0 deasserts the same line. - * Most reset lines have their status inverted so a 0 bit in the STATUS - * register means the line is asserted and a 1 means it's deasserted. A few - * lines don't though, so store the expected value of the status registers when - * all lines are asserted. - */ -static const u64 jh7100_reset_asserted[2] = { - /* STATUS0 */ - BIT_ULL_MASK(JH7100_RST_U74) | - BIT_ULL_MASK(JH7100_RST_VP6_DRESET) | - BIT_ULL_MASK(JH7100_RST_VP6_BRESET) | - /* STATUS1 */ - BIT_ULL_MASK(JH7100_RST_HIFI4_DRESET) | - BIT_ULL_MASK(JH7100_RST_HIFI4_BRESET), - /* STATUS2 */ - BIT_ULL_MASK(JH7100_RST_E24) | - /* STATUS3 */ - 0, -}; - -struct jh7100_reset { - struct reset_controller_dev rcdev; - /* protect registers against concurrent read-modify-write */ - spinlock_t lock; - void __iomem *base; -}; - -static inline struct jh7100_reset * -jh7100_reset_from(struct reset_controller_dev *rcdev) -{ - return container_of(rcdev, struct jh7100_reset, rcdev); -} - -static int jh7100_reset_update(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct jh7100_reset *data = jh7100_reset_from(rcdev); - unsigned long offset = BIT_ULL_WORD(id); - u64 mask = BIT_ULL_MASK(id); - void __iomem *reg_assert = data->base + JH7100_RESET_ASSERT0 + offset * sizeof(u64); - void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); - u64 done = jh7100_reset_asserted[offset] & mask; - u64 value; - unsigned long flags; - int ret; - - if (!assert) - done ^= mask; - - spin_lock_irqsave(&data->lock, flags); - - value = readq(reg_assert); - if (assert) - value |= mask; - else - value &= ~mask; - writeq(value, reg_assert); - - /* if the associated clock is gated, deasserting might otherwise hang forever */ - ret = readq_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); - - spin_unlock_irqrestore(&data->lock, flags); - return ret; -} - -static int jh7100_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return jh7100_reset_update(rcdev, id, true); -} - -static int jh7100_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return jh7100_reset_update(rcdev, id, false); -} - -static int jh7100_reset_reset(struct reset_controller_dev *rcdev, - unsigned long id) -{ - int ret; - - ret = jh7100_reset_assert(rcdev, id); - if (ret) - return ret; - - return jh7100_reset_deassert(rcdev, id); -} - -static int jh7100_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct jh7100_reset *data = jh7100_reset_from(rcdev); - unsigned long offset = BIT_ULL_WORD(id); - u64 mask = BIT_ULL_MASK(id); - void __iomem *reg_status = data->base + JH7100_RESET_STATUS0 + offset * sizeof(u64); - u64 value = readq(reg_status); - - return !((value ^ jh7100_reset_asserted[offset]) & mask); -} - -static const struct reset_control_ops jh7100_reset_ops = { - .assert = jh7100_reset_assert, - .deassert = jh7100_reset_deassert, - .reset = jh7100_reset_reset, - .status = jh7100_reset_status, -}; - -static int __init jh7100_reset_probe(struct platform_device *pdev) -{ - struct jh7100_reset *data; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->base)) - return PTR_ERR(data->base); - - data->rcdev.ops = &jh7100_reset_ops; - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = JH7100_RSTN_END; - data->rcdev.dev = &pdev->dev; - data->rcdev.of_node = pdev->dev.of_node; - spin_lock_init(&data->lock); - - return devm_reset_controller_register(&pdev->dev, &data->rcdev); -} - -static const struct of_device_id jh7100_reset_dt_ids[] = { - { .compatible = "starfive,jh7100-reset" }, - { /* sentinel */ } -}; - -static struct platform_driver jh7100_reset_driver = { - .driver = { - .name = "jh7100-reset", - .of_match_table = jh7100_reset_dt_ids, - .suppress_bind_attrs = true, - }, -}; -builtin_platform_driver_probe(jh7100_reset_driver, jh7100_reset_probe); diff --git a/drivers/reset/starfive/Kconfig b/drivers/reset/starfive/Kconfig new file mode 100644 index 000000000000..1fa706a2c3dc --- /dev/null +++ b/drivers/reset/starfive/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config RESET_STARFIVE_JH71X0 + bool + +config RESET_STARFIVE_JH7100 + bool "StarFive JH7100 Reset Driver" + depends on ARCH_STARFIVE || COMPILE_TEST + select RESET_STARFIVE_JH71X0 + default ARCH_STARFIVE + help + This enables the reset controller driver for the StarFive JH7100 SoC. + +config RESET_STARFIVE_JH7110 + bool "StarFive JH7110 Reset Driver" + depends on AUXILIARY_BUS && CLK_STARFIVE_JH7110_SYS + select RESET_STARFIVE_JH71X0 + default ARCH_STARFIVE + help + This enables the reset controller driver for the StarFive JH7110 SoC. diff --git a/drivers/reset/starfive/Makefile b/drivers/reset/starfive/Makefile new file mode 100644 index 000000000000..7a44b66fb9d5 --- /dev/null +++ b/drivers/reset/starfive/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_RESET_STARFIVE_JH71X0) += reset-starfive-jh71x0.o + +obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o +obj-$(CONFIG_RESET_STARFIVE_JH7110) += reset-starfive-jh7110.o diff --git a/drivers/reset/starfive/reset-starfive-jh7100.c b/drivers/reset/starfive/reset-starfive-jh7100.c new file mode 100644 index 000000000000..2a56f7fd4ba7 --- /dev/null +++ b/drivers/reset/starfive/reset-starfive-jh7100.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Reset driver for the StarFive JH7100 SoC + * + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include +#include + +#include "reset-starfive-jh71x0.h" + +#include + +/* register offsets */ +#define JH7100_RESET_ASSERT0 0x00 +#define JH7100_RESET_ASSERT1 0x04 +#define JH7100_RESET_ASSERT2 0x08 +#define JH7100_RESET_ASSERT3 0x0c +#define JH7100_RESET_STATUS0 0x10 +#define JH7100_RESET_STATUS1 0x14 +#define JH7100_RESET_STATUS2 0x18 +#define JH7100_RESET_STATUS3 0x1c + +/* + * Writing a 1 to the n'th bit of the m'th ASSERT register asserts + * line 32m + n, and writing a 0 deasserts the same line. + * Most reset lines have their status inverted so a 0 bit in the STATUS + * register means the line is asserted and a 1 means it's deasserted. A few + * lines don't though, so store the expected value of the status registers when + * all lines are asserted. + */ +static const u32 jh7100_reset_asserted[4] = { + /* STATUS0 */ + BIT(JH7100_RST_U74 % 32) | + BIT(JH7100_RST_VP6_DRESET % 32) | + BIT(JH7100_RST_VP6_BRESET % 32), + /* STATUS1 */ + BIT(JH7100_RST_HIFI4_DRESET % 32) | + BIT(JH7100_RST_HIFI4_BRESET % 32), + /* STATUS2 */ + BIT(JH7100_RST_E24 % 32), + /* STATUS3 */ + 0, +}; + +static int __init jh7100_reset_probe(struct platform_device *pdev) +{ + void __iomem *base = devm_platform_ioremap_resource(pdev, 0); + + if (IS_ERR(base)) + return PTR_ERR(base); + + return reset_starfive_jh71x0_register(&pdev->dev, pdev->dev.of_node, + base + JH7100_RESET_ASSERT0, + base + JH7100_RESET_STATUS0, + jh7100_reset_asserted, + JH7100_RSTN_END, + THIS_MODULE); +} + +static const struct of_device_id jh7100_reset_dt_ids[] = { + { .compatible = "starfive,jh7100-reset" }, + { /* sentinel */ } +}; + +static struct platform_driver jh7100_reset_driver = { + .driver = { + .name = "jh7100-reset", + .of_match_table = jh7100_reset_dt_ids, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver_probe(jh7100_reset_driver, jh7100_reset_probe); diff --git a/drivers/reset/starfive/reset-starfive-jh7110.c b/drivers/reset/starfive/reset-starfive-jh7110.c new file mode 100644 index 000000000000..2d26ae95c8cc --- /dev/null +++ b/drivers/reset/starfive/reset-starfive-jh7110.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Reset driver for the StarFive JH7110 SoC + * + * Copyright (C) 2022 StarFive Technology Co., Ltd. + */ + +#include + +#include + +#include "reset-starfive-jh71x0.h" + +#include + +struct jh7110_reset_info { + unsigned int nr_resets; + unsigned int assert_offset; + unsigned int status_offset; +}; + +static const struct jh7110_reset_info jh7110_sys_info = { + .nr_resets = JH7110_SYSRST_END, + .assert_offset = 0x2F8, + .status_offset = 0x308, +}; + +static const struct jh7110_reset_info jh7110_aon_info = { + .nr_resets = JH7110_AONRST_END, + .assert_offset = 0x38, + .status_offset = 0x3C, +}; + +static int jh7110_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct jh7110_reset_info *info = (struct jh7110_reset_info *)(id->driver_data); + struct jh71x0_reset_adev *rdev = to_jh71x0_reset_adev(adev); + void __iomem *base = rdev->base; + + if (!info || !base) + return -ENODEV; + + return reset_starfive_jh71x0_register(&adev->dev, adev->dev.parent->of_node, + base + info->assert_offset, + base + info->status_offset, + NULL, + info->nr_resets, + NULL); +} + +static const struct auxiliary_device_id jh7110_reset_ids[] = { + { + .name = "clk_starfive_jh7110_sys.rst-sys", + .driver_data = (kernel_ulong_t)&jh7110_sys_info, + }, + { + .name = "clk_starfive_jh7110_sys.rst-aon", + .driver_data = (kernel_ulong_t)&jh7110_aon_info, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, jh7110_reset_ids); + +static struct auxiliary_driver jh7110_reset_driver = { + .probe = jh7110_reset_probe, + .id_table = jh7110_reset_ids, +}; +module_auxiliary_driver(jh7110_reset_driver); + +MODULE_AUTHOR("Hal Feng "); +MODULE_DESCRIPTION("StarFive JH7110 reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/starfive/reset-starfive-jh71x0.c b/drivers/reset/starfive/reset-starfive-jh71x0.c new file mode 100644 index 000000000000..55bbbd2de52c --- /dev/null +++ b/drivers/reset/starfive/reset-starfive-jh71x0.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Reset driver for the StarFive JH71X0 SoCs + * + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include +#include +#include +#include +#include +#include + +#include "reset-starfive-jh71x0.h" + +struct jh71x0_reset { + struct reset_controller_dev rcdev; + /* protect registers against concurrent read-modify-write */ + spinlock_t lock; + void __iomem *assert; + void __iomem *status; + const u32 *asserted; +}; + +static inline struct jh71x0_reset * +jh71x0_reset_from(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct jh71x0_reset, rcdev); +} + +static int jh71x0_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct jh71x0_reset *data = jh71x0_reset_from(rcdev); + unsigned long offset = id / 32; + u32 mask = BIT(id % 32); + void __iomem *reg_assert = data->assert + offset * sizeof(u32); + void __iomem *reg_status = data->status + offset * sizeof(u32); + u32 done = data->asserted ? data->asserted[offset] & mask : 0; + u32 value; + unsigned long flags; + int ret; + + if (!assert) + done ^= mask; + + spin_lock_irqsave(&data->lock, flags); + + value = readl(reg_assert); + if (assert) + value |= mask; + else + value &= ~mask; + writel(value, reg_assert); + + /* if the associated clock is gated, deasserting might otherwise hang forever */ + ret = readl_poll_timeout_atomic(reg_status, value, (value & mask) == done, 0, 1000); + + spin_unlock_irqrestore(&data->lock, flags); + return ret; +} + +static int jh71x0_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return jh71x0_reset_update(rcdev, id, true); +} + +static int jh71x0_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return jh71x0_reset_update(rcdev, id, false); +} + +static int jh71x0_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = jh71x0_reset_assert(rcdev, id); + if (ret) + return ret; + + return jh71x0_reset_deassert(rcdev, id); +} + +static int jh71x0_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct jh71x0_reset *data = jh71x0_reset_from(rcdev); + unsigned long offset = id / 32; + u32 mask = BIT(id % 32); + void __iomem *reg_status = data->status + offset * sizeof(u32); + u32 value = readl(reg_status); + + return !((value ^ data->asserted[offset]) & mask); +} + +static const struct reset_control_ops jh71x0_reset_ops = { + .assert = jh71x0_reset_assert, + .deassert = jh71x0_reset_deassert, + .reset = jh71x0_reset_reset, + .status = jh71x0_reset_status, +}; + +int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, + const u32 *asserted, unsigned int nr_resets, + struct module *owner) +{ + struct jh71x0_reset *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->rcdev.ops = &jh71x0_reset_ops; + data->rcdev.owner = owner; + data->rcdev.nr_resets = nr_resets; + data->rcdev.dev = dev; + data->rcdev.of_node = of_node; + + spin_lock_init(&data->lock); + data->assert = assert; + data->status = status; + data->asserted = asserted; + + return devm_reset_controller_register(dev, &data->rcdev); +} +EXPORT_SYMBOL_GPL(reset_starfive_jh71x0_register); diff --git a/drivers/reset/starfive/reset-starfive-jh71x0.h b/drivers/reset/starfive/reset-starfive-jh71x0.h new file mode 100644 index 000000000000..db7d39a87f87 --- /dev/null +++ b/drivers/reset/starfive/reset-starfive-jh71x0.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Emil Renner Berthing + */ + +#ifndef __RESET_STARFIVE_JH71X0_H +#define __RESET_STARFIVE_JH71X0_H + +int reset_starfive_jh71x0_register(struct device *dev, struct device_node *of_node, + void __iomem *assert, void __iomem *status, + const u32 *asserted, unsigned int nr_resets, + struct module *owner); + +#endif /* __RESET_STARFIVE_JH71X0_H */ diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index a2207c0cf432..5039df757127 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -694,7 +694,7 @@ static int __init rpmsg_init(void) { int ret; - rpmsg_class = class_create(THIS_MODULE, "rpmsg"); + rpmsg_class = class_create("rpmsg"); if (IS_ERR(rpmsg_class)) { pr_err("failed to create rpmsg class\n"); return PTR_ERR(rpmsg_class); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5a71579af0a1..753872408615 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1970,7 +1970,7 @@ config RTC_DRV_MSC313 config RTC_DRV_POLARFIRE_SOC tristate "Microchip PolarFire SoC built-in RTC" - depends on SOC_MICROCHIP_POLARFIRE + depends on ARCH_MICROCHIP_POLARFIRE help If you say yes here you will get support for the built-in RTC on Polarfire SoC. diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index e5b7b48cffac..edfd942f8c54 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -475,7 +475,7 @@ EXPORT_SYMBOL_GPL(devm_rtc_device_register); static int __init rtc_init(void) { - rtc_class = class_create(THIS_MODULE, "rtc"); + rtc_class = class_create("rtc"); if (IS_ERR(rtc_class)) { pr_err("couldn't create class\n"); return PTR_ERR(rtc_class); diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 6a3f44cf6ebe..f40cc06b0979 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -317,11 +317,10 @@ out: return ret; } -static int pm80x_rtc_remove(struct platform_device *pdev) +static void pm80x_rtc_remove(struct platform_device *pdev) { struct pm80x_rtc_info *info = platform_get_drvdata(pdev); pm80x_free_irq(info->chip, info->irq, info); - return 0; } static struct platform_driver pm80x_rtc_driver = { @@ -330,7 +329,7 @@ static struct platform_driver pm80x_rtc_driver = { .pm = &pm80x_rtc_pm_ops, }, .probe = pm80x_rtc_probe, - .remove = pm80x_rtc_remove, + .remove_new = pm80x_rtc_remove, }; module_platform_driver(pm80x_rtc_driver); diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 2c809a1a445e..0f124ed5b3e5 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -331,7 +331,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev) return 0; } -static int pm860x_rtc_remove(struct platform_device *pdev) +static void pm860x_rtc_remove(struct platform_device *pdev) { struct pm860x_rtc_info *info = platform_get_drvdata(pdev); @@ -340,8 +340,6 @@ static int pm860x_rtc_remove(struct platform_device *pdev) /* disable measurement */ pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); #endif /* VRTC_CALIBRATION */ - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -373,7 +371,7 @@ static struct platform_driver pm860x_rtc_driver = { .pm = &pm860x_rtc_pm_ops, }, .probe = pm860x_rtc_probe, - .remove = pm860x_rtc_remove, + .remove_new = pm860x_rtc_remove, }; module_platform_driver(pm860x_rtc_driver); diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index ea33e149d545..75bb2ac9005c 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -392,12 +392,10 @@ static int ab8500_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(rtc); } -static int ab8500_rtc_remove(struct platform_device *pdev) +static void ab8500_rtc_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); - - return 0; } static struct platform_driver ab8500_rtc_driver = { @@ -405,7 +403,7 @@ static struct platform_driver ab8500_rtc_driver = { .name = "ab8500-rtc", }, .probe = ab8500_rtc_probe, - .remove = ab8500_rtc_remove, + .remove_new = ab8500_rtc_remove, .id_table = ab85xx_rtc_ids, }; diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 66783cb5e711..eaf2c9ab9661 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -613,13 +613,11 @@ static int ac100_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(chip->rtc); } -static int ac100_rtc_remove(struct platform_device *pdev) +static void ac100_rtc_remove(struct platform_device *pdev) { struct ac100_rtc_dev *chip = platform_get_drvdata(pdev); ac100_rtc_unregister_clks(chip); - - return 0; } static const struct of_device_id ac100_rtc_match[] = { @@ -630,7 +628,7 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match); static struct platform_driver ac100_rtc_driver = { .probe = ac100_rtc_probe, - .remove = ac100_rtc_remove, + .remove_new = ac100_rtc_remove, .driver = { .name = "ac100-rtc", .of_match_table = of_match_ptr(ac100_rtc_match), diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index cc542e6b1d5b..b4139c200676 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -491,7 +491,6 @@ MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); static __init int armada38x_rtc_probe(struct platform_device *pdev) { - struct resource *res; struct armada38x_rtc *rtc; rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc), @@ -508,12 +507,10 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); - rtc->regs = devm_ioremap_resource(&pdev->dev, res); + rtc->regs = devm_platform_ioremap_resource_byname(pdev, "rtc"); if (IS_ERR(rtc->regs)) return PTR_ERR(rtc->regs); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc"); - rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res); + rtc->regs_soc = devm_platform_ioremap_resource_byname(pdev, "rtc-soc"); if (IS_ERR(rtc->regs_soc)) return PTR_ERR(rtc->regs_soc); diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c index de795e489f71..a83b47e0d8f5 100644 --- a/drivers/rtc/rtc-asm9260.c +++ b/drivers/rtc/rtc-asm9260.c @@ -308,14 +308,13 @@ err_return: return ret; } -static int asm9260_rtc_remove(struct platform_device *pdev) +static void asm9260_rtc_remove(struct platform_device *pdev) { struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev); /* Disable alarm matching */ iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR); clk_disable_unprepare(priv->clk); - return 0; } static const struct of_device_id asm9260_dt_ids[] = { @@ -326,7 +325,7 @@ MODULE_DEVICE_TABLE(of, asm9260_dt_ids); static struct platform_driver asm9260_rtc_driver = { .probe = asm9260_rtc_probe, - .remove = asm9260_rtc_remove, + .remove_new = asm9260_rtc_remove, .driver = { .name = "asm9260-rtc", .of_match_table = asm9260_dt_ids, diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index b7b5ea1a4e67..610f27dfc462 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -442,7 +442,7 @@ err_clk: /* * Disable and remove the RTC driver */ -static int at91_rtc_remove(struct platform_device *pdev) +static void at91_rtc_remove(struct platform_device *pdev) { struct sam9_rtc *rtc = platform_get_drvdata(pdev); u32 mr = rtt_readl(rtc, MR); @@ -451,8 +451,6 @@ static int at91_rtc_remove(struct platform_device *pdev) rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); clk_disable_unprepare(rtc->sclk); - - return 0; } static void at91_rtc_shutdown(struct platform_device *pdev) @@ -531,7 +529,7 @@ MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); static struct platform_driver at91_rtc_driver = { .probe = at91_rtc_probe, - .remove = at91_rtc_remove, + .remove_new = at91_rtc_remove, .shutdown = at91_rtc_shutdown, .driver = { .name = "rtc-at91sam9", diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index 1efa81cecc27..3cdc015692ca 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -336,14 +336,12 @@ err_clk: return ret; } -static int brcmstb_waketmr_remove(struct platform_device *pdev) +static void brcmstb_waketmr_remove(struct platform_device *pdev) { struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev); unregister_reboot_notifier(&timer->reboot_notifier); clk_disable_unprepare(timer->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -382,7 +380,7 @@ static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = { static struct platform_driver brcmstb_waketmr_driver = { .probe = brcmstb_waketmr_probe, - .remove = brcmstb_waketmr_remove, + .remove_new = brcmstb_waketmr_remove, .driver = { .name = "brcmstb-waketimer", .pm = &brcmstb_waketmr_pm_ops, diff --git a/drivers/rtc/rtc-cadence.c b/drivers/rtc/rtc-cadence.c index 1edf7f16d73a..4ca60b519836 100644 --- a/drivers/rtc/rtc-cadence.c +++ b/drivers/rtc/rtc-cadence.c @@ -354,7 +354,7 @@ err_disable_pclk: return ret; } -static int cdns_rtc_remove(struct platform_device *pdev) +static void cdns_rtc_remove(struct platform_device *pdev) { struct cdns_rtc *crtc = platform_get_drvdata(pdev); @@ -363,8 +363,6 @@ static int cdns_rtc_remove(struct platform_device *pdev) clk_disable_unprepare(crtc->pclk); clk_disable_unprepare(crtc->ref_clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -404,7 +402,7 @@ static struct platform_driver cdns_rtc_driver = { .pm = &cdns_rtc_pm_ops, }, .probe = cdns_rtc_probe, - .remove = cdns_rtc_remove, + .remove_new = cdns_rtc_remove, }; module_platform_driver(cdns_rtc_driver); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 00e2ca7374ec..c9416fe8542d 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1489,10 +1489,9 @@ static int __init cmos_platform_probe(struct platform_device *pdev) return cmos_do_probe(&pdev->dev, resource, irq); } -static int cmos_platform_remove(struct platform_device *pdev) +static void cmos_platform_remove(struct platform_device *pdev) { cmos_do_remove(&pdev->dev); - return 0; } static void cmos_platform_shutdown(struct platform_device *pdev) @@ -1514,7 +1513,7 @@ static void cmos_platform_shutdown(struct platform_device *pdev) MODULE_ALIAS("platform:rtc_cmos"); static struct platform_driver cmos_platform_driver = { - .remove = cmos_platform_remove, + .remove_new = cmos_platform_remove, .shutdown = cmos_platform_shutdown, .driver = { .name = driver_name, diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index a3ec066d8066..998ab8606f0b 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -371,7 +371,7 @@ static int cros_ec_rtc_probe(struct platform_device *pdev) return 0; } -static int cros_ec_rtc_remove(struct platform_device *pdev) +static void cros_ec_rtc_remove(struct platform_device *pdev) { struct cros_ec_rtc *cros_ec_rtc = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -382,13 +382,11 @@ static int cros_ec_rtc_remove(struct platform_device *pdev) &cros_ec_rtc->notifier); if (ret) dev_err(dev, "failed to unregister notifier\n"); - - return 0; } static struct platform_driver cros_ec_rtc_driver = { .probe = cros_ec_rtc_probe, - .remove = cros_ec_rtc_remove, + .remove_new = cros_ec_rtc_remove, .driver = { .name = DRV_NAME, .pm = &cros_ec_rtc_pm_ops, diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 93ce72b9ae59..f46428ca77cc 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -213,7 +213,7 @@ static int ds1390_probe(struct spi_device *spi) return res; } -static const struct of_device_id ds1390_of_match[] = { +static const struct of_device_id ds1390_of_match[] __maybe_unused = { { .compatible = "dallas,ds1390" }, {} }; diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 5db9c737c022..0f707be0eb87 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1322,7 +1322,7 @@ ds1685_rtc_probe(struct platform_device *pdev) * ds1685_rtc_remove - removes rtc driver. * @pdev: pointer to platform_device structure. */ -static int +static void ds1685_rtc_remove(struct platform_device *pdev) { struct ds1685_priv *rtc = platform_get_drvdata(pdev); @@ -1344,8 +1344,6 @@ ds1685_rtc_remove(struct platform_device *pdev) rtc->write(rtc, RTC_EXT_CTRL_4A, (rtc->read(rtc, RTC_EXT_CTRL_4A) & ~(RTC_CTRL_4A_RWK_MASK))); - - return 0; } /* @@ -1356,7 +1354,7 @@ static struct platform_driver ds1685_rtc_driver = { .name = "rtc-ds1685", }, .probe = ds1685_rtc_probe, - .remove = ds1685_rtc_remove, + .remove_new = ds1685_rtc_remove, }; module_platform_driver(ds1685_rtc_driver); /* ----------------------------------------------------------------------- */ diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 25c6e7d9570f..8bfe7378f653 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -191,7 +191,7 @@ err_disable_pclk: return ret; } -static int ftrtc010_rtc_remove(struct platform_device *pdev) +static void ftrtc010_rtc_remove(struct platform_device *pdev) { struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev); @@ -199,8 +199,6 @@ static int ftrtc010_rtc_remove(struct platform_device *pdev) clk_disable_unprepare(rtc->extclk); if (!IS_ERR(rtc->pclk)) clk_disable_unprepare(rtc->pclk); - - return 0; } static const struct of_device_id ftrtc010_rtc_dt_match[] = { @@ -216,7 +214,7 @@ static struct platform_driver ftrtc010_rtc_driver = { .of_match_table = ftrtc010_rtc_dt_match, }, .probe = ftrtc010_rtc_probe, - .remove = ftrtc010_rtc_remove, + .remove_new = ftrtc010_rtc_remove, }; module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe); diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 16fdefafec5d..b81cea505ee9 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -296,14 +296,12 @@ err_open: return ret; } -static int hid_time_remove(struct platform_device *pdev) +static void hid_time_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); sensor_hub_device_close(hsdev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); - - return 0; } static const struct platform_device_id hid_time_ids[] = { @@ -321,7 +319,7 @@ static struct platform_driver hid_time_platform_driver = { .name = KBUILD_MODNAME, }, .probe = hid_time_probe, - .remove = hid_time_remove, + .remove_new = hid_time_remove, }; module_platform_driver(hid_time_platform_driver); diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 59d279e3e6f5..36453b008139 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -414,7 +414,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev) return dev_err_probe(dev, ret, "Unable to register clk32k clock\n"); - ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &rtc->clk32k); + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &rtc->clk32k); if (ret) return dev_err_probe(dev, ret, "Unable to register clk32k clock provider\n"); diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index eec881a81067..a4612e543f35 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -264,7 +264,7 @@ disable_rtc_clk: return ret; } -static int lpc24xx_rtc_remove(struct platform_device *pdev) +static void lpc24xx_rtc_remove(struct platform_device *pdev) { struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev); @@ -276,8 +276,6 @@ static int lpc24xx_rtc_remove(struct platform_device *pdev) clk_disable_unprepare(rtc->clk_rtc); clk_disable_unprepare(rtc->clk_reg); - - return 0; } static const struct of_device_id lpc24xx_rtc_match[] = { @@ -288,7 +286,7 @@ MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match); static struct platform_driver lpc24xx_rtc_driver = { .probe = lpc24xx_rtc_probe, - .remove = lpc24xx_rtc_remove, + .remove_new = lpc24xx_rtc_remove, .driver = { .name = "lpc24xx-rtc", .of_match_table = lpc24xx_rtc_match, diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index b0250d91fb00..35a6021d9ba4 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -806,14 +806,12 @@ err_rtc: return ret; } -static int max77686_rtc_remove(struct platform_device *pdev) +static void max77686_rtc_remove(struct platform_device *pdev) { struct max77686_rtc_info *info = platform_get_drvdata(pdev); free_irq(info->virq, info); regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -877,7 +875,7 @@ static struct platform_driver max77686_rtc_driver = { .pm = &max77686_rtc_pm_ops, }, .probe = max77686_rtc_probe, - .remove = max77686_rtc_remove, + .remove_new = max77686_rtc_remove, .id_table = rtc_id, }; diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index d4234e78497e..763a42f422eb 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -324,7 +324,7 @@ err_irq_request: return ret; } -static int mc13xxx_rtc_remove(struct platform_device *pdev) +static void mc13xxx_rtc_remove(struct platform_device *pdev) { struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); @@ -334,8 +334,6 @@ static int mc13xxx_rtc_remove(struct platform_device *pdev) mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv); mc13xxx_unlock(priv->mc13xxx); - - return 0; } static const struct platform_device_id mc13xxx_rtc_idtable[] = { @@ -352,7 +350,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable); static struct platform_driver mc13xxx_rtc_driver = { .id_table = mc13xxx_rtc_idtable, - .remove = mc13xxx_rtc_remove, + .remove_new = mc13xxx_rtc_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/rtc/rtc-meson-vrtc.c b/drivers/rtc/rtc-meson-vrtc.c index 1463c8621561..648fa362ec44 100644 --- a/drivers/rtc/rtc-meson-vrtc.c +++ b/drivers/rtc/rtc-meson-vrtc.c @@ -23,7 +23,7 @@ static int meson_vrtc_read_time(struct device *dev, struct rtc_time *tm) struct timespec64 time; dev_dbg(dev, "%s\n", __func__); - ktime_get_raw_ts64(&time); + ktime_get_real_ts64(&time); rtc_time64_to_tm(time.tv_sec, tm); return 0; @@ -96,7 +96,7 @@ static int __maybe_unused meson_vrtc_suspend(struct device *dev) long alarm_secs; struct timespec64 time; - ktime_get_raw_ts64(&time); + ktime_get_real_ts64(&time); local_time = time.tv_sec; dev_dbg(dev, "alarm_time = %lus, local_time=%lus\n", diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 6d7656a75cae..07df43e4c4d0 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -372,7 +372,7 @@ out_dispose: return err; } -static int mpc5121_rtc_remove(struct platform_device *op) +static void mpc5121_rtc_remove(struct platform_device *op) { struct mpc5121_rtc_data *rtc = platform_get_drvdata(op); struct mpc5121_rtc_regs __iomem *regs = rtc->regs; @@ -383,8 +383,6 @@ static int mpc5121_rtc_remove(struct platform_device *op) irq_dispose_mapping(rtc->irq); irq_dispose_mapping(rtc->irq_periodic); - - return 0; } #ifdef CONFIG_OF @@ -402,7 +400,7 @@ static struct platform_driver mpc5121_rtc_driver = { .of_match_table = of_match_ptr(mpc5121_rtc_match), }, .probe = mpc5121_rtc_probe, - .remove = mpc5121_rtc_remove, + .remove_new = mpc5121_rtc_remove, }; module_platform_driver(mpc5121_rtc_driver); diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c index 2a479d44f198..5b96a6d39210 100644 --- a/drivers/rtc/rtc-mpfs.c +++ b/drivers/rtc/rtc-mpfs.c @@ -274,11 +274,9 @@ static int mpfs_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(rtcdev->rtc); } -static int mpfs_rtc_remove(struct platform_device *pdev) +static void mpfs_rtc_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); - - return 0; } static const struct of_device_id mpfs_rtc_of_match[] = { @@ -290,7 +288,7 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match); static struct platform_driver mpfs_rtc_driver = { .probe = mpfs_rtc_probe, - .remove = mpfs_rtc_remove, + .remove_new = mpfs_rtc_remove, .driver = { .name = "mpfs_rtc", .of_match_table = mpfs_rtc_of_match, diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index f1e356394814..81857a457c32 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -357,13 +357,11 @@ err: return ret; } -static int mtk_rtc_remove(struct platform_device *pdev) +static void mtk_rtc_remove(struct platform_device *pdev) { struct mtk_rtc *hw = platform_get_drvdata(pdev); clk_disable_unprepare(hw->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -396,7 +394,7 @@ static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume); static struct platform_driver mtk_rtc_driver = { .probe = mtk_rtc_probe, - .remove = mtk_rtc_remove, + .remove_new = mtk_rtc_remove, .driver = { .name = MTK_RTC_DEV, .of_match_table = mtk_rtc_match, diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index f6d2ad91ff7a..6934bce4b29f 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -362,12 +362,11 @@ static int mxc_rtc_probe(struct platform_device *pdev) return ret; } -static int mxc_rtc_remove(struct platform_device *pdev) +static void mxc_rtc_remove(struct platform_device *pdev) { struct mxc_rtc_data *pdata = platform_get_drvdata(pdev); clk_disable_unprepare(pdata->clk); - return 0; } static const struct of_device_id mxc_ids[] = { @@ -382,7 +381,7 @@ static struct platform_driver mxc_rtc_driver = { .of_match_table = mxc_ids, }, .probe = mxc_rtc_probe, - .remove = mxc_rtc_remove, + .remove_new = mxc_rtc_remove, }; module_platform_driver(mxc_rtc_driver); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 4d4f3b1a7309..8ae4d7824ec9 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock @@ -910,7 +911,7 @@ err: return ret; } -static int omap_rtc_remove(struct platform_device *pdev) +static void omap_rtc_remove(struct platform_device *pdev) { struct omap_rtc *rtc = platform_get_drvdata(pdev); u8 reg; @@ -941,8 +942,6 @@ static int omap_rtc_remove(struct platform_device *pdev) /* Disable the clock/module */ pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static int __maybe_unused omap_rtc_suspend(struct device *dev) @@ -1017,7 +1016,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev) static struct platform_driver omap_rtc_driver = { .probe = omap_rtc_probe, - .remove = omap_rtc_remove, + .remove_new = omap_rtc_remove, .shutdown = omap_rtc_shutdown, .driver = { .name = "omap_rtc", diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 67571f7f0bbc..6971e47c6021 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -308,10 +308,9 @@ static int palmas_rtc_probe(struct platform_device *pdev) return 0; } -static int palmas_rtc_remove(struct platform_device *pdev) +static void palmas_rtc_remove(struct platform_device *pdev) { palmas_rtc_alarm_irq_enable(&pdev->dev, 0); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -347,7 +346,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_rtc_match); static struct platform_driver palmas_rtc_driver = { .probe = palmas_rtc_probe, - .remove = palmas_rtc_remove, + .remove_new = palmas_rtc_remove, .driver = { .name = "palmas-rtc", .pm = &palmas_rtc_pm_ops, diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 48951a16d65d..23edd11aa40c 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -260,14 +260,12 @@ static int pcf50633_rtc_probe(struct platform_device *pdev) return 0; } -static int pcf50633_rtc_remove(struct platform_device *pdev) +static void pcf50633_rtc_remove(struct platform_device *pdev) { struct pcf50633_rtc *rtc; rtc = platform_get_drvdata(pdev); pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); - - return 0; } static struct platform_driver pcf50633_rtc_driver = { @@ -275,7 +273,7 @@ static struct platform_driver pcf50633_rtc_driver = { .name = "pcf50633-rtc", }, .probe = pcf50633_rtc_probe, - .remove = pcf50633_rtc_remove, + .remove_new = pcf50633_rtc_remove, }; module_platform_driver(pcf50633_rtc_driver); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 2e111cdb94f7..e7115ebef707 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -21,7 +21,7 @@ #define PCF8523_CONTROL2_AF BIT(3) #define PCF8523_REG_CONTROL3 0x02 -#define PCF8523_CONTROL3_PM GENMASK(7,5) +#define PCF8523_CONTROL3_PM GENMASK(7, 5) #define PCF8523_PM_STANDBY 0x7 #define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ #define PCF8523_CONTROL3_BSF BIT(3) @@ -65,7 +65,7 @@ static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node load); fallthrough; case 12500: - value |= PCF8523_CONTROL1_CAP_SEL; + value = PCF8523_CONTROL1_CAP_SEL; break; case 7000: break; @@ -234,8 +234,7 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) int ret; u32 value; - switch(param->param) { - + switch (param->param) { case RTC_PARAM_BACKUP_SWITCH_MODE: ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); if (ret < 0) @@ -243,7 +242,7 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) value = FIELD_GET(PCF8523_CONTROL3_PM, value); - switch(value) { + switch (value) { case 0x0: case 0x4: param->uvalue = RTC_BSM_LEVEL; @@ -273,7 +272,7 @@ static int pcf8523_param_set(struct device *dev, struct rtc_param *param) struct pcf8523 *pcf8523 = dev_get_drvdata(dev); u8 mode; - switch(param->param) { + switch (param->param) { case RTC_PARAM_BACKUP_SWITCH_MODE: switch (param->uvalue) { case RTC_BSM_DISABLED: @@ -385,9 +384,9 @@ static const struct rtc_class_ops pcf8523_rtc_ops = { }; static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x13, + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x13, }; static int pcf8523_probe(struct i2c_client *client) diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index fa351ac20158..4f85e0c3d757 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -284,15 +284,13 @@ static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en) clk_disable(pdata->clk); } -static int pic32_rtc_remove(struct platform_device *pdev) +static void pic32_rtc_remove(struct platform_device *pdev) { struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev); pic32_rtc_setaie(&pdev->dev, 0); clk_unprepare(pdata->clk); pdata->clk = NULL; - - return 0; } static int pic32_rtc_probe(struct platform_device *pdev) @@ -373,7 +371,7 @@ MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids); static struct platform_driver pic32_rtc_driver = { .probe = pic32_rtc_probe, - .remove = pic32_rtc_remove, + .remove_new = pic32_rtc_remove, .driver = { .name = "pic32-rtc", .of_match_table = of_match_ptr(pic32_rtc_dt_ids), diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 372494e82f40..f6b779c12ca7 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -530,15 +530,14 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return 0; } -static int pm8xxx_remove(struct platform_device *pdev) +static void pm8xxx_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); - return 0; } static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, - .remove = pm8xxx_remove, + .remove_new = pm8xxx_remove, .driver = { .name = "rtc-pm8xxx", .of_match_table = pm8xxx_id_table, diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index 18684a7026c4..6f4bf919827a 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -262,12 +262,11 @@ static int rc5t583_rtc_probe(struct platform_device *pdev) * Disable rc5t583 RTC interrupts. * Sets status flag to free. */ -static int rc5t583_rtc_remove(struct platform_device *pdev) +static void rc5t583_rtc_remove(struct platform_device *pdev) { struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev); rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -299,7 +298,7 @@ static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend, static struct platform_driver rc5t583_rtc_driver = { .probe = rc5t583_rtc_probe, - .remove = rc5t583_rtc_remove, + .remove_new = rc5t583_rtc_remove, .driver = { .name = "rtc-rc5t583", .pm = &rc5t583_rtc_pm_ops, diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c index 8f9abd65846c..29662dfd56fe 100644 --- a/drivers/rtc/rtc-rtd119x.c +++ b/drivers/rtc/rtc-rtd119x.c @@ -216,7 +216,7 @@ static int rtd119x_rtc_probe(struct platform_device *pdev) return 0; } -static int rtd119x_rtc_remove(struct platform_device *pdev) +static void rtd119x_rtc_remove(struct platform_device *pdev) { struct rtd119x_rtc *data = platform_get_drvdata(pdev); @@ -224,13 +224,11 @@ static int rtd119x_rtc_remove(struct platform_device *pdev) clk_disable_unprepare(data->clk); clk_put(data->clk); - - return 0; } static struct platform_driver rtd119x_rtc_driver = { .probe = rtd119x_rtc_probe, - .remove = rtd119x_rtc_remove, + .remove_new = rtd119x_rtc_remove, .driver = { .name = "rtd1295-rtc", .of_match_table = rtd119x_rtc_dt_ids, diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index 0d36bc50197c..dca736caba85 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -391,11 +391,9 @@ dis_runtime_pm: return ret; } -static int rzn1_rtc_remove(struct platform_device *pdev) +static void rzn1_rtc_remove(struct platform_device *pdev) { pm_runtime_put(&pdev->dev); - - return 0; } static const struct of_device_id rzn1_rtc_of_match[] = { @@ -406,7 +404,7 @@ MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match); static struct platform_driver rzn1_rtc_driver = { .probe = rzn1_rtc_probe, - .remove = rzn1_rtc_remove, + .remove_new = rzn1_rtc_remove, .driver = { .name = "rzn1-rtc", .of_match_table = rzn1_rtc_of_match, diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 8fc5efde3e0b..70e1a18e5efd 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -385,7 +385,7 @@ static void s3c6410_rtc_disable(struct s3c_rtc *info) writew(con, info->base + S3C2410_RTCCON); } -static int s3c_rtc_remove(struct platform_device *pdev) +static void s3c_rtc_remove(struct platform_device *pdev) { struct s3c_rtc *info = platform_get_drvdata(pdev); @@ -394,8 +394,6 @@ static int s3c_rtc_remove(struct platform_device *pdev) if (info->data->needs_src_clk) clk_unprepare(info->rtc_src_clk); clk_unprepare(info->rtc_clk); - - return 0; } static int s3c_rtc_probe(struct platform_device *pdev) @@ -600,7 +598,7 @@ MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); static struct platform_driver s3c_rtc_driver = { .probe = s3c_rtc_probe, - .remove = s3c_rtc_remove, + .remove_new = s3c_rtc_remove, .driver = { .name = "s3c-rtc", .pm = &s3c_rtc_pm_ops, diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 4243fe6d3842..dad294a0ce2a 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -85,7 +85,7 @@ struct s5m_rtc_reg_config { unsigned int write_alarm_udr_mask; }; -/* Register map for S5M8763 and S5M8767 */ +/* Register map for S5M8767 */ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .regs_count = 8, .time = S5M_RTC_SEC, @@ -236,7 +236,6 @@ static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, switch (info->device_type) { case S5M8767X: - case S5M8763X: ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; @@ -299,7 +298,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) data |= info->regs->write_alarm_udr_mask; switch (info->device_type) { - case S5M8763X: case S5M8767X: data &= ~S5M_RTC_TIME_EN_MASK; break; @@ -329,38 +327,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) return ret; } -static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) -{ - tm->tm_sec = bcd2bin(data[RTC_SEC]); - tm->tm_min = bcd2bin(data[RTC_MIN]); - - if (data[RTC_HOUR] & HOUR_12) { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); - if (data[RTC_HOUR] & HOUR_PM) - tm->tm_hour += 12; - } else { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); - } - - tm->tm_wday = data[RTC_WEEKDAY] & 0x07; - tm->tm_mday = bcd2bin(data[RTC_DATE]); - tm->tm_mon = bcd2bin(data[RTC_MONTH]); - tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; - tm->tm_year -= 1900; -} - -static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) -{ - data[RTC_SEC] = bin2bcd(tm->tm_sec); - data[RTC_MIN] = bin2bcd(tm->tm_min); - data[RTC_HOUR] = bin2bcd(tm->tm_hour); - data[RTC_WEEKDAY] = tm->tm_wday; - data[RTC_DATE] = bin2bcd(tm->tm_mday); - data[RTC_MONTH] = bin2bcd(tm->tm_mon); - data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); - data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); -} - static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); @@ -385,10 +351,6 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, tm); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -412,9 +374,6 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) int ret = 0; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(tm, data); - break; case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -444,7 +403,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; - unsigned int val; int ret, i; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -453,15 +411,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, &alrm->time); - ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val); - if (ret < 0) - return ret; - - alrm->enabled = !!val; - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -500,10 +449,6 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -531,7 +476,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) { int ret; u8 data[RTC_MAX_NUM_TIME_REGS]; - u8 alarm0_conf; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -543,11 +487,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - alarm0_conf = 0x77; - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -585,10 +524,6 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(&alrm->time, data); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -655,7 +590,6 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) int ret; switch (info->device_type) { - case S5M8763X: case S5M8767X: /* UDR update time. Default of 7.32 ms is too long. */ ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, @@ -729,11 +663,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->regs = &s2mps13_rtc_regs; alarm_irq = S2MPS14_IRQ_RTCA0; break; - case S5M8763X: - regmap_cfg = &s5m_rtc_regmap_config; - info->regs = &s5m_rtc_regs; - alarm_irq = S5M8763_IRQ_ALARM0; - break; case S5M8767X: regmap_cfg = &s5m_rtc_regmap_config; info->regs = &s5m_rtc_regs; @@ -786,13 +715,8 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev->ops = &s5m_rtc_ops; - if (info->device_type == S5M8763X) { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_0000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_9999; - } else { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; - } + info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; if (!info->irq) { clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 1250887e4382..0b2cfa8ca05b 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -297,7 +297,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev) return sa1100_rtc_init(pdev, info); } -static int sa1100_rtc_remove(struct platform_device *pdev) +static void sa1100_rtc_remove(struct platform_device *pdev) { struct sa1100_rtc *info = platform_get_drvdata(pdev); @@ -307,8 +307,6 @@ static int sa1100_rtc_remove(struct platform_device *pdev) spin_unlock_irq(&info->lock); clk_disable_unprepare(info->clk); } - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -343,7 +341,7 @@ MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, - .remove = sa1100_rtc_remove, + .remove_new = sa1100_rtc_remove, .driver = { .name = "sa1100-rtc", .pm = &sa1100_rtc_pm_ops, diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index 736fe535cd45..1df5c7e94198 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -405,15 +405,13 @@ err_disable_clock: return status; } -static int spear_rtc_remove(struct platform_device *pdev) +static void spear_rtc_remove(struct platform_device *pdev) { struct spear_rtc_config *config = platform_get_drvdata(pdev); spear_rtc_disable_interrupt(config); clk_disable_unprepare(config->clk); device_init_wakeup(&pdev->dev, 0); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -477,7 +475,7 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table); static struct platform_driver spear_rtc_driver = { .probe = spear_rtc_probe, - .remove = spear_rtc_remove, + .remove_new = spear_rtc_remove, .shutdown = spear_rtc_shutdown, .driver = { .name = "rtc-spear", diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index ac9e228b56d0..229cb2847cc4 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -846,7 +846,7 @@ err_no_rtc_ck: return ret; } -static int stm32_rtc_remove(struct platform_device *pdev) +static void stm32_rtc_remove(struct platform_device *pdev) { struct stm32_rtc *rtc = platform_get_drvdata(pdev); const struct stm32_rtc_registers *regs = &rtc->data->regs; @@ -869,8 +869,6 @@ static int stm32_rtc_remove(struct platform_device *pdev) dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -917,7 +915,7 @@ static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, - .remove = stm32_rtc_remove, + .remove_new = stm32_rtc_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_rtc_pm_ops, diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index aae40d20d086..6f11b745f34d 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -232,17 +232,15 @@ static const struct rtc_class_ops stmp3xxx_rtc_ops = { .set_alarm = stmp3xxx_rtc_set_alarm, }; -static int stmp3xxx_rtc_remove(struct platform_device *pdev) +static void stmp3xxx_rtc_remove(struct platform_device *pdev) { struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(pdev); if (!rtc_data) - return 0; + return; writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); - - return 0; } static int stmp3xxx_rtc_probe(struct platform_device *pdev) @@ -406,7 +404,7 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids); static struct platform_driver stmp3xxx_rtcdrv = { .probe = stmp3xxx_rtc_probe, - .remove = stmp3xxx_rtc_remove, + .remove_new = stmp3xxx_rtc_remove, .driver = { .name = "stmp3xxx-rtc", .pm = &stmp3xxx_rtc_pm_ops, diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 7038f47d77ff..dc76537f1b62 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -260,7 +260,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, } /* Switch to the external, more precise, oscillator, if present */ - if (of_get_property(node, "clocks", NULL)) { + if (of_property_present(node, "clocks")) { reg |= SUN6I_LOSC_CTRL_EXT_OSC; if (rtc->data->has_losc_en) reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN; diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index 4b578e4d44f6..f33dc301f301 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -235,8 +235,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev) if (!sp_rtc) return -ENOMEM; - sp_rtc->res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, RTC_REG_NAME); - sp_rtc->reg_base = devm_ioremap_resource(&plat_dev->dev, sp_rtc->res); + sp_rtc->reg_base = devm_platform_ioremap_resource_byname(plat_dev, RTC_REG_NAME); if (IS_ERR(sp_rtc->reg_base)) return dev_err_probe(&plat_dev->dev, PTR_ERR(sp_rtc->reg_base), "%s devm_ioremap_resource fail\n", RTC_REG_NAME); @@ -304,15 +303,13 @@ free_clk: return ret; } -static int sp_rtc_remove(struct platform_device *plat_dev) +static void sp_rtc_remove(struct platform_device *plat_dev) { struct sunplus_rtc *sp_rtc = dev_get_drvdata(&plat_dev->dev); device_init_wakeup(&plat_dev->dev, 0); reset_control_assert(sp_rtc->rstc); clk_disable_unprepare(sp_rtc->rtcclk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -347,7 +344,7 @@ static SIMPLE_DEV_PM_OPS(sp_rtc_pm_ops, sp_rtc_suspend, sp_rtc_resume); static struct platform_driver sp_rtc_driver = { .probe = sp_rtc_probe, - .remove = sp_rtc_remove, + .remove_new = sp_rtc_remove, .driver = { .name = "sp7021-rtc", .of_match_table = sp_rtc_of_match, diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 85f7ad5d5390..441e0a66b215 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -342,13 +342,11 @@ disable_clk: return ret; } -static int tegra_rtc_remove(struct platform_device *pdev) +static void tegra_rtc_remove(struct platform_device *pdev) { struct tegra_rtc_info *info = platform_get_drvdata(pdev); clk_disable_unprepare(info->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -401,7 +399,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev) static struct platform_driver tegra_rtc_driver = { .probe = tegra_rtc_probe, - .remove = tegra_rtc_remove, + .remove_new = tegra_rtc_remove, .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index ba23163cc042..0d90fe923355 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -632,7 +632,8 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev) struct ti_k3_rtc *priv = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(priv->irq); + return enable_irq_wake(priv->irq); + return 0; } diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 52093e7ba22d..9f14e2475747 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -279,13 +279,12 @@ fail_rtc_register: return ret; }; -static int tps6586x_rtc_remove(struct platform_device *pdev) +static void tps6586x_rtc_remove(struct platform_device *pdev) { struct device *tps_dev = to_tps6586x_dev(&pdev->dev); tps6586x_update(tps_dev, RTC_CTRL, 0, RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -317,7 +316,7 @@ static struct platform_driver tps6586x_rtc_driver = { .pm = &tps6586x_pm_ops, }, .probe = tps6586x_rtc_probe, - .remove = tps6586x_rtc_remove, + .remove_new = tps6586x_rtc_remove, }; module_platform_driver(tps6586x_rtc_driver); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index c24d1e18f56c..81b36948c2fa 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -586,7 +586,7 @@ static int twl_rtc_probe(struct platform_device *pdev) * Disable all TWL RTC module interrupts. * Sets status flag to free. */ -static int twl_rtc_remove(struct platform_device *pdev) +static void twl_rtc_remove(struct platform_device *pdev) { struct twl_rtc *twl_rtc = platform_get_drvdata(pdev); @@ -599,8 +599,6 @@ static int twl_rtc_remove(struct platform_device *pdev) twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, REG_INT_MSK_STS_A); } - - return 0; } static void twl_rtc_shutdown(struct platform_device *pdev) @@ -642,7 +640,7 @@ MODULE_DEVICE_TABLE(of, twl_rtc_of_match); static struct platform_driver twl4030rtc_driver = { .probe = twl_rtc_probe, - .remove = twl_rtc_remove, + .remove_new = twl_rtc_remove, .shutdown = twl_rtc_shutdown, .driver = { .name = "twl_rtc", diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 197b649cd629..ccfa76513a2c 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -235,14 +235,12 @@ static int vt8500_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(vt8500_rtc->rtc); } -static int vt8500_rtc_remove(struct platform_device *pdev) +static void vt8500_rtc_remove(struct platform_device *pdev) { struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); /* Disable alarm matching */ writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); - - return 0; } static const struct of_device_id wmt_dt_ids[] = { @@ -253,7 +251,7 @@ MODULE_DEVICE_TABLE(of, wmt_dt_ids); static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, - .remove = vt8500_rtc_remove, + .remove_new = vt8500_rtc_remove, .driver = { .name = "vt8500-rtc", .of_match_table = wmt_dt_ids, diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 6eaa9321c074..947f8071803f 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -451,14 +451,12 @@ static int wm8350_rtc_probe(struct platform_device *pdev) return 0; } -static int wm8350_rtc_remove(struct platform_device *pdev) +static void wm8350_rtc_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350); - - return 0; } static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend, @@ -466,7 +464,7 @@ static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend, static struct platform_driver wm8350_rtc_driver = { .probe = wm8350_rtc_probe, - .remove = wm8350_rtc_remove, + .remove_new = wm8350_rtc_remove, .driver = { .name = "wm8350-rtc", .pm = &wm8350_rtc_pm_ops, diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index d3d0054e21fd..f78efc9760c0 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -192,14 +192,13 @@ static int xgene_rtc_probe(struct platform_device *pdev) return 0; } -static int xgene_rtc_remove(struct platform_device *pdev) +static void xgene_rtc_remove(struct platform_device *pdev) { struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); xgene_rtc_alarm_irq_enable(&pdev->dev, 0); device_init_wakeup(&pdev->dev, 0); clk_disable_unprepare(pdata->clk); - return 0; } static int __maybe_unused xgene_rtc_suspend(struct device *dev) @@ -264,7 +263,7 @@ MODULE_DEVICE_TABLE(of, xgene_rtc_of_match); static struct platform_driver xgene_rtc_driver = { .probe = xgene_rtc_probe, - .remove = xgene_rtc_remove, + .remove_new = xgene_rtc_remove, .driver = { .name = "xgene-rtc", .pm = &xgene_rtc_pm_ops, diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index c9b85c838ebe..08ed171bdab4 100644 --- a/drivers/rtc/rtc-zynqmp.c +++ b/drivers/rtc/rtc-zynqmp.c @@ -342,12 +342,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(xrtcdev->rtc); } -static int xlnx_rtc_remove(struct platform_device *pdev) +static void xlnx_rtc_remove(struct platform_device *pdev) { xlnx_rtc_alarm_irq_enable(&pdev->dev, 0); device_init_wakeup(&pdev->dev, 0); - - return 0; } static int __maybe_unused xlnx_rtc_suspend(struct device *dev) @@ -384,7 +382,7 @@ MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match); static struct platform_driver xlnx_rtc_driver = { .probe = xlnx_rtc_probe, - .remove = xlnx_rtc_remove, + .remove_new = xlnx_rtc_remove, .driver = { .name = KBUILD_MODNAME, .pm = &xlnx_rtc_pm_ops, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ade1369fe5ed..113c509bf6d0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -127,6 +127,8 @@ static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int, struct dasd_device *, struct dasd_device *, unsigned int, int, unsigned int, unsigned int, unsigned int, unsigned int); +static int dasd_eckd_query_pprc_status(struct dasd_device *, + struct dasd_pprc_data_sc4 *); /* initial attempt at a probe function. this can be simplified once * the other detection code is gone */ @@ -3733,6 +3735,26 @@ static int count_exts(unsigned int from, unsigned int to, int trks_per_ext) return count; } +static int dasd_in_copy_relation(struct dasd_device *device) +{ + struct dasd_pprc_data_sc4 *temp; + int rc; + + if (!dasd_eckd_pprc_enabled(device)) + return 0; + + temp = kzalloc(sizeof(*temp), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + rc = dasd_eckd_query_pprc_status(device, temp); + if (!rc) + rc = temp->dev_info[0].state; + + kfree(temp); + return rc; +} + /* * Release allocated space for a given range or an entire volume. */ @@ -3749,6 +3771,7 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, int cur_to_trk, cur_from_trk; struct dasd_ccw_req *cqr; u32 beg_cyl, end_cyl; + int copy_relation; struct ccw1 *ccw; int trks_per_ext; size_t ras_size; @@ -3760,6 +3783,10 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk)) return ERR_PTR(-EINVAL); + copy_relation = dasd_in_copy_relation(device); + if (copy_relation < 0) + return ERR_PTR(copy_relation); + rq = req ? blk_mq_rq_to_pdu(req) : NULL; features = &private->features; @@ -3788,9 +3815,11 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, /* * This bit guarantees initialisation of tracks within an extent that is * not fully specified, but is only supported with a certain feature - * subset. + * subset and for devices not in a copy relation. */ - ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01); + if (features->feature[56] & 0x01 && !copy_relation) + ras_data->op_flags.guarantee_init = 1; + ras_data->lss = private->conf.ned->ID; ras_data->dev_addr = private->conf.ned->unit_addr; ras_data->nr_exts = nr_exts; diff --git a/drivers/s390/char/hmcdrv_dev.c b/drivers/s390/char/hmcdrv_dev.c index cb8fdf057eca..8d50c894711f 100644 --- a/drivers/s390/char/hmcdrv_dev.c +++ b/drivers/s390/char/hmcdrv_dev.c @@ -308,7 +308,7 @@ int hmcdrv_dev_init(void) * /proc/devices), but not under /dev nor /sys/devices/virtual. So * we have to create an associated class (see /sys/class). */ - hmcdrv_dev_class = class_create(THIS_MODULE, HMCDRV_DEV_CLASS); + hmcdrv_dev_class = class_create(HMCDRV_DEV_CLASS); if (IS_ERR(hmcdrv_dev_class)) { rc = PTR_ERR(hmcdrv_dev_class); diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 09d7570d3b7d..7115c0f85650 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1319,7 +1319,7 @@ static int raw3270_init(void) if (rc == 0) { /* Create attributes for early (= console) device. */ mutex_lock(&raw3270_mutex); - class3270 = class_create(THIS_MODULE, "3270"); + class3270 = class_create("3270"); list_for_each_entry(rp, &raw3270_devices, list) { get_device(&rp->cdev->dev); raw3270_create_attributes(rp); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 909ba7f08688..6a23ec286c70 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -204,7 +204,7 @@ struct read_storage_sccb { u16 assigned; u16 standby; u16 :16; - u32 entries[0]; + u32 entries[]; } __packed; static inline void sclp_fill_core_info(struct sclp_core_info *info, diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 15971997cfe2..3c87057436d5 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -241,7 +241,7 @@ struct attach_storage_sccb { u16 :16; u16 assigned; u32 :32; - u32 entries[0]; + u32 entries[]; } __packed; static int sclp_attach_storage(u8 id) diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index ac1d00980fa6..dbd5c53d8edf 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "sclp.h" #include "sclp_rw.h" @@ -336,7 +336,7 @@ int __init sclp_early_get_hsa_size(unsigned long *hsa_size) #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL -void __weak __init add_mem_detect_block(u64 start, u64 end) {} +void __weak __init add_physmem_online_range(u64 start, u64 end) {} int __init sclp_early_read_storage_info(void) { struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb; @@ -369,7 +369,7 @@ int __init sclp_early_read_storage_info(void) if (!sccb->entries[sn]) continue; rn = sccb->entries[sn] >> 16; - add_mem_detect_block((rn - 1) * rzm, rn * rzm); + add_physmem_online_range((rn - 1) * rzm, rn * rzm); } break; case 0x0310: @@ -382,6 +382,6 @@ int __init sclp_early_read_storage_info(void) return 0; fail: - mem_detect.count = 0; + physmem_info.range_count = 0; return -EIO; } diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index c21dc68e05a0..277a0f903d11 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -117,7 +117,7 @@ EXPORT_SYMBOL(unregister_tape_dev); static int __init tape_init(void) { - tape_class = class_create(THIS_MODULE, "tape390"); + tape_class = class_create("tape390"); return 0; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index ed970ecfafdf..6946ba9a9de2 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -699,7 +699,7 @@ static int vmlogrdr_register_driver(void) if (ret) goto out_iucv; - vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); + vmlogrdr_class = class_create("vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { ret = PTR_ERR(vmlogrdr_class); vmlogrdr_class = NULL; diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 131293f7f152..82efdd20ad01 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -1022,7 +1022,7 @@ static int __init ur_init(void) debug_set_level(vmur_dbf, 6); - vmur_class = class_create(THIS_MODULE, "vmur"); + vmur_class = class_create("vmur"); if (IS_ERR(vmur_class)) { rc = PTR_ERR(vmur_class); goto fail_free_dbf; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 620a917cd3a1..0abd77f4b664 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -1171,7 +1171,7 @@ int __init chsc_get_cssid_iid(int idx, u8 *cssid, u8 *iid) u8 cssid; u8 iid; u32 : 16; - } list[0]; + } list[]; } *sdcal_area; int ret; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 32fa7faa5bf6..d1caacb08e67 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -120,7 +120,7 @@ struct chsc_scpd { u32 zeroes1; struct chsc_header response; u32:32; - u8 data[0]; + u8 data[]; } __packed __aligned(PAGE_SIZE); struct chsc_sda_area { diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8eb089b99cde..d5c43e9b5128 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1111,6 +1111,8 @@ static void io_subchannel_verify(struct subchannel *sch) cdev = sch_get_cdev(sch); if (cdev) dev_fsm_event(cdev, DEV_EVENT_VERIFY); + else + css_schedule_eval(sch->schid); } static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 5ea6249d8180..641f0dbb65a9 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -95,7 +95,7 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue, " lgr 1,%[token]\n" " .insn rsy,0xeb000000008a,%[qs],%[ccq],0(%[state])" : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart) - : [state] "d" ((unsigned long)state), [token] "d" (token) + : [state] "a" ((unsigned long)state), [token] "d" (token) : "memory", "cc", "1"); *count = _ccq & 0xff; *start = _queuestart & 0xff; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f4cc1720156f..8d6b9a52bf3c 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -122,7 +122,13 @@ static struct hrtimer ap_poll_timer; * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. */ -static unsigned long long poll_timeout = 250000; +static unsigned long poll_high_timeout = 250000UL; + +/* + * Some state machine states only require a low frequency polling. + * We use 25 Hz frequency for these. + */ +static unsigned long poll_low_timeout = 40000000UL; /* Maximum domain id, if not given via qci */ static int ap_max_domain_id = 15; @@ -200,6 +206,18 @@ static inline int ap_qact_available(void) return 0; } +/* + * ap_sb_available(): Test if the AP secure binding facility is available. + * + * Returns 1 if secure binding facility is available. + */ +int ap_sb_available(void) +{ + if (ap_qci_info) + return ap_qci_info->apsb; + return 0; +} + /* * ap_fetch_qci_info(): Fetch cryptographic config info * @@ -248,13 +266,13 @@ static void __init ap_init_qci_info(void) AP_DBF_INFO("%s successful fetched initial qci info\n", __func__); if (ap_qci_info->apxa) { - if (ap_qci_info->Na) { - ap_max_adapter_id = ap_qci_info->Na; + if (ap_qci_info->na) { + ap_max_adapter_id = ap_qci_info->na; AP_DBF_INFO("%s new ap_max_adapter_id is %d\n", __func__, ap_max_adapter_id); } - if (ap_qci_info->Nd) { - ap_max_domain_id = ap_qci_info->Nd; + if (ap_qci_info->nd) { + ap_max_domain_id = ap_qci_info->nd; AP_DBF_INFO("%s new ap_max_domain_id is %d\n", __func__, ap_max_domain_id); } @@ -324,35 +342,32 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); /* * ap_queue_info(): Check and get AP queue info. - * Returns true if TAPQ succeeded and the info is filled or - * false otherwise. + * Returns: 1 if APQN exists and info is filled, + * 0 if APQN seems to exit but there is no info + * available (eg. caused by an asynch pending error) + * -1 invalid APQN, TAPQ error or AP queue status which + * indicates there is no APQN. */ -static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, - int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) +static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, + int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) { struct ap_queue_status status; - union { - unsigned long value; - struct { - unsigned int fac : 32; /* facility bits */ - unsigned int at : 8; /* ap type */ - unsigned int _res1 : 8; - unsigned int _res2 : 4; - unsigned int ml : 4; /* apxl ml */ - unsigned int _res3 : 4; - unsigned int qd : 4; /* queue depth */ - } tapq_gr2; - } tapq_info; + struct ap_tapq_gr2 tapq_info; tapq_info.value = 0; /* make sure we don't run into a specifiation exception */ if (AP_QID_CARD(qid) > ap_max_adapter_id || AP_QID_QUEUE(qid) > ap_max_domain_id) - return false; + return -1; /* call TAPQ on this APQN */ - status = ap_test_queue(qid, ap_apft_available(), &tapq_info.value); + status = ap_test_queue(qid, ap_apft_available(), &tapq_info); + + /* handle pending async error with return 'no info available' */ + if (status.async) + return 0; + switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: @@ -365,11 +380,11 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, * there is at least one of the mode bits set. */ if (WARN_ON_ONCE(!tapq_info.value)) - return false; - *q_type = tapq_info.tapq_gr2.at; - *q_fac = tapq_info.tapq_gr2.fac; - *q_depth = tapq_info.tapq_gr2.qd; - *q_ml = tapq_info.tapq_gr2.ml; + return 0; + *q_type = tapq_info.at; + *q_fac = tapq_info.fac; + *q_depth = tapq_info.qd; + *q_ml = tapq_info.ml; *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; switch (*q_type) { @@ -389,12 +404,12 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, default: break; } - return true; + return 1; default: /* * A response code which indicates, there is no info available. */ - return false; + return -1; } } @@ -412,10 +427,13 @@ void ap_wait(enum ap_sm_wait wait) break; } fallthrough; - case AP_SM_WAIT_TIMEOUT: + case AP_SM_WAIT_LOW_TIMEOUT: + case AP_SM_WAIT_HIGH_TIMEOUT: spin_lock_bh(&ap_poll_timer_lock); if (!hrtimer_is_queued(&ap_poll_timer)) { - hr_time = poll_timeout; + hr_time = + wait == AP_SM_WAIT_LOW_TIMEOUT ? + poll_low_timeout : poll_high_timeout; hrtimer_forward_now(&ap_poll_timer, hr_time); hrtimer_restart(&ap_poll_timer); } @@ -1166,12 +1184,12 @@ EXPORT_SYMBOL(ap_parse_mask_str); * AP bus attributes. */ -static ssize_t ap_domain_show(struct bus_type *bus, char *buf) +static ssize_t ap_domain_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); + return sysfs_emit(buf, "%d\n", ap_domain_index); } -static ssize_t ap_domain_store(struct bus_type *bus, +static ssize_t ap_domain_store(const struct bus_type *bus, const char *buf, size_t count) { int domain; @@ -1193,65 +1211,61 @@ static ssize_t ap_domain_store(struct bus_type *bus, static BUS_ATTR_RW(ap_domain); -static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) +static ssize_t ap_control_domain_mask_show(const struct bus_type *bus, char *buf) { if (!ap_qci_info) /* QCI not supported */ - return scnprintf(buf, PAGE_SIZE, "not supported\n"); + return sysfs_emit(buf, "not supported\n"); - return scnprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_qci_info->adm[0], ap_qci_info->adm[1], - ap_qci_info->adm[2], ap_qci_info->adm[3], - ap_qci_info->adm[4], ap_qci_info->adm[5], - ap_qci_info->adm[6], ap_qci_info->adm[7]); + return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_qci_info->adm[0], ap_qci_info->adm[1], + ap_qci_info->adm[2], ap_qci_info->adm[3], + ap_qci_info->adm[4], ap_qci_info->adm[5], + ap_qci_info->adm[6], ap_qci_info->adm[7]); } static BUS_ATTR_RO(ap_control_domain_mask); -static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) +static ssize_t ap_usage_domain_mask_show(const struct bus_type *bus, char *buf) { if (!ap_qci_info) /* QCI not supported */ - return scnprintf(buf, PAGE_SIZE, "not supported\n"); + return sysfs_emit(buf, "not supported\n"); - return scnprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_qci_info->aqm[0], ap_qci_info->aqm[1], - ap_qci_info->aqm[2], ap_qci_info->aqm[3], - ap_qci_info->aqm[4], ap_qci_info->aqm[5], - ap_qci_info->aqm[6], ap_qci_info->aqm[7]); + return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_qci_info->aqm[0], ap_qci_info->aqm[1], + ap_qci_info->aqm[2], ap_qci_info->aqm[3], + ap_qci_info->aqm[4], ap_qci_info->aqm[5], + ap_qci_info->aqm[6], ap_qci_info->aqm[7]); } static BUS_ATTR_RO(ap_usage_domain_mask); -static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf) +static ssize_t ap_adapter_mask_show(const struct bus_type *bus, char *buf) { if (!ap_qci_info) /* QCI not supported */ - return scnprintf(buf, PAGE_SIZE, "not supported\n"); + return sysfs_emit(buf, "not supported\n"); - return scnprintf(buf, PAGE_SIZE, - "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", - ap_qci_info->apm[0], ap_qci_info->apm[1], - ap_qci_info->apm[2], ap_qci_info->apm[3], - ap_qci_info->apm[4], ap_qci_info->apm[5], - ap_qci_info->apm[6], ap_qci_info->apm[7]); + return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_qci_info->apm[0], ap_qci_info->apm[1], + ap_qci_info->apm[2], ap_qci_info->apm[3], + ap_qci_info->apm[4], ap_qci_info->apm[5], + ap_qci_info->apm[6], ap_qci_info->apm[7]); } static BUS_ATTR_RO(ap_adapter_mask); -static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) +static ssize_t ap_interrupts_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", - ap_irq_flag ? 1 : 0); + return sysfs_emit(buf, "%d\n", ap_irq_flag ? 1 : 0); } static BUS_ATTR_RO(ap_interrupts); -static ssize_t config_time_show(struct bus_type *bus, char *buf) +static ssize_t config_time_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); + return sysfs_emit(buf, "%d\n", ap_config_time); } -static ssize_t config_time_store(struct bus_type *bus, +static ssize_t config_time_store(const struct bus_type *bus, const char *buf, size_t count) { int time; @@ -1265,19 +1279,22 @@ static ssize_t config_time_store(struct bus_type *bus, static BUS_ATTR_RW(config_time); -static ssize_t poll_thread_show(struct bus_type *bus, char *buf) +static ssize_t poll_thread_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); + return sysfs_emit(buf, "%d\n", ap_poll_kthread ? 1 : 0); } -static ssize_t poll_thread_store(struct bus_type *bus, +static ssize_t poll_thread_store(const struct bus_type *bus, const char *buf, size_t count) { - int flag, rc; + bool value; + int rc; - if (sscanf(buf, "%d\n", &flag) != 1) - return -EINVAL; - if (flag) { + rc = kstrtobool(buf, &value); + if (rc) + return rc; + + if (value) { rc = ap_poll_thread_start(); if (rc) count = rc; @@ -1289,23 +1306,27 @@ static ssize_t poll_thread_store(struct bus_type *bus, static BUS_ATTR_RW(poll_thread); -static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) +static ssize_t poll_timeout_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); + return sysfs_emit(buf, "%lu\n", poll_high_timeout); } -static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, +static ssize_t poll_timeout_store(const struct bus_type *bus, const char *buf, size_t count) { - unsigned long long time; + unsigned long value; ktime_t hr_time; + int rc; + + rc = kstrtoul(buf, 0, &value); + if (rc) + return rc; /* 120 seconds = maximum poll interval */ - if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || - time > 120000000000ULL) + if (value > 120000000000UL) return -EINVAL; - poll_timeout = time; - hr_time = poll_timeout; + poll_high_timeout = value; + hr_time = poll_high_timeout; spin_lock_bh(&ap_poll_timer_lock); hrtimer_cancel(&ap_poll_timer); @@ -1318,30 +1339,29 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, static BUS_ATTR_RW(poll_timeout); -static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) +static ssize_t ap_max_domain_id_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", ap_max_domain_id); + return sysfs_emit(buf, "%d\n", ap_max_domain_id); } static BUS_ATTR_RO(ap_max_domain_id); -static ssize_t ap_max_adapter_id_show(struct bus_type *bus, char *buf) +static ssize_t ap_max_adapter_id_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", ap_max_adapter_id); + return sysfs_emit(buf, "%d\n", ap_max_adapter_id); } static BUS_ATTR_RO(ap_max_adapter_id); -static ssize_t apmask_show(struct bus_type *bus, char *buf) +static ssize_t apmask_show(const struct bus_type *bus, char *buf) { int rc; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - rc = scnprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_perms.apm[0], ap_perms.apm[1], - ap_perms.apm[2], ap_perms.apm[3]); + rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", + ap_perms.apm[0], ap_perms.apm[1], + ap_perms.apm[2], ap_perms.apm[3]); mutex_unlock(&ap_perms_mutex); return rc; @@ -1393,7 +1413,7 @@ static int apmask_commit(unsigned long *newapm) return 0; } -static ssize_t apmask_store(struct bus_type *bus, const char *buf, +static ssize_t apmask_store(const struct bus_type *bus, const char *buf, size_t count) { int rc, changes = 0; @@ -1425,16 +1445,15 @@ done: static BUS_ATTR_RW(apmask); -static ssize_t aqmask_show(struct bus_type *bus, char *buf) +static ssize_t aqmask_show(const struct bus_type *bus, char *buf) { int rc; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - rc = scnprintf(buf, PAGE_SIZE, - "0x%016lx%016lx%016lx%016lx\n", - ap_perms.aqm[0], ap_perms.aqm[1], - ap_perms.aqm[2], ap_perms.aqm[3]); + rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", + ap_perms.aqm[0], ap_perms.aqm[1], + ap_perms.aqm[2], ap_perms.aqm[3]); mutex_unlock(&ap_perms_mutex); return rc; @@ -1486,7 +1505,7 @@ static int aqmask_commit(unsigned long *newaqm) return 0; } -static ssize_t aqmask_store(struct bus_type *bus, const char *buf, +static ssize_t aqmask_store(const struct bus_type *bus, const char *buf, size_t count) { int rc, changes = 0; @@ -1518,13 +1537,12 @@ done: static BUS_ATTR_RW(aqmask); -static ssize_t scans_show(struct bus_type *bus, char *buf) +static ssize_t scans_show(const struct bus_type *bus, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%llu\n", - atomic64_read(&ap_scan_bus_count)); + return sysfs_emit(buf, "%llu\n", atomic64_read(&ap_scan_bus_count)); } -static ssize_t scans_store(struct bus_type *bus, const char *buf, +static ssize_t scans_store(const struct bus_type *bus, const char *buf, size_t count) { AP_DBF_INFO("%s force AP bus rescan\n", __func__); @@ -1536,22 +1554,47 @@ static ssize_t scans_store(struct bus_type *bus, const char *buf, static BUS_ATTR_RW(scans); -static ssize_t bindings_show(struct bus_type *bus, char *buf) +static ssize_t bindings_show(const struct bus_type *bus, char *buf) { int rc; unsigned int apqns, n; ap_calc_bound_apqns(&apqns, &n); if (atomic64_read(&ap_scan_bus_count) >= 1 && n == apqns) - rc = scnprintf(buf, PAGE_SIZE, "%u/%u (complete)\n", n, apqns); + rc = sysfs_emit(buf, "%u/%u (complete)\n", n, apqns); else - rc = scnprintf(buf, PAGE_SIZE, "%u/%u\n", n, apqns); + rc = sysfs_emit(buf, "%u/%u\n", n, apqns); return rc; } static BUS_ATTR_RO(bindings); +static ssize_t features_show(const struct bus_type *bus, char *buf) +{ + int n = 0; + + if (!ap_qci_info) /* QCI not supported */ + return sysfs_emit(buf, "-\n"); + + if (ap_qci_info->apsc) + n += sysfs_emit_at(buf, n, "APSC "); + if (ap_qci_info->apxa) + n += sysfs_emit_at(buf, n, "APXA "); + if (ap_qci_info->qact) + n += sysfs_emit_at(buf, n, "QACT "); + if (ap_qci_info->rc8a) + n += sysfs_emit_at(buf, n, "RC8A "); + if (ap_qci_info->apsb) + n += sysfs_emit_at(buf, n, "APSB "); + + sysfs_emit_at(buf, n == 0 ? 0 : n - 1, "\n"); + + return n; +} + +static BUS_ATTR_RO(features); + static struct attribute *ap_bus_attrs[] = { &bus_attr_ap_domain.attr, &bus_attr_ap_control_domain_mask.attr, @@ -1567,6 +1610,7 @@ static struct attribute *ap_bus_attrs[] = { &bus_attr_aqmask.attr, &bus_attr_scans.attr, &bus_attr_bindings.attr, + &bus_attr_features.attr, NULL, }; ATTRIBUTE_GROUPS(ap_bus); @@ -1762,12 +1806,12 @@ static inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) */ static inline void ap_scan_domains(struct ap_card *ac) { - bool decfg, chkstop; - ap_qid_t qid; - unsigned int func; - struct device *dev; - struct ap_queue *aq; int rc, dom, depth, type, ml; + bool decfg, chkstop; + struct ap_queue *aq; + struct device *dev; + unsigned int func; + ap_qid_t qid; /* * Go through the configuration for the domains and compare them @@ -1786,20 +1830,24 @@ static inline void ap_scan_domains(struct ap_card *ac) AP_DBF_INFO("%s(%d,%d) not in config anymore, rm queue dev\n", __func__, ac->id, dom); device_unregister(dev); - put_device(dev); } - continue; + goto put_dev_and_continue; } /* domain is valid, get info from this APQN */ - if (!ap_queue_info(qid, &type, &func, &depth, - &ml, &decfg, &chkstop)) { - if (aq) { + rc = ap_queue_info(qid, &type, &func, &depth, + &ml, &decfg, &chkstop); + switch (rc) { + case -1: + if (dev) { AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n", __func__, ac->id, dom); device_unregister(dev); - put_device(dev); } - continue; + fallthrough; + case 0: + goto put_dev_and_continue; + default: + break; } /* if no queue device exists, create a new one */ if (!aq) { @@ -1915,12 +1963,12 @@ put_dev_and_continue: */ static inline void ap_scan_adapter(int ap) { - bool decfg, chkstop; - ap_qid_t qid; - unsigned int func; - struct device *dev; - struct ap_card *ac; int rc, dom, depth, type, comp_type, ml; + bool decfg, chkstop; + struct ap_card *ac; + struct device *dev; + unsigned int func; + ap_qid_t qid; /* Is there currently a card device for this adapter ? */ dev = bus_find_device(&ap_bus_type, NULL, @@ -1950,11 +1998,11 @@ static inline void ap_scan_adapter(int ap) if (ap_test_config_usage_domain(dom)) { qid = AP_MKQID(ap, dom); if (ap_queue_info(qid, &type, &func, &depth, - &ml, &decfg, &chkstop)) + &ml, &decfg, &chkstop) > 0) break; } if (dom > ap_max_domain_id) { - /* Could not find a valid APQN for this adapter */ + /* Could not find one valid APQN for this adapter */ if (ac) { AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n", __func__, ap); @@ -1979,7 +2027,6 @@ static inline void ap_scan_adapter(int ap) } return; } - if (ac) { /* Check APQN against existing card device for changes */ if (ac->raw_hwtype != type) { @@ -1988,9 +2035,10 @@ static inline void ap_scan_adapter(int ap) ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); ac = NULL; - } else if (ac->functions != func) { + } else if ((ac->functions & TAPQ_CARD_FUNC_CMP_MASK) != + (func & TAPQ_CARD_FUNC_CMP_MASK)) { AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n", - __func__, ap, type); + __func__, ap, func); ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); ac = NULL; @@ -2245,7 +2293,7 @@ static int __init ap_module_init(void) * If we are running under z/VM adjust polling to z/VM polling rate. */ if (MACHINE_IS_VM) - poll_timeout = 1500000; + poll_high_timeout = 1500000; hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ap_poll_timer.function = ap_poll_timeout; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 0f17933954fb..101fb324476f 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -39,22 +39,32 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) return (*ptr & (0x80000000u >> nr)) != 0; } -#define AP_RESPONSE_NORMAL 0x00 -#define AP_RESPONSE_Q_NOT_AVAIL 0x01 -#define AP_RESPONSE_RESET_IN_PROGRESS 0x02 -#define AP_RESPONSE_DECONFIGURED 0x03 -#define AP_RESPONSE_CHECKSTOPPED 0x04 -#define AP_RESPONSE_BUSY 0x05 -#define AP_RESPONSE_INVALID_ADDRESS 0x06 -#define AP_RESPONSE_OTHERWISE_CHANGED 0x07 -#define AP_RESPONSE_INVALID_GISA 0x08 -#define AP_RESPONSE_Q_FULL 0x10 -#define AP_RESPONSE_NO_PENDING_REPLY 0x10 -#define AP_RESPONSE_INDEX_TOO_BIG 0x11 -#define AP_RESPONSE_NO_FIRST_PART 0x13 -#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 -#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16 -#define AP_RESPONSE_INVALID_DOMAIN 0x42 +#define AP_RESPONSE_NORMAL 0x00 +#define AP_RESPONSE_Q_NOT_AVAIL 0x01 +#define AP_RESPONSE_RESET_IN_PROGRESS 0x02 +#define AP_RESPONSE_DECONFIGURED 0x03 +#define AP_RESPONSE_CHECKSTOPPED 0x04 +#define AP_RESPONSE_BUSY 0x05 +#define AP_RESPONSE_INVALID_ADDRESS 0x06 +#define AP_RESPONSE_OTHERWISE_CHANGED 0x07 +#define AP_RESPONSE_INVALID_GISA 0x08 +#define AP_RESPONSE_Q_BOUND_TO_ANOTHER 0x09 +#define AP_RESPONSE_STATE_CHANGE_IN_PROGRESS 0x0A +#define AP_RESPONSE_Q_NOT_BOUND 0x0B +#define AP_RESPONSE_Q_FULL 0x10 +#define AP_RESPONSE_NO_PENDING_REPLY 0x10 +#define AP_RESPONSE_INDEX_TOO_BIG 0x11 +#define AP_RESPONSE_NO_FIRST_PART 0x13 +#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 +#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16 +#define AP_RESPONSE_Q_BIND_ERROR 0x30 +#define AP_RESPONSE_Q_NOT_AVAIL_FOR_ASSOC 0x31 +#define AP_RESPONSE_Q_NOT_EMPTY 0x32 +#define AP_RESPONSE_BIND_LIMIT_EXCEEDED 0x33 +#define AP_RESPONSE_INVALID_ASSOC_SECRET 0x34 +#define AP_RESPONSE_ASSOC_SECRET_NOT_UNIQUE 0x35 +#define AP_RESPONSE_ASSOC_FAILED 0x36 +#define AP_RESPONSE_INVALID_DOMAIN 0x42 /* * Known device types @@ -92,6 +102,7 @@ enum ap_sm_state { AP_SM_STATE_IDLE, AP_SM_STATE_WORKING, AP_SM_STATE_QUEUE_FULL, + AP_SM_STATE_ASSOC_WAIT, NR_AP_SM_STATES }; @@ -108,10 +119,11 @@ enum ap_sm_event { * AP queue state wait behaviour */ enum ap_sm_wait { - AP_SM_WAIT_AGAIN = 0, /* retry immediately */ - AP_SM_WAIT_TIMEOUT, /* wait for timeout */ - AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ - AP_SM_WAIT_NONE, /* no wait */ + AP_SM_WAIT_AGAIN = 0, /* retry immediately */ + AP_SM_WAIT_HIGH_TIMEOUT, /* poll high freq, wait for timeout */ + AP_SM_WAIT_LOW_TIMEOUT, /* poll low freq, wait for timeout */ + AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ + AP_SM_WAIT_NONE, /* no wait */ NR_AP_SM_WAIT }; @@ -178,7 +190,7 @@ struct ap_device { struct ap_card { struct ap_device ap_dev; int raw_hwtype; /* AP raw hardware type. */ - unsigned int functions; /* AP device function bitfield. */ + unsigned int functions; /* TAPQ GR2 upper 32 facility bits */ int queue_depth; /* AP queue depth.*/ int id; /* AP card number. */ unsigned int maxmsgsize; /* AP msg limit for this card */ @@ -187,6 +199,9 @@ struct ap_card { atomic64_t total_request_count; /* # requests ever for this AP device.*/ }; +#define TAPQ_CARD_FUNC_CMP_MASK 0xFFFF0000 +#define ASSOC_IDX_INVALID 0x10000 + #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) struct ap_queue { @@ -199,6 +214,7 @@ struct ap_queue { bool chkstop; /* checkstop state */ ap_qid_t qid; /* AP queue id. */ bool interrupt; /* indicate if interrupts are enabled */ + unsigned int assoc_idx; /* SE association index */ int queue_count; /* # messages currently on AP queue. */ int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ @@ -209,6 +225,7 @@ struct ap_queue { struct list_head requestq; /* List of message yet to be sent. */ struct ap_message *reply; /* Per device reply message. */ enum ap_sm_state sm_state; /* ap queue state machine state */ + int rapq_fbit; /* fbit arg for next rapq invocation */ int last_err_rc; /* last error state response code */ }; @@ -242,10 +259,10 @@ enum ap_fi_flags { struct ap_message { struct list_head list; /* Request queueing. */ - unsigned long long psmid; /* Message id. */ + unsigned long psmid; /* Message id. */ void *msg; /* Pointer to message buffer. */ - unsigned int len; /* actual msg len in msg buffer */ - unsigned int bufsize; /* allocated msg buffer size */ + size_t len; /* actual msg len in msg buffer */ + size_t bufsize; /* allocated msg buffer size */ u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ struct ap_fi fi; /* Failure Injection cmd */ int rc; /* Return code for this message */ @@ -285,8 +302,8 @@ static inline void ap_release_message(struct ap_message *ap_msg) * for the first time. Otherwise the ap message queue will get * confused. */ -int ap_send(ap_qid_t, unsigned long long, void *, size_t); -int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); +int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen); +int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen); enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event); @@ -296,6 +313,7 @@ void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg); void ap_flush_queue(struct ap_queue *aq); void *ap_airq_ptr(void); +int ap_sb_available(void); void ap_wait(enum ap_sm_wait wait); void ap_request_timeout(struct timer_list *t); void ap_bus_force_rescan(void); diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 6b2170cf186e..b2bd477659a7 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -24,7 +24,7 @@ static ssize_t hwtype_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); + return sysfs_emit(buf, "%d\n", ac->ap_dev.device_type); } static DEVICE_ATTR_RO(hwtype); @@ -34,7 +34,7 @@ static ssize_t raw_hwtype_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); + return sysfs_emit(buf, "%d\n", ac->raw_hwtype); } static DEVICE_ATTR_RO(raw_hwtype); @@ -44,7 +44,7 @@ static ssize_t depth_show(struct device *dev, struct device_attribute *attr, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); + return sysfs_emit(buf, "%d\n", ac->queue_depth); } static DEVICE_ATTR_RO(depth); @@ -54,7 +54,7 @@ static ssize_t ap_functions_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); + return sysfs_emit(buf, "0x%08X\n", ac->functions); } static DEVICE_ATTR_RO(ap_functions); @@ -70,7 +70,7 @@ static ssize_t request_count_show(struct device *dev, spin_lock_bh(&ap_queues_lock); req_cnt = atomic64_read(&ac->total_request_count); spin_unlock_bh(&ap_queues_lock); - return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); + return sysfs_emit(buf, "%llu\n", req_cnt); } static ssize_t request_count_store(struct device *dev, @@ -107,7 +107,7 @@ static ssize_t requestq_count_show(struct device *dev, if (ac == aq->card) reqq_cnt += aq->requestq_count; spin_unlock_bh(&ap_queues_lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); + return sysfs_emit(buf, "%d\n", reqq_cnt); } static DEVICE_ATTR_RO(requestq_count); @@ -126,7 +126,7 @@ static ssize_t pendingq_count_show(struct device *dev, if (ac == aq->card) penq_cnt += aq->pendingq_count; spin_unlock_bh(&ap_queues_lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); + return sysfs_emit(buf, "%d\n", penq_cnt); } static DEVICE_ATTR_RO(pendingq_count); @@ -134,8 +134,7 @@ static DEVICE_ATTR_RO(pendingq_count); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "ap:t%02X\n", - to_ap_dev(dev)->device_type); + return sysfs_emit(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); } static DEVICE_ATTR_RO(modalias); @@ -145,7 +144,7 @@ static ssize_t config_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", ac->config ? 1 : 0); + return sysfs_emit(buf, "%d\n", ac->config ? 1 : 0); } static ssize_t config_store(struct device *dev, @@ -179,7 +178,7 @@ static ssize_t chkstop_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", ac->chkstop ? 1 : 0); + return sysfs_emit(buf, "%d\n", ac->chkstop ? 1 : 0); } static DEVICE_ATTR_RO(chkstop); @@ -189,7 +188,7 @@ static ssize_t max_msg_size_show(struct device *dev, { struct ap_card *ac = to_ap_card(dev); - return scnprintf(buf, PAGE_SIZE, "%u\n", ac->maxmsgsize); + return sysfs_emit(buf, "%u\n", ac->maxmsgsize); } static DEVICE_ATTR_RO(max_msg_size); diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 2637fe1df727..ed8f813653fe 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -18,6 +18,21 @@ static void __ap_flush_queue(struct ap_queue *aq); +/* + * some AP queue helper functions + */ + +static inline bool ap_q_supports_bind(struct ap_queue *aq) +{ + return ap_test_bit(&aq->card->functions, AP_FUNC_EP11) || + ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL); +} + +static inline bool ap_q_supports_assoc(struct ap_queue *aq) +{ + return ap_test_bit(&aq->card->functions, AP_FUNC_EP11); +} + /** * ap_queue_enable_irq(): Enable interrupt support on this AP queue. * @aq: The AP queue @@ -35,6 +50,8 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) qirqctrl.ir = 1; qirqctrl.isc = AP_ISC; status = ap_aqic(aq->qid, qirqctrl, virt_to_phys(ind)); + if (status.async) + return -EPERM; switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_OTHERWISE_CHANGED: @@ -59,7 +76,7 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) * @qid: The AP queue number * @psmid: The program supplied message identifier * @msg: The message text - * @length: The message length + * @msglen: The message length * @special: Special Bit * * Returns AP queue status structure. @@ -68,19 +85,21 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) * because a segment boundary was reached. The NQAP is repeated. */ static inline struct ap_queue_status -__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, +__ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen, int special) { if (special) qid |= 0x400000UL; - return ap_nqap(qid, psmid, msg, length); + return ap_nqap(qid, psmid, msg, msglen); } -int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) +int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen) { struct ap_queue_status status; - status = __ap_send(qid, psmid, msg, length, 0); + status = __ap_send(qid, psmid, msg, msglen, 0); + if (status.async) + return -EPERM; switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -95,13 +114,15 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) } EXPORT_SYMBOL(ap_send); -int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) +int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen) { struct ap_queue_status status; if (!msg) return -EINVAL; - status = ap_dqap(qid, psmid, msg, length, NULL, NULL); + status = ap_dqap(qid, psmid, msg, msglen, NULL, NULL, NULL); + if (status.async) + return -EPERM; switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -150,7 +171,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) do { status = ap_dqap(aq->qid, &aq->reply->psmid, aq->reply->msg, aq->reply->bufsize, - &reslen, &resgr0); + &aq->reply->len, &reslen, &resgr0); parts++; } while (status.response_code == 0xFF && resgr0 != 0); @@ -177,7 +198,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) break; } if (!found) { - AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n", + AP_DBF_WARN("%s unassociated reply psmid=0x%016lx on 0x%02x.%04x\n", __func__, aq->reply->psmid, AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); } @@ -210,6 +231,8 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq) if (!aq->reply) return AP_SM_WAIT_NONE; status = ap_sm_recv(aq); + if (status.async) + return AP_SM_WAIT_NONE; switch (status.response_code) { case AP_RESPONSE_NORMAL: if (aq->queue_count > 0) { @@ -221,7 +244,7 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq) case AP_RESPONSE_NO_PENDING_REPLY: if (aq->queue_count > 0) return aq->interrupt ? - AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; + AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT; aq->sm_state = AP_SM_STATE_IDLE; return AP_SM_WAIT_NONE; default: @@ -261,6 +284,8 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) status = __ap_send(qid, ap_msg->psmid, ap_msg->msg, ap_msg->len, ap_msg->flags & AP_MSG_FLAG_SPECIAL); + if (status.async) + return AP_SM_WAIT_NONE; switch (status.response_code) { case AP_RESPONSE_NORMAL: aq->queue_count = max_t(int, 1, aq->queue_count + 1); @@ -277,10 +302,10 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) case AP_RESPONSE_Q_FULL: aq->sm_state = AP_SM_STATE_QUEUE_FULL; return aq->interrupt ? - AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; + AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_HIGH_TIMEOUT; case AP_RESPONSE_RESET_IN_PROGRESS: aq->sm_state = AP_SM_STATE_RESET_WAIT; - return AP_SM_WAIT_TIMEOUT; + return AP_SM_WAIT_LOW_TIMEOUT; case AP_RESPONSE_INVALID_DOMAIN: AP_DBF_WARN("%s RESPONSE_INVALID_DOMAIN on NQAP\n", __func__); fallthrough; @@ -322,13 +347,16 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) { struct ap_queue_status status; - status = ap_rapq(aq->qid); + status = ap_rapq(aq->qid, aq->rapq_fbit); + if (status.async) + return AP_SM_WAIT_NONE; switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: aq->sm_state = AP_SM_STATE_RESET_WAIT; aq->interrupt = false; - return AP_SM_WAIT_TIMEOUT; + aq->rapq_fbit = 0; + return AP_SM_WAIT_LOW_TIMEOUT; default: aq->dev_state = AP_DEV_STATE_ERROR; aq->last_err_rc = status.response_code; @@ -368,7 +396,7 @@ static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq) return AP_SM_WAIT_AGAIN; case AP_RESPONSE_BUSY: case AP_RESPONSE_RESET_IN_PROGRESS: - return AP_SM_WAIT_TIMEOUT; + return AP_SM_WAIT_LOW_TIMEOUT; case AP_RESPONSE_Q_NOT_AVAIL: case AP_RESPONSE_DECONFIGURED: case AP_RESPONSE_CHECKSTOPPED: @@ -412,7 +440,7 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) return AP_SM_WAIT_AGAIN; fallthrough; case AP_RESPONSE_NO_PENDING_REPLY: - return AP_SM_WAIT_TIMEOUT; + return AP_SM_WAIT_LOW_TIMEOUT; default: aq->dev_state = AP_DEV_STATE_ERROR; aq->last_err_rc = status.response_code; @@ -423,6 +451,59 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) } } +/** + * ap_sm_assoc_wait(): Test queue for completion of a pending + * association request. + * @aq: pointer to the AP queue + */ +static enum ap_sm_wait ap_sm_assoc_wait(struct ap_queue *aq) +{ + struct ap_queue_status status; + struct ap_tapq_gr2 info; + + status = ap_test_queue(aq->qid, 1, &info); + /* handle asynchronous error on this queue */ + if (status.async && status.response_code) { + aq->dev_state = AP_DEV_STATE_ERROR; + aq->last_err_rc = status.response_code; + AP_DBF_WARN("%s asynch RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return AP_SM_WAIT_NONE; + } + if (status.response_code > AP_RESPONSE_BUSY) { + aq->dev_state = AP_DEV_STATE_ERROR; + aq->last_err_rc = status.response_code; + AP_DBF_WARN("%s RC 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return AP_SM_WAIT_NONE; + } + + /* check bs bits */ + switch (info.bs) { + case AP_BS_Q_USABLE: + /* association is through */ + aq->sm_state = AP_SM_STATE_IDLE; + AP_DBF_DBG("%s queue 0x%02x.%04x associated with %u\n", + __func__, AP_QID_CARD(aq->qid), + AP_QID_QUEUE(aq->qid), aq->assoc_idx); + return AP_SM_WAIT_NONE; + case AP_BS_Q_USABLE_NO_SECURE_KEY: + /* association still pending */ + return AP_SM_WAIT_LOW_TIMEOUT; + default: + /* reset from 'outside' happened or no idea at all */ + aq->assoc_idx = ASSOC_IDX_INVALID; + aq->dev_state = AP_DEV_STATE_ERROR; + aq->last_err_rc = status.response_code; + AP_DBF_WARN("%s bs 0x%02x on 0x%02x.%04x -> AP_DEV_STATE_ERROR\n", + __func__, info.bs, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return AP_SM_WAIT_NONE; + } +} + /* * AP state machine jump table */ @@ -451,6 +532,10 @@ static ap_func_t *ap_jumptable[NR_AP_SM_STATES][NR_AP_SM_EVENTS] = { [AP_SM_EVENT_POLL] = ap_sm_read, [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, }, + [AP_SM_STATE_ASSOC_WAIT] = { + [AP_SM_EVENT_POLL] = ap_sm_assoc_wait, + [AP_SM_EVENT_TIMEOUT] = ap_sm_reset, + }, }; enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event) @@ -490,9 +575,9 @@ static ssize_t request_count_show(struct device *dev, spin_unlock_bh(&aq->lock); if (valid) - return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); + return sysfs_emit(buf, "%llu\n", req_cnt); else - return scnprintf(buf, PAGE_SIZE, "-\n"); + return sysfs_emit(buf, "-\n"); } static ssize_t request_count_store(struct device *dev, @@ -520,7 +605,7 @@ static ssize_t requestq_count_show(struct device *dev, if (aq->dev_state > AP_DEV_STATE_UNINITIATED) reqq_cnt = aq->requestq_count; spin_unlock_bh(&aq->lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); + return sysfs_emit(buf, "%d\n", reqq_cnt); } static DEVICE_ATTR_RO(requestq_count); @@ -535,7 +620,7 @@ static ssize_t pendingq_count_show(struct device *dev, if (aq->dev_state > AP_DEV_STATE_UNINITIATED) penq_cnt = aq->pendingq_count; spin_unlock_bh(&aq->lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); + return sysfs_emit(buf, "%d\n", penq_cnt); } static DEVICE_ATTR_RO(pendingq_count); @@ -550,14 +635,14 @@ static ssize_t reset_show(struct device *dev, switch (aq->sm_state) { case AP_SM_STATE_RESET_START: case AP_SM_STATE_RESET_WAIT: - rc = scnprintf(buf, PAGE_SIZE, "Reset in progress.\n"); + rc = sysfs_emit(buf, "Reset in progress.\n"); break; case AP_SM_STATE_WORKING: case AP_SM_STATE_QUEUE_FULL: - rc = scnprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); + rc = sysfs_emit(buf, "Reset Timer armed.\n"); break; default: - rc = scnprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); + rc = sysfs_emit(buf, "No Reset Timer set.\n"); } spin_unlock_bh(&aq->lock); return rc; @@ -591,11 +676,11 @@ static ssize_t interrupt_show(struct device *dev, spin_lock_bh(&aq->lock); if (aq->sm_state == AP_SM_STATE_SETIRQ_WAIT) - rc = scnprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); + rc = sysfs_emit(buf, "Enable Interrupt pending.\n"); else if (aq->interrupt) - rc = scnprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); + rc = sysfs_emit(buf, "Interrupts enabled.\n"); else - rc = scnprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); + rc = sysfs_emit(buf, "Interrupts disabled.\n"); spin_unlock_bh(&aq->lock); return rc; } @@ -609,7 +694,7 @@ static ssize_t config_show(struct device *dev, int rc; spin_lock_bh(&aq->lock); - rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->config ? 1 : 0); + rc = sysfs_emit(buf, "%d\n", aq->config ? 1 : 0); spin_unlock_bh(&aq->lock); return rc; } @@ -623,13 +708,33 @@ static ssize_t chkstop_show(struct device *dev, int rc; spin_lock_bh(&aq->lock); - rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->chkstop ? 1 : 0); + rc = sysfs_emit(buf, "%d\n", aq->chkstop ? 1 : 0); spin_unlock_bh(&aq->lock); return rc; } static DEVICE_ATTR_RO(chkstop); +static ssize_t ap_functions_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + struct ap_queue_status status; + struct ap_tapq_gr2 info; + + status = ap_test_queue(aq->qid, 1, &info); + if (status.response_code > AP_RESPONSE_BUSY) { + AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } + + return sysfs_emit(buf, "0x%08X\n", info.fac); +} + +static DEVICE_ATTR_RO(ap_functions); + #ifdef CONFIG_ZCRYPT_DEBUG static ssize_t states_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -641,50 +746,46 @@ static ssize_t states_show(struct device *dev, /* queue device state */ switch (aq->dev_state) { case AP_DEV_STATE_UNINITIATED: - rc = scnprintf(buf, PAGE_SIZE, "UNINITIATED\n"); + rc = sysfs_emit(buf, "UNINITIATED\n"); break; case AP_DEV_STATE_OPERATING: - rc = scnprintf(buf, PAGE_SIZE, "OPERATING"); + rc = sysfs_emit(buf, "OPERATING"); break; case AP_DEV_STATE_SHUTDOWN: - rc = scnprintf(buf, PAGE_SIZE, "SHUTDOWN"); + rc = sysfs_emit(buf, "SHUTDOWN"); break; case AP_DEV_STATE_ERROR: - rc = scnprintf(buf, PAGE_SIZE, "ERROR"); + rc = sysfs_emit(buf, "ERROR"); break; default: - rc = scnprintf(buf, PAGE_SIZE, "UNKNOWN"); + rc = sysfs_emit(buf, "UNKNOWN"); } /* state machine state */ if (aq->dev_state) { switch (aq->sm_state) { case AP_SM_STATE_RESET_START: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [RESET_START]\n"); + rc += sysfs_emit_at(buf, rc, " [RESET_START]\n"); break; case AP_SM_STATE_RESET_WAIT: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [RESET_WAIT]\n"); + rc += sysfs_emit_at(buf, rc, " [RESET_WAIT]\n"); break; case AP_SM_STATE_SETIRQ_WAIT: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [SETIRQ_WAIT]\n"); + rc += sysfs_emit_at(buf, rc, " [SETIRQ_WAIT]\n"); break; case AP_SM_STATE_IDLE: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [IDLE]\n"); + rc += sysfs_emit_at(buf, rc, " [IDLE]\n"); break; case AP_SM_STATE_WORKING: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [WORKING]\n"); + rc += sysfs_emit_at(buf, rc, " [WORKING]\n"); break; case AP_SM_STATE_QUEUE_FULL: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [FULL]\n"); + rc += sysfs_emit_at(buf, rc, " [FULL]\n"); + break; + case AP_SM_STATE_ASSOC_WAIT: + rc += sysfs_emit_at(buf, rc, " [ASSOC_WAIT]\n"); break; default: - rc += scnprintf(buf + rc, PAGE_SIZE - rc, - " [UNKNOWN]\n"); + rc += sysfs_emit_at(buf, rc, " [UNKNOWN]\n"); } } spin_unlock_bh(&aq->lock); @@ -705,33 +806,33 @@ static ssize_t last_err_rc_show(struct device *dev, switch (rc) { case AP_RESPONSE_NORMAL: - return scnprintf(buf, PAGE_SIZE, "NORMAL\n"); + return sysfs_emit(buf, "NORMAL\n"); case AP_RESPONSE_Q_NOT_AVAIL: - return scnprintf(buf, PAGE_SIZE, "Q_NOT_AVAIL\n"); + return sysfs_emit(buf, "Q_NOT_AVAIL\n"); case AP_RESPONSE_RESET_IN_PROGRESS: - return scnprintf(buf, PAGE_SIZE, "RESET_IN_PROGRESS\n"); + return sysfs_emit(buf, "RESET_IN_PROGRESS\n"); case AP_RESPONSE_DECONFIGURED: - return scnprintf(buf, PAGE_SIZE, "DECONFIGURED\n"); + return sysfs_emit(buf, "DECONFIGURED\n"); case AP_RESPONSE_CHECKSTOPPED: - return scnprintf(buf, PAGE_SIZE, "CHECKSTOPPED\n"); + return sysfs_emit(buf, "CHECKSTOPPED\n"); case AP_RESPONSE_BUSY: - return scnprintf(buf, PAGE_SIZE, "BUSY\n"); + return sysfs_emit(buf, "BUSY\n"); case AP_RESPONSE_INVALID_ADDRESS: - return scnprintf(buf, PAGE_SIZE, "INVALID_ADDRESS\n"); + return sysfs_emit(buf, "INVALID_ADDRESS\n"); case AP_RESPONSE_OTHERWISE_CHANGED: - return scnprintf(buf, PAGE_SIZE, "OTHERWISE_CHANGED\n"); + return sysfs_emit(buf, "OTHERWISE_CHANGED\n"); case AP_RESPONSE_Q_FULL: - return scnprintf(buf, PAGE_SIZE, "Q_FULL/NO_PENDING_REPLY\n"); + return sysfs_emit(buf, "Q_FULL/NO_PENDING_REPLY\n"); case AP_RESPONSE_INDEX_TOO_BIG: - return scnprintf(buf, PAGE_SIZE, "INDEX_TOO_BIG\n"); + return sysfs_emit(buf, "INDEX_TOO_BIG\n"); case AP_RESPONSE_NO_FIRST_PART: - return scnprintf(buf, PAGE_SIZE, "NO_FIRST_PART\n"); + return sysfs_emit(buf, "NO_FIRST_PART\n"); case AP_RESPONSE_MESSAGE_TOO_BIG: - return scnprintf(buf, PAGE_SIZE, "MESSAGE_TOO_BIG\n"); + return sysfs_emit(buf, "MESSAGE_TOO_BIG\n"); case AP_RESPONSE_REQ_FAC_NOT_INST: - return scnprintf(buf, PAGE_SIZE, "REQ_FAC_NOT_INST\n"); + return sysfs_emit(buf, "REQ_FAC_NOT_INST\n"); default: - return scnprintf(buf, PAGE_SIZE, "response code %d\n", rc); + return sysfs_emit(buf, "response code %d\n", rc); } } static DEVICE_ATTR_RO(last_err_rc); @@ -745,6 +846,7 @@ static struct attribute *ap_queue_dev_attrs[] = { &dev_attr_interrupt.attr, &dev_attr_config.attr, &dev_attr_chkstop.attr, + &dev_attr_ap_functions.attr, #ifdef CONFIG_ZCRYPT_DEBUG &dev_attr_states.attr, &dev_attr_last_err_rc.attr, @@ -766,6 +868,186 @@ static struct device_type ap_queue_type = { .groups = ap_queue_dev_attr_groups, }; +static ssize_t se_bind_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + struct ap_queue_status status; + struct ap_tapq_gr2 info; + + if (!ap_q_supports_bind(aq)) + return sysfs_emit(buf, "-\n"); + + status = ap_test_queue(aq->qid, 1, &info); + if (status.response_code > AP_RESPONSE_BUSY) { + AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } + switch (info.bs) { + case AP_BS_Q_USABLE: + case AP_BS_Q_USABLE_NO_SECURE_KEY: + return sysfs_emit(buf, "bound\n"); + default: + return sysfs_emit(buf, "unbound\n"); + } +} + +static ssize_t se_bind_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ap_queue *aq = to_ap_queue(dev); + struct ap_queue_status status; + bool value; + int rc; + + if (!ap_q_supports_bind(aq)) + return -EINVAL; + + /* only 0 (unbind) and 1 (bind) allowed */ + rc = kstrtobool(buf, &value); + if (rc) + return rc; + + if (value) { + /* bind, do BAPQ */ + spin_lock_bh(&aq->lock); + if (aq->sm_state < AP_SM_STATE_IDLE) { + spin_unlock_bh(&aq->lock); + return -EBUSY; + } + status = ap_bapq(aq->qid); + spin_unlock_bh(&aq->lock); + if (status.response_code) { + AP_DBF_WARN("%s RC 0x%02x on bapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), + AP_QID_QUEUE(aq->qid)); + return -EIO; + } + } else { + /* unbind, set F bit arg and trigger RAPQ */ + spin_lock_bh(&aq->lock); + __ap_flush_queue(aq); + aq->rapq_fbit = 1; + aq->assoc_idx = ASSOC_IDX_INVALID; + aq->sm_state = AP_SM_STATE_RESET_START; + ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + } + + return count; +} + +static DEVICE_ATTR_RW(se_bind); + +static ssize_t se_associate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + struct ap_queue_status status; + struct ap_tapq_gr2 info; + + if (!ap_q_supports_assoc(aq)) + return sysfs_emit(buf, "-\n"); + + status = ap_test_queue(aq->qid, 1, &info); + if (status.response_code > AP_RESPONSE_BUSY) { + AP_DBF_DBG("%s RC 0x%02x on tapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } + + switch (info.bs) { + case AP_BS_Q_USABLE: + if (aq->assoc_idx == ASSOC_IDX_INVALID) { + AP_DBF_WARN("%s AP_BS_Q_USABLE but invalid assoc_idx\n", __func__); + return -EIO; + } + return sysfs_emit(buf, "associated %u\n", aq->assoc_idx); + case AP_BS_Q_USABLE_NO_SECURE_KEY: + if (aq->assoc_idx != ASSOC_IDX_INVALID) + return sysfs_emit(buf, "association pending\n"); + fallthrough; + default: + return sysfs_emit(buf, "unassociated\n"); + } +} + +static ssize_t se_associate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ap_queue *aq = to_ap_queue(dev); + struct ap_queue_status status; + unsigned int value; + int rc; + + if (!ap_q_supports_assoc(aq)) + return -EINVAL; + + /* association index needs to be >= 0 */ + rc = kstrtouint(buf, 0, &value); + if (rc) + return rc; + if (value >= ASSOC_IDX_INVALID) + return -EINVAL; + + spin_lock_bh(&aq->lock); + + /* sm should be in idle state */ + if (aq->sm_state != AP_SM_STATE_IDLE) { + spin_unlock_bh(&aq->lock); + return -EBUSY; + } + + /* already associated or association pending ? */ + if (aq->assoc_idx != ASSOC_IDX_INVALID) { + spin_unlock_bh(&aq->lock); + return -EINVAL; + } + + /* trigger the asynchronous association request */ + status = ap_aapq(aq->qid, value); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_STATE_CHANGE_IN_PROGRESS: + aq->sm_state = AP_SM_STATE_ASSOC_WAIT; + aq->assoc_idx = value; + ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + break; + default: + spin_unlock_bh(&aq->lock); + AP_DBF_WARN("%s RC 0x%02x on aapq(0x%02x.%04x)\n", + __func__, status.response_code, + AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid)); + return -EIO; + } + + return count; +} + +static DEVICE_ATTR_RW(se_associate); + +static struct attribute *ap_queue_dev_sb_attrs[] = { + &dev_attr_se_bind.attr, + &dev_attr_se_associate.attr, + NULL +}; + +static struct attribute_group ap_queue_dev_sb_attr_group = { + .attrs = ap_queue_dev_sb_attrs +}; + +static const struct attribute_group *ap_queue_dev_sb_attr_groups[] = { + &ap_queue_dev_sb_attr_group, + NULL +}; + static void ap_queue_device_release(struct device *dev) { struct ap_queue *aq = to_ap_queue(dev); @@ -787,6 +1069,9 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) aq->ap_dev.device.release = ap_queue_device_release; aq->ap_dev.device.type = &ap_queue_type; aq->ap_dev.device_type = device_type; + // add optional SE secure binding attributes group + if (ap_sb_available() && is_prot_virt_guest()) + aq->ap_dev.device.groups = ap_queue_dev_sb_attr_groups; aq->qid = qid; aq->interrupt = false; spin_lock_init(&aq->lock); @@ -922,7 +1207,7 @@ void ap_queue_remove(struct ap_queue *aq) * to the initial value AP_DEV_STATE_UNINITIATED. */ spin_lock_bh(&aq->lock); - ap_zapq(aq->qid); + ap_zapq(aq->qid, 0); aq->dev_state = AP_DEV_STATE_UNINITIATED; spin_unlock_bh(&aq->lock); } @@ -933,6 +1218,7 @@ void ap_queue_init_state(struct ap_queue *aq) aq->dev_state = AP_DEV_STATE_OPERATING; aq->sm_state = AP_SM_STATE_RESET_START; aq->last_err_rc = 0; + aq->assoc_idx = ASSOC_IDX_INVALID; ap_wait(ap_sm_event(aq, AP_SM_EVENT_POLL)); spin_unlock_bh(&aq->lock); } diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 5a05d1cdfec2..a8def50c149b 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -1293,6 +1293,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return PTR_ERR(kkey); rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) break; @@ -1426,6 +1427,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, kkey, ktp.keylen, &ktp.protkey); DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc); kfree(apqns); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) break; @@ -1552,6 +1554,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, protkey, &protkeylen); DEBUG_DBG("%s pkey_keyblob2pkey3()=%d\n", __func__, rc); kfree(apqns); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) { kfree(protkey); diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index a48c6938ae68..a5ab03e42ff1 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -60,14 +60,8 @@ static void vfio_ap_matrix_dev_release(struct device *dev) kfree(matrix_dev); } -static int matrix_bus_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - static struct bus_type matrix_bus = { .name = "matrix", - .match = &matrix_bus_match, }; static struct device_driver matrix_driver = { diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 72e10abb103a..cfbcb864ab63 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -599,9 +599,9 @@ out_unlock: static void vfio_ap_matrix_init(struct ap_config_info *info, struct ap_matrix *matrix) { - matrix->apm_max = info->apxa ? info->Na : 63; - matrix->aqm_max = info->apxa ? info->Nd : 15; - matrix->adm_max = info->apxa ? info->Nd : 15; + matrix->apm_max = info->apxa ? info->na : 63; + matrix->aqm_max = info->apxa ? info->nd : 15; + matrix->adm_max = info->apxa ? info->nd : 15; } static void vfio_ap_mdev_update_guest_apcb(struct ap_matrix_mdev *matrix_mdev) @@ -1657,7 +1657,7 @@ static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q) if (!q) return 0; retry_zapq: - status = ap_zapq(q->apqn); + status = ap_zapq(q->apqn, 0); q->reset_rc = status.response_code; switch (status.response_code) { case AP_RESPONSE_NORMAL: @@ -2115,8 +2115,8 @@ static void vfio_ap_filter_apid_by_qtype(unsigned long *apm, unsigned long *aqm) { bool apid_cleared; struct ap_queue_status status; - unsigned long apid, apqi, info; - int qtype, qtype_mask = 0xff000000; + unsigned long apid, apqi; + struct ap_tapq_gr2 info; for_each_set_bit_inv(apid, apm, AP_DEVICES) { apid_cleared = false; @@ -2133,15 +2133,13 @@ static void vfio_ap_filter_apid_by_qtype(unsigned long *apm, unsigned long *aqm) case AP_RESPONSE_DECONFIGURED: case AP_RESPONSE_CHECKSTOPPED: case AP_RESPONSE_BUSY: - qtype = info & qtype_mask; - /* * The vfio_ap device driver only * supports CEX4 and newer adapters, so * remove the APID if the adapter is * older than a CEX4. */ - if (qtype < AP_DEVICE_TYPE_CEX4) { + if (info.at < AP_DEVICE_TYPE_CEX4) { clear_bit_inv(apid, apm); apid_cleared = true; } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 6fe05bb82c77..444ef95d3f59 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -159,25 +159,20 @@ static ssize_t ioctlmask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i, rc; struct zcdn_device *zcdndev = to_zcdn_dev(dev); + int i, n; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - buf[0] = '0'; - buf[1] = 'x'; + n = sysfs_emit(buf, "0x"); for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++) - snprintf(buf + 2 + 2 * i * sizeof(long), - PAGE_SIZE - 2 - 2 * i * sizeof(long), - "%016lx", zcdndev->perms.ioctlm[i]); - buf[2 + 2 * i * sizeof(long)] = '\n'; - buf[2 + 2 * i * sizeof(long) + 1] = '\0'; - rc = 2 + 2 * i * sizeof(long) + 1; + n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.ioctlm[i]); + n += sysfs_emit_at(buf, n, "\n"); mutex_unlock(&ap_perms_mutex); - return rc; + return n; } static ssize_t ioctlmask_store(struct device *dev, @@ -201,25 +196,20 @@ static ssize_t apmask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i, rc; struct zcdn_device *zcdndev = to_zcdn_dev(dev); + int i, n; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - buf[0] = '0'; - buf[1] = 'x'; + n = sysfs_emit(buf, "0x"); for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++) - snprintf(buf + 2 + 2 * i * sizeof(long), - PAGE_SIZE - 2 - 2 * i * sizeof(long), - "%016lx", zcdndev->perms.apm[i]); - buf[2 + 2 * i * sizeof(long)] = '\n'; - buf[2 + 2 * i * sizeof(long) + 1] = '\0'; - rc = 2 + 2 * i * sizeof(long) + 1; + n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.apm[i]); + n += sysfs_emit_at(buf, n, "\n"); mutex_unlock(&ap_perms_mutex); - return rc; + return n; } static ssize_t apmask_store(struct device *dev, @@ -243,25 +233,20 @@ static ssize_t aqmask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i, rc; struct zcdn_device *zcdndev = to_zcdn_dev(dev); + int i, n; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - buf[0] = '0'; - buf[1] = 'x'; + n = sysfs_emit(buf, "0x"); for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++) - snprintf(buf + 2 + 2 * i * sizeof(long), - PAGE_SIZE - 2 - 2 * i * sizeof(long), - "%016lx", zcdndev->perms.aqm[i]); - buf[2 + 2 * i * sizeof(long)] = '\n'; - buf[2 + 2 * i * sizeof(long) + 1] = '\0'; - rc = 2 + 2 * i * sizeof(long) + 1; + n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.aqm[i]); + n += sysfs_emit_at(buf, n, "\n"); mutex_unlock(&ap_perms_mutex); - return rc; + return n; } static ssize_t aqmask_store(struct device *dev, @@ -285,25 +270,20 @@ static ssize_t admask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i, rc; struct zcdn_device *zcdndev = to_zcdn_dev(dev); + int i, n; if (mutex_lock_interruptible(&ap_perms_mutex)) return -ERESTARTSYS; - buf[0] = '0'; - buf[1] = 'x'; + n = sysfs_emit(buf, "0x"); for (i = 0; i < sizeof(zcdndev->perms.adm) / sizeof(long); i++) - snprintf(buf + 2 + 2 * i * sizeof(long), - PAGE_SIZE - 2 - 2 * i * sizeof(long), - "%016lx", zcdndev->perms.adm[i]); - buf[2 + 2 * i * sizeof(long)] = '\n'; - buf[2 + 2 * i * sizeof(long) + 1] = '\0'; - rc = 2 + 2 * i * sizeof(long) + 1; + n += sysfs_emit_at(buf, n, "%016lx", zcdndev->perms.adm[i]); + n += sysfs_emit_at(buf, n, "\n"); mutex_unlock(&ap_perms_mutex); - return rc; + return n; } static ssize_t admask_store(struct device *dev, @@ -340,8 +320,8 @@ static const struct attribute_group *zcdn_dev_attr_groups[] = { NULL }; -static ssize_t zcdn_create_store(struct class *class, - struct class_attribute *attr, +static ssize_t zcdn_create_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t count) { int rc; @@ -357,8 +337,8 @@ static ssize_t zcdn_create_store(struct class *class, static const struct class_attribute class_attr_zcdn_create = __ATTR(create, 0600, NULL, zcdn_create_store); -static ssize_t zcdn_destroy_store(struct class *class, - struct class_attribute *attr, +static ssize_t zcdn_destroy_store(const struct class *class, + const struct class_attribute *attr, const char *buf, size_t count) { int rc; @@ -2171,7 +2151,7 @@ static int __init zcdn_init(void) int rc; /* create a new class 'zcrypt' */ - zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME); + zcrypt_class = class_create(ZCRYPT_NAME); if (IS_ERR(zcrypt_class)) { rc = PTR_ERR(zcrypt_class); goto out_class_create_failed; diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 6ca675042416..c815722d0ac8 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -41,7 +41,7 @@ static ssize_t type_show(struct device *dev, { struct zcrypt_card *zc = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); + return sysfs_emit(buf, "%s\n", zc->type_string); } static DEVICE_ATTR_RO(type); @@ -54,7 +54,7 @@ static ssize_t online_show(struct device *dev, struct ap_card *ac = to_ap_card(dev); int online = ac->config && zc->online ? 1 : 0; - return scnprintf(buf, PAGE_SIZE, "%d\n", online); + return sysfs_emit(buf, "%d\n", online); } static ssize_t online_store(struct device *dev, @@ -118,7 +118,7 @@ static ssize_t load_show(struct device *dev, { struct zcrypt_card *zc = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); + return sysfs_emit(buf, "%d\n", atomic_read(&zc->load)); } static DEVICE_ATTR_RO(load); diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index 6229ba9c56d9..f5907b67db29 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h @@ -89,10 +89,7 @@ struct cca_pvt_ext_crt_sec { #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 /** - * Set up private key fields of a type6 MEX message. The _pad variant - * strips leading zeroes from the b_key. - * Note that all numerics in the key token are big-endian, - * while the entries in the key block header are little-endian. + * Set up private key fields of a type6 MEX message. * * @mex: pointer to user input data * @p: pointer to memory area for the key @@ -111,10 +108,9 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) struct t6_keyblock_hdr t6_hdr; struct cca_token_hdr pubhdr; struct cca_public_sec pubsec; - char exponent[0]; + char exponent[]; } __packed *key = p; - unsigned char *temp; - int i; + unsigned char *ptr; /* * The inputdatalength was a selection criteria in the dispatching @@ -131,37 +127,29 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) key->pubsec = static_pub_sec; /* key parameter block */ - temp = key->exponent; - if (copy_from_user(temp, mex->b_key, mex->inputdatalength)) + ptr = key->exponent; + if (copy_from_user(ptr, mex->b_key, mex->inputdatalength)) return -EFAULT; - /* Strip leading zeroes from b_key. */ - for (i = 0; i < mex->inputdatalength; i++) - if (temp[i]) - break; - if (i >= mex->inputdatalength) - return -EINVAL; - memmove(temp, temp + i, mex->inputdatalength - i); - temp += mex->inputdatalength - i; + ptr += mex->inputdatalength; /* modulus */ - if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength)) + if (copy_from_user(ptr, mex->n_modulus, mex->inputdatalength)) return -EFAULT; key->pubsec.modulus_bit_len = 8 * mex->inputdatalength; key->pubsec.modulus_byte_len = mex->inputdatalength; - key->pubsec.exponent_len = mex->inputdatalength - i; + key->pubsec.exponent_len = mex->inputdatalength; key->pubsec.section_length = sizeof(key->pubsec) + - 2 * mex->inputdatalength - i; + 2 * mex->inputdatalength; key->pubhdr.token_length = key->pubsec.section_length + sizeof(key->pubhdr); key->t6_hdr.ulen = key->pubhdr.token_length + 4; key->t6_hdr.blen = key->pubhdr.token_length + 6; - return sizeof(*key) + 2 * mex->inputdatalength - i; + + return sizeof(*key) + 2 * mex->inputdatalength; } /** * Set up private key fields of a type6 CRT message. - * Note that all numerics in the key token are big-endian, - * while the entries in the key block header are little-endian. * * @mex: pointer to user input data * @p: pointer to memory area for the key @@ -180,7 +168,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) struct t6_keyblock_hdr t6_hdr; struct cca_token_hdr token; struct cca_pvt_ext_crt_sec pvt; - char key_parts[0]; + char key_parts[]; } __packed *key = p; struct cca_public_sec *pub; int short_len, long_len, pad_len, key_len, size; @@ -242,6 +230,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) * used. */ memcpy((char *)(pub + 1), pk_exponent, 3); + return size; } diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 60ba20a133be..8c8808cc68a4 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -450,18 +450,18 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, char rule_array[8]; struct lv1 { u16 len; - u8 clrkey[0]; + u8 clrkey[]; } lv1; - struct lv2 { - u16 len; - struct keyid { - u16 len; - u16 attr; - u8 data[SECKEYBLOBSIZE]; - } keyid; - } lv2; + /* followed by struct lv2 */ } __packed * preqparm; - struct lv2 *plv2; + struct lv2 { + u16 len; + struct keyid { + u16 len; + u16 attr; + u8 data[SECKEYBLOBSIZE]; + } keyid; + } __packed * plv2; struct cmrepparm { u8 subfunc_code[2]; u16 rule_array_len; @@ -512,11 +512,11 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, } preqparm->lv1.len = sizeof(struct lv1) + keysize; memcpy(preqparm->lv1.clrkey, clrkey, keysize); - plv2 = (struct lv2 *)(((u8 *)&preqparm->lv2) + keysize); + plv2 = (struct lv2 *)(((u8 *)preqparm) + sizeof(*preqparm) + keysize); plv2->len = sizeof(struct lv2); plv2->keyid.len = sizeof(struct keyid); plv2->keyid.attr = 0x30; - preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; + preqcblk->req_parml = sizeof(*preqparm) + keysize + sizeof(*plv2); /* fill xcrb struct */ prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); @@ -761,22 +761,22 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, u16 key_name_2_len; u16 user_data_1_len; u16 user_data_2_len; - u8 key_name_1[0]; - u8 key_name_2[0]; - u8 user_data_1[0]; - u8 user_data_2[0]; + /* u8 key_name_1[]; */ + /* u8 key_name_2[]; */ + /* u8 user_data_1[]; */ + /* u8 user_data_2[]; */ } vud; struct { u16 len; struct { u16 len; u16 flag; - u8 kek_id_1[0]; + /* u8 kek_id_1[]; */ } tlv1; struct { u16 len; u16 flag; - u8 kek_id_2[0]; + /* u8 kek_id_2[]; */ } tlv2; struct { u16 len; @@ -786,17 +786,17 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, struct { u16 len; u16 flag; - u8 gen_key_id_1_label[0]; + /* u8 gen_key_id_1_label[]; */ } tlv4; struct { u16 len; u16 flag; - u8 gen_key_id_2[0]; + /* u8 gen_key_id_2[]; */ } tlv5; struct { u16 len; u16 flag; - u8 gen_key_id_2_label[0]; + /* u8 gen_key_id_2_label[]; */ } tlv6; } kb; } __packed * preqparm; @@ -811,7 +811,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, struct { u16 len; u16 flag; - u8 gen_key[0]; /* 120-136 bytes */ + u8 gen_key[]; /* 120-136 bytes */ } tlv1; } kb; } __packed * prepparm; @@ -955,7 +955,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, struct rule_array_block { u8 subfunc_code[2]; u16 rule_array_len; - char rule_array[0]; + char rule_array[]; } __packed * preq_ra_block; struct vud_block { u16 len; @@ -967,7 +967,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, struct { u16 len; u16 flag; /* 0x0063 */ - u8 clr_key[0]; /* clear key value bytes */ + u8 clr_key[]; /* clear key value bytes */ } tlv2; } __packed * preq_vud_block; struct key_block { @@ -975,7 +975,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, struct { u16 len; u16 flag; /* 0x0030 */ - u8 key_token[0]; /* key skeleton */ + u8 key_token[]; /* key skeleton */ } tlv1; } __packed * preq_key_block; struct iprepparm { @@ -989,7 +989,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain, struct { u16 len; u16 flag; /* 0x0030 */ - u8 key_token[0]; /* key token */ + u8 key_token[]; /* key token */ } tlv1; } kb; } __packed * prepparm; @@ -1201,7 +1201,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, u16 len; u16 cca_key_token_len; u16 cca_key_token_flags; - u8 cca_key_token[0]; // 64 or more + u8 cca_key_token[]; /* 64 or more */ } kb; } __packed * preqparm; struct aurepparm { @@ -1370,7 +1370,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, u16 len; u16 cca_key_token_len; u16 cca_key_token_flags; - u8 cca_key_token[0]; + u8 cca_key_token[]; } kb; } __packed * preqparm; struct aurepparm { @@ -1387,17 +1387,15 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, u8 form; u8 pad1[3]; u16 keylen; - u8 key[0]; /* the key (keylen bytes) */ - u16 keyattrlen; - u8 keyattr[32]; - u8 pad2[1]; - u8 vptype; - u8 vp[32]; /* verification pattern */ + u8 key[]; /* the key (keylen bytes) */ + /* u16 keyattrlen; */ + /* u8 keyattr[32]; */ + /* u8 pad2[1]; */ + /* u8 vptype; */ + /* u8 vp[32]; verification pattern */ } ckb; } vud; - struct { - u16 len; - } kb; + /* followed by a key block */ } __packed * prepparm; int keylen = ((struct eccprivkeytoken *)key)->len; @@ -1525,7 +1523,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, size_t parmbsize = sizeof(struct fqreqparm); struct fqrepparm { u8 subfunc_code[2]; - u8 lvdata[0]; + u8 lvdata[]; } __packed * prepparm; /* get already prepared memory for 2 cprbs with param block each */ diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c index cb7849defce3..251b5bd3d19c 100644 --- a/drivers/s390/crypto/zcrypt_cex2c.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -75,7 +75,7 @@ static ssize_t cca_serialnr_show(struct device *dev, if (ap_domain_index >= 0) cca_get_info(ac->id, ap_domain_index, &ci, zc->online); - return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial); + return sysfs_emit(buf, "%s\n", ci.serial); } static struct device_attribute dev_attr_cca_serialnr = @@ -110,51 +110,46 @@ static ssize_t cca_mkvps_show(struct device *dev, &ci, zq->online); if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') - n = scnprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", - new_state[ci.new_aes_mk_state - '1'], - ci.new_aes_mkvp); + n = sysfs_emit(buf, "AES NEW: %s 0x%016llx\n", + new_state[ci.new_aes_mk_state - '1'], + ci.new_aes_mkvp); else - n = scnprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); + n = sysfs_emit(buf, "AES NEW: - -\n"); if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "AES CUR: %s 0x%016llx\n", - cao_state[ci.cur_aes_mk_state - '1'], - ci.cur_aes_mkvp); + n += sysfs_emit_at(buf, n, "AES CUR: %s 0x%016llx\n", + cao_state[ci.cur_aes_mk_state - '1'], + ci.cur_aes_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); + n += sysfs_emit_at(buf, n, "AES CUR: - -\n"); if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "AES OLD: %s 0x%016llx\n", - cao_state[ci.old_aes_mk_state - '1'], - ci.old_aes_mkvp); + n += sysfs_emit_at(buf, n, "AES OLD: %s 0x%016llx\n", + cao_state[ci.old_aes_mk_state - '1'], + ci.old_aes_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); + n += sysfs_emit_at(buf, n, "AES OLD: - -\n"); if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA NEW: %s 0x%016llx\n", - new_state[ci.new_apka_mk_state - '1'], - ci.new_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA NEW: %s 0x%016llx\n", + new_state[ci.new_apka_mk_state - '1'], + ci.new_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n"); + n += sysfs_emit_at(buf, n, "APKA NEW: - -\n"); if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA CUR: %s 0x%016llx\n", - cao_state[ci.cur_apka_mk_state - '1'], - ci.cur_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA CUR: %s 0x%016llx\n", + cao_state[ci.cur_apka_mk_state - '1'], + ci.cur_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n"); + n += sysfs_emit_at(buf, n, "APKA CUR: - -\n"); if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA OLD: %s 0x%016llx\n", - cao_state[ci.old_apka_mk_state - '1'], - ci.old_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA OLD: %s 0x%016llx\n", + cao_state[ci.old_apka_mk_state - '1'], + ci.old_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n"); + n += sysfs_emit_at(buf, n, "APKA OLD: - -\n"); return n; } @@ -181,7 +176,7 @@ static const struct attribute_group cca_queue_attr_grp = { static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) { struct ap_message ap_msg; - unsigned long long psmid; + unsigned long psmid; unsigned int domain; struct { struct type86_hdr hdr; @@ -203,21 +198,22 @@ static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) ap_msg.msg = (void *)get_zeroed_page(GFP_KERNEL); if (!ap_msg.msg) return -ENOMEM; + ap_msg.bufsize = PAGE_SIZE; rng_type6cprb_msgx(&ap_msg, 4, &domain); msg = ap_msg.msg; msg->cprbx.domain = AP_QID_QUEUE(aq->qid); - rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.msg, ap_msg.len); + rc = ap_send(aq->qid, 0x0102030405060708UL, ap_msg.msg, ap_msg.len); if (rc) goto out_free; /* Wait for the test message to complete. */ for (i = 0; i < 2 * HZ; i++) { msleep(1000 / HZ); - rc = ap_recv(aq->qid, &psmid, ap_msg.msg, 4096); - if (rc == 0 && psmid == 0x0102030405060708ULL) + rc = ap_recv(aq->qid, &psmid, ap_msg.msg, ap_msg.bufsize); + if (rc == 0 && psmid == 0x0102030405060708UL) break; } @@ -342,7 +338,7 @@ static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) zq->queue = aq; zq->online = 1; atomic_set(&zq->load, 0); - ap_rapq(aq->qid); + ap_rapq(aq->qid, 0); rc = zcrypt_cex2c_rng_supported(aq); if (rc < 0) { zcrypt_queue_free(zq); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index b03916b7538b..9cfce9ff2e65 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -88,7 +88,7 @@ static ssize_t cca_serialnr_show(struct device *dev, if (ap_domain_index >= 0) cca_get_info(ac->id, ap_domain_index, &ci, zc->online); - return scnprintf(buf, PAGE_SIZE, "%s\n", ci.serial); + return sysfs_emit(buf, "%s\n", ci.serial); } static struct device_attribute dev_attr_cca_serialnr = @@ -123,79 +123,70 @@ static ssize_t cca_mkvps_show(struct device *dev, &ci, zq->online); if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3') - n += scnprintf(buf + n, PAGE_SIZE, - "AES NEW: %s 0x%016llx\n", - new_state[ci.new_aes_mk_state - '1'], - ci.new_aes_mkvp); + n += sysfs_emit_at(buf, n, "AES NEW: %s 0x%016llx\n", + new_state[ci.new_aes_mk_state - '1'], + ci.new_aes_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE, "AES NEW: - -\n"); + n += sysfs_emit_at(buf, n, "AES NEW: - -\n"); if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "AES CUR: %s 0x%016llx\n", - cao_state[ci.cur_aes_mk_state - '1'], - ci.cur_aes_mkvp); + n += sysfs_emit_at(buf, n, "AES CUR: %s 0x%016llx\n", + cao_state[ci.cur_aes_mk_state - '1'], + ci.cur_aes_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); + n += sysfs_emit_at(buf, n, "AES CUR: - -\n"); if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "AES OLD: %s 0x%016llx\n", - cao_state[ci.old_aes_mk_state - '1'], - ci.old_aes_mkvp); + n += sysfs_emit_at(buf, n, "AES OLD: %s 0x%016llx\n", + cao_state[ci.old_aes_mk_state - '1'], + ci.old_aes_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); + n += sysfs_emit_at(buf, n, "AES OLD: - -\n"); if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA NEW: %s 0x%016llx\n", - new_state[ci.new_apka_mk_state - '1'], - ci.new_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA NEW: %s 0x%016llx\n", + new_state[ci.new_apka_mk_state - '1'], + ci.new_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA NEW: - -\n"); + n += sysfs_emit_at(buf, n, "APKA NEW: - -\n"); if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA CUR: %s 0x%016llx\n", - cao_state[ci.cur_apka_mk_state - '1'], - ci.cur_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA CUR: %s 0x%016llx\n", + cao_state[ci.cur_apka_mk_state - '1'], + ci.cur_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA CUR: - -\n"); + n += sysfs_emit_at(buf, n, "APKA CUR: - -\n"); if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "APKA OLD: %s 0x%016llx\n", - cao_state[ci.old_apka_mk_state - '1'], - ci.old_apka_mkvp); + n += sysfs_emit_at(buf, n, "APKA OLD: %s 0x%016llx\n", + cao_state[ci.old_apka_mk_state - '1'], + ci.old_apka_mkvp); else - n += scnprintf(buf + n, PAGE_SIZE - n, "APKA OLD: - -\n"); + n += sysfs_emit_at(buf, n, "APKA OLD: - -\n"); if (ci.new_asym_mk_state >= '1' && ci.new_asym_mk_state <= '3') - n += scnprintf(buf + n, PAGE_SIZE, - "ASYM NEW: %s 0x%016llx%016llx\n", - new_state[ci.new_asym_mk_state - '1'], - *((u64 *)(ci.new_asym_mkvp)), - *((u64 *)(ci.new_asym_mkvp + sizeof(u64)))); + n += sysfs_emit_at(buf, n, "ASYM NEW: %s 0x%016llx%016llx\n", + new_state[ci.new_asym_mk_state - '1'], + *((u64 *)(ci.new_asym_mkvp)), + *((u64 *)(ci.new_asym_mkvp + sizeof(u64)))); else - n += scnprintf(buf + n, PAGE_SIZE, "ASYM NEW: - -\n"); + n += sysfs_emit_at(buf, n, "ASYM NEW: - -\n"); if (ci.cur_asym_mk_state >= '1' && ci.cur_asym_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "ASYM CUR: %s 0x%016llx%016llx\n", - cao_state[ci.cur_asym_mk_state - '1'], - *((u64 *)(ci.cur_asym_mkvp)), - *((u64 *)(ci.cur_asym_mkvp + sizeof(u64)))); + n += sysfs_emit_at(buf, n, "ASYM CUR: %s 0x%016llx%016llx\n", + cao_state[ci.cur_asym_mk_state - '1'], + *((u64 *)(ci.cur_asym_mkvp)), + *((u64 *)(ci.cur_asym_mkvp + sizeof(u64)))); else - n += scnprintf(buf + n, PAGE_SIZE - n, "ASYM CUR: - -\n"); + n += sysfs_emit_at(buf, n, "ASYM CUR: - -\n"); if (ci.old_asym_mk_state >= '1' && ci.old_asym_mk_state <= '2') - n += scnprintf(buf + n, PAGE_SIZE - n, - "ASYM OLD: %s 0x%016llx%016llx\n", - cao_state[ci.old_asym_mk_state - '1'], - *((u64 *)(ci.old_asym_mkvp)), - *((u64 *)(ci.old_asym_mkvp + sizeof(u64)))); + n += sysfs_emit_at(buf, n, "ASYM OLD: %s 0x%016llx%016llx\n", + cao_state[ci.old_asym_mk_state - '1'], + *((u64 *)(ci.old_asym_mkvp)), + *((u64 *)(ci.old_asym_mkvp + sizeof(u64)))); else - n += scnprintf(buf + n, PAGE_SIZE - n, "ASYM OLD: - -\n"); + n += sysfs_emit_at(buf, n, "ASYM OLD: - -\n"); return n; } @@ -228,9 +219,9 @@ static ssize_t ep11_api_ordinalnr_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.API_ord_nr > 0) - return scnprintf(buf, PAGE_SIZE, "%u\n", ci.API_ord_nr); + return sysfs_emit(buf, "%u\n", ci.API_ord_nr); else - return scnprintf(buf, PAGE_SIZE, "\n"); + return sysfs_emit(buf, "\n"); } static struct device_attribute dev_attr_ep11_api_ordinalnr = @@ -249,11 +240,11 @@ static ssize_t ep11_fw_version_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.FW_version > 0) - return scnprintf(buf, PAGE_SIZE, "%d.%d\n", - (int)(ci.FW_version >> 8), - (int)(ci.FW_version & 0xFF)); + return sysfs_emit(buf, "%d.%d\n", + (int)(ci.FW_version >> 8), + (int)(ci.FW_version & 0xFF)); else - return scnprintf(buf, PAGE_SIZE, "\n"); + return sysfs_emit(buf, "\n"); } static struct device_attribute dev_attr_ep11_fw_version = @@ -272,9 +263,9 @@ static ssize_t ep11_serialnr_show(struct device *dev, ep11_get_card_info(ac->id, &ci, zc->online); if (ci.serial[0]) - return scnprintf(buf, PAGE_SIZE, "%16.16s\n", ci.serial); + return sysfs_emit(buf, "%16.16s\n", ci.serial); else - return scnprintf(buf, PAGE_SIZE, "\n"); + return sysfs_emit(buf, "\n"); } static struct device_attribute dev_attr_ep11_serialnr = @@ -309,11 +300,11 @@ static ssize_t ep11_card_op_modes_show(struct device *dev, if (ci.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { if (n > 0) buf[n++] = ' '; - n += scnprintf(buf + n, PAGE_SIZE - n, - "%s", ep11_op_modes[i].mode_txt); + n += sysfs_emit_at(buf, n, "%s", + ep11_op_modes[i].mode_txt); } } - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + n += sysfs_emit_at(buf, n, "\n"); return n; } @@ -356,29 +347,29 @@ static ssize_t ep11_mkvps_show(struct device *dev, &di); if (di.cur_wk_state == '0') { - n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s -\n", - cwk_state[di.cur_wk_state - '0']); + n = sysfs_emit(buf, "WK CUR: %s -\n", + cwk_state[di.cur_wk_state - '0']); } else if (di.cur_wk_state == '1') { - n = scnprintf(buf, PAGE_SIZE, "WK CUR: %s 0x", - cwk_state[di.cur_wk_state - '0']); + n = sysfs_emit(buf, "WK CUR: %s 0x", + cwk_state[di.cur_wk_state - '0']); bin2hex(buf + n, di.cur_wkvp, sizeof(di.cur_wkvp)); n += 2 * sizeof(di.cur_wkvp); - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + n += sysfs_emit_at(buf, n, "\n"); } else { - n = scnprintf(buf, PAGE_SIZE, "WK CUR: - -\n"); + n = sysfs_emit(buf, "WK CUR: - -\n"); } if (di.new_wk_state == '0') { - n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s -\n", - nwk_state[di.new_wk_state - '0']); + n += sysfs_emit_at(buf, n, "WK NEW: %s -\n", + nwk_state[di.new_wk_state - '0']); } else if (di.new_wk_state >= '1' && di.new_wk_state <= '2') { - n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: %s 0x", - nwk_state[di.new_wk_state - '0']); + n += sysfs_emit_at(buf, n, "WK NEW: %s 0x", + nwk_state[di.new_wk_state - '0']); bin2hex(buf + n, di.new_wkvp, sizeof(di.new_wkvp)); n += 2 * sizeof(di.new_wkvp); - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + n += sysfs_emit_at(buf, n, "\n"); } else { - n += scnprintf(buf + n, PAGE_SIZE - n, "WK NEW: - -\n"); + n += sysfs_emit_at(buf, n, "WK NEW: - -\n"); } return n; @@ -406,11 +397,11 @@ static ssize_t ep11_queue_op_modes_show(struct device *dev, if (di.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) { if (n > 0) buf[n++] = ' '; - n += scnprintf(buf + n, PAGE_SIZE - n, - "%s", ep11_op_modes[i].mode_txt); + n += sysfs_emit_at(buf, n, "%s", + ep11_op_modes[i].mode_txt); } } - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + n += sysfs_emit_at(buf, n, "\n"); return n; } diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c index b1c29017be5b..f67d19d08571 100644 --- a/drivers/s390/crypto/zcrypt_ep11misc.c +++ b/drivers/s390/crypto/zcrypt_ep11misc.c @@ -1275,7 +1275,7 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen, u32 pkeybitsize; u64 pkeysize; u8 res2[8]; - u8 pkey[0]; + u8 pkey[]; } __packed * wki; const u8 *key; struct ep11kblob_header *hdr; diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 7d245645fdd5..05ace18c12b0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -441,14 +441,17 @@ static void zcrypt_cex2a_receive(struct ap_queue *aq, t80h = reply->msg; if (t80h->type == TYPE80_RSP_CODE) { len = t80h->len; - if (len > reply->bufsize || len > msg->bufsize) { + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete((struct completion *)msg->private); @@ -476,7 +479,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_cex2a_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = &work; rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex); @@ -527,7 +530,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_cex2a_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = &work; rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 5ad251477593..2f9bf23fbb44 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -208,7 +208,7 @@ static int icamex_msg_to_type6mex_msgx(struct zcrypt_queue *zq, struct CPRBX cprbx; struct function_and_rules_block fr; unsigned short length; - char text[0]; + char text[]; } __packed * msg = ap_msg->msg; int size; @@ -278,7 +278,7 @@ static int icacrt_msg_to_type6crt_msgx(struct zcrypt_queue *zq, struct CPRBX cprbx; struct function_and_rules_block fr; unsigned short length; - char text[0]; + char text[]; } __packed * msg = ap_msg->msg; int size; @@ -566,8 +566,8 @@ struct type86x_reply { struct type86_fmt2_ext fmt2; struct CPRBX cprbx; unsigned char pad[4]; /* 4 byte function code/rules block ? */ - unsigned short length; - char text[]; + unsigned short length; /* length of data including length field size */ + char data[]; } __packed; struct type86_ep11_reply { @@ -581,45 +581,9 @@ static int convert_type86_ica(struct zcrypt_queue *zq, char __user *outputdata, unsigned int outputdatalength) { - static unsigned char static_pad[] = { - 0x00, 0x02, - 0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD, - 0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57, - 0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B, - 0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39, - 0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5, - 0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D, - 0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB, - 0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F, - 0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9, - 0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45, - 0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9, - 0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F, - 0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD, - 0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D, - 0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD, - 0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9, - 0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B, - 0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B, - 0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B, - 0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD, - 0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7, - 0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1, - 0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3, - 0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23, - 0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55, - 0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43, - 0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F, - 0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F, - 0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5, - 0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD, - 0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41, - 0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09 - }; struct type86x_reply *msg = reply->msg; unsigned short service_rc, service_rs; - unsigned int reply_len, pad_len; - char *data; + unsigned int data_len; service_rc = msg->cprbx.ccp_rtcode; if (unlikely(service_rc != 0)) { @@ -647,32 +611,12 @@ static int convert_type86_ica(struct zcrypt_queue *zq, ap_send_online_uevent(&zq->queue->ap_dev, zq->online); return -EAGAIN; } - data = msg->text; - reply_len = msg->length - 2; - if (reply_len > outputdatalength) - return -EINVAL; - /* - * For all encipher requests, the length of the ciphertext (reply_len) - * will always equal the modulus length. For MEX decipher requests - * the output needs to get padded. Minimum pad size is 10. - * - * Currently, the cases where padding will be added is for: - * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support - * ZERO-PAD and CRT is only supported for PKD requests) - * - PCICC, always - */ - pad_len = outputdatalength - reply_len; - if (pad_len > 0) { - if (pad_len < 10) - return -EINVAL; - /* 'restore' padding left in the CEXXC card. */ - if (copy_to_user(outputdata, static_pad, pad_len - 1)) - return -EFAULT; - if (put_user(0, outputdata + pad_len - 1)) - return -EFAULT; - } + data_len = msg->length - sizeof(msg->length); + if (data_len > outputdatalength) + return -EMSGSIZE; + /* Copy the crypto response to user space. */ - if (copy_to_user(outputdata + pad_len, data, reply_len)) + if (copy_to_user(outputdata, msg->data, data_len)) return -EFAULT; return 0; } @@ -926,8 +870,7 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct response_type *resp_type = - (struct response_type *)msg->private; + struct response_type *resp_type = msg->private; struct type86x_reply *t86r; int len; @@ -939,28 +882,37 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, t86r->cprbx.cprb_ver_id == 0x02) { switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_ICA: - len = sizeof(struct type86x_reply) + t86r->length - 2; - if (len > reply->bufsize || len > msg->bufsize) { + len = sizeof(struct type86x_reply) + t86r->length; + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; case CEXXC_RESPONSE_TYPE_XCRB: - len = t86r->fmt2.offset2 + t86r->fmt2.count2; - if (len > reply->bufsize || len > msg->bufsize) { + if (t86r->fmt2.count2) + len = t86r->fmt2.offset2 + t86r->fmt2.count2; + else + len = t86r->fmt2.offset1 + t86r->fmt2.count1; + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); + msg->len = sizeof(error_reply); } } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete(&resp_type->work); @@ -982,8 +934,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct response_type *resp_type = - (struct response_type *)msg->private; + struct response_type *resp_type = msg->private; struct type86_ep11_reply *t86r; int len; @@ -996,18 +947,22 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_EP11: len = t86r->fmt2.offset1 + t86r->fmt2.count1; - if (len > reply->bufsize || len > msg->bufsize) { + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); + msg->len = sizeof(error_reply); } } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete(&resp_type->work); @@ -1036,7 +991,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, return -ENOMEM; ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = &resp_type; rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex); @@ -1086,7 +1041,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, return -ENOMEM; ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = &resp_type; rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt); @@ -1137,7 +1092,7 @@ int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb, if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) @@ -1157,7 +1112,7 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq, struct ap_message *ap_msg) { int rc; - struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct response_type *rtype = ap_msg->private; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -1218,7 +1173,7 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb, if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive_ep11; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) @@ -1240,7 +1195,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue * { int rc; unsigned int lfmt; - struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct response_type *rtype = ap_msg->private; struct { struct type6_hdr hdr; struct ep11_cprb cprbx; @@ -1328,7 +1283,7 @@ int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code, if (!ap_msg->msg) return -ENOMEM; ap_msg->receive = zcrypt_msgtype6_receive; - ap_msg->psmid = (((unsigned long long)current->pid) << 32) + + ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL); if (!ap_msg->private) @@ -1359,7 +1314,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, short int verb_length; short int key_length; } __packed * msg = ap_msg->msg; - struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct response_type *rtype = ap_msg->private; int rc; msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index cdc5a4b2c019..112a80e8e6c2 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -44,7 +44,7 @@ static ssize_t online_show(struct device *dev, struct ap_queue *aq = to_ap_queue(dev); int online = aq->config && zq->online ? 1 : 0; - return scnprintf(buf, PAGE_SIZE, "%d\n", online); + return sysfs_emit(buf, "%d\n", online); } static ssize_t online_store(struct device *dev, @@ -84,7 +84,7 @@ static ssize_t load_show(struct device *dev, { struct zcrypt_queue *zq = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); + return sysfs_emit(buf, "%d\n", atomic_read(&zq->load)); } static DEVICE_ATTR_RO(load); diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 954fc31b4bc7..02922768b129 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -391,7 +391,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area)); } -static bool virtio_ccw_kvm_notify(struct virtqueue *vq) +static inline bool virtio_ccw_do_kvm_notify(struct virtqueue *vq, u32 data) { struct virtio_ccw_vq_info *info = vq->priv; struct virtio_ccw_device *vcdev; @@ -402,12 +402,22 @@ static bool virtio_ccw_kvm_notify(struct virtqueue *vq) BUILD_BUG_ON(sizeof(struct subchannel_id) != sizeof(unsigned int)); info->cookie = kvm_hypercall3(KVM_S390_VIRTIO_CCW_NOTIFY, *((unsigned int *)&schid), - vq->index, info->cookie); + data, info->cookie); if (info->cookie < 0) return false; return true; } +static bool virtio_ccw_kvm_notify(struct virtqueue *vq) +{ + return virtio_ccw_do_kvm_notify(vq, vq->index); +} + +static bool virtio_ccw_kvm_notify_with_data(struct virtqueue *vq) +{ + return virtio_ccw_do_kvm_notify(vq, vring_notification_data(vq)); +} + static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, struct ccw1 *ccw, int index) { @@ -495,6 +505,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, struct ccw1 *ccw) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); + bool (*notify)(struct virtqueue *vq); int err; struct virtqueue *vq = NULL; struct virtio_ccw_vq_info *info; @@ -502,6 +513,11 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, unsigned long flags; bool may_reduce; + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) + notify = virtio_ccw_kvm_notify_with_data; + else + notify = virtio_ccw_kvm_notify; + /* Allocate queue. */ info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL); if (!info) { @@ -524,7 +540,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev, may_reduce = vcdev->revision > 0; vq = vring_create_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev, true, may_reduce, ctx, - virtio_ccw_kvm_notify, callback, name); + notify, callback, name); if (!vq) { /* For now, we fail if we can't get the requested size. */ diff --git a/drivers/sbus/char/oradax.c b/drivers/sbus/char/oradax.c index d698ca506cca..aafce8d00000 100644 --- a/drivers/sbus/char/oradax.c +++ b/drivers/sbus/char/oradax.c @@ -323,7 +323,7 @@ static int __init dax_attach(void) goto done; } - cl = class_create(THIS_MODULE, DAX_NAME); + cl = class_create(DAX_NAME); if (IS_ERR(cl)) { dax_err("class_create failed"); ret = PTR_ERR(cl); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 03e71e3d5e5b..0704809d9d99 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -971,8 +971,7 @@ config SCSI_SYM53C8XX_MMIO config SCSI_IPR tristate "IBM Power Linux RAID adapter support" - depends on PCI && SCSI && ATA - select SATA_HOST + depends on PCI && SCSI select FW_LOADER select IRQ_POLL select SGL_ALLOC diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 72fe6df78bc5..ac648bb8f7e7 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -995,7 +995,7 @@ static int __init init_ch_module(void) int rc; printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); - ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); + ch_sysfs_class = class_create("scsi_changer"); if (IS_ERR(ch_sysfs_class)) { rc = PTR_ERR(ch_sysfs_class); return rc; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 395b00b942f7..debd36974119 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -3880,7 +3880,7 @@ static int cxlflash_class_init(void) cxlflash_major = MAJOR(devno); - cxlflash_class = class_create(THIS_MODULE, "cxlflash"); + cxlflash_class = class_create("cxlflash"); if (IS_ERR(cxlflash_class)) { rc = PTR_ERR(cxlflash_class); pr_err("%s: class_create failed rc=%d\n", __func__, rc); diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c index e003d923acbf..055d2e87a2c8 100644 --- a/drivers/scsi/esas2r/esas2r_ioctl.c +++ b/drivers/scsi/esas2r/esas2r_ioctl.c @@ -56,7 +56,7 @@ dma_addr_t esas2r_buffered_ioctl_addr; u32 esas2r_buffered_ioctl_size; struct pci_dev *esas2r_buffered_ioctl_pcid; -static DEFINE_SEMAPHORE(buffered_ioctl_semaphore); +static DEFINE_SEMAPHORE(buffered_ioctl_semaphore, 1); typedef int (*BUFFERED_IOCTL_CALLBACK)(struct esas2r_adapter *, struct esas2r_request *, struct esas2r_sg_context *, diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 6260aa5ea6af..e17957f8085c 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -659,17 +659,17 @@ static const struct device_type fcoe_fcf_device_type = { .release = fcoe_fcf_device_release, }; -static ssize_t ctlr_create_store(struct bus_type *bus, const char *buf, +static ssize_t ctlr_create_store(const struct bus_type *bus, const char *buf, size_t count) { - return fcoe_ctlr_create_store(bus, buf, count); + return fcoe_ctlr_create_store(buf, count); } static BUS_ATTR_WO(ctlr_create); -static ssize_t ctlr_destroy_store(struct bus_type *bus, const char *buf, +static ssize_t ctlr_destroy_store(const struct bus_type *bus, const char *buf, size_t count) { - return fcoe_ctlr_destroy_store(bus, buf, count); + return fcoe_ctlr_destroy_store(buf, count); } static BUS_ATTR_WO(ctlr_destroy); diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 62341c6353a7..46b0bf237be1 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -745,8 +745,7 @@ static int libfcoe_device_notification(struct notifier_block *notifier, return NOTIFY_OK; } -ssize_t fcoe_ctlr_create_store(struct bus_type *bus, - const char *buf, size_t count) +ssize_t fcoe_ctlr_create_store(const char *buf, size_t count) { struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; @@ -808,8 +807,7 @@ out_nodev: return count; } -ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus, - const char *buf, size_t count) +ssize_t fcoe_ctlr_destroy_store(const char *buf, size_t count) { int rc = -ENODEV; struct net_device *netdev = NULL; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 4d3c280a7360..4e13797b2a4a 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -595,10 +594,6 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, trace_entry->time = jiffies; trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; trace_entry->type = type; - if (ipr_cmd->ioa_cfg->sis64) - trace_entry->ata_op_code = ipr_cmd->i.ata_ioadl.regs.command; - else - trace_entry->ata_op_code = ipr_cmd->ioarcb.u.add_data.u.regs.command; trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; trace_entry->u.add_data = add_data; @@ -636,7 +631,6 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) { struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64; dma_addr_t dma_addr = ipr_cmd->dma_addr; int hrrq_id; @@ -651,18 +645,15 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) if (ipr_cmd->ioa_cfg->sis64) { ioarcb->u.sis64_addr_data.data_ioadl_addr = cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64)); - ioasa64->u.gata.status = 0; } else { ioarcb->write_ioadl_addr = cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl)); ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - ioasa->u.gata.status = 0; } ioasa->hdr.ioasc = 0; ioasa->hdr.residual_data_len = 0; ipr_cmd->scsi_cmd = NULL; - ipr_cmd->qc = NULL; ipr_cmd->sense_buffer[0] = 0; ipr_cmd->dma_use_sg = 0; } @@ -806,48 +797,6 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) return 0; } -/** - * __ipr_sata_eh_done - done function for aborted SATA commands - * @ipr_cmd: ipr command struct - * - * This function is invoked for ops generated to SATA - * devices which are being aborted. - * - * Return value: - * none - **/ -static void __ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) -{ - struct ata_queued_cmd *qc = ipr_cmd->qc; - struct ipr_sata_port *sata_port = qc->ap->private_data; - - qc->err_mask |= AC_ERR_OTHER; - sata_port->ioasa.status |= ATA_BUSY; - ata_qc_complete(qc); - if (ipr_cmd->eh_comp) - complete(ipr_cmd->eh_comp); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); -} - -/** - * ipr_sata_eh_done - done function for aborted SATA commands - * @ipr_cmd: ipr command struct - * - * This function is invoked for ops generated to SATA - * devices which are being aborted. - * - * Return value: - * none - **/ -static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq; - unsigned long hrrq_flags; - - spin_lock_irqsave(&hrrq->_lock, hrrq_flags); - __ipr_sata_eh_done(ipr_cmd); - spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags); -} /** * __ipr_scsi_eh_done - mid-layer done function for aborted ops @@ -920,8 +869,6 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) if (ipr_cmd->scsi_cmd) ipr_cmd->done = __ipr_scsi_eh_done; - else if (ipr_cmd->qc) - ipr_cmd->done = __ipr_sata_eh_done; ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); @@ -1142,31 +1089,6 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, } } -/** - * ipr_update_ata_class - Update the ata class in the resource entry - * @res: resource entry struct - * @proto: cfgte device bus protocol value - * - * Return value: - * none - **/ -static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto) -{ - switch (proto) { - case IPR_PROTO_SATA: - case IPR_PROTO_SAS_STP: - res->ata_class = ATA_DEV_ATA; - break; - case IPR_PROTO_SATA_ATAPI: - case IPR_PROTO_SAS_STP_ATAPI: - res->ata_class = ATA_DEV_ATAPI; - break; - default: - res->ata_class = ATA_DEV_UNKNOWN; - break; - } -} - /** * ipr_init_res_entry - Initialize a resource entry struct. * @res: resource entry struct @@ -1179,7 +1101,6 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, struct ipr_config_table_entry_wrapper *cfgtew) { int found = 0; - unsigned int proto; struct ipr_ioa_cfg *ioa_cfg = res->ioa_cfg; struct ipr_resource_entry *gscsi_res = NULL; @@ -1190,10 +1111,8 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, res->resetting_device = 0; res->reset_occurred = 0; res->sdev = NULL; - res->sata_port = NULL; if (ioa_cfg->sis64) { - proto = cfgtew->u.cfgte64->proto; res->flags = be16_to_cpu(cfgtew->u.cfgte64->flags); res->res_flags = be16_to_cpu(cfgtew->u.cfgte64->res_flags); res->qmodel = IPR_QUEUEING_MODEL64(res); @@ -1239,7 +1158,6 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, set_bit(res->target, ioa_cfg->target_ids); } } else { - proto = cfgtew->u.cfgte->proto; res->qmodel = IPR_QUEUEING_MODEL(res); res->flags = cfgtew->u.cfgte->flags; if (res->flags & IPR_IS_IOA_RESOURCE) @@ -1252,8 +1170,6 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, res->lun = cfgtew->u.cfgte->res_addr.lun; res->lun_wwn = get_unaligned_be64(cfgtew->u.cfgte->lun_wwn); } - - ipr_update_ata_class(res, proto); } /** @@ -1339,7 +1255,6 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, struct ipr_config_table_entry_wrapper *cfgtew) { char buffer[IPR_MAX_RES_PATH_LENGTH]; - unsigned int proto; int new_path = 0; if (res->ioa_cfg->sis64) { @@ -1351,7 +1266,6 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, sizeof(struct ipr_std_inq_data)); res->qmodel = IPR_QUEUEING_MODEL64(res); - proto = cfgtew->u.cfgte64->proto; res->res_handle = cfgtew->u.cfgte64->res_handle; res->dev_id = cfgtew->u.cfgte64->dev_id; @@ -1380,11 +1294,8 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, sizeof(struct ipr_std_inq_data)); res->qmodel = IPR_QUEUEING_MODEL(res); - proto = cfgtew->u.cfgte->proto; res->res_handle = cfgtew->u.cfgte->res_handle; } - - ipr_update_ata_class(res, proto); } /** @@ -4496,17 +4407,6 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; **/ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth) { - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - - if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN) - qdepth = IPR_MAX_CMD_PER_ATA_LUN; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_change_queue_depth(sdev, qdepth); return sdev->queue_depth; } @@ -4799,68 +4699,13 @@ static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget) return NULL; } -static struct ata_port_info sata_port_info; - -/** - * ipr_target_alloc - Prepare for commands to a SCSI target - * @starget: scsi target struct - * - * If the device is a SATA device, this function allocates an - * ATA port with libata, else it does nothing. - * - * Return value: - * 0 on success / non-0 on failure - **/ -static int ipr_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; - struct ipr_sata_port *sata_port; - struct ata_port *ap; - struct ipr_resource_entry *res; - unsigned long lock_flags; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = ipr_find_starget(starget); - starget->hostdata = NULL; - - if (res && ipr_is_gata(res)) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); - if (!sata_port) - return -ENOMEM; - - ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost); - if (ap) { - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - sata_port->ioa_cfg = ioa_cfg; - sata_port->ap = ap; - sata_port->res = res; - - res->sata_port = sata_port; - ap->private_data = sata_port; - starget->hostdata = sata_port; - } else { - kfree(sata_port); - return -ENOMEM; - } - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return 0; -} - /** * ipr_target_destroy - Destroy a SCSI target * @starget: scsi target struct * - * If the device was a SATA device, this function frees the libata - * ATA port, else it does nothing. - * **/ static void ipr_target_destroy(struct scsi_target *starget) { - struct ipr_sata_port *sata_port = starget->hostdata; struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; @@ -4874,12 +4719,6 @@ static void ipr_target_destroy(struct scsi_target *starget) clear_bit(starget->id, ioa_cfg->target_ids); } } - - if (sata_port) { - starget->hostdata = NULL; - ata_sas_port_destroy(sata_port->ap); - kfree(sata_port); - } } /** @@ -4922,11 +4761,8 @@ static void ipr_slave_destroy(struct scsi_device *sdev) spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *) sdev->hostdata; if (res) { - if (res->sata_port) - res->sata_port->ap->link.device[0].class = ATA_DEV_NONE; sdev->hostdata = NULL; res->sdev = NULL; - res->sata_port = NULL; } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); } @@ -4944,7 +4780,6 @@ static int ipr_slave_configure(struct scsi_device *sdev) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; struct ipr_resource_entry *res; - struct ata_port *ap = NULL; unsigned long lock_flags = 0; char buffer[IPR_MAX_RES_PATH_LENGTH]; @@ -4964,15 +4799,8 @@ static int ipr_slave_configure(struct scsi_device *sdev) IPR_VSET_RW_TIMEOUT); blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); } - if (ipr_is_gata(res) && res->sata_port) - ap = res->sata_port->ap; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - if (ap) { - scsi_change_queue_depth(sdev, IPR_MAX_CMD_PER_ATA_LUN); - ata_sas_slave_configure(sdev, ap); - } - if (ioa_cfg->sis64) sdev_printk(KERN_INFO, sdev, "Resource path: %s\n", ipr_format_res_path(ioa_cfg, @@ -4983,37 +4811,6 @@ static int ipr_slave_configure(struct scsi_device *sdev) return 0; } -/** - * ipr_ata_slave_alloc - Prepare for commands to a SATA device - * @sdev: scsi device struct - * - * This function initializes an ATA port so that future commands - * sent through queuecommand will work. - * - * Return value: - * 0 on success - **/ -static int ipr_ata_slave_alloc(struct scsi_device *sdev) -{ - struct ipr_sata_port *sata_port = NULL; - int rc = -ENXIO; - - ENTER; - if (sdev->sdev_target) - sata_port = sdev->sdev_target->hostdata; - if (sata_port) { - rc = ata_sas_port_init(sata_port->ap); - if (rc == 0) - rc = ata_sas_sync_probe(sata_port->ap); - } - - if (rc) - ipr_slave_destroy(sdev); - - LEAVE; - return rc; -} - /** * ipr_slave_alloc - Prepare for commands to a device. * @sdev: scsi device struct @@ -5047,8 +4844,10 @@ static int ipr_slave_alloc(struct scsi_device *sdev) res->needs_sync_complete = 1; rc = 0; if (ipr_is_gata(res)) { + sdev_printk(KERN_ERR, sdev, "SATA devices are no longer " + "supported by this driver. Skipping device.\n"); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return ipr_ata_slave_alloc(sdev); + return -ENXIO; } } @@ -5091,23 +4890,6 @@ static bool ipr_cmnd_is_free(struct ipr_cmnd *ipr_cmd) return false; } -/** - * ipr_match_res - Match function for specified resource entry - * @ipr_cmd: ipr command struct - * @resource: resource entry to match - * - * Returns: - * 1 if command matches sdev / 0 if command does not match sdev - **/ -static int ipr_match_res(struct ipr_cmnd *ipr_cmd, void *resource) -{ - struct ipr_resource_entry *res = resource; - - if (res && ipr_cmd->ioarcb.res_handle == res->res_handle) - return 1; - return 0; -} - /** * ipr_wait_for_ops - Wait for matching commands to complete * @ioa_cfg: ioa config struct @@ -5220,8 +5002,7 @@ static int ipr_eh_host_reset(struct scsi_cmnd *cmd) * This function issues a device reset to the affected device. * If the device is a SCSI device, a LUN reset will be sent * to the device first. If that does not work, a target reset - * will be sent. If the device is a SATA device, a PHY reset will - * be sent. + * will be sent. * * Return value: * 0 on success / non-zero on failure @@ -5232,7 +5013,6 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, struct ipr_cmnd *ipr_cmd; struct ipr_ioarcb *ioarcb; struct ipr_cmd_pkt *cmd_pkt; - struct ipr_ioarcb_ata_regs *regs; u32 ioasc; ENTER; @@ -5240,86 +5020,21 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, ioarcb = &ipr_cmd->ioarcb; cmd_pkt = &ioarcb->cmd_pkt; - if (ipr_cmd->ioa_cfg->sis64) { - regs = &ipr_cmd->i.ata_ioadl.regs; + if (ipr_cmd->ioa_cfg->sis64) ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb)); - } else - regs = &ioarcb->u.add_data.u.regs; ioarcb->res_handle = res->res_handle; cmd_pkt->request_type = IPR_RQTYPE_IOACMD; cmd_pkt->cdb[0] = IPR_RESET_DEVICE; - if (ipr_is_gata(res)) { - cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET; - ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(regs->flags)); - regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; - } ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); - if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) { - if (ipr_cmd->ioa_cfg->sis64) - memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata, - sizeof(struct ipr_ioasa_gata)); - else - memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata, - sizeof(struct ipr_ioasa_gata)); - } LEAVE; return IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0; } -/** - * ipr_sata_reset - Reset the SATA port - * @link: SATA link to reset - * @classes: class of the attached device - * @deadline: unused - * - * This function issues a SATA phy reset to the affected ATA link. - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) -{ - struct ipr_sata_port *sata_port = link->ap->private_data; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - int rc = -ENXIO, ret; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - while (ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - res = sata_port->res; - if (res) { - rc = ipr_device_reset(ioa_cfg, res); - *classes = res->ata_class; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - ret = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res); - if (ret != SUCCESS) { - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - } - } else - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - LEAVE; - return rc; -} - /** * __ipr_eh_dev_reset - Reset the device * @scsi_cmd: scsi command struct @@ -5333,12 +5048,9 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, **/ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) { - struct ipr_cmnd *ipr_cmd; struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; - struct ata_port *ap; - int rc = 0, i; - struct ipr_hrr_queue *hrrq; + int rc = 0; ENTER; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; @@ -5354,36 +5066,10 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) if (ioa_cfg->hrrq[IPR_INIT_HRRQ].ioa_is_dead) return FAILED; - for_each_hrrq(hrrq, ioa_cfg) { - spin_lock(&hrrq->_lock); - for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) { - ipr_cmd = ioa_cfg->ipr_cmnd_list[i]; - - if (ipr_cmd->ioarcb.res_handle == res->res_handle) { - if (!ipr_cmd->qc) - continue; - if (ipr_cmnd_is_free(ipr_cmd)) - continue; - - ipr_cmd->done = ipr_sata_eh_done; - if (!(ipr_cmd->qc->flags & ATA_QCFLAG_EH)) { - ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; - ipr_cmd->qc->flags |= ATA_QCFLAG_EH; - } - } - } - spin_unlock(&hrrq->_lock); - } res->resetting_device = 1; scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); - if (ipr_is_gata(res) && res->sata_port) { - ap = res->sata_port->ap; - spin_unlock_irq(scsi_cmd->device->host->host_lock); - ata_std_error_handler(ap); - spin_lock_irq(scsi_cmd->device->host->host_lock); - } else - rc = ipr_device_reset(ioa_cfg, res); + rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; res->reset_occurred = 1; @@ -5407,12 +5093,8 @@ static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) rc = __ipr_eh_dev_reset(cmd); spin_unlock_irq(cmd->device->host->host_lock); - if (rc == SUCCESS) { - if (ipr_is_gata(res) && res->sata_port) - rc = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res); - else - rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); - } + if (rc == SUCCESS) + rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); return rc; } @@ -6564,7 +6246,7 @@ static int ipr_queuecommand(struct Scsi_Host *shost, struct ipr_resource_entry *res; struct ipr_ioarcb *ioarcb; struct ipr_cmnd *ipr_cmd; - unsigned long hrrq_flags, lock_flags; + unsigned long hrrq_flags; int rc; struct ipr_hrr_queue *hrrq; int hrrq_id; @@ -6574,13 +6256,6 @@ static int ipr_queuecommand(struct Scsi_Host *shost, scsi_cmd->result = (DID_OK << 16); res = scsi_cmd->device->hostdata; - if (ipr_is_gata(res) && res->sata_port) { - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - rc = ata_sas_queuecmd(scsi_cmd, res->sata_port->ap); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return rc; - } - hrrq_id = ipr_get_hrrq_index(ioa_cfg); hrrq = &ioa_cfg->hrrq[hrrq_id]; @@ -6690,30 +6365,6 @@ err_nodev: return 0; } -/** - * ipr_ioctl - IOCTL handler - * @sdev: scsi device struct - * @cmd: IOCTL cmd - * @arg: IOCTL arg - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_ioctl(struct scsi_device *sdev, unsigned int cmd, - void __user *arg) -{ - struct ipr_resource_entry *res; - - res = (struct ipr_resource_entry *)sdev->hostdata; - if (res && ipr_is_gata(res)) { - if (cmd == HDIO_GET_IDENTITY) - return -ENOTTY; - return ata_sas_scsi_ioctl(res->sata_port->ap, sdev, cmd, arg); - } - - return -EINVAL; -} - /** * ipr_ioa_info - Get information about the card/driver * @host: scsi host struct @@ -6740,12 +6391,7 @@ static const struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "IPR", .info = ipr_ioa_info, - .ioctl = ipr_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ipr_ioctl, -#endif .queuecommand = ipr_queuecommand, - .dma_need_drain = ata_scsi_dma_need_drain, .eh_abort_handler = ipr_eh_abort, .eh_device_reset_handler = ipr_eh_dev_reset, .eh_host_reset_handler = ipr_eh_host_reset, @@ -6753,7 +6399,6 @@ static const struct scsi_host_template driver_template = { .slave_configure = ipr_slave_configure, .slave_destroy = ipr_slave_destroy, .scan_finished = ipr_scan_finished, - .target_alloc = ipr_target_alloc, .target_destroy = ipr_target_destroy, .change_queue_depth = ipr_change_queue_depth, .bios_param = ipr_biosparam, @@ -6767,418 +6412,6 @@ static const struct scsi_host_template driver_template = { .proc_name = IPR_NAME, }; -/** - * ipr_ata_phy_reset - libata phy_reset handler - * @ap: ata port to reset - * - **/ -static void ipr_ata_phy_reset(struct ata_port *ap) -{ - unsigned long flags; - struct ipr_sata_port *sata_port = ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - int rc; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - while (ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - } - - if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) - goto out_unlock; - - rc = ipr_device_reset(ioa_cfg, res); - - if (rc) { - ap->link.device[0].class = ATA_DEV_NONE; - goto out_unlock; - } - - ap->link.device[0].class = res->ata_class; - if (ap->link.device[0].class == ATA_DEV_UNKNOWN) - ap->link.device[0].class = ATA_DEV_NONE; - -out_unlock: - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - LEAVE; -} - -/** - * ipr_ata_post_internal - Cleanup after an internal command - * @qc: ATA queued command - * - * Return value: - * none - **/ -static void ipr_ata_post_internal(struct ata_queued_cmd *qc) -{ - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_cmnd *ipr_cmd; - struct ipr_hrr_queue *hrrq; - unsigned long flags; - - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - while (ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - } - - for_each_hrrq(hrrq, ioa_cfg) { - spin_lock(&hrrq->_lock); - list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { - if (ipr_cmd->qc == qc) { - ipr_device_reset(ioa_cfg, sata_port->res); - break; - } - } - spin_unlock(&hrrq->_lock); - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); -} - -/** - * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure - * @regs: destination - * @tf: source ATA taskfile - * - * Return value: - * none - **/ -static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs, - struct ata_taskfile *tf) -{ - regs->feature = tf->feature; - regs->nsect = tf->nsect; - regs->lbal = tf->lbal; - regs->lbam = tf->lbam; - regs->lbah = tf->lbah; - regs->device = tf->device; - regs->command = tf->command; - regs->hob_feature = tf->hob_feature; - regs->hob_nsect = tf->hob_nsect; - regs->hob_lbal = tf->hob_lbal; - regs->hob_lbam = tf->hob_lbam; - regs->hob_lbah = tf->hob_lbah; - regs->ctl = tf->ctl; -} - -/** - * ipr_sata_done - done function for SATA commands - * @ipr_cmd: ipr command struct - * - * This function is invoked by the interrupt handler for - * ops generated by the SCSI mid-layer to SATA devices - * - * Return value: - * none - **/ -static void ipr_sata_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ata_queued_cmd *qc = ipr_cmd->qc; - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - spin_lock(&ipr_cmd->hrrq->_lock); - if (ipr_cmd->ioa_cfg->sis64) - memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata, - sizeof(struct ipr_ioasa_gata)); - else - memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata, - sizeof(struct ipr_ioasa_gata)); - ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); - - if (be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET) - scsi_report_device_reset(ioa_cfg->host, res->bus, res->target); - - if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) - qc->err_mask |= __ac_err_mask(sata_port->ioasa.status); - else - qc->err_mask |= ac_err_mask(sata_port->ioasa.status); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); - spin_unlock(&ipr_cmd->hrrq->_lock); - ata_qc_complete(qc); -} - -/** - * ipr_build_ata_ioadl64 - Build an ATA scatter/gather list - * @ipr_cmd: ipr command struct - * @qc: ATA queued command - * - **/ -static void ipr_build_ata_ioadl64(struct ipr_cmnd *ipr_cmd, - struct ata_queued_cmd *qc) -{ - u32 ioadl_flags = 0; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ata_ioadl.ioadl64; - struct ipr_ioadl64_desc *last_ioadl64 = NULL; - int len = qc->nbytes; - struct scatterlist *sg; - unsigned int si; - dma_addr_t dma_addr = ipr_cmd->dma_addr; - - if (len == 0) - return; - - if (qc->dma_dir == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - } else if (qc->dma_dir == DMA_FROM_DEVICE) - ioadl_flags = IPR_IOADL_FLAGS_READ; - - ioarcb->data_transfer_length = cpu_to_be32(len); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - ioarcb->u.sis64_addr_data.data_ioadl_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ata_ioadl.ioadl64)); - - for_each_sg(qc->sg, sg, qc->n_elem, si) { - ioadl64->flags = cpu_to_be32(ioadl_flags); - ioadl64->data_len = cpu_to_be32(sg_dma_len(sg)); - ioadl64->address = cpu_to_be64(sg_dma_address(sg)); - - last_ioadl64 = ioadl64; - ioadl64++; - } - - if (likely(last_ioadl64)) - last_ioadl64->flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_build_ata_ioadl - Build an ATA scatter/gather list - * @ipr_cmd: ipr command struct - * @qc: ATA queued command - * - **/ -static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, - struct ata_queued_cmd *qc) -{ - u32 ioadl_flags = 0; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; - struct ipr_ioadl_desc *last_ioadl = NULL; - int len = qc->nbytes; - struct scatterlist *sg; - unsigned int si; - - if (len == 0) - return; - - if (qc->dma_dir == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->data_transfer_length = cpu_to_be32(len); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } else if (qc->dma_dir == DMA_FROM_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_READ; - ioarcb->read_data_transfer_length = cpu_to_be32(len); - ioarcb->read_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } - - for_each_sg(qc->sg, sg, qc->n_elem, si) { - ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); - ioadl->address = cpu_to_be32(sg_dma_address(sg)); - - last_ioadl = ioadl; - ioadl++; - } - - if (likely(last_ioadl)) - last_ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_qc_defer - Get a free ipr_cmd - * @qc: queued command - * - * Return value: - * 0 if success - **/ -static int ipr_qc_defer(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ipr_sata_port *sata_port = ap->private_data; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_cmnd *ipr_cmd; - struct ipr_hrr_queue *hrrq; - int hrrq_id; - - hrrq_id = ipr_get_hrrq_index(ioa_cfg); - hrrq = &ioa_cfg->hrrq[hrrq_id]; - - qc->lldd_task = NULL; - spin_lock(&hrrq->_lock); - if (unlikely(hrrq->ioa_is_dead)) { - spin_unlock(&hrrq->_lock); - return 0; - } - - if (unlikely(!hrrq->allow_cmds)) { - spin_unlock(&hrrq->_lock); - return ATA_DEFER_LINK; - } - - ipr_cmd = __ipr_get_free_ipr_cmnd(hrrq); - if (ipr_cmd == NULL) { - spin_unlock(&hrrq->_lock); - return ATA_DEFER_LINK; - } - - qc->lldd_task = ipr_cmd; - spin_unlock(&hrrq->_lock); - return 0; -} - -/** - * ipr_qc_issue - Issue a SATA qc to a device - * @qc: queued command - * - * Return value: - * 0 if success - **/ -static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ipr_sata_port *sata_port = ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_cmnd *ipr_cmd; - struct ipr_ioarcb *ioarcb; - struct ipr_ioarcb_ata_regs *regs; - - if (qc->lldd_task == NULL) - ipr_qc_defer(qc); - - ipr_cmd = qc->lldd_task; - if (ipr_cmd == NULL) - return AC_ERR_SYSTEM; - - qc->lldd_task = NULL; - spin_lock(&ipr_cmd->hrrq->_lock); - if (unlikely(!ipr_cmd->hrrq->allow_cmds || - ipr_cmd->hrrq->ioa_is_dead)) { - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); - spin_unlock(&ipr_cmd->hrrq->_lock); - return AC_ERR_SYSTEM; - } - - ipr_init_ipr_cmnd(ipr_cmd, ipr_lock_and_done); - ioarcb = &ipr_cmd->ioarcb; - - if (ioa_cfg->sis64) { - regs = &ipr_cmd->i.ata_ioadl.regs; - ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb)); - } else - regs = &ioarcb->u.add_data.u.regs; - - memset(regs, 0, sizeof(*regs)); - ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(*regs)); - - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_pending_q); - ipr_cmd->qc = qc; - ipr_cmd->done = ipr_sata_done; - ipr_cmd->ioarcb.res_handle = res->res_handle; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - ipr_cmd->dma_use_sg = qc->n_elem; - - if (ioa_cfg->sis64) - ipr_build_ata_ioadl64(ipr_cmd, qc); - else - ipr_build_ata_ioadl(ipr_cmd, qc); - - regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; - ipr_copy_sata_tf(regs, &qc->tf); - memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN); - ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res)); - - switch (qc->tf.protocol) { - case ATA_PROT_NODATA: - case ATA_PROT_PIO: - break; - - case ATA_PROT_DMA: - regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; - break; - - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - regs->flags |= IPR_ATA_FLAG_PACKET_CMD; - break; - - case ATAPI_PROT_DMA: - regs->flags |= IPR_ATA_FLAG_PACKET_CMD; - regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; - break; - - default: - WARN_ON(1); - spin_unlock(&ipr_cmd->hrrq->_lock); - return AC_ERR_INVALID; - } - - ipr_send_command(ipr_cmd); - spin_unlock(&ipr_cmd->hrrq->_lock); - - return 0; -} - -/** - * ipr_qc_fill_rtf - Read result TF - * @qc: ATA queued command - **/ -static void ipr_qc_fill_rtf(struct ata_queued_cmd *qc) -{ - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_ioasa_gata *g = &sata_port->ioasa; - struct ata_taskfile *tf = &qc->result_tf; - - tf->feature = g->error; - tf->nsect = g->nsect; - tf->lbal = g->lbal; - tf->lbam = g->lbam; - tf->lbah = g->lbah; - tf->device = g->device; - tf->command = g->status; - tf->hob_nsect = g->hob_nsect; - tf->hob_lbal = g->hob_lbal; - tf->hob_lbam = g->hob_lbam; - tf->hob_lbah = g->hob_lbah; -} - -static struct ata_port_operations ipr_sata_ops = { - .phy_reset = ipr_ata_phy_reset, - .hardreset = ipr_sata_reset, - .post_internal_cmd = ipr_ata_post_internal, - .qc_prep = ata_noop_qc_prep, - .qc_defer = ipr_qc_defer, - .qc_issue = ipr_qc_issue, - .qc_fill_rtf = ipr_qc_fill_rtf, - .port_start = ata_sas_port_start, - .port_stop = ata_sas_port_stop -}; - -static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | - ATA_FLAG_SAS_HOST, - .pio_mask = ATA_PIO4_ONLY, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - .port_ops = &ipr_sata_ops -}; - #ifdef CONFIG_PPC_PSERIES static const u16 ipr_blocked_processors[] = { PVR_NORTHSTAR, @@ -10181,7 +9414,6 @@ static int ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); - ata_host_init(&ioa_cfg->ata_host, &pdev->dev, &ipr_sata_ops); ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 69444d21fca1..c77d6ca1a210 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,6 @@ * This can be adjusted at runtime through sysfs device attributes. */ #define IPR_MAX_CMD_PER_LUN 6 -#define IPR_MAX_CMD_PER_ATA_LUN 1 /* * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of @@ -197,7 +195,6 @@ #define IPR_LUN_RESET 0x40 #define IPR_TARGET_RESET 0x20 #define IPR_BUS_RESET 0x10 -#define IPR_ATA_PHY_RESET 0x80 #define IPR_ID_HOST_RR_Q 0xC4 #define IPR_QUERY_IOA_CONFIG 0xC5 #define IPR_CANCEL_ALL_REQUESTS 0xCE @@ -521,7 +518,6 @@ struct ipr_cmd_pkt { #define IPR_RQTYPE_SCSICDB 0x00 #define IPR_RQTYPE_IOACMD 0x01 #define IPR_RQTYPE_HCAM 0x02 -#define IPR_RQTYPE_ATA_PASSTHRU 0x04 #define IPR_RQTYPE_PIPE 0x05 u8 reserved2; @@ -546,30 +542,6 @@ struct ipr_cmd_pkt { __be16 timeout; }__attribute__ ((packed, aligned(4))); -struct ipr_ioarcb_ata_regs { /* 22 bytes */ - u8 flags; -#define IPR_ATA_FLAG_PACKET_CMD 0x80 -#define IPR_ATA_FLAG_XFER_TYPE_DMA 0x40 -#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION 0x20 - u8 reserved[3]; - - __be16 data; - u8 feature; - u8 nsect; - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 command; - u8 reserved2[3]; - u8 hob_feature; - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - u8 ctl; -}__attribute__ ((packed, aligned(2))); - struct ipr_ioadl_desc { __be32 flags_and_data_len; #define IPR_IOADL_FLAGS_MASK 0xff000000 @@ -591,15 +563,8 @@ struct ipr_ioadl64_desc { __be64 address; }__attribute__((packed, aligned (16))); -struct ipr_ata64_ioadl { - struct ipr_ioarcb_ata_regs regs; - u16 reserved[5]; - struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES]; -}__attribute__((packed, aligned (16))); - struct ipr_ioarcb_add_data { union { - struct ipr_ioarcb_ata_regs regs; struct ipr_ioadl_desc ioadl[5]; __be32 add_cmd_parms[10]; } u; @@ -665,21 +630,6 @@ struct ipr_ioasa_gpdd { __be32 ioa_data[2]; }__attribute__((packed, aligned (4))); -struct ipr_ioasa_gata { - u8 error; - u8 nsect; /* Interrupt reason */ - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 status; - u8 alt_status; /* ATA CTL */ - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; -}__attribute__((packed, aligned (4))); - struct ipr_auto_sense { __be16 auto_sense_len; __be16 ioa_data_len; @@ -713,7 +663,6 @@ struct ipr_ioasa_hdr { __be32 ioasc_specific; /* status code specific field */ #define IPR_ADDITIONAL_STATUS_FMT 0x80000000 #define IPR_AUTOSENSE_VALID 0x40000000 -#define IPR_ATA_DEVICE_WAS_RESET 0x20000000 #define IPR_IOASC_SPECIFIC_MASK 0x00ffffff #define IPR_FIELD_POINTER_VALID (0x80000000 >> 8) #define IPR_FIELD_POINTER_MASK 0x0000ffff @@ -727,7 +676,6 @@ struct ipr_ioasa { struct ipr_ioasa_vset vset; struct ipr_ioasa_af_dasd dasd; struct ipr_ioasa_gpdd gpdd; - struct ipr_ioasa_gata gata; } u; struct ipr_auto_sense auto_sense; @@ -741,7 +689,6 @@ struct ipr_ioasa64 { struct ipr_ioasa_vset vset; struct ipr_ioasa_af_dasd dasd; struct ipr_ioasa_gpdd gpdd; - struct ipr_ioasa_gata gata; } u; struct ipr_auto_sense auto_sense; @@ -1279,13 +1226,6 @@ struct ipr_bus_attributes { u32 max_xfer_rate; }; -struct ipr_sata_port { - struct ipr_ioa_cfg *ioa_cfg; - struct ata_port *ap; - struct ipr_resource_entry *res; - struct ipr_ioasa_gata ioasa; -}; - struct ipr_resource_entry { u8 needs_sync_complete:1; u8 in_erp:1; @@ -1323,7 +1263,6 @@ struct ipr_resource_entry { struct ipr_ioa_cfg *ioa_cfg; struct scsi_device *sdev; - struct ipr_sata_port *sata_port; struct list_head queue; }; /* struct ipr_resource_entry */ @@ -1582,7 +1521,6 @@ struct ipr_ioa_cfg { struct ipr_cmnd *reset_cmd; int (*reset) (struct ipr_cmnd *); - struct ata_host ata_host; char ipr_cmd_label[8]; #define IPR_CMD_LABEL "ipr_cmd" u32 max_cmds; @@ -1604,7 +1542,6 @@ struct ipr_cmnd { union { struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES]; struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES]; - struct ipr_ata64_ioadl ata_ioadl; } i; union { struct ipr_ioasa ioasa; @@ -1612,7 +1549,6 @@ struct ipr_cmnd { } s; struct list_head queue; struct scsi_cmnd *scsi_cmd; - struct ata_queued_cmd *qc; struct completion completion; struct timer_list timer; struct work_struct work; diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index ec1a9ab61814..73cd25f30ca5 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3362,8 +3362,9 @@ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_dev = ccb->device; status = le32_to_cpu(registerRespPayload->status); device_id = le32_to_cpu(registerRespPayload->device_id); - pm8001_dbg(pm8001_ha, MSG, " register device is status = %d\n", - status); + pm8001_dbg(pm8001_ha, INIT, + "register device status %d phy_id 0x%x device_id %d\n", + status, pm8001_dev->attached_phy, device_id); switch (status) { case DEVREG_SUCCESS: pm8001_dbg(pm8001_ha, MSG, "DEVREG_SUCCESS\n"); @@ -4278,7 +4279,7 @@ int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, memset(&payload, 0, sizeof(payload)); payload.tag = cpu_to_le32(1); payload.device_id = cpu_to_le32(device_id); - pm8001_dbg(pm8001_ha, MSG, "unregister device device_id = %d\n", + pm8001_dbg(pm8001_ha, INIT, "unregister device device_id %d\n", device_id); return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 23c5230dbed4..9415a4819470 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -5346,7 +5346,7 @@ static int __init pmcraid_init(void) } pmcraid_major = MAJOR(dev); - pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); + pmcraid_class = class_create(PMCRAID_DEVFILE); if (IS_ERR(pmcraid_class)) { error = PTR_ERR(pmcraid_class); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index f2ee49756df8..45d359554182 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2450,6 +2450,9 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) qedi_ops->ll2->stop(qedi->cdev); } + cancel_delayed_work_sync(&qedi->recovery_work); + cancel_delayed_work_sync(&qedi->board_disable_work); + qedi_free_iscsi_pf_param(qedi); rval = qedi_ops->common->update_drv_state(qedi->cdev, false); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index df5e5b7fdcfe..84aa3571be6d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3796,6 +3796,7 @@ struct qla_qpair { uint64_t retry_term_jiff; struct qla_tgt_counters tgt_counters; uint16_t cpuid; + bool cpu_mapped; struct qla_fw_resources fwres ____cacheline_aligned; struct qla_buf_pool buf_pool; u32 cmd_cnt; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ec0423ec6681..1a955c3ff3d6 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -9426,6 +9426,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->rsp->req = qpair->req; qpair->rsp->qpair = qpair; + if (!qpair->cpu_mapped) + qla_cpu_update(qpair, raw_smp_processor_id()); + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) qpair->difdix_supported = 1; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index cce6e425c121..7b42558a8839 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -539,11 +539,14 @@ qla_mapq_init_qp_cpu_map(struct qla_hw_data *ha, if (!ha->qp_cpu_map) return; mask = pci_irq_get_affinity(ha->pdev, msix->vector_base0); + if (!mask) + return; qpair->cpuid = cpumask_first(mask); for_each_cpu(cpu, mask) { ha->qp_cpu_map[cpu] = qpair; } msix->cpuid = qpair->cpuid; + qpair->cpu_mapped = true; } static inline void diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 71feda2cdb63..245e3a5d81fd 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3770,6 +3770,9 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (rsp->qpair->cpuid != smp_processor_id() || !rsp->qpair->rcv_intr) { rsp->qpair->rcv_intr = 1; + + if (!rsp->qpair->cpu_mapped) + qla_cpu_update(rsp->qpair, raw_smp_processor_id()); } #define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in) \ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f4fa1035a191..8c58128ad32a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -5291,6 +5291,26 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) return SUCCESS; } +static bool scsi_debug_stop_all_queued_iter(struct request *rq, void *data) +{ + struct scsi_device *sdp = data; + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + + if (scmd->device == sdp) + scsi_debug_abort_cmnd(scmd); + + return true; +} + +/* Deletes (stops) timers or work queues of all queued commands per sdev */ +static void scsi_debug_stop_all_queued(struct scsi_device *sdp) +{ + struct Scsi_Host *shost = sdp->host; + + blk_mq_tagset_busy_iter(&shost->tag_set, + scsi_debug_stop_all_queued_iter, sdp); +} + static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) { struct scsi_device *sdp = SCpnt->device; @@ -5300,6 +5320,8 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + + scsi_debug_stop_all_queued(sdp); if (devip) set_bit(SDEBUG_UA_POR, devip->uas_bm); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b7c569a42aa4..0226c9279cef 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1463,6 +1463,8 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; int rtn = 0; + atomic_inc(&cmd->device->iorequest_cnt); + /* check if the device is still usable */ if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { /* in SDEV_DEL we error all commands. DID_NO_CONNECT @@ -1483,6 +1485,7 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) */ SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd, "queuecommand : device blocked\n")); + atomic_dec(&cmd->device->iorequest_cnt); return SCSI_MLQUEUE_DEVICE_BUSY; } @@ -1515,6 +1518,7 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) trace_scsi_dispatch_cmd_start(cmd); rtn = host->hostt->queuecommand(host, cmd); if (rtn) { + atomic_dec(&cmd->device->iorequest_cnt); trace_scsi_dispatch_cmd_error(cmd, rtn); if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && rtn != SCSI_MLQUEUE_TARGET_BUSY) @@ -1761,7 +1765,6 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, goto out_dec_host_busy; } - atomic_inc(&cmd->device->iorequest_cnt); return BLK_STS_OK; out_dec_host_busy: diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c index 7259704a7f52..7f0914ea168f 100644 --- a/drivers/scsi/scsi_sysctl.c +++ b/drivers/scsi/scsi_sysctl.c @@ -21,25 +21,11 @@ static struct ctl_table scsi_table[] = { { } }; -static struct ctl_table scsi_dir_table[] = { - { .procname = "scsi", - .mode = 0555, - .child = scsi_table }, - { } -}; - -static struct ctl_table scsi_root_table[] = { - { .procname = "dev", - .mode = 0555, - .child = scsi_dir_table }, - { } -}; - static struct ctl_table_header *scsi_table_header; int __init scsi_init_sysctl(void) { - scsi_table_header = register_sysctl_table(scsi_root_table); + scsi_table_header = register_sysctl("dev/scsi", scsi_table); if (!scsi_table_header) return -ENOMEM; return 0; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4bb87043e6db..1624d528aa1f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -587,7 +587,6 @@ ATTRIBUTE_GROUPS(sd_disk); static struct class sd_disk_class = { .name = "scsi_disk", - .owner = THIS_MODULE, .dev_release = scsi_disk_release, .dev_groups = sd_disk_groups, }; diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index b54f2c6c08c3..d7d0c35c58b8 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -662,8 +662,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, } } -static int ses_intf_add(struct device *cdev, - struct class_interface *intf) +static int ses_intf_add(struct device *cdev) { struct scsi_device *sdev = to_scsi_device(cdev->parent); struct scsi_device *tmp_sdev; @@ -865,8 +864,7 @@ static void ses_intf_remove_enclosure(struct scsi_device *sdev) enclosure_unregister(edev); } -static void ses_intf_remove(struct device *cdev, - struct class_interface *intf) +static void ses_intf_remove(struct device *cdev) { struct scsi_device *sdev = to_scsi_device(cdev->parent); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index a91049213203..037f8c98a6d3 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -96,8 +96,8 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; #define SG_SECTOR_SZ 512 -static int sg_add_device(struct device *, struct class_interface *); -static void sg_remove_device(struct device *, struct class_interface *); +static int sg_add_device(struct device *); +static void sg_remove_device(struct device *); static DEFINE_IDR(sg_index_idr); static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock @@ -1488,7 +1488,7 @@ out_unlock: } static int -sg_add_device(struct device *cl_dev, struct class_interface *cl_intf) +sg_add_device(struct device *cl_dev) { struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); Sg_device *sdp = NULL; @@ -1578,7 +1578,7 @@ sg_device_destroy(struct kref *kref) } static void -sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf) +sg_remove_device(struct device *cl_dev) { struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); Sg_device *sdp = dev_get_drvdata(cl_dev); @@ -1677,7 +1677,7 @@ init_sg(void) SG_MAX_DEVS, "sg"); if (rc) return rc; - sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic"); + sg_sysfs_class = class_create("scsi_generic"); if ( IS_ERR(sg_sysfs_class) ) { rc = PTR_ERR(sg_sysfs_class); goto err_out; diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 5b230e149c3d..8ffb75be99bc 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -109,7 +109,9 @@ enum { TASK_ATTRIBUTE_HEADOFQUEUE = 0x1, TASK_ATTRIBUTE_ORDERED = 0x2, TASK_ATTRIBUTE_ACA = 0x4, +}; +enum { SS_STS_NORMAL = 0x80000000, SS_STS_DONE = 0x40000000, SS_STS_HANDSHAKE = 0x20000000, @@ -121,7 +123,9 @@ enum { SS_I2H_REQUEST_RESET = 0x2000, SS_MU_OPERATIONAL = 0x80000000, +}; +enum { STEX_CDB_LENGTH = 16, STATUS_VAR_LEN = 128, diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index d9ce379c4d2e..e6bc622954cf 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1780,7 +1780,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) length = scsi_bufflen(scmnd); payload = (struct vmbus_packet_mpb_array *)&cmd_request->mpb; - payload_sz = sizeof(cmd_request->mpb); + payload_sz = 0; if (scsi_sg_count(scmnd)) { unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset); @@ -1789,10 +1789,10 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) unsigned long hvpfn, hvpfns_to_add; int j, i = 0, sg_count; - if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { + payload_sz = (hvpg_count * sizeof(u64) + + sizeof(struct vmbus_packet_mpb_array)); - payload_sz = (hvpg_count * sizeof(u64) + - sizeof(struct vmbus_packet_mpb_array)); + if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { payload = kzalloc(payload_sz, GFP_ATOMIC); if (!payload) return SCSI_MLQUEUE_DEVICE_BUSY; diff --git a/drivers/sh/intc/userimask.c b/drivers/sh/intc/userimask.c index f9f043a3d90a..abe9091827cd 100644 --- a/drivers/sh/intc/userimask.c +++ b/drivers/sh/intc/userimask.c @@ -61,10 +61,18 @@ static DEVICE_ATTR(userimask, S_IRUSR | S_IWUSR, static int __init userimask_sysdev_init(void) { + struct device *dev_root; + int ret = 0; + if (unlikely(!uimask)) return -ENXIO; - return device_create_file(intc_subsys.dev_root, &dev_attr_userimask); + dev_root = bus_get_dev_root(&intc_subsys); + if (dev_root) { + ret = device_create_file(dev_root, &dev_attr_userimask); + put_device(dev_root); + } + return ret; } late_initcall(userimask_sysdev_init); diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 165f7548401b..6abb730344ab 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -174,11 +174,6 @@ static int __init meson_gx_socinfo_init(void) return -ENODEV; soc_dev_attr->family = "Amlogic Meson"; - - np = of_find_node_by_path("/"); - of_property_read_string(np, "model", &soc_dev_attr->machine); - of_node_put(np); - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x:%x - %x:%x", socinfo_to_major(socinfo), socinfo_to_minor(socinfo), diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c index a3e2bc1d2686..d62a776c89a1 100644 --- a/drivers/soc/apple/apple-pmgr-pwrstate.c +++ b/drivers/soc/apple/apple-pmgr-pwrstate.c @@ -322,6 +322,5 @@ static struct platform_driver apple_pmgr_ps_driver = { MODULE_AUTHOR("Hector Martin "); MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs"); -MODULE_LICENSE("GPL v2"); module_platform_driver(apple_pmgr_ps_driver); diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 7268c2fbcbc1..e0d096607fef 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -36,7 +36,7 @@ config UCC config CPM_TSA tristate "CPM TSA support" depends on OF && HAS_IOMEM - depends on CPM1 || COMPILE_TEST + depends on CPM1 || (CPM && COMPILE_TEST) help Freescale CPM Time Slot Assigner (TSA) controller. @@ -47,7 +47,7 @@ config CPM_TSA config CPM_QMC tristate "CPM QMC support" depends on OF && HAS_IOMEM - depends on CPM1 || (FSL_SOC && COMPILE_TEST) + depends on CPM1 || (FSL_SOC && CPM && COMPILE_TEST) depends on CPM_TSA help Freescale CPM QUICC Multichannel Controller diff --git a/drivers/soc/fujitsu/a64fx-diag.c b/drivers/soc/fujitsu/a64fx-diag.c index d87f348427bf..524fbfeb94e3 100644 --- a/drivers/soc/fujitsu/a64fx-diag.c +++ b/drivers/soc/fujitsu/a64fx-diag.c @@ -149,6 +149,5 @@ static struct platform_driver a64fx_diag_driver = { module_platform_driver(a64fx_diag_driver); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Hitomi Hasegawa "); MODULE_DESCRIPTION("A64FX diag driver"); diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 0d31377f178d..ce48a9f3b4c8 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -126,7 +126,6 @@ static int qcom_rmtfs_mem_release(struct inode *inode, struct file *filp) } static struct class rmtfs_class = { - .owner = THIS_MODULE, .name = "rmtfs", }; diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig index 2b7795233282..fa71c9a36df7 100644 --- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig @@ -18,6 +18,16 @@ if SOUNDWIRE comment "SoundWire Devices" +config SOUNDWIRE_AMD + tristate "AMD SoundWire Manager driver" + select SOUNDWIRE_GENERIC_ALLOCATION + depends on ACPI && SND_SOC + help + SoundWire AMD Manager driver. + If you have an AMD platform which has a SoundWire Manager then + enable this config option to get the SoundWire support for that + device. + config SOUNDWIRE_CADENCE tristate diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index ca97414ada70..925566ff4272 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -15,12 +15,17 @@ ifdef CONFIG_DEBUG_FS soundwire-bus-y += debugfs.o endif +#AMD driver +soundwire-amd-y := amd_manager.o +obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o + #Cadence Objs soundwire-cadence-y := cadence_master.o obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o #Intel driver -soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o +soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o \ + intel_bus_common.o obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o #Qualcomm driver diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c new file mode 100644 index 000000000000..9fb7f91ca182 --- /dev/null +++ b/drivers/soundwire/amd_manager.c @@ -0,0 +1,1208 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SoundWire AMD Manager driver + * + * Copyright 2023 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bus.h" +#include "amd_manager.h" + +#define DRV_NAME "amd_sdw_manager" + +#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus) + +static void amd_enable_sdw_pads(struct amd_sdw_manager *amd_manager) +{ + u32 sw_pad_pulldown_val; + u32 val; + + mutex_lock(amd_manager->acp_sdw_lock); + val = readl(amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN); + val |= amd_manager->reg_mask->sw_pad_enable_mask; + writel(val, amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN); + usleep_range(1000, 1500); + + sw_pad_pulldown_val = readl(amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL); + sw_pad_pulldown_val &= amd_manager->reg_mask->sw_pad_pulldown_mask; + writel(sw_pad_pulldown_val, amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL); + mutex_unlock(amd_manager->acp_sdw_lock); +} + +static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager) +{ + u32 val; + int ret; + + writel(AMD_SDW_ENABLE, amd_manager->mmio + ACP_SW_EN); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, val, ACP_DELAY_US, + AMD_SDW_TIMEOUT); + if (ret) + return ret; + + /* SoundWire manager bus reset */ + writel(AMD_SDW_BUS_RESET_REQ, amd_manager->mmio + ACP_SW_BUS_RESET_CTRL); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_BUS_RESET_CTRL, val, + (val & AMD_SDW_BUS_RESET_DONE), ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) + return ret; + + writel(AMD_SDW_BUS_RESET_CLEAR_REQ, amd_manager->mmio + ACP_SW_BUS_RESET_CTRL); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_BUS_RESET_CTRL, val, !val, + ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) { + dev_err(amd_manager->dev, "Failed to reset SoundWire manager instance%d\n", + amd_manager->instance); + return ret; + } + + writel(AMD_SDW_DISABLE, amd_manager->mmio + ACP_SW_EN); + return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, !val, ACP_DELAY_US, + AMD_SDW_TIMEOUT); +} + +static int amd_enable_sdw_manager(struct amd_sdw_manager *amd_manager) +{ + u32 val; + + writel(AMD_SDW_ENABLE, amd_manager->mmio + ACP_SW_EN); + return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, val, ACP_DELAY_US, + AMD_SDW_TIMEOUT); +} + +static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager) +{ + u32 val; + + writel(AMD_SDW_DISABLE, amd_manager->mmio + ACP_SW_EN); + /* + * After invoking manager disable sequence, check whether + * manager has executed clock stop sequence. In this case, + * manager should ignore checking enable status register. + */ + val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + if (val) + return 0; + return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, !val, ACP_DELAY_US, + AMD_SDW_TIMEOUT); +} + +static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager) +{ + struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask; + u32 val; + + mutex_lock(amd_manager->acp_sdw_lock); + val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + val |= reg_mask->acp_sdw_intr_mask; + writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + mutex_unlock(amd_manager->acp_sdw_lock); + + writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio + + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); + writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio + + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11); + writel(AMD_SDW_IRQ_ERROR_MASK, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK); +} + +static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager) +{ + struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask; + u32 val; + + mutex_lock(amd_manager->acp_sdw_lock); + val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + val &= ~reg_mask->acp_sdw_intr_mask; + writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); + mutex_unlock(amd_manager->acp_sdw_lock); + + writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); + writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11); + writel(0x00, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK); +} + +static int amd_deinit_sdw_manager(struct amd_sdw_manager *amd_manager) +{ + amd_disable_sdw_interrupts(amd_manager); + return amd_disable_sdw_manager(amd_manager); +} + +static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager) +{ + u32 frame_size; + + frame_size = (amd_manager->rows_index << 3) | amd_manager->cols_index; + writel(frame_size, amd_manager->mmio + ACP_SW_FRAMESIZE); +} + +static void amd_sdw_ctl_word_prep(u32 *lower_word, u32 *upper_word, struct sdw_msg *msg, + int cmd_offset) +{ + u32 upper_data; + u32 lower_data = 0; + u16 addr; + u8 upper_addr, lower_addr; + u8 data = 0; + + addr = msg->addr + cmd_offset; + upper_addr = (addr & 0xFF00) >> 8; + lower_addr = addr & 0xFF; + + if (msg->flags == SDW_MSG_FLAG_WRITE) + data = msg->buf[cmd_offset]; + + upper_data = FIELD_PREP(AMD_SDW_MCP_CMD_DEV_ADDR, msg->dev_num); + upper_data |= FIELD_PREP(AMD_SDW_MCP_CMD_COMMAND, msg->flags + 2); + upper_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_ADDR_HIGH, upper_addr); + lower_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_ADDR_LOW, lower_addr); + lower_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_DATA, data); + + *upper_word = upper_data; + *lower_word = lower_data; +} + +static u64 amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data, + u32 upper_data) +{ + u64 resp; + u32 lower_resp, upper_resp; + u32 sts; + int ret; + + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts, + !(sts & AMD_SDW_IMM_CMD_BUSY), ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) { + dev_err(amd_manager->dev, "SDW%x previous cmd status clear failed\n", + amd_manager->instance); + return ret; + } + + if (sts & AMD_SDW_IMM_RES_VALID) { + dev_err(amd_manager->dev, "SDW%x manager is in bad state\n", amd_manager->instance); + writel(0x00, amd_manager->mmio + ACP_SW_IMM_CMD_STS); + } + writel(upper_data, amd_manager->mmio + ACP_SW_IMM_CMD_UPPER_WORD); + writel(lower_data, amd_manager->mmio + ACP_SW_IMM_CMD_LOWER_QWORD); + + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts, + (sts & AMD_SDW_IMM_RES_VALID), ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) { + dev_err(amd_manager->dev, "SDW%x cmd response timeout occurred\n", + amd_manager->instance); + return ret; + } + upper_resp = readl(amd_manager->mmio + ACP_SW_IMM_RESP_UPPER_WORD); + lower_resp = readl(amd_manager->mmio + ACP_SW_IMM_RESP_LOWER_QWORD); + + writel(AMD_SDW_IMM_RES_VALID, amd_manager->mmio + ACP_SW_IMM_CMD_STS); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts, + !(sts & AMD_SDW_IMM_RES_VALID), ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) { + dev_err(amd_manager->dev, "SDW%x cmd status retry failed\n", + amd_manager->instance); + return ret; + } + resp = upper_resp; + resp = (resp << 32) | lower_resp; + return resp; +} + +static enum sdw_command_response +amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg) +{ + struct sdw_msg scp_msg = {0}; + u64 response_buf[2] = {0}; + u32 upper_data = 0, lower_data = 0; + int index; + + scp_msg.dev_num = msg->dev_num; + scp_msg.addr = SDW_SCP_ADDRPAGE1; + scp_msg.buf = &msg->addr_page1; + scp_msg.flags = SDW_MSG_FLAG_WRITE; + amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0); + response_buf[0] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data); + scp_msg.addr = SDW_SCP_ADDRPAGE2; + scp_msg.buf = &msg->addr_page2; + amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0); + response_buf[1] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data); + + for (index = 0; index < 2; index++) { + if (response_buf[index] == -ETIMEDOUT) { + dev_err_ratelimited(amd_manager->dev, + "SCP_addrpage command timeout for Slave %d\n", + msg->dev_num); + return SDW_CMD_TIMEOUT; + } else if (!(response_buf[index] & AMD_SDW_MCP_RESP_ACK)) { + if (response_buf[index] & AMD_SDW_MCP_RESP_NACK) { + dev_err_ratelimited(amd_manager->dev, + "SCP_addrpage NACKed for Slave %d\n", + msg->dev_num); + return SDW_CMD_FAIL; + } + dev_dbg_ratelimited(amd_manager->dev, "SCP_addrpage ignored for Slave %d\n", + msg->dev_num); + return SDW_CMD_IGNORED; + } + } + return SDW_CMD_OK; +} + +static int amd_prep_msg(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg) +{ + int ret; + + if (msg->page) { + ret = amd_program_scp_addr(amd_manager, msg); + if (ret) { + msg->len = 0; + return ret; + } + } + switch (msg->flags) { + case SDW_MSG_FLAG_READ: + case SDW_MSG_FLAG_WRITE: + break; + default: + dev_err(amd_manager->dev, "Invalid msg cmd: %d\n", msg->flags); + return -EINVAL; + } + return 0; +} + +static enum sdw_command_response amd_sdw_fill_msg_resp(struct amd_sdw_manager *amd_manager, + struct sdw_msg *msg, u64 response, + int offset) +{ + if (response & AMD_SDW_MCP_RESP_ACK) { + if (msg->flags == SDW_MSG_FLAG_READ) + msg->buf[offset] = FIELD_GET(AMD_SDW_MCP_RESP_RDATA, response); + } else { + if (response == -ETIMEDOUT) { + dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n", + msg->dev_num); + return SDW_CMD_TIMEOUT; + } else if (response & AMD_SDW_MCP_RESP_NACK) { + dev_err_ratelimited(amd_manager->dev, + "command response NACK received for Slave %d\n", + msg->dev_num); + return SDW_CMD_FAIL; + } + dev_err_ratelimited(amd_manager->dev, "command is ignored for Slave %d\n", + msg->dev_num); + return SDW_CMD_IGNORED; + } + return SDW_CMD_OK; +} + +static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg, + int cmd_offset) +{ + u64 response; + u32 upper_data = 0, lower_data = 0; + + amd_sdw_ctl_word_prep(&lower_data, &upper_data, msg, cmd_offset); + response = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data); + return amd_sdw_fill_msg_resp(amd_manager, msg, response, cmd_offset); +} + +static enum sdw_command_response amd_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + int ret, i; + + ret = amd_prep_msg(amd_manager, msg); + if (ret) + return SDW_CMD_FAIL_OTHER; + for (i = 0; i < msg->len; i++) { + ret = _amd_sdw_xfer_msg(amd_manager, msg, i); + if (ret) + return ret; + } + return SDW_CMD_OK; +} + +static void amd_sdw_fill_slave_status(struct amd_sdw_manager *amd_manager, u16 index, u32 status) +{ + switch (status) { + case SDW_SLAVE_ATTACHED: + case SDW_SLAVE_UNATTACHED: + case SDW_SLAVE_ALERT: + amd_manager->status[index] = status; + break; + default: + amd_manager->status[index] = SDW_SLAVE_RESERVED; + break; + } +} + +static void amd_sdw_process_ping_status(u64 response, struct amd_sdw_manager *amd_manager) +{ + u64 slave_stat; + u32 val; + u16 dev_index; + + /* slave status response */ + slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response); + slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8; + dev_dbg(amd_manager->dev, "slave_stat:0x%llx\n", slave_stat); + for (dev_index = 0; dev_index <= SDW_MAX_DEVICES; ++dev_index) { + val = (slave_stat >> (dev_index * 2)) & AMD_SDW_MCP_SLAVE_STATUS_MASK; + dev_dbg(amd_manager->dev, "val:0x%x\n", val); + amd_sdw_fill_slave_status(amd_manager, dev_index, val); + } +} + +static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_manager) +{ + u64 response; + + mutex_lock(&amd_manager->bus.msg_lock); + response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0); + mutex_unlock(&amd_manager->bus.msg_lock); + amd_sdw_process_ping_status(response, amd_manager); +} + +static u32 amd_sdw_read_ping_status(struct sdw_bus *bus) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + u64 response; + u32 slave_stat; + + response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0); + /* slave status from ping response */ + slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response); + slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8; + dev_dbg(amd_manager->dev, "slave_stat:0x%x\n", slave_stat); + return slave_stat; +} + +static int amd_sdw_compute_params(struct sdw_bus *bus) +{ + struct sdw_transport_data t_data = {0}; + struct sdw_master_runtime *m_rt; + struct sdw_port_runtime *p_rt; + struct sdw_bus_params *b_params = &bus->params; + int port_bo, hstart, hstop, sample_int; + unsigned int rate, bps; + + port_bo = 0; + hstart = 1; + hstop = bus->params.col - 1; + t_data.hstop = hstop; + t_data.hstart = hstart; + + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + rate = m_rt->stream->params.rate; + bps = m_rt->stream->params.bps; + sample_int = (bus->params.curr_dr_freq / rate); + list_for_each_entry(p_rt, &m_rt->port_list, port_node) { + port_bo = (p_rt->num * 64) + 1; + dev_dbg(bus->dev, "p_rt->num=%d hstart=%d hstop=%d port_bo=%d\n", + p_rt->num, hstart, hstop, port_bo); + sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, + false, SDW_BLK_GRP_CNT_1, sample_int, + port_bo, port_bo >> 8, hstart, hstop, + SDW_BLK_PKG_PER_PORT, 0x0); + + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, bps, + SDW_PORT_FLOW_MODE_ISOCH, + b_params->m_data_mode); + t_data.hstart = hstart; + t_data.hstop = hstop; + t_data.block_offset = port_bo; + t_data.sub_block_offset = 0; + } + sdw_compute_slave_ports(m_rt, &t_data); + } + return 0; +} + +static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params, + unsigned int bank) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + u32 frame_fmt_reg, dpn_frame_fmt; + + dev_dbg(amd_manager->dev, "p_params->num:0x%x\n", p_params->num); + switch (amd_manager->instance) { + case ACP_SDW0: + frame_fmt_reg = sdw0_manager_dp_reg[p_params->num].frame_fmt_reg; + break; + case ACP_SDW1: + frame_fmt_reg = sdw1_manager_dp_reg[p_params->num].frame_fmt_reg; + break; + default: + return -EINVAL; + } + + dpn_frame_fmt = readl(amd_manager->mmio + frame_fmt_reg); + u32p_replace_bits(&dpn_frame_fmt, p_params->flow_mode, AMD_DPN_FRAME_FMT_PFM); + u32p_replace_bits(&dpn_frame_fmt, p_params->data_mode, AMD_DPN_FRAME_FMT_PDM); + u32p_replace_bits(&dpn_frame_fmt, p_params->bps - 1, AMD_DPN_FRAME_FMT_WORD_LEN); + writel(dpn_frame_fmt, amd_manager->mmio + frame_fmt_reg); + return 0; +} + +static int amd_sdw_transport_params(struct sdw_bus *bus, + struct sdw_transport_params *params, + enum sdw_reg_bank bank) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + u32 dpn_frame_fmt; + u32 dpn_sampleinterval; + u32 dpn_hctrl; + u32 dpn_offsetctrl; + u32 dpn_lanectrl; + u32 frame_fmt_reg, sample_int_reg, hctrl_dp0_reg; + u32 offset_reg, lane_ctrl_ch_en_reg; + + switch (amd_manager->instance) { + case ACP_SDW0: + frame_fmt_reg = sdw0_manager_dp_reg[params->port_num].frame_fmt_reg; + sample_int_reg = sdw0_manager_dp_reg[params->port_num].sample_int_reg; + hctrl_dp0_reg = sdw0_manager_dp_reg[params->port_num].hctrl_dp0_reg; + offset_reg = sdw0_manager_dp_reg[params->port_num].offset_reg; + lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg; + break; + case ACP_SDW1: + frame_fmt_reg = sdw1_manager_dp_reg[params->port_num].frame_fmt_reg; + sample_int_reg = sdw1_manager_dp_reg[params->port_num].sample_int_reg; + hctrl_dp0_reg = sdw1_manager_dp_reg[params->port_num].hctrl_dp0_reg; + offset_reg = sdw1_manager_dp_reg[params->port_num].offset_reg; + lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg; + break; + default: + return -EINVAL; + } + writel(AMD_SDW_SSP_COUNTER_VAL, amd_manager->mmio + ACP_SW_SSP_COUNTER); + + dpn_frame_fmt = readl(amd_manager->mmio + frame_fmt_reg); + u32p_replace_bits(&dpn_frame_fmt, params->blk_pkg_mode, AMD_DPN_FRAME_FMT_BLK_PKG_MODE); + u32p_replace_bits(&dpn_frame_fmt, params->blk_grp_ctrl, AMD_DPN_FRAME_FMT_BLK_GRP_CTRL); + u32p_replace_bits(&dpn_frame_fmt, SDW_STREAM_PCM, AMD_DPN_FRAME_FMT_PCM_OR_PDM); + writel(dpn_frame_fmt, amd_manager->mmio + frame_fmt_reg); + + dpn_sampleinterval = params->sample_interval - 1; + writel(dpn_sampleinterval, amd_manager->mmio + sample_int_reg); + + dpn_hctrl = FIELD_PREP(AMD_DPN_HCTRL_HSTOP, params->hstop); + dpn_hctrl |= FIELD_PREP(AMD_DPN_HCTRL_HSTART, params->hstart); + writel(dpn_hctrl, amd_manager->mmio + hctrl_dp0_reg); + + dpn_offsetctrl = FIELD_PREP(AMD_DPN_OFFSET_CTRL_1, params->offset1); + dpn_offsetctrl |= FIELD_PREP(AMD_DPN_OFFSET_CTRL_2, params->offset2); + writel(dpn_offsetctrl, amd_manager->mmio + offset_reg); + + /* + * lane_ctrl_ch_en_reg will be used to program lane_ctrl and ch_mask + * parameters. + */ + dpn_lanectrl = readl(amd_manager->mmio + lane_ctrl_ch_en_reg); + u32p_replace_bits(&dpn_lanectrl, params->lane_ctrl, AMD_DPN_CH_EN_LCTRL); + writel(dpn_lanectrl, amd_manager->mmio + lane_ctrl_ch_en_reg); + return 0; +} + +static int amd_sdw_port_enable(struct sdw_bus *bus, + struct sdw_enable_ch *enable_ch, + unsigned int bank) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + u32 dpn_ch_enable; + u32 lane_ctrl_ch_en_reg; + + switch (amd_manager->instance) { + case ACP_SDW0: + lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; + break; + case ACP_SDW1: + lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; + break; + default: + return -EINVAL; + } + + /* + * lane_ctrl_ch_en_reg will be used to program lane_ctrl and ch_mask + * parameters. + */ + dpn_ch_enable = readl(amd_manager->mmio + lane_ctrl_ch_en_reg); + u32p_replace_bits(&dpn_ch_enable, enable_ch->ch_mask, AMD_DPN_CH_EN_CHMASK); + if (enable_ch->enable) + writel(dpn_ch_enable, amd_manager->mmio + lane_ctrl_ch_en_reg); + else + writel(0, amd_manager->mmio + lane_ctrl_ch_en_reg); + return 0; +} + +static int sdw_master_read_amd_prop(struct sdw_bus *bus) +{ + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); + struct fwnode_handle *link; + struct sdw_master_prop *prop; + u32 quirk_mask = 0; + u32 wake_en_mask = 0; + u32 power_mode_mask = 0; + char name[32]; + + prop = &bus->prop; + /* Find manager handle */ + snprintf(name, sizeof(name), "mipi-sdw-link-%d-subproperties", bus->link_id); + link = device_get_named_child_node(bus->dev, name); + if (!link) { + dev_err(bus->dev, "Manager node %s not found\n", name); + return -EIO; + } + fwnode_property_read_u32(link, "amd-sdw-enable", &quirk_mask); + if (!(quirk_mask & AMD_SDW_QUIRK_MASK_BUS_ENABLE)) + prop->hw_disabled = true; + prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH | + SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY; + + fwnode_property_read_u32(link, "amd-sdw-wakeup-enable", &wake_en_mask); + amd_manager->wake_en_mask = wake_en_mask; + fwnode_property_read_u32(link, "amd-sdw-power-mode", &power_mode_mask); + amd_manager->power_mode_mask = power_mode_mask; + return 0; +} + +static int amd_prop_read(struct sdw_bus *bus) +{ + sdw_master_read_prop(bus); + sdw_master_read_amd_prop(bus); + return 0; +} + +static const struct sdw_master_port_ops amd_sdw_port_ops = { + .dpn_set_port_params = amd_sdw_port_params, + .dpn_set_port_transport_params = amd_sdw_transport_params, + .dpn_port_enable_ch = amd_sdw_port_enable, +}; + +static const struct sdw_master_ops amd_sdw_ops = { + .read_prop = amd_prop_read, + .xfer_msg = amd_sdw_xfer_msg, + .read_ping_status = amd_sdw_read_ping_status, +}; + +static int amd_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dai_runtime *dai_runtime; + struct sdw_stream_config sconfig; + struct sdw_port_config *pconfig; + int ch, dir; + int ret; + + dai_runtime = amd_manager->dai_runtime_array[dai->id]; + if (!dai_runtime) + return -EIO; + + ch = params_channels(params); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dir = SDW_DATA_DIR_RX; + else + dir = SDW_DATA_DIR_TX; + dev_dbg(amd_manager->dev, "dir:%d dai->id:0x%x\n", dir, dai->id); + + sconfig.direction = dir; + sconfig.ch_count = ch; + sconfig.frame_rate = params_rate(params); + sconfig.type = dai_runtime->stream_type; + + sconfig.bps = snd_pcm_format_width(params_format(params)); + + /* Port configuration */ + pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); + if (!pconfig) { + ret = -ENOMEM; + goto error; + } + + pconfig->num = dai->id; + pconfig->ch_mask = (1 << ch) - 1; + ret = sdw_stream_add_master(&amd_manager->bus, &sconfig, + pconfig, 1, dai_runtime->stream); + if (ret) + dev_err(amd_manager->dev, "add manager to stream failed:%d\n", ret); + + kfree(pconfig); +error: + return ret; +} + +static int amd_sdw_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dai_runtime *dai_runtime; + int ret; + + dai_runtime = amd_manager->dai_runtime_array[dai->id]; + if (!dai_runtime) + return -EIO; + + ret = sdw_stream_remove_master(&amd_manager->bus, dai_runtime->stream); + if (ret < 0) + dev_err(dai->dev, "remove manager from stream %s failed: %d\n", + dai_runtime->stream->name, ret); + return ret; +} + +static int amd_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) +{ + struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dai_runtime *dai_runtime; + + dai_runtime = amd_manager->dai_runtime_array[dai->id]; + if (stream) { + /* first paranoia check */ + if (dai_runtime) { + dev_err(dai->dev, "dai_runtime already allocated for dai %s\n", dai->name); + return -EINVAL; + } + + /* allocate and set dai_runtime info */ + dai_runtime = kzalloc(sizeof(*dai_runtime), GFP_KERNEL); + if (!dai_runtime) + return -ENOMEM; + + dai_runtime->stream_type = SDW_STREAM_PCM; + dai_runtime->bus = &amd_manager->bus; + dai_runtime->stream = stream; + amd_manager->dai_runtime_array[dai->id] = dai_runtime; + } else { + /* second paranoia check */ + if (!dai_runtime) { + dev_err(dai->dev, "dai_runtime not allocated for dai %s\n", dai->name); + return -EINVAL; + } + + /* for NULL stream we release allocated dai_runtime */ + kfree(dai_runtime); + amd_manager->dai_runtime_array[dai->id] = NULL; + } + return 0; +} + +static int amd_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) +{ + return amd_set_sdw_stream(dai, stream, direction); +} + +static void *amd_get_sdw_stream(struct snd_soc_dai *dai, int direction) +{ + struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dai_runtime *dai_runtime; + + dai_runtime = amd_manager->dai_runtime_array[dai->id]; + if (!dai_runtime) + return ERR_PTR(-EINVAL); + + return dai_runtime->stream; +} + +static const struct snd_soc_dai_ops amd_sdw_dai_ops = { + .hw_params = amd_sdw_hw_params, + .hw_free = amd_sdw_hw_free, + .set_stream = amd_pcm_set_sdw_stream, + .get_stream = amd_get_sdw_stream, +}; + +static const struct snd_soc_component_driver amd_sdw_dai_component = { + .name = "soundwire", +}; + +static int amd_sdw_register_dais(struct amd_sdw_manager *amd_manager) +{ + struct sdw_amd_dai_runtime **dai_runtime_array; + struct snd_soc_dai_driver *dais; + struct snd_soc_pcm_stream *stream; + struct device *dev; + int i, num_dais; + + dev = amd_manager->dev; + num_dais = amd_manager->num_dout_ports + amd_manager->num_din_ports; + dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL); + if (!dais) + return -ENOMEM; + + dai_runtime_array = devm_kcalloc(dev, num_dais, + sizeof(struct sdw_amd_dai_runtime *), + GFP_KERNEL); + if (!dai_runtime_array) + return -ENOMEM; + amd_manager->dai_runtime_array = dai_runtime_array; + for (i = 0; i < num_dais; i++) { + dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW%d Pin%d", amd_manager->instance, + i); + if (!dais[i].name) + return -ENOMEM; + if (i < amd_manager->num_dout_ports) + stream = &dais[i].playback; + else + stream = &dais[i].capture; + + stream->channels_min = 2; + stream->channels_max = 2; + stream->rates = SNDRV_PCM_RATE_48000; + stream->formats = SNDRV_PCM_FMTBIT_S16_LE; + + dais[i].ops = &amd_sdw_dai_ops; + dais[i].id = i; + } + + return devm_snd_soc_register_component(dev, &amd_sdw_dai_component, + dais, num_dais); +} + +static void amd_sdw_update_slave_status_work(struct work_struct *work) +{ + struct amd_sdw_manager *amd_manager = + container_of(work, struct amd_sdw_manager, amd_sdw_work); + int retry_count = 0; + + if (amd_manager->status[0] == SDW_SLAVE_ATTACHED) { + writel(0, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); + writel(0, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11); + } + +update_status: + sdw_handle_slave_status(&amd_manager->bus, amd_manager->status); + /* + * During the peripheral enumeration sequence, the SoundWire manager interrupts + * are masked. Once the device number programming is done for all peripherals, + * interrupts will be unmasked. Read the peripheral device status from ping command + * and process the response. This sequence will ensure all peripheral devices enumerated + * and initialized properly. + */ + if (amd_manager->status[0] == SDW_SLAVE_ATTACHED) { + if (retry_count++ < SDW_MAX_DEVICES) { + writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio + + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); + writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio + + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11); + amd_sdw_read_and_process_ping_status(amd_manager); + goto update_status; + } else { + dev_err_ratelimited(amd_manager->dev, + "Device0 detected after %d iterations\n", + retry_count); + } + } +} + +static void amd_sdw_update_slave_status(u32 status_change_0to7, u32 status_change_8to11, + struct amd_sdw_manager *amd_manager) +{ + u64 slave_stat; + u32 val; + int dev_index; + + if (status_change_0to7 == AMD_SDW_SLAVE_0_ATTACHED) + memset(amd_manager->status, 0, sizeof(amd_manager->status)); + slave_stat = status_change_0to7; + slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STATUS_8TO_11, status_change_8to11) << 32; + dev_dbg(amd_manager->dev, "status_change_0to7:0x%x status_change_8to11:0x%x\n", + status_change_0to7, status_change_8to11); + if (slave_stat) { + for (dev_index = 0; dev_index <= SDW_MAX_DEVICES; ++dev_index) { + if (slave_stat & AMD_SDW_MCP_SLAVE_STATUS_VALID_MASK(dev_index)) { + val = (slave_stat >> AMD_SDW_MCP_SLAVE_STAT_SHIFT_MASK(dev_index)) & + AMD_SDW_MCP_SLAVE_STATUS_MASK; + amd_sdw_fill_slave_status(amd_manager, dev_index, val); + } + } + } +} + +static void amd_sdw_process_wake_event(struct amd_sdw_manager *amd_manager) +{ + pm_request_resume(amd_manager->dev); + writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance)); + writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11); +} + +static void amd_sdw_irq_thread(struct work_struct *work) +{ + struct amd_sdw_manager *amd_manager = + container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread); + u32 status_change_8to11; + u32 status_change_0to7; + + status_change_8to11 = readl(amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11); + status_change_0to7 = readl(amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7); + dev_dbg(amd_manager->dev, "[SDW%d] SDW INT: 0to7=0x%x, 8to11=0x%x\n", + amd_manager->instance, status_change_0to7, status_change_8to11); + if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK) + return amd_sdw_process_wake_event(amd_manager); + + if (status_change_8to11 & AMD_SDW_PREQ_INTR_STAT) { + amd_sdw_read_and_process_ping_status(amd_manager); + } else { + /* Check for the updated status on peripheral device */ + amd_sdw_update_slave_status(status_change_0to7, status_change_8to11, amd_manager); + } + if (status_change_8to11 || status_change_0to7) + schedule_work(&amd_manager->amd_sdw_work); + writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11); + writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7); +} + +static void amd_sdw_probe_work(struct work_struct *work) +{ + struct amd_sdw_manager *amd_manager = container_of(work, struct amd_sdw_manager, + probe_work); + struct sdw_master_prop *prop; + int ret; + + prop = &amd_manager->bus.prop; + if (!prop->hw_disabled) { + amd_enable_sdw_pads(amd_manager); + ret = amd_init_sdw_manager(amd_manager); + if (ret) + return; + amd_enable_sdw_interrupts(amd_manager); + ret = amd_enable_sdw_manager(amd_manager); + if (ret) + return; + amd_sdw_set_frameshape(amd_manager); + } + /* Enable runtime PM */ + pm_runtime_set_autosuspend_delay(amd_manager->dev, AMD_SDW_MASTER_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(amd_manager->dev); + pm_runtime_mark_last_busy(amd_manager->dev); + pm_runtime_set_active(amd_manager->dev); + pm_runtime_enable(amd_manager->dev); +} + +static int amd_sdw_manager_probe(struct platform_device *pdev) +{ + const struct acp_sdw_pdata *pdata = pdev->dev.platform_data; + struct resource *res; + struct device *dev = &pdev->dev; + struct sdw_master_prop *prop; + struct sdw_bus_params *params; + struct amd_sdw_manager *amd_manager; + int ret; + + amd_manager = devm_kzalloc(dev, sizeof(struct amd_sdw_manager), GFP_KERNEL); + if (!amd_manager) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOMEM; + + amd_manager->acp_mmio = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(amd_manager->mmio)) { + dev_err(dev, "mmio not found\n"); + return PTR_ERR(amd_manager->mmio); + } + amd_manager->instance = pdata->instance; + amd_manager->mmio = amd_manager->acp_mmio + + (amd_manager->instance * SDW_MANAGER_REG_OFFSET); + amd_manager->acp_sdw_lock = pdata->acp_sdw_lock; + amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS); + amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS); + amd_manager->dev = dev; + amd_manager->bus.ops = &amd_sdw_ops; + amd_manager->bus.port_ops = &amd_sdw_port_ops; + amd_manager->bus.compute_params = &amd_sdw_compute_params; + amd_manager->bus.clk_stop_timeout = 200; + amd_manager->bus.link_id = amd_manager->instance; + + switch (amd_manager->instance) { + case ACP_SDW0: + amd_manager->num_dout_ports = AMD_SDW0_MAX_TX_PORTS; + amd_manager->num_din_ports = AMD_SDW0_MAX_RX_PORTS; + break; + case ACP_SDW1: + amd_manager->num_dout_ports = AMD_SDW1_MAX_TX_PORTS; + amd_manager->num_din_ports = AMD_SDW1_MAX_RX_PORTS; + break; + default: + return -EINVAL; + } + + amd_manager->reg_mask = &sdw_manager_reg_mask_array[amd_manager->instance]; + params = &amd_manager->bus.params; + params->max_dr_freq = AMD_SDW_DEFAULT_CLK_FREQ * 2; + params->curr_dr_freq = AMD_SDW_DEFAULT_CLK_FREQ * 2; + params->col = AMD_SDW_DEFAULT_COLUMNS; + params->row = AMD_SDW_DEFAULT_ROWS; + prop = &amd_manager->bus.prop; + prop->clk_freq = &amd_sdw_freq_tbl[0]; + prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ; + + ret = sdw_bus_master_add(&amd_manager->bus, dev, dev->fwnode); + if (ret) { + dev_err(dev, "Failed to register SoundWire manager(%d)\n", ret); + return ret; + } + ret = amd_sdw_register_dais(amd_manager); + if (ret) { + dev_err(dev, "CPU DAI registration failed\n"); + sdw_bus_master_delete(&amd_manager->bus); + return ret; + } + dev_set_drvdata(dev, amd_manager); + INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread); + INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work); + INIT_WORK(&amd_manager->probe_work, amd_sdw_probe_work); + /* + * Instead of having lengthy probe sequence, use deferred probe. + */ + schedule_work(&amd_manager->probe_work); + return 0; +} + +static int amd_sdw_manager_remove(struct platform_device *pdev) +{ + struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + cancel_work_sync(&amd_manager->probe_work); + amd_disable_sdw_interrupts(amd_manager); + sdw_bus_master_delete(&amd_manager->bus); + return amd_disable_sdw_manager(amd_manager); +} + +static int amd_sdw_clock_stop(struct amd_sdw_manager *amd_manager) +{ + u32 val; + int ret; + + ret = sdw_bus_prep_clk_stop(&amd_manager->bus); + if (ret < 0 && ret != -ENODATA) { + dev_err(amd_manager->dev, "prepare clock stop failed %d", ret); + return 0; + } + ret = sdw_bus_clk_stop(&amd_manager->bus); + if (ret < 0 && ret != -ENODATA) { + dev_err(amd_manager->dev, "bus clock stop failed %d", ret); + return 0; + } + + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val, + (val & AMD_SDW_CLK_STOP_DONE), ACP_DELAY_US, AMD_SDW_TIMEOUT); + if (ret) { + dev_err(amd_manager->dev, "SDW%x clock stop failed\n", amd_manager->instance); + return 0; + } + + amd_manager->clk_stopped = true; + if (amd_manager->wake_en_mask) + writel(0x01, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance)); + + dev_dbg(amd_manager->dev, "SDW%x clock stop successful\n", amd_manager->instance); + return 0; +} + +static int amd_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager) +{ + int ret; + u32 val; + + if (amd_manager->clk_stopped) { + val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + val |= AMD_SDW_CLK_RESUME_REQ; + writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val, + (val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US, + AMD_SDW_TIMEOUT); + if (val & AMD_SDW_CLK_RESUME_DONE) { + writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + ret = sdw_bus_exit_clk_stop(&amd_manager->bus); + if (ret < 0) + dev_err(amd_manager->dev, "bus failed to exit clock stop %d\n", + ret); + amd_manager->clk_stopped = false; + } + } + if (amd_manager->clk_stopped) { + dev_err(amd_manager->dev, "SDW%x clock stop exit failed\n", amd_manager->instance); + return 0; + } + dev_dbg(amd_manager->dev, "SDW%x clock stop exit successful\n", amd_manager->instance); + return 0; +} + +static int amd_resume_child_device(struct device *dev, void *data) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret; + + if (!slave->probed) { + dev_dbg(dev, "skipping device, no probed driver\n"); + return 0; + } + if (!slave->dev_num_sticky) { + dev_dbg(dev, "skipping device, never detected on bus\n"); + return 0; + } + ret = pm_request_resume(dev); + if (ret < 0) { + dev_err(dev, "pm_request_resume failed: %d\n", ret); + return ret; + } + return 0; +} + +static int __maybe_unused amd_pm_prepare(struct device *dev) +{ + struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev); + struct sdw_bus *bus = &amd_manager->bus; + int ret; + + if (bus->prop.hw_disabled) { + dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n", + bus->link_id); + return 0; + } + /* + * When multiple peripheral devices connected over the same link, if SoundWire manager + * device is not in runtime suspend state, observed that device alerts are missing + * without pm_prepare on AMD platforms in clockstop mode0. + */ + if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) { + ret = pm_request_resume(dev); + if (ret < 0) { + dev_err(bus->dev, "pm_request_resume failed: %d\n", ret); + return 0; + } + } + /* To force peripheral devices to system level suspend state, resume the devices + * from runtime suspend state first. Without that unable to dispatch the alert + * status to peripheral driver during system level resume as they are in runtime + * suspend state. + */ + ret = device_for_each_child(bus->dev, NULL, amd_resume_child_device); + if (ret < 0) + dev_err(dev, "amd_resume_child_device failed: %d\n", ret); + return 0; +} + +static int __maybe_unused amd_suspend(struct device *dev) +{ + struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev); + struct sdw_bus *bus = &amd_manager->bus; + int ret; + + if (bus->prop.hw_disabled) { + dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n", + bus->link_id); + return 0; + } + + if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) { + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { + /* + * As per hardware programming sequence on AMD platforms, + * clock stop should be invoked first before powering-off + */ + ret = amd_sdw_clock_stop(amd_manager); + if (ret) + return ret; + return amd_deinit_sdw_manager(amd_manager); + } + return 0; +} + +static int __maybe_unused amd_suspend_runtime(struct device *dev) +{ + struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev); + struct sdw_bus *bus = &amd_manager->bus; + int ret; + + if (bus->prop.hw_disabled) { + dev_dbg(bus->dev, "SoundWire manager %d is disabled,\n", + bus->link_id); + return 0; + } + if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) { + return amd_sdw_clock_stop(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { + ret = amd_sdw_clock_stop(amd_manager); + if (ret) + return ret; + return amd_deinit_sdw_manager(amd_manager); + } + return 0; +} + +static int __maybe_unused amd_resume_runtime(struct device *dev) +{ + struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev); + struct sdw_bus *bus = &amd_manager->bus; + int ret; + u32 val; + + if (bus->prop.hw_disabled) { + dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n", + bus->link_id); + return 0; + } + + if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) { + return amd_sdw_clock_stop_exit(amd_manager); + } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) { + val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + if (val) { + val |= AMD_SDW_CLK_RESUME_REQ; + writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val, + (val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US, + AMD_SDW_TIMEOUT); + if (val & AMD_SDW_CLK_RESUME_DONE) { + writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL); + amd_manager->clk_stopped = false; + } + } + sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); + amd_init_sdw_manager(amd_manager); + amd_enable_sdw_interrupts(amd_manager); + ret = amd_enable_sdw_manager(amd_manager); + if (ret) + return ret; + amd_sdw_set_frameshape(amd_manager); + } + return 0; +} + +static const struct dev_pm_ops amd_pm = { + .prepare = amd_pm_prepare, + SET_SYSTEM_SLEEP_PM_OPS(amd_suspend, amd_resume_runtime) + SET_RUNTIME_PM_OPS(amd_suspend_runtime, amd_resume_runtime, NULL) +}; + +static struct platform_driver amd_sdw_driver = { + .probe = &amd_sdw_manager_probe, + .remove = &amd_sdw_manager_remove, + .driver = { + .name = "amd_sdw_manager", + .pm = &amd_pm, + } +}; +module_platform_driver(amd_sdw_driver); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD SoundWire driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h new file mode 100644 index 000000000000..5f040151a259 --- /dev/null +++ b/drivers/soundwire/amd_manager.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __AMD_MANAGER_H +#define __AMD_MANAGER_H + +#include + +#define SDW_MANAGER_REG_OFFSET 0xc00 +#define AMD_SDW_DEFAULT_ROWS 50 +#define AMD_SDW_DEFAULT_COLUMNS 10 +#define ACP_PAD_PULLDOWN_CTRL 0x0001448 +#define ACP_SW_PAD_KEEPER_EN 0x0001454 +#define ACP_SW0_WAKE_EN 0x0001458 +#define ACP_EXTERNAL_INTR_CNTL0 0x0001a04 +#define ACP_EXTERNAL_INTR_STAT0 0x0001a0c +#define ACP_EXTERNAL_INTR_CNTL(i) (ACP_EXTERNAL_INTR_CNTL0 + ((i) * 4)) +#define ACP_EXTERNAL_INTR_STAT(i) (ACP_EXTERNAL_INTR_STAT0 + ((i) * 4)) +#define ACP_SW_WAKE_EN(i) (ACP_SW0_WAKE_EN + ((i) * 8)) + +#define ACP_SW_EN 0x0003000 +#define ACP_SW_EN_STATUS 0x0003004 +#define ACP_SW_FRAMESIZE 0x0003008 +#define ACP_SW_SSP_COUNTER 0x000300c +#define ACP_SW_AUDIO0_TX_EN 0x0003010 +#define ACP_SW_AUDIO0_TX_EN_STATUS 0x0003014 +#define ACP_SW_AUDIO0_TX_FRAME_FORMAT 0x0003018 +#define ACP_SW_AUDIO0_TX_SAMPLEINTERVAL 0x000301c +#define ACP_SW_AUDIO0_TX_HCTRL_DP0 0x0003020 +#define ACP_SW_AUDIO0_TX_HCTRL_DP1 0x0003024 +#define ACP_SW_AUDIO0_TX_HCTRL_DP2 0x0003028 +#define ACP_SW_AUDIO0_TX_HCTRL_DP3 0x000302c +#define ACP_SW_AUDIO0_TX_OFFSET_DP0 0x0003030 +#define ACP_SW_AUDIO0_TX_OFFSET_DP1 0x0003034 +#define ACP_SW_AUDIO0_TX_OFFSET_DP2 0x0003038 +#define ACP_SW_AUDIO0_TX_OFFSET_DP3 0x000303c +#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0 0x0003040 +#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP1 0x0003044 +#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP2 0x0003048 +#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP3 0x000304c +#define ACP_SW_AUDIO1_TX_EN 0x0003050 +#define ACP_SW_AUDIO1_TX_EN_STATUS 0x0003054 +#define ACP_SW_AUDIO1_TX_FRAME_FORMAT 0x0003058 +#define ACP_SW_AUDIO1_TX_SAMPLEINTERVAL 0x000305c +#define ACP_SW_AUDIO1_TX_HCTRL 0x0003060 +#define ACP_SW_AUDIO1_TX_OFFSET 0x0003064 +#define ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0 0x0003068 +#define ACP_SW_AUDIO2_TX_EN 0x000306c +#define ACP_SW_AUDIO2_TX_EN_STATUS 0x0003070 +#define ACP_SW_AUDIO2_TX_FRAME_FORMAT 0x0003074 +#define ACP_SW_AUDIO2_TX_SAMPLEINTERVAL 0x0003078 +#define ACP_SW_AUDIO2_TX_HCTRL 0x000307c +#define ACP_SW_AUDIO2_TX_OFFSET 0x0003080 +#define ACP_SW_AUDIO2_TX_CHANNEL_ENABLE_DP0 0x0003084 +#define ACP_SW_AUDIO0_RX_EN 0x0003088 +#define ACP_SW_AUDIO0_RX_EN_STATUS 0x000308c +#define ACP_SW_AUDIO0_RX_FRAME_FORMAT 0x0003090 +#define ACP_SW_AUDIO0_RX_SAMPLEINTERVAL 0x0003094 +#define ACP_SW_AUDIO0_RX_HCTRL_DP0 0x0003098 +#define ACP_SW_AUDIO0_RX_HCTRL_DP1 0x000309c +#define ACP_SW_AUDIO0_RX_HCTRL_DP2 0x0003100 +#define ACP_SW_AUDIO0_RX_HCTRL_DP3 0x0003104 +#define ACP_SW_AUDIO0_RX_OFFSET_DP0 0x0003108 +#define ACP_SW_AUDIO0_RX_OFFSET_DP1 0x000310c +#define ACP_SW_AUDIO0_RX_OFFSET_DP2 0x0003110 +#define ACP_SW_AUDIO0_RX_OFFSET_DP3 0x0003114 +#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP0 0x0003118 +#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP1 0x000311c +#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP2 0x0003120 +#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP3 0x0003124 +#define ACP_SW_AUDIO1_RX_EN 0x0003128 +#define ACP_SW_AUDIO1_RX_EN_STATUS 0x000312c +#define ACP_SW_AUDIO1_RX_FRAME_FORMAT 0x0003130 +#define ACP_SW_AUDIO1_RX_SAMPLEINTERVAL 0x0003134 +#define ACP_SW_AUDIO1_RX_HCTRL 0x0003138 +#define ACP_SW_AUDIO1_RX_OFFSET 0x000313c +#define ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0 0x0003140 +#define ACP_SW_AUDIO2_RX_EN 0x0003144 +#define ACP_SW_AUDIO2_RX_EN_STATUS 0x0003148 +#define ACP_SW_AUDIO2_RX_FRAME_FORMAT 0x000314c +#define ACP_SW_AUDIO2_RX_SAMPLEINTERVAL 0x0003150 +#define ACP_SW_AUDIO2_RX_HCTRL 0x0003154 +#define ACP_SW_AUDIO2_RX_OFFSET 0x0003158 +#define ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0 0x000315c +#define ACP_SW_BPT_PORT_EN 0x0003160 +#define ACP_SW_BPT_PORT_EN_STATUS 0x0003164 +#define ACP_SW_BPT_PORT_FRAME_FORMAT 0x0003168 +#define ACP_SW_BPT_PORT_SAMPLEINTERVAL 0x000316c +#define ACP_SW_BPT_PORT_HCTRL 0x0003170 +#define ACP_SW_BPT_PORT_OFFSET 0x0003174 +#define ACP_SW_BPT_PORT_CHANNEL_ENABLE 0x0003178 +#define ACP_SW_BPT_PORT_FIRST_BYTE_ADDR 0x000317c +#define ACP_SW_CLK_RESUME_CTRL 0x0003180 +#define ACP_SW_CLK_RESUME_DELAY_CNTR 0x0003184 +#define ACP_SW_BUS_RESET_CTRL 0x0003188 +#define ACP_SW_PRBS_ERR_STATUS 0x000318c +#define ACP_SW_IMM_CMD_UPPER_WORD 0x0003230 +#define ACP_SW_IMM_CMD_LOWER_QWORD 0x0003234 +#define ACP_SW_IMM_RESP_UPPER_WORD 0x0003238 +#define ACP_SW_IMM_RESP_LOWER_QWORD 0x000323c +#define ACP_SW_IMM_CMD_STS 0x0003240 +#define ACP_SW_BRA_BASE_ADDRESS 0x0003244 +#define ACP_SW_BRA_TRANSFER_SIZE 0x0003248 +#define ACP_SW_BRA_DMA_BUSY 0x000324c +#define ACP_SW_BRA_RESP 0x0003250 +#define ACP_SW_BRA_RESP_FRAME_ADDR 0x0003254 +#define ACP_SW_BRA_CURRENT_TRANSFER_SIZE 0x0003258 +#define ACP_SW_STATE_CHANGE_STATUS_0TO7 0x000325c +#define ACP_SW_STATE_CHANGE_STATUS_8TO11 0x0003260 +#define ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003264 +#define ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003268 +#define ACP_SW_CLK_FREQUENCY_CTRL 0x000326c +#define ACP_SW_ERROR_INTR_MASK 0x0003270 +#define ACP_SW_PHY_TEST_MODE_DATA_OFF 0x0003274 + +#define ACP_DELAY_US 10 +#define AMD_SDW_TIMEOUT 1000 +#define AMD_SDW_DEFAULT_CLK_FREQ 12000000 + +#define AMD_SDW_MCP_RESP_ACK BIT(0) +#define AMD_SDW_MCP_RESP_NACK BIT(1) +#define AMD_SDW_MCP_RESP_RDATA GENMASK(14, 7) + +#define AMD_SDW_MCP_CMD_SSP_TAG BIT(31) +#define AMD_SDW_MCP_CMD_COMMAND GENMASK(14, 12) +#define AMD_SDW_MCP_CMD_DEV_ADDR GENMASK(11, 8) +#define AMD_SDW_MCP_CMD_REG_ADDR_HIGH GENMASK(7, 0) +#define AMD_SDW_MCP_CMD_REG_ADDR_LOW GENMASK(31, 24) +#define AMD_SDW_MCP_CMD_REG_DATA GENMASK(14, 7) +#define AMD_SDW_MCP_SLAVE_STAT_0_3 GENMASK(14, 7) +#define AMD_SDW_MCP_SLAVE_STAT_4_11 GENMASK_ULL(39, 24) +#define AMD_SDW_MCP_SLAVE_STATUS_MASK GENMASK(1, 0) +#define AMD_SDW_MCP_SLAVE_STATUS_BITS GENMASK(3, 2) +#define AMD_SDW_MCP_SLAVE_STATUS_8TO_11 GENMASK_ULL(15, 0) +#define AMD_SDW_MCP_SLAVE_STATUS_VALID_MASK(x) BIT(((x) * 4)) +#define AMD_SDW_MCP_SLAVE_STAT_SHIFT_MASK(x) (((x) * 4) + 1) + +#define AMD_SDW_MASTER_SUSPEND_DELAY_MS 2000 +#define AMD_SDW_QUIRK_MASK_BUS_ENABLE BIT(0) + +#define AMD_SDW_IMM_RES_VALID 1 +#define AMD_SDW_IMM_CMD_BUSY 2 +#define AMD_SDW_ENABLE 1 +#define AMD_SDW_DISABLE 0 +#define AMD_SDW_BUS_RESET_CLEAR_REQ 0 +#define AMD_SDW_BUS_RESET_REQ 1 +#define AMD_SDW_BUS_RESET_DONE 2 +#define AMD_SDW_BUS_BASE_FREQ 24000000 + +#define AMD_SDW0_EXT_INTR_MASK 0x200000 +#define AMD_SDW1_EXT_INTR_MASK 4 +#define AMD_SDW_IRQ_MASK_0TO7 0x77777777 +#define AMD_SDW_IRQ_MASK_8TO11 0x000d7777 +#define AMD_SDW_IRQ_ERROR_MASK 0xff +#define AMD_SDW_MAX_FREQ_NUM 1 +#define AMD_SDW0_MAX_TX_PORTS 3 +#define AMD_SDW0_MAX_RX_PORTS 3 +#define AMD_SDW1_MAX_TX_PORTS 1 +#define AMD_SDW1_MAX_RX_PORTS 1 +#define AMD_SDW0_MAX_DAI 6 +#define AMD_SDW1_MAX_DAI 2 +#define AMD_SDW_SLAVE_0_ATTACHED 5 +#define AMD_SDW_SSP_COUNTER_VAL 3 + +#define AMD_DPN_FRAME_FMT_PFM GENMASK(1, 0) +#define AMD_DPN_FRAME_FMT_PDM GENMASK(3, 2) +#define AMD_DPN_FRAME_FMT_BLK_PKG_MODE BIT(4) +#define AMD_DPN_FRAME_FMT_BLK_GRP_CTRL GENMASK(6, 5) +#define AMD_DPN_FRAME_FMT_WORD_LEN GENMASK(12, 7) +#define AMD_DPN_FRAME_FMT_PCM_OR_PDM BIT(13) +#define AMD_DPN_HCTRL_HSTOP GENMASK(3, 0) +#define AMD_DPN_HCTRL_HSTART GENMASK(7, 4) +#define AMD_DPN_OFFSET_CTRL_1 GENMASK(7, 0) +#define AMD_DPN_OFFSET_CTRL_2 GENMASK(15, 8) +#define AMD_DPN_CH_EN_LCTRL GENMASK(2, 0) +#define AMD_DPN_CH_EN_CHMASK GENMASK(10, 3) +#define AMD_SDW_STAT_MAX_RETRY_COUNT 100 +#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f +#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa +#define AMD_SDW0_PAD_PULLDOWN_CTRL_DISABLE_MASK 0x60 +#define AMD_SDW1_PAD_PULLDOWN_CTRL_DISABLE_MASK 5 +#define AMD_SDW0_PAD_KEEPER_EN_MASK 1 +#define AMD_SDW1_PAD_KEEPER_EN_MASK 0x10 +#define AMD_SDW0_PAD_KEEPER_DISABLE_MASK 0x1e +#define AMD_SDW1_PAD_KEEPER_DISABLE_MASK 0xf +#define AMD_SDW_PREQ_INTR_STAT BIT(19) +#define AMD_SDW_CLK_STOP_DONE 1 +#define AMD_SDW_CLK_RESUME_REQ 2 +#define AMD_SDW_CLK_RESUME_DONE 3 +#define AMD_SDW_WAKE_STAT_MASK BIT(16) + +static u32 amd_sdw_freq_tbl[AMD_SDW_MAX_FREQ_NUM] = { + AMD_SDW_DEFAULT_CLK_FREQ, +}; + +struct sdw_manager_dp_reg { + u32 frame_fmt_reg; + u32 sample_int_reg; + u32 hctrl_dp0_reg; + u32 offset_reg; + u32 lane_ctrl_ch_en_reg; +}; + +/* + * SDW0 Manager instance registers 6 CPU DAI (3 TX & 3 RX Ports) + * whereas SDW1 Manager Instance registers 2 CPU DAI (one TX & one RX port) + * Below is the CPU DAI <->Manager port number mapping + * i.e SDW0 Pin0 -> port number 0 -> AUDIO0 TX + * SDW0 Pin1 -> Port number 1 -> AUDIO1 TX + * SDW0 Pin2 -> Port number 2 -> AUDIO2 TX + * SDW0 Pin3 -> port number 3 -> AUDIO0 RX + * SDW0 Pin4 -> Port number 4 -> AUDIO1 RX + * SDW0 Pin5 -> Port number 5 -> AUDIO2 RX + * Whereas for SDW1 instance + * SDW1 Pin0 -> port number 0 -> AUDIO1 TX + * SDW1 Pin1 -> Port number 1 -> AUDIO1 RX + * Same mapping should be used for programming DMA controller registers in SoundWire DMA driver. + * i.e if AUDIO0 TX channel is selected then we need to use AUDIO0 TX registers for DMA programming + * in SoundWire DMA driver. + */ + +static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = { + {ACP_SW_AUDIO0_TX_FRAME_FORMAT, ACP_SW_AUDIO0_TX_SAMPLEINTERVAL, ACP_SW_AUDIO0_TX_HCTRL_DP0, + ACP_SW_AUDIO0_TX_OFFSET_DP0, ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL, + ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO2_TX_FRAME_FORMAT, ACP_SW_AUDIO2_TX_SAMPLEINTERVAL, ACP_SW_AUDIO2_TX_HCTRL, + ACP_SW_AUDIO2_TX_OFFSET, ACP_SW_AUDIO2_TX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO0_RX_FRAME_FORMAT, ACP_SW_AUDIO0_RX_SAMPLEINTERVAL, ACP_SW_AUDIO0_RX_HCTRL_DP0, + ACP_SW_AUDIO0_RX_OFFSET_DP0, ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL, + ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO2_RX_FRAME_FORMAT, ACP_SW_AUDIO2_RX_SAMPLEINTERVAL, ACP_SW_AUDIO2_RX_HCTRL, + ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0}, +}; + +static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = { + {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL, + ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0}, + {ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL, + ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0} +}; + +static struct sdw_manager_reg_mask sdw_manager_reg_mask_array[2] = { + { + AMD_SDW0_PAD_KEEPER_EN_MASK, + AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK, + AMD_SDW0_EXT_INTR_MASK + }, + { + AMD_SDW1_PAD_KEEPER_EN_MASK, + AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK, + AMD_SDW1_EXT_INTR_MASK + } +}; +#endif diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index b6aca59c3130..1ea6a64f8c4a 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -384,45 +384,73 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, /* * Read/Write IO functions. - * no_pm versions can only be called by the bus, e.g. while enumerating or - * handling suspend-resume sequences. - * all clients need to use the pm versions */ -int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags, + size_t count, u8 *val) { struct sdw_msg msg; + size_t size; int ret; - ret = sdw_fill_msg(&msg, slave, addr, count, - slave->dev_num, SDW_MSG_FLAG_READ, val); - if (ret < 0) - return ret; + while (count) { + // Only handle bytes up to next page boundary + size = min_t(size_t, count, (SDW_REGADDR + 1) - (addr & SDW_REGADDR)); - ret = sdw_transfer(slave->bus, &msg); - if (slave->is_mockup_device) - ret = 0; - return ret; + ret = sdw_fill_msg(&msg, slave, addr, size, slave->dev_num, flags, val); + if (ret < 0) + return ret; + + ret = sdw_transfer(slave->bus, &msg); + if (ret < 0 && !slave->is_mockup_device) + return ret; + + addr += size; + val += size; + count -= size; + } + + return 0; +} + +/** + * sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM + * @slave: SDW Slave + * @addr: Register address + * @count: length + * @val: Buffer for values to be read + * + * Note that if the message crosses a page boundary each page will be + * transferred under a separate invocation of the msg_lock. + */ +int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +{ + return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val); } EXPORT_SYMBOL(sdw_nread_no_pm); +/** + * sdw_nwrite_no_pm() - Write "n" contiguous SDW Slave registers with no PM + * @slave: SDW Slave + * @addr: Register address + * @count: length + * @val: Buffer for values to be written + * + * Note that if the message crosses a page boundary each page will be + * transferred under a separate invocation of the msg_lock. + */ int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) { - struct sdw_msg msg; - int ret; - - ret = sdw_fill_msg(&msg, slave, addr, count, - slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val); - if (ret < 0) - return ret; - - ret = sdw_transfer(slave->bus, &msg); - if (slave->is_mockup_device) - ret = 0; - return ret; + return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val); } EXPORT_SYMBOL(sdw_nwrite_no_pm); +/** + * sdw_write_no_pm() - Write a SDW Slave register with no PM + * @slave: SDW Slave + * @addr: Register address + * @value: Register value + */ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) { return sdw_nwrite_no_pm(slave, addr, 1, &value); @@ -495,6 +523,11 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val } EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked); +/** + * sdw_read_no_pm() - Read a SDW Slave register with no PM + * @slave: SDW Slave + * @addr: Register address + */ int sdw_read_no_pm(struct sdw_slave *slave, u32 addr) { u8 buf; @@ -541,14 +574,21 @@ EXPORT_SYMBOL(sdw_update); * @addr: Register address * @count: length * @val: Buffer for values to be read + * + * This version of the function will take a PM reference to the slave + * device. + * Note that if the message crosses a page boundary each page will be + * transferred under a separate invocation of the msg_lock. */ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { int ret; - ret = pm_runtime_resume_and_get(&slave->dev); - if (ret < 0 && ret != -EACCES) + ret = pm_runtime_get_sync(&slave->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(&slave->dev); return ret; + } ret = sdw_nread_no_pm(slave, addr, count, val); @@ -565,14 +605,21 @@ EXPORT_SYMBOL(sdw_nread); * @addr: Register address * @count: length * @val: Buffer for values to be written + * + * This version of the function will take a PM reference to the slave + * device. + * Note that if the message crosses a page boundary each page will be + * transferred under a separate invocation of the msg_lock. */ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) { int ret; - ret = pm_runtime_resume_and_get(&slave->dev); - if (ret < 0 && ret != -EACCES) + ret = pm_runtime_get_sync(&slave->dev); + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(&slave->dev); return ret; + } ret = sdw_nwrite_no_pm(slave, addr, count, val); @@ -587,6 +634,9 @@ EXPORT_SYMBOL(sdw_nwrite); * sdw_read() - Read a SDW Slave register * @slave: SDW Slave * @addr: Register address + * + * This version of the function will take a PM reference to the slave + * device. */ int sdw_read(struct sdw_slave *slave, u32 addr) { @@ -606,6 +656,9 @@ EXPORT_SYMBOL(sdw_read); * @slave: SDW Slave * @addr: Register address * @value: Register value + * + * This version of the function will take a PM reference to the slave + * device. */ int sdw_write(struct sdw_slave *slave, u32 addr, u8 value) { @@ -1541,9 +1594,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) sdw_modify_slave_status(slave, SDW_SLAVE_ALERT); - ret = pm_runtime_resume_and_get(&slave->dev); + ret = pm_runtime_get_sync(&slave->dev); if (ret < 0 && ret != -EACCES) { dev_err(&slave->dev, "Failed to resume device: %d\n", ret); + pm_runtime_put_noidle(&slave->dev); return ret; } diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 96927a143796..fda6b24ac2da 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -144,6 +144,13 @@ struct sdw_master_runtime { struct list_head bus_node; }; +struct sdw_transport_data { + int hstart; + int hstop; + int block_offset; + int sub_block_offset; +}; + struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, enum sdw_data_direction direction, unsigned int port_num); @@ -158,17 +165,6 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg); int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf); -/* Retrieve and return channel count from channel mask */ -static inline int sdw_ch_mask_to_ch(int ch_mask) -{ - int c = 0; - - for (c = 0; ch_mask; ch_mask >>= 1) - c += ch_mask & 1; - - return c; -} - /* Fill transport parameter data structure */ static inline void sdw_fill_xport_params(struct sdw_transport_params *params, int port_num, bool grp_ctrl_valid, @@ -212,5 +208,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val void sdw_clear_slave_status(struct sdw_bus *bus, u32 request); int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); +void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, + struct sdw_transport_data *t_data); #endif /* __SDW_BUS_H */ diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index e835dabb516c..39502bc75712 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -27,32 +27,36 @@ module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444); MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_CONFIG 0x0 - -#define CDNS_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24) -#define CDNS_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16) -#define CDNS_MCP_CONFIG_MMASTER BIT(7) #define CDNS_MCP_CONFIG_BUS_REL BIT(6) -#define CDNS_MCP_CONFIG_SNIFFER BIT(5) -#define CDNS_MCP_CONFIG_SSPMOD BIT(4) -#define CDNS_MCP_CONFIG_CMD BIT(3) -#define CDNS_MCP_CONFIG_OP GENMASK(2, 0) -#define CDNS_MCP_CONFIG_OP_NORMAL 0 + +#define CDNS_IP_MCP_CONFIG 0x0 /* IP offset added at run-time */ + +#define CDNS_IP_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24) +#define CDNS_IP_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16) +#define CDNS_IP_MCP_CONFIG_MMASTER BIT(7) +#define CDNS_IP_MCP_CONFIG_SNIFFER BIT(5) +#define CDNS_IP_MCP_CONFIG_CMD BIT(3) +#define CDNS_IP_MCP_CONFIG_OP GENMASK(2, 0) +#define CDNS_IP_MCP_CONFIG_OP_NORMAL 0 #define CDNS_MCP_CONTROL 0x4 -#define CDNS_MCP_CONTROL_RST_DELAY GENMASK(10, 8) #define CDNS_MCP_CONTROL_CMD_RST BIT(7) #define CDNS_MCP_CONTROL_SOFT_RST BIT(6) -#define CDNS_MCP_CONTROL_SW_RST BIT(5) #define CDNS_MCP_CONTROL_HW_RST BIT(4) -#define CDNS_MCP_CONTROL_CLK_PAUSE BIT(3) #define CDNS_MCP_CONTROL_CLK_STOP_CLR BIT(2) -#define CDNS_MCP_CONTROL_CMD_ACCEPT BIT(1) -#define CDNS_MCP_CONTROL_BLOCK_WAKEUP BIT(0) -#define CDNS_MCP_CMDCTRL 0x8 +#define CDNS_IP_MCP_CONTROL 0x4 /* IP offset added at run-time */ -#define CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2) +#define CDNS_IP_MCP_CONTROL_RST_DELAY GENMASK(10, 8) +#define CDNS_IP_MCP_CONTROL_SW_RST BIT(5) +#define CDNS_IP_MCP_CONTROL_CLK_PAUSE BIT(3) +#define CDNS_IP_MCP_CONTROL_CMD_ACCEPT BIT(1) +#define CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP BIT(0) + +#define CDNS_IP_MCP_CMDCTRL 0x8 /* IP offset added at run-time */ + +#define CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2) #define CDNS_MCP_SSPSTAT 0xC #define CDNS_MCP_FRAME_SHAPE 0x10 @@ -125,8 +129,8 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_FIFOSTAT 0x7C #define CDNS_MCP_RX_FIFO_AVAIL GENMASK(5, 0) -#define CDNS_MCP_CMD_BASE 0x80 -#define CDNS_MCP_RESP_BASE 0x80 +#define CDNS_IP_MCP_CMD_BASE 0x80 /* IP offset added at run-time */ +#define CDNS_IP_MCP_RESP_BASE 0x80 /* IP offset added at run-time */ /* FIFO can hold 8 commands */ #define CDNS_MCP_CMD_LEN 8 #define CDNS_MCP_CMD_WORD_LEN 0x4 @@ -206,6 +210,16 @@ static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value) writel(value, cdns->registers + offset); } +static inline u32 cdns_ip_readl(struct sdw_cdns *cdns, int offset) +{ + return cdns_readl(cdns, cdns->ip_offset + offset); +} + +static inline void cdns_ip_writel(struct sdw_cdns *cdns, int offset, u32 value) +{ + return cdns_writel(cdns, cdns->ip_offset + offset, value); +} + static inline void cdns_updatel(struct sdw_cdns *cdns, int offset, u32 mask, u32 val) { @@ -216,6 +230,12 @@ static inline void cdns_updatel(struct sdw_cdns *cdns, cdns_writel(cdns, offset, tmp); } +static inline void cdns_ip_updatel(struct sdw_cdns *cdns, + int offset, u32 mask, u32 val) +{ + cdns_updatel(cdns, cdns->ip_offset + offset, mask, val); +} + static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value) { int timeout = 10; @@ -408,9 +428,9 @@ static int cdns_parity_error_injection(void *data, u64 value) mutex_lock(&bus->bus_lock); /* program hardware to inject parity error */ - cdns_updatel(cdns, CDNS_MCP_CMDCTRL, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR); /* commit changes */ cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE, @@ -422,9 +442,9 @@ static int cdns_parity_error_injection(void *data, u64 value) dev_info(cdns->dev, "parity error injection, read: %d\n", ret); /* program hardware to disable parity error */ - cdns_updatel(cdns, CDNS_MCP_CMDCTRL, - CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR, - 0); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL, + CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR, + 0); /* commit changes */ cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE, @@ -570,10 +590,10 @@ static void cdns_read_response(struct sdw_cdns *cdns) num_resp = ARRAY_SIZE(cdns->response_buf); } - cmd_base = CDNS_MCP_CMD_BASE; + cmd_base = CDNS_IP_MCP_CMD_BASE; for (i = 0; i < num_resp; i++) { - cdns->response_buf[i] = cdns_readl(cdns, cmd_base); + cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base); cmd_base += CDNS_MCP_CMD_WORD_LEN; } } @@ -592,7 +612,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, cdns->msg_count = count; } - base = CDNS_MCP_CMD_BASE; + base = CDNS_IP_MCP_CMD_BASE; addr = msg->addr + offset; for (i = 0; i < count; i++) { @@ -605,7 +625,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, data |= msg->buf[i + offset]; data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync); - cdns_writel(cdns, base, data); + cdns_ip_writel(cdns, base, data); base += CDNS_MCP_CMD_WORD_LEN; } @@ -653,10 +673,10 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg) data[0] |= msg->addr_page1; data[1] |= msg->addr_page2; - base = CDNS_MCP_CMD_BASE; - cdns_writel(cdns, base, data[0]); + base = CDNS_IP_MCP_CMD_BASE; + cdns_ip_writel(cdns, base, data[0]); base += CDNS_MCP_CMD_WORD_LEN; - cdns_writel(cdns, base, data[1]); + cdns_ip_writel(cdns, base, data[1]); time = wait_for_completion_timeout(&cdns->tx_complete, msecs_to_jiffies(CDNS_TX_TIMEOUT)); @@ -1033,6 +1053,7 @@ update_status: void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, bool initial_delay, int reset_iterations) { + u32 ip_mcp_control; u32 mcp_control; u32 mcp_config_update; int i; @@ -1040,6 +1061,12 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string if (initial_delay) usleep_range(1000, 1500); + ip_mcp_control = cdns_ip_readl(cdns, CDNS_IP_MCP_CONTROL); + + /* the following bits should be cleared immediately */ + if (ip_mcp_control & CDNS_IP_MCP_CONTROL_SW_RST) + dev_err(cdns->dev, "%s failed: IP_MCP_CONTROL_SW_RST is not cleared\n", string); + mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL); /* the following bits should be cleared immediately */ @@ -1047,10 +1074,9 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string); if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST) dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string); - if (mcp_control & CDNS_MCP_CONTROL_SW_RST) - dev_err(cdns->dev, "%s failed: MCP_CONTROL_SW_RST is not cleared\n", string); if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR) dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string); + mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE); if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT) dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string); @@ -1327,34 +1353,39 @@ int sdw_cdns_init(struct sdw_cdns *cdns) CDNS_MCP_CONTROL_CMD_RST); /* Set cmd accept mode */ - cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, - CDNS_MCP_CONTROL_CMD_ACCEPT); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, + CDNS_IP_MCP_CONTROL_CMD_ACCEPT); /* Configure mcp config */ val = cdns_readl(cdns, CDNS_MCP_CONFIG); - /* enable bus operations with clock and data */ - val &= ~CDNS_MCP_CONFIG_OP; - val |= CDNS_MCP_CONFIG_OP_NORMAL; - - /* Set cmd mode for Tx and Rx cmds */ - val &= ~CDNS_MCP_CONFIG_CMD; - - /* Disable sniffer mode */ - val &= ~CDNS_MCP_CONFIG_SNIFFER; - /* Disable auto bus release */ val &= ~CDNS_MCP_CONFIG_BUS_REL; + cdns_writel(cdns, CDNS_MCP_CONFIG, val); + + /* Configure IP mcp config */ + val = cdns_ip_readl(cdns, CDNS_IP_MCP_CONFIG); + + /* enable bus operations with clock and data */ + val &= ~CDNS_IP_MCP_CONFIG_OP; + val |= CDNS_IP_MCP_CONFIG_OP_NORMAL; + + /* Set cmd mode for Tx and Rx cmds */ + val &= ~CDNS_IP_MCP_CONFIG_CMD; + + /* Disable sniffer mode */ + val &= ~CDNS_IP_MCP_CONFIG_SNIFFER; + if (cdns->bus.multi_link) /* Set Multi-master mode to take gsync into account */ - val |= CDNS_MCP_CONFIG_MMASTER; + val |= CDNS_IP_MCP_CONFIG_MMASTER; /* leave frame delay to hardware default of 0x1F */ /* leave command retry to hardware default of 0 */ - cdns_writel(cdns, CDNS_MCP_CONFIG, val); + cdns_ip_writel(cdns, CDNS_IP_MCP_CONFIG, val); /* changes will be committed later */ return 0; @@ -1584,9 +1615,9 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) * in clock stop state */ if (block_wake) - cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_BLOCK_WAKEUP, - CDNS_MCP_CONTROL_BLOCK_WAKEUP); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP); list_for_each_entry(slave, &cdns->bus.slaves, node) { if (slave->status == SDW_SLAVE_ATTACHED || @@ -1659,18 +1690,18 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) return ret; } - cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, 0); - cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, - CDNS_MCP_CONTROL_CMD_ACCEPT); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, + CDNS_IP_MCP_CONTROL_CMD_ACCEPT); if (!bus_reset) { /* enable bus operations with clock and data */ - cdns_updatel(cdns, CDNS_MCP_CONFIG, - CDNS_MCP_CONFIG_OP, - CDNS_MCP_CONFIG_OP_NORMAL); + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONFIG, + CDNS_IP_MCP_CONFIG_OP, + CDNS_IP_MCP_CONFIG_OP_NORMAL); ret = cdns_config_update(cdns); if (ret < 0) { diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index dec0b4f993c1..27c56274217f 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -84,7 +84,6 @@ struct sdw_cdns_stream_config { * @bus: Bus handle * @stream_type: Stream type * @link_id: Master link id - * @hw_params: hw_params to be applied in .prepare step * @suspended: status set when suspended, to be used in .prepare * @paused: status set in .trigger, to be used in suspend * @direction: stream direction @@ -96,7 +95,6 @@ struct sdw_cdns_dai_runtime { struct sdw_bus *bus; enum sdw_stream_type stream_type; int link_id; - struct snd_pcm_hw_params *hw_params; bool suspended; bool paused; int direction; @@ -107,6 +105,7 @@ struct sdw_cdns_dai_runtime { * @dev: Linux device * @bus: Bus handle * @instance: instance number + * @ip_offset: version-dependent offset to access IP_MCP registers and fields * @response_buf: SoundWire response buffer * @tx_complete: Tx completion * @ports: Data ports @@ -122,6 +121,8 @@ struct sdw_cdns { struct sdw_bus bus; unsigned int instance; + u32 ip_offset; + /* * The datasheet says the RX FIFO AVAIL can be 2 entries more * than the FIFO capacity, so allow for this. diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 7969881f126d..58ea013fa918 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -73,6 +73,23 @@ static const struct adr_remap hp_omen_16[] = { {} }; +/* + * Intel NUC M15 LAPRC510 and LAPRC710 + */ +static const struct adr_remap intel_rooks_county[] = { + /* rt711-sdca on link0 */ + { + 0x000020025d071100ull, + 0x000030025d071101ull + }, + /* rt1316-sdca on link2 */ + { + 0x000120025d071100ull, + 0x000230025d131601ull + }, + {} +}; + static const struct dmi_system_id adr_remap_quirk_table[] = { /* TGL devices */ { @@ -98,6 +115,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { }, .driver_data = (void *)intel_tgl_bios, }, + { + /* quirk used for NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), + }, + .driver_data = (void *)intel_rooks_county, + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index f7c66083a4dd..325c475b6a66 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -28,15 +29,8 @@ struct sdw_group { unsigned int *rates; }; -struct sdw_transport_data { - int hstart; - int hstop; - int block_offset; - int sub_block_offset; -}; - -static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, - struct sdw_transport_data *t_data) +void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, + struct sdw_transport_data *t_data) { struct sdw_slave_runtime *s_rt = NULL; struct sdw_port_runtime *p_rt; @@ -54,7 +48,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, slave_total_ch = 0; list_for_each_entry(p_rt, &s_rt->port_list, port_node) { - ch = sdw_ch_mask_to_ch(p_rt->ch_mask); + ch = hweight32(p_rt->ch_mask); sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false, @@ -85,6 +79,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, } } } +EXPORT_SYMBOL(sdw_compute_slave_ports); static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, struct sdw_group_params *params, diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 2651767272c7..238acf5c97a9 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -19,38 +19,6 @@ #include "bus.h" #include "intel.h" - -enum intel_pdi_type { - INTEL_PDI_IN = 0, - INTEL_PDI_OUT = 1, - INTEL_PDI_BD = 2, -}; - -#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns) - -/* - * Read, write helpers for HW registers - */ -static inline int intel_readl(void __iomem *base, int offset) -{ - return readl(base + offset); -} - -static inline void intel_writel(void __iomem *base, int offset, int value) -{ - writel(value, base + offset); -} - -static inline u16 intel_readw(void __iomem *base, int offset) -{ - return readw(base + offset); -} - -static inline void intel_writew(void __iomem *base, int offset, u16 value) -{ - writew(value, base + offset); -} - static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target) { int timeout = 10; @@ -357,6 +325,15 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) mutex_unlock(sdw->link_res->shim_lock); } +static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw) +{ + void __iomem *shim = sdw->link_res->shim; + int sync_reg; + + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + return !!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK); +} + static int intel_link_power_up(struct sdw_intel *sdw) { unsigned int link_id = sdw->instance; @@ -507,7 +484,6 @@ static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw) { void __iomem *shim = sdw->link_res->shim; u32 sync_reg; - int ret; /* Read SYNC register */ sync_reg = intel_readl(shim, SDW_SHIM_SYNC); @@ -519,13 +495,9 @@ static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw) */ sync_reg |= SDW_SHIM_SYNC_SYNCGO; - ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, - SDW_SHIM_SYNC_SYNCGO); + intel_writel(shim, SDW_SHIM_SYNC, sync_reg); - if (ret < 0) - dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret); - - return ret; + return 0; } static int intel_shim_sync_go(struct sdw_intel *sdw) @@ -618,13 +590,6 @@ static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, return 0; } -static int intel_pdi_ch_update(struct sdw_intel *sdw) -{ - intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm); - - return 0; -} - static void intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) { @@ -717,63 +682,6 @@ static int intel_free_stream(struct sdw_intel *sdw, return 0; } -/* - * bank switch routines - */ - -static int intel_pre_bank_switch(struct sdw_intel *sdw) -{ - struct sdw_cdns *cdns = &sdw->cdns; - struct sdw_bus *bus = &cdns->bus; - - /* Write to register only for multi-link */ - if (!bus->multi_link) - return 0; - - intel_shim_sync_arm(sdw); - - return 0; -} - -static int intel_post_bank_switch(struct sdw_intel *sdw) -{ - struct sdw_cdns *cdns = &sdw->cdns; - struct sdw_bus *bus = &cdns->bus; - void __iomem *shim = sdw->link_res->shim; - int sync_reg, ret; - - /* Write to register only for multi-link */ - if (!bus->multi_link) - return 0; - - mutex_lock(sdw->link_res->shim_lock); - - /* Read SYNC register */ - sync_reg = intel_readl(shim, SDW_SHIM_SYNC); - - /* - * post_bank_switch() ops is called from the bus in loop for - * all the Masters in the steam with the expectation that - * we trigger the bankswitch for the only first Master in the list - * and do nothing for the other Masters - * - * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. - */ - if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) { - ret = 0; - goto unlock; - } - - ret = intel_shim_sync_go_unlocked(sdw); -unlock: - mutex_unlock(sdw->link_res->shim_lock); - - if (ret < 0) - dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret); - - return ret; -} - /* * DAI routines */ @@ -817,7 +725,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, dai_runtime->paused = false; dai_runtime->suspended = false; dai_runtime->pdi = pdi; - dai_runtime->hw_params = params; /* Inform DSP about PDI stream number */ ret = intel_params_stream(sdw, substream->stream, dai, params, @@ -870,6 +777,11 @@ static int intel_prepare(struct snd_pcm_substream *substream, } if (dai_runtime->suspended) { + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_hw_params *hw_params; + + hw_params = &rtd->dpcm[substream->stream].hw_params; + dai_runtime->suspended = false; /* @@ -881,7 +793,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, */ /* configure stream */ - ch = params_channels(dai_runtime->hw_params); + ch = params_channels(hw_params); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) dir = SDW_DATA_DIR_RX; else @@ -893,7 +805,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, /* Inform DSP about PDI stream number */ ret = intel_params_stream(sdw, substream->stream, dai, - dai_runtime->hw_params, + hw_params, sdw->instance, dai_runtime->pdi->intel_alh_id); } @@ -932,7 +844,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) return ret; } - dai_runtime->hw_params = NULL; dai_runtime->pdi = NULL; return 0; @@ -1088,7 +999,6 @@ static int intel_create_dai(struct sdw_cdns *cdns, if (num == 0) return 0; - /* TODO: Read supported rates/formats from hardware */ for (i = off; i < (off + num); i++) { dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL, "SDW%d Pin%d", @@ -1099,15 +1009,11 @@ static int intel_create_dai(struct sdw_cdns *cdns, if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) { dais[i].playback.channels_min = 1; dais[i].playback.channels_max = max_ch; - dais[i].playback.rates = SNDRV_PCM_RATE_48000; - dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE; } if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) { dais[i].capture.channels_min = 1; dais[i].capture.channels_max = max_ch; - dais[i].capture.rates = SNDRV_PCM_RATE_48000; - dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; } dais[i].ops = &intel_pcm_dai_ops; @@ -1131,7 +1037,7 @@ static int intel_register_dai(struct sdw_intel *sdw) if (ret) return ret; - intel_pdi_ch_update(sdw); + intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm); /* DAIs are created based on total number of PDIs supported */ num_dai = cdns->pcm.num_pdi; @@ -1171,205 +1077,6 @@ static int intel_register_dai(struct sdw_intel *sdw) dais, num_dai); } -static int intel_start_bus(struct sdw_intel *sdw) -{ - struct device *dev = sdw->cdns.dev; - struct sdw_cdns *cdns = &sdw->cdns; - struct sdw_bus *bus = &cdns->bus; - int ret; - - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); - return ret; - } - - /* - * follow recommended programming flows to avoid timeouts when - * gsync is enabled - */ - if (bus->multi_link) - intel_shim_sync_arm(sdw); - - ret = sdw_cdns_init(cdns); - if (ret < 0) { - dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret); - goto err_interrupt; - } - - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); - goto err_interrupt; - } - - if (bus->multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(dev, "%s: sync go failed: %d\n", __func__, ret); - goto err_interrupt; - } - } - sdw_cdns_check_self_clearing_bits(cdns, __func__, - true, INTEL_MASTER_RESET_ITERATIONS); - - return 0; - -err_interrupt: - sdw_cdns_enable_interrupt(cdns, false); - return ret; -} - -static int intel_start_bus_after_reset(struct sdw_intel *sdw) -{ - struct device *dev = sdw->cdns.dev; - struct sdw_cdns *cdns = &sdw->cdns; - struct sdw_bus *bus = &cdns->bus; - bool clock_stop0; - int status; - int ret; - - /* - * An exception condition occurs for the CLK_STOP_BUS_RESET - * case if one or more masters remain active. In this condition, - * all the masters are powered on for they are in the same power - * domain. Master can preserve its context for clock stop0, so - * there is no need to clear slave status and reset bus. - */ - clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); - - if (!clock_stop0) { - - /* - * make sure all Slaves are tagged as UNATTACHED and - * provide reason for reinitialization - */ - - status = SDW_UNATTACH_REQUEST_MASTER_RESET; - sdw_clear_slave_status(bus, status); - - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); - return ret; - } - - /* - * follow recommended programming flows to avoid - * timeouts when gsync is enabled - */ - if (bus->multi_link) - intel_shim_sync_arm(sdw); - - /* - * Re-initialize the IP since it was powered-off - */ - sdw_cdns_init(&sdw->cdns); - - } else { - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); - return ret; - } - } - - ret = sdw_cdns_clock_restart(cdns, !clock_stop0); - if (ret < 0) { - dev_err(dev, "unable to restart clock during resume\n"); - goto err_interrupt; - } - - if (!clock_stop0) { - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); - goto err_interrupt; - } - - if (bus->multi_link) { - ret = intel_shim_sync_go(sdw); - if (ret < 0) { - dev_err(sdw->cdns.dev, "sync go failed during resume\n"); - goto err_interrupt; - } - } - } - sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); - - return 0; - -err_interrupt: - sdw_cdns_enable_interrupt(cdns, false); - return ret; -} - -static void intel_check_clock_stop(struct sdw_intel *sdw) -{ - struct device *dev = sdw->cdns.dev; - bool clock_stop0; - - clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); - if (!clock_stop0) - dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__); -} - -static int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) -{ - struct device *dev = sdw->cdns.dev; - struct sdw_cdns *cdns = &sdw->cdns; - int ret; - - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); - return ret; - } - - ret = sdw_cdns_clock_restart(cdns, false); - if (ret < 0) { - dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret); - sdw_cdns_enable_interrupt(cdns, false); - return ret; - } - - sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks", - true, INTEL_MASTER_RESET_ITERATIONS); - - return 0; -} - -static int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) -{ - struct device *dev = sdw->cdns.dev; - struct sdw_cdns *cdns = &sdw->cdns; - bool wake_enable = false; - int ret; - - if (clock_stop) { - ret = sdw_cdns_clock_stop(cdns, true); - if (ret < 0) - dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret); - else - wake_enable = true; - } - - ret = sdw_cdns_enable_interrupt(cdns, false); - if (ret < 0) { - dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret); - return ret; - } - - ret = intel_link_power_down(sdw); - if (ret) { - dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret); - return ret; - } - - intel_shim_wake(sdw, wake_enable); - - return 0; -} const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { .debugfs_init = intel_debugfs_init, @@ -1391,6 +1098,11 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { .pre_bank_switch = intel_pre_bank_switch, .post_bank_switch = intel_post_bank_switch, + + .sync_arm = intel_shim_sync_arm, + .sync_go_unlocked = intel_shim_sync_go_unlocked, + .sync_go = intel_shim_sync_go, + .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked, }; EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL); diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index de9883313c8f..09d479f2c77b 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -50,6 +50,35 @@ struct sdw_intel { #endif }; +enum intel_pdi_type { + INTEL_PDI_IN = 0, + INTEL_PDI_OUT = 1, + INTEL_PDI_BD = 2, +}; + +/* + * Read, write helpers for HW registers + */ +static inline int intel_readl(void __iomem *base, int offset) +{ + return readl(base + offset); +} + +static inline void intel_writel(void __iomem *base, int offset, int value) +{ + writel(value, base + offset); +} + +static inline u16 intel_readw(void __iomem *base, int offset) +{ + return readw(base + offset); +} + +static inline void intel_writew(void __iomem *base, int offset, u16 value) +{ + writew(value, base + offset); +} + #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns) #define INTEL_MASTER_RESET_ITERATIONS 10 @@ -138,4 +167,42 @@ static inline void sdw_intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) SDW_INTEL_OPS(sdw, shim_wake)(sdw, wake_enable); } +static inline void sdw_intel_sync_arm(struct sdw_intel *sdw) +{ + if (SDW_INTEL_CHECK_OPS(sdw, sync_arm)) + SDW_INTEL_OPS(sdw, sync_arm)(sdw); +} + +static inline int sdw_intel_sync_go_unlocked(struct sdw_intel *sdw) +{ + if (SDW_INTEL_CHECK_OPS(sdw, sync_go_unlocked)) + return SDW_INTEL_OPS(sdw, sync_go_unlocked)(sdw); + return -ENOTSUPP; +} + +static inline int sdw_intel_sync_go(struct sdw_intel *sdw) +{ + if (SDW_INTEL_CHECK_OPS(sdw, sync_go)) + return SDW_INTEL_OPS(sdw, sync_go)(sdw); + return -ENOTSUPP; +} + +static inline bool sdw_intel_sync_check_cmdsync_unlocked(struct sdw_intel *sdw) +{ + if (SDW_INTEL_CHECK_OPS(sdw, sync_check_cmdsync_unlocked)) + return SDW_INTEL_OPS(sdw, sync_check_cmdsync_unlocked)(sdw); + return false; +} + +/* common bus management */ +int intel_start_bus(struct sdw_intel *sdw); +int intel_start_bus_after_reset(struct sdw_intel *sdw); +void intel_check_clock_stop(struct sdw_intel *sdw); +int intel_start_bus_after_clock_stop(struct sdw_intel *sdw); +int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop); + +/* common bank switch routines */ +int intel_pre_bank_switch(struct sdw_intel *sdw); +int intel_post_bank_switch(struct sdw_intel *sdw); + #endif /* __SDW_INTEL_LOCAL_H */ diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 5021be0f4158..b21e86084f7b 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -358,10 +358,12 @@ static int intel_resume_child_device(struct device *dev, void *data) } ret = pm_request_resume(dev); - if (ret < 0) + if (ret < 0) { dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); + return ret; + } - return ret; + return 0; } static int __maybe_unused intel_pm_prepare(struct device *dev) diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c new file mode 100644 index 000000000000..f180e3bea989 --- /dev/null +++ b/drivers/soundwire/intel_bus_common.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// Copyright(c) 2015-2023 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include "cadence_master.h" +#include "bus.h" +#include "intel.h" + +int intel_start_bus(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + int ret; + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); + return ret; + } + + /* + * follow recommended programming flows to avoid timeouts when + * gsync is enabled + */ + if (bus->multi_link) + sdw_intel_sync_arm(sdw); + + ret = sdw_cdns_init(cdns); + if (ret < 0) { + dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret); + goto err_interrupt; + } + + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); + goto err_interrupt; + } + + if (bus->multi_link) { + ret = sdw_intel_sync_go(sdw); + if (ret < 0) { + dev_err(dev, "%s: sync go failed: %d\n", __func__, ret); + goto err_interrupt; + } + } + sdw_cdns_check_self_clearing_bits(cdns, __func__, + true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; + +err_interrupt: + sdw_cdns_enable_interrupt(cdns, false); + return ret; +} + +int intel_start_bus_after_reset(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + bool clock_stop0; + int status; + int ret; + + /* + * An exception condition occurs for the CLK_STOP_BUS_RESET + * case if one or more masters remain active. In this condition, + * all the masters are powered on for they are in the same power + * domain. Master can preserve its context for clock stop0, so + * there is no need to clear slave status and reset bus. + */ + clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); + + if (!clock_stop0) { + + /* + * make sure all Slaves are tagged as UNATTACHED and + * provide reason for reinitialization + */ + + status = SDW_UNATTACH_REQUEST_MASTER_RESET; + sdw_clear_slave_status(bus, status); + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + /* + * follow recommended programming flows to avoid + * timeouts when gsync is enabled + */ + if (bus->multi_link) + sdw_intel_sync_arm(sdw); + + /* + * Re-initialize the IP since it was powered-off + */ + sdw_cdns_init(&sdw->cdns); + + } else { + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + } + + ret = sdw_cdns_clock_restart(cdns, !clock_stop0); + if (ret < 0) { + dev_err(dev, "unable to restart clock during resume\n"); + goto err_interrupt; + } + + if (!clock_stop0) { + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "unable to exit bus reset sequence during resume\n"); + goto err_interrupt; + } + + if (bus->multi_link) { + ret = sdw_intel_sync_go(sdw); + if (ret < 0) { + dev_err(sdw->cdns.dev, "sync go failed during resume\n"); + goto err_interrupt; + } + } + } + sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; + +err_interrupt: + sdw_cdns_enable_interrupt(cdns, false); + return ret; +} + +void intel_check_clock_stop(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + bool clock_stop0; + + clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); + if (!clock_stop0) + dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__); +} + +int intel_start_bus_after_clock_stop(struct sdw_intel *sdw) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + int ret; + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret); + return ret; + } + + ret = sdw_cdns_clock_restart(cdns, false); + if (ret < 0) { + dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret); + sdw_cdns_enable_interrupt(cdns, false); + return ret; + } + + sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks", + true, INTEL_MASTER_RESET_ITERATIONS); + + return 0; +} + +int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) +{ + struct device *dev = sdw->cdns.dev; + struct sdw_cdns *cdns = &sdw->cdns; + bool wake_enable = false; + int ret; + + if (clock_stop) { + ret = sdw_cdns_clock_stop(cdns, true); + if (ret < 0) + dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret); + else + wake_enable = true; + } + + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret); + return ret; + } + + ret = sdw_intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret); + return ret; + } + + sdw_intel_shim_wake(sdw, wake_enable); + + return 0; +} + +/* + * bank switch routines + */ + +int intel_pre_bank_switch(struct sdw_intel *sdw) +{ + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + + /* Write to register only for multi-link */ + if (!bus->multi_link) + return 0; + + sdw_intel_sync_arm(sdw); + + return 0; +} + +int intel_post_bank_switch(struct sdw_intel *sdw) +{ + struct sdw_cdns *cdns = &sdw->cdns; + struct sdw_bus *bus = &cdns->bus; + int ret = 0; + + /* Write to register only for multi-link */ + if (!bus->multi_link) + return 0; + + mutex_lock(sdw->link_res->shim_lock); + + /* + * post_bank_switch() ops is called from the bus in loop for + * all the Masters in the steam with the expectation that + * we trigger the bankswitch for the only first Master in the list + * and do nothing for the other Masters + * + * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. + */ + if (sdw_intel_sync_check_cmdsync_unlocked(sdw)) + ret = sdw_intel_sync_go_unlocked(sdw); + + mutex_unlock(sdw->link_res->shim_lock); + + if (ret < 0) + dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret); + + return ret; +} diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 335424870290..c296e0bf897b 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -28,6 +28,9 @@ #define SWRM_LINK_MANAGER_EE 0x018 #define SWRM_EE_CPU 1 #define SWRM_FRM_GEN_ENABLED BIT(0) +#define SWRM_VERSION_1_3_0 0x01030000 +#define SWRM_VERSION_1_5_1 0x01050001 +#define SWRM_VERSION_1_7_0 0x01070000 #define SWRM_COMP_HW_VERSION 0x00 #define SWRM_COMP_CFG_ADDR 0x04 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) @@ -351,8 +354,7 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, /* Its assumed that write is okay as we do not get any status back */ swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); - /* version 1.3 or less */ - if (swrm->version <= 0x01030000) + if (swrm->version <= SWRM_VERSION_1_3_0) usleep_range(150, 155); if (cmd_id == SWR_BROADCAST_CMD_ID) { @@ -695,7 +697,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); - if (ctrl->version >= 0x01070000) { + if (ctrl->version >= SWRM_VERSION_1_7_0) { ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU); ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU); @@ -704,8 +706,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) } /* Configure number of retries of a read/write cmd */ - if (ctrl->version > 0x01050001) { - /* Only for versions >= 1.5.1 */ + if (ctrl->version >= SWRM_VERSION_1_5_1) { ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES | SWRM_CONTINUE_EXEC_ON_CMD_IGNORE); @@ -1217,6 +1218,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ctrl->num_dout_ports = val; nports = ctrl->num_dout_ports + ctrl->num_din_ports; + if (nports > QCOM_SDW_MAX_PORTS) + return -EINVAL; + /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ set_bit(0, &ctrl->dout_port_mask); set_bit(0, &ctrl->din_port_mask); @@ -1239,7 +1243,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", bp_mode, nports); if (ret) { - if (ctrl->version <= 0x01030000) + if (ctrl->version <= SWRM_VERSION_1_3_0) memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); else return ret; @@ -1442,7 +1446,7 @@ static int qcom_swrm_probe(struct platform_device *pdev) pm_runtime_enable(dev); /* Clk stop is not supported on WSA Soundwire masters */ - if (ctrl->version <= 0x01030000) { + if (ctrl->version <= SWRM_VERSION_1_3_0) { ctrl->clock_stop_not_supported = true; } else { ctrl->reg_read(ctrl, SWRM_COMP_MASTER_ID, &val); @@ -1527,7 +1531,7 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev) } else { reset_control_reset(ctrl->audio_cgcr); - if (ctrl->version >= 0x01070000) { + if (ctrl->version >= SWRM_VERSION_1_7_0) { ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU); ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU); diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 8c6da1739e3d..c2191c07442b 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1369,7 +1369,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, if (ret < 0) { dev_err(bus->dev, "Compute params failed: %d\n", ret); - return ret; + goto restore_params; } } @@ -1389,7 +1389,7 @@ program_params: ret = do_bank_switch(stream); if (ret < 0) { - dev_err(bus->dev, "Bank switch failed: %d\n", ret); + pr_err("%s: do_bank_switch failed: %d\n", __func__, ret); goto restore_params; } @@ -1477,7 +1477,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream) /* Program params */ ret = sdw_program_params(bus, false); if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d\n", ret); + dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret); return ret; } @@ -1497,7 +1497,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream) ret = do_bank_switch(stream); if (ret < 0) { - dev_err(bus->dev, "Bank switch failed: %d\n", ret); + pr_err("%s: do_bank_switch failed: %d\n", __func__, ret); return ret; } @@ -1567,14 +1567,14 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream) /* Program params */ ret = sdw_program_params(bus, false); if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d\n", ret); + dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret); return ret; } } ret = do_bank_switch(stream); if (ret < 0) { - pr_err("Bank switch failed: %d\n", ret); + pr_err("%s: do_bank_switch failed: %d\n", __func__, ret); return ret; } @@ -1664,7 +1664,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) /* Program params */ ret = sdw_program_params(bus, false); if (ret < 0) { - dev_err(bus->dev, "Program params failed: %d\n", ret); + dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret); return ret; } } @@ -1893,7 +1893,8 @@ int sdw_stream_add_master(struct sdw_bus *bus, m_rt = sdw_master_rt_alloc(bus, stream); if (!m_rt) { - dev_err(bus->dev, "Master runtime alloc failed for stream:%s\n", stream->name); + dev_err(bus->dev, "%s: Master runtime alloc failed for stream:%s\n", + __func__, stream->name); ret = -ENOMEM; goto unlock; } @@ -2012,7 +2013,8 @@ int sdw_stream_add_slave(struct sdw_slave *slave, */ m_rt = sdw_master_rt_alloc(slave->bus, stream); if (!m_rt) { - dev_err(&slave->dev, "Master runtime alloc failed for stream:%s\n", stream->name); + dev_err(&slave->dev, "%s: Master runtime alloc failed for stream:%s\n", + __func__, stream->name); ret = -ENOMEM; goto unlock; } diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index ac85d5562212..26e663369319 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -301,49 +302,43 @@ static int cdns_spi_setup_transfer(struct spi_device *spi, } /** - * cdns_spi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible + * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO * @xspi: Pointer to the cdns_spi structure + * @ntx: Number of bytes to pack into the TX FIFO + * @nrx: Number of bytes to drain from the RX FIFO */ -static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) +static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) { - unsigned long trans_cnt = 0; + ntx = clamp(ntx, 0, xspi->tx_bytes); + nrx = clamp(nrx, 0, xspi->rx_bytes); - while ((trans_cnt < xspi->tx_fifo_depth) && - (xspi->tx_bytes > 0)) { + xspi->tx_bytes -= ntx; + xspi->rx_bytes -= nrx; + while (ntx || nrx) { /* When xspi in busy condition, bytes may send failed, * then spi control did't work thoroughly, add one byte delay */ - if (cdns_spi_read(xspi, CDNS_SPI_ISR) & - CDNS_SPI_IXR_TXFULL) + if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) udelay(10); - if (xspi->txbuf) - cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); - else - cdns_spi_write(xspi, CDNS_SPI_TXD, 0); + if (ntx) { + if (xspi->txbuf) + cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); + else + cdns_spi_write(xspi, CDNS_SPI_TXD, 0); - xspi->tx_bytes--; - trans_cnt++; - } -} + ntx--; + } -/** - * cdns_spi_read_rx_fifo - Reads the RX FIFO with as many bytes as possible - * @xspi: Pointer to the cdns_spi structure - * @count: Read byte count - */ -static void cdns_spi_read_rx_fifo(struct cdns_spi *xspi, unsigned long count) -{ - u8 data; + if (nrx) { + u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD); - /* Read out the data from the RX FIFO */ - while (count > 0) { - data = cdns_spi_read(xspi, CDNS_SPI_RXD); - if (xspi->rxbuf) - *xspi->rxbuf++ = data; - xspi->rx_bytes--; - count--; + if (xspi->rxbuf) + *xspi->rxbuf++ = data; + + nrx--; + } } } @@ -381,33 +376,22 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id) spi_finalize_current_transfer(ctlr); status = IRQ_HANDLED; } else if (intr_status & CDNS_SPI_IXR_TXOW) { - int trans_cnt = cdns_spi_read(xspi, CDNS_SPI_THLD); + int threshold = cdns_spi_read(xspi, CDNS_SPI_THLD); + int trans_cnt = xspi->rx_bytes - xspi->tx_bytes; + + if (threshold > 1) + trans_cnt -= threshold; + /* Set threshold to one if number of pending are * less than half fifo */ if (xspi->tx_bytes < xspi->tx_fifo_depth >> 1) cdns_spi_write(xspi, CDNS_SPI_THLD, 1); - while (trans_cnt) { - cdns_spi_read_rx_fifo(xspi, 1); - - if (xspi->tx_bytes) { - if (xspi->txbuf) - cdns_spi_write(xspi, CDNS_SPI_TXD, - *xspi->txbuf++); - else - cdns_spi_write(xspi, CDNS_SPI_TXD, 0); - xspi->tx_bytes--; - } - trans_cnt--; - } - if (!xspi->tx_bytes) { - /* Fixed delay due to controller limitation with - * RX_NEMPTY incorrect status - * Xilinx AR:65885 contains more details - */ - udelay(10); - cdns_spi_read_rx_fifo(xspi, xspi->rx_bytes); + if (xspi->tx_bytes) { + cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt); + } else { + cdns_spi_process_fifo(xspi, 0, trans_cnt); cdns_spi_write(xspi, CDNS_SPI_IDR, CDNS_SPI_IXR_DEFAULT); spi_finalize_current_transfer(ctlr); @@ -450,16 +434,17 @@ static int cdns_transfer_one(struct spi_controller *ctlr, xspi->tx_bytes = transfer->len; xspi->rx_bytes = transfer->len; - if (!spi_controller_is_slave(ctlr)) + if (!spi_controller_is_slave(ctlr)) { cdns_spi_setup_transfer(spi, transfer); + } else { + /* Set TX empty threshold to half of FIFO depth + * only if TX bytes are more than half FIFO depth. + */ + if (xspi->tx_bytes > xspi->tx_fifo_depth) + cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1); + } - /* Set TX empty threshold to half of FIFO depth - * only if TX bytes are more than half FIFO depth. - */ - if (xspi->tx_bytes > (xspi->tx_fifo_depth >> 1)) - cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1); - - cdns_spi_fill_tx_fifo(xspi); + cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0); spi_transfer_delay_exec(transfer); cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 5e6faa98aa85..5f2aee69c1c1 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -264,17 +264,17 @@ static void dw_spi_elba_set_cs(struct spi_device *spi, bool enable) struct regmap *syscon = dwsmmio->priv; u8 cs; - cs = spi->chip_select; + cs = spi_get_chipselect(spi, 0); if (cs < 2) - dw_spi_elba_override_cs(syscon, spi->chip_select, enable); + dw_spi_elba_override_cs(syscon, spi_get_chipselect(spi, 0), enable); /* * The DW SPI controller needs a native CS bit selected to start * the serial engine. */ - spi->chip_select = 0; + spi_set_chipselect(spi, 0, 0); dw_spi_set_cs(spi, enable); - spi->chip_select = cs; + spi_get_chipselect(spi, cs); } static int dw_spi_elba_init(struct platform_device *pdev, diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index ba7be505ec4e..a98b781b103a 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -294,6 +294,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) mas->cs_flag = set_flag; /* set xfer_mode to FIFO to complete cs_done in isr */ mas->cur_xfer_mode = GENI_SE_FIFO; + geni_se_select_mode(se, mas->cur_xfer_mode); + reinit_completion(&mas->cs_done); if (set_flag) geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a1ad8f41fb86..9291b2a0e887 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2355,8 +2355,8 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) } /* Select device driver */ - rc = of_modalias_node(nc, spi->modalias, - sizeof(spi->modalias)); + rc = of_alias_from_compatible(nc, spi->modalias, + sizeof(spi->modalias)); if (rc < 0) { dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc); goto err_out; @@ -2777,7 +2777,6 @@ static void spi_controller_release(struct device *dev) static struct class spi_master_class = { .name = "spi_master", - .owner = THIS_MODULE, .dev_release = spi_controller_release, .dev_groups = spi_master_groups, }; @@ -2880,7 +2879,6 @@ static const struct attribute_group *spi_slave_groups[] = { static struct class spi_slave_class = { .name = "spi_slave", - .owner = THIS_MODULE, .dev_release = spi_controller_release, .dev_groups = spi_slave_groups, }; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index a399c617ca25..39d94c850839 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -877,7 +877,7 @@ static int __init spidev_init(void) if (status < 0) return status; - spidev_class = class_create(THIS_MODULE, "spidev"); + spidev_class = class_create("spidev"); if (IS_ERR(spidev_class)) { unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); return PTR_ERR(spidev_class); diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c index 5bd23262abd6..9cbd473487cb 100644 --- a/drivers/spmi/hisi-spmi-controller.c +++ b/drivers/spmi/hisi-spmi-controller.c @@ -324,13 +324,12 @@ err_put_controller: return ret; } -static int spmi_del_controller(struct platform_device *pdev) +static void spmi_del_controller(struct platform_device *pdev) { struct spmi_controller *ctrl = platform_get_drvdata(pdev); spmi_controller_remove(ctrl); spmi_controller_put(ctrl); - return 0; } static const struct of_device_id spmi_controller_match_table[] = { @@ -343,7 +342,7 @@ MODULE_DEVICE_TABLE(of, spmi_controller_match_table); static struct platform_driver spmi_controller_driver = { .probe = spmi_controller_probe, - .remove = spmi_del_controller, + .remove_new = spmi_del_controller, .driver = { .name = "hisi_spmi_controller", .of_match_table = spmi_controller_match_table, diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c index ad511f2c3324..b3c991e1ea40 100644 --- a/drivers/spmi/spmi-mtk-pmif.c +++ b/drivers/spmi/spmi-mtk-pmif.c @@ -503,7 +503,7 @@ err_put_ctrl: return err; } -static int mtk_spmi_remove(struct platform_device *pdev) +static void mtk_spmi_remove(struct platform_device *pdev) { struct spmi_controller *ctrl = platform_get_drvdata(pdev); struct pmif *arb = spmi_controller_get_drvdata(ctrl); @@ -511,7 +511,6 @@ static int mtk_spmi_remove(struct platform_device *pdev) clk_bulk_disable_unprepare(arb->nclks, arb->clks); spmi_controller_remove(ctrl); spmi_controller_put(ctrl); - return 0; } static const struct of_device_id mtk_spmi_match_table[] = { @@ -530,10 +529,10 @@ MODULE_DEVICE_TABLE(of, mtk_spmi_match_table); static struct platform_driver mtk_spmi_driver = { .driver = { .name = "spmi-mtk", - .of_match_table = of_match_ptr(mtk_spmi_match_table), + .of_match_table = mtk_spmi_match_table, }, .probe = mtk_spmi_probe, - .remove = mtk_spmi_remove, + .remove_new = mtk_spmi_remove, }; module_platform_driver(mtk_spmi_driver); diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 8b6a42ab816f..dcb675d980d4 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -126,7 +126,7 @@ struct apid_data { }; /** - * spmi_pmic_arb - SPMI PMIC Arbiter object + * struct spmi_pmic_arb - SPMI PMIC Arbiter object * * @rd_base: on v1 "core", on v2 "observer" register base off DT. * @wr_base: on v1 "core", on v2 "chnls" register base off DT. @@ -180,7 +180,7 @@ struct spmi_pmic_arb { }; /** - * pmic_arb_ver: version dependent functionality. + * struct pmic_arb_ver_ops - version dependent functionality. * * @ver_str: version string. * @ppid_to_apid: finds the apid for a given ppid. @@ -1674,7 +1674,7 @@ err_put_ctrl: return err; } -static int spmi_pmic_arb_remove(struct platform_device *pdev) +static void spmi_pmic_arb_remove(struct platform_device *pdev) { struct spmi_controller *ctrl = platform_get_drvdata(pdev); struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); @@ -1682,7 +1682,6 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev) irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL); irq_domain_remove(pmic_arb->domain); spmi_controller_put(ctrl); - return 0; } static const struct of_device_id spmi_pmic_arb_match_table[] = { @@ -1693,7 +1692,7 @@ MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); static struct platform_driver spmi_pmic_arb_driver = { .probe = spmi_pmic_arb_probe, - .remove = spmi_pmic_arb_remove, + .remove_new = spmi_pmic_arb_remove, .driver = { .name = "spmi_pmic_arb", .of_match_table = spmi_pmic_arb_match_table, diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c index 73551531ed43..7313d4c18a04 100644 --- a/drivers/spmi/spmi.c +++ b/drivers/spmi/spmi.c @@ -350,7 +350,8 @@ static void spmi_drv_remove(struct device *dev) const struct spmi_driver *sdrv = to_spmi_driver(dev->driver); pm_runtime_get_sync(dev); - sdrv->remove(to_spmi_device(dev)); + if (sdrv->remove) + sdrv->remove(to_spmi_device(dev)); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); @@ -404,7 +405,7 @@ struct spmi_device *spmi_device_from_of(struct device_node *np) EXPORT_SYMBOL_GPL(spmi_device_from_of); /** - * spmi_controller_alloc() - Allocate a new SPMI device + * spmi_device_alloc() - Allocate a new SPMI device * @ctrl: associated controller * * Caller is responsible for either calling spmi_device_add() to add the @@ -582,8 +583,9 @@ void spmi_controller_remove(struct spmi_controller *ctrl) EXPORT_SYMBOL_GPL(spmi_controller_remove); /** - * spmi_driver_register() - Register client driver with SPMI core + * __spmi_driver_register() - Register client driver with SPMI core * @sdrv: client driver to be associated with client-device. + * @owner: module owner * * This API will register the client driver with the SPMI framework. * It is typically called from the driver's module-init function. diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index dfd2b357f484..7a21f2423204 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -103,17 +103,17 @@ * globals * ---------------------------- */ -static int read_timeout = 1000; /* ms to wait before read() times out */ -static int write_timeout = 1000; /* ms to wait before write() times out */ +static long read_timeout = 1000; /* ms to wait before read() times out */ +static long write_timeout = 1000; /* ms to wait before write() times out */ /* ---------------------------- * module command-line arguments * ---------------------------- */ -module_param(read_timeout, int, 0444); +module_param(read_timeout, long, 0444); MODULE_PARM_DESC(read_timeout, "ms to wait before blocking read() timing out; set to -1 for no timeout"); -module_param(write_timeout, int, 0444); +module_param(write_timeout, long, 0444); MODULE_PARM_DESC(write_timeout, "ms to wait before blocking write() timing out; set to -1 for no timeout"); /* ---------------------------- @@ -384,9 +384,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf, mutex_lock(&fifo->read_lock); ret = wait_event_interruptible_timeout(fifo->read_queue, ioread32(fifo->base_addr + XLLF_RDFO_OFFSET), - (read_timeout >= 0) ? - msecs_to_jiffies(read_timeout) : - MAX_SCHEDULE_TIMEOUT); + read_timeout); if (ret <= 0) { if (ret == 0) { @@ -528,9 +526,7 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf, ret = wait_event_interruptible_timeout(fifo->write_queue, ioread32(fifo->base_addr + XLLF_TDFV_OFFSET) >= words_to_write, - (write_timeout >= 0) ? - msecs_to_jiffies(write_timeout) : - MAX_SCHEDULE_TIMEOUT); + write_timeout); if (ret <= 0) { if (ret == 0) { @@ -920,15 +916,13 @@ err_initial: return rc; } -static int axis_fifo_remove(struct platform_device *pdev) +static void axis_fifo_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct axis_fifo *fifo = dev_get_drvdata(dev); misc_deregister(&fifo->miscdev); dev_set_drvdata(dev, NULL); - - return 0; } static const struct of_device_id axis_fifo_of_match[] = { @@ -943,12 +937,22 @@ static struct platform_driver axis_fifo_driver = { .of_match_table = axis_fifo_of_match, }, .probe = axis_fifo_probe, - .remove = axis_fifo_remove, + .remove_new = axis_fifo_remove, }; static int __init axis_fifo_init(void) { - pr_info("axis-fifo driver loaded with parameters read_timeout = %i, write_timeout = %i\n", + if (read_timeout >= 0) + read_timeout = msecs_to_jiffies(read_timeout); + else + read_timeout = MAX_SCHEDULE_TIMEOUT; + + if (write_timeout >= 0) + write_timeout = msecs_to_jiffies(write_timeout); + else + write_timeout = MAX_SCHEDULE_TIMEOUT; + + pr_info("axis-fifo driver loaded with parameters read_timeout = %li, write_timeout = %li\n", read_timeout, write_timeout); return platform_driver_register(&axis_fifo_driver); } diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index f9765841c4aa..eb63daaca702 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -3137,7 +3137,7 @@ static void nbu2ss_drv_shutdown(struct platform_device *pdev) } /*-------------------------------------------------------------------------*/ -static int nbu2ss_drv_remove(struct platform_device *pdev) +static void nbu2ss_drv_remove(struct platform_device *pdev) { struct nbu2ss_udc *udc; struct nbu2ss_ep *ep; @@ -3154,8 +3154,6 @@ static int nbu2ss_drv_remove(struct platform_device *pdev) /* Interrupt Handler - Release */ free_irq(vbus_irq, udc); - - return 0; } /*-------------------------------------------------------------------------*/ @@ -3210,7 +3208,7 @@ static int nbu2ss_drv_resume(struct platform_device *pdev) static struct platform_driver udc_driver = { .probe = nbu2ss_drv_probe, .shutdown = nbu2ss_drv_shutdown, - .remove = nbu2ss_drv_remove, + .remove_new = nbu2ss_drv_remove, .suspend = nbu2ss_drv_suspend, .resume = nbu2ss_drv_resume, .driver = { diff --git a/drivers/staging/fieldbus/anybuss/arcx-anybus.c b/drivers/staging/fieldbus/anybuss/arcx-anybus.c index 9af2e63050d1..f135b9f52c8d 100644 --- a/drivers/staging/fieldbus/anybuss/arcx-anybus.c +++ b/drivers/staging/fieldbus/anybuss/arcx-anybus.c @@ -321,7 +321,7 @@ out_reset: return err; } -static int controller_remove(struct platform_device *pdev) +static void controller_remove(struct platform_device *pdev) { struct controller_priv *cd = platform_get_drvdata(pdev); int id = cd->class_dev->id; @@ -329,7 +329,6 @@ static int controller_remove(struct platform_device *pdev) device_unregister(cd->class_dev); ida_simple_remove(&controller_index_ida, id); gpiod_set_value_cansleep(cd->reset_gpiod, 1); - return 0; } static const struct of_device_id controller_of_match[] = { @@ -341,7 +340,7 @@ MODULE_DEVICE_TABLE(of, controller_of_match); static struct platform_driver controller_driver = { .probe = controller_probe, - .remove = controller_remove, + .remove_new = controller_remove, .driver = { .name = "arcx-anybus-controller", .of_match_table = of_match_ptr(controller_of_match), @@ -352,7 +351,7 @@ static int __init controller_init(void) { int err; - controller_class = class_create(THIS_MODULE, "arcx_anybus_controller"); + controller_class = class_create("arcx_anybus_controller"); if (IS_ERR(controller_class)) return PTR_ERR(controller_class); err = platform_driver_register(&controller_driver); diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c index 5f54f2674bd1..bf1812d8924f 100644 --- a/drivers/staging/fieldbus/dev_core.c +++ b/drivers/staging/fieldbus/dev_core.c @@ -154,7 +154,6 @@ __ATTRIBUTE_GROUPS(fieldbus); static struct class fieldbus_class = { .name = "fieldbus_dev", - .owner = THIS_MODULE, .dev_groups = fieldbus_groups, }; diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index 45afa208d004..8541995008da 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -419,13 +419,11 @@ static int arche_apb_ctrl_probe(struct platform_device *pdev) return 0; } -static int arche_apb_ctrl_remove(struct platform_device *pdev) +static void arche_apb_ctrl_remove(struct platform_device *pdev) { device_remove_file(&pdev->dev, &dev_attr_state); poweroff_seq(pdev); platform_set_drvdata(pdev, NULL); - - return 0; } static int __maybe_unused arche_apb_ctrl_suspend(struct device *dev) @@ -471,7 +469,7 @@ static const struct of_device_id arche_apb_ctrl_of_match[] = { static struct platform_driver arche_apb_ctrl_device_driver = { .probe = arche_apb_ctrl_probe, - .remove = arche_apb_ctrl_remove, + .remove_new = arche_apb_ctrl_remove, .shutdown = arche_apb_ctrl_shutdown, .driver = { .name = "arche-apb-ctrl", diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index fcbd5f71eff2..ebe835f25d13 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -559,7 +559,7 @@ static int arche_remove_child(struct device *dev, void *unused) return 0; } -static int arche_platform_remove(struct platform_device *pdev) +static void arche_platform_remove(struct platform_device *pdev) { struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); @@ -570,8 +570,6 @@ static int arche_platform_remove(struct platform_device *pdev) if (usb3613_hub_mode_ctrl(false)) dev_warn(arche_pdata->dev, "failed to control hub device\n"); - /* TODO: Should we do anything more here ?? */ - return 0; } static __maybe_unused int arche_platform_suspend(struct device *dev) @@ -631,7 +629,7 @@ MODULE_DEVICE_TABLE(of, arche_combined_id); static struct platform_driver arche_platform_device_driver = { .probe = arche_platform_probe, - .remove = arche_platform_remove, + .remove_new = arche_platform_remove, .shutdown = arche_platform_shutdown, .driver = { .name = "arche-platform-ctrl", diff --git a/drivers/staging/greybus/audio_manager_module.c b/drivers/staging/greybus/audio_manager_module.c index 0a0f0a394c84..5f9dcbdbc191 100644 --- a/drivers/staging/greybus/audio_manager_module.c +++ b/drivers/staging/greybus/audio_manager_module.c @@ -12,8 +12,11 @@ #define to_gb_audio_module_attr(x) \ container_of(x, struct gb_audio_manager_module_attribute, attr) -#define to_gb_audio_module(x) \ - container_of(x, struct gb_audio_manager_module, kobj) + +static inline struct gb_audio_manager_module *to_gb_audio_module(struct kobject *kobj) +{ + return container_of(kobj, struct gb_audio_manager_module, kobj); +} struct gb_audio_manager_module_attribute { struct attribute attr; @@ -70,9 +73,8 @@ static void gb_audio_module_release(struct kobject *kobj) kfree(module); } -static ssize_t gb_audio_module_name_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_name_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, char *buf) { return sprintf(buf, "%s", module->desc.name); } @@ -80,9 +82,8 @@ static ssize_t gb_audio_module_name_show( static struct gb_audio_manager_module_attribute gb_audio_module_name_attribute = __ATTR(name, 0664, gb_audio_module_name_show, NULL); -static ssize_t gb_audio_module_vid_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_vid_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, char *buf) { return sprintf(buf, "%d", module->desc.vid); } @@ -90,9 +91,8 @@ static ssize_t gb_audio_module_vid_show( static struct gb_audio_manager_module_attribute gb_audio_module_vid_attribute = __ATTR(vid, 0664, gb_audio_module_vid_show, NULL); -static ssize_t gb_audio_module_pid_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_pid_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, char *buf) { return sprintf(buf, "%d", module->desc.pid); } @@ -100,9 +100,9 @@ static ssize_t gb_audio_module_pid_show( static struct gb_audio_manager_module_attribute gb_audio_module_pid_attribute = __ATTR(pid, 0664, gb_audio_module_pid_show, NULL); -static ssize_t gb_audio_module_intf_id_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_intf_id_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, + char *buf) { return sprintf(buf, "%d", module->desc.intf_id); } @@ -111,9 +111,9 @@ static struct gb_audio_manager_module_attribute gb_audio_module_intf_id_attribute = __ATTR(intf_id, 0664, gb_audio_module_intf_id_show, NULL); -static ssize_t gb_audio_module_ip_devices_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_ip_devices_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, + char *buf) { return sprintf(buf, "0x%X", module->desc.ip_devices); } @@ -122,9 +122,9 @@ static struct gb_audio_manager_module_attribute gb_audio_module_ip_devices_attribute = __ATTR(ip_devices, 0664, gb_audio_module_ip_devices_show, NULL); -static ssize_t gb_audio_module_op_devices_show( - struct gb_audio_manager_module *module, - struct gb_audio_manager_module_attribute *attr, char *buf) +static ssize_t gb_audio_module_op_devices_show(struct gb_audio_manager_module *module, + struct gb_audio_manager_module_attribute *attr, + char *buf) { return sprintf(buf, "0x%X", module->desc.op_devices); } @@ -181,10 +181,9 @@ static void send_add_uevent(struct gb_audio_manager_module *module) kobject_uevent_env(&module->kobj, KOBJ_ADD, envp); } -int gb_audio_manager_module_create( - struct gb_audio_manager_module **module, - struct kset *manager_kset, - int id, struct gb_audio_manager_module_descriptor *desc) +int gb_audio_manager_module_create(struct gb_audio_manager_module **module, + struct kset *manager_kset, + int id, struct gb_audio_manager_module_descriptor *desc) { int err; struct gb_audio_manager_module *m; diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c index 62d7674852be..08e6a807c132 100644 --- a/drivers/staging/greybus/audio_topology.c +++ b/drivers/staging/greybus/audio_topology.c @@ -24,9 +24,8 @@ struct gbaudio_ctl_pvt { struct gb_audio_ctl_elem_info *info; }; -static struct gbaudio_module_info *find_gb_module( - struct gbaudio_codec_info *codec, - char const *name) +static struct gbaudio_module_info *find_gb_module(struct gbaudio_codec_info *codec, + char const *name) { int dev_id; char begin[NAME_SIZE]; diff --git a/drivers/staging/greybus/authentication.c b/drivers/staging/greybus/authentication.c index 297e69f011c7..7e01790a4659 100644 --- a/drivers/staging/greybus/authentication.c +++ b/drivers/staging/greybus/authentication.c @@ -402,7 +402,7 @@ int cap_init(void) { int ret; - cap_class = class_create(THIS_MODULE, "gb_authenticate"); + cap_class = class_create("gb_authenticate"); if (IS_ERR(cap_class)) return PTR_ERR(cap_class); diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c index 3342b84597da..cd9141e4b794 100644 --- a/drivers/staging/greybus/fw-management.c +++ b/drivers/staging/greybus/fw-management.c @@ -696,7 +696,7 @@ int fw_mgmt_init(void) { int ret; - fw_mgmt_class = class_create(THIS_MODULE, "gb_fw_mgmt"); + fw_mgmt_class = class_create("gb_fw_mgmt"); if (IS_ERR(fw_mgmt_class)) return PTR_ERR(fw_mgmt_class); diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index d729b922a750..2a115a8fc263 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -41,8 +41,11 @@ struct gb_gpio_controller { struct irq_chip irqc; struct mutex irq_lock; }; -#define gpio_chip_to_gb_gpio_controller(chip) \ - container_of(chip, struct gb_gpio_controller, chip) + +static inline struct gb_gpio_controller *gpio_chip_to_gb_gpio_controller(struct gpio_chip *chip) +{ + return container_of(chip, struct gb_gpio_controller, chip); +} static struct gpio_chip *irq_data_to_gpio_chip(struct irq_data *d) { diff --git a/drivers/staging/greybus/greybus_authentication.h b/drivers/staging/greybus/greybus_authentication.h index 7edc7295b7ab..48b4a9794d3c 100644 --- a/drivers/staging/greybus/greybus_authentication.h +++ b/drivers/staging/greybus/greybus_authentication.h @@ -41,7 +41,6 @@ #define CAP_AUTH_RESULT_CR_NO_KEY 0x03 #define CAP_AUTH_RESULT_CR_SIG_FAIL 0x04 - /* IOCTL support */ struct cap_ioc_get_endpoint_uid { __u8 uid[8]; diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 1a61fce98056..d7b39f3bb652 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -100,7 +100,6 @@ struct gb_loopback { static struct class loopback_class = { .name = "gb_loopback", - .owner = THIS_MODULE, }; static DEFINE_IDA(loopback_ida); diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c index 3fda172239d2..88da1d796f13 100644 --- a/drivers/staging/greybus/pwm.c +++ b/drivers/staging/greybus/pwm.c @@ -21,9 +21,11 @@ struct gb_pwm_chip { struct pwm_chip chip; struct pwm_chip *pwm; }; -#define pwm_chip_to_gb_pwm_chip(chip) \ - container_of(chip, struct gb_pwm_chip, chip) +static inline struct gb_pwm_chip *pwm_chip_to_gb_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct gb_pwm_chip, chip); +} static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc) { diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c index 2a375f407d38..8bca8cb12cc6 100644 --- a/drivers/staging/greybus/raw.c +++ b/drivers/staging/greybus/raw.c @@ -340,7 +340,7 @@ static int raw_init(void) dev_t dev; int retval; - raw_class = class_create(THIS_MODULE, "gb_raw"); + raw_class = class_create("gb_raw"); if (IS_ERR(raw_class)) { retval = PTR_ERR(raw_class); goto error_class; diff --git a/drivers/staging/greybus/tools/.gitignore b/drivers/staging/greybus/tools/.gitignore deleted file mode 100644 index 1fd364aba774..000000000000 --- a/drivers/staging/greybus/tools/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -loopback_test diff --git a/drivers/staging/greybus/tools/Android.mk b/drivers/staging/greybus/tools/Android.mk deleted file mode 100644 index fdadbf611757..000000000000 --- a/drivers/staging/greybus/tools/Android.mk +++ /dev/null @@ -1,10 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= loopback_test.c -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := gb_loopback_test - -include $(BUILD_EXECUTABLE) - diff --git a/drivers/staging/greybus/tools/Makefile b/drivers/staging/greybus/tools/Makefile deleted file mode 100644 index a3bbd73171f2..000000000000 --- a/drivers/staging/greybus/tools/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -ifeq ($(strip $(V)), 1) - Q = -else - Q = @ -endif - -CFLAGS += -std=gnu99 -Wall -Wextra -g \ - -D_GNU_SOURCE \ - -Wno-unused-parameter \ - -Wmaybe-uninitialized \ - -Wredundant-decls \ - -Wcast-align \ - -Wsign-compare \ - -Wno-missing-field-initializers \ - -Wno-shift-negative-value - -CC := $(CROSS_COMPILE)gcc - -TOOLS = loopback_test - -all: $(TOOLS) - -%.o: %.c ../greybus_protocols.h - @echo ' TARGET_CC $@' - $(Q)$(CC) $(CFLAGS) -c $< -o $@ - -loopback_%: loopback_%.o - @echo ' TARGET_LD $@' - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ - -clean:: - rm -f *.o $(TOOLS) diff --git a/drivers/staging/greybus/tools/README.loopback b/drivers/staging/greybus/tools/README.loopback deleted file mode 100644 index 070a510cbe7c..000000000000 --- a/drivers/staging/greybus/tools/README.loopback +++ /dev/null @@ -1,198 +0,0 @@ - - - 1 - LOOPBACK DRIVER - -The driver implements the main logic of the loopback test and provides -sysfs files to configure the test and retrieve the results. -A user could run a test without the need of the test application given -that he understands the sysfs interface of the loopback driver. - -The loopback kernel driver needs to be loaded and at least one module -with the loopback feature enabled must be present for the sysfs files to be -created and for the loopback test application to be able to run. - -To load the module: -# modprobe gb-loopback - - -When the module is probed, New files are available on the sysfs -directory of the detected loopback device. -(typically under "/sys/bus/graybus/devices"). - -Here is a short summary of the sysfs interface files that should be visible: - -* Loopback Configuration Files: - async - Use asynchronous operations. - iteration_max - Number of tests iterations to perform. - size - payload size of the transfer. - timeout - The number of microseconds to give an individual - asynchronous request before timing out. - us_wait - Time to wait between 2 messages - type - By writing the test type to this file, the test starts. - Valid tests are: - 0 stop the test - 2 - ping - 3 - transfer - 4 - sink - -* Loopback feedback files: - error - number of errors that have occurred. - iteration_count - Number of iterations performed. - requests_completed - Number of requests successfully completed. - requests_timedout - Number of requests that have timed out. - timeout_max - Max allowed timeout - timeout_min - Min allowed timeout. - -* Loopback result files: - apbridge_unipro_latency_avg - apbridge_unipro_latency_max - apbridge_unipro_latency_min - gpbridge_firmware_latency_avg - gpbridge_firmware_latency_max - gpbridge_firmware_latency_min - requests_per_second_avg - requests_per_second_max - requests_per_second_min - latency_avg - latency_max - latency_min - throughput_avg - throughput_max - throughput_min - - - - 2 - LOOPBACK TEST APPLICATION - -The loopback test application manages and formats the results provided by -the loopback kernel module. The purpose of this application -is to: - - Start and manage multiple loopback device tests concurrently. - - Calculate the aggregate results for multiple devices. - - Gather and format test results (csv or human readable). - -The best way to get up to date usage information for the application is -usually to pass the "-h" parameter. -Here is the summary of the available options: - - Mandatory arguments - -t must be one of the test names - sink, transfer or ping - -i iteration count - the number of iterations to run the test over - Optional arguments - -S sysfs location - location for greybus 'endo' entries default /sys/bus/greybus/devices/ - -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/ - -s size of data packet to send during test - defaults to zero - -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc - default is zero which means broadcast to all connections - -v verbose output - -d debug output - -r raw data output - when specified the full list of latency values are included in the output CSV - -p porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file - -a aggregate - show aggregation of all enabled devies - -l list found loopback devices and exit. - -x Async - Enable async transfers. - -o Timeout - Timeout in microseconds for async operations. - - - - 3 - REAL WORLD EXAMPLE USAGES - - 3.1 - Using the driver sysfs files to run a test on a single device: - -* Run a 1000 transfers of a 100 byte packet. Each transfer is started only -after the previous one finished successfully: - echo 0 > /sys/bus/greybus/devices/1-2.17/type - echo 0 > /sys/bus/greybus/devices/1-2.17/async - echo 2000 > /sys/bus/greybus/devices/1-2.17/us_wait - echo 100 > /sys/bus/greybus/devices/1-2.17/size - echo 1000 > /sys/bus/greybus/devices/1-2.17/iteration_max - echo 0 > /sys/bus/greybus/devices/1-2.17/mask - echo 200000 > /sys/bus/greybus/devices/1-2.17/timeout - echo 3 > /sys/bus/greybus/devices/1-2.17/type - -* Run a 1000 transfers of a 100 byte packet. Transfers are started without -waiting for the previous one to finish: - echo 0 > /sys/bus/greybus/devices/1-2.17/type - echo 3 > /sys/bus/greybus/devices/1-2.17/async - echo 0 > /sys/bus/greybus/devices/1-2.17/us_wait - echo 100 > /sys/bus/greybus/devices/1-2.17/size - echo 1000 > /sys/bus/greybus/devices/1-2.17/iteration_max - echo 0 > /sys/bus/greybus/devices/1-2.17/mask - echo 200000 > /sys/bus/greybus/devices/1-2.17/timeout - echo 3 > /sys/bus/greybus/devices/1-2.17/type - -* Read the results from sysfs: - cat /sys/bus/greybus/devices/1-2.17/requests_per_second_min - cat /sys/bus/greybus/devices/1-2.17/requests_per_second_max - cat /sys/bus/greybus/devices/1-2.17/requests_per_second_avg - - cat /sys/bus/greybus/devices/1-2.17/latency_min - cat /sys/bus/greybus/devices/1-2.17/latency_max - cat /sys/bus/greybus/devices/1-2.17/latency_avg - - cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_min - cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_max - cat /sys/bus/greybus/devices/1-2.17/apbridge_unipro_latency_avg - - cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_min - cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_max - cat /sys/bus/greybus/devices/1-2.17/gpbridge_firmware_latency_avg - - cat /sys/bus/greybus/devices/1-2.17/error - cat /sys/bus/greybus/devices/1-2.17/requests_completed - cat /sys/bus/greybus/devices/1-2.17/requests_timedout - - -3.2 - using the test application: - -* Run a transfer test 10 iterations of size 100 bytes on all available devices - #/loopback_test -t transfer -i 10 -s 100 - 1970-1-1 0:10:7,transfer,1-4.17,100,10,0,443,509,471.700012,66,1963,2256,2124.600098,293,102776,118088,109318.898438,15312,1620,1998,1894.099976,378,56,57,56.799999,1 - 1970-1-1 0:10:7,transfer,1-5.17,100,10,0,399,542,463.399994,143,1845,2505,2175.800049,660,92568,125744,107393.296875,33176,1469,2305,1806.500000,836,56,57,56.799999,1 - - -* Show the aggregate results of both devices. ("-a") - #/loopback_test -t transfer -i 10 -s 100 -a - 1970-1-1 0:10:35,transfer,1-4.17,100,10,0,448,580,494.100006,132,1722,2230,2039.400024,508,103936,134560,114515.703125,30624,1513,1980,1806.900024,467,56,57,57.299999,1 - 1970-1-1 0:10:35,transfer,1-5.17,100,10,0,383,558,478.600006,175,1791,2606,2115.199951,815,88856,129456,110919.703125,40600,1457,2246,1773.599976,789,56,57,57.099998,1 - 1970-1-1 0:10:35,transfer,aggregate,100,10,0,383,580,486.000000,197,1722,2606,2077.000000,884,88856,134560,112717.000000,45704,1457,2246,1789.000000,789,56,57,57.000000,1 - -* Example usage of the mask option to select which devices will - run the test (1st, 2nd, or both devices): - # /loopback_test -t transfer -i 10 -s 100 -m 1 - 1970-1-1 0:11:56,transfer,1-4.17,100,10,0,514,558,544.900024,44,1791,1943,1836.599976,152,119248,129456,126301.296875,10208,1600,1001609,101613.601562,1000009,56,57,56.900002,1 - # /loopback_test -t transfer -i 10 -s 100 -m 2 - 1970-1-1 0:12:0,transfer,1-5.17,100,10,0,468,554,539.000000,86,1804,2134,1859.500000,330,108576,128528,124932.500000,19952,1606,1626,1619.300049,20,56,57,57.400002,1 - # /loopback_test -t transfer -i 10 -s 100 -m 3 - 1970-1-1 0:12:3,transfer,1-4.17,100,10,0,432,510,469.399994,78,1959,2313,2135.800049,354,100224,118320,108785.296875,18096,1610,2024,1893.500000,414,56,57,57.200001,1 - 1970-1-1 0:12:3,transfer,1-5.17,100,10,0,404,542,468.799988,138,1843,2472,2152.500000,629,93728,125744,108646.101562,32016,1504,2247,1853.099976,743,56,57,57.099998,1 - -* Show output in human readable format ("-p") - # /loopback_test -t transfer -i 10 -s 100 -m 3 -p - - 1970-1-1 0:12:37 - test: transfer - path: 1-4.17 - size: 100 - iterations: 10 - errors: 0 - async: Disabled - requests per-sec: min=390, max=547, average=469.299988, jitter=157 - ap-throughput B/s: min=90480 max=126904 average=108762.101562 jitter=36424 - ap-latency usec: min=1826 max=2560 average=2146.000000 jitter=734 - apbridge-latency usec: min=1620 max=1982 average=1882.099976 jitter=362 - gpbridge-latency usec: min=56 max=57 average=57.099998 jitter=1 - - - 1970-1-1 0:12:37 - test: transfer - path: 1-5.17 - size: 100 - iterations: 10 - errors: 0 - async: Disabled - requests per-sec: min=397, max=538, average=461.700012, jitter=141 - ap-throughput B/s: min=92104 max=124816 average=106998.898438 jitter=32712 - ap-latency usec: min=1856 max=2514 average=2185.699951 jitter=658 - apbridge-latency usec: min=1460 max=2296 average=1828.599976 jitter=836 - gpbridge-latency usec: min=56 max=57 average=57.099998 jitter=1 diff --git a/drivers/staging/greybus/tools/lbtest b/drivers/staging/greybus/tools/lbtest deleted file mode 100755 index 47c481239e98..000000000000 --- a/drivers/staging/greybus/tools/lbtest +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: BSD-3-Clause - -# Copyright (c) 2015 Google, Inc. -# Copyright (c) 2015 Linaro, Ltd. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import print_function -import csv -import datetime -import sys -import time - -dict = {'ping': '2', 'transfer': '3', 'sink': '4'} -verbose = 1 - -def abort(): - sys.exit(1) - -def usage(): - print('Usage: looptest TEST SIZE ITERATIONS PATH\n\n' - ' Run TEST for a number of ITERATIONS with operation data SIZE bytes\n' - ' TEST may be \'ping\' \'transfer\' or \'sink\'\n' - ' SIZE indicates the size of transfer <= greybus max payload bytes\n' - ' ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n' - ' Note if ITERATIONS is set to zero then this utility will\n' - ' initiate an infinite (non terminating) test and exit\n' - ' without logging any metrics data\n' - ' PATH indicates the sysfs path for the loopback greybus entries e.g.\n' - ' /sys/bus/greybus/devices/endo0:1:1:1:1/\n' - 'Examples:\n' - ' looptest transfer 128 10000\n' - ' looptest ping 0 128\n' - ' looptest sink 2030 32768\n' - .format(sys.argv[0]), file=sys.stderr) - - abort() - -def read_sysfs_int(path): - try: - f = open(path, "r"); - val = f.read(); - f.close() - return int(val) - except IOError as e: - print("I/O error({0}): {1}".format(e.errno, e.strerror)) - print("Invalid path %s" % path) - -def write_sysfs_val(path, val): - try: - f = open(path, "r+") - f.write(val) - f.close() - except IOError as e: - print("I/O error({0}): {1}".format(e.errno, e.strerror)) - print("Invalid path %s" % path) - -def log_csv(test_name, size, iteration_max, sys_pfx): - # file name will test_name_size_iteration_max.csv - # every time the same test with the same parameters is run we will then - # append to the same CSV with datestamp - representing each test dataset - fname = test_name + '_' + size + '_' + str(iteration_max) + '.csv' - - try: - # gather data set - date = str(datetime.datetime.now()) - error = read_sysfs_int(sys_pfx + 'error') - request_min = read_sysfs_int(sys_pfx + 'requests_per_second_min') - request_max = read_sysfs_int(sys_pfx + 'requests_per_second_max') - request_avg = read_sysfs_int(sys_pfx + 'requests_per_second_avg') - latency_min = read_sysfs_int(sys_pfx + 'latency_min') - latency_max = read_sysfs_int(sys_pfx + 'latency_max') - latency_avg = read_sysfs_int(sys_pfx + 'latency_avg') - throughput_min = read_sysfs_int(sys_pfx + 'throughput_min') - throughput_max = read_sysfs_int(sys_pfx + 'throughput_max') - throughput_avg = read_sysfs_int(sys_pfx + 'throughput_avg') - - # derive jitter - request_jitter = request_max - request_min - latency_jitter = latency_max - latency_min - throughput_jitter = throughput_max - throughput_min - - # append data set to file - with open(fname, 'a') as csvf: - row = csv.writer(csvf, delimiter=",", quotechar="'", - quoting=csv.QUOTE_MINIMAL) - row.writerow([date, test_name, size, iteration_max, error, - request_min, request_max, request_avg, request_jitter, - latency_min, latency_max, latency_avg, latency_jitter, - throughput_min, throughput_max, throughput_avg, throughput_jitter]) - except IOError as e: - print("I/O error({0}): {1}".format(e.errno, e.strerror)) - -def loopback_run(test_name, size, iteration_max, sys_pfx): - test_id = dict[test_name] - try: - # Terminate any currently running test - write_sysfs_val(sys_pfx + 'type', '0') - # Set parameter for no wait between messages - write_sysfs_val(sys_pfx + 'ms_wait', '0') - # Set operation size - write_sysfs_val(sys_pfx + 'size', size) - # Set iterations - write_sysfs_val(sys_pfx + 'iteration_max', str(iteration_max)) - # Initiate by setting loopback operation type - write_sysfs_val(sys_pfx + 'type', test_id) - time.sleep(1) - - if iteration_max == 0: - print ("Infinite test initiated CSV won't be logged\n") - return - - previous = 0 - err = 0 - while True: - # get current count bail out if it hasn't changed - iteration_count = read_sysfs_int(sys_pfx + 'iteration_count') - if previous == iteration_count: - err = 1 - break - elif iteration_count == iteration_max: - break - previous = iteration_count - if verbose: - print('%02d%% complete %d of %d ' % - (100 * iteration_count / iteration_max, - iteration_count, iteration_max)) - time.sleep(1) - if err: - print ('\nError executing test\n') - else: - log_csv(test_name, size, iteration_max, sys_pfx) - except ValueError as ve: - print("Error: %s " % format(e.strerror), file=sys.stderr) - abort() - -def main(): - if len(sys.argv) < 5: - usage() - - if sys.argv[1] in dict.keys(): - loopback_run(sys.argv[1], sys.argv[2], int(sys.argv[3]), sys.argv[4]) - else: - usage() -if __name__ == '__main__': - main() diff --git a/drivers/staging/greybus/tools/loopback_test.c b/drivers/staging/greybus/tools/loopback_test.c deleted file mode 100644 index d7ad51ff60c5..000000000000 --- a/drivers/staging/greybus/tools/loopback_test.c +++ /dev/null @@ -1,979 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Loopback test application - * - * Copyright 2015 Google Inc. - * Copyright 2015 Linaro Ltd. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_NUM_DEVICES 10 -#define MAX_SYSFS_PREFIX 0x80 -#define MAX_SYSFS_PATH 0x200 -#define CSV_MAX_LINE 0x1000 -#define SYSFS_MAX_INT 0x20 -#define MAX_STR_LEN 255 -#define DEFAULT_ASYNC_TIMEOUT 200000 - -struct dict { - char *name; - int type; -}; - -static struct dict dict[] = { - {"ping", 2}, - {"transfer", 3}, - {"sink", 4}, - {NULL,} /* list termination */ -}; - -struct loopback_results { - float latency_avg; - uint32_t latency_max; - uint32_t latency_min; - uint32_t latency_jitter; - - float request_avg; - uint32_t request_max; - uint32_t request_min; - uint32_t request_jitter; - - float throughput_avg; - uint32_t throughput_max; - uint32_t throughput_min; - uint32_t throughput_jitter; - - float apbridge_unipro_latency_avg; - uint32_t apbridge_unipro_latency_max; - uint32_t apbridge_unipro_latency_min; - uint32_t apbridge_unipro_latency_jitter; - - float gbphy_firmware_latency_avg; - uint32_t gbphy_firmware_latency_max; - uint32_t gbphy_firmware_latency_min; - uint32_t gbphy_firmware_latency_jitter; - - uint32_t error; -}; - -struct loopback_device { - char name[MAX_STR_LEN]; - char sysfs_entry[MAX_SYSFS_PATH]; - char debugfs_entry[MAX_SYSFS_PATH]; - struct loopback_results results; -}; - -struct loopback_test { - int verbose; - int debug; - int raw_data_dump; - int porcelain; - int mask; - int size; - int iteration_max; - int aggregate_output; - int test_id; - int device_count; - int list_devices; - int use_async; - int async_timeout; - int async_outstanding_operations; - int us_wait; - int file_output; - int stop_all; - int poll_count; - char test_name[MAX_STR_LEN]; - char sysfs_prefix[MAX_SYSFS_PREFIX]; - char debugfs_prefix[MAX_SYSFS_PREFIX]; - struct timespec poll_timeout; - struct loopback_device devices[MAX_NUM_DEVICES]; - struct loopback_results aggregate_results; - struct pollfd fds[MAX_NUM_DEVICES]; -}; - -struct loopback_test t; - -/* Helper macros to calculate the aggregate results for all devices */ -static inline int device_enabled(struct loopback_test *t, int dev_idx); - -#define GET_MAX(field) \ -static int get_##field##_aggregate(struct loopback_test *t) \ -{ \ - uint32_t max = 0; \ - int i; \ - for (i = 0; i < t->device_count; i++) { \ - if (!device_enabled(t, i)) \ - continue; \ - if (t->devices[i].results.field > max) \ - max = t->devices[i].results.field; \ - } \ - return max; \ -} \ - -#define GET_MIN(field) \ -static int get_##field##_aggregate(struct loopback_test *t) \ -{ \ - uint32_t min = ~0; \ - int i; \ - for (i = 0; i < t->device_count; i++) { \ - if (!device_enabled(t, i)) \ - continue; \ - if (t->devices[i].results.field < min) \ - min = t->devices[i].results.field; \ - } \ - return min; \ -} \ - -#define GET_AVG(field) \ -static int get_##field##_aggregate(struct loopback_test *t) \ -{ \ - uint32_t val = 0; \ - uint32_t count = 0; \ - int i; \ - for (i = 0; i < t->device_count; i++) { \ - if (!device_enabled(t, i)) \ - continue; \ - count++; \ - val += t->devices[i].results.field; \ - } \ - if (count) \ - val /= count; \ - return val; \ -} \ - -GET_MAX(throughput_max); -GET_MAX(request_max); -GET_MAX(latency_max); -GET_MAX(apbridge_unipro_latency_max); -GET_MAX(gbphy_firmware_latency_max); -GET_MIN(throughput_min); -GET_MIN(request_min); -GET_MIN(latency_min); -GET_MIN(apbridge_unipro_latency_min); -GET_MIN(gbphy_firmware_latency_min); -GET_AVG(throughput_avg); -GET_AVG(request_avg); -GET_AVG(latency_avg); -GET_AVG(apbridge_unipro_latency_avg); -GET_AVG(gbphy_firmware_latency_avg); - -void abort(void) -{ - _exit(1); -} - -void usage(void) -{ - fprintf(stderr, "Usage: loopback_test TEST [SIZE] ITERATIONS [SYSPATH] [DBGPATH]\n\n" - " Run TEST for a number of ITERATIONS with operation data SIZE bytes\n" - " TEST may be \'ping\' \'transfer\' or \'sink\'\n" - " SIZE indicates the size of transfer <= greybus max payload bytes\n" - " ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n" - " Note if ITERATIONS is set to zero then this utility will\n" - " initiate an infinite (non terminating) test and exit\n" - " without logging any metrics data\n" - " SYSPATH indicates the sysfs path for the loopback greybus entries e.g.\n" - " /sys/bus/greybus/devices\n" - " DBGPATH indicates the debugfs path for the loopback greybus entries e.g.\n" - " /sys/kernel/debug/gb_loopback/\n" - " Mandatory arguments\n" - " -t must be one of the test names - sink, transfer or ping\n" - " -i iteration count - the number of iterations to run the test over\n" - " Optional arguments\n" - " -S sysfs location - location for greybus 'endo' entries default /sys/bus/greybus/devices/\n" - " -D debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/\n" - " -s size of data packet to send during test - defaults to zero\n" - " -m mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc\n" - " default is zero which means broadcast to all connections\n" - " -v verbose output\n" - " -d debug output\n" - " -r raw data output - when specified the full list of latency values are included in the output CSV\n" - " -p porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file\n" - " -a aggregate - show aggregation of all enabled devices\n" - " -l list found loopback devices and exit\n" - " -x Async - Enable async transfers\n" - " -o Async Timeout - Timeout in uSec for async operations\n" - " -O Poll loop time out in seconds(max time a test is expected to last, default: 30sec)\n" - " -c Max number of outstanding operations for async operations\n" - " -w Wait in uSec between operations\n" - " -z Enable output to a CSV file (incompatible with -p)\n" - " -f When starting new loopback test, stop currently running tests on all devices\n" - "Examples:\n" - " Send 10000 transfers with a packet size of 128 bytes to all active connections\n" - " loopback_test -t transfer -s 128 -i 10000 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n" - " loopback_test -t transfer -s 128 -i 10000 -m 0\n" - " Send 10000 transfers with a packet size of 128 bytes to connection 1 and 4\n" - " loopback_test -t transfer -s 128 -i 10000 -m 9\n" - " loopback_test -t ping -s 0 128 -i -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n" - " loopback_test -t sink -s 2030 -i 32768 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"); - abort(); -} - -static inline int device_enabled(struct loopback_test *t, int dev_idx) -{ - if (!t->mask || (t->mask & (1 << dev_idx))) - return 1; - - return 0; -} - -static void show_loopback_devices(struct loopback_test *t) -{ - int i; - - if (t->device_count == 0) { - printf("No loopback devices.\n"); - return; - } - - for (i = 0; i < t->device_count; i++) - printf("device[%d] = %s\n", i, t->devices[i].name); -} - -int open_sysfs(const char *sys_pfx, const char *node, int flags) -{ - int fd; - char path[MAX_SYSFS_PATH]; - - snprintf(path, sizeof(path), "%s%s", sys_pfx, node); - fd = open(path, flags); - if (fd < 0) { - fprintf(stderr, "unable to open %s\n", path); - abort(); - } - return fd; -} - -int read_sysfs_int_fd(int fd, const char *sys_pfx, const char *node) -{ - char buf[SYSFS_MAX_INT]; - - if (read(fd, buf, sizeof(buf)) < 0) { - fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node, - strerror(errno)); - close(fd); - abort(); - } - return atoi(buf); -} - -float read_sysfs_float_fd(int fd, const char *sys_pfx, const char *node) -{ - char buf[SYSFS_MAX_INT]; - - if (read(fd, buf, sizeof(buf)) < 0) { - fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node, - strerror(errno)); - close(fd); - abort(); - } - return atof(buf); -} - -int read_sysfs_int(const char *sys_pfx, const char *node) -{ - int fd, val; - - fd = open_sysfs(sys_pfx, node, O_RDONLY); - val = read_sysfs_int_fd(fd, sys_pfx, node); - close(fd); - return val; -} - -float read_sysfs_float(const char *sys_pfx, const char *node) -{ - int fd; - float val; - - fd = open_sysfs(sys_pfx, node, O_RDONLY); - val = read_sysfs_float_fd(fd, sys_pfx, node); - close(fd); - return val; -} - -void write_sysfs_val(const char *sys_pfx, const char *node, int val) -{ - int fd, len; - char buf[SYSFS_MAX_INT]; - - fd = open_sysfs(sys_pfx, node, O_RDWR); - len = snprintf(buf, sizeof(buf), "%d", val); - if (write(fd, buf, len) < 0) { - fprintf(stderr, "unable to write to %s%s %s\n", sys_pfx, node, - strerror(errno)); - close(fd); - abort(); - } - close(fd); -} - -static int get_results(struct loopback_test *t) -{ - struct loopback_device *d; - struct loopback_results *r; - int i; - - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - - d = &t->devices[i]; - r = &d->results; - - r->error = read_sysfs_int(d->sysfs_entry, "error"); - r->request_min = read_sysfs_int(d->sysfs_entry, "requests_per_second_min"); - r->request_max = read_sysfs_int(d->sysfs_entry, "requests_per_second_max"); - r->request_avg = read_sysfs_float(d->sysfs_entry, "requests_per_second_avg"); - - r->latency_min = read_sysfs_int(d->sysfs_entry, "latency_min"); - r->latency_max = read_sysfs_int(d->sysfs_entry, "latency_max"); - r->latency_avg = read_sysfs_float(d->sysfs_entry, "latency_avg"); - - r->throughput_min = read_sysfs_int(d->sysfs_entry, "throughput_min"); - r->throughput_max = read_sysfs_int(d->sysfs_entry, "throughput_max"); - r->throughput_avg = read_sysfs_float(d->sysfs_entry, "throughput_avg"); - - r->apbridge_unipro_latency_min = - read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_min"); - r->apbridge_unipro_latency_max = - read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_max"); - r->apbridge_unipro_latency_avg = - read_sysfs_float(d->sysfs_entry, "apbridge_unipro_latency_avg"); - - r->gbphy_firmware_latency_min = - read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_min"); - r->gbphy_firmware_latency_max = - read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_max"); - r->gbphy_firmware_latency_avg = - read_sysfs_float(d->sysfs_entry, "gbphy_firmware_latency_avg"); - - r->request_jitter = r->request_max - r->request_min; - r->latency_jitter = r->latency_max - r->latency_min; - r->throughput_jitter = r->throughput_max - r->throughput_min; - r->apbridge_unipro_latency_jitter = - r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min; - r->gbphy_firmware_latency_jitter = - r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min; - } - - /*calculate the aggregate results of all enabled devices */ - if (t->aggregate_output) { - r = &t->aggregate_results; - - r->request_min = get_request_min_aggregate(t); - r->request_max = get_request_max_aggregate(t); - r->request_avg = get_request_avg_aggregate(t); - - r->latency_min = get_latency_min_aggregate(t); - r->latency_max = get_latency_max_aggregate(t); - r->latency_avg = get_latency_avg_aggregate(t); - - r->throughput_min = get_throughput_min_aggregate(t); - r->throughput_max = get_throughput_max_aggregate(t); - r->throughput_avg = get_throughput_avg_aggregate(t); - - r->apbridge_unipro_latency_min = - get_apbridge_unipro_latency_min_aggregate(t); - r->apbridge_unipro_latency_max = - get_apbridge_unipro_latency_max_aggregate(t); - r->apbridge_unipro_latency_avg = - get_apbridge_unipro_latency_avg_aggregate(t); - - r->gbphy_firmware_latency_min = - get_gbphy_firmware_latency_min_aggregate(t); - r->gbphy_firmware_latency_max = - get_gbphy_firmware_latency_max_aggregate(t); - r->gbphy_firmware_latency_avg = - get_gbphy_firmware_latency_avg_aggregate(t); - - r->request_jitter = r->request_max - r->request_min; - r->latency_jitter = r->latency_max - r->latency_min; - r->throughput_jitter = r->throughput_max - r->throughput_min; - r->apbridge_unipro_latency_jitter = - r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min; - r->gbphy_firmware_latency_jitter = - r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min; - } - - return 0; -} - -int format_output(struct loopback_test *t, - struct loopback_results *r, - const char *dev_name, - char *buf, int buf_len, - struct tm *tm) -{ - int len = 0; - - memset(buf, 0x00, buf_len); - len = snprintf(buf, buf_len, "%u-%u-%u %u:%u:%u", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - if (t->porcelain) { - len += snprintf(&buf[len], buf_len - len, - "\n test:\t\t\t%s\n path:\t\t\t%s\n size:\t\t\t%u\n iterations:\t\t%u\n errors:\t\t%u\n async:\t\t\t%s\n", - t->test_name, - dev_name, - t->size, - t->iteration_max, - r->error, - t->use_async ? "Enabled" : "Disabled"); - - len += snprintf(&buf[len], buf_len - len, - " requests per-sec:\tmin=%u, max=%u, average=%f, jitter=%u\n", - r->request_min, - r->request_max, - r->request_avg, - r->request_jitter); - - len += snprintf(&buf[len], buf_len - len, - " ap-throughput B/s:\tmin=%u max=%u average=%f jitter=%u\n", - r->throughput_min, - r->throughput_max, - r->throughput_avg, - r->throughput_jitter); - len += snprintf(&buf[len], buf_len - len, - " ap-latency usec:\tmin=%u max=%u average=%f jitter=%u\n", - r->latency_min, - r->latency_max, - r->latency_avg, - r->latency_jitter); - len += snprintf(&buf[len], buf_len - len, - " apbridge-latency usec:\tmin=%u max=%u average=%f jitter=%u\n", - r->apbridge_unipro_latency_min, - r->apbridge_unipro_latency_max, - r->apbridge_unipro_latency_avg, - r->apbridge_unipro_latency_jitter); - - len += snprintf(&buf[len], buf_len - len, - " gbphy-latency usec:\tmin=%u max=%u average=%f jitter=%u\n", - r->gbphy_firmware_latency_min, - r->gbphy_firmware_latency_max, - r->gbphy_firmware_latency_avg, - r->gbphy_firmware_latency_jitter); - - } else { - len += snprintf(&buf[len], buf_len - len, ",%s,%s,%u,%u,%u", - t->test_name, dev_name, t->size, t->iteration_max, - r->error); - - len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u", - r->request_min, - r->request_max, - r->request_avg, - r->request_jitter); - - len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u", - r->latency_min, - r->latency_max, - r->latency_avg, - r->latency_jitter); - - len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u", - r->throughput_min, - r->throughput_max, - r->throughput_avg, - r->throughput_jitter); - - len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u", - r->apbridge_unipro_latency_min, - r->apbridge_unipro_latency_max, - r->apbridge_unipro_latency_avg, - r->apbridge_unipro_latency_jitter); - - len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u", - r->gbphy_firmware_latency_min, - r->gbphy_firmware_latency_max, - r->gbphy_firmware_latency_avg, - r->gbphy_firmware_latency_jitter); - } - - printf("\n%s\n", buf); - - return len; -} - -static int log_results(struct loopback_test *t) -{ - int fd, i, len, ret; - struct tm tm; - time_t local_time; - char file_name[MAX_SYSFS_PATH]; - char data[CSV_MAX_LINE]; - - local_time = time(NULL); - tm = *localtime(&local_time); - - /* - * file name will test_name_size_iteration_max.csv - * every time the same test with the same parameters is run we will then - * append to the same CSV with datestamp - representing each test - * dataset. - */ - if (t->file_output && !t->porcelain) { - snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv", - t->test_name, t->size, t->iteration_max); - - fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, 0644); - if (fd < 0) { - fprintf(stderr, "unable to open %s for appending\n", file_name); - abort(); - } - } - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - - len = format_output(t, &t->devices[i].results, - t->devices[i].name, - data, sizeof(data), &tm); - if (t->file_output && !t->porcelain) { - ret = write(fd, data, len); - if (ret == -1) - fprintf(stderr, "unable to write %d bytes to csv.\n", len); - } - } - - if (t->aggregate_output) { - len = format_output(t, &t->aggregate_results, "aggregate", - data, sizeof(data), &tm); - if (t->file_output && !t->porcelain) { - ret = write(fd, data, len); - if (ret == -1) - fprintf(stderr, "unable to write %d bytes to csv.\n", len); - } - } - - if (t->file_output && !t->porcelain) - close(fd); - - return 0; -} - -int is_loopback_device(const char *path, const char *node) -{ - char file[MAX_SYSFS_PATH]; - - snprintf(file, MAX_SYSFS_PATH, "%s%s/iteration_count", path, node); - if (access(file, F_OK) == 0) - return 1; - return 0; -} - -int find_loopback_devices(struct loopback_test *t) -{ - struct dirent **namelist; - int i, n, ret; - unsigned int dev_id; - struct loopback_device *d; - - n = scandir(t->sysfs_prefix, &namelist, NULL, alphasort); - if (n < 0) { - perror("scandir"); - ret = -ENODEV; - goto baddir; - } - - /* Don't include '.' and '..' */ - if (n <= 2) { - ret = -ENOMEM; - goto done; - } - - for (i = 0; i < n; i++) { - ret = sscanf(namelist[i]->d_name, "gb_loopback%u", &dev_id); - if (ret != 1) - continue; - - if (!is_loopback_device(t->sysfs_prefix, namelist[i]->d_name)) - continue; - - if (t->device_count == MAX_NUM_DEVICES) { - fprintf(stderr, "max number of devices reached!\n"); - break; - } - - d = &t->devices[t->device_count++]; - snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id); - - snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/", - t->sysfs_prefix, d->name); - - snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s", - t->debugfs_prefix, d->name); - - if (t->debug) - printf("add %s %s\n", d->sysfs_entry, d->debugfs_entry); - } - - ret = 0; -done: - for (i = 0; i < n; i++) - free(namelist[i]); - free(namelist); -baddir: - return ret; -} - -static int open_poll_files(struct loopback_test *t) -{ - struct loopback_device *dev; - char buf[MAX_SYSFS_PATH + MAX_STR_LEN]; - char dummy; - int fds_idx = 0; - int i; - - for (i = 0; i < t->device_count; i++) { - dev = &t->devices[i]; - - if (!device_enabled(t, i)) - continue; - - snprintf(buf, sizeof(buf), "%s%s", dev->sysfs_entry, "iteration_count"); - t->fds[fds_idx].fd = open(buf, O_RDONLY); - if (t->fds[fds_idx].fd < 0) { - fprintf(stderr, "Error opening poll file!\n"); - goto err; - } - read(t->fds[fds_idx].fd, &dummy, 1); - t->fds[fds_idx].events = POLLERR | POLLPRI; - t->fds[fds_idx].revents = 0; - fds_idx++; - } - - t->poll_count = fds_idx; - - return 0; - -err: - for (i = 0; i < fds_idx; i++) - close(t->fds[i].fd); - - return -1; -} - -static int close_poll_files(struct loopback_test *t) -{ - int i; - - for (i = 0; i < t->poll_count; i++) - close(t->fds[i].fd); - - return 0; -} -static int is_complete(struct loopback_test *t) -{ - int iteration_count; - int i; - - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - - iteration_count = read_sysfs_int(t->devices[i].sysfs_entry, - "iteration_count"); - - /* at least one device did not finish yet */ - if (iteration_count != t->iteration_max) - return 0; - } - - return 1; -} - -static void stop_tests(struct loopback_test *t) -{ - int i; - - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - write_sysfs_val(t->devices[i].sysfs_entry, "type", 0); - } -} - -static void handler(int sig) { /* do nothing */ } - -static int wait_for_complete(struct loopback_test *t) -{ - int number_of_events = 0; - char dummy; - int ret; - int i; - struct timespec *ts = NULL; - struct sigaction sa; - sigset_t mask_old, mask; - - sigemptyset(&mask); - sigemptyset(&mask_old); - sigaddset(&mask, SIGINT); - sigprocmask(SIG_BLOCK, &mask, &mask_old); - - sa.sa_handler = handler; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGINT, &sa, NULL) == -1) { - fprintf(stderr, "sigaction error\n"); - return -1; - } - - if (t->poll_timeout.tv_sec != 0) - ts = &t->poll_timeout; - - while (1) { - ret = ppoll(t->fds, t->poll_count, ts, &mask_old); - if (ret <= 0) { - stop_tests(t); - fprintf(stderr, "Poll exit with errno %d\n", errno); - return -1; - } - - for (i = 0; i < t->poll_count; i++) { - if (t->fds[i].revents & POLLPRI) { - /* Dummy read to clear the event */ - read(t->fds[i].fd, &dummy, 1); - number_of_events++; - } - } - - if (number_of_events == t->poll_count) - break; - } - - if (!is_complete(t)) { - fprintf(stderr, "Iteration count did not finish!\n"); - return -1; - } - - return 0; -} - -static void prepare_devices(struct loopback_test *t) -{ - int i; - - /* - * Cancel any running tests on enabled devices. If - * stop_all option is given, stop test on all devices. - */ - for (i = 0; i < t->device_count; i++) - if (t->stop_all || device_enabled(t, i)) - write_sysfs_val(t->devices[i].sysfs_entry, "type", 0); - - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - - write_sysfs_val(t->devices[i].sysfs_entry, "us_wait", - t->us_wait); - - /* Set operation size */ - write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size); - - /* Set iterations */ - write_sysfs_val(t->devices[i].sysfs_entry, "iteration_max", - t->iteration_max); - - if (t->use_async) { - write_sysfs_val(t->devices[i].sysfs_entry, "async", 1); - write_sysfs_val(t->devices[i].sysfs_entry, - "timeout", t->async_timeout); - write_sysfs_val(t->devices[i].sysfs_entry, - "outstanding_operations_max", - t->async_outstanding_operations); - } else { - write_sysfs_val(t->devices[i].sysfs_entry, "async", 0); - } - } -} - -static int start(struct loopback_test *t) -{ - int i; - - /* the test starts by writing test_id to the type file. */ - for (i = 0; i < t->device_count; i++) { - if (!device_enabled(t, i)) - continue; - - write_sysfs_val(t->devices[i].sysfs_entry, "type", t->test_id); - } - - return 0; -} - -void loopback_run(struct loopback_test *t) -{ - int i; - int ret; - - for (i = 0; dict[i].name != NULL; i++) { - if (strstr(dict[i].name, t->test_name)) - t->test_id = dict[i].type; - } - if (!t->test_id) { - fprintf(stderr, "invalid test %s\n", t->test_name); - usage(); - return; - } - - prepare_devices(t); - - ret = open_poll_files(t); - if (ret) - goto err; - - start(t); - - ret = wait_for_complete(t); - close_poll_files(t); - if (ret) - goto err; - - get_results(t); - - log_results(t); - - return; - -err: - printf("Error running test\n"); -} - -static int sanity_check(struct loopback_test *t) -{ - int i; - - if (t->device_count == 0) { - fprintf(stderr, "No loopback devices found\n"); - return -1; - } - - for (i = 0; i < MAX_NUM_DEVICES; i++) { - if (!device_enabled(t, i)) - continue; - - if (t->mask && !strcmp(t->devices[i].name, "")) { - fprintf(stderr, "Bad device mask %x\n", (1 << i)); - return -1; - } - } - - return 0; -} - -int main(int argc, char *argv[]) -{ - int o, ret; - char *sysfs_prefix = "/sys/class/gb_loopback/"; - char *debugfs_prefix = "/sys/kernel/debug/gb_loopback/"; - - memset(&t, 0, sizeof(t)); - - while ((o = getopt(argc, argv, - "t:s:i:S:D:m:v::d::r::p::a::l::x::o:O:c:w:z::f::")) != -1) { - switch (o) { - case 't': - snprintf(t.test_name, MAX_STR_LEN, "%s", optarg); - break; - case 's': - t.size = atoi(optarg); - break; - case 'i': - t.iteration_max = atoi(optarg); - break; - case 'S': - snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg); - break; - case 'D': - snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg); - break; - case 'm': - t.mask = atol(optarg); - break; - case 'v': - t.verbose = 1; - break; - case 'd': - t.debug = 1; - break; - case 'r': - t.raw_data_dump = 1; - break; - case 'p': - t.porcelain = 1; - break; - case 'a': - t.aggregate_output = 1; - break; - case 'l': - t.list_devices = 1; - break; - case 'x': - t.use_async = 1; - break; - case 'o': - t.async_timeout = atoi(optarg); - break; - case 'O': - t.poll_timeout.tv_sec = atoi(optarg); - break; - case 'c': - t.async_outstanding_operations = atoi(optarg); - break; - case 'w': - t.us_wait = atoi(optarg); - break; - case 'z': - t.file_output = 1; - break; - case 'f': - t.stop_all = 1; - break; - default: - usage(); - return -EINVAL; - } - } - - if (!strcmp(t.sysfs_prefix, "")) - snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", sysfs_prefix); - - if (!strcmp(t.debugfs_prefix, "")) - snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", debugfs_prefix); - - ret = find_loopback_devices(&t); - if (ret) - return ret; - ret = sanity_check(&t); - if (ret) - return ret; - - if (t.list_devices) { - show_loopback_devices(&t); - return 0; - } - - if (t.test_name[0] == '\0' || t.iteration_max == 0) - usage(); - - if (t.async_timeout == 0) - t.async_timeout = DEFAULT_ASYNC_TIMEOUT; - - loopback_run(&t); - - return 0; -} diff --git a/drivers/staging/greybus/vibrator.c b/drivers/staging/greybus/vibrator.c index 0e2b188e5ca3..227e18d92a95 100644 --- a/drivers/staging/greybus/vibrator.c +++ b/drivers/staging/greybus/vibrator.c @@ -107,7 +107,6 @@ ATTRIBUTE_GROUPS(vibrator); static struct class vibrator_class = { .name = "vibrator", - .owner = THIS_MODULE, .dev_groups = vibrator_groups, }; diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index afd05bf3345e..d3968fe2ebb8 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -10,7 +10,6 @@ source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/meter/Kconfig" source "drivers/staging/iio/resolver/Kconfig" endmenu diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 5ed56fe57e14..c50f1019f829 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -8,5 +8,4 @@ obj-y += adc/ obj-y += addac/ obj-y += frequency/ obj-y += impedance-analyzer/ -obj-y += meter/ obj-y += resolver/ diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig deleted file mode 100644 index aa6a3e7f6cdb..000000000000 --- a/drivers/staging/iio/meter/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# IIO meter drivers configuration -# -menu "Active energy metering IC" - -config ADE7854 - tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver" - depends on SPI || I2C - help - Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase - Multifunction Energy Metering IC Driver. - - To compile this driver as a module, choose M here: the - module will be called ade7854. - -config ADE7854_I2C - tristate "support I2C bus connection" - depends on ADE7854 && I2C - default y - help - Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called ade7854-i2c. - -config ADE7854_SPI - tristate "support SPI bus connection" - depends on ADE7854 && SPI - default y - help - Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus. - - To compile this driver as a module, choose M here: the - module will be called ade7854-spi. - -endmenu diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile deleted file mode 100644 index ed4547e38f3a..000000000000 --- a/drivers/staging/iio/meter/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for metering ic drivers -# - -obj-$(CONFIG_ADE7854) += ade7854.o -obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o -obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c deleted file mode 100644 index 572d714eb0dd..000000000000 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus) - * - * Copyright 2010 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include - -#include -#include "ade7854.h" - -static int ade7854_i2c_write_reg(struct device *dev, - u16 reg_address, - u32 val, - int bits) -{ - int ret; - int count; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - - switch (bits) { - case 8: - st->tx[2] = val & 0xFF; - count = 3; - break; - case 16: - st->tx[2] = (val >> 8) & 0xFF; - st->tx[3] = val & 0xFF; - count = 4; - break; - case 24: - st->tx[2] = (val >> 16) & 0xFF; - st->tx[3] = (val >> 8) & 0xFF; - st->tx[4] = val & 0xFF; - count = 5; - break; - case 32: - st->tx[2] = (val >> 24) & 0xFF; - st->tx[3] = (val >> 16) & 0xFF; - st->tx[4] = (val >> 8) & 0xFF; - st->tx[5] = val & 0xFF; - count = 6; - break; - default: - ret = -EINVAL; - goto unlock; - } - - ret = i2c_master_send(st->i2c, st->tx, count); - -unlock: - mutex_unlock(&st->buf_lock); - - if (ret < 0) - return ret; - - return 0; -} - -static int ade7854_i2c_read_reg(struct device *dev, - u16 reg_address, - u32 *val, - int bits) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 2); - if (ret < 0) - goto unlock; - - ret = i2c_master_recv(st->i2c, st->rx, bits); - if (ret < 0) - goto unlock; - - switch (bits) { - case 8: - *val = st->rx[0]; - break; - case 16: - *val = (st->rx[0] << 8) | st->rx[1]; - break; - case 24: - *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; - break; - case 32: - *val = (st->rx[0] << 24) | (st->rx[1] << 16) | - (st->rx[2] << 8) | st->rx[3]; - break; - default: - ret = -EINVAL; - goto unlock; - } - -unlock: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_i2c_probe(struct i2c_client *client) -{ - struct ade7854_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - st->read_reg = ade7854_i2c_read_reg; - st->write_reg = ade7854_i2c_write_reg; - st->i2c = client; - st->irq = client->irq; - - return ade7854_probe(indio_dev, &client->dev); -} - -static const struct i2c_device_id ade7854_id[] = { - { "ade7854", 0 }, - { "ade7858", 0 }, - { "ade7868", 0 }, - { "ade7878", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ade7854_id); - -static struct i2c_driver ade7854_i2c_driver = { - .driver = { - .name = "ade7854", - }, - .probe_new = ade7854_i2c_probe, - .id_table = ade7854_id, -}; -module_i2c_driver(ade7854_i2c_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c deleted file mode 100644 index f12a6c8b3e88..000000000000 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (SPI Bus) - * - * Copyright 2010 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include - -#include -#include "ade7854.h" - -static int ade7854_spi_write_reg(struct device *dev, - u16 reg_address, - u32 val, - int bits) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 4, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_WRITE_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - switch (bits) { - case 8: - st->tx[3] = val & 0xFF; - break; - case 16: - xfer.len = 5; - st->tx[3] = (val >> 8) & 0xFF; - st->tx[4] = val & 0xFF; - break; - case 24: - xfer.len = 6; - st->tx[3] = (val >> 16) & 0xFF; - st->tx[4] = (val >> 8) & 0xFF; - st->tx[5] = val & 0xFF; - break; - case 32: - xfer.len = 7; - st->tx[3] = (val >> 24) & 0xFF; - st->tx[4] = (val >> 16) & 0xFF; - st->tx[5] = (val >> 8) & 0xFF; - st->tx[6] = val & 0xFF; - break; - default: - ret = -EINVAL; - goto unlock; - } - - ret = spi_sync_transfer(st->spi, &xfer, 1); -unlock: - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_spi_read_reg(struct device *dev, - u16 reg_address, - u32 *val, - int bits) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 3, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = bits, - } - }; - - mutex_lock(&st->buf_lock); - - st->tx[0] = ADE7854_READ_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - - ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - if (ret < 0) { - dev_err(&st->spi->dev, "problem when reading register 0x%02X", - reg_address); - goto unlock; - } - - switch (bits) { - case 8: - *val = st->rx[0]; - break; - case 16: - *val = be16_to_cpup((const __be16 *)st->rx); - break; - case 24: - *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; - break; - case 32: - *val = be32_to_cpup((const __be32 *)st->rx); - break; - } - -unlock: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_spi_probe(struct spi_device *spi) -{ - struct ade7854_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->read_reg = ade7854_spi_read_reg; - st->write_reg = ade7854_spi_write_reg; - st->irq = spi->irq; - st->spi = spi; - - return ade7854_probe(indio_dev, &spi->dev); -} - -static const struct spi_device_id ade7854_id[] = { - { "ade7854", 0 }, - { "ade7858", 0 }, - { "ade7868", 0 }, - { "ade7878", 0 }, - { } -}; -MODULE_DEVICE_TABLE(spi, ade7854_id); - -static struct spi_driver ade7854_driver = { - .driver = { - .name = "ade7854", - }, - .probe = ade7854_spi_probe, - .id_table = ade7854_id, -}; -module_spi_driver(ade7854_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 SPI Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c deleted file mode 100644 index 68da6ecde6a3..000000000000 --- a/drivers/staging/iio/meter/ade7854.c +++ /dev/null @@ -1,556 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver - * - * Copyright 2010 Analog Devices Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "meter.h" -#include "ade7854.h" - -static ssize_t ade7854_read_8bit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - u32 val = 0; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - ret = st->read_reg(dev, this_attr->address, &val, 8); - if (ret < 0) - return ret; - - return sprintf(buf, "%u\n", val); -} - -static ssize_t ade7854_read_16bit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - u32 val = 0; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - ret = st->read_reg(dev, this_attr->address, &val, 16); - if (ret < 0) - return ret; - - return sprintf(buf, "%u\n", val); -} - -static ssize_t ade7854_read_24bit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - u32 val; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - ret = st->read_reg(dev, this_attr->address, &val, 24); - if (ret < 0) - return ret; - - return sprintf(buf, "%u\n", val); -} - -static ssize_t ade7854_read_32bit(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - u32 val = 0; - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - ret = st->read_reg(dev, this_attr->address, &val, 32); - if (ret < 0) - return ret; - - return sprintf(buf, "%u\n", val); -} - -static ssize_t ade7854_write_8bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - int ret; - u8 val; - - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - ret = st->write_reg(dev, this_attr->address, val, 8); - -error_ret: - return ret ? ret : len; -} - -static ssize_t ade7854_write_16bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - int ret; - u16 val; - - ret = kstrtou16(buf, 10, &val); - if (ret) - goto error_ret; - ret = st->write_reg(dev, this_attr->address, val, 16); - -error_ret: - return ret ? ret : len; -} - -static ssize_t ade7854_write_24bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - int ret; - u32 val; - - ret = kstrtou32(buf, 10, &val); - if (ret) - goto error_ret; - ret = st->write_reg(dev, this_attr->address, val, 24); - -error_ret: - return ret ? ret : len; -} - -static ssize_t ade7854_write_32bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - int ret; - u32 val; - - ret = kstrtou32(buf, 10, &val); - if (ret) - goto error_ret; - ret = st->write_reg(dev, this_attr->address, val, 32); - -error_ret: - return ret ? ret : len; -} - -static int ade7854_reset(struct device *dev) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - u32 val; - - st->read_reg(dev, ADE7854_CONFIG, &val, 16); - val |= BIT(7); /* Software Chip Reset */ - - return st->write_reg(dev, ADE7854_CONFIG, val, 16); -} - -static IIO_DEV_ATTR_AIGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AIGAIN); -static IIO_DEV_ATTR_BIGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BIGAIN); -static IIO_DEV_ATTR_CIGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CIGAIN); -static IIO_DEV_ATTR_NIGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_NIGAIN); -static IIO_DEV_ATTR_AVGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AVGAIN); -static IIO_DEV_ATTR_BVGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BVGAIN); -static IIO_DEV_ATTR_CVGAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CVGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AVAGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BVAGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CVAGAIN); -static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AWATTOS); -static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BWATTOS); -static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CWATTOS); -static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_AVAROS); -static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_BVAROS); -static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(0644, - ade7854_read_24bit, - ade7854_write_24bit, - ADE7854_CVAROS); -static IIO_DEV_ATTR_VPEAK(0644, - ade7854_read_32bit, - ade7854_write_32bit, - ADE7854_VPEAK); -static IIO_DEV_ATTR_IPEAK(0644, - ade7854_read_32bit, - ade7854_write_32bit, - ADE7854_IPEAK); -static IIO_DEV_ATTR_APHCAL(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_APHCAL); -static IIO_DEV_ATTR_BPHCAL(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_BPHCAL); -static IIO_DEV_ATTR_CPHCAL(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CPHCAL); -static IIO_DEV_ATTR_CF1DEN(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CF1DEN); -static IIO_DEV_ATTR_CF2DEN(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CF2DEN); -static IIO_DEV_ATTR_CF3DEN(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CF3DEN); -static IIO_DEV_ATTR_LINECYC(0644, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_LINECYC); -static IIO_DEV_ATTR_SAGCYC(0644, - ade7854_read_8bit, - ade7854_write_8bit, - ADE7854_SAGCYC); -static IIO_DEV_ATTR_CFCYC(0644, - ade7854_read_8bit, - ade7854_write_8bit, - ADE7854_CFCYC); -static IIO_DEV_ATTR_PEAKCYC(0644, - ade7854_read_8bit, - ade7854_write_8bit, - ADE7854_PEAKCYC); -static IIO_DEV_ATTR_CHKSUM(ade7854_read_24bit, - ADE7854_CHECKSUM); -static IIO_DEV_ATTR_ANGLE0(ade7854_read_24bit, - ADE7854_ANGLE0); -static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit, - ADE7854_ANGLE1); -static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit, - ADE7854_ANGLE2); -static IIO_DEV_ATTR_AIRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_AIRMS); -static IIO_DEV_ATTR_BIRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_BIRMS); -static IIO_DEV_ATTR_CIRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_CIRMS); -static IIO_DEV_ATTR_NIRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_NIRMS); -static IIO_DEV_ATTR_AVRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_AVRMS); -static IIO_DEV_ATTR_BVRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_BVRMS); -static IIO_DEV_ATTR_CVRMS(0444, - ade7854_read_24bit, - NULL, - ADE7854_CVRMS); -static IIO_DEV_ATTR_AIRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_AIRMSOS); -static IIO_DEV_ATTR_BIRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_BIRMSOS); -static IIO_DEV_ATTR_CIRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CIRMSOS); -static IIO_DEV_ATTR_AVRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_AVRMSOS); -static IIO_DEV_ATTR_BVRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_BVRMSOS); -static IIO_DEV_ATTR_CVRMSOS(0444, - ade7854_read_16bit, - ade7854_write_16bit, - ADE7854_CVRMSOS); -static IIO_DEV_ATTR_VOLT_A(ade7854_read_24bit, - ADE7854_VAWV); -static IIO_DEV_ATTR_VOLT_B(ade7854_read_24bit, - ADE7854_VBWV); -static IIO_DEV_ATTR_VOLT_C(ade7854_read_24bit, - ADE7854_VCWV); -static IIO_DEV_ATTR_CURRENT_A(ade7854_read_24bit, - ADE7854_IAWV); -static IIO_DEV_ATTR_CURRENT_B(ade7854_read_24bit, - ADE7854_IBWV); -static IIO_DEV_ATTR_CURRENT_C(ade7854_read_24bit, - ADE7854_ICWV); -static IIO_DEV_ATTR_AWATTHR(ade7854_read_32bit, - ADE7854_AWATTHR); -static IIO_DEV_ATTR_BWATTHR(ade7854_read_32bit, - ADE7854_BWATTHR); -static IIO_DEV_ATTR_CWATTHR(ade7854_read_32bit, - ADE7854_CWATTHR); -static IIO_DEV_ATTR_AFWATTHR(ade7854_read_32bit, - ADE7854_AFWATTHR); -static IIO_DEV_ATTR_BFWATTHR(ade7854_read_32bit, - ADE7854_BFWATTHR); -static IIO_DEV_ATTR_CFWATTHR(ade7854_read_32bit, - ADE7854_CFWATTHR); -static IIO_DEV_ATTR_AVARHR(ade7854_read_32bit, - ADE7854_AVARHR); -static IIO_DEV_ATTR_BVARHR(ade7854_read_32bit, - ADE7854_BVARHR); -static IIO_DEV_ATTR_CVARHR(ade7854_read_32bit, - ADE7854_CVARHR); -static IIO_DEV_ATTR_AVAHR(ade7854_read_32bit, - ADE7854_AVAHR); -static IIO_DEV_ATTR_BVAHR(ade7854_read_32bit, - ADE7854_BVAHR); -static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit, - ADE7854_CVAHR); - -static int ade7854_set_irq(struct device *dev, bool enable) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - int ret; - u32 irqen; - - ret = st->read_reg(dev, ADE7854_MASK0, &irqen, 32); - if (ret < 0) - return ret; - - if (enable) - irqen |= BIT(17); /* 1: interrupt enabled when all periodical - * (at 8 kHz rate) DSP computations finish. - */ - else - irqen &= ~BIT(17); - - return st->write_reg(dev, ADE7854_MASK0, irqen, 32); -} - -static int ade7854_initial_setup(struct iio_dev *indio_dev) -{ - int ret; - struct device *dev = &indio_dev->dev; - - /* Disable IRQ */ - ret = ade7854_set_irq(dev, false); - if (ret) { - dev_err(dev, "disable irq failed"); - goto err_ret; - } - - ade7854_reset(dev); - usleep_range(ADE7854_STARTUP_DELAY, ADE7854_STARTUP_DELAY + 100); - -err_ret: - return ret; -} - -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000"); - -static IIO_CONST_ATTR(name, "ade7854"); - -static struct attribute *ade7854_attributes[] = { - &iio_dev_attr_aigain.dev_attr.attr, - &iio_dev_attr_bigain.dev_attr.attr, - &iio_dev_attr_cigain.dev_attr.attr, - &iio_dev_attr_nigain.dev_attr.attr, - &iio_dev_attr_avgain.dev_attr.attr, - &iio_dev_attr_bvgain.dev_attr.attr, - &iio_dev_attr_cvgain.dev_attr.attr, - &iio_dev_attr_linecyc.dev_attr.attr, - &iio_dev_attr_sagcyc.dev_attr.attr, - &iio_dev_attr_cfcyc.dev_attr.attr, - &iio_dev_attr_peakcyc.dev_attr.attr, - &iio_dev_attr_chksum.dev_attr.attr, - &iio_dev_attr_apparent_power_a_gain.dev_attr.attr, - &iio_dev_attr_apparent_power_b_gain.dev_attr.attr, - &iio_dev_attr_apparent_power_c_gain.dev_attr.attr, - &iio_dev_attr_active_power_a_offset.dev_attr.attr, - &iio_dev_attr_active_power_b_offset.dev_attr.attr, - &iio_dev_attr_active_power_c_offset.dev_attr.attr, - &iio_dev_attr_reactive_power_a_gain.dev_attr.attr, - &iio_dev_attr_reactive_power_b_gain.dev_attr.attr, - &iio_dev_attr_reactive_power_c_gain.dev_attr.attr, - &iio_dev_attr_reactive_power_a_offset.dev_attr.attr, - &iio_dev_attr_reactive_power_b_offset.dev_attr.attr, - &iio_dev_attr_reactive_power_c_offset.dev_attr.attr, - &iio_dev_attr_awatthr.dev_attr.attr, - &iio_dev_attr_bwatthr.dev_attr.attr, - &iio_dev_attr_cwatthr.dev_attr.attr, - &iio_dev_attr_afwatthr.dev_attr.attr, - &iio_dev_attr_bfwatthr.dev_attr.attr, - &iio_dev_attr_cfwatthr.dev_attr.attr, - &iio_dev_attr_avarhr.dev_attr.attr, - &iio_dev_attr_bvarhr.dev_attr.attr, - &iio_dev_attr_cvarhr.dev_attr.attr, - &iio_dev_attr_angle0.dev_attr.attr, - &iio_dev_attr_angle1.dev_attr.attr, - &iio_dev_attr_angle2.dev_attr.attr, - &iio_dev_attr_avahr.dev_attr.attr, - &iio_dev_attr_bvahr.dev_attr.attr, - &iio_dev_attr_cvahr.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_const_attr_name.dev_attr.attr, - &iio_dev_attr_vpeak.dev_attr.attr, - &iio_dev_attr_ipeak.dev_attr.attr, - &iio_dev_attr_aphcal.dev_attr.attr, - &iio_dev_attr_bphcal.dev_attr.attr, - &iio_dev_attr_cphcal.dev_attr.attr, - &iio_dev_attr_cf1den.dev_attr.attr, - &iio_dev_attr_cf2den.dev_attr.attr, - &iio_dev_attr_cf3den.dev_attr.attr, - &iio_dev_attr_airms.dev_attr.attr, - &iio_dev_attr_birms.dev_attr.attr, - &iio_dev_attr_cirms.dev_attr.attr, - &iio_dev_attr_nirms.dev_attr.attr, - &iio_dev_attr_avrms.dev_attr.attr, - &iio_dev_attr_bvrms.dev_attr.attr, - &iio_dev_attr_cvrms.dev_attr.attr, - &iio_dev_attr_airmsos.dev_attr.attr, - &iio_dev_attr_birmsos.dev_attr.attr, - &iio_dev_attr_cirmsos.dev_attr.attr, - &iio_dev_attr_avrmsos.dev_attr.attr, - &iio_dev_attr_bvrmsos.dev_attr.attr, - &iio_dev_attr_cvrmsos.dev_attr.attr, - &iio_dev_attr_volt_a.dev_attr.attr, - &iio_dev_attr_volt_b.dev_attr.attr, - &iio_dev_attr_volt_c.dev_attr.attr, - &iio_dev_attr_current_a.dev_attr.attr, - &iio_dev_attr_current_b.dev_attr.attr, - &iio_dev_attr_current_c.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ade7854_attribute_group = { - .attrs = ade7854_attributes, -}; - -static const struct iio_info ade7854_info = { - .attrs = &ade7854_attribute_group, -}; - -int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) -{ - int ret; - struct ade7854_state *st = iio_priv(indio_dev); - /* setup the industrialio driver allocated elements */ - mutex_init(&st->buf_lock); - - indio_dev->dev.parent = dev; - indio_dev->info = &ade7854_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = devm_iio_device_register(dev, indio_dev); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - return ade7854_initial_setup(indio_dev); -} -EXPORT_SYMBOL(ade7854_probe); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Energy Meter"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h deleted file mode 100644 index 7a49f8f1016f..000000000000 --- a/drivers/staging/iio/meter/ade7854.h +++ /dev/null @@ -1,173 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ADE7854_H -#define _ADE7854_H - -#define ADE7854_AIGAIN 0x4380 -#define ADE7854_AVGAIN 0x4381 -#define ADE7854_BIGAIN 0x4382 -#define ADE7854_BVGAIN 0x4383 -#define ADE7854_CIGAIN 0x4384 -#define ADE7854_CVGAIN 0x4385 -#define ADE7854_NIGAIN 0x4386 -#define ADE7854_AIRMSOS 0x4387 -#define ADE7854_AVRMSOS 0x4388 -#define ADE7854_BIRMSOS 0x4389 -#define ADE7854_BVRMSOS 0x438A -#define ADE7854_CIRMSOS 0x438B -#define ADE7854_CVRMSOS 0x438C -#define ADE7854_NIRMSOS 0x438D -#define ADE7854_AVAGAIN 0x438E -#define ADE7854_BVAGAIN 0x438F -#define ADE7854_CVAGAIN 0x4390 -#define ADE7854_AWGAIN 0x4391 -#define ADE7854_AWATTOS 0x4392 -#define ADE7854_BWGAIN 0x4393 -#define ADE7854_BWATTOS 0x4394 -#define ADE7854_CWGAIN 0x4395 -#define ADE7854_CWATTOS 0x4396 -#define ADE7854_AVARGAIN 0x4397 -#define ADE7854_AVAROS 0x4398 -#define ADE7854_BVARGAIN 0x4399 -#define ADE7854_BVAROS 0x439A -#define ADE7854_CVARGAIN 0x439B -#define ADE7854_CVAROS 0x439C -#define ADE7854_AFWGAIN 0x439D -#define ADE7854_AFWATTOS 0x439E -#define ADE7854_BFWGAIN 0x439F -#define ADE7854_BFWATTOS 0x43A0 -#define ADE7854_CFWGAIN 0x43A1 -#define ADE7854_CFWATTOS 0x43A2 -#define ADE7854_AFVARGAIN 0x43A3 -#define ADE7854_AFVAROS 0x43A4 -#define ADE7854_BFVARGAIN 0x43A5 -#define ADE7854_BFVAROS 0x43A6 -#define ADE7854_CFVARGAIN 0x43A7 -#define ADE7854_CFVAROS 0x43A8 -#define ADE7854_VATHR1 0x43A9 -#define ADE7854_VATHR0 0x43AA -#define ADE7854_WTHR1 0x43AB -#define ADE7854_WTHR0 0x43AC -#define ADE7854_VARTHR1 0x43AD -#define ADE7854_VARTHR0 0x43AE -#define ADE7854_RSV 0x43AF -#define ADE7854_VANOLOAD 0x43B0 -#define ADE7854_APNOLOAD 0x43B1 -#define ADE7854_VARNOLOAD 0x43B2 -#define ADE7854_VLEVEL 0x43B3 -#define ADE7854_DICOEFF 0x43B5 -#define ADE7854_HPFDIS 0x43B6 -#define ADE7854_ISUMLVL 0x43B8 -#define ADE7854_ISUM 0x43BF -#define ADE7854_AIRMS 0x43C0 -#define ADE7854_AVRMS 0x43C1 -#define ADE7854_BIRMS 0x43C2 -#define ADE7854_BVRMS 0x43C3 -#define ADE7854_CIRMS 0x43C4 -#define ADE7854_CVRMS 0x43C5 -#define ADE7854_NIRMS 0x43C6 -#define ADE7854_RUN 0xE228 -#define ADE7854_AWATTHR 0xE400 -#define ADE7854_BWATTHR 0xE401 -#define ADE7854_CWATTHR 0xE402 -#define ADE7854_AFWATTHR 0xE403 -#define ADE7854_BFWATTHR 0xE404 -#define ADE7854_CFWATTHR 0xE405 -#define ADE7854_AVARHR 0xE406 -#define ADE7854_BVARHR 0xE407 -#define ADE7854_CVARHR 0xE408 -#define ADE7854_AFVARHR 0xE409 -#define ADE7854_BFVARHR 0xE40A -#define ADE7854_CFVARHR 0xE40B -#define ADE7854_AVAHR 0xE40C -#define ADE7854_BVAHR 0xE40D -#define ADE7854_CVAHR 0xE40E -#define ADE7854_IPEAK 0xE500 -#define ADE7854_VPEAK 0xE501 -#define ADE7854_STATUS0 0xE502 -#define ADE7854_STATUS1 0xE503 -#define ADE7854_OILVL 0xE507 -#define ADE7854_OVLVL 0xE508 -#define ADE7854_SAGLVL 0xE509 -#define ADE7854_MASK0 0xE50A -#define ADE7854_MASK1 0xE50B -#define ADE7854_IAWV 0xE50C -#define ADE7854_IBWV 0xE50D -#define ADE7854_ICWV 0xE50E -#define ADE7854_VAWV 0xE510 -#define ADE7854_VBWV 0xE511 -#define ADE7854_VCWV 0xE512 -#define ADE7854_AWATT 0xE513 -#define ADE7854_BWATT 0xE514 -#define ADE7854_CWATT 0xE515 -#define ADE7854_AVA 0xE519 -#define ADE7854_BVA 0xE51A -#define ADE7854_CVA 0xE51B -#define ADE7854_CHECKSUM 0xE51F -#define ADE7854_VNOM 0xE520 -#define ADE7854_PHSTATUS 0xE600 -#define ADE7854_ANGLE0 0xE601 -#define ADE7854_ANGLE1 0xE602 -#define ADE7854_ANGLE2 0xE603 -#define ADE7854_PERIOD 0xE607 -#define ADE7854_PHNOLOAD 0xE608 -#define ADE7854_LINECYC 0xE60C -#define ADE7854_ZXTOUT 0xE60D -#define ADE7854_COMPMODE 0xE60E -#define ADE7854_GAIN 0xE60F -#define ADE7854_CFMODE 0xE610 -#define ADE7854_CF1DEN 0xE611 -#define ADE7854_CF2DEN 0xE612 -#define ADE7854_CF3DEN 0xE613 -#define ADE7854_APHCAL 0xE614 -#define ADE7854_BPHCAL 0xE615 -#define ADE7854_CPHCAL 0xE616 -#define ADE7854_PHSIGN 0xE617 -#define ADE7854_CONFIG 0xE618 -#define ADE7854_MMODE 0xE700 -#define ADE7854_ACCMODE 0xE701 -#define ADE7854_LCYCMODE 0xE702 -#define ADE7854_PEAKCYC 0xE703 -#define ADE7854_SAGCYC 0xE704 -#define ADE7854_CFCYC 0xE705 -#define ADE7854_HSDC_CFG 0xE706 -#define ADE7854_CONFIG2 0xEC01 - -#define ADE7854_READ_REG 0x1 -#define ADE7854_WRITE_REG 0x0 - -#define ADE7854_MAX_TX 7 -#define ADE7854_MAX_RX 7 -#define ADE7854_STARTUP_DELAY 1000 - -#define ADE7854_SPI_SLOW (u32)(300 * 1000) -#define ADE7854_SPI_BURST (u32)(1000 * 1000) -#define ADE7854_SPI_FAST (u32)(2000 * 1000) - -/** - * struct ade7854_state - device instance specific data - * @spi: actual spi_device - * @read_reg Wrapper function for I2C and SPI read - * @write_reg Wrapper function for I2C and SPI write - * @indio_dev: industrial I/O device structure - * @buf_lock: mutex to protect tx and rx - * @tx: transmit buffer - * @rx: receive buffer - **/ -struct ade7854_state { - struct spi_device *spi; - struct i2c_client *i2c; - int (*read_reg)(struct device *dev, u16 reg_address, u32 *val, - int bits); - int (*write_reg)(struct device *dev, u16 reg_address, u32 val, - int bits); - int irq; - struct mutex buf_lock; - u8 tx[ADE7854_MAX_TX] __aligned(IIO_DMA_MINALIGN); - u8 rx[ADE7854_MAX_RX]; - -}; - -int ade7854_probe(struct iio_dev *indio_dev, struct device *dev); -int ade7854_remove(struct iio_dev *indio_dev); - -#endif diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h deleted file mode 100644 index 5ed59bf30a25..000000000000 --- a/drivers/staging/iio/meter/meter.h +++ /dev/null @@ -1,398 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _METER_H -#define _METER_H - -#include - -/* metering ic types of attribute */ - -#define IIO_DEV_ATTR_CURRENT_A_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_a_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_B_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_b_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_C_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_c_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VOLT_A_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(volt_a_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VOLT_B_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(volt_b_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VOLT_C_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(volt_c_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_a_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_b_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_c_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_a_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_b_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_c_offset, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_A_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_a_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_B_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_b_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_C_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(current_c_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(apparent_power_a_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(apparent_power_b_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(apparent_power_c_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_a_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_b_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(active_power_c_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_a_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_b_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CURRENT_A(_show, _addr) \ - IIO_DEVICE_ATTR(current_a, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CURRENT_B(_show, _addr) \ - IIO_DEVICE_ATTR(current_b, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CURRENT_C(_show, _addr) \ - IIO_DEVICE_ATTR(current_c, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_VOLT_A(_show, _addr) \ - IIO_DEVICE_ATTR(volt_a, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_VOLT_B(_show, _addr) \ - IIO_DEVICE_ATTR(volt_b, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_VOLT_C(_show, _addr) \ - IIO_DEVICE_ATTR(volt_c, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_AENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(aenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_LENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_RAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(raenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_LAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(laenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_VAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(vaenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_LVAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lvaenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_RVAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(rvaenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_LVARENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lvarenergy, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CHKSUM(_show, _addr) \ - IIO_DEVICE_ATTR(chksum, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ANGLE0(_show, _addr) \ - IIO_DEVICE_ATTR(angle0, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ANGLE1(_show, _addr) \ - IIO_DEVICE_ATTR(angle1, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_ANGLE2(_show, _addr) \ - IIO_DEVICE_ATTR(angle2, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_AWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(awatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_BWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(bwatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(cwatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_AFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(afwatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_BFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(bfwatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(cfwatthr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_AVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(avarhr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_BVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(bvarhr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(cvarhr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_AVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(avahr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_BVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(bvahr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_CVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(cvahr, 0444, _show, NULL, _addr) - -#define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_PHCAL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(phcal, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_APHCAL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(aphcal, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BPHCAL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bphcal, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CPHCAL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cphcal, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_APOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(apos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AAPOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(aapos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BAPOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bapos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CAPOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(capos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AVRMSGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(avrmsgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BVRMSGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bvrmsgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CVRMSGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cvrmsgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AIGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(aigain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BIGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bigain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CIGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cigain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_NIGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(nigain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AVGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(avgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BVGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bvgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CVGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cvgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_WGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(wgain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_WDIV(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(wdiv, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CFNUM(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cfnum, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CFDEN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cfden, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CF1DEN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cf1den, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CF2DEN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cf2den, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CF3DEN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cf3den, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_IRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(irms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vrms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AIRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(airms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BIRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(birms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CIRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cirms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_NIRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(nirms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AVRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(avrms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BVRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bvrms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CVRMS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cvrms, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_IRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(irmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vrmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AIRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(airmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BIRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(birmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CIRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cirmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_AVRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(avrmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_BVRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(bvrmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CVRMSOS(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cvrmsos, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VAGAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vagain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_PGA_GAIN(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(pga_gain, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VADIV(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vadiv, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_LINECYC(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(linecyc, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_SAGCYC(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(sagcyc, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_CFCYC(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(cfcyc, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_PEAKCYC(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(peakcyc, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_SAGLVL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(saglvl, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_IPKLVL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(ipklvl, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VPKLVL(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vpklvl, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_IPEAK(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(ipeak, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_RIPEAK(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(ripeak, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VPEAK(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vpeak, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_RVPEAK(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(rvpeak, _mode, _show, _store, _addr) - -#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr) - -/* active energy register, AENERGY, is more than half full */ -#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask) - -/* a SAG on the line voltage */ -#define IIO_EVENT_ATTR_LINE_VOLT_SAG(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(line_volt_sag, _evlist, _show, _store, _mask) - -/* - * Indicates the end of energy accumulation over an integer number - * of half line cycles - */ -#define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask) - -/* on the rising and falling edge of the voltage waveform */ -#define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask) - -/* the active energy register has overflowed */ -#define IIO_EVENT_ATTR_AENERGY_OVERFLOW(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(aenergy_overflow, _evlist, _show, _store, _mask) - -/* the apparent energy register has overflowed */ -#define IIO_EVENT_ATTR_VAENERGY_OVERFLOW(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(vaenergy_overflow, _evlist, _show, _store, _mask) - -/* the active energy register, VAENERGY, is more than half full */ -#define IIO_EVENT_ATTR_VAENERGY_HALF_FULL(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(vaenergy_half_full, _evlist, _show, _store, _mask) - -/* the power has gone from negative to positive */ -#define IIO_EVENT_ATTR_PPOS(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(ppos, _evlist, _show, _store, _mask) - -/* the power has gone from positive to negative */ -#define IIO_EVENT_ATTR_PNEG(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(pneg, _evlist, _show, _store, _mask) - -/* waveform sample from Channel 1 has exceeded the IPKLVL value */ -#define IIO_EVENT_ATTR_IPKLVL_EXC(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(ipklvl_exc, _evlist, _show, _store, _mask) - -/* waveform sample from Channel 2 has exceeded the VPKLVL value */ -#define IIO_EVENT_ATTR_VPKLVL_EXC(_evlist, _show, _store, _mask) \ - IIO_EVENT_ATTR_SH(vpklvl_exc, _evlist, _show, _store, _mask) - -#endif /* _METER_H */ diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index eb364639fa58..06de5823eb8e 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -102,7 +102,7 @@ struct ad2s1210_state { static const int ad2s1210_mode_vals[4][2] = { [MOD_POS] = { 0, 0 }, [MOD_VEL] = { 0, 1 }, - [MOD_CONFIG] = { 1, 0 }, + [MOD_CONFIG] = { 1, 1 }, }; static inline void ad2s1210_set_mode(enum ad2s1210_mode mode, diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 9429ee155910..af3825578d85 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -75,9 +75,8 @@ static void ks_wlan_hw_wakeup_task(struct work_struct *work) if (ps_status == PS_SNOOZE) { ks_wlan_hw_wakeup_request(priv); - time_left = wait_for_completion_interruptible_timeout( - &priv->psstatus.wakeup_wait, - msecs_to_jiffies(20)); + time_left = wait_for_completion_interruptible_timeout(&priv->psstatus.wakeup_wait, + msecs_to_jiffies(20)); if (time_left <= 0) { netdev_dbg(priv->net_dev, "wake up timeout or interrupted !!!\n"); schedule_work(&priv->wakeup_work); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 63de214916f5..c079368019e8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -373,7 +373,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd, static int ov2680_detect(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u32 high, low; + u32 high = 0, low = 0; int ret; u16 id; u8 revision; @@ -383,7 +383,7 @@ static int ov2680_detect(struct i2c_client *client) ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high); if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + dev_err(&client->dev, "sensor_id_high read failed (%d)\n", ret); return -ENODEV; } ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low); diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 32700cb8bc4d..ca2efcc21efe 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -354,7 +354,7 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, struct v4l2_subdev_state *sd_state) { int ret; - u32 hs_settle; + u32 hs_settle = 0; ret = imx8mq_mipi_csi_sw_reset(state); if (ret) diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c index 7a5f80e637a0..44d3252d4612 100644 --- a/drivers/staging/most/dim2/dim2.c +++ b/drivers/staging/most/dim2/dim2.c @@ -108,7 +108,10 @@ struct dim2_platform_data { u8 fcnt; }; -#define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface) +static inline struct dim2_hdm *iface_to_hdm(struct most_interface *iface) +{ + return container_of(iface, struct dim2_hdm, most_iface); +} /* Macro to identify a network status message */ #define PACKET_IS_NET_INFO(p) \ @@ -775,8 +778,7 @@ static int dim2_probe(struct platform_device *pdev) goto err_free_dev; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->io_base = devm_ioremap_resource(&pdev->dev, res); + dev->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dev->io_base)) { ret = PTR_ERR(dev->io_base); goto err_free_dev; @@ -906,13 +908,11 @@ err_free_dev: * * Unregister the interface from mostcore */ -static int dim2_remove(struct platform_device *pdev) +static void dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); most_deregister_interface(&dev->most_iface); - - return 0; } /* platform specific functions [[ */ @@ -987,7 +987,6 @@ static int rcar_gen2_enable(struct platform_device *pdev) writel(0x04, dev->io_base + 0x600); } - /* BBCR = 0b11 */ writel(0x03, dev->io_base + 0x500); writel(0x0002FF02, dev->io_base + 0x508); @@ -1091,7 +1090,7 @@ MODULE_DEVICE_TABLE(of, dim2_of_match); static struct platform_driver dim2_driver = { .probe = dim2_probe, - .remove = dim2_remove, + .remove_new = dim2_remove, .driver = { .name = "hdm_dim2", .of_match_table = dim2_of_match, diff --git a/drivers/staging/most/dim2/hal.c b/drivers/staging/most/dim2/hal.c index a5d40b5b138a..6abe3ab2b2cf 100644 --- a/drivers/staging/most/dim2/hal.c +++ b/drivers/staging/most/dim2/hal.c @@ -346,9 +346,8 @@ static void dim2_clear_ctram(void) dim2_clear_ctr(ctr_addr); } -static void dim2_configure_channel( - u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size, - u16 packet_length) +static void dim2_configure_channel(u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, + u16 hw_buffer_size, u16 packet_length) { dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length); dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0); diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c index df53a4c4f850..4e85e681922f 100644 --- a/drivers/staging/most/i2c/i2c.c +++ b/drivers/staging/most/i2c/i2c.c @@ -44,7 +44,10 @@ struct hdm_i2c { char name[64]; }; -#define to_hdm(iface) container_of(iface, struct hdm_i2c, most_iface) +static inline struct hdm_i2c *to_hdm(struct most_interface *iface) +{ + return container_of(iface, struct hdm_i2c, most_iface); +} static irqreturn_t most_irq_handler(int, void *); static void pending_rx_work(struct work_struct *); diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c index ffa97ef21ea5..6254a5df2502 100644 --- a/drivers/staging/most/video/video.c +++ b/drivers/staging/most/video/video.c @@ -365,8 +365,7 @@ static const struct video_device comp_videodev_template = { /**************************************************************************/ -static struct most_video_dev *get_comp_dev( - struct most_interface *iface, int channel_idx) +static struct most_video_dev *get_comp_dev(struct most_interface *iface, int channel_idx) { struct most_video_dev *mdev; unsigned long flags; diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index b3f114cb00dc..2823cacde130 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -882,7 +882,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) return 0; } -static int tegra_nvec_remove(struct platform_device *pdev) +static void tegra_nvec_remove(struct platform_device *pdev) { struct nvec_chip *nvec = platform_get_drvdata(pdev); @@ -893,8 +893,6 @@ static int tegra_nvec_remove(struct platform_device *pdev) cancel_work_sync(&nvec->tx_work); /* FIXME: needs check whether nvec is responsible for power off */ pm_power_off = NULL; - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -942,7 +940,7 @@ MODULE_DEVICE_TABLE(of, nvidia_nvec_of_match); static struct platform_driver nvec_device_driver = { .probe = tegra_nvec_probe, - .remove = tegra_nvec_remove, + .remove_new = tegra_nvec_remove, .driver = { .name = "nvec", .pm = &nvec_pm_ops, diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c index 386d619e3ee9..f9a1da952c0a 100644 --- a/drivers/staging/nvec/nvec_kbd.c +++ b/drivers/staging/nvec/nvec_kbd.c @@ -161,7 +161,7 @@ static int nvec_kbd_probe(struct platform_device *pdev) return 0; } -static int nvec_kbd_remove(struct platform_device *pdev) +static void nvec_kbd_remove(struct platform_device *pdev) { struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); char disable_kbd[] = { NVEC_KBD, DISABLE_KBD }, @@ -170,13 +170,11 @@ static int nvec_kbd_remove(struct platform_device *pdev) nvec_write_async(nvec, uncnfg_wake_key_reporting, 3); nvec_write_async(nvec, disable_kbd, 2); nvec_unregister_notifier(nvec, &keys_dev.notifier); - - return 0; } static struct platform_driver nvec_kbd_driver = { .probe = nvec_kbd_probe, - .remove = nvec_kbd_remove, + .remove_new = nvec_kbd_remove, .driver = { .name = "nvec-kbd", }, diff --git a/drivers/staging/nvec/nvec_paz00.c b/drivers/staging/nvec/nvec_paz00.c index 8b4da95081c8..55d59840fca4 100644 --- a/drivers/staging/nvec/nvec_paz00.c +++ b/drivers/staging/nvec/nvec_paz00.c @@ -14,9 +14,6 @@ #include #include "nvec.h" -#define to_nvec_led(led_cdev) \ - container_of(led_cdev, struct nvec_led, cdev) - #define NVEC_LED_REQ {'\x0d', '\x10', '\x45', '\x10', '\x00'} #define NVEC_LED_MAX 8 @@ -29,7 +26,7 @@ struct nvec_led { static void nvec_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct nvec_led *led = to_nvec_led(led_cdev); + struct nvec_led *led = container_of(led_cdev, struct nvec_led, cdev); unsigned char buf[] = NVEC_LED_REQ; buf[4] = value; diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c index b1ef196e1cfe..9943b1fff190 100644 --- a/drivers/staging/nvec/nvec_power.c +++ b/drivers/staging/nvec/nvec_power.c @@ -416,7 +416,7 @@ static int nvec_power_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(*psy); } -static int nvec_power_remove(struct platform_device *pdev) +static void nvec_power_remove(struct platform_device *pdev) { struct nvec_power *power = platform_get_drvdata(pdev); @@ -429,13 +429,11 @@ static int nvec_power_remove(struct platform_device *pdev) case BAT: power_supply_unregister(nvec_bat_psy); } - - return 0; } static struct platform_driver nvec_power_driver = { .probe = nvec_power_probe, - .remove = nvec_power_remove, + .remove_new = nvec_power_remove, .driver = { .name = "nvec-power", } diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index 06041c7f7d4f..cb6d71b8dc83 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -125,7 +125,7 @@ static int nvec_mouse_probe(struct platform_device *pdev) return 0; } -static int nvec_mouse_remove(struct platform_device *pdev) +static void nvec_mouse_remove(struct platform_device *pdev) { struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); @@ -133,8 +133,6 @@ static int nvec_mouse_remove(struct platform_device *pdev) ps2_stopstreaming(ps2_dev.ser_dev); nvec_unregister_notifier(nvec, &ps2_dev.notifier); serio_unregister_port(ps2_dev.ser_dev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -166,7 +164,7 @@ static SIMPLE_DEV_PM_OPS(nvec_mouse_pm_ops, nvec_mouse_suspend, static struct platform_driver nvec_mouse_driver = { .probe = nvec_mouse_probe, - .remove = nvec_mouse_remove, + .remove_new = nvec_mouse_remove, .driver = { .name = "nvec-mouse", .pm = &nvec_mouse_pm_ops, diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index f662739137b5..9eee28f2940c 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -924,7 +924,7 @@ static int cvm_oct_probe(struct platform_device *pdev) return 0; } -static int cvm_oct_remove(struct platform_device *pdev) +static void cvm_oct_remove(struct platform_device *pdev) { int port; @@ -965,7 +965,6 @@ static int cvm_oct_remove(struct platform_device *pdev) if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); - return 0; } static const struct of_device_id cvm_oct_match[] = { @@ -978,7 +977,7 @@ MODULE_DEVICE_TABLE(of, cvm_oct_match); static struct platform_driver cvm_oct_driver = { .probe = cvm_oct_probe, - .remove = cvm_oct_remove, + .remove_new = cvm_oct_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = cvm_oct_match, diff --git a/drivers/staging/octeon/octeon-stubs.h b/drivers/staging/octeon/octeon-stubs.h index 7a02e59e283f..3e7b92cd2e35 100644 --- a/drivers/staging/octeon/octeon-stubs.h +++ b/drivers/staging/octeon/octeon-stubs.h @@ -1372,9 +1372,7 @@ static inline void cvmx_fau_async_fetch_and_add32(uint64_t scraddr, int32_t value) { } -static inline union cvmx_gmxx_rxx_rx_inbnd cvmx_spi4000_check_speed( - int interface, - int port) +static inline union cvmx_gmxx_rxx_rx_inbnd cvmx_spi4000_check_speed(int interface, int port) { union cvmx_gmxx_rxx_rx_inbnd r; diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index b59f6a4cb611..f08fdf06d566 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1400,7 +1400,7 @@ static int __init pi433_init(void) if (status < 0) return status; - pi433_class = class_create(THIS_MODULE, "pi433"); + pi433_class = class_create("pi433"); if (IS_ERR(pi433_class)) { unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); diff --git a/drivers/staging/qlge/qlge_dbg.c b/drivers/staging/qlge/qlge_dbg.c index 66d28358342f..c7e865f515cf 100644 --- a/drivers/staging/qlge/qlge_dbg.c +++ b/drivers/staging/qlge/qlge_dbg.c @@ -351,26 +351,23 @@ static int qlge_get_xgmac_regs(struct qlge_adapter *qdev, u32 *buf, /* We're reading 400 xgmac registers, but we filter out * several locations that are non-responsive to reads. */ - if ((i == 0x00000114) || - (i == 0x00000118) || - (i == 0x0000013c) || - (i == 0x00000140) || - (i > 0x00000150 && i < 0x000001fc) || - (i > 0x00000278 && i < 0x000002a0) || - (i > 0x000002c0 && i < 0x000002cf) || - (i > 0x000002dc && i < 0x000002f0) || - (i > 0x000003c8 && i < 0x00000400) || - (i > 0x00000400 && i < 0x00000410) || - (i > 0x00000410 && i < 0x00000420) || - (i > 0x00000420 && i < 0x00000430) || - (i > 0x00000430 && i < 0x00000440) || - (i > 0x00000440 && i < 0x00000450) || - (i > 0x00000450 && i < 0x00000500) || - (i > 0x0000054c && i < 0x00000568) || - (i > 0x000005c8 && i < 0x00000600)) { + if ((i == 0x00000114) || (i == 0x00000118) || + (i == 0x0000013c) || (i == 0x00000140) || + (i > 0x00000150 && i < 0x000001fc) || + (i > 0x00000278 && i < 0x000002a0) || + (i > 0x000002c0 && i < 0x000002cf) || + (i > 0x000002dc && i < 0x000002f0) || + (i > 0x000003c8 && i < 0x00000400) || + (i > 0x00000400 && i < 0x00000410) || + (i > 0x00000410 && i < 0x00000420) || + (i > 0x00000420 && i < 0x00000430) || + (i > 0x00000430 && i < 0x00000440) || + (i > 0x00000440 && i < 0x00000450) || + (i > 0x00000450 && i < 0x00000500) || + (i > 0x0000054c && i < 0x00000568) || + (i > 0x000005c8 && i < 0x00000600)) { if (other_function) - status = - qlge_read_other_func_xgmac_reg(qdev, i, buf); + status = qlge_read_other_func_xgmac_reg(qdev, i, buf); else status = qlge_read_xgmac_reg(qdev, i, buf); diff --git a/drivers/staging/rtl8192e/rtl8192e/Makefile b/drivers/staging/rtl8192e/rtl8192e/Makefile index 75e6ec510555..a442d79ea71e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/Makefile +++ b/drivers/staging/rtl8192e/rtl8192e/Makefile @@ -4,7 +4,7 @@ r8192e_pci-objs := \ r8192E_phy.o \ r8192E_firmware.o \ r8192E_cmdpkt.o \ - r8192E_hwimg.o \ + table.o \ r8190P_rtl8256.o \ rtl_cam.o \ rtl_core.o \ diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h index ac192254a4bb..385cca79f484 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h @@ -103,21 +103,10 @@ enum rf_optype { struct bb_reg_definition { u32 rfintfs; - u32 rfintfi; u32 rfintfo; u32 rfintfe; u32 rf3wireOffset; - u32 rfLSSI_Select; - u32 rfTxGainStage; - u32 rfHSSIPara1; u32 rfHSSIPara2; - u32 rfSwitchControl; - u32 rfAGCControl1; - u32 rfAGCControl2; - u32 rfRxIQImbalance; - u32 rfRxAFE; - u32 rfTxIQImbalance; - u32 rfTxAFE; u32 rfLSSIReadBack; u32 rfLSSIReadBackPi; }; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 73a86e1d0701..bb4539e337c8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -22,9 +22,6 @@ void rtl92e_set_bandwidth(struct net_device *dev, } for (eRFPath = 0; eRFPath < priv->num_total_rf_path; eRFPath++) { - if (!rtl92e_is_legal_rf_path(dev, eRFPath)) - continue; - switch (bandwidth) { case HT_CHANNEL_WIDTH_20: rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, @@ -67,19 +64,14 @@ bool rtl92e_config_rf(struct net_device *dev) for (eRFPath = (enum rf90_radio_path)RF90_PATH_A; eRFPath < priv->num_total_rf_path; eRFPath++) { - if (!rtl92e_is_legal_rf_path(dev, eRFPath)) - continue; - pPhyReg = &priv->phy_reg_def[eRFPath]; switch (eRFPath) { case RF90_PATH_A: - case RF90_PATH_C: u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV); break; case RF90_PATH_B: - case RF90_PATH_D: u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16); break; @@ -120,12 +112,10 @@ bool rtl92e_config_rf(struct net_device *dev) switch (eRFPath) { case RF90_PATH_A: - case RF90_PATH_C: rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); break; case RF90_PATH_B: - case RF90_PATH_D: rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); break; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 0b5b2ae27f9e..aed53fedeb61 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -343,18 +343,11 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev) else priv->tx_pwr_data_read_from_eeprom = false; - priv->rf_type = RTL819X_DEFAULT_RF_TYPE; - if (priv->card_8192_version > VERSION_8190_BD) { if (!priv->autoload_fail_flag) { tempval = (rtl92e_eeprom_read(dev, (EEPROM_RFInd_PowerDiff >> 1))) & 0xff; priv->eeprom_legacy_ht_tx_pwr_diff = tempval & 0xf; - - if (tempval&0x80) - priv->rf_type = RF_1T2R; - else - priv->rf_type = RF_2T4R; } else { priv->eeprom_legacy_ht_tx_pwr_diff = 0x04; } @@ -433,26 +426,12 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev) rtl92e_init_adaptive_rate(dev); - priv->rf_chip = RF_8256; - if (priv->reg_chnl_plan == 0xf) priv->chnl_plan = priv->eeprom_chnl_plan; else priv->chnl_plan = priv->reg_chnl_plan; - if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304) - priv->customer_id = RT_CID_DLINK; - switch (priv->eeprom_customer_id) { - case EEPROM_CID_DEFAULT: - priv->customer_id = RT_CID_DEFAULT; - break; - case EEPROM_CID_CAMEO: - priv->customer_id = RT_CID_819x_CAMEO; - break; - case EEPROM_CID_RUNTOP: - priv->customer_id = RT_CID_819x_RUNTOP; - break; case EEPROM_CID_NetCore: priv->customer_id = RT_CID_819X_NETCORE; break; @@ -463,20 +442,6 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev) else priv->chnl_plan = 0x0; break; - case EEPROM_CID_Nettronix: - priv->customer_id = RT_CID_Nettronix; - break; - case EEPROM_CID_Pronet: - priv->customer_id = RT_CID_PRONET; - break; - case EEPROM_CID_DLINK: - priv->customer_id = RT_CID_DLINK; - break; - - case EEPROM_CID_WHQL: - break; - default: - break; } if (priv->chnl_plan > CHANNEL_PLAN_LEN - 1) @@ -512,16 +477,6 @@ static void _rtl92e_hwconfig(struct net_device *dev) regRATR = RATE_ALL_CCK; regRRSR = RATE_ALL_CCK; break; - case WIRELESS_MODE_A: - regBwOpMode = BW_OPMODE_5G | BW_OPMODE_20MHZ; - regRATR = RATE_ALL_OFDM_AG; - regRRSR = RATE_ALL_OFDM_AG; - break; - case WIRELESS_MODE_G: - regBwOpMode = BW_OPMODE_20MHZ; - regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; - regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; - break; case WIRELESS_MODE_AUTO: case WIRELESS_MODE_N_24G: regBwOpMode = BW_OPMODE_20MHZ; @@ -529,12 +484,7 @@ static void _rtl92e_hwconfig(struct net_device *dev) RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; break; - case WIRELESS_MODE_N_5G: - regBwOpMode = BW_OPMODE_5G; - regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | - RATE_ALL_OFDM_2SS; - regRRSR = RATE_ALL_OFDM_AG; - break; + case WIRELESS_MODE_G: default: regBwOpMode = BW_OPMODE_20MHZ; regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; @@ -547,8 +497,7 @@ static void _rtl92e_hwconfig(struct net_device *dev) u32 ratr_value; ratr_value = regRATR; - if (priv->rf_type == RF_1T2R) - ratr_value &= ~(RATE_ALL_OFDM_2SS); + ratr_value &= ~(RATE_ALL_OFDM_2SS); rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); } @@ -701,7 +650,7 @@ start: } if (priv->rst_progress == RESET_TYPE_NORESET) { - rtStatus = rtl92e_config_phy(dev); + rtStatus = rtl92e_config_rf(dev); if (!rtStatus) { netdev_info(dev, "RF Config failed\n"); return rtStatus; @@ -806,7 +755,7 @@ void rtl92e_link_change(struct net_device *dev) if (ieee->state == RTLLIB_LINKED) { _rtl92e_net_update(dev); - priv->ops->update_ratr_table(dev); + rtl92e_update_ratr_table(dev); if ((ieee->pairwise_key_type == KEY_TYPE_WEP40) || (ieee->pairwise_key_type == KEY_TYPE_WEP104)) rtl92e_enable_hw_security_config(dev); @@ -1515,9 +1464,7 @@ static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer, return; if (!prev_st->bIsCCK && prev_st->bPacketToSelf) { - for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) { - if (!rtl92e_is_legal_rf_path(priv->rtllib->dev, rfpath)) - continue; + for (rfpath = RF90_PATH_A; rfpath < priv->num_total_rf_path; rfpath++) { if (priv->stats.rx_rssi_percentage[rfpath] == 0) { priv->stats.rx_rssi_percentage[rfpath] = prev_st->RxMIMOSignalStrength[rfpath]; @@ -1895,14 +1842,10 @@ void rtl92e_update_ratr_table(struct net_device *dev) break; case IEEE_N_24G: case IEEE_N_5G: - if (ieee->ht_info->peer_mimo_ps == 0) { + if (ieee->ht_info->peer_mimo_ps == 0) ratr_value &= 0x0007F007; - } else { - if (priv->rf_type == RF_1T2R) - ratr_value &= 0x000FF007; - else - ratr_value &= 0x0F81F007; - } + else + ratr_value &= 0x000FF007; break; default: break; @@ -1970,15 +1913,6 @@ void rtl92e_disable_irq(struct net_device *dev) priv->irq_enabled = 0; } -void rtl92e_clear_irq(struct net_device *dev) -{ - u32 tmp; - - tmp = rtl92e_readl(dev, ISR); - rtl92e_writel(dev, ISR, tmp); -} - - void rtl92e_enable_rx(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 1713381dc2b4..fa3b71dbb091 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -18,7 +18,6 @@ void rtl92e_enable_rx(struct net_device *dev); void rtl92e_enable_tx(struct net_device *dev); void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); -void rtl92e_clear_irq(struct net_device *dev); void rtl92e_init_variables(struct net_device *dev); void rtl92e_start_beacon(struct net_device *dev); void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index b011ec8c8a41..ddf998cf2041 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -6,7 +6,7 @@ */ #include "rtl_core.h" #include "r8192E_hw.h" -#include "r8192E_hwimg.h" +#include "table.h" #include "r8192E_firmware.h" #include "r8192E_cmdpkt.h" #include diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h index 99640c4779f7..f4d4b01630a2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h @@ -30,15 +30,8 @@ enum baseband_config { #define EEPROM_TxPwIndex_CCK 0x2C #define EEPROM_TxPwIndex_OFDM_24G 0x3A -#define EEPROM_CID_DEFAULT 0x0 -#define EEPROM_CID_CAMEO 0x1 -#define EEPROM_CID_RUNTOP 0x2 #define EEPROM_CID_TOSHIBA 0x4 #define EEPROM_CID_NetCore 0x5 -#define EEPROM_CID_Nettronix 0x6 -#define EEPROM_CID_Pronet 0x7 -#define EEPROM_CID_DLINK 0x8 -#define EEPROM_CID_WHQL 0xFE enum _RTL8192PCI_HW { MAC0 = 0x000, MAC4 = 0x004, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h deleted file mode 100644 index 7d63f5a5c1b7..000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef __INC_HAL8192PciE_FW_IMG_H -#define __INC_HAL8192PciE_FW_IMG_H - -/*Created on 2008/11/18, 3: 7*/ - -#include - -#define PHY_REGArrayLengthPciE 1 -extern u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLengthPciE]; -#define PHY_REG_1T2RArrayLengthPciE 296 -extern u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE]; -#define RadioA_ArrayLengthPciE 246 -extern u32 Rtl8192PciERadioA_Array[RadioA_ArrayLengthPciE]; -#define RadioB_ArrayLengthPciE 78 -extern u32 Rtl8192PciERadioB_Array[RadioB_ArrayLengthPciE]; -#define RadioC_ArrayLengthPciE 2 -extern u32 Rtl8192PciERadioC_Array[RadioC_ArrayLengthPciE]; -#define RadioD_ArrayLengthPciE 2 -extern u32 Rtl8192PciERadioD_Array[RadioD_ArrayLengthPciE]; -#define MACPHY_ArrayLengthPciE 18 -extern u32 Rtl8192PciEMACPHY_Array[MACPHY_ArrayLengthPciE]; -#define MACPHY_Array_PGLengthPciE 30 -extern u32 Rtl8192PciEMACPHY_Array_PG[MACPHY_Array_PGLengthPciE]; -#define AGCTAB_ArrayLengthPciE 384 -extern u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLengthPciE]; - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index c6cbdea6d5b2..4b0ebe96302e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -12,25 +12,7 @@ #include "r8192E_phy.h" #include "rtl_dm.h" -#include "r8192E_hwimg.h" - -static u32 RF_CHANNEL_TABLE_ZEBRA[] = { - 0, - 0x085c, - 0x08dc, - 0x095c, - 0x09dc, - 0x0a5c, - 0x0adc, - 0x0b5c, - 0x0bdc, - 0x0c5c, - 0x0cdc, - 0x0d5c, - 0x0ddc, - 0x0e5c, - 0x0f72, -}; +#include "table.h" /*************************Define local function prototype**********************/ @@ -47,22 +29,6 @@ static u32 _rtl92e_calculate_bit_shift(u32 dwBitMask) return ffs(dwBitMask) - 1; } -u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath) -{ - u8 ret = 1; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->rf_type == RF_2T4R) - ret = 0; - else if (priv->rf_type == RF_1T2R) { - if (eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B) - ret = 1; - else if (eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D) - ret = 0; - } - return ret; -} - void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData) { @@ -98,24 +64,20 @@ static u32 _rtl92e_phy_rf_read(struct net_device *dev, Offset &= 0x3f; - if (priv->rf_chip == RF_8256) { - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); - if (Offset >= 31) { - priv->rf_reg_0value[eRFPath] |= 0x140; - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - NewOffset = Offset - 30; - } else if (Offset >= 16) { - priv->rf_reg_0value[eRFPath] |= 0x100; - priv->rf_reg_0value[eRFPath] &= (~0x40); - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - - NewOffset = Offset - 15; - } else - NewOffset = Offset; + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + if (Offset >= 31) { + priv->rf_reg_0value[eRFPath] |= 0x140; + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); + NewOffset = Offset - 30; + } else if (Offset >= 16) { + priv->rf_reg_0value[eRFPath] |= 0x100; + priv->rf_reg_0value[eRFPath] &= (~0x40); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); + NewOffset = Offset - 15; } else { NewOffset = Offset; } @@ -129,15 +91,12 @@ static u32 _rtl92e_phy_rf_read(struct net_device *dev, ret = rtl92e_get_bb_reg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); - if (priv->rf_chip == RF_8256) { - priv->rf_reg_0value[eRFPath] &= 0xebf; + priv->rf_reg_0value[eRFPath] &= 0xebf; - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); - } + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); return ret; @@ -152,24 +111,22 @@ static void _rtl92e_phy_rf_write(struct net_device *dev, struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath]; Offset &= 0x3f; - if (priv->rf_chip == RF_8256) { - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); - if (Offset >= 31) { - priv->rf_reg_0value[eRFPath] |= 0x140; - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - NewOffset = Offset - 30; - } else if (Offset >= 16) { - priv->rf_reg_0value[eRFPath] |= 0x100; - priv->rf_reg_0value[eRFPath] &= (~0x40); - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - NewOffset = Offset - 15; - } else - NewOffset = Offset; + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + + if (Offset >= 31) { + priv->rf_reg_0value[eRFPath] |= 0x140; + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); + NewOffset = Offset - 30; + } else if (Offset >= 16) { + priv->rf_reg_0value[eRFPath] |= 0x100; + priv->rf_reg_0value[eRFPath] &= (~0x40); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); + NewOffset = Offset - 15; } else { NewOffset = Offset; } @@ -181,15 +138,13 @@ static void _rtl92e_phy_rf_write(struct net_device *dev, if (Offset == 0x0) priv->rf_reg_0value[eRFPath] = Data; - if (priv->rf_chip == RF_8256) { - if (Offset != 0) { - priv->rf_reg_0value[eRFPath] &= 0xebf; - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->rf_reg_0value[eRFPath] << 16)); - } - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); + if (Offset != 0) { + priv->rf_reg_0value[eRFPath] &= 0xebf; + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->rf_reg_0value[eRFPath] << 16)); } + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); } void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, @@ -198,8 +153,6 @@ void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, struct r8192_priv *priv = rtllib_priv(dev); u32 Original_Value, BitShift, New_Value; - if (!rtl92e_is_legal_rf_path(dev, eRFPath)) - return; if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter) return; @@ -235,8 +188,6 @@ u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 Original_Value, Readback_Value, BitShift; struct r8192_priv *priv = rtllib_priv(dev); - if (!rtl92e_is_legal_rf_path(dev, eRFPath)) - return 0; if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter) return 0; mutex_lock(&priv->rf_mutex); @@ -307,12 +258,12 @@ void rtl92e_config_mac(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); if (priv->tx_pwr_data_read_from_eeprom) { - dwArrayLen = MACPHY_Array_PGLength; - pdwArray = Rtl819XMACPHY_Array_PG; + dwArrayLen = RTL8192E_MACPHY_ARR_PG_LEN; + pdwArray = RTL8192E_MACPHY_ARR_PG; } else { - dwArrayLen = MACPHY_ArrayLength; - pdwArray = Rtl819XMACPHY_Array; + dwArrayLen = RTL8192E_MACPHY_ARR_LEN; + pdwArray = RTL8192E_MACPHY_ARR; } for (i = 0; i < dwArrayLen; i += 3) { if (pdwArray[i] == 0x318) @@ -330,17 +281,11 @@ static void _rtl92e_phy_config_bb(struct net_device *dev, u8 ConfigType) u32 *Rtl819XPHY_REGArray_Table = NULL; u32 *Rtl819XAGCTAB_Array_Table = NULL; u16 AGCTAB_ArrayLen, PHY_REGArrayLen = 0; - struct r8192_priv *priv = rtllib_priv(dev); - AGCTAB_ArrayLen = AGCTAB_ArrayLength; - Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array; - if (priv->rf_type == RF_2T4R) { - PHY_REGArrayLen = PHY_REGArrayLength; - Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArray; - } else if (priv->rf_type == RF_1T2R) { - PHY_REGArrayLen = PHY_REG_1T2RArrayLength; - Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArray; - } + AGCTAB_ArrayLen = RTL8192E_AGCTAB_ARR_LEN; + Rtl819XAGCTAB_Array_Table = RTL8192E_AGCTAB_ARR; + PHY_REGArrayLen = RTL8192E_PHY_REG_1T2R_ARR_LEN; + Rtl819XPHY_REGArray_Table = RTL8192E_PHY_REG_1T2R_ARR; if (ConfigType == BB_CONFIG_PHY_REG) { for (i = 0; i < PHY_REGArrayLen; i += 2) { @@ -363,89 +308,21 @@ static void _rtl92e_init_bb_rf_reg_def(struct net_device *dev) priv->phy_reg_def[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; priv->phy_reg_def[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; - priv->phy_reg_def[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW; - priv->phy_reg_def[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW; - - priv->phy_reg_def[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; - priv->phy_reg_def[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB; - priv->phy_reg_def[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB; - priv->phy_reg_def[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB; priv->phy_reg_def[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; priv->phy_reg_def[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; - priv->phy_reg_def[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE; - priv->phy_reg_def[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE; priv->phy_reg_def[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; priv->phy_reg_def[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; - priv->phy_reg_def[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE; - priv->phy_reg_def[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE; priv->phy_reg_def[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; priv->phy_reg_def[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; - priv->phy_reg_def[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; - priv->phy_reg_def[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter; - - priv->phy_reg_def[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; - priv->phy_reg_def[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; - priv->phy_reg_def[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; - priv->phy_reg_def[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; - - priv->phy_reg_def[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; - priv->phy_reg_def[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; - priv->phy_reg_def[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; - priv->phy_reg_def[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; - - priv->phy_reg_def[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; - priv->phy_reg_def[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; - priv->phy_reg_def[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; - priv->phy_reg_def[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; priv->phy_reg_def[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; priv->phy_reg_def[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; - priv->phy_reg_def[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; - priv->phy_reg_def[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; - - priv->phy_reg_def[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; - priv->phy_reg_def[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; - priv->phy_reg_def[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; - priv->phy_reg_def[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; - - priv->phy_reg_def[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; - priv->phy_reg_def[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; - priv->phy_reg_def[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; - priv->phy_reg_def[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; - - priv->phy_reg_def[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; - priv->phy_reg_def[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; - priv->phy_reg_def[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; - priv->phy_reg_def[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; - - priv->phy_reg_def[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; - priv->phy_reg_def[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; - priv->phy_reg_def[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; - priv->phy_reg_def[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; - - priv->phy_reg_def[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE; - priv->phy_reg_def[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; - priv->phy_reg_def[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; - priv->phy_reg_def[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; - - priv->phy_reg_def[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; - priv->phy_reg_def[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; - priv->phy_reg_def[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; - priv->phy_reg_def[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; - - priv->phy_reg_def[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE; - priv->phy_reg_def[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; - priv->phy_reg_def[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; - priv->phy_reg_def[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; priv->phy_reg_def[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; priv->phy_reg_def[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; - priv->phy_reg_def[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; - priv->phy_reg_def[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; - } bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, @@ -534,12 +411,7 @@ static bool _rtl92e_bb_config_para_file(struct net_device *dev) _rtl92e_phy_config_bb(dev, BB_CONFIG_AGC_TAB); if (priv->ic_cut > VERSION_8190_BD) { - if (priv->rf_type == RF_2T4R) - dwRegValue = priv->antenna_tx_pwr_diff[2] << 8 | - priv->antenna_tx_pwr_diff[1] << 4 | - priv->antenna_tx_pwr_diff[0]; - else - dwRegValue = 0x0; + dwRegValue = 0x0; rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage, (bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue); @@ -590,53 +462,10 @@ void rtl92e_set_tx_power(struct net_device *dev, u8 channel) if (priv->epromtype == EEPROM_93C46) { powerlevel = priv->tx_pwr_level_cck[channel - 1]; powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1]; - } else if (priv->epromtype == EEPROM_93C56) { - if (priv->rf_type == RF_2T4R) { - priv->antenna_tx_pwr_diff[2] = 0; - priv->antenna_tx_pwr_diff[1] = 0; - priv->antenna_tx_pwr_diff[0] = 0; - - rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage, - (bXBTxAGC | bXCTxAGC | bXDTxAGC), 0); - } } - switch (priv->rf_chip) { - case RF_8225: - break; - case RF_8256: - rtl92e_set_cck_tx_power(dev, powerlevel); - rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); - break; - case RF_8258: - break; - default: - netdev_err(dev, "Invalid RF Chip ID.\n"); - break; - } -} -bool rtl92e_config_phy(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - bool rtStatus = true; - - switch (priv->rf_chip) { - case RF_8225: - break; - case RF_8256: - rtStatus = rtl92e_config_rf(dev); - break; - - case RF_8258: - break; - case RF_PSEUDO_11N: - break; - - default: - netdev_err(dev, "Invalid RF Chip ID.\n"); - break; - } - return rtStatus; + rtl92e_set_cck_tx_power(dev, powerlevel); + rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); } u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) @@ -646,50 +475,26 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) switch (eRFPath) { case RF90_PATH_A: - for (i = 0; i < RadioA_ArrayLength; i += 2) { - if (Rtl819XRadioA_Array[i] == 0xfe) { + for (i = 0; i < RTL8192E_RADIO_A_ARR_LEN; i += 2) { + if (RTL8192E_RADIO_A_ARR[i] == 0xfe) { msleep(100); continue; } - rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioA_Array[i], + rtl92e_set_rf_reg(dev, eRFPath, RTL8192E_RADIO_A_ARR[i], bMask12Bits, - Rtl819XRadioA_Array[i+1]); + RTL8192E_RADIO_A_ARR[i + 1]); } break; case RF90_PATH_B: - for (i = 0; i < RadioB_ArrayLength; i += 2) { - if (Rtl819XRadioB_Array[i] == 0xfe) { + for (i = 0; i < RTL8192E_RADIO_B_ARR_LEN; i += 2) { + if (RTL8192E_RADIO_B_ARR[i] == 0xfe) { msleep(100); continue; } - rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioB_Array[i], + rtl92e_set_rf_reg(dev, eRFPath, RTL8192E_RADIO_B_ARR[i], bMask12Bits, - Rtl819XRadioB_Array[i+1]); - - } - break; - case RF90_PATH_C: - for (i = 0; i < RadioC_ArrayLength; i += 2) { - if (Rtl819XRadioC_Array[i] == 0xfe) { - msleep(100); - continue; - } - rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioC_Array[i], - bMask12Bits, - Rtl819XRadioC_Array[i+1]); - - } - break; - case RF90_PATH_D: - for (i = 0; i < RadioD_ArrayLength; i += 2) { - if (Rtl819XRadioD_Array[i] == 0xfe) { - msleep(100); - continue; - } - rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioD_Array[i], - bMask12Bits, - Rtl819XRadioD_Array[i+1]); + RTL8192E_RADIO_B_ARR[i + 1]); } break; @@ -707,21 +512,8 @@ static void _rtl92e_set_tx_power_level(struct net_device *dev, u8 channel) u8 powerlevel = priv->tx_pwr_level_cck[channel - 1]; u8 powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1]; - switch (priv->rf_chip) { - case RF_8225: - break; - - case RF_8256: - rtl92e_set_cck_tx_power(dev, powerlevel); - rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); - break; - - case RF_8258: - break; - default: - netdev_warn(dev, "%s(): Invalid RF Chip ID\n", __func__); - break; - } + rtl92e_set_cck_tx_power(dev, powerlevel); + rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); } static u8 _rtl92e_phy_set_sw_chnl_cmd_array(struct net_device *dev, @@ -786,58 +578,25 @@ static u8 _rtl92e_phy_switch_channel_step(struct net_device *dev, u8 channel, 0, 0, 0); RfDependCmdCnt = 0; - switch (priv->rf_chip) { - case RF_8225: - if (!(channel >= 1 && channel <= 14)) { - netdev_err(dev, - "Invalid channel requested for 8225: %d\n", - channel); - return false; - } - _rtl92e_phy_set_sw_chnl_cmd_array(dev, - ieee->RfDependCmd, - RfDependCmdCnt++, - MAX_RFDEPENDCMD_CNT, - CmdID_RF_WriteReg, - rZebra1_Channel, - RF_CHANNEL_TABLE_ZEBRA[channel], - 10); - _rtl92e_phy_set_sw_chnl_cmd_array(dev, - ieee->RfDependCmd, - RfDependCmdCnt++, - MAX_RFDEPENDCMD_CNT, - CmdID_End, 0, 0, 0); - break; - case RF_8256: - if (!(channel >= 1 && channel <= 14)) { - netdev_err(dev, - "Invalid channel requested for 8256: %d\n", - channel); - return false; - } - _rtl92e_phy_set_sw_chnl_cmd_array(dev, - ieee->RfDependCmd, - RfDependCmdCnt++, - MAX_RFDEPENDCMD_CNT, - CmdID_RF_WriteReg, - rZebra1_Channel, - channel, 10); - _rtl92e_phy_set_sw_chnl_cmd_array(dev, - ieee->RfDependCmd, - RfDependCmdCnt++, - MAX_RFDEPENDCMD_CNT, - CmdID_End, 0, 0, 0); - break; - - case RF_8258: - break; - - default: - netdev_warn(dev, "Unknown RF Chip ID\n"); + if (!(channel >= 1 && channel <= 14)) { + netdev_err(dev, + "Invalid channel requested for 8256: %d\n", + channel); return false; } - + _rtl92e_phy_set_sw_chnl_cmd_array(dev, + ieee->RfDependCmd, + RfDependCmdCnt++, + MAX_RFDEPENDCMD_CNT, + CmdID_RF_WriteReg, + rZebra1_Channel, + channel, 10); + _rtl92e_phy_set_sw_chnl_cmd_array(dev, + ieee->RfDependCmd, + RfDependCmdCnt++, + MAX_RFDEPENDCMD_CNT, + CmdID_End, 0, 0, 0); do { switch (*stage) { @@ -937,15 +696,6 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel) switch (priv->rtllib->mode) { - case WIRELESS_MODE_A: - case WIRELESS_MODE_N_5G: - if (channel <= 14) { - netdev_warn(dev, - "Channel %d not available in 802.11a.\n", - channel); - return false; - } - break; case WIRELESS_MODE_B: if (channel > 14) { netdev_warn(dev, @@ -1078,10 +828,6 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); u8 regBwOpMode; - if (priv->rf_chip == RF_PSEUDO_11N) { - priv->set_bw_mode_in_progress = false; - return; - } if (!priv->up) { netdev_err(dev, "%s(): Driver is not initialized\n", __func__); return; @@ -1147,25 +893,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev) } - switch (priv->rf_chip) { - case RF_8225: - break; - - case RF_8256: - rtl92e_set_bandwidth(dev, priv->current_chnl_bw); - break; - - case RF_8258: - break; - - case RF_PSEUDO_11N: - break; - - default: - netdev_info(dev, "%s(): Unknown RFChipID: %d\n", __func__, - priv->rf_chip); - break; - } + rtl92e_set_bandwidth(dev, priv->current_chnl_bw); atomic_dec(&(priv->rtllib->atm_swbw)); priv->set_bw_mode_in_progress = false; @@ -1291,129 +1019,88 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev, return false; priv->set_rf_pwr_state_in_progress = true; - switch (priv->rf_chip) { - case RF_8256: - switch (rf_power_state) { - case rf_on: - if ((priv->rtllib->rf_power_state == rf_off) && - RT_IN_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC)) { - bool rtstatus; - u32 InitilizeCount = 3; - - do { - InitilizeCount--; - rtstatus = rtl92e_enable_nic(dev); - } while (!rtstatus && (InitilizeCount > 0)); - - if (!rtstatus) { - netdev_err(dev, - "%s(): Failed to initialize Adapter.\n", - __func__); - priv->set_rf_pwr_state_in_progress = false; - return false; - } - - RT_CLEAR_PS_LEVEL(psc, - RT_RF_OFF_LEVL_HALT_NIC); - } else { - rtl92e_writeb(dev, ANAPAR, 0x37); - mdelay(1); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, - 0x4, 0x1); - priv->hw_rf_off_action = 0; - - rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, - BIT4, 0x1); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, - 0x300, 0x3); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, - 0x18, 0x3); - rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, - 0x3, 0x3); - rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, - 0x3, 0x3); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, - 0x60, 0x3); + switch (rf_power_state) { + case rf_on: + if ((priv->rtllib->rf_power_state == rf_off) && + RT_IN_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC)) { + bool rtstatus; + u32 InitilizeCount = 3; + do { + InitilizeCount--; + rtstatus = rtl92e_enable_nic(dev); + } while (!rtstatus && (InitilizeCount > 0)); + if (!rtstatus) { + netdev_err(dev, + "%s(): Failed to initialize Adapter.\n", + __func__); + priv->set_rf_pwr_state_in_progress = false; + return false; } - - break; - - case rf_sleep: - if (priv->rtllib->rf_power_state == rf_off) - break; - - - for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { - ring = &priv->tx_ring[QueueID]; - - if (skb_queue_len(&ring->queue) == 0) { - QueueID++; - continue; - } else { - udelay(10); - i++; - } - - if (i >= MAX_DOZE_WAITING_TIMES_9x) - break; - } - rtl92e_set_rf_off(dev); - break; - - case rf_off: - for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { - ring = &priv->tx_ring[QueueID]; - - if (skb_queue_len(&ring->queue) == 0) { - QueueID++; - continue; - } else { - udelay(10); - i++; - } - - if (i >= MAX_DOZE_WAITING_TIMES_9x) - break; - } - - if (psc->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && - !RT_IN_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC)) { - rtl92e_disable_nic(dev); - RT_SET_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC); - } else if (!(psc->RegRfPsLevel & - RT_RF_OFF_LEVL_HALT_NIC)) { - rtl92e_set_rf_off(dev); - } - - break; - - default: - bResult = false; - netdev_warn(dev, - "%s(): Unknown state requested: 0x%X.\n", - __func__, rf_power_state); - break; + RT_CLEAR_PS_LEVEL(psc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + rtl92e_writeb(dev, ANAPAR, 0x37); + mdelay(1); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, + 0x4, 0x1); + priv->hw_rf_off_action = 0; + rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, + BIT4, 0x1); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, + 0x300, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, + 0x18, 0x3); + rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, + 0x3, 0x3); + rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, + 0x3, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, + 0x60, 0x3); } - break; - + case rf_sleep: + if (priv->rtllib->rf_power_state == rf_off) + break; + for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { + ring = &priv->tx_ring[QueueID]; + if (skb_queue_len(&ring->queue) == 0) { + QueueID++; + continue; + } else { + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) + break; + } + rtl92e_set_rf_off(dev); + break; + case rf_off: + for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) { + ring = &priv->tx_ring[QueueID]; + if (skb_queue_len(&ring->queue) == 0) { + QueueID++; + continue; + } else { + udelay(10); + i++; + } + if (i >= MAX_DOZE_WAITING_TIMES_9x) + break; + } + rtl92e_set_rf_off(dev); + break; default: - netdev_warn(dev, "%s(): Unknown RF type\n", __func__); + bResult = false; + netdev_warn(dev, + "%s(): Unknown state requested: 0x%X.\n", + __func__, rf_power_state); break; } if (bResult) { priv->rtllib->rf_power_state = rf_power_state; - - switch (priv->rf_chip) { - case RF_8256: - break; - - default: - netdev_warn(dev, "%s(): Unknown RF type\n", __func__); - break; - } } priv->set_rf_pwr_state_in_progress = false; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 75629f5df954..6c4c33ded6a9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -9,28 +9,6 @@ #define MAX_DOZE_WAITING_TIMES_9x 64 -#define AGCTAB_ArrayLength AGCTAB_ArrayLengthPciE -#define MACPHY_ArrayLength MACPHY_ArrayLengthPciE -#define RadioA_ArrayLength RadioA_ArrayLengthPciE -#define RadioB_ArrayLength RadioB_ArrayLengthPciE -#define MACPHY_Array_PGLength MACPHY_Array_PGLengthPciE -#define RadioC_ArrayLength RadioC_ArrayLengthPciE -#define RadioD_ArrayLength RadioD_ArrayLengthPciE -#define PHY_REGArrayLength PHY_REGArrayLengthPciE -#define PHY_REG_1T2RArrayLength PHY_REG_1T2RArrayLengthPciE - -#define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG -#define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array -#define Rtl819XRadioA_Array Rtl8192PciERadioA_Array -#define Rtl819XRadioB_Array Rtl8192PciERadioB_Array -#define Rtl819XRadioC_Array Rtl8192PciERadioC_Array -#define Rtl819XRadioD_Array Rtl8192PciERadioD_Array -#define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array -#define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray -#define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray - -extern u32 rtl819XAGCTAB_Array[]; - enum hw90_block { HW90_BLOCK_MAC = 0, HW90_BLOCK_PHY0 = 1, @@ -47,15 +25,6 @@ enum rf90_radio_path { RF90_PATH_MAX }; -#define bMaskByte0 0xff -#define bMaskByte1 0xff00 -#define bMaskByte2 0xff0000 -#define bMaskByte3 0xff000000 -#define bMaskHWord 0xffff0000 -#define bMaskLWord 0x0000ffff -#define bMaskDWord 0xffffffff - -u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath); void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask); @@ -70,7 +39,6 @@ bool rtl92e_check_bb_and_rf(struct net_device *dev, bool rtl92e_config_bb(struct net_device *dev); void rtl92e_get_tx_power(struct net_device *dev); void rtl92e_set_tx_power(struct net_device *dev, u8 channel); -bool rtl92e_config_phy(struct net_device *dev); u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); u8 rtl92e_set_channel(struct net_device *dev, u8 channel); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h index f846f109ed98..e1b30fbdf8cc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h @@ -48,41 +48,22 @@ #define rFPGA0_TxGainStage 0x80c #define rFPGA0_RFTiming1 0x810 #define rFPGA0_RFTiming2 0x814 -#define rFPGA0_XA_HSSIParameter1 0x820 #define rFPGA0_XA_HSSIParameter2 0x824 -#define rFPGA0_XB_HSSIParameter1 0x828 #define rFPGA0_XB_HSSIParameter2 0x82c -#define rFPGA0_XC_HSSIParameter1 0x830 -#define rFPGA0_XC_HSSIParameter2 0x834 -#define rFPGA0_XD_HSSIParameter1 0x838 -#define rFPGA0_XD_HSSIParameter2 0x83c #define rFPGA0_XA_LSSIParameter 0x840 #define rFPGA0_XB_LSSIParameter 0x844 -#define rFPGA0_XC_LSSIParameter 0x848 -#define rFPGA0_XD_LSSIParameter 0x84c #define rFPGA0_RFWakeUpParameter 0x850 #define rFPGA0_RFSleepUpParameter 0x854 -#define rFPGA0_XAB_SwitchControl 0x858 -#define rFPGA0_XCD_SwitchControl 0x85c #define rFPGA0_XA_RFInterfaceOE 0x860 #define rFPGA0_XB_RFInterfaceOE 0x864 -#define rFPGA0_XC_RFInterfaceOE 0x868 -#define rFPGA0_XD_RFInterfaceOE 0x86c #define rFPGA0_XAB_RFInterfaceSW 0x870 -#define rFPGA0_XCD_RFInterfaceSW 0x874 -#define rFPGA0_XAB_RFParameter 0x878 -#define rFPGA0_XCD_RFParameter 0x87c #define rFPGA0_AnalogParameter1 0x880 #define rFPGA0_AnalogParameter2 0x884 #define rFPGA0_AnalogParameter3 0x888 #define rFPGA0_AnalogParameter4 0x88c #define rFPGA0_XA_LSSIReadBack 0x8a0 #define rFPGA0_XB_LSSIReadBack 0x8a4 -#define rFPGA0_XC_LSSIReadBack 0x8a8 -#define rFPGA0_XD_LSSIReadBack 0x8ac #define rFPGA0_PSDReport 0x8b4 -#define rFPGA0_XAB_RFInterfaceRB 0x8e0 -#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Page 9 - RF mode & OFDM TxSC */ #define rFPGA1_RFMOD 0x900 @@ -113,15 +94,6 @@ #define rOFDM0_TRxPathEnable 0xc04 #define rOFDM0_TRMuxPar 0xc08 #define rOFDM0_TRSWIsolation 0xc0c -/* RxIQ DC offset, Rx digital filter, DC notch filter */ -#define rOFDM0_XARxAFE 0xc10 -#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */ -#define rOFDM0_XBRxAFE 0xc18 -#define rOFDM0_XBRxIQImbalance 0xc1c -#define rOFDM0_XCRxAFE 0xc20 -#define rOFDM0_XCRxIQImbalance 0xc24 -#define rOFDM0_XDRxAFE 0xc28 -#define rOFDM0_XDRxIQImbalance 0xc2c #define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ #define rOFDM0_RxDetector2 0xc34 /* SBD */ #define rOFDM0_RxDetector3 0xc38 /* Frame Sync */ @@ -132,25 +104,16 @@ #define rOFDM0_CCADropThreshold 0xc48 #define rOFDM0_ECCAThreshold 0xc4c /* Energy CCA */ #define rOFDM0_XAAGCCore1 0xc50 -#define rOFDM0_XAAGCCore2 0xc54 #define rOFDM0_XBAGCCore1 0xc58 -#define rOFDM0_XBAGCCore2 0xc5c #define rOFDM0_XCAGCCore1 0xc60 -#define rOFDM0_XCAGCCore2 0xc64 #define rOFDM0_XDAGCCore1 0xc68 -#define rOFDM0_XDAGCCore2 0xc6c #define rOFDM0_AGCParameter1 0xc70 #define rOFDM0_AGCParameter2 0xc74 #define rOFDM0_AGCRSSITable 0xc78 #define rOFDM0_HTSTFAGC 0xc7c #define rOFDM0_XATxIQImbalance 0xc80 #define rOFDM0_XATxAFE 0xc84 -#define rOFDM0_XBTxIQImbalance 0xc88 -#define rOFDM0_XBTxAFE 0xc8c #define rOFDM0_XCTxIQImbalance 0xc90 -#define rOFDM0_XCTxAFE 0xc94 -#define rOFDM0_XDTxIQImbalance 0xc98 -#define rOFDM0_XDTxAFE 0xc9c #define rOFDM0_RxHPParameter 0xce0 #define rOFDM0_TxPseudoNoiseWgt 0xce4 #define rOFDM0_FrameSync 0xcf0 diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 104b16cfa979..27040d1e3230 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -25,32 +25,10 @@ int hwwep = 1; static char *ifname = "wlan%d"; -static const struct rtl819x_ops rtl819xp_ops = { - .nic_type = NIC_8192E, - .get_eeprom_size = rtl92e_get_eeprom_size, - .init_adapter_variable = rtl92e_init_variables, - .initialize_adapter = rtl92e_start_adapter, - .link_change = rtl92e_link_change, - .tx_fill_descriptor = rtl92e_fill_tx_desc, - .tx_fill_cmd_descriptor = rtl92e_fill_tx_cmd_desc, - .rx_query_status_descriptor = rtl92e_get_rx_stats, - .rx_command_packet_handler = NULL, - .stop_adapter = rtl92e_stop_adapter, - .update_ratr_table = rtl92e_update_ratr_table, - .irq_enable = rtl92e_enable_irq, - .irq_disable = rtl92e_disable_irq, - .irq_clear = rtl92e_clear_irq, - .rx_enable = rtl92e_enable_rx, - .tx_enable = rtl92e_enable_tx, - .interrupt_recognized = rtl92e_ack_irq, - .tx_check_stuck_handler = rtl92e_is_tx_stuck, - .rx_check_stuck_handler = rtl92e_is_rx_stuck, -}; - static struct pci_device_id rtl8192_pci_id_tbl[] = { - {RTL_PCI_DEVICE(0x10ec, 0x8192, rtl819xp_ops)}, - {RTL_PCI_DEVICE(0x07aa, 0x0044, rtl819xp_ops)}, - {RTL_PCI_DEVICE(0x07aa, 0x0047, rtl819xp_ops)}, + {PCI_DEVICE(0x10ec, 0x8192)}, + {PCI_DEVICE(0x07aa, 0x0044)}, + {PCI_DEVICE(0x07aa, 0x0047)}, {} }; @@ -255,14 +233,14 @@ void rtl92e_irq_enable(struct net_device *dev) priv->irq_enabled = 1; - priv->ops->irq_enable(dev); + rtl92e_enable_irq(dev); } void rtl92e_irq_disable(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - priv->ops->irq_disable(dev); + rtl92e_disable_irq(dev); priv->irq_enabled = 0; } @@ -271,9 +249,6 @@ static void _rtl92e_set_chan(struct net_device *dev, short ch) { struct r8192_priv *priv = rtllib_priv(dev); - if (priv->chan_forced) - return; - priv->chan = ch; if (priv->rf_set_chan) @@ -333,8 +308,7 @@ static const struct rtllib_qos_parameters def_qos_parameters = { static void _rtl92e_update_beacon(void *data) { - struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, - update_beacon_wq.work); + struct r8192_priv *priv = container_of(data, struct r8192_priv, update_beacon_wq.work); struct net_device *dev = priv->rtllib->dev; struct rtllib_device *ieee = priv->rtllib; struct rtllib_network *net = &ieee->current_network; @@ -348,8 +322,7 @@ static void _rtl92e_update_beacon(void *data) static void _rtl92e_qos_activate(void *data) { - struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, - qos_activate); + struct r8192_priv *priv = container_of(data, struct r8192_priv, qos_activate); struct net_device *dev = priv->rtllib->dev; int i; @@ -499,7 +472,7 @@ static void _rtl92e_prepare_beacon(struct tasklet_struct *t) skb_push(pnewskb, priv->rtllib->tx_headroom); pdesc = &ring->desc[0]; - priv->ops->tx_fill_descriptor(dev, pdesc, tcb_desc, pnewskb); + rtl92e_fill_tx_desc(dev, pdesc, tcb_desc, pnewskb); __skb_queue_tail(&ring->queue, pnewskb); pdesc->OWN = 1; } @@ -605,8 +578,7 @@ static void _rtl92e_refresh_support_rate(struct r8192_priv *priv) { struct rtllib_device *ieee = priv->rtllib; - if (ieee->mode == WIRELESS_MODE_N_24G || - ieee->mode == WIRELESS_MODE_N_5G) { + if (ieee->mode == WIRELESS_MODE_N_24G) { memcpy(ieee->reg_dot11ht_oper_rate_set, ieee->reg_ht_supp_rate_set, 16); memcpy(ieee->reg_dot11tx_ht_oper_rate_set, @@ -617,52 +589,13 @@ static void _rtl92e_refresh_support_rate(struct r8192_priv *priv) } } -static u8 _rtl92e_get_supported_wireless_mode(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 ret = 0; - - switch (priv->rf_chip) { - case RF_8225: - case RF_8256: - case RF_6052: - case RF_PSEUDO_11N: - ret = (WIRELESS_MODE_N_24G | WIRELESS_MODE_G | WIRELESS_MODE_B); - break; - case RF_8258: - ret = (WIRELESS_MODE_A | WIRELESS_MODE_N_5G); - break; - default: - ret = WIRELESS_MODE_B; - break; - } - return ret; -} - void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) { struct r8192_priv *priv = rtllib_priv(dev); - u8 support_mode = _rtl92e_get_supported_wireless_mode(dev); + u8 support_mode = (WIRELESS_MODE_N_24G | WIRELESS_MODE_G | WIRELESS_MODE_B); - if ((wireless_mode == WIRELESS_MODE_AUTO) || - ((wireless_mode & support_mode) == 0)) { - if (support_mode & WIRELESS_MODE_N_24G) { - wireless_mode = WIRELESS_MODE_N_24G; - } else if (support_mode & WIRELESS_MODE_N_5G) { - wireless_mode = WIRELESS_MODE_N_5G; - } else if ((support_mode & WIRELESS_MODE_A)) { - wireless_mode = WIRELESS_MODE_A; - } else if ((support_mode & WIRELESS_MODE_G)) { - wireless_mode = WIRELESS_MODE_G; - } else if ((support_mode & WIRELESS_MODE_B)) { - wireless_mode = WIRELESS_MODE_B; - } else { - netdev_info(dev, - "%s(): Unsupported mode requested. Fallback to 802.11b\n", - __func__); - wireless_mode = WIRELESS_MODE_B; - } - } + if ((wireless_mode == WIRELESS_MODE_AUTO) || ((wireless_mode & support_mode) == 0)) + wireless_mode = WIRELESS_MODE_N_24G; if ((wireless_mode & (WIRELESS_MODE_B | WIRELESS_MODE_G)) == (WIRELESS_MODE_G | WIRELESS_MODE_B)) @@ -670,12 +603,11 @@ void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) priv->rtllib->mode = wireless_mode; - if ((wireless_mode == WIRELESS_MODE_N_24G) || - (wireless_mode == WIRELESS_MODE_N_5G)) { + if (wireless_mode == WIRELESS_MODE_N_24G) priv->rtllib->ht_info->enable_ht = 1; - } else { + else priv->rtllib->ht_info->enable_ht = 0; - } + _rtl92e_refresh_support_rate(priv); } @@ -692,7 +624,7 @@ static int _rtl92e_sta_up(struct net_device *dev, bool is_silent_reset) priv->rtllib->ieee_up = 1; priv->up_first_time = 0; - init_status = priv->ops->initialize_adapter(dev); + init_status = rtl92e_start_adapter(dev); if (!init_status) { netdev_err(dev, "%s(): Initialization failed!\n", __func__); return -1; @@ -713,6 +645,7 @@ static int _rtl92e_sta_up(struct net_device *dev, bool is_silent_reset) else netif_wake_queue(dev); + priv->bfirst_after_down = false; return 0; } @@ -725,8 +658,7 @@ static int _rtl92e_sta_down(struct net_device *dev, bool shutdownrf) if (priv->up == 0) return -1; - if (priv->rtllib->rtllib_ips_leave) - priv->rtllib->rtllib_ips_leave(dev); + priv->rtllib->rtllib_ips_leave(dev); if (priv->rtllib->state == RTLLIB_LINKED) rtl92e_leisure_ps_leave(dev); @@ -762,7 +694,7 @@ static int _rtl92e_sta_down(struct net_device *dev, bool shutdownrf) } priv->rf_change_in_progress = true; spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - priv->ops->stop_adapter(dev, false); + rtl92e_stop_adapter(dev, false); spin_lock_irqsave(&priv->rf_ps_lock, flags); priv->rf_change_in_progress = false; spin_unlock_irqrestore(&priv->rf_ps_lock, flags); @@ -779,7 +711,7 @@ static void _rtl92e_init_priv_handler(struct net_device *dev) priv->rtllib->softmac_hard_start_xmit = _rtl92e_hard_start_xmit; priv->rtllib->set_chan = _rtl92e_set_chan; - priv->rtllib->link_change = priv->ops->link_change; + priv->rtllib->link_change = rtl92e_link_change; priv->rtllib->softmac_data_hard_start_xmit = _rtl92e_hard_data_xmit; priv->rtllib->check_nic_enough_desc = _rtl92e_check_nic_enough_desc; priv->rtllib->handle_assoc_response = _rtl92e_handle_assoc_response; @@ -854,7 +786,6 @@ static void _rtl92e_init_priv_variable(struct net_device *dev) priv->rtllib->short_slot = 1; priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; priv->bcck_in_ch14 = false; - priv->bfsync_processing = false; priv->cck_present_attn = 0; priv->rfa_txpowertrackingindex = 0; priv->rfc_txpowertrackingindex = 0; @@ -913,22 +844,15 @@ static void _rtl92e_init_priv_task(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - INIT_WORK_RSL(&priv->reset_wq, (void *)_rtl92e_restart, dev); - INIT_WORK_RSL(&priv->rtllib->ips_leave_wq, (void *)rtl92e_ips_leave_wq, - dev); - INIT_DELAYED_WORK_RSL(&priv->watch_dog_wq, - (void *)_rtl92e_watchdog_wq_cb, dev); - INIT_DELAYED_WORK_RSL(&priv->txpower_tracking_wq, - (void *)rtl92e_dm_txpower_tracking_wq, dev); - INIT_DELAYED_WORK_RSL(&priv->rfpath_check_wq, - (void *)rtl92e_dm_rf_pathcheck_wq, dev); - INIT_DELAYED_WORK_RSL(&priv->update_beacon_wq, - (void *)_rtl92e_update_beacon, dev); - INIT_WORK_RSL(&priv->qos_activate, (void *)_rtl92e_qos_activate, dev); - INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_wakeup_wq, - (void *)rtl92e_hw_wakeup_wq, dev); - INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_sleep_wq, - (void *)rtl92e_hw_sleep_wq, dev); + INIT_WORK(&priv->reset_wq, (void *)_rtl92e_restart); + INIT_WORK(&priv->rtllib->ips_leave_wq, (void *)rtl92e_ips_leave_wq); + INIT_DELAYED_WORK(&priv->watch_dog_wq, (void *)_rtl92e_watchdog_wq_cb); + INIT_DELAYED_WORK(&priv->txpower_tracking_wq, (void *)rtl92e_dm_txpower_tracking_wq); + INIT_DELAYED_WORK(&priv->rfpath_check_wq, (void *)rtl92e_dm_rf_pathcheck_wq); + INIT_DELAYED_WORK(&priv->update_beacon_wq, (void *)_rtl92e_update_beacon); + INIT_WORK(&priv->qos_activate, (void *)_rtl92e_qos_activate); + INIT_DELAYED_WORK(&priv->rtllib->hw_wakeup_wq, (void *)rtl92e_hw_wakeup_wq); + INIT_DELAYED_WORK(&priv->rtllib->hw_sleep_wq, (void *)rtl92e_hw_sleep_wq); tasklet_setup(&priv->irq_rx_tasklet, _rtl92e_irq_rx_tasklet); tasklet_setup(&priv->irq_tx_tasklet, _rtl92e_irq_tx_tasklet); tasklet_setup(&priv->irq_prepare_beacon_tasklet, @@ -941,13 +865,6 @@ static short _rtl92e_get_channel_map(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); - if ((priv->rf_chip != RF_8225) && (priv->rf_chip != RF_8256) && - (priv->rf_chip != RF_6052)) { - netdev_err(dev, "%s: unknown rf chip, can't set channel map\n", - __func__); - return -1; - } - if (priv->chnl_plan >= COUNTRY_CODE_MAX) { netdev_info(dev, "rtl819x_init:Error channel plan! Set to default.\n"); @@ -974,8 +891,8 @@ static short _rtl92e_init(struct net_device *dev) _rtl92e_init_priv_variable(dev); _rtl92e_init_priv_lock(priv); _rtl92e_init_priv_task(dev); - priv->ops->get_eeprom_size(dev); - priv->ops->init_adapter_variable(dev); + rtl92e_get_eeprom_size(dev); + rtl92e_init_variables(dev); _rtl92e_get_channel_map(dev); rtl92e_dm_init(dev); @@ -1068,7 +985,7 @@ static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev) spin_unlock_irqrestore(&priv->irq_th_lock, flags); if (bCheckFwTxCnt) { - if (priv->ops->tx_check_stuck_handler(dev)) + if (rtl92e_is_tx_stuck(dev)) return RESET_TYPE_SILENT; } @@ -1077,9 +994,7 @@ static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev) static enum reset_type _rtl92e_rx_check_stuck(struct net_device *dev) { - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->ops->rx_check_stuck_handler(dev)) + if (rtl92e_is_rx_stuck(dev)) return RESET_TYPE_SILENT; return RESET_TYPE_NORESET; @@ -1410,16 +1325,14 @@ static void _rtl92e_watchdog_timer_cb(struct timer_list *t) ****************************************************************************/ void rtl92e_rx_enable(struct net_device *dev) { - struct r8192_priv *priv = rtllib_priv(dev); - - priv->ops->rx_enable(dev); + rtl92e_enable_rx(dev); } void rtl92e_tx_enable(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - priv->ops->tx_enable(dev); + rtl92e_enable_tx(dev); rtllib_reset_queue(priv->rtllib); } @@ -1581,7 +1494,7 @@ static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb) tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); - priv->ops->tx_fill_cmd_descriptor(dev, entry, tcb_desc, skb); + rtl92e_fill_tx_cmd_desc(dev, entry, tcb_desc, skb); __skb_queue_tail(&ring->queue, skb); spin_unlock_irqrestore(&priv->irq_th_lock, flags); @@ -1640,7 +1553,7 @@ static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb) if (priv->rtllib->LedControlHandler) priv->rtllib->LedControlHandler(dev, LED_CTL_TX); } - priv->ops->tx_fill_descriptor(dev, pdesc, tcb_desc, skb); + rtl92e_fill_tx_desc(dev, pdesc, tcb_desc, skb); __skb_queue_tail(&ring->queue, skb); pdesc->OWN = 1; spin_unlock_irqrestore(&priv->irq_th_lock, flags); @@ -1680,7 +1593,7 @@ static short _rtl92e_alloc_rx_ring(struct net_device *dev) priv->rx_buf[rx_queue_idx][i] = skb; mapping = (dma_addr_t *)skb->cb; *mapping = dma_map_single(&priv->pdev->dev, - skb_tail_pointer_rsl(skb), + skb_tail_pointer(skb), priv->rxbuffersize, DMA_FROM_DEVICE); if (dma_mapping_error(&priv->pdev->dev, *mapping)) { dev_kfree_skb_any(skb); @@ -1890,8 +1803,7 @@ static void _rtl92e_rx_normal(struct net_device *dev) if (pdesc->OWN) return; - if (!priv->ops->rx_query_status_descriptor(dev, &stats, - pdesc, skb)) + if (!rtl92e_get_rx_stats(dev, &stats, pdesc, skb)) goto done; new_skb = dev_alloc_skb(priv->rxbuffersize); /* if allocation of new skb failed - drop current packet @@ -1937,7 +1849,7 @@ static void _rtl92e_rx_normal(struct net_device *dev) priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]] = skb; *((dma_addr_t *)skb->cb) = dma_map_single(&priv->pdev->dev, - skb_tail_pointer_rsl(skb), + skb_tail_pointer(skb), priv->rxbuffersize, DMA_FROM_DEVICE); if (dma_mapping_error(&priv->pdev->dev, *((dma_addr_t *)skb->cb))) { dev_kfree_skb_any(skb); @@ -2062,14 +1974,13 @@ void rtl92e_commit(struct net_device *dev) return; rtllib_softmac_stop_protocol(priv->rtllib, 0, true); rtl92e_irq_disable(dev); - priv->ops->stop_adapter(dev, true); + rtl92e_stop_adapter(dev, true); _rtl92e_up(dev, false); } static void _rtl92e_restart(void *data) { - struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, - reset_wq); + struct r8192_priv *priv = container_of(data, struct r8192_priv, reset_wq); struct net_device *dev = priv->rtllib->dev; mutex_lock(&priv->wx_mutex); @@ -2118,7 +2029,7 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev) spin_lock_irqsave(&priv->irq_th_lock, flags); - priv->ops->interrupt_recognized(dev, &inta, &intb); + rtl92e_ack_irq(dev, &inta, &intb); if (!inta) { spin_unlock_irqrestore(&priv->irq_th_lock, flags); @@ -2214,10 +2125,8 @@ static int _rtl92e_pci_probe(struct pci_dev *pdev, unsigned long ioaddr = 0; struct net_device *dev = NULL; struct r8192_priv *priv = NULL; - struct rtl819x_ops *ops = (struct rtl819x_ops *)(id->driver_data); unsigned long pmem_start, pmem_len, pmem_flags; int err = -ENOMEM; - u8 revision_id; if (pci_enable_device(pdev)) { dev_err(&pdev->dev, "Failed to enable PCI device"); @@ -2276,13 +2185,6 @@ static int _rtl92e_pci_probe(struct pci_dev *pdev, dev->mem_start = ioaddr; dev->mem_end = ioaddr + pci_resource_len(pdev, 0); - pci_read_config_byte(pdev, 0x08, &revision_id); - /* If the revisionid is 0x10, the device uses rtl8192se. */ - if (pdev->device == 0x8192 && revision_id == 0x10) - goto err_unmap; - - priv->ops = ops; - if (!rtl92e_check_adapter(pdev, dev)) goto err_unmap; @@ -2383,7 +2285,7 @@ bool rtl92e_enable_nic(struct net_device *dev) return false; } - init_status = priv->ops->initialize_adapter(dev); + init_status = rtl92e_start_adapter(dev); if (!init_status) { netdev_warn(dev, "%s(): Initialization failed!\n", __func__); priv->bdisable_nic = false; @@ -2396,22 +2298,6 @@ bool rtl92e_enable_nic(struct net_device *dev) return init_status; } -bool rtl92e_disable_nic(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 tmp_state = 0; - - priv->bdisable_nic = true; - tmp_state = priv->rtllib->state; - rtllib_softmac_stop_protocol(priv->rtllib, 0, false); - priv->rtllib->state = tmp_state; - _rtl92e_cancel_deferred_work(priv); - rtl92e_irq_disable(dev); - - priv->ops->stop_adapter(dev, false); - return true; -} - module_pci_driver(rtl8192_pci_driver); void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index fd96eef90c7f..285dac32c074 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -52,22 +52,12 @@ #define DRV_AUTHOR "" #define DRV_VERSION "0014.0401.2010" -#define IS_HARDWARE_TYPE_8192SE(_priv) \ - (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192SE) - -#define RTL_PCI_DEVICE(vend, dev, cfg) \ - .vendor = (vend), .device = (dev), \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ - .driver_data = (kernel_ulong_t)&(cfg) - #define TOTAL_CAM_ENTRY 32 #define CAM_CONTENT_COUNT 8 #define HAL_HW_PCI_REVISION_ID_8192PCIE 0x01 #define HAL_HW_PCI_REVISION_ID_8192SE 0x10 -#define RTL819X_DEFAULT_RF_TYPE RF_1T2R - #define RTLLIB_WATCH_DOG_TIME 2000 #define MAX_DEV_ADDR_SIZE 8 /*support till 64 bit bus width OS*/ @@ -134,24 +124,10 @@ enum dcmg_txcmd_op { TXCMD_XXXX_CTRL, }; -enum rt_rf_type_819xu { - RF_TYPE_MIN = 0, - RF_8225, - RF_8256, - RF_8258, - RF_6052 = 4, - RF_PSEUDO_11N = 5, -}; - enum rt_customer_id { RT_CID_DEFAULT = 0, - RT_CID_819x_CAMEO = 6, - RT_CID_819x_RUNTOP = 7, RT_CID_TOSHIBA = 9, RT_CID_819X_NETCORE = 10, - RT_CID_Nettronix = 11, - RT_CID_DLINK = 12, - RT_CID_PRONET = 13, }; enum reset_type { @@ -203,41 +179,6 @@ struct rtl8192_tx_ring { struct sk_buff_head queue; }; -struct rtl819x_ops { - enum nic_t nic_type; - void (*get_eeprom_size)(struct net_device *dev); - void (*init_adapter_variable)(struct net_device *dev); - void (*init_before_adapter_start)(struct net_device *dev); - bool (*initialize_adapter)(struct net_device *dev); - void (*link_change)(struct net_device *dev); - void (*tx_fill_descriptor)(struct net_device *dev, - struct tx_desc *tx_desc, - struct cb_desc *cb_desc, - struct sk_buff *skb); - void (*tx_fill_cmd_descriptor)(struct net_device *dev, - struct tx_desc_cmd *entry, - struct cb_desc *cb_desc, - struct sk_buff *skb); - bool (*rx_query_status_descriptor)(struct net_device *dev, - struct rtllib_rx_stats *stats, - struct rx_desc *pdesc, - struct sk_buff *skb); - bool (*rx_command_packet_handler)(struct net_device *dev, - struct sk_buff *skb, - struct rx_desc *pdesc); - void (*stop_adapter)(struct net_device *dev, bool reset); - void (*update_ratr_table)(struct net_device *dev); - void (*irq_enable)(struct net_device *dev); - void (*irq_disable)(struct net_device *dev); - void (*irq_clear)(struct net_device *dev); - void (*rx_enable)(struct net_device *dev); - void (*tx_enable)(struct net_device *dev); - void (*interrupt_recognized)(struct net_device *dev, - u32 *p_inta, u32 *p_intb); - bool (*tx_check_stuck_handler)(struct net_device *dev); - bool (*rx_check_stuck_handler)(struct net_device *dev); -}; - struct r8192_priv { struct pci_dev *pdev; struct pci_dev *bridge_pdev; @@ -255,14 +196,12 @@ struct r8192_priv { struct delayed_work txpower_tracking_wq; struct delayed_work rfpath_check_wq; struct delayed_work gpio_change_rf_wq; - struct rtl819x_ops *ops; struct rtllib_device *rtllib; struct work_struct reset_wq; enum rt_customer_id customer_id; - enum rt_rf_type_819xu rf_chip; enum ht_channel_width current_chnl_bw; struct bb_reg_definition phy_reg_def[4]; struct rate_adaptive rate_adaptive; @@ -342,7 +281,6 @@ struct r8192_priv { enum nic_t card_8192; u8 card_8192_version; - u8 rf_type; u8 ic_cut; char nick[IW_ESSID_MAX_SIZE + 1]; u8 check_roaming_cnt; @@ -419,7 +357,6 @@ struct r8192_priv { u8 rfa_txpowertrackingindex_real; u8 rfa_txpowertracking_default; u8 rfc_txpowertrackingindex; - u8 rfc_txpowertrackingindex_real; bool btxpower_tracking; bool bcck_in_ch14; @@ -438,14 +375,11 @@ struct r8192_priv { bool bcurrent_turbo_EDCA; bool bis_cur_rdlstate; - bool bfsync_processing; u32 rate_record; u32 rate_count_diff_rec; u32 continue_diff_count; bool bswitch_fsync; u8 framesync; - u8 frame_sync_monitor; - u32 reset_count; enum reset_type rst_progress; @@ -454,8 +388,6 @@ struct r8192_priv { bool reset_in_progress; bool force_reset; bool force_lps; - - bool chan_forced; }; extern const struct ethtool_ops rtl819x_ethtool_ops; @@ -495,7 +427,6 @@ u8 rtl92e_rx_db_to_percent(s8 antpower); void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); bool rtl92e_enable_nic(struct net_device *dev); -bool rtl92e_disable_nic(struct net_device *dev); bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state state_to_set, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index d8408acfc763..56a8ec517c06 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -173,7 +173,6 @@ static void _rtl92e_dm_pd_th(struct net_device *dev); static void _rtl92e_dm_cs_ratio(struct net_device *dev); static void _rtl92e_dm_init_cts_to_self(struct net_device *dev); -static void _rtl92e_dm_init_wa_broadcom_iot(struct net_device *dev); static void _rtl92e_dm_check_edca_turbo(struct net_device *dev); static void _rtl92e_dm_check_rx_path_selection(struct net_device *dev); @@ -214,11 +213,8 @@ void rtl92e_dm_init(struct net_device *dev) _rtl92e_dm_init_fsync(dev); _rtl92e_dm_init_rx_path_selection(dev); _rtl92e_dm_init_cts_to_self(dev); - if (IS_HARDWARE_TYPE_8192SE(dev)) - _rtl92e_dm_init_wa_broadcom_iot(dev); - INIT_DELAYED_WORK_RSL(&priv->gpio_change_rf_wq, - (void *)_rtl92e_dm_check_rf_ctrl_gpio, dev); + INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, (void *)_rtl92e_dm_check_rf_ctrl_gpio); } void rtl92e_dm_deinit(struct net_device *dev) @@ -273,26 +269,14 @@ void rtl92e_init_adaptive_rate(struct net_device *dev) pra->ping_rssi_enable = 0; pra->ping_rssi_thresh_for_ra = 15; - - if (priv->rf_type == RF_2T4R) { - pra->upper_rssi_threshold_ratr = 0x8f0f0000; - pra->middle_rssi_threshold_ratr = 0x8f0ff000; - pra->low_rssi_threshold_ratr = 0x8f0ff001; - pra->low_rssi_threshold_ratr_40M = 0x8f0ff005; - pra->low_rssi_threshold_ratr_20M = 0x8f0ff001; - pra->ping_rssi_ratr = 0x0000000d; - } else if (priv->rf_type == RF_1T2R) { - pra->upper_rssi_threshold_ratr = 0x000fc000; - pra->middle_rssi_threshold_ratr = 0x000ff000; - pra->low_rssi_threshold_ratr = 0x000ff001; - pra->low_rssi_threshold_ratr_40M = 0x000ff005; - pra->low_rssi_threshold_ratr_20M = 0x000ff001; - pra->ping_rssi_ratr = 0x0000000d; - } - + pra->upper_rssi_threshold_ratr = 0x000fc000; + pra->middle_rssi_threshold_ratr = 0x000ff000; + pra->low_rssi_threshold_ratr = 0x000ff001; + pra->low_rssi_threshold_ratr_40M = 0x000ff005; + pra->low_rssi_threshold_ratr_20M = 0x000ff001; + pra->ping_rssi_ratr = 0x0000000d; } - static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -309,8 +293,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev) if (pra->rate_adaptive_disabled) return; - if (!(priv->rtllib->mode == WIRELESS_MODE_N_24G || - priv->rtllib->mode == WIRELESS_MODE_N_5G)) + if (priv->rtllib->mode != WIRELESS_MODE_N_24G) return; if (priv->rtllib->state == RTLLIB_LINKED) { @@ -391,8 +374,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev) u32 ratr_value; ratr_value = targetRATR; - if (priv->rf_type == RF_1T2R) - ratr_value &= ~(RATE_ALL_OFDM_2SS); + ratr_value &= ~(RATE_ALL_OFDM_2SS); rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); @@ -490,93 +472,39 @@ static u8 CCKSwingTable_Ch14[CCK_TABLE_LEN][8] = { #define Tssi_Report_Value2 0x13e #define FW_Busy_Flag 0x13f -static void _rtl92e_dm_tx_update_tssi_weak_signal(struct net_device *dev, - u8 RF_Type) +static void _rtl92e_dm_tx_update_tssi_weak_signal(struct net_device *dev) { struct r8192_priv *p = rtllib_priv(dev); - if (RF_Type == RF_2T4R) { - if ((p->rfa_txpowertrackingindex > 0) && - (p->rfc_txpowertrackingindex > 0)) { - p->rfa_txpowertrackingindex--; - if (p->rfa_txpowertrackingindex_real > 4) { - p->rfa_txpowertrackingindex_real--; - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); - } - - p->rfc_txpowertrackingindex--; - if (p->rfc_txpowertrackingindex_real > 4) { - p->rfc_txpowertrackingindex_real--; - rtl92e_set_bb_reg(dev, - rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); - } - } else { - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[4]); + if (p->rfa_txpowertrackingindex > 0) { + p->rfa_txpowertrackingindex--; + if (p->rfa_txpowertrackingindex_real > 4) { + p->rfa_txpowertrackingindex_real--; rtl92e_set_bb_reg(dev, - rOFDM0_XCTxIQImbalance, - bMaskDWord, dm_tx_bb_gain[4]); + rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); } } else { - if (p->rfa_txpowertrackingindex > 0) { - p->rfa_txpowertrackingindex--; - if (p->rfa_txpowertrackingindex_real > 4) { - p->rfa_txpowertrackingindex_real--; - rtl92e_set_bb_reg(dev, - rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); - } - } else { - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, dm_tx_bb_gain[4]); - } + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, dm_tx_bb_gain[4]); } } -static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev, - u8 RF_Type) +static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev) { struct r8192_priv *p = rtllib_priv(dev); - if (RF_Type == RF_2T4R) { - if ((p->rfa_txpowertrackingindex < TX_BB_GAIN_TABLE_LEN - 1) && - (p->rfc_txpowertrackingindex < TX_BB_GAIN_TABLE_LEN - 1)) { - p->rfa_txpowertrackingindex++; - p->rfa_txpowertrackingindex_real++; - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); - p->rfc_txpowertrackingindex++; - p->rfc_txpowertrackingindex_real++; - rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); - } else { - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]); - rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]); - } + if (p->rfa_txpowertrackingindex < (TX_BB_GAIN_TABLE_LEN - 1)) { + p->rfa_txpowertrackingindex++; + p->rfa_txpowertrackingindex_real++; + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); } else { - if (p->rfa_txpowertrackingindex < (TX_BB_GAIN_TABLE_LEN - 1)) { - p->rfa_txpowertrackingindex++; - p->rfa_txpowertrackingindex_real++; - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); - } else { - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]); - } + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]); } } @@ -585,10 +513,8 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); bool viviflag = false; struct dcmd_txcmd tx_cmd; - u8 powerlevelOFDM24G; int i = 0, j = 0, k = 0; - u8 RF_Type, tmp_report[5] = {0, 0, 0, 0, 0}; - u32 Value; + u8 tmp_report[5] = {0, 0, 0, 0, 0}; u8 Pwr_Flag; u16 Avg_TSSI_Meas, tssi_13dBm, Avg_TSSI_Meas_from_driver = 0; u32 delta = 0; @@ -597,15 +523,11 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev) rtl92e_writeb(dev, FW_Busy_Flag, 0); priv->rtllib->bdynamic_txpower_enable = false; - powerlevelOFDM24G = priv->pwr_track >> 24; - RF_Type = priv->rf_type; - Value = (RF_Type<<8) | powerlevelOFDM24G; - for (j = 0; j <= 30; j++) { tx_cmd.op = TXCMD_SET_TX_PWR_TRACKING; tx_cmd.length = 4; - tx_cmd.value = Value; + tx_cmd.value = priv->pwr_track >> 24; rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_NORMAL, (u8 *)&tx_cmd, sizeof(struct dcmd_txcmd)); mdelay(1); @@ -677,18 +599,12 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev) return; } if (Avg_TSSI_Meas_from_driver < tssi_13dBm - E_FOR_TX_POWER_TRACK) - _rtl92e_dm_tx_update_tssi_weak_signal(dev, - RF_Type); + _rtl92e_dm_tx_update_tssi_weak_signal(dev); else - _rtl92e_dm_tx_update_tssi_strong_signal(dev, RF_Type); + _rtl92e_dm_tx_update_tssi_strong_signal(dev); - if (RF_Type == RF_2T4R) { - priv->cck_present_attn_diff - = priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default; - } else { - priv->cck_present_attn_diff - = priv->rfa_txpowertrackingindex_real - priv->rfa_txpowertracking_default; - } + priv->cck_present_attn_diff + = priv->rfa_txpowertrackingindex_real - priv->rfa_txpowertracking_default; if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) priv->cck_present_attn = @@ -897,10 +813,7 @@ static void _rtl92e_dm_check_tx_power_tracking_thermal(struct net_device *dev) static u8 TM_Trigger; u8 TxPowerCheckCnt = 0; - if (IS_HARDWARE_TYPE_8192SE(dev)) - TxPowerCheckCnt = 5; - else - TxPowerCheckCnt = 2; + TxPowerCheckCnt = 2; if (!priv->btxpower_tracking) return; @@ -1042,12 +955,10 @@ void rtl92e_dm_restore_state(struct net_device *dev) if (priv->rate_adaptive.rate_adaptive_disabled) return; - if (!(priv->rtllib->mode == WIRELESS_MODE_N_24G || - priv->rtllib->mode == WIRELESS_MODE_N_5G)) + if (priv->rtllib->mode != WIRELESS_MODE_N_24G) return; ratr_value = reg_ratr; - if (priv->rf_type == RF_1T2R) - ratr_value &= ~(RATE_ALL_OFDM_2SS); + ratr_value &= ~(RATE_ALL_OFDM_2SS); rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); if (priv->tx_pwr_tracking_init && priv->btxpower_tracking) @@ -1087,7 +998,6 @@ void rtl92e_dm_backup_state(struct net_device *dev) u32 bit_mask = bMaskByte0; priv->bswitch_fsync = false; - priv->bfsync_processing = false; if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) return; @@ -1619,16 +1529,6 @@ static void _rtl92e_dm_cts_to_self(struct net_device *dev) } } - -static void _rtl92e_dm_init_wa_broadcom_iot(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); - struct rt_hi_throughput *ht_info = priv->rtllib->ht_info; - - ht_info->bWAIotBroadcom = false; - ht_info->WAIotTH = WA_IOT_TH_VAL; -} - static void _rtl92e_dm_check_rf_ctrl_gpio(void *data) { struct r8192_priv *priv = container_of_dwork_rsl(data, @@ -1638,15 +1538,11 @@ static void _rtl92e_dm_check_rf_ctrl_gpio(void *data) enum rt_rf_power_state rf_power_state_to_set; bool bActuallySet = false; - bActuallySet = false; - if ((priv->up_first_time == 1) || (priv->being_init_adapter)) return; - if (priv->bfirst_after_down) { - priv->bfirst_after_down = true; + if (priv->bfirst_after_down) return; - } tmp1byte = rtl92e_readb(dev, GPI); @@ -1730,9 +1626,6 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev) static u8 disabled_rf_cnt, cck_Rx_Path_initialized; u8 update_cck_rx_path; - if (priv->rf_type != RF_2T4R) - return; - if (!cck_Rx_Path_initialized) { dm_rx_path_sel_table.cck_rx_path = (rtl92e_readb(dev, 0xa07)&0xf); cck_Rx_Path_initialized = 1; @@ -1932,7 +1825,6 @@ static void _rtl92e_dm_init_fsync(struct net_device *dev) priv->rtllib->fsync_firstdiff_ratethreshold = 100; priv->rtllib->fsync_seconddiff_ratethreshold = 200; priv->rtllib->fsync_state = Default_Fsync; - priv->frame_sync_monitor = 1; timer_setup(&priv->fsync_timer, _rtl92e_dm_fsync_timer_callback, 0); } @@ -2159,12 +2051,10 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev) } } - if (priv->frame_sync_monitor) { - if (reg_c38_State != RegC38_Fsync_AP_BCM) { - rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95); + if (reg_c38_State != RegC38_Fsync_AP_BCM) { + rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95); - reg_c38_State = RegC38_Fsync_AP_BCM; - } + reg_c38_State = RegC38_Fsync_AP_BCM; } } else { switch (priv->rtllib->fsync_state) { @@ -2181,50 +2071,40 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev) break; } - if (priv->frame_sync_monitor) { - if (priv->rtllib->state == RTLLIB_LINKED) { - if (priv->undecorated_smoothed_pwdb <= - RegC38_TH) { - if (reg_c38_State != - RegC38_NonFsync_Other_AP) { - rtl92e_writeb(dev, - rOFDM0_RxDetector3, - 0x90); + if (priv->rtllib->state == RTLLIB_LINKED) { + if (priv->undecorated_smoothed_pwdb <= + RegC38_TH) { + if (reg_c38_State != + RegC38_NonFsync_Other_AP) { + rtl92e_writeb(dev, + rOFDM0_RxDetector3, + 0x90); - reg_c38_State = - RegC38_NonFsync_Other_AP; - } - } else if (priv->undecorated_smoothed_pwdb >= - (RegC38_TH+5)) { - if (reg_c38_State) { - rtl92e_writeb(dev, - rOFDM0_RxDetector3, - priv->framesync); - reg_c38_State = RegC38_Default; - } + reg_c38_State = + RegC38_NonFsync_Other_AP; } - } else { + } else if (priv->undecorated_smoothed_pwdb >= + (RegC38_TH+5)) { if (reg_c38_State) { - rtl92e_writeb(dev, rOFDM0_RxDetector3, - priv->framesync); + rtl92e_writeb(dev, + rOFDM0_RxDetector3, + priv->framesync); reg_c38_State = RegC38_Default; } } + } else { + if (reg_c38_State) { + rtl92e_writeb(dev, rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + } } } - if (priv->frame_sync_monitor) { - if (priv->reset_count != reset_cnt) { - rtl92e_writeb(dev, rOFDM0_RxDetector3, - priv->framesync); - reg_c38_State = RegC38_Default; - reset_cnt = priv->reset_count; - } - } else { - if (reg_c38_State) { - rtl92e_writeb(dev, rOFDM0_RxDetector3, - priv->framesync); - reg_c38_State = RegC38_Default; - } + if (priv->reset_count != reset_cnt) { + rtl92e_writeb(dev, rOFDM0_RxDetector3, + priv->framesync); + reg_c38_State = RegC38_Default; + reset_cnt = priv->reset_count; } } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c index 81e1bb856c60..0bc3e013001e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c @@ -39,7 +39,7 @@ bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev) revision_id = pdev->revision; pci_read_config_word(pdev, 0x3C, &irq_line); - priv->card_8192 = priv->ops->nic_type; + priv->card_8192 = NIC_8192E; if (device_id == 0x8192) { switch (revision_id) { @@ -64,10 +64,10 @@ bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev) } } - if (priv->ops->nic_type != priv->card_8192) { + if (priv->card_8192 != NIC_8192E) { dev_info(&pdev->dev, "Detect info(%x) and hardware info(%x) not match!\n", - priv->ops->nic_type, priv->card_8192); + NIC_8192E, priv->card_8192); dev_info(&pdev->dev, "Please select proper driver before install!!!!\n"); return false; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index ef4f736ce325..5a1cd22f5e25 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -142,8 +142,7 @@ void rtl92e_ips_leave(struct net_device *dev) void rtl92e_ips_leave_wq(void *data) { - struct rtllib_device *ieee = container_of_work_rsl(data, - struct rtllib_device, ips_leave_wq); + struct rtllib_device *ieee = container_of(data, struct rtllib_device, ips_leave_wq); struct net_device *dev = ieee->dev; struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index bf0030144e5d..cb28288a618b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -432,15 +432,11 @@ static int _rtl92e_wx_set_scan(struct net_device *dev, if (priv->rtllib->rf_power_state != rf_off) { priv->rtllib->actscanning = true; - if (ieee->ScanOperationBackupHandler) - ieee->ScanOperationBackupHandler(ieee->dev, - SCAN_OPT_BACKUP); + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); rtllib_start_scan_syncro(priv->rtllib, 0); - if (ieee->ScanOperationBackupHandler) - ieee->ScanOperationBackupHandler(ieee->dev, - SCAN_OPT_RESTORE); + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); } ret = 0; } else { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c b/drivers/staging/rtl8192e/rtl8192e/table.c similarity index 95% rename from drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c rename to drivers/staging/rtl8192e/rtl8192e/table.c index e6fce749e65b..0b5cc6049232 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c +++ b/drivers/staging/rtl8192e/rtl8192e/table.c @@ -4,11 +4,9 @@ * * Contact Information: wlanfae */ -#include "r8192E_hwimg.h" +#include "table.h" -u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLengthPciE] = {0x0,}; - -u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE] = { +u32 RTL8192E_PHY_REG_1T2R_ARR[RTL8192E_PHY_REG_1T2R_ARR_LEN] = { 0x800, 0x00000000, 0x804, 0x00000001, 0x808, 0x0000fc00, @@ -159,7 +157,7 @@ u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPciE] = { 0xe1c, 0x12121416, }; -u32 Rtl8192PciERadioA_Array[RadioA_ArrayLengthPciE] = { +u32 RTL8192E_RADIO_A_ARR[RTL8192E_RADIO_A_ARR_LEN] = { 0x019, 0x00000003, 0x000, 0x000000bf, 0x001, 0x00000ee0, @@ -285,7 +283,7 @@ u32 Rtl8192PciERadioA_Array[RadioA_ArrayLengthPciE] = { 0x007, 0x00000700, }; -u32 Rtl8192PciERadioB_Array[RadioB_ArrayLengthPciE] = { +u32 RTL8192E_RADIO_B_ARR[RTL8192E_RADIO_B_ARR_LEN] = { 0x019, 0x00000003, 0x000, 0x000000bf, 0x001, 0x000006e0, @@ -327,13 +325,7 @@ u32 Rtl8192PciERadioB_Array[RadioB_ArrayLengthPciE] = { 0x007, 0x00000700, }; -u32 Rtl8192PciERadioC_Array[RadioC_ArrayLengthPciE] = { - 0x0, }; - -u32 Rtl8192PciERadioD_Array[RadioD_ArrayLengthPciE] = { - 0x0, }; - -u32 Rtl8192PciEMACPHY_Array[] = { +u32 RTL8192E_MACPHY_ARR[] = { 0x03c, 0xffff0000, 0x00000f0f, 0x340, 0xffffffff, 0x161a1a1a, 0x344, 0xffffffff, 0x12121416, @@ -342,7 +334,7 @@ u32 Rtl8192PciEMACPHY_Array[] = { 0x318, 0x00000fff, 0x00000100, }; -u32 Rtl8192PciEMACPHY_Array_PG[] = { +u32 RTL8192E_MACPHY_ARR_PG[] = { 0x03c, 0xffff0000, 0x00000f0f, 0xe00, 0xffffffff, 0x06090909, 0xe04, 0xffffffff, 0x00030306, @@ -355,7 +347,7 @@ u32 Rtl8192PciEMACPHY_Array_PG[] = { 0x318, 0x00000fff, 0x00000800, }; -u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLengthPciE] = { +u32 RTL8192E_AGCTAB_ARR[RTL8192E_AGCTAB_ARR_LEN] = { 0xc78, 0x7d000001, 0xc78, 0x7d010001, 0xc78, 0x7d020001, diff --git a/drivers/staging/rtl8192e/rtl8192e/table.h b/drivers/staging/rtl8192e/rtl8192e/table.h new file mode 100644 index 000000000000..82be44a9d4e8 --- /dev/null +++ b/drivers/staging/rtl8192e/rtl8192e/table.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * Contact Information: wlanfae + */ +#ifndef __INC_HAL8192PciE_FW_IMG_H +#define __INC_HAL8192PciE_FW_IMG_H + +/*Created on 2008/11/18, 3: 7*/ + +#include + +#define RTL8192E_PHY_REG_1T2R_ARR_LEN 296 +extern u32 RTL8192E_PHY_REG_1T2R_ARR[RTL8192E_PHY_REG_1T2R_ARR_LEN]; +#define RTL8192E_RADIO_A_ARR_LEN 246 +extern u32 RTL8192E_RADIO_A_ARR[RTL8192E_RADIO_A_ARR_LEN]; +#define RTL8192E_RADIO_B_ARR_LEN 78 +extern u32 RTL8192E_RADIO_B_ARR[RTL8192E_RADIO_B_ARR_LEN]; +#define RTL8192E_MACPHY_ARR_LEN 18 +extern u32 RTL8192E_MACPHY_ARR[RTL8192E_MACPHY_ARR_LEN]; +#define RTL8192E_MACPHY_ARR_PG_LEN 30 +extern u32 RTL8192E_MACPHY_ARR_PG[RTL8192E_MACPHY_ARR_PG_LEN]; +#define RTL8192E_AGCTAB_ARR_LEN 384 +extern u32 RTL8192E_AGCTAB_ARR[RTL8192E_AGCTAB_ARR_LEN]; + +#endif diff --git a/drivers/staging/rtl8192e/rtl819x_HT.h b/drivers/staging/rtl8192e/rtl819x_HT.h index 22e4f126ed56..f4e9fa849796 100644 --- a/drivers/staging/rtl8192e/rtl819x_HT.h +++ b/drivers/staging/rtl8192e/rtl819x_HT.h @@ -162,9 +162,6 @@ struct rt_hi_throughput { u8 IOTPeer; u32 iot_action; u8 iot_ra_func; - - u8 bWAIotBroadcom; - u8 WAIotTH; } __packed; struct bss_ht { diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c index 68c131afc2ba..c61fdf73c572 100644 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -517,6 +517,7 @@ void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); mod_timer(&pTxTS->TsAddBaTimer, jiffies + 10); } - } else + } else { netdev_dbg(ieee->dev, "BA timer is already added\n"); + } } diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 1152fbf43383..6e665e866f1f 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -62,24 +62,9 @@ #define IW_CUSTOM_MAX 256 /* In bytes */ #endif -#define skb_tail_pointer_rsl(skb) skb_tail_pointer(skb) - -#define queue_delayed_work_rsl(x, y, z) queue_delayed_work(x, y, z) -#define INIT_DELAYED_WORK_RSL(x, y, z) INIT_DELAYED_WORK(x, y) - -#define queue_work_rsl(x, y) queue_work(x, y) -#define INIT_WORK_RSL(x, y, z) INIT_WORK(x, y) - -#define container_of_work_rsl(x, y, z) container_of(x, y, z) #define container_of_dwork_rsl(x, y, z) \ container_of(to_delayed_work(x), y, z) -#define iwe_stream_add_event_rsl(info, start, stop, iwe, len) \ - iwe_stream_add_event(info, start, stop, iwe, len) - -#define iwe_stream_add_point_rsl(info, start, stop, iwe, p) \ - iwe_stream_add_point(info, start, stop, iwe, p) - static inline void *netdev_priv_rsl(struct net_device *dev) { return netdev_priv(dev); @@ -115,7 +100,6 @@ static inline void *netdev_priv_rsl(struct net_device *dev) ((psc->CurPsLevel & _PS_FLAG) ? true : false) #define RT_CLEAR_PS_LEVEL(psc, _PS_FLAG) \ (psc->CurPsLevel &= (~(_PS_FLAG))) -#define RT_SET_PS_LEVEL(psc, _PS_FLAG) (psc->CurPsLevel |= _PS_FLAG) /* defined for skb cb field */ /* At most 28 byte */ @@ -323,7 +307,6 @@ enum rt_op_mode { RT_OP_MODE_NO_LINK, }; - #define aSifsTime \ (((priv->rtllib->current_network.mode == IEEE_A) \ || (priv->rtllib->current_network.mode == IEEE_N_24G) \ @@ -449,11 +432,6 @@ enum led_ctl_mode { LED_CTL_START_TO_LINK = 8, }; -enum rt_rf_type_def { - RF_1T2R = 0, - RF_2T4R, -}; - enum wireless_mode { WIRELESS_MODE_UNKNOWN = 0x00, WIRELESS_MODE_A = 0x01, @@ -669,7 +647,6 @@ struct rtllib_security { u16 flags; } __packed; - /* 802.11 data frame from AP * ,-------------------------------------------------------------------. * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | @@ -989,6 +966,7 @@ static inline const char *eap_get_type(int type) return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; } + static inline u8 Frame_QoSTID(u8 *buf) { struct rtllib_hdr_3addr *hdr; @@ -1000,7 +978,6 @@ static inline u8 Frame_QoSTID(u8 *buf) (fc & RTLLIB_FCTL_FROMDS)) ? 30 : 24)))->field.tid; } - struct eapol { u8 snap[6]; u16 ethertype; @@ -1215,8 +1192,6 @@ struct bandwidth_autoswitch { bool bautoswitch_enable; }; - - #define REORDER_WIN_SIZE 128 #define REORDER_ENTRY_NUM 128 struct rx_reorder_entry { @@ -1224,6 +1199,7 @@ struct rx_reorder_entry { u16 SeqNum; struct rtllib_rxb *prxb; }; + enum fsync_state { Default_Fsync, HW_Fsync, @@ -1260,7 +1236,6 @@ struct rt_pwr_save_ctrl { u8 LPSAwakeIntvl; u32 CurPsLevel; - u32 RegRfPsLevel; }; #define RT_RF_CHANGE_SOURCE u32 @@ -1350,6 +1325,7 @@ struct sw_cam_table { u8 key_index; }; + #define TOTAL_CAM_ENTRY 32 struct rate_adaptive { u8 rate_adaptive_disabled; @@ -1388,7 +1364,6 @@ struct rt_intel_promisc_mode { bool fltr_src_sta_frame; }; - /*************** DRIVER STATUS *****/ #define STATUS_SCANNING 0 /*************** DRIVER STATUS *****/ @@ -1416,7 +1391,6 @@ struct rtllib_device { size_t assocreq_ies_len, assocresp_ies_len; bool bForcedBgMode; - u8 RF_Type; u8 hwsec_active; bool is_silent_reset; @@ -1457,7 +1431,6 @@ struct rtllib_device { struct rx_reorder_entry RxReorderEntry[128]; struct list_head RxReorder_Unused_List; - /* Bookkeeping structures */ struct net_device_stats stats; struct rtllib_softmac_stats softmac_stats; @@ -1754,7 +1727,6 @@ struct rtllib_device { struct rtllib_assoc_response_frame *resp, struct rtllib_network *network); - /* check whether Tx hw resource available */ short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); void (*SetBWModeHandler)(struct net_device *dev, @@ -1827,7 +1799,6 @@ struct rtllib_device { */ #define IEEE_SOFTMAC_BEACONS (1<<6) - static inline void *rtllib_priv(struct net_device *dev) { return ((struct rtllib_device *)netdev_priv(dev))->priv; @@ -1919,17 +1890,15 @@ static inline int rtllib_is_cck_rate(u8 rate) return 0; } - /* rtllib.c */ void free_rtllib(struct net_device *dev); struct net_device *alloc_rtllib(int sizeof_priv); /* rtllib_tx.c */ -int rtllib_encrypt_fragment( - struct rtllib_device *ieee, - struct sk_buff *frag, - int hdr_len); +int rtllib_encrypt_fragment(struct rtllib_device *ieee, + struct sk_buff *frag, + int hdr_len); netdev_tx_t rtllib_xmit(struct sk_buff *skb, struct net_device *dev); void rtllib_txb_free(struct rtllib_txb *txb); @@ -2129,7 +2098,6 @@ static inline const char *escape_essid(const char *essid, u8 essid_len) /* fun with the built-in rtllib stack... */ bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn); - /* For the function is more related to hardware setting, it's better to use the * ieee handler to refer to it. */ diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c index a8d22da8bc9a..f88096bcb181 100644 --- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c +++ b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c @@ -34,9 +34,9 @@ struct rtllib_ccmp_data { u8 tx_pn[CCMP_PN_LEN]; u8 rx_pn[CCMP_PN_LEN]; - u32 dot11RSNAStatsCCMPFormatErrors; - u32 dot11RSNAStatsCCMPReplays; - u32 dot11RSNAStatsCCMPDecryptErrors; + u32 dot11rsna_stats_ccmp_format_errors; + u32 dot11rsna_stats_ccmp_replays; + u32 dot11rsna_stats_ccmp_decrypt_errors; int key_idx; @@ -74,7 +74,6 @@ fail: return NULL; } - static void rtllib_ccmp_deinit(void *priv) { struct rtllib_ccmp_data *_priv = priv; @@ -84,7 +83,6 @@ static void rtllib_ccmp_deinit(void *priv) kfree(priv); } - static int ccmp_init_iv_and_aad(struct rtllib_hdr_4addr *hdr, u8 *pn, u8 *iv, u8 *aad) { @@ -150,8 +148,6 @@ static int ccmp_init_iv_and_aad(struct rtllib_hdr_4addr *hdr, return aad_len; } - - static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct rtllib_ccmp_data *key = priv; @@ -220,7 +216,6 @@ static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return 0; } - static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct rtllib_ccmp_data *key = priv; @@ -231,7 +226,7 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 pn[6]; if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { - key->dot11RSNAStatsCCMPFormatErrors++; + key->dot11rsna_stats_ccmp_format_errors++; return -1; } @@ -243,7 +238,7 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pr_debug("CCMP: received packet without ExtIV flag from %pM\n", hdr->addr2); } - key->dot11RSNAStatsCCMPFormatErrors++; + key->dot11rsna_stats_ccmp_format_errors++; return -2; } keyidx >>= 6; @@ -268,7 +263,7 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pn[5] = pos[0]; pos += 8; if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { - key->dot11RSNAStatsCCMPReplays++; + key->dot11rsna_stats_ccmp_replays++; return -4; } if (!tcb_desc->bHwSec) { @@ -301,7 +296,7 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pr_debug("CCMP: decrypt failed: STA= %pM\n", hdr->addr2); } - key->dot11RSNAStatsCCMPDecryptErrors++; + key->dot11rsna_stats_ccmp_decrypt_errors++; return -5; } @@ -315,7 +310,6 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return keyidx; } - static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv) { struct rtllib_ccmp_data *data = priv; @@ -338,7 +332,7 @@ static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv) data->rx_pn[5] = seq[0]; } if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) || - crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN)) + crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN)) return -1; } else if (len == 0) { data->key_set = 0; @@ -349,7 +343,6 @@ static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv) return 0; } - static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv) { struct rtllib_ccmp_data *data = priv; @@ -373,7 +366,6 @@ static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv) return CCMP_TK_LEN; } - static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv) { struct rtllib_ccmp_data *ccmp = priv; @@ -382,9 +374,9 @@ static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv) "key[%d] alg=CCMP key_set=%d tx_pn=%pM rx_pn=%pM format_errors=%d replays=%d decrypt_errors=%d\n", ccmp->key_idx, ccmp->key_set, ccmp->tx_pn, ccmp->rx_pn, - ccmp->dot11RSNAStatsCCMPFormatErrors, - ccmp->dot11RSNAStatsCCMPReplays, - ccmp->dot11RSNAStatsCCMPDecryptErrors); + ccmp->dot11rsna_stats_ccmp_format_errors, + ccmp->dot11rsna_stats_ccmp_replays, + ccmp->dot11rsna_stats_ccmp_decrypt_errors); } static struct lib80211_crypto_ops rtllib_crypt_ccmp = { @@ -403,13 +395,11 @@ static struct lib80211_crypto_ops rtllib_crypt_ccmp = { .owner = THIS_MODULE, }; - static int __init rtllib_crypto_ccmp_init(void) { return lib80211_register_crypto_ops(&rtllib_crypt_ccmp); } - static void __exit rtllib_crypto_ccmp_exit(void) { lib80211_unregister_crypto_ops(&rtllib_crypt_ccmp); diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 669e74a67190..b649d02dc5c8 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -154,7 +154,6 @@ rtllib_frag_cache_get(struct rtllib_device *ieee, return skb; } - /* Called only as a tasklet (software IRQ) */ static int rtllib_frag_cache_invalidate(struct rtllib_device *ieee, struct rtllib_hdr_4addr *hdr) @@ -232,10 +231,12 @@ rtllib_rx_frame_mgmt(struct rtllib_device *ieee, struct sk_buff *skb, static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ static unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + /* No encapsulation header if EtherType < 0x600 (=length) */ /* Called by rtllib_rx_frame_decrypt */ @@ -318,7 +319,6 @@ rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, return res; } - /* Called only as a tasklet (software IRQ), by rtllib_rx */ static inline int rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb, @@ -355,9 +355,8 @@ rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb, return 0; } - /* this function is stolen from ipw2200 driver*/ -#define IEEE_PACKET_RETRY_TIME (5*HZ) +#define IEEE_PACKET_RETRY_TIME (5 * HZ) static int is_duplicate_packet(struct rtllib_device *ieee, struct rtllib_hdr_4addr *header) { @@ -887,7 +886,6 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, return rxb->nr_subframes; } - static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats) @@ -938,7 +936,7 @@ static int rtllib_rx_check_duplicate(struct rtllib_device *ieee, if (GetTs(ieee, (struct ts_common_info **)&pRxTS, hdr->addr2, (u8)Frame_QoSTID((u8 *)(skb->data)), RX_DIR, true)) { - if ((fc & (1<<11)) && (frag == pRxTS->rx_last_frag_num) && + if ((fc & (1 << 11)) && (frag == pRxTS->rx_last_frag_num) && (WLAN_GET_SEQ_SEQ(sc) == pRxTS->rx_last_seq_num)) return -1; pRxTS->rx_last_frag_num = frag; @@ -1169,7 +1167,6 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, if (crypt && !(fc & RTLLIB_FCTL_WEP) && !ieee->open_wep) { if (/*ieee->ieee802_1x &&*/ rtllib_is_eapol_frame(ieee, skb, hdrlen)) { - /* pass unencrypted EAPOL frames even if encryption is * configured */ @@ -1209,13 +1206,11 @@ static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast, u8 nr_subframes) { if (unicast) { - if (ieee->state == RTLLIB_LINKED) { if (((ieee->link_detect_info.NumRxUnicastOkInPeriod + ieee->link_detect_info.NumTxOkInPeriod) > 8) || (ieee->link_detect_info.NumRxUnicastOkInPeriod > 2)) { - if (ieee->LeisurePSLeave) - ieee->LeisurePSLeave(ieee->dev); + ieee->LeisurePSLeave(ieee->dev); } } } @@ -1555,7 +1550,6 @@ static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; static int rtllib_verify_qos_info(struct rtllib_qos_information_element *info_element, int sub_type) { - if (info_element->elementID != QOS_ELEMENT_ID) return -1; if (info_element->qui_subtype != sub_type) @@ -1570,7 +1564,6 @@ static int rtllib_verify_qos_info(struct rtllib_qos_information_element return 0; } - /* Parse a QoS parameter element */ static int rtllib_read_qos_param_element( struct rtllib_qos_parameter_info *element_param, @@ -1600,7 +1593,6 @@ static int rtllib_read_qos_info_element( return rtllib_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE); } - /* Write QoS parameters from the ac parameters. */ static int rtllib_qos_convert_ac_to_parameters(struct rtllib_qos_parameter_info *param_elm, struct rtllib_qos_data *qos_data) @@ -1624,23 +1616,23 @@ static int rtllib_qos_convert_ac_to_parameters(struct rtllib_qos_parameter_info case 1: /* BIT(0) | BIT(3) */ if (acm) - qos_data->wmm_acm |= (0x01<<0)|(0x01<<3); + qos_data->wmm_acm |= (0x01 << 0) | (0x01 << 3); break; case 2: /* BIT(4) | BIT(5) */ if (acm) - qos_data->wmm_acm |= (0x01<<4)|(0x01<<5); + qos_data->wmm_acm |= (0x01 << 4) | (0x01 << 5); break; case 3: /* BIT(6) | BIT(7) */ if (acm) - qos_data->wmm_acm |= (0x01<<6)|(0x01<<7); + qos_data->wmm_acm |= (0x01 << 6) | (0x01 << 7); break; case 0: default: /* BIT(1) | BIT(2) */ if (acm) - qos_data->wmm_acm |= (0x01<<1)|(0x01<<2); + qos_data->wmm_acm |= (0x01 << 1) | (0x01 << 2); break; } @@ -1844,7 +1836,6 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, } } - if (*tmp_htinfo_len == 0) { if (info_element->len >= 4 && info_element->data[0] == 0x00 && @@ -1933,7 +1924,6 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, info_element->data[2] == 0x96) network->cisco_cap_exist = true; - if (info_element->len >= 3 && info_element->data[0] == 0x00 && info_element->data[1] == 0x0a && @@ -1986,7 +1976,7 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee, info_element->data[3] == 0x04) { netdev_dbg(ieee->dev, "MFIE_TYPE_WZC: %d bytes\n", info_element->len); - network->wzc_ie_len = min(info_element->len+2, MAX_WZC_IE_LEN); + network->wzc_ie_len = min(info_element->len + 2, MAX_WZC_IE_LEN); memcpy(network->wzc_ie, info_element, network->wzc_ie_len); } } @@ -2143,15 +2133,13 @@ int rtllib_parse_info_param(struct rtllib_device *ieee, network->dtim_data = RTLLIB_DTIM_VALID; - if (info_element->data[2] & 1) network->dtim_data |= RTLLIB_DTIM_MBCAST; - offset = (info_element->data[2] >> 1)*2; + offset = (info_element->data[2] >> 1) * 2; - - if (ieee->assoc_id < 8*offset || - ieee->assoc_id > 8*(offset + info_element->len - 3)) + if (ieee->assoc_id < 8 * offset || + ieee->assoc_id > 8 * (offset + info_element->len - 3)) break; offset = (ieee->assoc_id / 8) - offset; @@ -2204,7 +2192,6 @@ int rtllib_parse_info_param(struct rtllib_device *ieee, &tmp_htcap_len); break; - case MFIE_TYPE_HT_INFO: netdev_dbg(ieee->dev, "MFIE_TYPE_HT_INFO: %d bytes\n", info_element->len); @@ -2367,7 +2354,7 @@ static inline int rtllib_network_init( if (rtllib_is_empty_essid(network->ssid, network->ssid_len)) network->flags |= NETWORK_EMPTY_ESSID; stats->signal = 30 + (stats->SignalStrength * 70) / 100; - stats->noise = rtllib_translate_todbm((u8)(100-stats->signal)) - 25; + stats->noise = rtllib_translate_todbm((u8)(100 - stats->signal)) - 25; memcpy(&network->stats, stats, sizeof(network->stats)); @@ -2393,7 +2380,6 @@ static inline int is_same_network(struct rtllib_network *src, (dst->capability & WLAN_CAPABILITY_ESS))); } - static inline void update_network(struct rtllib_device *ieee, struct rtllib_network *dst, struct rtllib_network *src) @@ -2556,22 +2542,22 @@ static inline void rtllib_process_probe_response( "'%s' ( %pM ): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", escape_essid(info_element->data, info_element->len), beacon->header.addr3, - (le16_to_cpu(beacon->capability) & (1<<0xf)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0xe)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0xd)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0xc)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0xb)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0xa)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x9)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x8)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x7)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x6)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x5)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x4)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x3)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x2)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x1)) ? '1' : '0', - (le16_to_cpu(beacon->capability) & (1<<0x0)) ? '1' : '0'); + (le16_to_cpu(beacon->capability) & (1 << 0xf)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0xe)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0xd)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0xc)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0xb)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0xa)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x9)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x8)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x7)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x6)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x5)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x4)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x3)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x2)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x1)) ? '1' : '0', + (le16_to_cpu(beacon->capability) & (1 << 0x0)) ? '1' : '0'); if (rtllib_network_init(ieee, beacon, network, stats)) { netdev_dbg(ieee->dev, "Dropped '%s' ( %pM) via %s.\n", @@ -2581,7 +2567,6 @@ static inline void rtllib_process_probe_response( goto free_network; } - if (!rtllib_legal_channel(ieee, network->channel)) goto free_network; @@ -2689,9 +2674,7 @@ static inline void rtllib_process_probe_response( is_same_network(&ieee->current_network, network, (network->ssid_len ? 1 : 0)) && (ieee->state == RTLLIB_LINKED)) { - if (ieee->handle_beacon != NULL) - ieee->handle_beacon(ieee->dev, beacon, - &ieee->current_network); + ieee->handle_beacon(ieee->dev, beacon, &ieee->current_network); } free_network: kfree(network); @@ -2710,7 +2693,6 @@ static void rtllib_rx_mgt(struct rtllib_device *ieee, ieee->last_rx_ps_time = jiffies; switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { - case RTLLIB_STYPE_BEACON: netdev_dbg(ieee->dev, "received BEACON (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))); diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 2552aa089700..b9886e83a6dc 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -659,8 +659,7 @@ static void rtllib_beacons_stop(struct rtllib_device *ieee) void rtllib_stop_send_beacons(struct rtllib_device *ieee) { - if (ieee->stop_send_beacons) - ieee->stop_send_beacons(ieee->dev); + ieee->stop_send_beacons(ieee->dev); if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) rtllib_beacons_stop(ieee); } @@ -669,8 +668,7 @@ EXPORT_SYMBOL(rtllib_stop_send_beacons); void rtllib_start_send_beacons(struct rtllib_device *ieee) { - if (ieee->start_send_beacons) - ieee->start_send_beacons(ieee->dev); + ieee->start_send_beacons(ieee->dev); if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) rtllib_beacons_start(ieee); } @@ -729,8 +727,7 @@ EXPORT_SYMBOL(rtllib_act_scanning); /* called with ieee->lock held */ static void rtllib_start_scan(struct rtllib_device *ieee) { - if (ieee->rtllib_ips_leave_wq != NULL) - ieee->rtllib_ips_leave_wq(ieee->dev); + ieee->rtllib_ips_leave_wq(ieee->dev); if (IS_DOT11D_ENABLE(ieee)) { if (IS_COUNTRY_IE_VALID(ieee)) @@ -1501,7 +1498,7 @@ static void rtllib_associate_step2(struct rtllib_device *ieee) static void rtllib_associate_complete_wq(void *data) { struct rtllib_device *ieee = (struct rtllib_device *) - container_of_work_rsl(data, + container_of(data, struct rtllib_device, associate_complete_wq); struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl; @@ -1575,8 +1572,7 @@ static void rtllib_associate_procedure_wq(void *data) struct rtllib_device, associate_procedure_wq); rtllib_stop_scan_syncro(ieee); - if (ieee->rtllib_ips_leave != NULL) - ieee->rtllib_ips_leave(ieee->dev); + ieee->rtllib_ips_leave(ieee->dev); mutex_lock(&ieee->wx_mutex); if (ieee->data_hard_stop) @@ -1585,8 +1581,7 @@ static void rtllib_associate_procedure_wq(void *data) rtllib_stop_scan(ieee); HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); if (ieee->rf_power_state == rf_off) { - if (ieee->rtllib_ips_leave_wq != NULL) - ieee->rtllib_ips_leave_wq(ieee->dev); + ieee->rtllib_ips_leave_wq(ieee->dev); mutex_unlock(&ieee->wx_mutex); return; } @@ -2241,10 +2236,8 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb, memcpy(ieee->ht_info->PeerHTInfoBuf, network->bssht.bd_ht_info_buf, network->bssht.bd_ht_info_len); - if (ieee->handle_assoc_response != NULL) - ieee->handle_assoc_response(ieee->dev, - (struct rtllib_assoc_response_frame *)header, - network); + ieee->handle_assoc_response(ieee->dev, + (struct rtllib_assoc_response_frame *)header, network); } kfree(network); @@ -2856,8 +2849,7 @@ void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown) if (shutdown) { ieee->proto_started = 0; ieee->proto_stoppping = 1; - if (ieee->rtllib_ips_leave != NULL) - ieee->rtllib_ips_leave(ieee->dev); + ieee->rtllib_ips_leave(ieee->dev); } rtllib_stop_send_beacons(ieee); @@ -3004,20 +2996,13 @@ int rtllib_softmac_init(struct rtllib_device *ieee) timer_setup(&ieee->beacon_timer, rtllib_send_beacon_cb, 0); - INIT_DELAYED_WORK_RSL(&ieee->link_change_wq, - (void *)rtllib_link_change_wq, ieee); - INIT_DELAYED_WORK_RSL(&ieee->start_ibss_wq, - (void *)rtllib_start_ibss_wq, ieee); - INIT_WORK_RSL(&ieee->associate_complete_wq, - (void *)rtllib_associate_complete_wq, ieee); - INIT_DELAYED_WORK_RSL(&ieee->associate_procedure_wq, - (void *)rtllib_associate_procedure_wq, ieee); - INIT_DELAYED_WORK_RSL(&ieee->softmac_scan_wq, - (void *)rtllib_softmac_scan_wq, ieee); - INIT_DELAYED_WORK_RSL(&ieee->associate_retry_wq, - (void *)rtllib_associate_retry_wq, ieee); - INIT_WORK_RSL(&ieee->wx_sync_scan_wq, (void *)rtllib_wx_sync_scan_wq, - ieee); + INIT_DELAYED_WORK(&ieee->link_change_wq, (void *)rtllib_link_change_wq); + INIT_DELAYED_WORK(&ieee->start_ibss_wq, (void *)rtllib_start_ibss_wq); + INIT_WORK(&ieee->associate_complete_wq, (void *)rtllib_associate_complete_wq); + INIT_DELAYED_WORK(&ieee->associate_procedure_wq, (void *)rtllib_associate_procedure_wq); + INIT_DELAYED_WORK(&ieee->softmac_scan_wq, (void *)rtllib_softmac_scan_wq); + INIT_DELAYED_WORK(&ieee->associate_retry_wq, (void *)rtllib_associate_retry_wq); + INIT_WORK(&ieee->wx_sync_scan_wq, (void *)rtllib_wx_sync_scan_wq); mutex_init(&ieee->wx_mutex); mutex_init(&ieee->scan_mutex); diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c index 06f3d75dc102..1f2fa711e60b 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -326,8 +326,7 @@ EXPORT_SYMBOL(rtllib_wx_set_mode); void rtllib_wx_sync_scan_wq(void *data) { - struct rtllib_device *ieee = container_of_work_rsl(data, - struct rtllib_device, wx_sync_scan_wq); + struct rtllib_device *ieee = container_of(data, struct rtllib_device, wx_sync_scan_wq); short chan; enum ht_extchnl_offset chan_offset = 0; enum ht_channel_width bandwidth = 0; @@ -340,8 +339,7 @@ void rtllib_wx_sync_scan_wq(void *data) chan = ieee->current_network.channel; - if (ieee->LeisurePSLeave) - ieee->LeisurePSLeave(ieee->dev); + ieee->LeisurePSLeave(ieee->dev); /* notify AP to be in PS mode */ rtllib_sta_ps_send_null_frame(ieee, 1); rtllib_sta_ps_send_null_frame(ieee, 1); @@ -356,8 +354,7 @@ void rtllib_wx_sync_scan_wq(void *data) /* wait for ps packet to be kicked out successfully */ msleep(50); - if (ieee->ScanOperationBackupHandler) - ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); if (ieee->ht_info->bCurrentHTSupport && ieee->ht_info->enable_ht && ieee->ht_info->bCurBW40MHz) { @@ -382,8 +379,7 @@ void rtllib_wx_sync_scan_wq(void *data) ieee->set_chan(ieee->dev, chan); } - if (ieee->ScanOperationBackupHandler) - ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); + ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); ieee->state = RTLLIB_LINKED; ieee->link_change(ieee->dev); diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 217426ee2e92..d6691f3c7c70 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -41,8 +41,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid); - start = iwe_stream_add_event_rsl(info, start, stop, - &iwe, IW_EV_ADDR_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); /* Remaining entries will be displayed in the order we provide them */ /* Add the ESSID */ @@ -50,16 +49,13 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.u.data.flags = 1; if (network->ssid_len > 0) { iwe.u.data.length = min_t(u8, network->ssid_len, 32); - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, - network->ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); } else if (network->hidden_ssid_len == 0) { iwe.u.data.length = sizeof(""); - start = iwe_stream_add_point_rsl(info, start, stop, - &iwe, ""); + start = iwe_stream_add_point(info, start, stop, &iwe, ""); } else { iwe.u.data.length = min_t(u8, network->hidden_ssid_len, 32); - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, - network->hidden_ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, network->hidden_ssid); } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; @@ -71,8 +67,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, } *pname = '\0'; snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name); - start = iwe_stream_add_event_rsl(info, start, stop, - &iwe, IW_EV_CHAR_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ iwe.cmd = SIOCGIWMODE; if (network->capability & @@ -81,8 +76,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; - start = iwe_stream_add_event_rsl(info, start, stop, - &iwe, IW_EV_UINT_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); } /* Add frequency/channel */ @@ -90,8 +84,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.u.freq.m = network->channel; iwe.u.freq.e = 0; iwe.u.freq.i = 0; - start = iwe_stream_add_event_rsl(info, start, stop, &iwe, - IW_EV_FREQ_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -100,8 +93,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - start = iwe_stream_add_point_rsl(info, start, stop, - &iwe, network->ssid); + start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); /* Add basic and extended rates */ max_rate = 0; p = custom; @@ -152,12 +144,11 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, iwe.u.bitrate.disabled = 0; iwe.u.bitrate.fixed = 0; iwe.u.bitrate.value = max_rate * 500000; - start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_PARAM_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point_rsl(info, start, stop, - &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); /* Add quality statistics */ /* TODO: Fix these values... */ iwe.cmd = IWEVQUAL; @@ -172,13 +163,13 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL)) iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; iwe.u.qual.updated = 7; - start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); iwe.cmd = IWEVCUSTOM; p = custom; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); memset(&iwe, 0, sizeof(iwe)); if (network->wpa_ie_len) { @@ -187,7 +178,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, memcpy(buf, network->wpa_ie, network->wpa_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->wpa_ie_len; - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } memset(&iwe, 0, sizeof(iwe)); if (network->rsn_ie_len) { @@ -196,7 +187,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, memcpy(buf, network->rsn_ie, network->rsn_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->rsn_ie_len; - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } /* add info for WZC */ @@ -207,7 +198,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, memcpy(buf, network->wzc_ie, network->wzc_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->wzc_ie_len; - start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf); + start = iwe_stream_add_point(info, start, stop, &iwe, buf); } /* Add EXTRA: Age to display seconds since last beacon/probe response @@ -220,8 +211,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, (100 * (jiffies - network->last_scanned)) / HZ); iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point_rsl(info, start, stop, - &iwe, custom); + start = iwe_stream_add_point(info, start, stop, &iwe, custom); return start; } diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 5c73e3f8541a..ca09367005e1 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -1958,43 +1958,6 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee, return 0; } -static inline u8 ieee80211_SignalStrengthTranslate( - u8 CurrSS - ) -{ - u8 RetSS; - - // Step 1. Scale mapping. - if (CurrSS >= 71 && CurrSS <= 100) { - RetSS = 90 + ((CurrSS - 70) / 3); - } else if (CurrSS >= 41 && CurrSS <= 70) { - RetSS = 78 + ((CurrSS - 40) / 3); - } else if (CurrSS >= 31 && CurrSS <= 40) { - RetSS = 66 + (CurrSS - 30); - } else if (CurrSS >= 21 && CurrSS <= 30) { - RetSS = 54 + (CurrSS - 20); - } else if (CurrSS >= 5 && CurrSS <= 20) { - RetSS = 42 + (((CurrSS - 5) * 2) / 3); - } else if (CurrSS == 4) { - RetSS = 36; - } else if (CurrSS == 3) { - RetSS = 27; - } else if (CurrSS == 2) { - RetSS = 18; - } else if (CurrSS == 1) { - RetSS = 9; - } else { - RetSS = CurrSS; - } - //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); - - // Step 2. Smoothing. - - //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); - - return RetSS; -} - /* 0-100 index */ static long ieee80211_translate_todbm(u8 signal_strength_index) { @@ -2095,7 +2058,6 @@ static inline int ieee80211_network_init( network->flags |= NETWORK_EMPTY_ESSID; stats->signal = 30 + (stats->SignalStrength * 70) / 100; - //stats->signal = ieee80211_SignalStrengthTranslate(stats->signal); stats->noise = ieee80211_translate_todbm((u8)(100 - stats->signal)) - 25; memcpy(&network->stats, stats, sizeof(network->stats)); diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index 00fc8fd344db..cbae852478ea 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -1,19 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 /*++ -Copyright-c Realtek Semiconductor Corp. All rights reserved. - -Module Name: - r8192U_dm.c - -Abstract: - HW dynamic mechanism. - -Major Change History: - When Who What - ---------- --------------- ------------------------------- - 2008-05-14 amy create version 0 porting from windows code. - ---*/ + * Copyright-c Realtek Semiconductor Corp. All rights reserved. + * + * Module Name: + * r8192U_dm.c + * + * Abstract: + * HW dynamic mechanism. + *-- + */ #include "r8192U.h" #include "r8192U_dm.h" #include "r8192U_hw.h" @@ -54,12 +49,8 @@ static void dm_init_bandwidth_autoswitch(struct net_device *dev); static void dm_bandwidth_autoswitch(struct net_device *dev); /* DM --> TX power control */ -/*static void dm_initialize_txpower_tracking(struct net_device *dev);*/ - static void dm_check_txpower_tracking(struct net_device *dev); -/*static void dm_txpower_reset_recovery(struct net_device *dev);*/ - /* DM --> Dynamic Init Gain by RSSI */ static void dm_dig_init(struct net_device *dev); static void dm_ctrl_initgain_byrssi(struct net_device *dev); @@ -74,7 +65,6 @@ static void dm_init_ctstoself(struct net_device *dev); /* DM --> EDCA turbo mode control */ static void dm_check_edca_turbo(struct net_device *dev); -/*static void dm_gpio_change_rf(struct net_device *dev);*/ /* DM --> Check PBC */ static void dm_check_pbc_gpio(struct net_device *dev); @@ -121,7 +111,6 @@ void init_hal_dm(struct net_device *dev) /* Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. */ dm_init_dynamic_txpower(dev); init_rate_adaptive(dev); - /*dm_initialize_txpower_tracking(dev);*/ dm_dig_init(dev); dm_init_edca_turbo(dev); dm_init_bandwidth_autoswitch(dev); @@ -146,21 +135,6 @@ void dm_CheckRxAggregation(struct net_device *dev) unsigned long curTxOkCnt = 0; unsigned long curRxOkCnt = 0; -/* - if (pHalData->bForcedUsbRxAggr) { - if (pHalData->ForcedUsbRxAggrInfo == 0) { - if (pHalData->bCurrentRxAggrEnable) { - Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, FALSE); - } - } else { - if (!pHalData->bCurrentRxAggrEnable || (pHalData->ForcedUsbRxAggrInfo != pHalData->LastUsbRxAggrInfoSetting)) { - Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, TRUE); - } - } - return; - } - -*/ curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; @@ -194,10 +168,6 @@ void dm_CheckRxAggregation(struct net_device *dev) void hal_dm_watchdog(struct net_device *dev) { - /*struct r8192_priv *priv = ieee80211_priv(dev);*/ - - /*static u8 previous_bssid[6] ={0};*/ - /*Add by amy 2008/05/15 ,porting from windows code.*/ dm_check_rate_adaptive(dev); dm_dynamic_txpower(dev); @@ -274,12 +244,8 @@ void init_rate_adaptive(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 05/26/08 amy Create version 0 porting from windows code. - * - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ static void dm_check_rate_adaptive(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -304,7 +270,6 @@ static void dm_check_rate_adaptive(struct net_device *dev) return; if (priv->ieee80211->state == IEEE80211_LINKED) { - /*RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");*/ /* Check whether Short GI is enabled */ bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) || @@ -351,36 +316,27 @@ static void dm_check_rate_adaptive(struct net_device *dev) (pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M); } - /*DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA);*/ if (priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) { - /*DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB);*/ pra->ratr_state = DM_RATR_STA_HIGH; targetRATR = pra->upper_rssi_threshold_ratr; } else if (priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) { - /*DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB);*/ pra->ratr_state = DM_RATR_STA_MIDDLE; targetRATR = pra->middle_rssi_threshold_ratr; } else { - /*DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB);*/ pra->ratr_state = DM_RATR_STA_LOW; targetRATR = pra->low_rssi_threshold_ratr; } /* cosa add for test */ if (pra->ping_rssi_enable) { - /*pHalData->UndecoratedSmoothedPWDB = 19;*/ if (priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) { if ((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) || ping_rssi_state) { - /*DbgPrint("TestRSSI = %d, set RATR to 0x%x\n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR);*/ pra->ratr_state = DM_RATR_STA_LOW; targetRATR = pra->ping_rssi_ratr; ping_rssi_state = 1; } - /*else - DbgPrint("TestRSSI is between the range.\n");*/ } else { - /*DbgPrint("TestRSSI Recover to 0x%x\n", targetRATR);*/ ping_rssi_state = 0; } } @@ -502,7 +458,6 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) u32 Value; u8 Pwr_Flag; u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver = 0; - /*RT_STATUS rtStatus = RT_STATUS_SUCCESS;*/ bool rtStatus = true; u32 delta = 0; @@ -524,7 +479,6 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (rtStatus == RT_STATUS_FAILURE) RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n"); usleep_range(1000, 2000); - /*DbgPrint("hi, vivi, strange\n");*/ for (i = 0; i <= 30; i++) { read_nic_byte(dev, 0x1ba, &Pwr_Flag); @@ -570,8 +524,6 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) TSSI_13dBm = priv->TSSI_13dBm; RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm); - /*if (abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)*/ - /* For MacOS-compatible */ if (Avg_TSSI_Meas_from_driver > TSSI_13dBm) delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm; else @@ -675,7 +627,6 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) } } priv->btxpower_trackingInit = true; - /*pHalData->TXPowercount = 0;*/ return; } @@ -719,9 +670,6 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) } tmpCCK40Mindex = 0; } - /*DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d", - ((u1Byte)tmpRegA - pHalData->ThermalMeter[0]), - tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex);*/ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) /* 40M */ tmpCCKindex = tmpCCK40Mindex; else @@ -741,7 +689,6 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) } if (CCKSwingNeedUpdate) { - /*DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index);*/ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } if (priv->OFDM_index != tmpOFDMindex) { @@ -1312,7 +1259,6 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); static u8 TM_Trigger; - /*DbgPrint("dm_CheckTXPowerTracking()\n");*/ if (!priv->btxpower_tracking) return; if (priv->txpower_count <= 2) { @@ -1332,7 +1278,6 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) TM_Trigger = 1; return; } - /*DbgPrint("Schedule TxPowerTrackingWorkItem\n");*/ queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0); TM_Trigger = 0; } @@ -1340,7 +1285,6 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) static void dm_check_txpower_tracking(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - /*static u32 tx_power_track_counter = 0;*/ #ifdef RTL8190P dm_CheckTXPowerTracking_TSSI(dev); @@ -1425,7 +1369,6 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", rCCK0_DebugPort, TempVal); } else { - /*priv->CCKTxPowerAdjustCntNotCh14++; cosa add for debug.*/ /* Write 0xa22 0xa23 */ TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] + (CCKSwingTable_Ch14[priv->CCK_index][1]<<8); @@ -1508,10 +1451,7 @@ void dm_restore_dynamic_mechanism_state(struct net_device *dev) ratr_value = reg_ratr; if (priv->rf_type == RF_1T2R) { /* 1T2R, Spatial Stream 2 should be disabled */ ratr_value &= ~(RATE_ALL_OFDM_2SS); - /*DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value);*/ } - /*DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value);*/ - /*cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]);*/ write_nic_dword(dev, RATR0, ratr_value); write_nic_byte(dev, UFWP, 1); } @@ -1533,7 +1473,6 @@ static void dm_bb_initialgain_restore(struct net_device *dev) return; /* Disable Initial Gain */ - /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */ rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1); rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1); @@ -1548,7 +1487,6 @@ static void dm_bb_initialgain_restore(struct net_device *dev) RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n", priv->initgain_backup.xdagccore1); RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca); /* Enable Initial Gain */ - /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100);*/ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); /* Only clear byte 1 and rewrite. */ } /* dm_BBInitialGainRestore */ @@ -1561,7 +1499,6 @@ static void dm_bb_initialgain_backup(struct net_device *dev) if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) return; - /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */ priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask); priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask); @@ -1589,12 +1526,8 @@ static void dm_bb_initialgain_backup(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 05/15/2008 amy Create Version 0 porting from windows code. - * - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ static void dm_dig_init(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -1634,11 +1567,8 @@ static void dm_dig_init(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 05/27/2008 amy Create Version 0 porting from windows code. - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ static void dm_ctrl_initgain_byrssi(struct net_device *dev) { if (!dm_digtable.dig_enable_flag) @@ -1663,7 +1593,6 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi( if (!dm_digtable.dig_enable_flag) return; - /*DbgPrint("Dig by Sw Rssi\n");*/ if (dm_digtable.dig_algorithm_switch) /* if switched algorithm, we have to disable FW Dig. */ fw_dig = 0; @@ -1680,11 +1609,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi( else dm_digtable.cur_connect_state = DIG_DISCONNECT; - /*DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d\n", - DM_DigTable.PreConnectState, DM_DigTable.CurConnectState);*/ - dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb; - /*DbgPrint("DM_DigTable.Rssi_val = %d\n", DM_DigTable.Rssi_val);*/ dm_initial_gain(dev); dm_pd_th(dev); dm_cs_ratio(dev); @@ -1720,11 +1645,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh)) return; - /*DbgPrint("Dig by Fw False Alarm\n");*/ - /*if (DM_DigTable.Dig_State == DM_STA_DIG_OFF)*/ - /*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d", - pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh, - DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/ /* 1. When RSSI decrease, We have to judge if it is smaller than a threshold * and then execute the step below. */ @@ -1757,12 +1677,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. */ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40); - else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) - else - PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40); - */ } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); @@ -1770,7 +1684,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( write_nic_byte(dev, 0xa0a, 0x08); /* 1.5 Higher EDCCA. */ - /*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);*/ return; } @@ -1791,7 +1704,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( reset_cnt = priv->reset_count; dm_digtable.dig_state = DM_STA_DIG_ON; - /*DbgPrint("DIG ON\n\r");*/ /* 2.1 Set initial gain. * 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment. @@ -1814,13 +1726,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. */ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - /* - else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) - else - PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42); - */ } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); @@ -1830,7 +1735,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( /* 2.4 Lower EDCCA. * 2008/01/11 MH 90/92 series are the same. */ - /*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);*/ /* 2.5 DIG On. */ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); /* Only clear byte 1 and rewrite. */ @@ -1850,12 +1754,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 05/28/2008 amy Create Version 0 porting from windows code. - * - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ static void dm_ctrl_initgain_byrssi_highpwr( struct net_device *dev) { @@ -1881,11 +1781,6 @@ static void dm_ctrl_initgain_byrssi_highpwr( /* 3.1 Higher PD_TH for OFDM for high power state. */ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); - - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); - */ - } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); } else { @@ -1899,10 +1794,6 @@ static void dm_ctrl_initgain_byrssi_highpwr( /* 3.2 Recover PD_TH for OFDM for normal power region. */ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - */ - } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); } @@ -1944,7 +1835,6 @@ static void dm_initial_gain( dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; dm_digtable.pre_ig_value = 0; } - /*DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue);*/ /* if silent reset happened, we should rewrite the values back */ if (priv->reset_count != reset_cnt) { @@ -1960,7 +1850,6 @@ static void dm_initial_gain( if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) || !initialized || force_write) { initial_gain = (u8)dm_digtable.cur_ig_value; - /*DbgPrint("Write initial gain = 0x%x\n", initial_gain);*/ /* Set initial gain. */ write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); @@ -2012,7 +1901,6 @@ static void dm_pd_th( { if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) || (initialized <= 3) || force_write) { - /*DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState);*/ if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) { /* Lower PD_TH for OFDM. */ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { @@ -2020,9 +1908,6 @@ static void dm_pd_th( * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. */ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); - */ } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); } else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) { @@ -2032,18 +1917,12 @@ static void dm_pd_th( * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. */ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); - */ } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) { /* Higher PD_TH for OFDM for high power state. */ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) { write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); - /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) - write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); - */ } else write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); } @@ -2090,7 +1969,6 @@ static void dm_cs_ratio( { if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || !initialized || force_write) { - /*DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState);*/ if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) { /* Lower CS ratio for CCK. */ write_nic_byte(dev, 0xa0a, 0x08); @@ -2119,7 +1997,6 @@ static void dm_check_edca_turbo( { struct r8192_priv *priv = ieee80211_priv(dev); PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; - /*PSTA_QOS pStaQos = pMgntInfo->pStaQos;*/ /* Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. */ static unsigned long lastTxOkCnt; @@ -2136,20 +2013,16 @@ static void dm_check_edca_turbo( if (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO) goto dm_CheckEdcaTurbo_EXIT; - /*printk("========>%s():bis_any_nonbepkts is %d\n", __func__, priv->bis_any_nonbepkts);*/ - /* Check the status for current condition. */ if (!priv->ieee80211->bis_any_nonbepkts) { curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; /* For RT-AP, we needs to turn it on when Rx>Tx */ if (curRxOkCnt > 4*curTxOkCnt) { - /*printk("%s():curRxOkCnt > 4*curTxOkCnt\n");*/ if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = true; } } else { - /*printk("%s():curRxOkCnt < 4*curTxOkCnt\n");*/ if (priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = false; @@ -2249,7 +2122,6 @@ static void dm_ctstoself(struct net_device *dev) curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; if (curRxOkCnt > 4*curTxOkCnt) { /* downlink, disable CTS to self */ pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; - /*DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n");*/ } else { /* uplink */ pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; } @@ -2269,12 +2141,8 @@ static void dm_ctstoself(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 05/28/2008 amy Create Version 0 porting from windows code. - * - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ static void dm_check_pbc_gpio(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -2303,18 +2171,13 @@ static void dm_check_pbc_gpio(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 01/30/2008 MHC Create Version 0. - * - *---------------------------------------------------------------------------*/ + *--------------------------------------------------------------------------- + */ void dm_rf_pathcheck_workitemcallback(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct r8192_priv *priv = container_of(dwork, struct r8192_priv, rfpath_check_wq); struct net_device *dev = priv->ieee80211->dev; - /*bool bactually_set = false;*/ u8 rfpath = 0, i; /* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will @@ -2378,7 +2241,6 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev) if (priv->ieee80211->mode == WIRELESS_MODE_B) { DM_RxPathSelTable.cck_method = CCK_RX_VERSION_2; /* pure B mode, fixed cck version2 */ - /*DbgPrint("Pure B mode, use cck rx version2\n");*/ } /* decide max/sec/min rssi index */ @@ -2531,7 +2393,6 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev) if ((DM_RxPathSelTable.disabled_rf >> i) & 0x1) { /* disabled rf */ if (tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) { /* enable the BB Rx path */ - /*DbgPrint("RF-%d is enabled.\n", 0x1<framesync); reg_c38_State = RegC38_Default; - /*DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x\n", pHalData->framesync);*/ } } } else { if (reg_c38_State) { write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; - /*DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x\n", pHalData->framesync);*/ } } } @@ -2848,55 +2702,15 @@ void dm_check_fsync(struct net_device *dev) write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; reset_cnt = priv->reset_count; - /*DbgPrint("reg_c38_State = 0 for silent reset.\n");*/ } } else { if (reg_c38_State) { write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; - /*DbgPrint("framesync no monitor, write 0xc38 = 0x%x\n", pHalData->framesync);*/ } } } -/*----------------------------------------------------------------------------- - * Function: dm_shadow_init() - * - * Overview: Store all NIC MAC/BB register content. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 05/29/2008 amy Create Version 0 porting from windows code. - * - *--------------------------------------------------------------------------- - */ -void dm_shadow_init(struct net_device *dev) -{ - u8 page; - u16 offset; - - for (page = 0; page < 5; page++) - for (offset = 0; offset < 256; offset++) { - read_nic_byte(dev, offset + page * 256, &dm_shadow[page][offset]); - /*DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]);*/ - } - - for (page = 8; page < 11; page++) - for (offset = 0; offset < 256; offset++) - read_nic_byte(dev, offset + page * 256, &dm_shadow[page][offset]); - - for (page = 12; page < 15; page++) - for (offset = 0; offset < 256; offset++) - read_nic_byte(dev, offset + page * 256, &dm_shadow[page][offset]); - -} /* dm_shadow_init */ - /*---------------------------Define function prototype------------------------*/ /*----------------------------------------------------------------------------- * Function: DM_DynamicTxPower() @@ -2909,11 +2723,6 @@ void dm_shadow_init(struct net_device *dev) * Output: NONE * * Return: NONE - * - * Revised History: - * When Who Remark - * 03/06/2008 Jacken Create Version 0. - * *--------------------------------------------------------------------------- */ static void dm_init_dynamic_txpower(struct net_device *dev) @@ -2939,7 +2748,6 @@ static void dm_dynamic_txpower(struct net_device *dev) priv->bDynamicTxLowPower = false; return; } - /*printk("priv->ieee80211->current_network.unknown_cap_exist is %d , priv->ieee80211->current_network.broadcom_cap_exist is %d\n", priv->ieee80211->current_network.unknown_cap_exist, priv->ieee80211->current_network.broadcom_cap_exist);*/ if ((priv->ieee80211->current_network.atheros_cap_exist) && (priv->ieee80211->mode == IEEE_G)) { txhipower_threshold = TX_POWER_ATHEROAP_THRESH_HIGH; txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW; @@ -2948,7 +2756,6 @@ static void dm_dynamic_txpower(struct net_device *dev) txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW; } - /*printk("=======>%s(): txhipower_threshold is %d, txlowpower_threshold is %d\n", __func__, txhipower_threshold, txlowpower_threshold);*/ RT_TRACE(COMP_TXAGC, "priv->undecorated_smoothed_pwdb = %ld\n", priv->undecorated_smoothed_pwdb); if (priv->ieee80211->state == IEEE80211_LINKED) { @@ -2967,7 +2774,6 @@ static void dm_dynamic_txpower(struct net_device *dev) priv->bDynamicTxLowPower = false; } } else { - /*pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;*/ priv->bDynamicTxHighPower = false; priv->bDynamicTxLowPower = false; } @@ -2994,14 +2800,10 @@ static void dm_check_txrateandretrycount(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee80211; /* for 11n tx rate */ - /*priv->stats.CurrentShowTxate = read_nic_byte(dev, CURRENT_TX_RATE_REG);*/ read_nic_byte(dev, CURRENT_TX_RATE_REG, &ieee->softmac_stats.CurrentShowTxate); - /*printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate);*/ /* for initial tx rate */ - /*priv->stats.last_packet_rate = read_nic_byte(dev, INITIAL_TX_RATE_REG);*/ read_nic_byte(dev, INITIAL_TX_RATE_REG, &ieee->softmac_stats.last_packet_rate); /* for tx retry count */ - /*priv->stats.txretrycount = read_nic_dword(dev, TX_RETRY_COUNT_REG);*/ read_nic_dword(dev, TX_RETRY_COUNT_REG, &ieee->softmac_stats.txretrycount); } diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h index 2159018b4e38..f4eb18216677 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.h +++ b/drivers/staging/rtl8192u/r8192U_dm.h @@ -168,7 +168,6 @@ void dm_rf_operation_test_callback(unsigned long data); void dm_rf_pathcheck_workitemcallback(struct work_struct *work); void dm_fsync_work_callback(struct work_struct *work); void dm_cck_txpower_adjust(struct net_device *dev, bool binch14); -void dm_shadow_init(struct net_device *dev); void dm_initialize_txpower_tracking(struct net_device *dev); /*--------------------------Exported Function prototype---------------------*/ diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index 97f4d89500ae..e6836eacc7aa 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -1044,93 +1044,6 @@ static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel) } } -/****************************************************************************** - * function: This function sets RF state on or off - * input: net_device *dev - * RT_RF_POWER_STATE eRFPowerState //Power State to set - * output: none - * return: none - * notice: - *****************************************************************************/ -bool rtl8192_SetRFPowerState(struct net_device *dev, - RT_RF_POWER_STATE eRFPowerState) -{ - bool bResult = true; - struct r8192_priv *priv = ieee80211_priv(dev); - - if (eRFPowerState == priv->ieee80211->eRFPowerState) - return false; - - if (priv->SetRFPowerStateInProgress) - return false; - - priv->SetRFPowerStateInProgress = true; - - switch (priv->rf_chip) { - case RF_8256: - switch (eRFPowerState) { - case eRfOn: - /* RF-A, RF-B */ - /* enable RF-Chip A/B - 0x860[4] */ - rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT(4), - 0x1); - /* analog to digital on - 0x88c[9:8] */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, - 0x3); - /* digital to analog on - 0x880[4:3] */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, - 0x3); - /* rx antenna on - 0xc04[1:0] */ - rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x3, 0x3); - /* rx antenna on - 0xd04[1:0] */ - rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x3, 0x3); - /* analog to digital part2 on - 0x880[6:5] */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, - 0x3); - - break; - - case eRfSleep: - - break; - - case eRfOff: - /* RF-A, RF-B */ - /* disable RF-Chip A/B - 0x860[4] */ - rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT(4), - 0x0); - /* analog to digital off, for power save */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, - 0x0); /* 0x88c[11:8] */ - /* digital to analog off, for power save - 0x880[4:3] */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, - 0x0); - /* rx antenna off - 0xc04[3:0] */ - rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0); - /* rx antenna off - 0xd04[3:0] */ - rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); - /* analog to digital part2 off, for power save */ - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, - 0x0); /* 0x880[6:5] */ - - break; - - default: - bResult = false; - RT_TRACE(COMP_ERR, "%s(): unknown state to set: 0x%X\n", - __func__, eRFPowerState); - break; - } - break; - default: - RT_TRACE(COMP_ERR, "Not support rf_chip(%x)\n", priv->rf_chip); - break; - } - priv->SetRFPowerStateInProgress = false; - - return bResult; -} - /****************************************************************************** * function: This function sets command table variable (struct sw_chnl_cmd). * input: sw_chnl_cmd *CmdTable //table to be set diff --git a/drivers/staging/rtl8192u/r819xU_phy.h b/drivers/staging/rtl8192u/r819xU_phy.h index 8c2933264407..bafaa6a90c50 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.h +++ b/drivers/staging/rtl8192u/r819xU_phy.h @@ -74,8 +74,6 @@ void rtl8192_SetBWMode(struct net_device *dev, enum ht_extension_chan_offset offset); void rtl8192_SwChnl_WorkItem(struct net_device *dev); void rtl8192_SetBWModeWorkItem(struct net_device *dev); -bool rtl8192_SetRFPowerState(struct net_device *dev, - RT_RF_POWER_STATE eRFPowerState); void InitialGain819xUsb(struct net_device *dev, u8 Operation); void InitialGainOperateWorkItemCallBack(struct work_struct *work); diff --git a/drivers/staging/rtl8712/rtl8712_efuse.h b/drivers/staging/rtl8712/rtl8712_efuse.h index 2e1ea9d7a295..7a49740212eb 100644 --- a/drivers/staging/rtl8712/rtl8712_efuse.h +++ b/drivers/staging/rtl8712/rtl8712_efuse.h @@ -23,6 +23,7 @@ struct PGPKT_STRUCT { u8 word_en; u8 data[PGPKT_DATA_SIZE]; }; + /*--------------------------------------------------------------------------*/ u8 r8712_efuse_reg_init(struct _adapter *padapter); void r8712_efuse_reg_uninit(struct _adapter *padapter); diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 63e12b157001..fccfa0915a02 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -663,7 +663,7 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) if (!pnetwork) return; memcpy((u8 *)pnetwork + 16, (u8 *)pbuf + 8, - sizeof(struct wlan_network) - 16); + sizeof(struct wlan_network) - 16); } else { pnetwork = (struct wlan_network *)pbuf; } @@ -674,36 +674,36 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) pnetwork->network_type = le32_to_cpu(pnetwork->network_type); pnetwork->network.Length = le32_to_cpu(pnetwork->network.Length); pnetwork->network.Ssid.SsidLength = - le32_to_cpu(pnetwork->network.Ssid.SsidLength); + le32_to_cpu(pnetwork->network.Ssid.SsidLength); pnetwork->network.Privacy = le32_to_cpu(pnetwork->network.Privacy); pnetwork->network.Rssi = le32_to_cpu(pnetwork->network.Rssi); pnetwork->network.NetworkTypeInUse = - le32_to_cpu(pnetwork->network.NetworkTypeInUse); + le32_to_cpu(pnetwork->network.NetworkTypeInUse); pnetwork->network.Configuration.ATIMWindow = - le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); + le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); pnetwork->network.Configuration.BeaconPeriod = - le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); + le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); pnetwork->network.Configuration.DSConfig = - le32_to_cpu(pnetwork->network.Configuration.DSConfig); + le32_to_cpu(pnetwork->network.Configuration.DSConfig); pnetwork->network.Configuration.FHConfig.DwellTime = - le32_to_cpu(pnetwork->network.Configuration.FHConfig.DwellTime); + le32_to_cpu(pnetwork->network.Configuration.FHConfig.DwellTime); pnetwork->network.Configuration.FHConfig.HopPattern = - le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopPattern); + le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopPattern); pnetwork->network.Configuration.FHConfig.HopSet = - le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet); + le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet); pnetwork->network.Configuration.FHConfig.Length = - le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length); + le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length); pnetwork->network.Configuration.Length = - le32_to_cpu(pnetwork->network.Configuration.Length); + le32_to_cpu(pnetwork->network.Configuration.Length); pnetwork->network.InfrastructureMode = - le32_to_cpu(pnetwork->network.InfrastructureMode); + le32_to_cpu(pnetwork->network.InfrastructureMode); pnetwork->network.IELength = le32_to_cpu(pnetwork->network.IELength); #endif the_same_macaddr = !memcmp(pnetwork->network.MacAddress, - cur_network->network.MacAddress, ETH_ALEN); + cur_network->network.MacAddress, ETH_ALEN); pnetwork->network.Length = - r8712_get_wlan_bssid_ex_sz(&pnetwork->network); + r8712_get_wlan_bssid_ex_sz(&pnetwork->network); spin_lock_irqsave(&pmlmepriv->lock, irqL); if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) goto ignore_joinbss_callback; @@ -713,24 +713,24 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, _FW_LINKED)) { if (the_same_macaddr) { ptarget_wlan = - r8712_find_network(&pmlmepriv->scanned_queue, - cur_network->network.MacAddress); + r8712_find_network(&pmlmepriv->scanned_queue, + cur_network->network.MacAddress); } else { pcur_wlan = - r8712_find_network(&pmlmepriv->scanned_queue, - cur_network->network.MacAddress); + r8712_find_network(&pmlmepriv->scanned_queue, + cur_network->network.MacAddress); if (pcur_wlan) pcur_wlan->fixed = false; pcur_sta = r8712_get_stainfo(pstapriv, - cur_network->network.MacAddress); + cur_network->network.MacAddress); spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL2); r8712_free_stainfo(adapter, pcur_sta); spin_unlock_irqrestore(&(pstapriv->sta_hash_lock), irqL2); ptarget_wlan = - r8712_find_network(&pmlmepriv->scanned_queue, - pnetwork->network.MacAddress); + r8712_find_network(&pmlmepriv->scanned_queue, + pnetwork->network.MacAddress); if (ptarget_wlan) ptarget_wlan->fixed = true; } @@ -745,7 +745,7 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) pmlmepriv->fw_state ^= - _FW_UNDER_LINKING; + _FW_UNDER_LINKING; goto ignore_joinbss_callback; } @@ -753,16 +753,16 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { if (the_same_macaddr) { ptarget_sta = - r8712_get_stainfo(pstapriv, - pnetwork->network.MacAddress); + r8712_get_stainfo(pstapriv, + pnetwork->network.MacAddress); if (!ptarget_sta) ptarget_sta = - r8712_alloc_stainfo(pstapriv, - pnetwork->network.MacAddress); + r8712_alloc_stainfo(pstapriv, + pnetwork->network.MacAddress); } else { ptarget_sta = - r8712_alloc_stainfo(pstapriv, - pnetwork->network.MacAddress); + r8712_alloc_stainfo(pstapriv, + pnetwork->network.MacAddress); } if (ptarget_sta) /*update ptarget_sta*/ { ptarget_sta->aid = pnetwork->join_res; @@ -773,27 +773,28 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) adapter->securitypriv.busetkipkey = false; adapter->securitypriv.bgrpkey_handshake = false; ptarget_sta->ieee8021x_blocked = true; - ptarget_sta->XPrivacy = adapter-> - securitypriv.PrivacyAlgrthm; + ptarget_sta->XPrivacy = + adapter->securitypriv.PrivacyAlgrthm; memset((u8 *)&ptarget_sta->x_UncstKey, - 0, - sizeof(union Keytype)); + 0, + sizeof(union Keytype)); memset((u8 *)&ptarget_sta->tkiprxmickey, - 0, - sizeof(union Keytype)); + 0, + sizeof(union Keytype)); memset((u8 *)&ptarget_sta->tkiptxmickey, - 0, - sizeof(union Keytype)); - memset((u8 *)&ptarget_sta->txpn, 0, - sizeof(union pn48)); - memset((u8 *)&ptarget_sta->rxpn, 0, - sizeof(union pn48)); + 0, + sizeof(union Keytype)); + memset((u8 *)&ptarget_sta->txpn, + 0, + sizeof(union pn48)); + memset((u8 *)&ptarget_sta->rxpn, + 0, + sizeof(union pn48)); } } else { - if (check_fwstate(pmlmepriv, - _FW_UNDER_LINKING)) + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) pmlmepriv->fw_state ^= - _FW_UNDER_LINKING; + _FW_UNDER_LINKING; goto ignore_joinbss_callback; } } @@ -815,12 +816,12 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) break; } r8712_update_protection(adapter, - (cur_network->network.IEs) + - sizeof(struct NDIS_802_11_FIXED_IEs), - (cur_network->network.IELength)); + (cur_network->network.IEs) + + sizeof(struct NDIS_802_11_FIXED_IEs), + (cur_network->network.IELength)); /*TODO: update HT_Capability*/ update_ht_cap(adapter, cur_network->network.IEs, - cur_network->network.IELength); + cur_network->network.IELength); /*indicate connect*/ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) r8712_indicate_connect(adapter); @@ -831,7 +832,7 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) } else { if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { mod_timer(&pmlmepriv->assoc_timer, - jiffies + msecs_to_jiffies(1)); + jiffies + msecs_to_jiffies(1)); _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); } } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index c6fd6cf741ef..7e2c61c75150 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -32,8 +32,6 @@ int rtw_init_mlme_priv(struct adapter *padapter) INIT_LIST_HEAD(&pmlmepriv->scanned_queue.queue); spin_lock_init(&pmlmepriv->scanned_queue.lock); - set_scanned_network_val(pmlmepriv, 0); - memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); pbuf = vzalloc(array_size(MAX_BSS_CNT, sizeof(struct wlan_network))); @@ -161,8 +159,6 @@ struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) pnetwork->aid = 0; pnetwork->join_res = 0; - pmlmepriv->num_of_scanned++; - exit: spin_unlock_bh(&free_queue->lock); @@ -198,8 +194,6 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor list_add_tail(&(pnetwork->list), &(free_queue->queue)); - pmlmepriv->num_of_scanned--; - spin_unlock_bh(&free_queue->lock); } @@ -220,8 +214,6 @@ void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network * list_add_tail(&(pnetwork->list), get_list_head(free_queue)); - pmlmepriv->num_of_scanned--; - /* spin_unlock_irqrestore(&free_queue->lock, irqL); */ } @@ -863,7 +855,6 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv) list_del_init(plist); list_add_tail(plist, &free_queue->queue); plist = ptemp; - pmlmepriv->num_of_scanned--; } spin_unlock_bh(&free_queue->lock); @@ -1549,7 +1540,7 @@ void _rtw_join_timeout_handler(struct timer_list *t) if (adapter->bDriverStopped || adapter->bSurpriseRemoved) return; - spin_lock_irq(&pmlmepriv->lock); + spin_lock_bh(&pmlmepriv->lock); if (rtw_to_roam(adapter) > 0) { /* join timeout caused by roaming */ while (1) { @@ -1577,7 +1568,7 @@ void _rtw_join_timeout_handler(struct timer_list *t) } - spin_unlock_irq(&pmlmepriv->lock); + spin_unlock_bh(&pmlmepriv->lock); } /* @@ -1590,11 +1581,11 @@ void rtw_scan_timeout_handler(struct timer_list *t) mlmepriv.scan_to_timer); struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - spin_lock_irq(&pmlmepriv->lock); + spin_lock_bh(&pmlmepriv->lock); _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - spin_unlock_irq(&pmlmepriv->lock); + spin_unlock_bh(&pmlmepriv->lock); rtw_indicate_scan_done(adapter, true); } diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c index e36f8c369a04..e26b789b9cdd 100644 --- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c +++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c @@ -1177,14 +1177,6 @@ bool hal_btcoex_IsBtDisabled(struct adapter *padapter) return false; } -void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType) -{ - struct hal_com_data *pHalData; - - - pHalData = GET_HAL_DATA(padapter); -} - void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum) { struct hal_com_data *pHalData; diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index e42556d03bce..852232102433 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -859,22 +859,6 @@ bool eqNByte(u8 *str1, u8 *str2, u32 num) return true; } -/* */ -/* Description: */ -/* Translate a character to hex digit. */ -/* */ -u32 MapCharToHexDigit(char chTmp) -{ - if (chTmp >= '0' && chTmp <= '9') - return chTmp - '0'; - else if (chTmp >= 'a' && chTmp <= 'f') - return 10 + (chTmp - 'a'); - else if (chTmp >= 'A' && chTmp <= 'F') - return 10 + (chTmp - 'A'); - else - return 0; -} - bool GetU1ByteIntegerFromStringInDecimal(char *Str, u8 *pInt) { u16 i = 0; @@ -893,45 +877,6 @@ bool GetU1ByteIntegerFromStringInDecimal(char *Str, u8 *pInt) return true; } -/* <20121004, Kordan> For example, - * ParseQualifiedString(inString, 0, outString, '[', ']') gets "Kordan" from - * a string "Hello [Kordan]". - * If RightQualifier does not exist, it will hang in the while loop - */ -bool ParseQualifiedString( - char *In, u32 *Start, char *Out, char LeftQualifier, char RightQualifier -) -{ - u32 i = 0, j = 0; - char c = In[(*Start)++]; - - if (c != LeftQualifier) - return false; - - i = (*Start); - while ((c = In[(*Start)++]) != RightQualifier) - ; /* find ']' */ - j = (*Start) - 2; - strncpy((char *)Out, (const char *)(In+i), j-i+1); - - return true; -} - -bool isAllSpaceOrTab(u8 *data, u8 size) -{ - u8 cnt = 0, NumOfSpaceAndTab = 0; - - while (size > cnt) { - if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0') - ++NumOfSpaceAndTab; - - ++cnt; - } - - return size == NumOfSpaceAndTab; -} - - void rtw_hal_check_rxfifo_full(struct adapter *adapter) { struct dvobj_priv *psdpriv = adapter->dvobj; @@ -952,60 +897,7 @@ void rtw_hal_check_rxfifo_full(struct adapter *adapter) } } -void linked_info_dump(struct adapter *padapter, u8 benable) -{ - struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); - - if (padapter->bLinkInfoDump == benable) - return; - - if (benable) { - pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ - rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); - - pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */ - rtw_pm_set_ips(padapter, IPS_NONE); - } else { - rtw_pm_set_ips(padapter, pwrctrlpriv->ips_org_mode); - - rtw_pm_set_lps(padapter, pwrctrlpriv->ips_org_mode); - } - padapter->bLinkInfoDump = benable; -} - #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA -void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter) -{ - u8 isCCKrate, rf_path; - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; - - netdev_dbg(padapter->pnetdev, - "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", - HDATA_RATE(psample_pkt_rssi->data_rate), - psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); - - isCCKrate = psample_pkt_rssi->data_rate <= DESC_RATE11M; - - if (isCCKrate) - psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; - - for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { - netdev_dbg(padapter->pnetdev, - "RF_PATH_%d =>signal_strength:%d(%%), signal_quality:%d(%%)\n", - rf_path, - psample_pkt_rssi->mimo_signal_strength[rf_path], - psample_pkt_rssi->mimo_signal_quality[rf_path]); - - if (!isCCKrate) { - netdev_dbg(padapter->pnetdev, - "\trx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", - psample_pkt_rssi->ofdm_pwr[rf_path], - psample_pkt_rssi->ofdm_snr[rf_path]); - } - } -} - void rtw_dump_raw_rssi_info(struct adapter *padapter) { u8 isCCKrate, rf_path; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 0fcae6871108..c3c1b49674d3 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -2304,7 +2304,6 @@ void Hal_EfuseParseBTCoexistInfo_8723B( } hal_btcoex_SetBTCoexist(padapter, pHalData->EEPROMBluetoothCoexist); - hal_btcoex_SetChipType(padapter, pHalData->EEPROMBluetoothType); hal_btcoex_SetPgAntNum(padapter, pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1); if (pHalData->EEPROMBluetoothAntNum == Ant_x1) hal_btcoex_SetSingleAntPath(padapter, pHalData->ant_path); diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 82159e1c7f9b..ea6bb44c5e1d 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -305,7 +305,11 @@ struct sdio_data intf_data; }; #define dvobj_to_pwrctl(dvobj) (&(dvobj->pwrctl_priv)) -#define pwrctl_to_dvobj(pwrctl) container_of(pwrctl, struct dvobj_priv, pwrctl_priv) + +static inline struct dvobj_priv *pwrctl_to_dvobj(struct pwrctrl_priv *pwrctl_priv) +{ + return container_of(pwrctl_priv, struct dvobj_priv, pwrctl_priv); +} static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) { diff --git a/drivers/staging/rtl8723bs/include/hal_btcoex.h b/drivers/staging/rtl8723bs/include/hal_btcoex.h index fb167642da01..525cce3574fe 100644 --- a/drivers/staging/rtl8723bs/include/hal_btcoex.h +++ b/drivers/staging/rtl8723bs/include/hal_btcoex.h @@ -23,7 +23,6 @@ struct bt_coexist { void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist); bool hal_btcoex_IsBtExist(struct adapter *padapter); bool hal_btcoex_IsBtDisabled(struct adapter *); -void hal_btcoex_SetChipType(struct adapter *padapter, u8 chipType); void hal_btcoex_SetPgAntNum(struct adapter *padapter, u8 antNum); void hal_btcoex_SetSingleAntPath(struct adapter *padapter, u8 singleAntPath); diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h index 6356b8c2ef81..17d5cfb66a36 100644 --- a/drivers/staging/rtl8723bs/include/hal_com.h +++ b/drivers/staging/rtl8723bs/include/hal_com.h @@ -147,18 +147,9 @@ u8 GetHalDefVar(struct adapter *adapter, enum hal_def_variable variable, bool eqNByte(u8 *str1, u8 *str2, u32 num); -u32 MapCharToHexDigit(char chTmp); - -bool ParseQualifiedString(char *In, u32 *Start, char *Out, char LeftQualifier, - char RightQualifier); - bool GetU1ByteIntegerFromStringInDecimal(char *str, u8 *in); -bool isAllSpaceOrTab(u8 *data, u8 size); - -void linked_info_dump(struct adapter *padapter, u8 benable); #ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA -void rtw_get_raw_rssi_info(void *sel, struct adapter *padapter); void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe); void rtw_dump_raw_rssi_info(struct adapter *padapter); #endif diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index 9041d8dc5fb1..1098b0209200 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -174,7 +174,7 @@ struct ieee_param { u8 reserved[32]; u8 data[]; } wpa_ie; - struct{ + struct{ int command; int reason_code; } mlme; @@ -271,10 +271,10 @@ struct eapol { #define P80211_OUI_LEN 3 struct ieee80211_snap_hdr { - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ } __attribute__ ((packed)); #define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) @@ -342,12 +342,13 @@ struct ieee80211_snap_hdr { #define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) #define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) -#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_RATES_MASK 0x0000000F #define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ IEEE80211_CCK_RATE_2MB_MASK) -#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ - IEEE80211_CCK_RATE_5MB_MASK | \ - IEEE80211_CCK_RATE_11MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK \ + (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) #define IEEE80211_OFDM_RATES_MASK 0x00000FF0 #define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ @@ -359,8 +360,9 @@ struct ieee80211_snap_hdr { IEEE80211_OFDM_RATE_36MB_MASK | \ IEEE80211_OFDM_RATE_48MB_MASK | \ IEEE80211_OFDM_RATE_54MB_MASK) -#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ - IEEE80211_CCK_DEFAULT_RATES_MASK) +#define IEEE80211_DEFAULT_RATES_MASK \ + (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) #define IEEE80211_NUM_OFDM_RATES 8 #define IEEE80211_NUM_CCK_RATES 4 @@ -509,7 +511,7 @@ join_res: static inline int is_multicast_mac_addr(const u8 *addr) { - return ((addr[0] != 0xff) && (0x01 & addr[0])); + return ((addr[0] != 0xff) && (0x01 & addr[0])); } static inline int is_broadcast_mac_addr(const u8 *addr) @@ -612,17 +614,18 @@ enum { * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel * is not permitted. */ - enum rtw_ieee80211_channel_flags { - RTW_IEEE80211_CHAN_DISABLED = 1<<0, - RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, - RTW_IEEE80211_CHAN_NO_IBSS = 1<<2, - RTW_IEEE80211_CHAN_RADAR = 1<<3, - RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4, - RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5, - }; +enum rtw_ieee80211_channel_flags { + RTW_IEEE80211_CHAN_DISABLED = 1<<0, + RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + RTW_IEEE80211_CHAN_NO_IBSS = 1<<2, + RTW_IEEE80211_CHAN_RADAR = 1<<3, + RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4, + RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5, +}; - #define RTW_IEEE80211_CHAN_NO_HT40 \ - (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS) +#define RTW_IEEE80211_CHAN_NO_HT40 \ + (RTW_IEEE80211_CHAN_NO_HT40PLUS | \ + RTW_IEEE80211_CHAN_NO_HT40MINUS) /* Represent channel details, subset of ieee80211_channel */ struct rtw_ieee80211_channel { diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index 1b343b434f4d..fc0b43d38d9a 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -303,7 +303,6 @@ struct mlme_priv { struct __queue free_bss_pool; struct __queue scanned_queue; u8 *free_bss_buf; - u32 num_of_scanned; struct ndis_802_11_ssid assoc_ssid; u8 assoc_bssid[6]; @@ -490,25 +489,6 @@ static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, signed int state) pmlmepriv->bScanInProcess = false; } -/* - * No Limit on the calling context, - * therefore set it to be the critical section... - */ -static inline void clr_fwstate(struct mlme_priv *pmlmepriv, signed int state) -{ - spin_lock_bh(&pmlmepriv->lock); - if (check_fwstate(pmlmepriv, state) == true) - pmlmepriv->fw_state ^= state; - spin_unlock_bh(&pmlmepriv->lock); -} - -static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, signed int val) -{ - spin_lock_bh(&pmlmepriv->lock); - pmlmepriv->num_of_scanned = val; - spin_unlock_bh(&pmlmepriv->lock); -} - extern u16 rtw_get_capability(struct wlan_bssid_ex *bss); extern void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target); extern void rtw_disconnect_hdl_under_linked(struct adapter *adapter, struct sta_info *psta, u8 free_assoc); diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h index 44f67103503a..fef2fd0e8c84 100644 --- a/drivers/staging/rtl8723bs/include/rtw_recv.h +++ b/drivers/staging/rtl8723bs/include/rtw_recv.h @@ -398,8 +398,7 @@ static inline u8 *recvframe_pull(union recv_frame *precvframe, signed int sz) precvframe->u.hdr.rx_data += sz; - if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) - { + if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) { precvframe->u.hdr.rx_data -= sz; return NULL; } @@ -425,8 +424,7 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, signed int sz) precvframe->u.hdr.rx_tail += sz; - if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) - { + if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) { precvframe->u.hdr.rx_tail = prev_rx_tail; return NULL; } @@ -451,8 +449,7 @@ static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, signed int s precvframe->u.hdr.rx_tail -= sz; - if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) - { + if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) { precvframe->u.hdr.rx_tail += sz; return NULL; } diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index 42cab93982c0..c0af378ada71 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -31,13 +31,6 @@ static inline void xd_set_err_code(struct rtsx_chip *chip, u8 err_code) xd_card->err_code = err_code; } -static inline int xd_check_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct xd_info *xd_card = &chip->xd_card; - - return (xd_card->err_code == err_code); -} - static int xd_set_init_para(struct rtsx_chip *chip) { struct xd_info *xd_card = &chip->xd_card; diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 4f81765912ea..346d00df815a 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1976,7 +1976,7 @@ cleanup_mmal: return ret; } -static int bcm2835_mmal_remove(struct platform_device *pdev) +static void bcm2835_mmal_remove(struct platform_device *pdev) { int camera; struct vchiq_mmal_instance *instance = gdev[0]->instance; @@ -1986,13 +1986,11 @@ static int bcm2835_mmal_remove(struct platform_device *pdev) gdev[camera] = NULL; } vchiq_mmal_finalise(instance); - - return 0; } static struct platform_driver bcm2835_camera_driver = { .probe = bcm2835_mmal_probe, - .remove = bcm2835_mmal_remove, + .remove_new = bcm2835_mmal_remove, .driver = { .name = "bcm2835-camera", }, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index cddcd3c596c9..90a3958d1f29 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -149,7 +149,7 @@ static char *g_fragments_base; static char *g_free_fragments; static struct semaphore g_free_fragments_sema; -static DEFINE_SEMAPHORE(g_free_fragments_mutex); +static DEFINE_SEMAPHORE(g_free_fragments_mutex, 1); static int vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, @@ -1849,14 +1849,12 @@ error_exit: return err; } -static int vchiq_remove(struct platform_device *pdev) +static void vchiq_remove(struct platform_device *pdev) { platform_device_unregister(bcm2835_audio); platform_device_unregister(bcm2835_camera); vchiq_debugfs_deinit(); vchiq_deregister_chrdev(); - - return 0; } static struct platform_driver vchiq_driver = { @@ -1865,7 +1863,7 @@ static struct platform_driver vchiq_driver = { .of_match_table = vchiq_of_match, }, .probe = vchiq_probe, - .remove = vchiq_remove, + .remove_new = vchiq_remove, }; static int __init vchiq_driver_init(void) diff --git a/drivers/staging/vme_user/Kconfig b/drivers/staging/vme_user/Kconfig index c8eabf8f40f1..d65cc5510649 100644 --- a/drivers/staging/vme_user/Kconfig +++ b/drivers/staging/vme_user/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 menuconfig VME_BUS bool "VME bridge support" - depends on STAGING && PCI + depends on PCI help If you say Y here you get support for the VME bridge Framework. @@ -28,7 +28,6 @@ comment "VME Device Drivers" config VME_USER tristate "VME user space access driver" - depends on STAGING && VME_BUS help If you say Y here you want to be able to access a limited number of VME windows in a manner at least semi-compatible with the interface diff --git a/drivers/staging/vme_user/vme_fake.c b/drivers/staging/vme_user/vme_fake.c index f5d2c345978a..7c53a8a7b79b 100644 --- a/drivers/staging/vme_user/vme_fake.c +++ b/drivers/staging/vme_user/vme_fake.c @@ -329,7 +329,6 @@ err_aspace: err_dwidth: err_window: return retval; - } /* @@ -638,7 +637,6 @@ static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge, } fake_lm_check(bridge, addr, aspace, cycle); - } static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge, @@ -669,7 +667,6 @@ static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge, } fake_lm_check(bridge, addr, aspace, cycle); - } static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge, @@ -700,7 +697,6 @@ static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge, } fake_lm_check(bridge, addr, aspace, cycle); - } static ssize_t fake_master_write(struct vme_master_resource *image, void *buf, @@ -1234,7 +1230,6 @@ err_driver: kfree(fake_bridge); err_struct: return retval; - } static void __exit fake_exit(void) diff --git a/drivers/staging/vme_user/vme_tsi148.c b/drivers/staging/vme_user/vme_tsi148.c index 482049cfc664..2f5eafd50934 100644 --- a/drivers/staging/vme_user/vme_tsi148.c +++ b/drivers/staging/vme_user/vme_tsi148.c @@ -737,7 +737,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, return 0; if (!image->bus_resource.name) { - image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); + image->bus_resource.name = kmalloc(VMENAMSIZ + 3, GFP_ATOMIC); if (!image->bus_resource.name) { retval = -ENOMEM; goto err_name; @@ -983,7 +983,7 @@ static int tsi148_master_set(struct vme_master_resource *image, int enabled, goto err_aspace; } - temp_ctl &= ~(3<<4); + temp_ctl &= ~(3 << 4); if (cycle & VME_SUPER) temp_ctl |= TSI148_LCSR_OTAT_SUP; if (cycle & VME_PROG) @@ -1023,7 +1023,6 @@ err_gran: err_res: err_window: return retval; - } /* @@ -1741,7 +1740,6 @@ static int tsi148_dma_list_add(struct vme_dma_list *list, list); prev->descriptor.dnlau = cpu_to_be32(address_high); prev->descriptor.dnlal = cpu_to_be32(address_low); - } return 0; @@ -1773,7 +1771,6 @@ static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel) return 0; else return 1; - } /* @@ -2187,14 +2184,14 @@ static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, /* Ensure that the CR/CSR is configured at the correct offset */ cbar = ioread32be(bridge->base + TSI148_CBAR); - cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3; + cbar = (cbar & TSI148_CRCSR_CBAR_M) >> 3; vstat = tsi148_slot_get(tsi148_bridge); if (cbar != vstat) { cbar = vstat; dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n"); - iowrite32be(cbar<<3, bridge->base + TSI148_CBAR); + iowrite32be(cbar << 3, bridge->base + TSI148_CBAR); } dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar); @@ -2220,7 +2217,6 @@ static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, } return 0; - } static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge, @@ -2530,7 +2526,6 @@ err_driver: kfree(tsi148_bridge); err_struct: return retval; - } static void tsi148_remove(struct pci_dev *pdev) diff --git a/drivers/staging/vme_user/vme_tsi148.h b/drivers/staging/vme_user/vme_tsi148.h index b3cb4a089cc8..63f726e1811a 100644 --- a/drivers/staging/vme_user/vme_tsi148.h +++ b/drivers/staging/vme_user/vme_tsi148.h @@ -536,22 +536,22 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * PFCS Register Set */ -#define TSI148_PCFS_CMMD_SERR (1<<8) /* SERR_L out pin ssys err */ -#define TSI148_PCFS_CMMD_PERR (1<<6) /* PERR_L out pin parity */ -#define TSI148_PCFS_CMMD_MSTR (1<<2) /* PCI bus master */ -#define TSI148_PCFS_CMMD_MEMSP (1<<1) /* PCI mem space access */ -#define TSI148_PCFS_CMMD_IOSP (1<<0) /* PCI I/O space enable */ +#define TSI148_PCFS_CMMD_SERR BIT(8) /* SERR_L out pin ssys err */ +#define TSI148_PCFS_CMMD_PERR BIT(6) /* PERR_L out pin parity */ +#define TSI148_PCFS_CMMD_MSTR BIT(2) /* PCI bus master */ +#define TSI148_PCFS_CMMD_MEMSP BIT(1) /* PCI mem space access */ +#define TSI148_PCFS_CMMD_IOSP BIT(0) /* PCI I/O space enable */ -#define TSI148_PCFS_STAT_RCPVE (1<<15) /* Detected Parity Error */ -#define TSI148_PCFS_STAT_SIGSE (1<<14) /* Signalled System Error */ -#define TSI148_PCFS_STAT_RCVMA (1<<13) /* Received Master Abort */ -#define TSI148_PCFS_STAT_RCVTA (1<<12) /* Received Target Abort */ -#define TSI148_PCFS_STAT_SIGTA (1<<11) /* Signalled Target Abort */ +#define TSI148_PCFS_STAT_RCPVE BIT(15) /* Detected Parity Error */ +#define TSI148_PCFS_STAT_SIGSE BIT(14) /* Signalled System Error */ +#define TSI148_PCFS_STAT_RCVMA BIT(13) /* Received Master Abort */ +#define TSI148_PCFS_STAT_RCVTA BIT(12) /* Received Target Abort */ +#define TSI148_PCFS_STAT_SIGTA BIT(11) /* Signalled Target Abort */ #define TSI148_PCFS_STAT_SELTIM (3<<9) /* DELSEL Timing */ -#define TSI148_PCFS_STAT_DPAR (1<<8) /* Data Parity Err Reported */ -#define TSI148_PCFS_STAT_FAST (1<<7) /* Fast back-to-back Cap */ -#define TSI148_PCFS_STAT_P66M (1<<5) /* 66 MHz Capable */ -#define TSI148_PCFS_STAT_CAPL (1<<4) /* Capab List - address $34 */ +#define TSI148_PCFS_STAT_DPAR BIT(8) /* Data Parity Err Reported */ +#define TSI148_PCFS_STAT_FAST BIT(7) /* Fast back-to-back Cap */ +#define TSI148_PCFS_STAT_P66M BIT(5) /* 66 MHz Capable */ +#define TSI148_PCFS_STAT_CAPL BIT(4) /* Capab List - address $34 */ /* * Revision ID/Class Code Registers (CRG +$008) @@ -572,17 +572,17 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, * Memory Base Address Lower Reg (CRG + $010) */ #define TSI148_PCFS_MBARL_BASEL_M (0xFFFFF<<12) /* Base Addr Lower Mask */ -#define TSI148_PCFS_MBARL_PRE (1<<3) /* Prefetch */ +#define TSI148_PCFS_MBARL_PRE BIT(3) /* Prefetch */ #define TSI148_PCFS_MBARL_MTYPE_M (3<<1) /* Memory Type Mask */ -#define TSI148_PCFS_MBARL_IOMEM (1<<0) /* I/O Space Indicator */ +#define TSI148_PCFS_MBARL_IOMEM BIT(0) /* I/O Space Indicator */ /* * Message Signaled Interrupt Capabilities Register (CRG + $040) */ -#define TSI148_PCFS_MSICAP_64BAC (1<<7) /* 64-bit Address Capable */ +#define TSI148_PCFS_MSICAP_64BAC BIT(7) /* 64-bit Address Capable */ #define TSI148_PCFS_MSICAP_MME_M (7<<4) /* Multiple Msg Enable Mask */ #define TSI148_PCFS_MSICAP_MMC_M (7<<1) /* Multiple Msg Capable Mask */ -#define TSI148_PCFS_MSICAP_MSIEN (1<<0) /* Msg signaled INT Enable */ +#define TSI148_PCFS_MSICAP_MSIEN BIT(0) /* Msg signaled INT Enable */ /* * Message Address Lower Register (CRG +$044) @@ -599,22 +599,22 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, */ #define TSI148_PCFS_PCIXCAP_MOST_M (7<<4) /* Max outstanding Split Tran */ #define TSI148_PCFS_PCIXCAP_MMRBC_M (3<<2) /* Max Mem Read byte cnt */ -#define TSI148_PCFS_PCIXCAP_ERO (1<<1) /* Enable Relaxed Ordering */ -#define TSI148_PCFS_PCIXCAP_DPERE (1<<0) /* Data Parity Recover Enable */ +#define TSI148_PCFS_PCIXCAP_ERO BIT(1) /* Enable Relaxed Ordering */ +#define TSI148_PCFS_PCIXCAP_DPERE BIT(0) /* Data Parity Recover Enable */ /* * PCI-X Status Register (CRG +$054) */ -#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Received Split Comp Error */ +#define TSI148_PCFS_PCIXSTAT_RSCEM BIT(29) /* Received Split Comp Error */ #define TSI148_PCFS_PCIXSTAT_DMCRS_M (7<<26) /* max Cumulative Read Size */ #define TSI148_PCFS_PCIXSTAT_DMOST_M (7<<23) /* max outstanding Split Trans */ #define TSI148_PCFS_PCIXSTAT_DMMRC_M (3<<21) /* max mem read byte count */ -#define TSI148_PCFS_PCIXSTAT_DC (1<<20) /* Device Complexity */ -#define TSI148_PCFS_PCIXSTAT_USC (1<<19) /* Unexpected Split comp */ -#define TSI148_PCFS_PCIXSTAT_SCD (1<<18) /* Split completion discard */ -#define TSI148_PCFS_PCIXSTAT_133C (1<<17) /* 133MHz capable */ -#define TSI148_PCFS_PCIXSTAT_64D (1<<16) /* 64 bit device */ +#define TSI148_PCFS_PCIXSTAT_DC BIT(20) /* Device Complexity */ +#define TSI148_PCFS_PCIXSTAT_USC BIT(19) /* Unexpected Split comp */ +#define TSI148_PCFS_PCIXSTAT_SCD BIT(18) /* Split completion discard */ +#define TSI148_PCFS_PCIXSTAT_133C BIT(17) /* 133MHz capable */ +#define TSI148_PCFS_PCIXSTAT_64D BIT(16) /* 64 bit device */ #define TSI148_PCFS_PCIXSTAT_BN_M (0xFF<<8) /* Bus number */ #define TSI148_PCFS_PCIXSTAT_DN_M (0x1F<<3) /* Device number */ #define TSI148_PCFS_PCIXSTAT_FN_M (7<<0) /* Function Number */ @@ -646,23 +646,23 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * Outbound Translation Attribute */ -#define TSI148_LCSR_OTAT_EN (1<<31) /* Window Enable */ -#define TSI148_LCSR_OTAT_MRPFD (1<<18) /* Prefetch Disable */ +#define TSI148_LCSR_OTAT_EN BIT(31) /* Window Enable */ +#define TSI148_LCSR_OTAT_MRPFD BIT(18) /* Prefetch Disable */ #define TSI148_LCSR_OTAT_PFS_M (3<<16) /* Prefetch Size Mask */ #define TSI148_LCSR_OTAT_PFS_2 (0<<16) /* 2 Cache Lines P Size */ -#define TSI148_LCSR_OTAT_PFS_4 (1<<16) /* 4 Cache Lines P Size */ +#define TSI148_LCSR_OTAT_PFS_4 BIT(16) /* 4 Cache Lines P Size */ #define TSI148_LCSR_OTAT_PFS_8 (2<<16) /* 8 Cache Lines P Size */ #define TSI148_LCSR_OTAT_PFS_16 (3<<16) /* 16 Cache Lines P Size */ #define TSI148_LCSR_OTAT_2eSSTM_M (7<<11) /* 2eSST Xfer Rate Mask */ #define TSI148_LCSR_OTAT_2eSSTM_160 (0<<11) /* 160MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_OTAT_2eSSTM_267 (1<<11) /* 267MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_OTAT_2eSSTM_267 BIT(11) /* 267MB/s 2eSST Xfer Rate */ #define TSI148_LCSR_OTAT_2eSSTM_320 (2<<11) /* 320MB/s 2eSST Xfer Rate */ #define TSI148_LCSR_OTAT_TM_M (7<<8) /* Xfer Protocol Mask */ #define TSI148_LCSR_OTAT_TM_SCT (0<<8) /* SCT Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_BLT (1<<8) /* BLT Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_BLT BIT(8) /* BLT Xfer Protocol */ #define TSI148_LCSR_OTAT_TM_MBLT (2<<8) /* MBLT Xfer Protocol */ #define TSI148_LCSR_OTAT_TM_2eVME (3<<8) /* 2eVME Xfer Protocol */ #define TSI148_LCSR_OTAT_TM_2eSST (4<<8) /* 2eSST Xfer Protocol */ @@ -670,14 +670,14 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_OTAT_DBW_M (3<<6) /* Max Data Width */ #define TSI148_LCSR_OTAT_DBW_16 (0<<6) /* 16-bit Data Width */ -#define TSI148_LCSR_OTAT_DBW_32 (1<<6) /* 32-bit Data Width */ +#define TSI148_LCSR_OTAT_DBW_32 BIT(6) /* 32-bit Data Width */ -#define TSI148_LCSR_OTAT_SUP (1<<5) /* Supervisory Access */ -#define TSI148_LCSR_OTAT_PGM (1<<4) /* Program Access */ +#define TSI148_LCSR_OTAT_SUP BIT(5) /* Supervisory Access */ +#define TSI148_LCSR_OTAT_PGM BIT(4) /* Program Access */ #define TSI148_LCSR_OTAT_AMODE_M (0xf<<0) /* Address Mode Mask */ #define TSI148_LCSR_OTAT_AMODE_A16 (0<<0) /* A16 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_A24 (1<<0) /* A24 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_A24 BIT(0) /* A24 Address Space */ #define TSI148_LCSR_OTAT_AMODE_A32 (2<<0) /* A32 Address Space */ #define TSI148_LCSR_OTAT_AMODE_A64 (4<<0) /* A32 Address Space */ #define TSI148_LCSR_OTAT_AMODE_CRCSR (5<<0) /* CR/CSR Address Space */ @@ -689,17 +689,17 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * VME Master Control Register CRG+$234 */ -#define TSI148_LCSR_VMCTRL_VSA (1<<27) /* VMEbus Stop Ack */ -#define TSI148_LCSR_VMCTRL_VS (1<<26) /* VMEbus Stop */ -#define TSI148_LCSR_VMCTRL_DHB (1<<25) /* Device Has Bus */ -#define TSI148_LCSR_VMCTRL_DWB (1<<24) /* Device Wants Bus */ +#define TSI148_LCSR_VMCTRL_VSA BIT(27) /* VMEbus Stop Ack */ +#define TSI148_LCSR_VMCTRL_VS BIT(26) /* VMEbus Stop */ +#define TSI148_LCSR_VMCTRL_DHB BIT(25) /* Device Has Bus */ +#define TSI148_LCSR_VMCTRL_DWB BIT(24) /* Device Wants Bus */ -#define TSI148_LCSR_VMCTRL_RMWEN (1<<20) /* RMW Enable */ +#define TSI148_LCSR_VMCTRL_RMWEN BIT(20) /* RMW Enable */ #define TSI148_LCSR_VMCTRL_ATO_M (7<<16) /* Master Access Time-out Mask */ #define TSI148_LCSR_VMCTRL_ATO_32 (0<<16) /* 32 us */ -#define TSI148_LCSR_VMCTRL_ATO_128 (1<<16) /* 128 us */ +#define TSI148_LCSR_VMCTRL_ATO_128 BIT(16) /* 128 us */ #define TSI148_LCSR_VMCTRL_ATO_512 (2<<16) /* 512 us */ #define TSI148_LCSR_VMCTRL_ATO_2M (3<<16) /* 2 ms */ #define TSI148_LCSR_VMCTRL_ATO_8M (4<<16) /* 8 ms */ @@ -709,7 +709,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_VMCTRL_VTOFF_M (7<<12) /* VMEbus Master Time off */ #define TSI148_LCSR_VMCTRL_VTOFF_0 (0<<12) /* 0us */ -#define TSI148_LCSR_VMCTRL_VTOFF_1 (1<<12) /* 1us */ +#define TSI148_LCSR_VMCTRL_VTOFF_1 BIT(12) /* 1us */ #define TSI148_LCSR_VMCTRL_VTOFF_2 (2<<12) /* 2us */ #define TSI148_LCSR_VMCTRL_VTOFF_4 (3<<12) /* 4us */ #define TSI148_LCSR_VMCTRL_VTOFF_8 (4<<12) /* 8us */ @@ -719,7 +719,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_VMCTRL_VTON_M (7<<8) /* VMEbus Master Time On */ #define TSI148_LCSR_VMCTRL_VTON_4 (0<<8) /* 8us */ -#define TSI148_LCSR_VMCTRL_VTON_8 (1<<8) /* 8us */ +#define TSI148_LCSR_VMCTRL_VTON_8 BIT(8) /* 8us */ #define TSI148_LCSR_VMCTRL_VTON_16 (2<<8) /* 16us */ #define TSI148_LCSR_VMCTRL_VTON_32 (3<<8) /* 32us */ #define TSI148_LCSR_VMCTRL_VTON_64 (4<<8) /* 64us */ @@ -730,22 +730,22 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_VMCTRL_VREL_M (3<<3) /* VMEbus Master Rel Mode Mask */ #define TSI148_LCSR_VMCTRL_VREL_T_D (0<<3) /* Time on or Done */ -#define TSI148_LCSR_VMCTRL_VREL_T_R_D (1<<3) /* Time on and REQ or Done */ +#define TSI148_LCSR_VMCTRL_VREL_T_R_D BIT(3) /* Time on and REQ or Done */ #define TSI148_LCSR_VMCTRL_VREL_T_B_D (2<<3) /* Time on and BCLR or Done */ #define TSI148_LCSR_VMCTRL_VREL_T_D_R (3<<3) /* Time on or Done and REQ */ -#define TSI148_LCSR_VMCTRL_VFAIR (1<<2) /* VMEbus Master Fair Mode */ +#define TSI148_LCSR_VMCTRL_VFAIR BIT(2) /* VMEbus Master Fair Mode */ #define TSI148_LCSR_VMCTRL_VREQL_M (3<<0) /* VMEbus Master Req Level Mask */ /* * VMEbus Control Register CRG+$238 */ -#define TSI148_LCSR_VCTRL_LRE (1<<31) /* Late Retry Enable */ +#define TSI148_LCSR_VCTRL_LRE BIT(31) /* Late Retry Enable */ #define TSI148_LCSR_VCTRL_DLT_M (0xF<<24) /* Deadlock Timer */ #define TSI148_LCSR_VCTRL_DLT_OFF (0<<24) /* Deadlock Timer Off */ -#define TSI148_LCSR_VCTRL_DLT_16 (1<<24) /* 16 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_16 BIT(24) /* 16 VCLKS */ #define TSI148_LCSR_VCTRL_DLT_32 (2<<24) /* 32 VCLKS */ #define TSI148_LCSR_VCTRL_DLT_64 (3<<24) /* 64 VCLKS */ #define TSI148_LCSR_VCTRL_DLT_128 (4<<24) /* 128 VCLKS */ @@ -758,22 +758,22 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_VCTRL_DLT_16384 (0xB<<24) /* 16384 VCLKS */ #define TSI148_LCSR_VCTRL_DLT_32768 (0xC<<24) /* 32768 VCLKS */ -#define TSI148_LCSR_VCTRL_NERBB (1<<20) /* No Early Release of Bus Busy +#define TSI148_LCSR_VCTRL_NERBB BIT(20) /* No Early Release of Bus Busy */ -#define TSI148_LCSR_VCTRL_SRESET (1<<17) /* System Reset */ -#define TSI148_LCSR_VCTRL_LRESET (1<<16) /* Local Reset */ +#define TSI148_LCSR_VCTRL_SRESET BIT(17) /* System Reset */ +#define TSI148_LCSR_VCTRL_LRESET BIT(16) /* Local Reset */ -#define TSI148_LCSR_VCTRL_SFAILAI (1<<15) /* SYSFAIL Auto Slot ID */ +#define TSI148_LCSR_VCTRL_SFAILAI BIT(15) /* SYSFAIL Auto Slot ID */ #define TSI148_LCSR_VCTRL_BID_M (0x1F<<8) /* Broadcast ID Mask */ -#define TSI148_LCSR_VCTRL_ATOEN (1<<7) /* Arbiter Time-out Enable */ -#define TSI148_LCSR_VCTRL_ROBIN (1<<6) /* VMEbus Round Robin */ +#define TSI148_LCSR_VCTRL_ATOEN BIT(7) /* Arbiter Time-out Enable */ +#define TSI148_LCSR_VCTRL_ROBIN BIT(6) /* VMEbus Round Robin */ #define TSI148_LCSR_VCTRL_GTO_M (7<<0) /* VMEbus Global Time-out Mask */ #define TSI148_LCSR_VCTRL_GTO_8 (0<<0) /* 8 us */ -#define TSI148_LCSR_VCTRL_GTO_16 (1<<0) /* 16 us */ +#define TSI148_LCSR_VCTRL_GTO_16 BIT(0) /* 16 us */ #define TSI148_LCSR_VCTRL_GTO_32 (2<<0) /* 32 us */ #define TSI148_LCSR_VCTRL_GTO_64 (3<<0) /* 64 us */ #define TSI148_LCSR_VCTRL_GTO_128 (4<<0) /* 128 us */ @@ -784,48 +784,48 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * VMEbus Status Register CRG + $23C */ -#define TSI148_LCSR_VSTAT_CPURST (1<<15) /* Clear power up reset */ -#define TSI148_LCSR_VSTAT_BRDFL (1<<14) /* Board fail */ -#define TSI148_LCSR_VSTAT_PURSTS (1<<12) /* Power up reset status */ -#define TSI148_LCSR_VSTAT_BDFAILS (1<<11) /* Board Fail Status */ -#define TSI148_LCSR_VSTAT_SYSFAILS (1<<10) /* System Fail Status */ -#define TSI148_LCSR_VSTAT_ACFAILS (1<<9) /* AC fail status */ -#define TSI148_LCSR_VSTAT_SCONS (1<<8) /* System Cont Status */ -#define TSI148_LCSR_VSTAT_GAP (1<<5) /* Geographic Addr Parity */ +#define TSI148_LCSR_VSTAT_CPURST BIT(15) /* Clear power up reset */ +#define TSI148_LCSR_VSTAT_BRDFL BIT(14) /* Board fail */ +#define TSI148_LCSR_VSTAT_PURSTS BIT(12) /* Power up reset status */ +#define TSI148_LCSR_VSTAT_BDFAILS BIT(11) /* Board Fail Status */ +#define TSI148_LCSR_VSTAT_SYSFAILS BIT(10) /* System Fail Status */ +#define TSI148_LCSR_VSTAT_ACFAILS BIT(9) /* AC fail status */ +#define TSI148_LCSR_VSTAT_SCONS BIT(8) /* System Cont Status */ +#define TSI148_LCSR_VSTAT_GAP BIT(5) /* Geographic Addr Parity */ #define TSI148_LCSR_VSTAT_GA_M (0x1F<<0) /* Geographic Addr Mask */ /* * PCI Configuration Status Register CRG+$240 */ -#define TSI148_LCSR_PSTAT_REQ64S (1<<6) /* Request 64 status set */ -#define TSI148_LCSR_PSTAT_M66ENS (1<<5) /* M66ENS 66Mhz enable */ -#define TSI148_LCSR_PSTAT_FRAMES (1<<4) /* Frame Status */ -#define TSI148_LCSR_PSTAT_IRDYS (1<<3) /* IRDY status */ -#define TSI148_LCSR_PSTAT_DEVSELS (1<<2) /* DEVL status */ -#define TSI148_LCSR_PSTAT_STOPS (1<<1) /* STOP status */ -#define TSI148_LCSR_PSTAT_TRDYS (1<<0) /* TRDY status */ +#define TSI148_LCSR_PSTAT_REQ64S BIT(6) /* Request 64 status set */ +#define TSI148_LCSR_PSTAT_M66ENS BIT(5) /* M66ENS 66Mhz enable */ +#define TSI148_LCSR_PSTAT_FRAMES BIT(4) /* Frame Status */ +#define TSI148_LCSR_PSTAT_IRDYS BIT(3) /* IRDY status */ +#define TSI148_LCSR_PSTAT_DEVSELS BIT(2) /* DEVL status */ +#define TSI148_LCSR_PSTAT_STOPS BIT(1) /* STOP status */ +#define TSI148_LCSR_PSTAT_TRDYS BIT(0) /* TRDY status */ /* * VMEbus Exception Attributes Register CRG + $268 */ -#define TSI148_LCSR_VEAT_VES (1<<31) /* Status */ -#define TSI148_LCSR_VEAT_VEOF (1<<30) /* Overflow */ -#define TSI148_LCSR_VEAT_VESCL (1<<29) /* Status Clear */ -#define TSI148_LCSR_VEAT_2EOT (1<<21) /* 2e Odd Termination */ -#define TSI148_LCSR_VEAT_2EST (1<<20) /* 2e Slave terminated */ -#define TSI148_LCSR_VEAT_BERR (1<<19) /* Bus Error */ -#define TSI148_LCSR_VEAT_LWORD (1<<18) /* LWORD_ signal state */ -#define TSI148_LCSR_VEAT_WRITE (1<<17) /* WRITE_ signal state */ -#define TSI148_LCSR_VEAT_IACK (1<<16) /* IACK_ signal state */ -#define TSI148_LCSR_VEAT_DS1 (1<<15) /* DS1_ signal state */ -#define TSI148_LCSR_VEAT_DS0 (1<<14) /* DS0_ signal state */ +#define TSI148_LCSR_VEAT_VES BIT(31) /* Status */ +#define TSI148_LCSR_VEAT_VEOF BIT(30) /* Overflow */ +#define TSI148_LCSR_VEAT_VESCL BIT(29) /* Status Clear */ +#define TSI148_LCSR_VEAT_2EOT BIT(21) /* 2e Odd Termination */ +#define TSI148_LCSR_VEAT_2EST BIT(20) /* 2e Slave terminated */ +#define TSI148_LCSR_VEAT_BERR BIT(19) /* Bus Error */ +#define TSI148_LCSR_VEAT_LWORD BIT(18) /* LWORD_ signal state */ +#define TSI148_LCSR_VEAT_WRITE BIT(17) /* WRITE_ signal state */ +#define TSI148_LCSR_VEAT_IACK BIT(16) /* IACK_ signal state */ +#define TSI148_LCSR_VEAT_DS1 BIT(15) /* DS1_ signal state */ +#define TSI148_LCSR_VEAT_DS0 BIT(14) /* DS0_ signal state */ #define TSI148_LCSR_VEAT_AM_M (0x3F<<8) /* Address Mode Mask */ #define TSI148_LCSR_VEAT_XAM_M (0xFF<<0) /* Master AMode Mask */ /* * VMEbus PCI Error Diagnostics PCI/X Attributes Register CRG + $280 */ -#define TSI148_LCSR_EDPAT_EDPCL (1<<29) +#define TSI148_LCSR_EDPAT_EDPCL BIT(29) /* * Inbound Translation Starting Address Lower @@ -851,36 +851,36 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * Inbound Translation Attribute */ -#define TSI148_LCSR_ITAT_EN (1<<31) /* Window Enable */ -#define TSI148_LCSR_ITAT_TH (1<<18) /* Prefetch Threshold */ +#define TSI148_LCSR_ITAT_EN BIT(31) /* Window Enable */ +#define TSI148_LCSR_ITAT_TH BIT(18) /* Prefetch Threshold */ #define TSI148_LCSR_ITAT_VFS_M (3<<16) /* Virtual FIFO Size Mask */ #define TSI148_LCSR_ITAT_VFS_64 (0<<16) /* 64 bytes Virtual FIFO Size */ -#define TSI148_LCSR_ITAT_VFS_128 (1<<16) /* 128 bytes Virtual FIFO Sz */ +#define TSI148_LCSR_ITAT_VFS_128 BIT(16) /* 128 bytes Virtual FIFO Sz */ #define TSI148_LCSR_ITAT_VFS_256 (2<<16) /* 256 bytes Virtual FIFO Sz */ #define TSI148_LCSR_ITAT_VFS_512 (3<<16) /* 512 bytes Virtual FIFO Sz */ #define TSI148_LCSR_ITAT_2eSSTM_M (7<<12) /* 2eSST Xfer Rate Mask */ #define TSI148_LCSR_ITAT_2eSSTM_160 (0<<12) /* 160MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_ITAT_2eSSTM_267 (1<<12) /* 267MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_ITAT_2eSSTM_267 BIT(12) /* 267MB/s 2eSST Xfer Rate */ #define TSI148_LCSR_ITAT_2eSSTM_320 (2<<12) /* 320MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_ITAT_2eSSTB (1<<11) /* 2eSST Bcast Xfer Protocol */ -#define TSI148_LCSR_ITAT_2eSST (1<<10) /* 2eSST Xfer Protocol */ -#define TSI148_LCSR_ITAT_2eVME (1<<9) /* 2eVME Xfer Protocol */ -#define TSI148_LCSR_ITAT_MBLT (1<<8) /* MBLT Xfer Protocol */ -#define TSI148_LCSR_ITAT_BLT (1<<7) /* BLT Xfer Protocol */ +#define TSI148_LCSR_ITAT_2eSSTB BIT(11) /* 2eSST Bcast Xfer Protocol */ +#define TSI148_LCSR_ITAT_2eSST BIT(10) /* 2eSST Xfer Protocol */ +#define TSI148_LCSR_ITAT_2eVME BIT(9) /* 2eVME Xfer Protocol */ +#define TSI148_LCSR_ITAT_MBLT BIT(8) /* MBLT Xfer Protocol */ +#define TSI148_LCSR_ITAT_BLT BIT(7) /* BLT Xfer Protocol */ #define TSI148_LCSR_ITAT_AS_M (7<<4) /* Address Space Mask */ #define TSI148_LCSR_ITAT_AS_A16 (0<<4) /* A16 Address Space */ -#define TSI148_LCSR_ITAT_AS_A24 (1<<4) /* A24 Address Space */ +#define TSI148_LCSR_ITAT_AS_A24 BIT(4) /* A24 Address Space */ #define TSI148_LCSR_ITAT_AS_A32 (2<<4) /* A32 Address Space */ #define TSI148_LCSR_ITAT_AS_A64 (4<<4) /* A64 Address Space */ -#define TSI148_LCSR_ITAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_ITAT_NPRIV (1<<2) /* Non-Priv (User) Access */ -#define TSI148_LCSR_ITAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_ITAT_DATA (1<<0) /* Data Access */ +#define TSI148_LCSR_ITAT_SUPR BIT(3) /* Supervisor Access */ +#define TSI148_LCSR_ITAT_NPRIV BIT(2) /* Non-Priv (User) Access */ +#define TSI148_LCSR_ITAT_PGM BIT(1) /* Program Access */ +#define TSI148_LCSR_ITAT_DATA BIT(0) /* Data Access */ /* * GCSR Base Address Lower Address CRG +$404 @@ -890,18 +890,18 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * GCSR Attribute Register CRG + $408 */ -#define TSI148_LCSR_GCSRAT_EN (1<<7) /* Enable access to GCSR */ +#define TSI148_LCSR_GCSRAT_EN BIT(7) /* Enable access to GCSR */ #define TSI148_LCSR_GCSRAT_AS_M (7<<4) /* Address Space Mask */ #define TSI148_LCSR_GCSRAT_AS_A16 (0<<4) /* Address Space 16 */ -#define TSI148_LCSR_GCSRAT_AS_A24 (1<<4) /* Address Space 24 */ +#define TSI148_LCSR_GCSRAT_AS_A24 BIT(4) /* Address Space 24 */ #define TSI148_LCSR_GCSRAT_AS_A32 (2<<4) /* Address Space 32 */ #define TSI148_LCSR_GCSRAT_AS_A64 (4<<4) /* Address Space 64 */ -#define TSI148_LCSR_GCSRAT_SUPR (1<<3) /* Sup set -GCSR decoder */ -#define TSI148_LCSR_GCSRAT_NPRIV (1<<2) /* Non-Privliged set - CGSR */ -#define TSI148_LCSR_GCSRAT_PGM (1<<1) /* Program set - GCSR decoder */ -#define TSI148_LCSR_GCSRAT_DATA (1<<0) /* DATA set GCSR decoder */ +#define TSI148_LCSR_GCSRAT_SUPR BIT(3) /* Sup set -GCSR decoder */ +#define TSI148_LCSR_GCSRAT_NPRIV BIT(2) /* Non-Privliged set - CGSR */ +#define TSI148_LCSR_GCSRAT_PGM BIT(1) /* Program set - GCSR decoder */ +#define TSI148_LCSR_GCSRAT_DATA BIT(0) /* DATA set GCSR decoder */ /* * CRG Base Address Lower Address CRG + $410 @@ -911,18 +911,18 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * CRG Attribute Register CRG + $414 */ -#define TSI148_LCSR_CRGAT_EN (1<<7) /* Enable PRG Access */ +#define TSI148_LCSR_CRGAT_EN BIT(7) /* Enable PRG Access */ #define TSI148_LCSR_CRGAT_AS_M (7<<4) /* Address Space */ #define TSI148_LCSR_CRGAT_AS_A16 (0<<4) /* Address Space 16 */ -#define TSI148_LCSR_CRGAT_AS_A24 (1<<4) /* Address Space 24 */ +#define TSI148_LCSR_CRGAT_AS_A24 BIT(4) /* Address Space 24 */ #define TSI148_LCSR_CRGAT_AS_A32 (2<<4) /* Address Space 32 */ #define TSI148_LCSR_CRGAT_AS_A64 (4<<4) /* Address Space 64 */ -#define TSI148_LCSR_CRGAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_CRGAT_NPRIV (1<<2) /* Non-Privliged(User) Access */ -#define TSI148_LCSR_CRGAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_CRGAT_DATA (1<<0) /* Data Access */ +#define TSI148_LCSR_CRGAT_SUPR BIT(3) /* Supervisor Access */ +#define TSI148_LCSR_CRGAT_NPRIV BIT(2) /* Non-Privliged(User) Access */ +#define TSI148_LCSR_CRGAT_PGM BIT(1) /* Program Access */ +#define TSI148_LCSR_CRGAT_DATA BIT(0) /* Data Access */ /* * CR/CSR Offset Lower Register CRG + $41C @@ -932,7 +932,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * CR/CSR Attribute register CRG + $420 */ -#define TSI148_LCSR_CRAT_EN (1<<7) /* Enable access to CR/CSR */ +#define TSI148_LCSR_CRAT_EN BIT(7) /* Enable access to CR/CSR */ /* * Location Monitor base address lower register CRG + $428 @@ -942,18 +942,18 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * Location Monitor Attribute Register CRG + $42C */ -#define TSI148_LCSR_LMAT_EN (1<<7) /* Enable Location Monitor */ +#define TSI148_LCSR_LMAT_EN BIT(7) /* Enable Location Monitor */ #define TSI148_LCSR_LMAT_AS_M (7<<4) /* Address Space MASK */ #define TSI148_LCSR_LMAT_AS_A16 (0<<4) /* A16 */ -#define TSI148_LCSR_LMAT_AS_A24 (1<<4) /* A24 */ +#define TSI148_LCSR_LMAT_AS_A24 BIT(4) /* A24 */ #define TSI148_LCSR_LMAT_AS_A32 (2<<4) /* A32 */ #define TSI148_LCSR_LMAT_AS_A64 (4<<4) /* A64 */ -#define TSI148_LCSR_LMAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_LMAT_NPRIV (1<<2) /* Non-Priv (User) Access */ -#define TSI148_LCSR_LMAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_LMAT_DATA (1<<0) /* Data Access */ +#define TSI148_LCSR_LMAT_SUPR BIT(3) /* Supervisor Access */ +#define TSI148_LCSR_LMAT_NPRIV BIT(2) /* Non-Priv (User) Access */ +#define TSI148_LCSR_LMAT_PGM BIT(1) /* Program Access */ +#define TSI148_LCSR_LMAT_DATA BIT(0) /* Data Access */ /* * Broadcast Pulse Generator Timer Register CRG + $438 @@ -969,34 +969,34 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, * VMEbus Interrupt Control Register CRG + $43C */ #define TSI148_LCSR_VICR_CNTS_M (3<<22) /* Cntr Source MASK */ -#define TSI148_LCSR_VICR_CNTS_DIS (1<<22) /* Cntr Disable */ +#define TSI148_LCSR_VICR_CNTS_DIS BIT(22) /* Cntr Disable */ #define TSI148_LCSR_VICR_CNTS_IRQ1 (2<<22) /* IRQ1 to Cntr */ #define TSI148_LCSR_VICR_CNTS_IRQ2 (3<<22) /* IRQ2 to Cntr */ #define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interrupt MASK */ -#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interrupt Disable */ +#define TSI148_LCSR_VICR_EDGIS_DIS BIT(20) /* Edge interrupt Disable */ #define TSI148_LCSR_VICR_EDGIS_IRQ1 (2<<20) /* IRQ1 to Edge */ #define TSI148_LCSR_VICR_EDGIS_IRQ2 (3<<20) /* IRQ2 to Edge */ #define TSI148_LCSR_VICR_IRQIF_M (3<<18) /* IRQ1* Function MASK */ -#define TSI148_LCSR_VICR_IRQIF_NORM (1<<18) /* Normal */ +#define TSI148_LCSR_VICR_IRQIF_NORM BIT(18) /* Normal */ #define TSI148_LCSR_VICR_IRQIF_PULSE (2<<18) /* Pulse Generator */ #define TSI148_LCSR_VICR_IRQIF_PROG (3<<18) /* Programmable Clock */ #define TSI148_LCSR_VICR_IRQIF_1U (4<<18) /* 1us Clock */ #define TSI148_LCSR_VICR_IRQ2F_M (3<<16) /* IRQ2* Function MASK */ -#define TSI148_LCSR_VICR_IRQ2F_NORM (1<<16) /* Normal */ +#define TSI148_LCSR_VICR_IRQ2F_NORM BIT(16) /* Normal */ #define TSI148_LCSR_VICR_IRQ2F_PULSE (2<<16) /* Pulse Generator */ #define TSI148_LCSR_VICR_IRQ2F_PROG (3<<16) /* Programmable Clock */ #define TSI148_LCSR_VICR_IRQ2F_1U (4<<16) /* 1us Clock */ -#define TSI148_LCSR_VICR_BIP (1<<15) /* Broadcast Interrupt Pulse */ +#define TSI148_LCSR_VICR_BIP BIT(15) /* Broadcast Interrupt Pulse */ -#define TSI148_LCSR_VICR_IRQC (1<<12) /* VMEbus IRQ Clear */ -#define TSI148_LCSR_VICR_IRQS (1<<11) /* VMEbus IRQ Status */ +#define TSI148_LCSR_VICR_IRQC BIT(12) /* VMEbus IRQ Clear */ +#define TSI148_LCSR_VICR_IRQS BIT(11) /* VMEbus IRQ Status */ #define TSI148_LCSR_VICR_IRQL_M (7<<8) /* VMEbus SW IRQ Level Mask */ -#define TSI148_LCSR_VICR_IRQL_1 (1<<8) /* VMEbus SW IRQ Level 1 */ +#define TSI148_LCSR_VICR_IRQL_1 BIT(8) /* VMEbus SW IRQ Level 1 */ #define TSI148_LCSR_VICR_IRQL_2 (2<<8) /* VMEbus SW IRQ Level 2 */ #define TSI148_LCSR_VICR_IRQL_3 (3<<8) /* VMEbus SW IRQ Level 3 */ #define TSI148_LCSR_VICR_IRQL_4 (4<<8) /* VMEbus SW IRQ Level 4 */ @@ -1014,29 +1014,29 @@ static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1, /* * Interrupt Enable Register CRG + $440 */ -#define TSI148_LCSR_INTEN_DMA1EN (1<<25) /* DMAC 1 */ -#define TSI148_LCSR_INTEN_DMA0EN (1<<24) /* DMAC 0 */ -#define TSI148_LCSR_INTEN_LM3EN (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTEN_LM2EN (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTEN_LM1EN (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTEN_LM0EN (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTEN_MB3EN (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTEN_MB2EN (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTEN_MB1EN (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTEN_MB0EN (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTEN_PERREN (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTEN_VERREN (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTEN_VIEEN (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTEN_IACKEN (1<<10) /* IACK */ -#define TSI148_LCSR_INTEN_SYSFLEN (1<<9) /* System Fail */ -#define TSI148_LCSR_INTEN_ACFLEN (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTEN_IRQ7EN (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTEN_IRQ6EN (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTEN_IRQ5EN (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTEN_IRQ4EN (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTEN_IRQ3EN (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTEN_IRQ2EN (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTEN_IRQ1EN (1<<1) /* IRQ1 */ +#define TSI148_LCSR_INTEN_DMA1EN BIT(25) /* DMAC 1 */ +#define TSI148_LCSR_INTEN_DMA0EN BIT(24) /* DMAC 0 */ +#define TSI148_LCSR_INTEN_LM3EN BIT(23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTEN_LM2EN BIT(22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTEN_LM1EN BIT(21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTEN_LM0EN BIT(20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTEN_MB3EN BIT(19) /* Mail Box 3 */ +#define TSI148_LCSR_INTEN_MB2EN BIT(18) /* Mail Box 2 */ +#define TSI148_LCSR_INTEN_MB1EN BIT(17) /* Mail Box 1 */ +#define TSI148_LCSR_INTEN_MB0EN BIT(16) /* Mail Box 0 */ +#define TSI148_LCSR_INTEN_PERREN BIT(13) /* PCI/X Error */ +#define TSI148_LCSR_INTEN_VERREN BIT(12) /* VMEbus Error */ +#define TSI148_LCSR_INTEN_VIEEN BIT(11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTEN_IACKEN BIT(10) /* IACK */ +#define TSI148_LCSR_INTEN_SYSFLEN BIT(9) /* System Fail */ +#define TSI148_LCSR_INTEN_ACFLEN BIT(8) /* AC Fail */ +#define TSI148_LCSR_INTEN_IRQ7EN BIT(7) /* IRQ7 */ +#define TSI148_LCSR_INTEN_IRQ6EN BIT(6) /* IRQ6 */ +#define TSI148_LCSR_INTEN_IRQ5EN BIT(5) /* IRQ5 */ +#define TSI148_LCSR_INTEN_IRQ4EN BIT(4) /* IRQ4 */ +#define TSI148_LCSR_INTEN_IRQ3EN BIT(3) /* IRQ3 */ +#define TSI148_LCSR_INTEN_IRQ2EN BIT(2) /* IRQ2 */ +#define TSI148_LCSR_INTEN_IRQ1EN BIT(1) /* IRQ1 */ static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN, TSI148_LCSR_INTEN_LM1EN, @@ -1054,29 +1054,29 @@ static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN, /* * Interrupt Enable Out Register CRG + $444 */ -#define TSI148_LCSR_INTEO_DMA1EO (1<<25) /* DMAC 1 */ -#define TSI148_LCSR_INTEO_DMA0EO (1<<24) /* DMAC 0 */ -#define TSI148_LCSR_INTEO_LM3EO (1<<23) /* Loc Monitor 3 */ -#define TSI148_LCSR_INTEO_LM2EO (1<<22) /* Loc Monitor 2 */ -#define TSI148_LCSR_INTEO_LM1EO (1<<21) /* Loc Monitor 1 */ -#define TSI148_LCSR_INTEO_LM0EO (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTEO_MB3EO (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTEO_MB2EO (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTEO_MB1EO (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTEO_MB0EO (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTEO_PERREO (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTEO_VERREO (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTEO_VIEEO (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTEO_IACKEO (1<<10) /* IACK */ -#define TSI148_LCSR_INTEO_SYSFLEO (1<<9) /* System Fail */ -#define TSI148_LCSR_INTEO_ACFLEO (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTEO_IRQ7EO (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTEO_IRQ6EO (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTEO_IRQ5EO (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTEO_IRQ4EO (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTEO_IRQ3EO (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTEO_IRQ2EO (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTEO_IRQ1EO (1<<1) /* IRQ1 */ +#define TSI148_LCSR_INTEO_DMA1EO BIT(25) /* DMAC 1 */ +#define TSI148_LCSR_INTEO_DMA0EO BIT(24) /* DMAC 0 */ +#define TSI148_LCSR_INTEO_LM3EO BIT(23) /* Loc Monitor 3 */ +#define TSI148_LCSR_INTEO_LM2EO BIT(22) /* Loc Monitor 2 */ +#define TSI148_LCSR_INTEO_LM1EO BIT(21) /* Loc Monitor 1 */ +#define TSI148_LCSR_INTEO_LM0EO BIT(20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTEO_MB3EO BIT(19) /* Mail Box 3 */ +#define TSI148_LCSR_INTEO_MB2EO BIT(18) /* Mail Box 2 */ +#define TSI148_LCSR_INTEO_MB1EO BIT(17) /* Mail Box 1 */ +#define TSI148_LCSR_INTEO_MB0EO BIT(16) /* Mail Box 0 */ +#define TSI148_LCSR_INTEO_PERREO BIT(13) /* PCI/X Error */ +#define TSI148_LCSR_INTEO_VERREO BIT(12) /* VMEbus Error */ +#define TSI148_LCSR_INTEO_VIEEO BIT(11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTEO_IACKEO BIT(10) /* IACK */ +#define TSI148_LCSR_INTEO_SYSFLEO BIT(9) /* System Fail */ +#define TSI148_LCSR_INTEO_ACFLEO BIT(8) /* AC Fail */ +#define TSI148_LCSR_INTEO_IRQ7EO BIT(7) /* IRQ7 */ +#define TSI148_LCSR_INTEO_IRQ6EO BIT(6) /* IRQ6 */ +#define TSI148_LCSR_INTEO_IRQ5EO BIT(5) /* IRQ5 */ +#define TSI148_LCSR_INTEO_IRQ4EO BIT(4) /* IRQ4 */ +#define TSI148_LCSR_INTEO_IRQ3EO BIT(3) /* IRQ3 */ +#define TSI148_LCSR_INTEO_IRQ2EO BIT(2) /* IRQ2 */ +#define TSI148_LCSR_INTEO_IRQ1EO BIT(1) /* IRQ1 */ static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO, TSI148_LCSR_INTEO_LM1EO, @@ -1094,29 +1094,29 @@ static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO, /* * Interrupt Status Register CRG + $448 */ -#define TSI148_LCSR_INTS_DMA1S (1<<25) /* DMA 1 */ -#define TSI148_LCSR_INTS_DMA0S (1<<24) /* DMA 0 */ -#define TSI148_LCSR_INTS_LM3S (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTS_LM2S (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTS_LM1S (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTS_LM0S (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTS_MB3S (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTS_MB2S (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTS_MB1S (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTS_MB0S (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTS_PERRS (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTS_VERRS (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTS_VIES (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTS_IACKS (1<<10) /* IACK */ -#define TSI148_LCSR_INTS_SYSFLS (1<<9) /* System Fail */ -#define TSI148_LCSR_INTS_ACFLS (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTS_IRQ7S (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTS_IRQ6S (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTS_IRQ5S (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTS_IRQ4S (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTS_IRQ3S (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTS_IRQ2S (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTS_IRQ1S (1<<1) /* IRQ1 */ +#define TSI148_LCSR_INTS_DMA1S BIT(25) /* DMA 1 */ +#define TSI148_LCSR_INTS_DMA0S BIT(24) /* DMA 0 */ +#define TSI148_LCSR_INTS_LM3S BIT(23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTS_LM2S BIT(22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTS_LM1S BIT(21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTS_LM0S BIT(20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTS_MB3S BIT(19) /* Mail Box 3 */ +#define TSI148_LCSR_INTS_MB2S BIT(18) /* Mail Box 2 */ +#define TSI148_LCSR_INTS_MB1S BIT(17) /* Mail Box 1 */ +#define TSI148_LCSR_INTS_MB0S BIT(16) /* Mail Box 0 */ +#define TSI148_LCSR_INTS_PERRS BIT(13) /* PCI/X Error */ +#define TSI148_LCSR_INTS_VERRS BIT(12) /* VMEbus Error */ +#define TSI148_LCSR_INTS_VIES BIT(11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTS_IACKS BIT(10) /* IACK */ +#define TSI148_LCSR_INTS_SYSFLS BIT(9) /* System Fail */ +#define TSI148_LCSR_INTS_ACFLS BIT(8) /* AC Fail */ +#define TSI148_LCSR_INTS_IRQ7S BIT(7) /* IRQ7 */ +#define TSI148_LCSR_INTS_IRQ6S BIT(6) /* IRQ6 */ +#define TSI148_LCSR_INTS_IRQ5S BIT(5) /* IRQ5 */ +#define TSI148_LCSR_INTS_IRQ4S BIT(4) /* IRQ4 */ +#define TSI148_LCSR_INTS_IRQ3S BIT(3) /* IRQ3 */ +#define TSI148_LCSR_INTS_IRQ2S BIT(2) /* IRQ2 */ +#define TSI148_LCSR_INTS_IRQ1S BIT(1) /* IRQ1 */ static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S, TSI148_LCSR_INTS_LM1S, @@ -1131,22 +1131,22 @@ static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S, /* * Interrupt Clear Register CRG + $44C */ -#define TSI148_LCSR_INTC_DMA1C (1<<25) /* DMA 1 */ -#define TSI148_LCSR_INTC_DMA0C (1<<24) /* DMA 0 */ -#define TSI148_LCSR_INTC_LM3C (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTC_LM2C (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTC_LM1C (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTC_LM0C (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTC_MB3C (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTC_MB2C (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTC_MB1C (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTC_MB0C (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTC_PERRC (1<<13) /* VMEbus Error */ -#define TSI148_LCSR_INTC_VERRC (1<<12) /* VMEbus Access Time-out */ -#define TSI148_LCSR_INTC_VIEC (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTC_IACKC (1<<10) /* IACK */ -#define TSI148_LCSR_INTC_SYSFLC (1<<9) /* System Fail */ -#define TSI148_LCSR_INTC_ACFLC (1<<8) /* AC Fail */ +#define TSI148_LCSR_INTC_DMA1C BIT(25) /* DMA 1 */ +#define TSI148_LCSR_INTC_DMA0C BIT(24) /* DMA 0 */ +#define TSI148_LCSR_INTC_LM3C BIT(23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTC_LM2C BIT(22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTC_LM1C BIT(21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTC_LM0C BIT(20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTC_MB3C BIT(19) /* Mail Box 3 */ +#define TSI148_LCSR_INTC_MB2C BIT(18) /* Mail Box 2 */ +#define TSI148_LCSR_INTC_MB1C BIT(17) /* Mail Box 1 */ +#define TSI148_LCSR_INTC_MB0C BIT(16) /* Mail Box 0 */ +#define TSI148_LCSR_INTC_PERRC BIT(13) /* VMEbus Error */ +#define TSI148_LCSR_INTC_VERRC BIT(12) /* VMEbus Access Time-out */ +#define TSI148_LCSR_INTC_VIEC BIT(11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTC_IACKC BIT(10) /* IACK */ +#define TSI148_LCSR_INTC_SYSFLC BIT(9) /* System Fail */ +#define TSI148_LCSR_INTC_ACFLC BIT(8) /* AC Fail */ static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C, TSI148_LCSR_INTC_LM1C, @@ -1192,15 +1192,15 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, /* * DMA Control (0-1) Registers CRG + $500 */ -#define TSI148_LCSR_DCTL_ABT (1<<27) /* Abort */ -#define TSI148_LCSR_DCTL_PAU (1<<26) /* Pause */ -#define TSI148_LCSR_DCTL_DGO (1<<25) /* DMA Go */ +#define TSI148_LCSR_DCTL_ABT BIT(27) /* Abort */ +#define TSI148_LCSR_DCTL_PAU BIT(26) /* Pause */ +#define TSI148_LCSR_DCTL_DGO BIT(25) /* DMA Go */ -#define TSI148_LCSR_DCTL_MOD (1<<23) /* Mode */ +#define TSI148_LCSR_DCTL_MOD BIT(23) /* Mode */ #define TSI148_LCSR_DCTL_VBKS_M (7<<12) /* VMEbus block Size MASK */ #define TSI148_LCSR_DCTL_VBKS_32 (0<<12) /* VMEbus block Size 32 */ -#define TSI148_LCSR_DCTL_VBKS_64 (1<<12) /* VMEbus block Size 64 */ +#define TSI148_LCSR_DCTL_VBKS_64 BIT(12) /* VMEbus block Size 64 */ #define TSI148_LCSR_DCTL_VBKS_128 (2<<12) /* VMEbus block Size 128 */ #define TSI148_LCSR_DCTL_VBKS_256 (3<<12) /* VMEbus block Size 256 */ #define TSI148_LCSR_DCTL_VBKS_512 (4<<12) /* VMEbus block Size 512 */ @@ -1210,7 +1210,7 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_LCSR_DCTL_VBOT_M (7<<8) /* VMEbus back-off MASK */ #define TSI148_LCSR_DCTL_VBOT_0 (0<<8) /* VMEbus back-off 0us */ -#define TSI148_LCSR_DCTL_VBOT_1 (1<<8) /* VMEbus back-off 1us */ +#define TSI148_LCSR_DCTL_VBOT_1 BIT(8) /* VMEbus back-off 1us */ #define TSI148_LCSR_DCTL_VBOT_2 (2<<8) /* VMEbus back-off 2us */ #define TSI148_LCSR_DCTL_VBOT_4 (3<<8) /* VMEbus back-off 4us */ #define TSI148_LCSR_DCTL_VBOT_8 (4<<8) /* VMEbus back-off 8us */ @@ -1220,7 +1220,7 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_LCSR_DCTL_PBKS_M (7<<4) /* PCI block size MASK */ #define TSI148_LCSR_DCTL_PBKS_32 (0<<4) /* PCI block size 32 bytes */ -#define TSI148_LCSR_DCTL_PBKS_64 (1<<4) /* PCI block size 64 bytes */ +#define TSI148_LCSR_DCTL_PBKS_64 BIT(4) /* PCI block size 64 bytes */ #define TSI148_LCSR_DCTL_PBKS_128 (2<<4) /* PCI block size 128 bytes */ #define TSI148_LCSR_DCTL_PBKS_256 (3<<4) /* PCI block size 256 bytes */ #define TSI148_LCSR_DCTL_PBKS_512 (4<<4) /* PCI block size 512 bytes */ @@ -1230,7 +1230,7 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_LCSR_DCTL_PBOT_M (7<<0) /* PCI back off MASK */ #define TSI148_LCSR_DCTL_PBOT_0 (0<<0) /* PCI back off 0us */ -#define TSI148_LCSR_DCTL_PBOT_1 (1<<0) /* PCI back off 1us */ +#define TSI148_LCSR_DCTL_PBOT_1 BIT(0) /* PCI back off 1us */ #define TSI148_LCSR_DCTL_PBOT_2 (2<<0) /* PCI back off 2us */ #define TSI148_LCSR_DCTL_PBOT_4 (3<<0) /* PCI back off 3us */ #define TSI148_LCSR_DCTL_PBOT_8 (4<<0) /* PCI back off 4us */ @@ -1241,14 +1241,14 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, /* * DMA Status Registers (0-1) CRG + $504 */ -#define TSI148_LCSR_DSTA_SMA (1<<31) /* PCI Signalled Master Abt */ -#define TSI148_LCSR_DSTA_RTA (1<<30) /* PCI Received Target Abt */ -#define TSI148_LCSR_DSTA_MRC (1<<29) /* PCI Max Retry Count */ -#define TSI148_LCSR_DSTA_VBE (1<<28) /* VMEbus error */ -#define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */ -#define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */ -#define TSI148_LCSR_DSTA_DON (1<<25) /* Done */ -#define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */ +#define TSI148_LCSR_DSTA_SMA BIT(31) /* PCI Signalled Master Abt */ +#define TSI148_LCSR_DSTA_RTA BIT(30) /* PCI Received Target Abt */ +#define TSI148_LCSR_DSTA_MRC BIT(29) /* PCI Max Retry Count */ +#define TSI148_LCSR_DSTA_VBE BIT(28) /* VMEbus error */ +#define TSI148_LCSR_DSTA_ABT BIT(27) /* Abort */ +#define TSI148_LCSR_DSTA_PAU BIT(26) /* Pause */ +#define TSI148_LCSR_DSTA_DON BIT(25) /* Done */ +#define TSI148_LCSR_DSTA_BSY BIT(24) /* Busy */ /* * DMA Current Link Address Lower (0-1) @@ -1260,20 +1260,20 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, */ #define TSI148_LCSR_DSAT_TYP_M (3<<28) /* Source Bus Type */ #define TSI148_LCSR_DSAT_TYP_PCI (0<<28) /* PCI Bus */ -#define TSI148_LCSR_DSAT_TYP_VME (1<<28) /* VMEbus */ +#define TSI148_LCSR_DSAT_TYP_VME BIT(28) /* VMEbus */ #define TSI148_LCSR_DSAT_TYP_PAT (2<<28) /* Data Pattern */ -#define TSI148_LCSR_DSAT_PSZ (1<<25) /* Pattern Size */ -#define TSI148_LCSR_DSAT_NIN (1<<24) /* No Increment */ +#define TSI148_LCSR_DSAT_PSZ BIT(25) /* Pattern Size */ +#define TSI148_LCSR_DSAT_NIN BIT(24) /* No Increment */ #define TSI148_LCSR_DSAT_2eSSTM_M (3<<11) /* 2eSST Trans Rate Mask */ #define TSI148_LCSR_DSAT_2eSSTM_160 (0<<11) /* 160 MB/s */ -#define TSI148_LCSR_DSAT_2eSSTM_267 (1<<11) /* 267 MB/s */ +#define TSI148_LCSR_DSAT_2eSSTM_267 BIT(11) /* 267 MB/s */ #define TSI148_LCSR_DSAT_2eSSTM_320 (2<<11) /* 320 MB/s */ #define TSI148_LCSR_DSAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ #define TSI148_LCSR_DSAT_TM_SCT (0<<8) /* SCT */ -#define TSI148_LCSR_DSAT_TM_BLT (1<<8) /* BLT */ +#define TSI148_LCSR_DSAT_TM_BLT BIT(8) /* BLT */ #define TSI148_LCSR_DSAT_TM_MBLT (2<<8) /* MBLT */ #define TSI148_LCSR_DSAT_TM_2eVME (3<<8) /* 2eVME */ #define TSI148_LCSR_DSAT_TM_2eSST (4<<8) /* 2eSST */ @@ -1281,14 +1281,14 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_LCSR_DSAT_DBW_M (3<<6) /* Max Data Width MASK */ #define TSI148_LCSR_DSAT_DBW_16 (0<<6) /* 16 Bits */ -#define TSI148_LCSR_DSAT_DBW_32 (1<<6) /* 32 Bits */ +#define TSI148_LCSR_DSAT_DBW_32 BIT(6) /* 32 Bits */ -#define TSI148_LCSR_DSAT_SUP (1<<5) /* Supervisory Mode */ -#define TSI148_LCSR_DSAT_PGM (1<<4) /* Program Mode */ +#define TSI148_LCSR_DSAT_SUP BIT(5) /* Supervisory Mode */ +#define TSI148_LCSR_DSAT_PGM BIT(4) /* Program Mode */ #define TSI148_LCSR_DSAT_AMODE_M (0xf<<0) /* Address Space Mask */ #define TSI148_LCSR_DSAT_AMODE_A16 (0<<0) /* A16 */ -#define TSI148_LCSR_DSAT_AMODE_A24 (1<<0) /* A24 */ +#define TSI148_LCSR_DSAT_AMODE_A24 BIT(0) /* A24 */ #define TSI148_LCSR_DSAT_AMODE_A32 (2<<0) /* A32 */ #define TSI148_LCSR_DSAT_AMODE_A64 (4<<0) /* A64 */ #define TSI148_LCSR_DSAT_AMODE_CRCSR (5<<0) /* CR/CSR */ @@ -1301,16 +1301,16 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, * DMA Destination Attribute Registers (0-1) */ #define TSI148_LCSR_DDAT_TYP_PCI (0<<28) /* Destination PCI Bus */ -#define TSI148_LCSR_DDAT_TYP_VME (1<<28) /* Destination VMEbus */ +#define TSI148_LCSR_DDAT_TYP_VME BIT(28) /* Destination VMEbus */ #define TSI148_LCSR_DDAT_2eSSTM_M (3<<11) /* 2eSST Transfer Rate Mask */ #define TSI148_LCSR_DDAT_2eSSTM_160 (0<<11) /* 160 MB/s */ -#define TSI148_LCSR_DDAT_2eSSTM_267 (1<<11) /* 267 MB/s */ +#define TSI148_LCSR_DDAT_2eSSTM_267 BIT(11) /* 267 MB/s */ #define TSI148_LCSR_DDAT_2eSSTM_320 (2<<11) /* 320 MB/s */ #define TSI148_LCSR_DDAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ #define TSI148_LCSR_DDAT_TM_SCT (0<<8) /* SCT */ -#define TSI148_LCSR_DDAT_TM_BLT (1<<8) /* BLT */ +#define TSI148_LCSR_DDAT_TM_BLT BIT(8) /* BLT */ #define TSI148_LCSR_DDAT_TM_MBLT (2<<8) /* MBLT */ #define TSI148_LCSR_DDAT_TM_2eVME (3<<8) /* 2eVME */ #define TSI148_LCSR_DDAT_TM_2eSST (4<<8) /* 2eSST */ @@ -1318,14 +1318,14 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_LCSR_DDAT_DBW_M (3<<6) /* Max Data Width MASK */ #define TSI148_LCSR_DDAT_DBW_16 (0<<6) /* 16 Bits */ -#define TSI148_LCSR_DDAT_DBW_32 (1<<6) /* 32 Bits */ +#define TSI148_LCSR_DDAT_DBW_32 BIT(6) /* 32 Bits */ -#define TSI148_LCSR_DDAT_SUP (1<<5) /* Supervisory/User Access */ -#define TSI148_LCSR_DDAT_PGM (1<<4) /* Program/Data Access */ +#define TSI148_LCSR_DDAT_SUP BIT(5) /* Supervisory/User Access */ +#define TSI148_LCSR_DDAT_PGM BIT(4) /* Program/Data Access */ #define TSI148_LCSR_DDAT_AMODE_M (0xf<<0) /* Address Space Mask */ #define TSI148_LCSR_DDAT_AMODE_A16 (0<<0) /* A16 */ -#define TSI148_LCSR_DDAT_AMODE_A24 (1<<0) /* A24 */ +#define TSI148_LCSR_DDAT_AMODE_A24 BIT(0) /* A24 */ #define TSI148_LCSR_DDAT_AMODE_A32 (2<<0) /* A32 */ #define TSI148_LCSR_DDAT_AMODE_A64 (4<<0) /* A64 */ #define TSI148_LCSR_DDAT_AMODE_CRCSR (5<<0) /* CRC/SR */ @@ -1338,7 +1338,7 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, * DMA Next Link Address Lower */ #define TSI148_LCSR_DNLAL_DNLAL_M (0x3FFFFFF<<6) /* Address Mask */ -#define TSI148_LCSR_DNLAL_LLA (1<<0) /* Last Link Address Indicator */ +#define TSI148_LCSR_DNLAL_LLA BIT(0) /* Last Link Address Indicator */ /* * DMA 2eSST Broadcast Select @@ -1352,22 +1352,22 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, /* * GCSR Control and Status Register CRG + $604 */ -#define TSI148_GCSR_GCTRL_LRST (1<<15) /* Local Reset */ -#define TSI148_GCSR_GCTRL_SFAILEN (1<<14) /* System Fail enable */ -#define TSI148_GCSR_GCTRL_BDFAILS (1<<13) /* Board Fail Status */ -#define TSI148_GCSR_GCTRL_SCON (1<<12) /* System Copntroller */ -#define TSI148_GCSR_GCTRL_MEN (1<<11) /* Module Enable (READY) */ +#define TSI148_GCSR_GCTRL_LRST BIT(15) /* Local Reset */ +#define TSI148_GCSR_GCTRL_SFAILEN BIT(14) /* System Fail enable */ +#define TSI148_GCSR_GCTRL_BDFAILS BIT(13) /* Board Fail Status */ +#define TSI148_GCSR_GCTRL_SCON BIT(12) /* System Copntroller */ +#define TSI148_GCSR_GCTRL_MEN BIT(11) /* Module Enable (READY) */ -#define TSI148_GCSR_GCTRL_LMI3S (1<<7) /* Loc Monitor 3 Int Status */ -#define TSI148_GCSR_GCTRL_LMI2S (1<<6) /* Loc Monitor 2 Int Status */ -#define TSI148_GCSR_GCTRL_LMI1S (1<<5) /* Loc Monitor 1 Int Status */ -#define TSI148_GCSR_GCTRL_LMI0S (1<<4) /* Loc Monitor 0 Int Status */ -#define TSI148_GCSR_GCTRL_MBI3S (1<<3) /* Mail box 3 Int Status */ -#define TSI148_GCSR_GCTRL_MBI2S (1<<2) /* Mail box 2 Int Status */ -#define TSI148_GCSR_GCTRL_MBI1S (1<<1) /* Mail box 1 Int Status */ -#define TSI148_GCSR_GCTRL_MBI0S (1<<0) /* Mail box 0 Int Status */ +#define TSI148_GCSR_GCTRL_LMI3S BIT(7) /* Loc Monitor 3 Int Status */ +#define TSI148_GCSR_GCTRL_LMI2S BIT(6) /* Loc Monitor 2 Int Status */ +#define TSI148_GCSR_GCTRL_LMI1S BIT(5) /* Loc Monitor 1 Int Status */ +#define TSI148_GCSR_GCTRL_LMI0S BIT(4) /* Loc Monitor 0 Int Status */ +#define TSI148_GCSR_GCTRL_MBI3S BIT(3) /* Mail box 3 Int Status */ +#define TSI148_GCSR_GCTRL_MBI2S BIT(2) /* Mail box 2 Int Status */ +#define TSI148_GCSR_GCTRL_MBI1S BIT(1) /* Mail box 1 Int Status */ +#define TSI148_GCSR_GCTRL_MBI0S BIT(0) /* Mail box 0 Int Status */ -#define TSI148_GCSR_GAP (1<<5) /* Geographic Addr Parity */ +#define TSI148_GCSR_GAP BIT(5) /* Geographic Addr Parity */ #define TSI148_GCSR_GA_M (0x1F<<0) /* Geographic Address Mask */ /* @@ -1377,20 +1377,20 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, /* * CR/CSR Bit Clear Register CRG + $FF4 */ -#define TSI148_CRCSR_CSRBCR_LRSTC (1<<7) /* Local Reset Clear */ -#define TSI148_CRCSR_CSRBCR_SFAILC (1<<6) /* System Fail Enable Clear */ -#define TSI148_CRCSR_CSRBCR_BDFAILS (1<<5) /* Board Fail Status */ -#define TSI148_CRCSR_CSRBCR_MENC (1<<4) /* Module Enable Clear */ -#define TSI148_CRCSR_CSRBCR_BERRSC (1<<3) /* Bus Error Status Clear */ +#define TSI148_CRCSR_CSRBCR_LRSTC BIT(7) /* Local Reset Clear */ +#define TSI148_CRCSR_CSRBCR_SFAILC BIT(6) /* System Fail Enable Clear */ +#define TSI148_CRCSR_CSRBCR_BDFAILS BIT(5) /* Board Fail Status */ +#define TSI148_CRCSR_CSRBCR_MENC BIT(4) /* Module Enable Clear */ +#define TSI148_CRCSR_CSRBCR_BERRSC BIT(3) /* Bus Error Status Clear */ /* * CR/CSR Bit Set Register CRG+$FF8 */ -#define TSI148_CRCSR_CSRBSR_LISTS (1<<7) /* Local Reset Clear */ -#define TSI148_CRCSR_CSRBSR_SFAILS (1<<6) /* System Fail Enable Clear */ -#define TSI148_CRCSR_CSRBSR_BDFAILS (1<<5) /* Board Fail Status */ -#define TSI148_CRCSR_CSRBSR_MENS (1<<4) /* Module Enable Clear */ -#define TSI148_CRCSR_CSRBSR_BERRS (1<<3) /* Bus Error Status Clear */ +#define TSI148_CRCSR_CSRBSR_LISTS BIT(7) /* Local Reset Clear */ +#define TSI148_CRCSR_CSRBSR_SFAILS BIT(6) /* System Fail Enable Clear */ +#define TSI148_CRCSR_CSRBSR_BDFAILS BIT(5) /* Board Fail Status */ +#define TSI148_CRCSR_CSRBSR_MENS BIT(4) /* Module Enable Clear */ +#define TSI148_CRCSR_CSRBSR_BERRS BIT(3) /* Bus Error Status Clear */ /* * CR/CSR Base Address Register CRG + FFC diff --git a/drivers/staging/vme_user/vme_user.c b/drivers/staging/vme_user/vme_user.c index 4e533c0bfe6d..b9367b575d00 100644 --- a/drivers/staging/vme_user/vme_user.c +++ b/drivers/staging/vme_user/vme_user.c @@ -614,7 +614,7 @@ static int vme_user_probe(struct vme_dev *vdev) } /* Create sysfs entries - on udev systems this creates the dev files */ - vme_user_sysfs_class = class_create(THIS_MODULE, driver_name); + vme_user_sysfs_class = class_create(driver_name); if (IS_ERR(vme_user_sysfs_class)) { dev_err(&vdev->dev, "Error creating vme_user class.\n"); err = PTR_ERR(vme_user_sysfs_class); diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index 6ce41983dcf4..0e135af8316b 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -2171,50 +2171,6 @@ bb_software_reset(struct vnt_private *priv) bb_write_embedded(priv, 0x9C, 0); } -/* - * Description: Baseband Power Save Mode ON - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * none - * - * Return Value: none - * - */ -void -bb_power_save_mode_on(struct vnt_private *priv) -{ - unsigned char by_org_data; - - bb_read_embedded(priv, 0x0D, &by_org_data); - by_org_data |= BIT(0); - bb_write_embedded(priv, 0x0D, by_org_data); -} - -/* - * Description: Baseband Power Save Mode OFF - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * none - * - * Return Value: none - * - */ -void -bb_power_save_mode_off(struct vnt_private *priv) -{ - unsigned char by_org_data; - - bb_read_embedded(priv, 0x0D, &by_org_data); - by_org_data &= ~(BIT(0)); - bb_write_embedded(priv, 0x0D, by_org_data); -} - /* * Description: Set Tx Antenna mode * diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h index 15b2802ed727..e4a02c240a1c 100644 --- a/drivers/staging/vt6655/baseband.h +++ b/drivers/staging/vt6655/baseband.h @@ -63,8 +63,6 @@ void bb_set_vga_gain_offset(struct vnt_private *priv, unsigned char by_data); /* VT3253 Baseband */ bool bb_vt3253_init(struct vnt_private *priv); void bb_software_reset(struct vnt_private *priv); -void bb_power_save_mode_on(struct vnt_private *priv); -void bb_power_save_mode_off(struct vnt_private *priv); void bb_set_tx_antenna_mode(struct vnt_private *priv, unsigned char by_antenna_mode); void bb_set_rx_antenna_mode(struct vnt_private *priv, diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c index 7827e579ef3d..b9dc0d13c00c 100644 --- a/drivers/staging/vt6656/card.c +++ b/drivers/staging/vt6656/card.c @@ -11,7 +11,6 @@ * vnt_add_basic_rate - Add to BasicRateSet * vnt_ofdm_min_rate - Check if any OFDM rate is in BasicRateSet * vnt_get_tsf_offset - Calculate TSFOffset - * vnt_get_current_tsf - Read Current NIC TSF counter * vnt_get_next_tbtt - Calculate Next Beacon TSF counter * vnt_reset_next_tbtt - Set NIC Beacon time * vnt_update_next_tbtt - Sync. NIC Beacon time @@ -230,26 +229,6 @@ int vnt_adjust_tsf(struct vnt_private *priv, u8 rx_rate, MESSAGE_REQUEST_TSF, 0, 8, data); } -/* - * Description: Read NIC TSF counter - * Get local TSF counter - * - * Parameters: - * In: - * priv - The adapter to be read - * Out: - * current_tsf - Current TSF counter - * - * Return Value: true if success; otherwise false - * - */ -bool vnt_get_current_tsf(struct vnt_private *priv, u64 *current_tsf) -{ - *current_tsf = priv->current_tsf; - - return true; -} - /* * Description: Clear NIC TSF counter * Clear local TSF counter diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h index be32c25c95de..eb01f7cc871f 100644 --- a/drivers/staging/vt6656/card.h +++ b/drivers/staging/vt6656/card.h @@ -30,7 +30,6 @@ void vnt_update_top_rates(struct vnt_private *priv); bool vnt_ofdm_min_rate(struct vnt_private *priv); int vnt_adjust_tsf(struct vnt_private *priv, u8 rx_rate, u64 time_stamp, u64 local_tsf); -bool vnt_get_current_tsf(struct vnt_private *priv, u64 *current_tsf); bool vnt_clear_current_tsf(struct vnt_private *priv); int vnt_reset_next_tbtt(struct vnt_private *priv, u16 beacon_interval); int vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf, diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index 02a2191d5c4d..11658865ca50 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -689,6 +689,7 @@ static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, for (i = 0; i < ns3plug; i++) { pstart = s3plug[i].addr; pend = s3plug[i].addr + s3plug[i].len; + j = -1; /* find the matching PDR (or filename) */ if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */ for (j = 0; j < pda->nrec; j++) { @@ -696,8 +697,6 @@ static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, le16_to_cpu(pda->rec[j]->code)) break; } - } else { - j = -1; } if (j >= pda->nrec && j != -1) { /* if no matching PDR, fail */ pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n", @@ -1008,12 +1007,11 @@ static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk, rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL); rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL); if (!rstmsg || !rwrmsg) { - kfree(rstmsg); - kfree(rwrmsg); netdev_err(wlandev->netdev, "%s: no memory for firmware download, aborting download\n", __func__); - return -ENOMEM; + result = -ENOMEM; + goto free_result; } /* Initialize the messages */ diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 834cce50f9b0..b516c2893420 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -364,8 +364,6 @@ struct iscsi_np *iscsit_add_np( init_completion(&np->np_restart_comp); INIT_LIST_HEAD(&np->np_list); - timer_setup(&np->np_login_timer, iscsi_handle_login_thread_timeout, 0); - ret = iscsi_target_setup_login_socket(np, sockaddr); if (ret != 0) { kfree(np); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 274bdd7845ca..90b870f234f0 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -811,59 +811,6 @@ void iscsi_post_login_handler( iscsit_dec_conn_usage_count(conn); } -void iscsi_handle_login_thread_timeout(struct timer_list *t) -{ - struct iscsi_np *np = from_timer(np, t, np_login_timer); - - spin_lock_bh(&np->np_thread_lock); - pr_err("iSCSI Login timeout on Network Portal %pISpc\n", - &np->np_sockaddr); - - if (np->np_login_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&np->np_thread_lock); - return; - } - - if (np->np_thread) - send_sig(SIGINT, np->np_thread, 1); - - np->np_login_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&np->np_thread_lock); -} - -static void iscsi_start_login_thread_timer(struct iscsi_np *np) -{ - /* - * This used the TA_LOGIN_TIMEOUT constant because at this - * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout - */ - spin_lock_bh(&np->np_thread_lock); - np->np_login_timer_flags &= ~ISCSI_TF_STOP; - np->np_login_timer_flags |= ISCSI_TF_RUNNING; - mod_timer(&np->np_login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ); - - pr_debug("Added timeout timer to iSCSI login request for" - " %u seconds.\n", TA_LOGIN_TIMEOUT); - spin_unlock_bh(&np->np_thread_lock); -} - -static void iscsi_stop_login_thread_timer(struct iscsi_np *np) -{ - spin_lock_bh(&np->np_thread_lock); - if (!(np->np_login_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&np->np_thread_lock); - return; - } - np->np_login_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&np->np_thread_lock); - - del_timer_sync(&np->np_login_timer); - - spin_lock_bh(&np->np_thread_lock); - np->np_login_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&np->np_thread_lock); -} - int iscsit_setup_np( struct iscsi_np *np, struct sockaddr_storage *sockaddr) @@ -1123,10 +1070,13 @@ static struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np) spin_lock_init(&conn->nopin_timer_lock); spin_lock_init(&conn->response_queue_lock); spin_lock_init(&conn->state_lock); + spin_lock_init(&conn->login_worker_lock); + spin_lock_init(&conn->login_timer_lock); timer_setup(&conn->nopin_response_timer, iscsit_handle_nopin_response_timeout, 0); timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0); + timer_setup(&conn->login_timer, iscsit_login_timeout, 0); if (iscsit_conn_set_transport(conn, np->np_transport) < 0) goto free_conn; @@ -1304,7 +1254,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) goto new_sess_out; } - iscsi_start_login_thread_timer(np); + iscsit_start_login_timer(conn, current); pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); conn->conn_state = TARG_CONN_STATE_XPT_UP; @@ -1417,8 +1367,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) if (ret < 0) goto new_sess_out; - iscsi_stop_login_thread_timer(np); - if (ret == 1) { tpg_np = conn->tpg_np; @@ -1434,7 +1382,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) new_sess_out: new_sess = true; old_sess_out: - iscsi_stop_login_thread_timer(np); + iscsit_stop_login_timer(conn); tpg_np = conn->tpg_np; iscsi_target_login_sess_out(conn, zero_tsih, new_sess); new_sess = false; @@ -1448,7 +1396,6 @@ old_sess_out: return 1; exit: - iscsi_stop_login_thread_timer(np); spin_lock_bh(&np->np_thread_lock); np->np_thread_state = ISCSI_NP_THREAD_EXIT; spin_unlock_bh(&np->np_thread_lock); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 24040c118e49..fa3fb5f4e6bc 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -535,25 +535,6 @@ static void iscsi_target_login_drop(struct iscsit_conn *conn, struct iscsi_login iscsi_target_login_sess_out(conn, zero_tsih, true); } -struct conn_timeout { - struct timer_list timer; - struct iscsit_conn *conn; -}; - -static void iscsi_target_login_timeout(struct timer_list *t) -{ - struct conn_timeout *timeout = from_timer(timeout, t, timer); - struct iscsit_conn *conn = timeout->conn; - - pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); - - if (conn->login_kworker) { - pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", - conn->login_kworker->comm, conn->login_kworker->pid); - send_sig(SIGINT, conn->login_kworker, 1); - } -} - static void iscsi_target_do_login_rx(struct work_struct *work) { struct iscsit_conn *conn = container_of(work, @@ -562,12 +543,15 @@ static void iscsi_target_do_login_rx(struct work_struct *work) struct iscsi_np *np = login->np; struct iscsi_portal_group *tpg = conn->tpg; struct iscsi_tpg_np *tpg_np = conn->tpg_np; - struct conn_timeout timeout; int rc, zero_tsih = login->zero_tsih; bool state; pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", conn, current->comm, current->pid); + + spin_lock(&conn->login_worker_lock); + set_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags); + spin_unlock(&conn->login_worker_lock); /* * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready() * before initial PDU processing in iscsi_target_start_negotiation() @@ -597,19 +581,16 @@ static void iscsi_target_do_login_rx(struct work_struct *work) goto err; } - conn->login_kworker = current; allow_signal(SIGINT); - - timeout.conn = conn; - timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0); - mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ); - pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid); + rc = iscsit_set_login_timer_kworker(conn, current); + if (rc < 0) { + /* The login timer has already expired */ + pr_debug("iscsi_target_do_login_rx, login failed\n"); + goto err; + } rc = conn->conn_transport->iscsit_get_login_rx(conn, login); - del_timer_sync(&timeout.timer); - destroy_timer_on_stack(&timeout.timer); flush_signals(current); - conn->login_kworker = NULL; if (rc < 0) goto err; @@ -646,7 +627,17 @@ static void iscsi_target_do_login_rx(struct work_struct *work) if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_WRITE_ACTIVE)) goto err; + + /* + * Set the login timer thread pointer to NULL to prevent the + * login process from getting stuck if the initiator + * stops sending data. + */ + rc = iscsit_set_login_timer_kworker(conn, NULL); + if (rc < 0) + goto err; } else if (rc == 1) { + iscsit_stop_login_timer(conn); cancel_delayed_work(&conn->login_work); iscsi_target_nego_release(conn); iscsi_post_login_handler(np, conn, zero_tsih); @@ -656,6 +647,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) err: iscsi_target_restore_sock_callbacks(conn); + iscsit_stop_login_timer(conn); cancel_delayed_work(&conn->login_work); iscsi_target_login_drop(conn, login); iscsit_deaccess_np(np, tpg, tpg_np); @@ -1130,6 +1122,7 @@ int iscsi_target_locate_portal( iscsi_target_set_sock_callbacks(conn); login->np = np; + conn->tpg = NULL; login_req = (struct iscsi_login_req *) login->req; payload_length = ntoh24(login_req->dlength); @@ -1197,7 +1190,6 @@ int iscsi_target_locate_portal( */ sessiontype = strncmp(s_buf, DISCOVERY, 9); if (!sessiontype) { - conn->tpg = iscsit_global->discovery_tpg; if (!login->leading_connection) goto get_target; @@ -1214,9 +1206,11 @@ int iscsi_target_locate_portal( * Serialize access across the discovery struct iscsi_portal_group to * process login attempt. */ + conn->tpg = iscsit_global->discovery_tpg; if (iscsit_access_np(np, conn->tpg) < 0) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); + conn->tpg = NULL; ret = -1; goto out; } @@ -1368,14 +1362,30 @@ int iscsi_target_start_negotiation( * and perform connection cleanup now. */ ret = iscsi_target_do_login(conn, login); - if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) - ret = -1; + if (!ret) { + spin_lock(&conn->login_worker_lock); + + if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) + ret = -1; + else if (!test_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags)) { + if (iscsit_set_login_timer_kworker(conn, NULL) < 0) { + /* + * The timeout has expired already. + * Schedule login_work to perform the cleanup. + */ + schedule_delayed_work(&conn->login_work, 0); + } + } + + spin_unlock(&conn->login_worker_lock); + } if (ret < 0) { iscsi_target_restore_sock_callbacks(conn); iscsi_remove_failed_auth_entry(conn); } if (ret != 0) { + iscsit_stop_login_timer(conn); cancel_delayed_work_sync(&conn->login_work); iscsi_target_nego_release(conn); } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 26dc8ed3045b..b14835fcb033 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1040,6 +1040,57 @@ void iscsit_stop_nopin_timer(struct iscsit_conn *conn) spin_unlock_bh(&conn->nopin_timer_lock); } +void iscsit_login_timeout(struct timer_list *t) +{ + struct iscsit_conn *conn = from_timer(conn, t, login_timer); + struct iscsi_login *login = conn->login; + + pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); + + spin_lock_bh(&conn->login_timer_lock); + login->login_failed = 1; + + if (conn->login_kworker) { + pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", + conn->login_kworker->comm, conn->login_kworker->pid); + send_sig(SIGINT, conn->login_kworker, 1); + } else { + schedule_delayed_work(&conn->login_work, 0); + } + spin_unlock_bh(&conn->login_timer_lock); +} + +void iscsit_start_login_timer(struct iscsit_conn *conn, struct task_struct *kthr) +{ + pr_debug("Login timer started\n"); + + conn->login_kworker = kthr; + mod_timer(&conn->login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ); +} + +int iscsit_set_login_timer_kworker(struct iscsit_conn *conn, struct task_struct *kthr) +{ + struct iscsi_login *login = conn->login; + int ret = 0; + + spin_lock_bh(&conn->login_timer_lock); + if (login->login_failed) { + /* The timer has already expired */ + ret = -1; + } else { + conn->login_kworker = kthr; + } + spin_unlock_bh(&conn->login_timer_lock); + + return ret; +} + +void iscsit_stop_login_timer(struct iscsit_conn *conn) +{ + pr_debug("Login timer stopped\n"); + timer_delete_sync(&conn->login_timer); +} + int iscsit_send_tx_data( struct iscsit_cmd *cmd, struct iscsit_conn *conn, diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 33ea799a0850..24b8e577575a 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -56,6 +56,10 @@ extern void iscsit_handle_nopin_timeout(struct timer_list *t); extern void __iscsit_start_nopin_timer(struct iscsit_conn *); extern void iscsit_start_nopin_timer(struct iscsit_conn *); extern void iscsit_stop_nopin_timer(struct iscsit_conn *); +extern void iscsit_login_timeout(struct timer_list *t); +extern void iscsit_start_login_timer(struct iscsit_conn *, struct task_struct *kthr); +extern void iscsit_stop_login_timer(struct iscsit_conn *); +extern int iscsit_set_login_timer_kworker(struct iscsit_conn *, struct task_struct *kthr); extern int iscsit_send_tx_data(struct iscsit_cmd *, struct iscsit_conn *, int); extern int iscsit_fe_sendpage_sg(struct iscsit_cmd *, struct iscsit_conn *); extern int iscsit_tx_login_rsp(struct iscsit_conn *, u8, u8); diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index 49702cb08f4f..3861ae06d902 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -1004,8 +1004,10 @@ static u32 get_async_notif_value(optee_invoke_fn *invoke_fn, bool *value_valid, invoke_fn(OPTEE_SMC_GET_ASYNC_NOTIF_VALUE, 0, 0, 0, 0, 0, 0, 0, &res); - if (res.a0) + if (res.a0) { + *value_valid = false; return 0; + } *value_valid = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_VALID); *value_pending = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_PENDING); return res.a1; diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 452cbb8ad484..0eb342de0b00 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -1226,7 +1226,7 @@ static int __init tee_init(void) { int rc; - tee_class = class_create(THIS_MODULE, "tee"); + tee_class = class_create("tee"); if (IS_ERR(tee_class)) { pr_err("couldn't create class\n"); return PTR_ERR(tee_class); diff --git a/drivers/thermal/cpuidle_cooling.c b/drivers/thermal/cpuidle_cooling.c index 6f6daead485e..69f4c0a8dfcc 100644 --- a/drivers/thermal/cpuidle_cooling.c +++ b/drivers/thermal/cpuidle_cooling.c @@ -237,9 +237,6 @@ out: * * This function is in charge of creating a cooling device per cpuidle * driver and register it to the thermal framework. - * - * Return: zero on success, or negative value corresponding to the - * error detected in the underlying subsystems. */ void cpuidle_cooling_register(struct cpuidle_driver *drv) { diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index 3d3067804df2..1050fb4d94c2 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -21,19 +21,11 @@ * a. if the trend is THERMAL_TREND_RAISING, use higher cooling * state for this trip point * b. if the trend is THERMAL_TREND_DROPPING, do nothing - * c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit - * for this trip point - * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit - * for this trip point * If the temperature is lower than a trip point, * a. if the trend is THERMAL_TREND_RAISING, do nothing * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling * state for this trip point, if the cooling state already * equals lower limit, deactivate the thermal instance - * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing - * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, - * if the cooling state already equals lower limit, - * deactivate the thermal instance */ static unsigned long get_target_state(struct thermal_instance *instance, enum thermal_trend trend, bool throttle) @@ -61,24 +53,16 @@ static unsigned long get_target_state(struct thermal_instance *instance, return next_target; } - switch (trend) { - case THERMAL_TREND_RAISING: - if (throttle) { + if (throttle) { + if (trend == THERMAL_TREND_RAISING) next_target = clamp((cur_state + 1), instance->lower, instance->upper); - } - break; - case THERMAL_TREND_DROPPING: - if (cur_state <= instance->lower) { - if (!throttle) + } else { + if (trend == THERMAL_TREND_DROPPING) { + if (cur_state <= instance->lower) next_target = THERMAL_NO_TARGET; - } else { - if (!throttle) { + else next_target = clamp((cur_state - 1), instance->lower, instance->upper); - } } - break; - default: - break; } return next_target; diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index cb7e7697cf1e..ecd7e07eece0 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -103,15 +103,6 @@ config INTEL_TCC_COOLING on how fast the setting takes effect, and how much the CPU frequency is reduced. -config INTEL_MENLOW - tristate "Thermal Management driver for Intel menlow platform" - depends on ACPI_THERMAL - help - ACPI thermal management enhancement driver on - Intel Menlow platform. - - If unsure, say N. - config INTEL_HFI_THERMAL bool "Intel Hardware Feedback Interface" depends on NET diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile index 5d8833c82ab6..182b3411300a 100644 --- a/drivers/thermal/intel/Makefile +++ b/drivers/thermal/intel/Makefile @@ -13,5 +13,4 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o -obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_HFI_THERMAL) += intel_hfi.o diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 810231b59dcd..5e1164226ada 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -131,7 +131,7 @@ static ssize_t available_uuids_show(struct device *dev, for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { if (priv->uuid_bitmap & (1 << i)) - length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]); + length += sysfs_emit_at(buf, length, "%s\n", int3400_thermal_uuids[i]); } return length; @@ -149,7 +149,7 @@ static ssize_t current_uuid_show(struct device *dev, for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) { if (priv->os_uuid_mask & BIT(i)) - length += sysfs_emit_at(buf, length, int3400_thermal_uuids[i]); + length += sysfs_emit_at(buf, length, "%s\n", int3400_thermal_uuids[i]); } if (length) diff --git a/drivers/thermal/intel/intel_menlow.c b/drivers/thermal/intel/intel_menlow.c deleted file mode 100644 index 5a6ad0552311..000000000000 --- a/drivers/thermal/intel/intel_menlow.c +++ /dev/null @@ -1,521 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel menlow Driver for thermal management extension - * - * Copyright (C) 2008 Intel Corp - * Copyright (C) 2008 Sujith Thomas - * Copyright (C) 2008 Zhang Rui - * - * This driver creates the sys I/F for programming the sensors. - * It also implements the driver for intel menlow memory controller (hardware - * id is INT0002) which makes use of the platform specific ACPI methods - * to get/set bandwidth. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Thomas Sujith"); -MODULE_AUTHOR("Zhang Rui"); -MODULE_DESCRIPTION("Intel Menlow platform specific driver"); -MODULE_LICENSE("GPL v2"); - -/* - * Memory controller device control - */ - -#define MEMORY_GET_BANDWIDTH "GTHS" -#define MEMORY_SET_BANDWIDTH "STHS" -#define MEMORY_ARG_CUR_BANDWIDTH 1 -#define MEMORY_ARG_MAX_BANDWIDTH 0 - -static void intel_menlow_unregister_sensor(void); - -/* - * GTHS returning 'n' would mean that [0,n-1] states are supported - * In that case max_cstate would be n-1 - * GTHS returning '0' would mean that no bandwidth control states are supported - */ -static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev, - unsigned long *max_state) -{ - struct acpi_device *device = cdev->devdata; - acpi_handle handle = device->handle; - unsigned long long value; - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status = AE_OK; - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH; - status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, - &arg_list, &value); - if (ACPI_FAILURE(status)) - return -EFAULT; - - if (!value) - return -EINVAL; - - *max_state = value - 1; - return 0; -} - -static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, - unsigned long *value) -{ - struct acpi_device *device = cdev->devdata; - acpi_handle handle = device->handle; - unsigned long long result; - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status = AE_OK; - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH; - status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH, - &arg_list, &result); - if (ACPI_FAILURE(status)) - return -EFAULT; - - *value = result; - return 0; -} - -static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev, - unsigned long state) -{ - struct acpi_device *device = cdev->devdata; - acpi_handle handle = device->handle; - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; - unsigned long long temp; - unsigned long max_state; - - if (memory_get_max_bandwidth(cdev, &max_state)) - return -EFAULT; - - if (state > max_state) - return -EINVAL; - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = state; - - status = - acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list, - &temp); - - pr_info("Bandwidth value was %ld: status is %d\n", state, status); - if (ACPI_FAILURE(status)) - return -EFAULT; - - return 0; -} - -static const struct thermal_cooling_device_ops memory_cooling_ops = { - .get_max_state = memory_get_max_bandwidth, - .get_cur_state = memory_get_cur_bandwidth, - .set_cur_state = memory_set_cur_bandwidth, -}; - -/* - * Memory Device Management - */ -static int intel_menlow_memory_add(struct acpi_device *device) -{ - int result = -ENODEV; - struct thermal_cooling_device *cdev; - - if (!device) - return -EINVAL; - - if (!acpi_has_method(device->handle, MEMORY_GET_BANDWIDTH)) - goto end; - - if (!acpi_has_method(device->handle, MEMORY_SET_BANDWIDTH)) - goto end; - - cdev = thermal_cooling_device_register("Memory controller", device, - &memory_cooling_ops); - if (IS_ERR(cdev)) { - result = PTR_ERR(cdev); - goto end; - } - - device->driver_data = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, "thermal_cooling"); - if (result) - goto unregister; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, "device"); - if (result) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - goto unregister; - } - - end: - return result; - - unregister: - thermal_cooling_device_unregister(cdev); - return result; - -} - -static void intel_menlow_memory_remove(struct acpi_device *device) -{ - struct thermal_cooling_device *cdev; - - if (!device) - return; - - cdev = acpi_driver_data(device); - if (!cdev) - return; - - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - sysfs_remove_link(&cdev->device.kobj, "device"); - thermal_cooling_device_unregister(cdev); -} - -static const struct acpi_device_id intel_menlow_memory_ids[] = { - {"INT0002", 0}, - {"", 0}, -}; - -static struct acpi_driver intel_menlow_memory_driver = { - .name = "intel_menlow_thermal_control", - .ids = intel_menlow_memory_ids, - .ops = { - .add = intel_menlow_memory_add, - .remove = intel_menlow_memory_remove, - }, -}; - -/* - * Sensor control on menlow platform - */ - -#define THERMAL_AUX0 0 -#define THERMAL_AUX1 1 -#define GET_AUX0 "GAX0" -#define GET_AUX1 "GAX1" -#define SET_AUX0 "SAX0" -#define SET_AUX1 "SAX1" - -struct intel_menlow_attribute { - struct device_attribute attr; - struct device *device; - acpi_handle handle; - struct list_head node; -}; - -static LIST_HEAD(intel_menlow_attr_list); -static DEFINE_MUTEX(intel_menlow_attr_lock); - -/* - * sensor_get_auxtrip - get the current auxtrip value from sensor - * @handle: Object handle - * @index : GET_AUX1/GET_AUX0 - * @value : The address will be fill by the value - */ -static int sensor_get_auxtrip(acpi_handle handle, int index, - unsigned long long *value) -{ - acpi_status status; - - if ((index != 0 && index != 1) || !value) - return -EINVAL; - - status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0, - NULL, value); - if (ACPI_FAILURE(status)) - return -EIO; - - return 0; -} - -/* - * sensor_set_auxtrip - set the new auxtrip value to sensor - * @handle: Object handle - * @index : GET_AUX1/GET_AUX0 - * @value : The value will be set - */ -static int sensor_set_auxtrip(acpi_handle handle, int index, int value) -{ - acpi_status status; - union acpi_object arg = { - ACPI_TYPE_INTEGER - }; - struct acpi_object_list args = { - 1, &arg - }; - unsigned long long temp; - - if (index != 0 && index != 1) - return -EINVAL; - - status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1, - NULL, &temp); - if (ACPI_FAILURE(status)) - return -EIO; - if ((index && value < temp) || (!index && value > temp)) - return -EINVAL; - - arg.integer.value = value; - status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0, - &args, &temp); - if (ACPI_FAILURE(status)) - return -EIO; - - /* do we need to check the return value of SAX0/SAX1 ? */ - - return 0; -} - -#define to_intel_menlow_attr(_attr) \ - container_of(_attr, struct intel_menlow_attribute, attr) - -static ssize_t aux_show(struct device *dev, struct device_attribute *dev_attr, - char *buf, int idx) -{ - struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); - unsigned long long value; - int result; - - result = sensor_get_auxtrip(attr->handle, idx, &value); - if (result) - return result; - - return sprintf(buf, "%lu", deci_kelvin_to_celsius(value)); -} - -static ssize_t aux0_show(struct device *dev, - struct device_attribute *dev_attr, char *buf) -{ - return aux_show(dev, dev_attr, buf, 0); -} - -static ssize_t aux1_show(struct device *dev, - struct device_attribute *dev_attr, char *buf) -{ - return aux_show(dev, dev_attr, buf, 1); -} - -static ssize_t aux_store(struct device *dev, struct device_attribute *dev_attr, - const char *buf, size_t count, int idx) -{ - struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr); - int value; - int result; - - /*Sanity check; should be a positive integer */ - if (!sscanf(buf, "%d", &value)) - return -EINVAL; - - if (value < 0) - return -EINVAL; - - result = sensor_set_auxtrip(attr->handle, idx, - celsius_to_deci_kelvin(value)); - return result ? result : count; -} - -static ssize_t aux0_store(struct device *dev, - struct device_attribute *dev_attr, - const char *buf, size_t count) -{ - return aux_store(dev, dev_attr, buf, count, 0); -} - -static ssize_t aux1_store(struct device *dev, - struct device_attribute *dev_attr, - const char *buf, size_t count) -{ - return aux_store(dev, dev_attr, buf, count, 1); -} - -/* BIOS can enable/disable the thermal user application in dabney platform */ -#define BIOS_ENABLED "\\_TZ.GSTS" -static ssize_t bios_enabled_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - acpi_status status; - unsigned long long bios_enabled; - - status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled"); -} - -static int intel_menlow_add_one_attribute(char *name, umode_t mode, void *show, - void *store, struct device *dev, - acpi_handle handle) -{ - struct intel_menlow_attribute *attr; - int result; - - attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL); - if (!attr) - return -ENOMEM; - - sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */ - attr->attr.attr.name = name; - attr->attr.attr.mode = mode; - attr->attr.show = show; - attr->attr.store = store; - attr->device = dev; - attr->handle = handle; - - result = device_create_file(dev, &attr->attr); - if (result) { - kfree(attr); - return result; - } - - mutex_lock(&intel_menlow_attr_lock); - list_add_tail(&attr->node, &intel_menlow_attr_list); - mutex_unlock(&intel_menlow_attr_lock); - - return 0; -} - -static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, - void *context, void **rv) -{ - acpi_status status; - acpi_handle dummy; - struct thermal_zone_device *thermal; - int result; - - result = acpi_bus_get_private_data(handle, (void **)&thermal); - if (result) - return 0; - - /* _TZ must have the AUX0/1 methods */ - status = acpi_get_handle(handle, GET_AUX0, &dummy); - if (ACPI_FAILURE(status)) - return (status == AE_NOT_FOUND) ? AE_OK : status; - - status = acpi_get_handle(handle, SET_AUX0, &dummy); - if (ACPI_FAILURE(status)) - return (status == AE_NOT_FOUND) ? AE_OK : status; - - result = intel_menlow_add_one_attribute("aux0", 0644, - aux0_show, aux0_store, - &thermal->device, handle); - if (result) - return AE_ERROR; - - status = acpi_get_handle(handle, GET_AUX1, &dummy); - if (ACPI_FAILURE(status)) - goto aux1_not_found; - - status = acpi_get_handle(handle, SET_AUX1, &dummy); - if (ACPI_FAILURE(status)) - goto aux1_not_found; - - result = intel_menlow_add_one_attribute("aux1", 0644, - aux1_show, aux1_store, - &thermal->device, handle); - if (result) { - intel_menlow_unregister_sensor(); - return AE_ERROR; - } - - /* - * create the "dabney_enabled" attribute which means the user app - * should be loaded or not - */ - - result = intel_menlow_add_one_attribute("bios_enabled", 0444, - bios_enabled_show, NULL, - &thermal->device, handle); - if (result) { - intel_menlow_unregister_sensor(); - return AE_ERROR; - } - - return AE_OK; - - aux1_not_found: - if (status == AE_NOT_FOUND) - return AE_OK; - - intel_menlow_unregister_sensor(); - return status; -} - -static void intel_menlow_unregister_sensor(void) -{ - struct intel_menlow_attribute *pos, *next; - - mutex_lock(&intel_menlow_attr_lock); - list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) { - list_del(&pos->node); - device_remove_file(pos->device, &pos->attr); - kfree(pos); - } - mutex_unlock(&intel_menlow_attr_lock); - - return; -} - -static int __init intel_menlow_module_init(void) -{ - int result = -ENODEV; - acpi_status status; - unsigned long long enable; - - if (acpi_disabled) - return result; - - /* Looking for the \_TZ.GSTS method */ - status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable); - if (ACPI_FAILURE(status) || !enable) - return -ENODEV; - - /* Looking for ACPI device MEM0 with hardware id INT0002 */ - result = acpi_bus_register_driver(&intel_menlow_memory_driver); - if (result) - return result; - - /* Looking for sensors in each ACPI thermal zone */ - status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - intel_menlow_register_sensor, NULL, NULL, NULL); - if (ACPI_FAILURE(status)) { - acpi_bus_unregister_driver(&intel_menlow_memory_driver); - return -ENODEV; - } - - return 0; -} - -static void __exit intel_menlow_module_exit(void) -{ - acpi_bus_unregister_driver(&intel_menlow_memory_driver); - intel_menlow_unregister_sensor(); -} - -module_init(intel_menlow_module_init); -module_exit(intel_menlow_module_exit); diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c index dce50d239357..b3905e34c507 100644 --- a/drivers/thermal/intel/intel_pch_thermal.c +++ b/drivers/thermal/intel/intel_pch_thermal.c @@ -127,7 +127,8 @@ static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp) static void pch_critical(struct thermal_zone_device *tzd) { - dev_dbg(&tzd->device, "%s: critical temperature reached\n", tzd->type); + dev_dbg(thermal_zone_device(tzd), "%s: critical temperature reached\n", + thermal_zone_device_type(tzd)); } static struct thermal_zone_device_ops tzd_ops = { diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index 91fc7e239497..36243a3972fd 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -703,6 +703,10 @@ static int powerclamp_set_cur_state(struct thermal_cooling_device *cdev, new_target_ratio = clamp(new_target_ratio, 0UL, (unsigned long) (max_idle - 1)); + + if (powerclamp_data.target_ratio == new_target_ratio) + goto exit_set; + if (!powerclamp_data.target_ratio && new_target_ratio > 0) { pr_info("Start idle injection to reduce power\n"); powerclamp_data.target_ratio = new_target_ratio; diff --git a/drivers/thermal/mediatek/auxadc_thermal.c b/drivers/thermal/mediatek/auxadc_thermal.c index b6bb9eaafb74..0b5528804bbd 100644 --- a/drivers/thermal/mediatek/auxadc_thermal.c +++ b/drivers/thermal/mediatek/auxadc_thermal.c @@ -116,6 +116,10 @@ /* The calibration coefficient of sensor */ #define MT8173_CALIBRATION 165 +/* Valid temperatures range */ +#define MT8173_TEMP_MIN -20000 +#define MT8173_TEMP_MAX 150000 + /* * Layout of the fuses providing the calibration data * These macros could be used for MT8183, MT8173, MT2701, and MT2712. @@ -689,6 +693,11 @@ static const struct mtk_thermal_data mt7986_thermal_data = { .version = MTK_THERMAL_V3, }; +static bool mtk_thermal_temp_is_valid(int temp) +{ + return (temp >= MT8173_TEMP_MIN) && (temp <= MT8173_TEMP_MAX); +} + /** * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius * @mt: The thermal controller @@ -815,6 +824,17 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) temp = mt->raw_to_mcelsius( mt, conf->bank_data[bank->id].sensors[i], raw); + /* + * Depending on the filt/sen intervals and ADC polling time, + * we may need up to 60 milliseconds after initialization: this + * will result in the first reading containing an out of range + * temperature value. + * Validate the reading to both address the aforementioned issue + * and to eventually avoid bogus readings during runtime in the + * event that the AUXADC gets unstable due to high EMI, etc. + */ + if (!mtk_thermal_temp_is_valid(temp)) + temp = THERMAL_TEMP_INVALID; if (temp > max) max = temp; @@ -959,14 +979,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, static u64 of_get_phys_base(struct device_node *np) { - u64 size64; - const __be32 *regaddr_p; + struct resource res; - regaddr_p = of_get_address(np, 0, &size64, NULL); - if (!regaddr_p) + if (of_address_to_resource(np, 0, &res)) return OF_BAD_ADDR; - return of_translate_address(np, regaddr_p); + return res.start; } static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf) @@ -1186,14 +1204,6 @@ static int mtk_thermal_probe(struct platform_device *pdev) mt->conf = of_device_get_match_data(&pdev->dev); - mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); - if (IS_ERR(mt->clk_peri_therm)) - return PTR_ERR(mt->clk_peri_therm); - - mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc"); - if (IS_ERR(mt->clk_auxadc)) - return PTR_ERR(mt->clk_auxadc); - mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(mt->thermal_base)) return PTR_ERR(mt->thermal_base); @@ -1212,7 +1222,12 @@ static int mtk_thermal_probe(struct platform_device *pdev) return -ENODEV; } - auxadc_base = of_iomap(auxadc, 0); + auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL); + if (IS_ERR(auxadc_base)) { + of_node_put(auxadc); + return PTR_ERR(auxadc_base); + } + auxadc_phys_base = of_get_phys_base(auxadc); of_node_put(auxadc); @@ -1228,7 +1243,12 @@ static int mtk_thermal_probe(struct platform_device *pdev) return -ENODEV; } - apmixed_base = of_iomap(apmixedsys, 0); + apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL); + if (IS_ERR(apmixed_base)) { + of_node_put(apmixedsys); + return PTR_ERR(apmixed_base); + } + apmixed_phys_base = of_get_phys_base(apmixedsys); of_node_put(apmixedsys); @@ -1242,16 +1262,18 @@ static int mtk_thermal_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_prepare_enable(mt->clk_auxadc); - if (ret) { + mt->clk_auxadc = devm_clk_get_enabled(&pdev->dev, "auxadc"); + if (IS_ERR(mt->clk_auxadc)) { + ret = PTR_ERR(mt->clk_auxadc); dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); return ret; } - ret = clk_prepare_enable(mt->clk_peri_therm); - if (ret) { + mt->clk_peri_therm = devm_clk_get_enabled(&pdev->dev, "therm"); + if (IS_ERR(mt->clk_peri_therm)) { + ret = PTR_ERR(mt->clk_peri_therm); dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); - goto err_disable_clk_auxadc; + return ret; } mtk_thermal_turn_on_buffer(mt, apmixed_base); @@ -1273,43 +1295,20 @@ static int mtk_thermal_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mt); - /* Delay for thermal banks to be ready */ - msleep(30); - tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, &mtk_thermal_ops); - if (IS_ERR(tzdev)) { - ret = PTR_ERR(tzdev); - goto err_disable_clk_peri_therm; - } + if (IS_ERR(tzdev)) + return PTR_ERR(tzdev); ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev); if (ret) dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); return 0; - -err_disable_clk_peri_therm: - clk_disable_unprepare(mt->clk_peri_therm); -err_disable_clk_auxadc: - clk_disable_unprepare(mt->clk_auxadc); - - return ret; -} - -static int mtk_thermal_remove(struct platform_device *pdev) -{ - struct mtk_thermal *mt = platform_get_drvdata(pdev); - - clk_disable_unprepare(mt->clk_peri_therm); - clk_disable_unprepare(mt->clk_auxadc); - - return 0; } static struct platform_driver mtk_thermal_driver = { .probe = mtk_thermal_probe, - .remove = mtk_thermal_remove, .driver = { .name = "mtk-thermal", .of_match_table = mtk_thermal_of_match, diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index c5025aca22ee..842f678c1c3e 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1398,6 +1398,12 @@ int thermal_zone_device_id(struct thermal_zone_device *tzd) } EXPORT_SYMBOL_GPL(thermal_zone_device_id); +struct device *thermal_zone_device(struct thermal_zone_device *tzd) +{ + return &tzd->device; +} +EXPORT_SYMBOL_GPL(thermal_zone_device); + /** * thermal_zone_device_unregister - removes the registered thermal zone device * @tz: the thermal zone device to remove diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c index 628225deb8fe..3514bf65b7a4 100644 --- a/drivers/thunderbolt/acpi.c +++ b/drivers/thunderbolt/acpi.c @@ -341,7 +341,7 @@ static struct acpi_device *tb_acpi_find_companion(struct device *dev) */ if (tb_is_switch(dev)) return tb_acpi_switch_find_companion(tb_to_switch(dev)); - else if (tb_is_usb4_port_device(dev)) + if (tb_is_usb4_port_device(dev)) return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent), tb_to_usb4_port_device(dev)->port->port); return NULL; diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index 6e7d28e8d81a..3a213322ec7a 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -1033,7 +1033,7 @@ static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space, if (res->tb_error == TB_CFG_ERROR_LOCK) return -EACCES; - else if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED) + if (res->tb_error == TB_CFG_ERROR_PORT_NOT_CONNECTED) return -ENOTCONN; return -EIO; diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index c90d22f56d4e..0f6099c18a94 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -416,7 +416,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size) if (pos + 1 == drom_size || pos + entry->len > drom_size || !entry->len) { tb_sw_warn(sw, "DROM buffer overrun\n"); - return -EILSEQ; + return -EIO; } switch (entry->type) { @@ -471,14 +471,13 @@ err: static int tb_drom_copy_nvm(struct tb_switch *sw, u16 *size) { - u32 drom_offset; + u16 drom_offset; int ret; if (!sw->dma_port) return -ENODEV; - ret = tb_sw_read(sw, &drom_offset, TB_CFG_SWITCH, - sw->cap_plug_events + 12, 1); + ret = tb_eeprom_get_drom_offset(sw, &drom_offset); if (ret) return ret; @@ -513,7 +512,7 @@ err_free: return ret; } -static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size) +static int usb4_copy_drom(struct tb_switch *sw, u16 *size) { int ret; @@ -536,15 +535,40 @@ static int usb4_copy_host_drom(struct tb_switch *sw, u16 *size) return ret; } -static int tb_drom_read_n(struct tb_switch *sw, u16 offset, u8 *val, - size_t count) +static int tb_drom_bit_bang(struct tb_switch *sw, u16 *size) { - if (tb_switch_is_usb4(sw)) - return usb4_switch_drom_read(sw, offset, val, count); - return tb_eeprom_read_n(sw, offset, val, count); + int ret; + + ret = tb_eeprom_read_n(sw, 14, (u8 *)size, 2); + if (ret) + return ret; + + *size &= 0x3ff; + *size += TB_DROM_DATA_START; + + tb_sw_dbg(sw, "reading DROM (length: %#x)\n", *size); + if (*size < sizeof(struct tb_drom_header)) { + tb_sw_warn(sw, "DROM too small, aborting\n"); + return -EIO; + } + + sw->drom = kzalloc(*size, GFP_KERNEL); + if (!sw->drom) + return -ENOMEM; + + ret = tb_eeprom_read_n(sw, 0, sw->drom, *size); + if (ret) + goto err; + + return 0; + +err: + kfree(sw->drom); + sw->drom = NULL; + return ret; } -static int tb_drom_parse(struct tb_switch *sw) +static int tb_drom_parse_v1(struct tb_switch *sw) { const struct tb_drom_header *header = (const struct tb_drom_header *)sw->drom; @@ -555,7 +579,7 @@ static int tb_drom_parse(struct tb_switch *sw) tb_sw_warn(sw, "DROM UID CRC8 mismatch (expected: %#x, got: %#x)\n", header->uid_crc8, crc); - return -EILSEQ; + return -EIO; } if (!sw->uid) sw->uid = header->uid; @@ -589,6 +613,85 @@ static int usb4_drom_parse(struct tb_switch *sw) return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE); } +static int tb_drom_parse(struct tb_switch *sw, u16 size) +{ + const struct tb_drom_header *header = (const void *)sw->drom; + int ret; + + if (header->data_len + TB_DROM_DATA_START != size) { + tb_sw_warn(sw, "DROM size mismatch\n"); + ret = -EIO; + goto err; + } + + tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision); + + switch (header->device_rom_revision) { + case 3: + ret = usb4_drom_parse(sw); + break; + default: + tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n", + header->device_rom_revision); + fallthrough; + case 1: + ret = tb_drom_parse_v1(sw); + break; + } + + if (ret) { + tb_sw_warn(sw, "parsing DROM failed\n"); + goto err; + } + + return 0; + +err: + kfree(sw->drom); + sw->drom = NULL; + + return ret; +} + +static int tb_drom_host_read(struct tb_switch *sw) +{ + u16 size; + + if (tb_switch_is_usb4(sw)) { + usb4_switch_read_uid(sw, &sw->uid); + if (!usb4_copy_drom(sw, &size)) + return tb_drom_parse(sw, size); + } else { + if (!tb_drom_copy_efi(sw, &size)) + return tb_drom_parse(sw, size); + + if (!tb_drom_copy_nvm(sw, &size)) + return tb_drom_parse(sw, size); + + tb_drom_read_uid_only(sw, &sw->uid); + } + + return 0; +} + +static int tb_drom_device_read(struct tb_switch *sw) +{ + u16 size; + int ret; + + if (tb_switch_is_usb4(sw)) { + usb4_switch_read_uid(sw, &sw->uid); + ret = usb4_copy_drom(sw, &size); + } else { + ret = tb_drom_bit_bang(sw, &size); + } + + if (ret) + return ret; + + return tb_drom_parse(sw, size); +} + /** * tb_drom_read() - Copy DROM to sw->drom and parse it * @sw: Router whose DROM to read and parse @@ -601,103 +704,10 @@ static int usb4_drom_parse(struct tb_switch *sw) */ int tb_drom_read(struct tb_switch *sw) { - u16 size; - struct tb_drom_header *header; - int res, retries = 1; - if (sw->drom) return 0; - if (tb_route(sw) == 0) { - /* - * Apple's NHI EFI driver supplies a DROM for the root switch - * in a device property. Use it if available. - */ - if (tb_drom_copy_efi(sw, &size) == 0) - goto parse; - - /* Non-Apple hardware has the DROM as part of NVM */ - if (tb_drom_copy_nvm(sw, &size) == 0) - goto parse; - - /* - * USB4 hosts may support reading DROM through router - * operations. - */ - if (tb_switch_is_usb4(sw)) { - usb4_switch_read_uid(sw, &sw->uid); - if (!usb4_copy_host_drom(sw, &size)) - goto parse; - } else { - /* - * The root switch contains only a dummy drom - * (header only, no entries). Hardcode the - * configuration here. - */ - tb_drom_read_uid_only(sw, &sw->uid); - } - - return 0; - } - - res = tb_drom_read_n(sw, 14, (u8 *) &size, 2); - if (res) - return res; - size &= 0x3ff; - size += TB_DROM_DATA_START; - tb_sw_dbg(sw, "reading drom (length: %#x)\n", size); - if (size < sizeof(*header)) { - tb_sw_warn(sw, "drom too small, aborting\n"); - return -EIO; - } - - sw->drom = kzalloc(size, GFP_KERNEL); - if (!sw->drom) - return -ENOMEM; -read: - res = tb_drom_read_n(sw, 0, sw->drom, size); - if (res) - goto err; - -parse: - header = (void *) sw->drom; - - if (header->data_len + TB_DROM_DATA_START != size) { - tb_sw_warn(sw, "drom size mismatch\n"); - if (retries--) { - msleep(100); - goto read; - } - goto err; - } - - tb_sw_dbg(sw, "DROM version: %d\n", header->device_rom_revision); - - switch (header->device_rom_revision) { - case 3: - res = usb4_drom_parse(sw); - break; - default: - tb_sw_warn(sw, "DROM device_rom_revision %#x unknown\n", - header->device_rom_revision); - fallthrough; - case 1: - res = tb_drom_parse(sw); - break; - } - - /* If the DROM parsing fails, wait a moment and retry once */ - if (res == -EILSEQ && retries--) { - tb_sw_warn(sw, "parsing DROM failed\n"); - msleep(100); - goto read; - } - - if (!res) - return 0; - -err: - kfree(sw->drom); - sw->drom = NULL; - return -EIO; + if (!tb_route(sw)) + return tb_drom_host_read(sw); + return tb_drom_device_read(sw); } diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index cfebec107f3f..c0aee5dc5237 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -54,6 +54,21 @@ static int ring_interrupt_index(const struct tb_ring *ring) return bit; } +static void nhi_mask_interrupt(struct tb_nhi *nhi, int mask, int ring) +{ + if (nhi->quirks & QUIRK_AUTO_CLEAR_INT) + return; + iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring); +} + +static void nhi_clear_interrupt(struct tb_nhi *nhi, int ring) +{ + if (nhi->quirks & QUIRK_AUTO_CLEAR_INT) + ioread32(nhi->iobase + REG_RING_NOTIFY_BASE + ring); + else + iowrite32(~0, nhi->iobase + REG_RING_INT_CLEAR + ring); +} + /* * ring_interrupt_active() - activate/deactivate interrupts for a single ring * @@ -61,8 +76,8 @@ static int ring_interrupt_index(const struct tb_ring *ring) */ static void ring_interrupt_active(struct tb_ring *ring, bool active) { - int reg = REG_RING_INTERRUPT_BASE + - ring_interrupt_index(ring) / 32 * 4; + int index = ring_interrupt_index(ring) / 32 * 4; + int reg = REG_RING_INTERRUPT_BASE + index; int interrupt_bit = ring_interrupt_index(ring) & 31; int mask = 1 << interrupt_bit; u32 old, new; @@ -123,7 +138,11 @@ static void ring_interrupt_active(struct tb_ring *ring, bool active) "interrupt for %s %d is already %s\n", RING_TYPE(ring), ring->hop, active ? "enabled" : "disabled"); - iowrite32(new, ring->nhi->iobase + reg); + + if (active) + iowrite32(new, ring->nhi->iobase + reg); + else + nhi_mask_interrupt(ring->nhi, mask, index); } /* @@ -136,11 +155,11 @@ static void nhi_disable_interrupts(struct tb_nhi *nhi) int i = 0; /* disable interrupts */ for (i = 0; i < RING_INTERRUPT_REG_COUNT(nhi); i++) - iowrite32(0, nhi->iobase + REG_RING_INTERRUPT_BASE + 4 * i); + nhi_mask_interrupt(nhi, ~0, 4 * i); /* clear interrupt status bits */ for (i = 0; i < RING_NOTIFY_REG_COUNT(nhi); i++) - ioread32(nhi->iobase + REG_RING_NOTIFY_BASE + 4 * i); + nhi_clear_interrupt(nhi, 4 * i); } /* ring helper methods */ @@ -526,7 +545,8 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring) ring->hop); ret = -EBUSY; goto err_unlock; - } else if (!ring->is_tx && nhi->rx_rings[ring->hop]) { + } + if (!ring->is_tx && nhi->rx_rings[ring->hop]) { dev_warn(&nhi->pdev->dev, "RX hop %d already allocated\n", ring->hop); ret = -EBUSY; diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h index faef165a919c..6ba295815477 100644 --- a/drivers/thunderbolt/nhi_regs.h +++ b/drivers/thunderbolt/nhi_regs.h @@ -93,6 +93,8 @@ struct ring_desc { #define REG_RING_INTERRUPT_BASE 0x38200 #define RING_INTERRUPT_REG_COUNT(nhi) ((31 + 2 * nhi->hop_count) / 32) +#define REG_RING_INTERRUPT_MASK_CLEAR_BASE 0x38208 + #define REG_INT_THROTTLING_RATE 0x38c00 /* Interrupt Vector Allocation */ diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index da373ac38285..51e86b5171c7 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -271,9 +271,9 @@ static int nvm_authenticate(struct tb_switch *sw, bool auth_only) } sw->nvm->authenticating = true; return usb4_switch_nvm_authenticate(sw); - } else if (auth_only) { - return -EOPNOTSUPP; } + if (auth_only) + return -EOPNOTSUPP; sw->nvm->authenticating = true; if (!tb_route(sw)) { diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index a0996cb2893c..485b6e430686 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -9,6 +9,7 @@ #include #include +#include #include "sb_regs.h" #include "tb.h" @@ -851,7 +852,7 @@ bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in) */ if (ret == -EOPNOTSUPP) return true; - else if (ret) + if (ret) return false; return !status; @@ -877,7 +878,7 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in) &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EBUSY : 0; @@ -900,7 +901,7 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in) &status); if (ret == -EOPNOTSUPP) return 0; - else if (ret) + if (ret) return ret; return status ? -EIO : 0; @@ -1302,6 +1303,20 @@ static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, return 0; } +static int usb4_port_sb_opcode_err_to_errno(u32 val) +{ + switch (val) { + case 0: + return 0; + case USB4_SB_OPCODE_ERR: + return -EAGAIN; + case USB4_SB_OPCODE_ONS: + return -EOPNOTSUPP; + default: + return -EIO; + } +} + static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, u8 index, enum usb4_sb_opcode opcode, int timeout_msec) { @@ -1324,21 +1339,8 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, if (ret) return ret; - switch (val) { - case 0: - return 0; - - case USB4_SB_OPCODE_ERR: - return -EAGAIN; - - case USB4_SB_OPCODE_ONS: - return -EOPNOTSUPP; - - default: - if (val != opcode) - return -EIO; - break; - } + if (val != opcode) + return usb4_port_sb_opcode_err_to_errno(val); } while (ktime_before(ktime_get(), timeout)); return -ETIMEDOUT; @@ -1813,12 +1815,13 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, if (ret) return ret; - switch (val) { + ret = usb4_port_sb_opcode_err_to_errno(val); + switch (ret) { case 0: *status = 0; return 0; - case USB4_SB_OPCODE_ERR: + case -EAGAIN: ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, sizeof(metadata)); if (ret) @@ -1827,11 +1830,8 @@ int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, *status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK; return 0; - case USB4_SB_OPCODE_ONS: - return -EOPNOTSUPP; - default: - return -EIO; + return ret; } } @@ -1995,7 +1995,7 @@ static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale) unsigned long uframes; uframes = bw * 512UL << scale; - return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000); + return DIV_ROUND_CLOSEST(uframes * 8000, MEGA); } static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale) @@ -2003,7 +2003,7 @@ static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale) unsigned long uframes; /* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */ - uframes = ((unsigned long)mbps * 1000 * 1000) / 8000; + uframes = ((unsigned long)mbps * MEGA) / 8000; return DIV_ROUND_UP(uframes, 512UL << scale); } diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index a48335c95d39..e2b54887d331 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -1178,9 +1178,8 @@ static int tb_xdomain_get_uuid(struct tb_xdomain *xd) if (xd->state_retries-- > 0) { dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); return -EAGAIN; - } else { - dev_dbg(&xd->dev, "failed to read remote UUID\n"); } + dev_dbg(&xd->dev, "failed to read remote UUID\n"); return ret; } @@ -1367,12 +1366,10 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd) dev_dbg(&xd->dev, "failed to request remote properties, retrying\n"); return -EAGAIN; - } else { - /* Give up now */ - dev_err(&xd->dev, - "failed read XDomain properties from %pUb\n", - xd->remote_uuid); } + /* Give up now */ + dev_err(&xd->dev, "failed read XDomain properties from %pUb\n", + xd->remote_uuid); return ret; } @@ -2179,13 +2176,12 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw, if (xd->remote_uuid && uuid_equal(xd->remote_uuid, lookup->uuid)) return xd; - } else if (lookup->link && - lookup->link == xd->link && - lookup->depth == xd->depth) { - return xd; - } else if (lookup->route && - lookup->route == xd->route) { - return xd; + } else { + if (lookup->link && lookup->link == xd->link && + lookup->depth == xd->depth) + return xd; + if (lookup->route && lookup->route == xd->route) + return xd; } } else if (tb_port_has_remote(port)) { xd = switch_find_xdomain(port->remote->sw, lookup); diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index d35fc068da74..341abaed4ce2 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -160,7 +160,7 @@ config LEGACY_TIOCSTI a dangerous legacy operation, and can be disabled on most systems. - Say 'Y here only if you have confirmed that your system's + Say Y here only if you have confirmed that your system's userspace depends on this functionality to continue operating normally. @@ -301,6 +301,15 @@ config GOLDFISH_TTY_EARLY_CONSOLE default y if GOLDFISH_TTY=y select SERIAL_EARLYCON +config IPWIRELESS + tristate "IPWireless 3G UMTS PCMCIA card support" + depends on PCMCIA && NETDEVICES + select PPP + help + This is a driver for 3G UMTS PCMCIA card from IPWireless company. In + some countries (for example Czech Republic, T-Mobile ISP) this card + is shipped for service called UMTS 4G. + config N_GSM tristate "GSM MUX line discipline support (EXPERIMENTAL)" depends on NET diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index d7515d61659e..c06ad0a0744b 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -347,7 +347,7 @@ static void check_modem_status(struct serial_state *info) #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif - port->tty->hw_stopped = 0; + port->tty->hw_stopped = false; info->IER |= UART_IER_THRI; amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); @@ -362,7 +362,7 @@ static void check_modem_status(struct serial_state *info) #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif - port->tty->hw_stopped = 1; + port->tty->hw_stopped = true; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ amiga_custom.intena = IF_TBE; @@ -1197,7 +1197,7 @@ static void rs_set_termios(struct tty_struct *tty, const struct ktermios *old_te /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; + tty->hw_stopped = false; rs_start(tty); } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index ef3116e87975..10855e66fda1 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -553,7 +553,7 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, if (tty->hw_stopped) { if (cts) { - tty->hw_stopped = 0; + tty->hw_stopped = false; if (!mxser_16550A_or_MUST(info)) __mxser_start_tx(info); @@ -563,7 +563,7 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, } else if (cts) return; - tty->hw_stopped = 1; + tty->hw_stopped = true; if (!mxser_16550A_or_MUST(info)) __mxser_stop_tx(info); } @@ -1361,7 +1361,7 @@ static void mxser_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; + tty->hw_stopped = false; mxser_start(tty); } diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7aa05ebed8e1..b411a26cc092 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,7 @@ struct gsm_msg { enum gsm_dlci_state { DLCI_CLOSED, + DLCI_WAITING_CONFIG, /* Waiting for DLCI configuration from user */ DLCI_CONFIGURE, /* Sending PN (for adaption > 1) */ DLCI_OPENING, /* Sending SABM not seen UA */ DLCI_OPEN, /* SABM/UA complete */ @@ -330,6 +332,7 @@ struct gsm_mux { unsigned int t3; /* Power wake-up timer in seconds. */ int n2; /* Retry count */ u8 k; /* Window size */ + bool wait_config; /* Wait for configuration by ioctl before DLCI open */ u32 keep_alive; /* Control channel keep-alive in 10ms */ /* Statistics (not currently exposed) */ @@ -451,6 +454,7 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk); static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, u8 ctrl); static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg); +static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr); static void gsmld_write_trigger(struct gsm_mux *gsm); static void gsmld_write_task(struct work_struct *work); @@ -2280,6 +2284,7 @@ static void gsm_dlci_begin_open(struct gsm_dlci *dlci) switch (dlci->state) { case DLCI_CLOSED: + case DLCI_WAITING_CONFIG: case DLCI_CLOSING: dlci->retries = gsm->n2; if (!need_pn) { @@ -2311,6 +2316,7 @@ static void gsm_dlci_set_opening(struct gsm_dlci *dlci) { switch (dlci->state) { case DLCI_CLOSED: + case DLCI_WAITING_CONFIG: case DLCI_CLOSING: dlci->state = DLCI_OPENING; break; @@ -2319,6 +2325,24 @@ static void gsm_dlci_set_opening(struct gsm_dlci *dlci) } } +/** + * gsm_dlci_set_wait_config - wait for channel configuration + * @dlci: DLCI to configure + * + * Wait for a DLCI configuration from the application. + */ +static void gsm_dlci_set_wait_config(struct gsm_dlci *dlci) +{ + switch (dlci->state) { + case DLCI_CLOSED: + case DLCI_CLOSING: + dlci->state = DLCI_WAITING_CONFIG; + break; + default: + break; + } +} + /** * gsm_dlci_begin_close - start channel open procedure * @dlci: DLCI to open @@ -2453,6 +2477,128 @@ static void gsm_kick_timer(struct timer_list *t) pr_info("%s TX queue stalled\n", __func__); } +/** + * gsm_dlci_copy_config_values - copy DLCI configuration + * @dlci: source DLCI + * @dc: configuration structure to fill + */ +static void gsm_dlci_copy_config_values(struct gsm_dlci *dlci, struct gsm_dlci_config *dc) +{ + memset(dc, 0, sizeof(*dc)); + dc->channel = (u32)dlci->addr; + dc->adaption = (u32)dlci->adaption; + dc->mtu = (u32)dlci->mtu; + dc->priority = (u32)dlci->prio; + if (dlci->ftype == UIH) + dc->i = 1; + else + dc->i = 2; + dc->k = (u32)dlci->k; +} + +/** + * gsm_dlci_config - configure DLCI from configuration + * @dlci: DLCI to configure + * @dc: DLCI configuration + * @open: open DLCI after configuration? + */ +static int gsm_dlci_config(struct gsm_dlci *dlci, struct gsm_dlci_config *dc, int open) +{ + struct gsm_mux *gsm; + bool need_restart = false; + bool need_open = false; + unsigned int i; + + /* + * Check that userspace doesn't put stuff in here to prevent breakages + * in the future. + */ + for (i = 0; i < ARRAY_SIZE(dc->reserved); i++) + if (dc->reserved[i]) + return -EINVAL; + + if (!dlci) + return -EINVAL; + gsm = dlci->gsm; + + /* Stuff we don't support yet - I frame transport */ + if (dc->adaption != 1 && dc->adaption != 2) + return -EOPNOTSUPP; + if (dc->mtu > MAX_MTU || dc->mtu < MIN_MTU || dc->mtu > gsm->mru) + return -EINVAL; + if (dc->priority >= 64) + return -EINVAL; + if (dc->i == 0 || dc->i > 2) /* UIH and UI only */ + return -EINVAL; + if (dc->k > 7) + return -EINVAL; + + /* + * See what is needed for reconfiguration + */ + /* Framing fields */ + if (dc->adaption != dlci->adaption) + need_restart = true; + if (dc->mtu != dlci->mtu) + need_restart = true; + if (dc->i != dlci->ftype) + need_restart = true; + /* Requires care */ + if (dc->priority != dlci->prio) + need_restart = true; + + if ((open && gsm->wait_config) || need_restart) + need_open = true; + if (dlci->state == DLCI_WAITING_CONFIG) { + need_restart = false; + need_open = true; + } + + /* + * Close down what is needed, restart and initiate the new + * configuration. + */ + if (need_restart) { + gsm_dlci_begin_close(dlci); + wait_event_interruptible(gsm->event, dlci->state == DLCI_CLOSED); + if (signal_pending(current)) + return -EINTR; + } + /* + * Setup the new configuration values + */ + dlci->adaption = (int)dc->adaption; + + if (dc->mtu) + dlci->mtu = (unsigned int)dc->mtu; + else + dlci->mtu = gsm->mtu; + + if (dc->priority) + dlci->prio = (u8)dc->priority; + else + dlci->prio = roundup(dlci->addr + 1, 8) - 1; + + if (dc->i == 1) + dlci->ftype = UIH; + else if (dc->i == 2) + dlci->ftype = UI; + + if (dc->k) + dlci->k = (u8)dc->k; + else + dlci->k = gsm->k; + + if (need_open) { + if (gsm->initiator) + gsm_dlci_begin_open(dlci); + else + gsm_dlci_set_opening(dlci); + } + + return 0; +} + /* * Allocate/Free DLCI channels */ @@ -3078,6 +3224,7 @@ static struct gsm_mux *gsm_alloc_mux(void) gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ gsm->mtu = 64; gsm->dead = true; /* Avoid early tty opens */ + gsm->wait_config = false; /* Disabled */ gsm->keep_alive = 0; /* Disabled */ /* Store the instance to the mux array or abort if no space is @@ -3130,8 +3277,8 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) int need_close = 0; int need_restart = 0; - /* Stuff we don't support yet - UI or I frame transport, windowing */ - if ((c->adaption != 1 && c->adaption != 2) || c->k) + /* Stuff we don't support yet - UI or I frame transport */ + if (c->adaption != 1 && c->adaption != 2) return -EOPNOTSUPP; /* Check the MRU/MTU range looks sane */ if (c->mru < MIN_MTU || c->mtu < MIN_MTU) @@ -3218,6 +3365,7 @@ static void gsm_copy_config_ext_values(struct gsm_mux *gsm, struct gsm_config_ext *ce) { memset(ce, 0, sizeof(*ce)); + ce->wait_config = gsm->wait_config ? 1 : 0; ce->keep_alive = gsm->keep_alive; } @@ -3233,7 +3381,12 @@ static int gsm_config_ext(struct gsm_mux *gsm, struct gsm_config_ext *ce) if (ce->reserved[i]) return -EINVAL; + /* + * Setup the new configuration values + */ + gsm->wait_config = ce->wait_config ? true : false; gsm->keep_alive = ce->keep_alive; + return 0; } @@ -3433,9 +3586,16 @@ static int gsmld_open(struct tty_struct *tty) tty->receive_room = 65536; /* Attach the initial passive connection */ - gsm->encoding = GSM_ADV_OPT; gsmld_attach_gsm(tty, gsm); + /* The mux will not be activated yet, we wait for correct + * configuration first. + */ + if (gsm->encoding == GSM_BASIC_OPT) + gsm->receive = gsm0_receive; + else + gsm->receive = gsm1_receive; + return 0; } @@ -3556,8 +3716,10 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd, { struct gsm_config c; struct gsm_config_ext ce; + struct gsm_dlci_config dc; struct gsm_mux *gsm = tty->disc_data; - unsigned int base; + unsigned int base, addr; + struct gsm_dlci *dlci; switch (cmd) { case GSMIOC_GETCONF: @@ -3581,6 +3743,35 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd, if (copy_from_user(&ce, (void __user *)arg, sizeof(ce))) return -EFAULT; return gsm_config_ext(gsm, &ce); + case GSMIOC_GETCONF_DLCI: + if (copy_from_user(&dc, (void __user *)arg, sizeof(dc))) + return -EFAULT; + if (dc.channel == 0 || dc.channel >= NUM_DLCI) + return -EINVAL; + addr = array_index_nospec(dc.channel, NUM_DLCI); + dlci = gsm->dlci[addr]; + if (!dlci) { + dlci = gsm_dlci_alloc(gsm, addr); + if (!dlci) + return -ENOMEM; + } + gsm_dlci_copy_config_values(dlci, &dc); + if (copy_to_user((void __user *)arg, &dc, sizeof(dc))) + return -EFAULT; + return 0; + case GSMIOC_SETCONF_DLCI: + if (copy_from_user(&dc, (void __user *)arg, sizeof(dc))) + return -EFAULT; + if (dc.channel == 0 || dc.channel >= NUM_DLCI) + return -EINVAL; + addr = array_index_nospec(dc.channel, NUM_DLCI); + dlci = gsm->dlci[addr]; + if (!dlci) { + dlci = gsm_dlci_alloc(gsm, addr); + if (!dlci) + return -ENOMEM; + } + return gsm_dlci_config(dlci, &dc, 0); default: return n_tty_ioctl_helper(tty, cmd, arg); } @@ -4008,7 +4199,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) { struct gsm_dlci *dlci = tty->driver_data; struct tty_port *port = &dlci->port; - struct gsm_mux *gsm = dlci->gsm; port->count++; tty_port_tty_set(port, tty); @@ -4018,10 +4208,15 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) a DM straight back. This is ok as that will have caused a hangup */ tty_port_set_initialized(port, true); /* Start sending off SABM messages */ - if (gsm->initiator) - gsm_dlci_begin_open(dlci); - else - gsm_dlci_set_opening(dlci); + if (!dlci->gsm->wait_config) { + /* Start sending off SABM messages */ + if (dlci->gsm->initiator) + gsm_dlci_begin_open(dlci); + else + gsm_dlci_set_opening(dlci); + } else { + gsm_dlci_set_wait_config(dlci); + } /* And wait for virtual carrier */ return tty_port_block_til_ready(port, tty, filp); } @@ -4142,6 +4337,7 @@ static int gsmtty_ioctl(struct tty_struct *tty, { struct gsm_dlci *dlci = tty->driver_data; struct gsm_netconfig nc; + struct gsm_dlci_config dc; int index; if (dlci->state == DLCI_CLOSED) @@ -4165,6 +4361,23 @@ static int gsmtty_ioctl(struct tty_struct *tty, gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); return 0; + case GSMIOC_GETCONF_DLCI: + if (copy_from_user(&dc, (void __user *)arg, sizeof(dc))) + return -EFAULT; + if (dc.channel != dlci->addr) + return -EPERM; + gsm_dlci_copy_config_values(dlci, &dc); + if (copy_to_user((void __user *)arg, &dc, sizeof(dc))) + return -EFAULT; + return 0; + case GSMIOC_SETCONF_DLCI: + if (copy_from_user(&dc, (void __user *)arg, sizeof(dc))) + return -EFAULT; + if (dc.channel >= NUM_DLCI) + return -EINVAL; + if (dc.channel != 0 && dc.channel != dlci->addr) + return -EPERM; + return gsm_dlci_config(dlci, &dc, 1); case TIOCMIWAIT: return gsm_wait_modem_change(dlci, (u32)arg); default: diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index c8f56c9b1a1c..1c9e5d2ea7de 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -28,27 +28,26 @@ * EAGAIN */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include +#include +#include +#include #include -#include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include + #include "tty.h" /* @@ -625,7 +624,7 @@ static size_t __process_echoes(struct tty_struct *tty) c = echo_buf(ldata, tail); if (c == ECHO_OP_START) { unsigned char op; - int no_space_left = 0; + bool space_left = true; /* * Since add_echo_byte() is called without holding @@ -664,7 +663,7 @@ static size_t __process_echoes(struct tty_struct *tty) num_bs = 8 - (num_chars & 7); if (num_bs > space) { - no_space_left = 1; + space_left = false; break; } space -= num_bs; @@ -690,7 +689,7 @@ static size_t __process_echoes(struct tty_struct *tty) case ECHO_OP_START: /* This is an escaped echo op start code */ if (!space) { - no_space_left = 1; + space_left = false; break; } tty_put_char(tty, ECHO_OP_START); @@ -710,7 +709,7 @@ static size_t __process_echoes(struct tty_struct *tty) * */ if (space < 2) { - no_space_left = 1; + space_left = false; break; } tty_put_char(tty, '^'); @@ -720,7 +719,7 @@ static size_t __process_echoes(struct tty_struct *tty) tail += 2; } - if (no_space_left) + if (!space_left) break; } else { if (O_OPOST(tty)) { @@ -1177,7 +1176,7 @@ static void n_tty_receive_overrun(struct tty_struct *tty) ldata->num_overrun++; if (time_after(jiffies, ldata->overrun_time + HZ) || - time_after(ldata->overrun_time, jiffies)) { + time_after(ldata->overrun_time, jiffies)) { tty_warn(tty, "%d input overrun(s)\n", ldata->num_overrun); ldata->overrun_time = jiffies; ldata->num_overrun = 0; @@ -1691,7 +1690,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, room = N_TTY_BUF_SIZE - (ldata->read_head - tail); if (I_PARMRK(tty)) - room = (room + 2) / 3; + room = DIV_ROUND_UP(room, 3); room--; if (room <= 0) { overflow = ldata->icanon && ldata->canon_head == tail; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 07394fdaf522..2b1c8ab99dba 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -931,7 +931,7 @@ static void __init unix98_pty_init(void) if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + device_create(&tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); } #else diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 287153d32536..1e8fe44a7099 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -365,6 +365,13 @@ static inline void serial8250_do_prepare_rx_dma(struct uart_8250_port *p) if (dma->prepare_rx_dma) dma->prepare_rx_dma(p); } + +static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + return dma && dma->tx_running; +} #else static inline int serial8250_tx_dma(struct uart_8250_port *p) { @@ -380,6 +387,11 @@ static inline int serial8250_request_dma(struct uart_8250_port *p) return -1; } static inline void serial8250_release_dma(struct uart_8250_port *p) { } + +static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) +{ + return false; +} #endif static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index ed5a94747692..af0e1c070187 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -1012,16 +1012,18 @@ static int brcmuart_probe(struct platform_device *pdev) of_property_read_u32(np, "clock-frequency", &clk_rate); /* See if a Baud clock has been specified */ - baud_mux_clk = of_clk_get_by_name(np, "sw_baud"); + baud_mux_clk = devm_clk_get(dev, "sw_baud"); if (IS_ERR(baud_mux_clk)) { - if (PTR_ERR(baud_mux_clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(baud_mux_clk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto release_dma; + } dev_dbg(dev, "BAUD MUX clock not specified\n"); } else { dev_dbg(dev, "BAUD MUX clock found\n"); ret = clk_prepare_enable(baud_mux_clk); if (ret) - return ret; + goto release_dma; priv->baud_mux_clk = baud_mux_clk; init_real_clk_rates(dev, priv); clk_rate = priv->default_mux_rate; @@ -1029,7 +1031,8 @@ static int brcmuart_probe(struct platform_device *pdev) if (clk_rate == 0) { dev_err(dev, "clock-frequency or clk not defined\n"); - return -EINVAL; + ret = -EINVAL; + goto err_clk_disable; } dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not "); @@ -1116,7 +1119,11 @@ err1: serial8250_unregister_port(priv->line); err: brcmuart_free_bufs(dev, priv); - brcmuart_arbitration(priv, 0); +err_clk_disable: + clk_disable_unprepare(baud_mux_clk); +release_dma: + if (priv->dma_enabled) + brcmuart_arbitration(priv, 0); return ret; } @@ -1128,7 +1135,9 @@ static int brcmuart_remove(struct platform_device *pdev) hrtimer_cancel(&priv->hrt); serial8250_unregister_port(priv->line); brcmuart_free_bufs(&pdev->dev, priv); - brcmuart_arbitration(priv, 0); + clk_disable_unprepare(priv->baud_mux_clk); + if (priv->dma_enabled) + brcmuart_arbitration(priv, 0); return 0; } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index ab63c308be0a..13bf535eedcd 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1158,6 +1158,7 @@ void serial8250_unregister_port(int line) uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; uart->capabilities = 0; + serial8250_init_port(uart); serial8250_apply_quirks(uart); uart_add_one_port(&serial8250_reg, &uart->port); } else { diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index d94c3811a8f7..25a9ecf26be6 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -13,36 +13,49 @@ #include #include #include -#include #include "8250.h" #define UART_DLL_EM 9 #define UART_DLM_EM 10 +#define UART_HCR0_EM 11 + +/* + * A high value for UART_FCR_EM avoids overlapping with existing UART_* + * register defines. UART_FCR_EM_HW is the real HW register offset. + */ +#define UART_FCR_EM 0x10003 +#define UART_FCR_EM_HW 3 + +#define UART_HCR0_EM_SW_RESET BIT(7) /* SW Reset */ struct serial8250_em_priv { - struct clk *sclk; int line; }; -static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) +static void serial8250_em_serial_out_helper(struct uart_port *p, int offset, + int value) { switch (offset) { case UART_TX: /* TX @ 0x00 */ writeb(value, p->membase); break; - case UART_FCR: /* FCR @ 0x0c (+1) */ case UART_LCR: /* LCR @ 0x10 (+1) */ case UART_MCR: /* MCR @ 0x14 (+1) */ case UART_SCR: /* SCR @ 0x20 (+1) */ writel(value, p->membase + ((offset + 1) << 2)); break; + case UART_FCR_EM: + writel(value, p->membase + (UART_FCR_EM_HW << 2)); + break; case UART_IER: /* IER @ 0x04 */ value &= 0x0f; /* only 4 valid bits - not Xscale */ fallthrough; case UART_DLL_EM: /* DLL @ 0x24 (+9) */ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + case UART_HCR0_EM: /* HCR0 @ 0x2c */ writel(value, p->membase + (offset << 2)); + break; } } @@ -51,20 +64,81 @@ static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset) switch (offset) { case UART_RX: /* RX @ 0x00 */ return readb(p->membase); + case UART_LCR: /* LCR @ 0x10 (+1) */ case UART_MCR: /* MCR @ 0x14 (+1) */ case UART_LSR: /* LSR @ 0x18 (+1) */ case UART_MSR: /* MSR @ 0x1c (+1) */ case UART_SCR: /* SCR @ 0x20 (+1) */ return readl(p->membase + ((offset + 1) << 2)); + case UART_FCR_EM: + return readl(p->membase + (UART_FCR_EM_HW << 2)); case UART_IER: /* IER @ 0x04 */ case UART_IIR: /* IIR @ 0x08 */ case UART_DLL_EM: /* DLL @ 0x24 (+9) */ case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + case UART_HCR0_EM: /* HCR0 @ 0x2c */ return readl(p->membase + (offset << 2)); } return 0; } +static void serial8250_em_reg_update(struct uart_port *p, int off, int value) +{ + unsigned int ier, fcr, lcr, mcr, hcr0; + + ier = serial8250_em_serial_in(p, UART_IER); + fcr = serial8250_em_serial_in(p, UART_FCR_EM); + lcr = serial8250_em_serial_in(p, UART_LCR); + mcr = serial8250_em_serial_in(p, UART_MCR); + hcr0 = serial8250_em_serial_in(p, UART_HCR0_EM); + + serial8250_em_serial_out_helper(p, UART_FCR_EM, fcr | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0 | + UART_HCR0_EM_SW_RESET); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0 & + ~UART_HCR0_EM_SW_RESET); + + switch (off) { + case UART_FCR_EM: + fcr = value; + break; + case UART_LCR: + lcr = value; + break; + case UART_MCR: + mcr = value; + break; + } + + serial8250_em_serial_out_helper(p, UART_IER, ier); + serial8250_em_serial_out_helper(p, UART_FCR_EM, fcr); + serial8250_em_serial_out_helper(p, UART_MCR, mcr); + serial8250_em_serial_out_helper(p, UART_LCR, lcr); + serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0); +} + +static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) +{ + switch (offset) { + case UART_TX: + case UART_SCR: + case UART_IER: + case UART_DLL_EM: + case UART_DLM_EM: + serial8250_em_serial_out_helper(p, offset, value); + break; + case UART_FCR: + serial8250_em_reg_update(p, UART_FCR_EM, value); + break; + case UART_LCR: + case UART_MCR: + serial8250_em_reg_update(p, offset, value); + break; + } +} + static int serial8250_em_serial_dl_read(struct uart_8250_port *up) { return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8; @@ -79,8 +153,10 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) static int serial8250_em_probe(struct platform_device *pdev) { struct serial8250_em_priv *priv; + struct device *dev = &pdev->dev; struct uart_8250_port up; struct resource *regs; + struct clk *sclk; int irq, ret; irq = platform_get_irq(pdev, 0); @@ -88,31 +164,26 @@ static int serial8250_em_probe(struct platform_device *pdev) return irq; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) { - dev_err(&pdev->dev, "missing registers\n"); - return -EINVAL; - } + if (!regs) + return dev_err_probe(dev, -EINVAL, "missing registers\n"); - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->sclk = devm_clk_get(&pdev->dev, "sclk"); - if (IS_ERR(priv->sclk)) { - dev_err(&pdev->dev, "unable to get clock\n"); - return PTR_ERR(priv->sclk); - } + sclk = devm_clk_get_enabled(dev, "sclk"); + if (IS_ERR(sclk)) + return dev_err_probe(dev, PTR_ERR(sclk), "unable to get clock\n"); memset(&up, 0, sizeof(up)); up.port.mapbase = regs->start; up.port.irq = irq; up.port.type = PORT_16750; up.port.flags = UPF_FIXED_PORT | UPF_IOREMAP | UPF_FIXED_TYPE; - up.port.dev = &pdev->dev; + up.port.dev = dev; up.port.private_data = priv; - clk_prepare_enable(priv->sclk); - up.port.uartclk = clk_get_rate(priv->sclk); + up.port.uartclk = clk_get_rate(sclk); up.port.iotype = UPIO_MEM32; up.port.serial_in = serial8250_em_serial_in; @@ -121,11 +192,8 @@ static int serial8250_em_probe(struct platform_device *pdev) up.dl_write = serial8250_em_serial_dl_write; ret = serial8250_register_8250_port(&up); - if (ret < 0) { - dev_err(&pdev->dev, "unable to register 8250 port\n"); - clk_disable_unprepare(priv->sclk); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "unable to register 8250 port\n"); priv->line = ret; platform_set_drvdata(pdev, priv); @@ -137,7 +205,6 @@ static int serial8250_em_remove(struct platform_device *pdev) struct serial8250_em_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); - clk_disable_unprepare(priv->sclk); return 0; } diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 64770c62bbec..b406cba10b0e 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -40,9 +40,13 @@ #define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 + #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define PCI_SUBDEVICE_ID_USR_2980 0x0128 +#define PCI_SUBDEVICE_ID_USR_2981 0x0129 + #define PCI_DEVICE_ID_SEALEVEL_710xC 0x1001 #define PCI_DEVICE_ID_SEALEVEL_720xC 0x1002 #define PCI_DEVICE_ID_SEALEVEL_740xC 0x1004 @@ -829,6 +833,15 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { (kernel_ulong_t)&bd \ } +#define USR_DEVICE(devid, sdevid, bd) { \ + PCI_DEVICE_SUB( \ + PCI_VENDOR_ID_USR, \ + PCI_DEVICE_ID_EXAR_##devid, \ + PCI_VENDOR_ID_EXAR, \ + PCI_SUBDEVICE_ID_USR_##sdevid), 0, 0, \ + (kernel_ulong_t)&bd \ + } + static const struct pci_device_id exar_pci_tbl[] = { EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x), EXAR_DEVICE(ACCESSIO, COM_4S, pbn_exar_XR17C15x), @@ -853,6 +866,10 @@ static const struct pci_device_id exar_pci_tbl[] = { IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), + /* USRobotics USR298x-OEM PCI Modems */ + USR_DEVICE(XR17C152, 2980, pbn_exar_XR17C15x), + USR_DEVICE(XR17C152, 2981, pbn_exar_XR17C15x), + /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x), EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index c55be6fda0ca..e80c4f6551a1 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1920,6 +1920,8 @@ pci_moxa_setup(struct serial_private *priv, #define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530 #define PCI_VENDOR_ID_ADVANTECH 0x13fe #define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 +#define PCI_DEVICE_ID_ADVANTECH_PCI1600 0x1600 +#define PCI_DEVICE_ID_ADVANTECH_PCI1600_1611 0x1611 #define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 #define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618 #define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618 @@ -4085,6 +4087,9 @@ static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, pciserial_resume_one); static const struct pci_device_id serial_pci_tbl[] = { + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600, + PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3ba9c8b93ae6..c153ba3a018a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -668,6 +669,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_supported); /** * serial8250_em485_config() - generic ->rs485_config() callback * @port: uart port + * @termios: termios structure * @rs485: rs485 settings * * Generic callback usable by 8250 uart drivers to activate rs485 settings @@ -1932,6 +1934,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) int serial8250_handle_irq(struct uart_port *port, unsigned int iir) { struct uart_8250_port *up = up_to_u8250p(port); + struct tty_port *tport = &port->state->port; bool skip_rx = false; unsigned long flags; u16 status; @@ -1957,6 +1960,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) skip_rx = true; if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) { + if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) + pm_wakeup_event(tport->tty->dev, 0); if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } @@ -2016,18 +2021,19 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port) static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); + unsigned int result = 0; unsigned long flags; - u16 lsr; serial8250_rpm_get(up); spin_lock_irqsave(&port->lock, flags); - lsr = serial_lsr_in(up); + if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up))) + result = TIOCSER_TEMT; spin_unlock_irqrestore(&port->lock, flags); serial8250_rpm_put(up); - return uart_lsr_tx_empty(lsr) ? TIOCSER_TEMT : 0; + return result; } unsigned int serial8250_do_get_mctrl(struct uart_port *port) diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index 2509e7f74ccf..89956bbf34d9 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -113,13 +113,15 @@ static int tegra_uart_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&port8250); if (ret < 0) - goto err_clkdisable; + goto err_ctrl_assert; platform_set_drvdata(pdev, uart); uart->line = ret; return 0; +err_ctrl_assert: + reset_control_assert(uart->rst); err_clkdisable: clk_disable_unprepare(uart->clk); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0072892ca7fc..3e3fb377d90d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -248,13 +248,6 @@ config SERIAL_SAMSUNG Choose Y/M here only if you build for such SoC. -config SERIAL_SAMSUNG_UARTS_4 - bool - depends on SERIAL_SAMSUNG - default y - help - Internal node for the common case of 4 Samsung compatible UARTs - config SERIAL_SAMSUNG_UARTS int depends on SERIAL_SAMSUNG @@ -769,7 +762,7 @@ config SERIAL_PMACZILOG_CONSOLE config SERIAL_CPM tristate "CPM SCC/SMC serial port support" - depends on CPM2 || CPM1 || (PPC32 && COMPILE_TEST) + depends on CPM2 || CPM1 select SERIAL_CORE help This driver supports the SCC and SMC serial ports on Motorola @@ -958,7 +951,7 @@ config SERIAL_OMAP_CONSOLE config SERIAL_SIFIVE tristate "SiFive UART support" depends on OF - default SOC_SIFIVE || SOC_CANAAN + default ARCH_SIFIVE || ARCH_CANAAN select SERIAL_CORE help Select this option if you are building a kernel for a device that @@ -968,7 +961,7 @@ config SERIAL_SIFIVE config SERIAL_SIFIVE_CONSOLE bool "Console on SiFive UART" depends on SERIAL_SIFIVE=y - default SOC_SIFIVE || SOC_CANAAN + default ARCH_SIFIVE || ARCH_CANAAN select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 59e25f2b6632..4b2512eef577 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -606,10 +606,11 @@ static int arc_serial_probe(struct platform_device *pdev) } uart->baud = val; - port->membase = of_iomap(np, 0); - if (!port->membase) + port->membase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->membase)) { /* No point of dev_err since UART itself is hosed here */ - return -ENXIO; + return PTR_ERR(port->membase); + } port->irq = irq_of_parse_and_map(np, 0); diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 62bc7244dc67..55e82d0bf92d 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -596,6 +596,40 @@ static int bcm_uart_verify_port(struct uart_port *port, return 0; } +#ifdef CONFIG_CONSOLE_POLL +/* + * return true when outstanding tx equals fifo size + */ +static bool bcm_uart_tx_full(struct uart_port *port) +{ + unsigned int val; + + val = bcm_uart_readl(port, UART_MCTL_REG); + val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT; + return !(port->fifosize - val); +} + +static int bcm_uart_poll_get_char(struct uart_port *port) +{ + unsigned int iestat; + + iestat = bcm_uart_readl(port, UART_IR_REG); + if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) + return NO_POLL_CHAR; + + return bcm_uart_readl(port, UART_FIFO_REG); +} + +static void bcm_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + while (bcm_uart_tx_full(port)) { + cpu_relax(); + } + + bcm_uart_writel(port, c, UART_FIFO_REG); +} +#endif + /* serial core callbacks */ static const struct uart_ops bcm_uart_ops = { .tx_empty = bcm_uart_tx_empty, @@ -614,6 +648,10 @@ static const struct uart_ops bcm_uart_ops = { .request_port = bcm_uart_request_port, .config_port = bcm_uart_config_port, .verify_port = bcm_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = bcm_uart_poll_get_char, + .poll_put_char = bcm_uart_poll_put_char, +#endif }; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index 0577618e78c0..46c03ed71c31 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -19,8 +19,6 @@ struct gpio_desc; #include "cpm_uart_cpm2.h" #elif defined(CONFIG_CPM1) #include "cpm_uart_cpm1.h" -#elif defined(CONFIG_COMPILE_TEST) -#include "cpm_uart_cpm2.h" #endif #define SERIAL_CPM_MAJOR 204 diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 5565f302cb21..349e7da643f0 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -678,15 +678,14 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && - xmit->tail != xmit->head) { + while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && !uart_circ_empty(xmit)) { count = 0; p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; uart_xmit_advance(port, 1); count++; - if (xmit->head == xmit->tail) + if (uart_circ_empty(xmit)) break; } out_be16(&bdp->cbd_datlen, count); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 074bfed57fc9..7486a2b8556c 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1296,7 +1296,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) * 10ms at any baud rate. */ sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud / bits / 1000) * 2; - sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1)); + sport->rx_dma_rng_buf_len = (1 << fls(sport->rx_dma_rng_buf_len)); if (sport->rx_dma_rng_buf_len < 16) sport->rx_dma_rng_buf_len = 16; @@ -1406,12 +1406,12 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio struct lpuart_port, port); unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) - & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); lpuart32_write(&sport->port, modem, UARTMODIR); if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ - modem |= UARTMODEM_TXRTSE; + modem |= UARTMODIR_TXRTSE; /* * The hardware defaults to RTS logic HIGH while transfer. @@ -1420,9 +1420,9 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio * Note: UART is assumed to be active high. */ if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem |= UARTMODEM_TXRTSPOL; + modem |= UARTMODIR_TXRTSPOL; else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) - modem &= ~UARTMODEM_TXRTSPOL; + modem &= ~UARTMODIR_TXRTSPOL; } lpuart32_write(&sport->port, modem, UARTMODIR); @@ -1495,34 +1495,36 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state) static void lpuart32_break_ctl(struct uart_port *port, int break_state) { - unsigned long temp, modem; - struct tty_struct *tty; - unsigned int cflag = 0; + unsigned long temp; - tty = tty_port_tty_get(&port->state->port); - if (tty) { - cflag = tty->termios.c_cflag; - tty_kref_put(tty); - } - - temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK; - modem = lpuart32_read(port, UARTMODIR); + temp = lpuart32_read(port, UARTCTRL); + /* + * LPUART IP now has two known bugs, one is CTS has higher priority than the + * break signal, which causes the break signal sending through UARTCTRL_SBK + * may impacted by the CTS input if the HW flow control is enabled. It + * exists on all platforms we support in this driver. + * Another bug is i.MX8QM LPUART may have an additional break character + * being sent after SBK was cleared. + * To avoid above two bugs, we use Transmit Data Inversion function to send + * the break signal instead of UARTCTRL_SBK. + */ if (break_state != 0) { - temp |= UARTCTRL_SBK; /* - * LPUART CTS has higher priority than SBK, need to disable CTS before - * asserting SBK to avoid any interference if flow control is enabled. + * Disable the transmitter to prevent any data from being sent out + * during break, then invert the TX line to send break. */ - if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE) - lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + temp &= ~UARTCTRL_TE; + lpuart32_write(port, temp, UARTCTRL); + temp |= UARTCTRL_TXINV; + lpuart32_write(port, temp, UARTCTRL); } else { - /* Re-enable the CTS when break off. */ - if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE)) - lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR); + /* Disable the TXINV to turn off break and re-enable transmitter. */ + temp &= ~UARTCTRL_TXINV; + lpuart32_write(port, temp, UARTCTRL); + temp |= UARTCTRL_TE; + lpuart32_write(port, temp, UARTCTRL); } - - lpuart32_write(port, temp, UARTCTRL); } static void lpuart_setup_watermark(struct lpuart_port *sport) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 523f296d5747..c5e17569c3ad 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -289,20 +289,6 @@ static inline int imx_uart_is_imx1(struct imx_port *sport) return sport->devdata->devtype == IMX1_UART; } -static inline int imx_uart_is_imx21(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX21_UART; -} - -static inline int imx_uart_is_imx53(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX53_UART; -} - -static inline int imx_uart_is_imx6q(struct imx_port *sport) -{ - return sport->devdata->devtype == IMX6Q_UART; -} /* * Save and restore functions for UCR1, UCR2 and UCR3 registers */ @@ -1808,9 +1794,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, static const char *imx_uart_type(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; - - return sport->port.type == PORT_IMX ? "IMX" : NULL; + return port->type == PORT_IMX ? "IMX" : NULL; } /* @@ -1818,10 +1802,8 @@ static const char *imx_uart_type(struct uart_port *port) */ static void imx_uart_config_port(struct uart_port *port, int flags) { - struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE) - sport->port.type = PORT_IMX; + port->type = PORT_IMX; } /* @@ -1832,20 +1814,19 @@ static void imx_uart_config_port(struct uart_port *port, int flags) static int imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct imx_port *sport = (struct imx_port *)port; int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX) ret = -EINVAL; - if (sport->port.irq != ser->irq) + if (port->irq != ser->irq) ret = -EINVAL; if (ser->io_type != UPIO_MEM) ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) + if (port->uartclk / 16 != ser->baud_base) ret = -EINVAL; - if (sport->port.mapbase != (unsigned long)ser->iomem_base) + if (port->mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; - if (sport->port.iobase != ser->port) + if (port->iobase != ser->port) ret = -EINVAL; if (ser->hub6 != 0) ret = -EINVAL; @@ -2262,21 +2243,16 @@ static int imx_uart_probe(struct platform_device *pdev) } sport->port.line = ret; - if (of_get_property(np, "uart-has-rtscts", NULL) || - of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) - sport->have_rtscts = 1; + sport->have_rtscts = of_property_read_bool(np, "uart-has-rtscts") || + of_property_read_bool(np, "fsl,uart-has-rtscts"); /* deprecated */ - if (of_get_property(np, "fsl,dte-mode", NULL)) - sport->dte_mode = 1; + sport->dte_mode = of_property_read_bool(np, "fsl,dte-mode"); - if (of_get_property(np, "rts-gpios", NULL)) - sport->have_rtsgpio = 1; + sport->have_rtsgpio = of_property_present(np, "rts-gpios"); - if (of_get_property(np, "fsl,inverted-tx", NULL)) - sport->inverted_tx = 1; + sport->inverted_tx = of_property_read_bool(np, "fsl,inverted-tx"); - if (of_get_property(np, "fsl,inverted-rx", NULL)) - sport->inverted_rx = 1; + sport->inverted_rx = of_property_read_bool(np, "fsl,inverted-rx"); if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) { sport->rx_period_length = dma_buf_conf[0]; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e9cacfe7e032..9fee722058f4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -525,6 +525,11 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg) return false; } +static bool max310x_reg_noinc(struct device *dev, unsigned int reg) +{ + return reg == MAX310X_RHR_REG; +} + static int max310x_set_baud(struct uart_port *port, int baud) { unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0; @@ -651,14 +656,14 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int { struct max310x_one *one = to_max310x_port(port); - regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len); + regmap_noinc_write(one->regmap, MAX310X_THR_REG, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { struct max310x_one *one = to_max310x_port(port); - regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); + regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1468,6 +1473,10 @@ static struct regmap_config regcfg = { .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, + .writeable_noinc_reg = max310x_reg_noinc, + .readable_noinc_reg = max310x_reg_noinc, + .max_raw_read = MAX310X_FIFO_SIZE, + .max_raw_write = MAX310X_FIFO_SIZE, }; #ifdef CONFIG_SPI_MASTER @@ -1553,6 +1562,10 @@ static struct regmap_config regcfg_i2c = { .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, .max_register = MAX310X_I2C_REVID_EXTREG, + .writeable_noinc_reg = max310x_reg_noinc, + .readable_noinc_reg = max310x_reg_noinc, + .max_raw_read = MAX310X_FIFO_SIZE, + .max_raw_write = MAX310X_FIFO_SIZE, }; static const struct max310x_if_cfg max310x_i2c_if_cfg = { diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 74110017988a..2501db5a7aaf 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -779,7 +779,7 @@ static int meson_uart_remove(struct platform_device *pdev) return 0; } -static struct meson_uart_data s4_uart_data = { +static struct meson_uart_data meson_g12a_uart_data = { .has_xtal_div2 = true, }; @@ -788,9 +788,13 @@ static const struct of_device_id meson_uart_dt_match[] = { { .compatible = "amlogic,meson8-uart" }, { .compatible = "amlogic,meson8b-uart" }, { .compatible = "amlogic,meson-gx-uart" }, + { + .compatible = "amlogic,meson-g12a-uart", + .data = (void *)&meson_g12a_uart_data, + }, { .compatible = "amlogic,meson-s4-uart", - .data = (void *)&s4_uart_data, + .data = (void *)&meson_g12a_uart_data, }, { /* sentinel */ }, }; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index ef6e7bb6105c..a368f4293967 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1587,8 +1587,8 @@ static int mxs_auart_probe(struct platform_device *pdev) } s->port.line = ret; - if (of_get_property(np, "uart-has-rtscts", NULL) || - of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) + if (of_property_read_bool(np, "uart-has-rtscts") || + of_property_read_bool(np, "fsl,uart-has-rtscts") /* deprecated */) set_bit(MXS_AUART_RTSCTS, &s->flags); if (s->port.line >= ARRAY_SIZE(auart_port)) { diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 28fbc927a546..8582479f0211 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -854,21 +854,19 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) } static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport, - unsigned int chunk) + unsigned int remaining) { struct qcom_geni_serial_port *port = to_dev_port(uport); struct circ_buf *xmit = &uport->state->xmit; - unsigned int tx_bytes, c, remaining = chunk; + unsigned int tx_bytes; u8 buf[BYTES_PER_FIFO_WORD]; while (remaining) { memset(buf, 0, sizeof(buf)); tx_bytes = min(remaining, BYTES_PER_FIFO_WORD); - for (c = 0; c < tx_bytes ; c++) { - buf[c] = xmit->buf[xmit->tail]; - uart_xmit_advance(uport, 1); - } + memcpy(buf, &xmit->buf[xmit->tail], tx_bytes); + uart_xmit_advance(uport, tx_bytes); iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); @@ -1535,6 +1533,7 @@ static const struct uart_ops qcom_geni_console_pops = { #ifdef CONFIG_CONSOLE_POLL .poll_get_char = qcom_geni_serial_get_char, .poll_put_char = qcom_geni_serial_poll_put_char, + .poll_init = qcom_geni_serial_port_setup, #endif .pm = qcom_geni_serial_pm, }; @@ -1665,19 +1664,18 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) uport->private_data = &port->private_data; platform_set_drvdata(pdev, port); - ret = uart_add_one_port(drv, uport); - if (ret) - return ret; - irq_set_status_flags(uport->irq, IRQ_NOAUTOEN); ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH, port->name, uport); if (ret) { dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); - uart_remove_one_port(drv, uport); return ret; } + ret = uart_add_one_port(drv, uport); + if (ret) + return ret; + /* * Set pm_runtime status as ACTIVE so that wakeup_irq gets * enabled/disabled from dev_pm_arm_wake_irq during system diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index de56f383964e..b6de0dc51f29 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -41,7 +41,7 @@ #include -#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#if defined(CONFIG_SIBYTE_BCM1x80) #include #include diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2bd32c8ece39..54e82f476a2c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,6 @@ static struct lock_class_key port_lock_key; */ #define RS485_MAX_RTS_DELAY 100 /* msecs */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - const struct ktermios *old_termios); -static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state); @@ -137,7 +135,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (port && !uart_tx_stopped(port)) + if (port && !(port->flags & UPF_DEAD) && !uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -177,6 +175,51 @@ static void uart_port_dtr_rts(struct uart_port *uport, bool active) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); } +/* Caller holds port mutex */ +static void uart_change_line_settings(struct tty_struct *tty, struct uart_state *state, + const struct ktermios *old_termios) +{ + struct uart_port *uport = uart_port_check(state); + struct ktermios *termios; + bool old_hw_stopped; + + /* + * If we have no tty, termios, or the port does not exist, + * then we can't set the parameters for this port. + */ + if (!tty || uport->type == PORT_UNKNOWN) + return; + + termios = &tty->termios; + uport->ops->set_termios(uport, termios, old_termios); + + /* + * Set modem status enables based on termios cflag + */ + spin_lock_irq(&uport->lock); + if (termios->c_cflag & CRTSCTS) + uport->status |= UPSTAT_CTS_ENABLE; + else + uport->status &= ~UPSTAT_CTS_ENABLE; + + if (termios->c_cflag & CLOCAL) + uport->status &= ~UPSTAT_DCD_ENABLE; + else + uport->status |= UPSTAT_DCD_ENABLE; + + /* reset sw-assisted CTS flow control based on (possibly) new mode */ + old_hw_stopped = uport->hw_stopped; + uport->hw_stopped = uart_softcts_mode(uport) && + !(uport->ops->get_mctrl(uport) & TIOCM_CTS); + if (uport->hw_stopped != old_hw_stopped) { + if (!old_hw_stopped) + uport->ops->stop_tx(uport); + else + __uart_start(tty); + } + spin_unlock_irq(&uport->lock); +} + /* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port mutex. @@ -232,7 +275,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, /* * Initialise the hardware port settings. */ - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); /* * Setup the RTS and DTR signals once the @@ -485,52 +528,6 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) } EXPORT_SYMBOL(uart_get_divisor); -/* Caller holds port mutex */ -static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, - const struct ktermios *old_termios) -{ - struct uart_port *uport = uart_port_check(state); - struct ktermios *termios; - int hw_stopped; - - /* - * If we have no tty, termios, or the port does not exist, - * then we can't set the parameters for this port. - */ - if (!tty || uport->type == PORT_UNKNOWN) - return; - - termios = &tty->termios; - uport->ops->set_termios(uport, termios, old_termios); - - /* - * Set modem status enables based on termios cflag - */ - spin_lock_irq(&uport->lock); - if (termios->c_cflag & CRTSCTS) - uport->status |= UPSTAT_CTS_ENABLE; - else - uport->status &= ~UPSTAT_CTS_ENABLE; - - if (termios->c_cflag & CLOCAL) - uport->status &= ~UPSTAT_DCD_ENABLE; - else - uport->status |= UPSTAT_DCD_ENABLE; - - /* reset sw-assisted CTS flow control based on (possibly) new mode */ - hw_stopped = uport->hw_stopped; - uport->hw_stopped = uart_softcts_mode(uport) && - !(uport->ops->get_mctrl(uport) & TIOCM_CTS); - if (uport->hw_stopped) { - if (!hw_stopped) - uport->ops->stop_tx(uport); - } else { - if (hw_stopped) - __uart_start(tty); - } - spin_unlock_irq(&uport->lock); -} - static int uart_put_char(struct tty_struct *tty, unsigned char c) { struct uart_state *state = tty->driver_data; @@ -994,7 +991,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, current->comm, tty_name(port->tty)); } - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); } } else { retval = uart_startup(tty, state, true); @@ -1491,7 +1488,7 @@ static int uart_set_iso7816_config(struct uart_port *port, * There are 5 words reserved for future use. Check that userspace * doesn't put stuff in there to prevent breakages in the future. */ - for (i = 0; i < 5; i++) + for (i = 0; i < ARRAY_SIZE(iso7816.reserved); i++) if (iso7816.reserved[i]) return -EINVAL; @@ -1552,7 +1549,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) goto out; /* rs485_config requires more locking than others */ - if (cmd == TIOCGRS485) + if (cmd == TIOCSRS485) down_write(&tty->termios_rwsem); mutex_lock(&port->mutex); @@ -1595,7 +1592,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) } out_up: mutex_unlock(&port->mutex); - if (cmd == TIOCGRS485) + if (cmd == TIOCSRS485) up_write(&tty->termios_rwsem); out: return ret; @@ -1656,15 +1653,15 @@ static void uart_set_termios(struct tty_struct *tty, goto out; } - uart_change_speed(tty, state, old_termios); + uart_change_line_settings(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */ cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + if (((old_termios->c_cflag & CBAUD) != B0) && ((cflag & CBAUD) == B0)) uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ - else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + else if (((old_termios->c_cflag & CBAUD) == B0) && ((cflag & CBAUD) != B0)) { unsigned int mask = TIOCM_DTR; if (!(cflag & CRTSCTS) || !tty_throttled(tty)) @@ -2452,7 +2449,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) ret = ops->startup(uport); if (ret == 0) { if (tty) - uart_change_speed(tty, state, NULL); + uart_change_line_settings(tty, state, NULL); spin_lock_irq(&uport->lock); if (!(uport->rs485.flags & SER_RS485_ENABLED)) ops->set_mctrl(uport, uport->mctrl); @@ -2593,6 +2590,7 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) { struct uart_driver *drv = driver->driver_state; struct uart_state *state = drv->state + line; + enum uart_pm_state pm_state; struct tty_port *tport; struct uart_port *port; int baud = 9600; @@ -2610,6 +2608,9 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) goto out; } + pm_state = state->pm_state; + uart_change_pm(state, UART_PM_STATE_ON); + if (port->ops->poll_init) { /* * We don't set initialized as we only initialized the hw, @@ -2626,6 +2627,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options) console_list_unlock(); } out: + if (ret) + uart_change_pm(state, pm_state); mutex_unlock(&tport->mutex); return ret; } @@ -3305,13 +3308,13 @@ void uart_handle_cts_change(struct uart_port *uport, bool active) if (uart_softcts_mode(uport)) { if (uport->hw_stopped) { if (active) { - uport->hw_stopped = 0; + uport->hw_stopped = false; uport->ops->start_tx(uport); uart_write_wakeup(uport); } } else { if (!active) { - uport->hw_stopped = 1; + uport->hw_stopped = true; uport->ops->stop_tx(uport); } } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index caa09a0c48f4..7c9457962a3d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -588,14 +588,28 @@ static void sci_start_tx(struct uart_port *port) if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && dma_submit_error(s->cookie_tx)) { + if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) + /* Switch irq from SCIF to DMA */ + disable_irq(s->irqs[SCIx_TXI_IRQ]); + s->cookie_tx = 0; schedule_work(&s->work_tx); } #endif - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE || + port->type == PORT_SCIFA || port->type == PORT_SCIFB) { /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ ctrl = serial_port_in(port, SCSCR); + + /* + * For SCI, TE (transmit enable) must be set after setting TIE + * (transmit interrupt enable) or in the same instruction to start + * the transmit process. + */ + if (port->type == PORT_SCI) + ctrl |= SCSCR_TE; + serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); } } @@ -833,6 +847,11 @@ static void sci_transmit_chars(struct uart_port *port) } else if (!uart_circ_empty(xmit) && !stopped) { c = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) { + ctrl = serial_port_in(port, SCSCR); + ctrl &= ~SCSCR_TE; + serial_port_out(port, SCSCR, ctrl); + return; } else { break; } @@ -846,9 +865,16 @@ static void sci_transmit_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - sci_stop_tx(port); + if (uart_circ_empty(xmit)) { + if (port->type == PORT_SCI) { + ctrl = serial_port_in(port, SCSCR); + ctrl &= ~SCSCR_TIE; + ctrl |= SCSCR_TEIE; + serial_port_out(port, SCSCR, ctrl); + } + sci_stop_tx(port); + } } static void sci_receive_chars(struct uart_port *port) @@ -1192,9 +1218,15 @@ static void sci_dma_tx_complete(void *arg) schedule_work(&s->work_tx); } else { s->cookie_tx = -EINVAL; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || + s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { u16 ctrl = serial_port_in(port, SCSCR); serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { + /* Switch irq from DMA to SCIF */ + dmaengine_pause(s->chan_tx_saved); + enable_irq(s->irqs[SCIx_TXI_IRQ]); + } } } @@ -1266,9 +1298,13 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s) /* Direct new serial port interrupts back to CPU */ scr = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || + s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { enable_irq(s->irqs[SCIx_RXI_IRQ]); + if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) + scif_set_rtrg(port, s->rx_trigger); + else + scr &= ~SCSCR_RDRQE; } serial_port_out(port, SCSCR, scr | SCSCR_RIE); } @@ -1505,7 +1541,8 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) tty_flip_buffer_push(&port->state->port); } - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || + s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) sci_dma_rx_submit(s, true); sci_dma_rx_reenable_irq(s); @@ -1531,15 +1568,12 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, memset(&cfg, 0, sizeof(cfg)); cfg.direction = dir; - if (dir == DMA_MEM_TO_DEV) { - cfg.dst_addr = port->mapbase + - (sci_getreg(port, SCxTDR)->offset << port->regshift); - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - } else { - cfg.src_addr = port->mapbase + - (sci_getreg(port, SCxRDR)->offset << port->regshift); - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - } + cfg.dst_addr = port->mapbase + + (sci_getreg(port, SCxTDR)->offset << port->regshift); + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + cfg.src_addr = port->mapbase + + (sci_getreg(port, SCxRDR)->offset << port->regshift); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ret = dmaengine_slave_config(chan, &cfg); if (ret) { @@ -1574,7 +1608,7 @@ static void sci_request_dma(struct uart_port *port) * Don't request a dma channel if no channel was specified * in the device tree. */ - if (!of_find_property(port->dev->of_node, "dmas", NULL)) + if (!of_property_present(port->dev->of_node, "dmas")) return; chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV); @@ -1632,7 +1666,8 @@ static void sci_request_dma(struct uart_port *port) s->chan_rx_saved = s->chan_rx = chan; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || + s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) sci_dma_rx_submit(s, false); } } @@ -1685,9 +1720,15 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) u16 ssr = serial_port_in(port, SCxSR); /* Disable future Rx interrupts */ - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - disable_irq_nosync(irq); - scr |= SCSCR_RDRQE; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || + s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { + disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]); + if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { + scif_set_rtrg(port, 1); + scr |= SCSCR_RIE; + } else { + scr |= SCSCR_RDRQE; + } } else { if (sci_dma_rx_submit(s, false) < 0) goto handle_pio; @@ -1737,6 +1778,24 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) return IRQ_HANDLED; } +static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + unsigned long flags; + unsigned short ctrl; + + if (port->type != PORT_SCI) + return sci_tx_interrupt(irq, ptr); + + spin_lock_irqsave(&port->lock, flags); + ctrl = serial_port_in(port, SCSCR); + ctrl &= ~(SCSCR_TE | SCSCR_TEIE); + serial_port_out(port, SCSCR, ctrl); + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; +} + static irqreturn_t sci_br_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; @@ -1873,7 +1932,7 @@ static const struct sci_irq_desc { [SCIx_TEI_IRQ] = { .desc = "tx end", - .handler = sci_tx_interrupt, + .handler = sci_tx_end_interrupt, }, /* @@ -2580,8 +2639,14 @@ done: sci_set_mctrl(port, port->mctrl); } - scr_val |= SCSCR_RE | SCSCR_TE | - (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); + /* + * For SCI, TE (transmit enable) must be set after setting TIE + * (transmit interrupt enable) or in the same instruction to + * start the transmitting process. So skip setting TE here for SCI. + */ + if (port->type != PORT_SCI) + scr_val |= SCSCR_TE; + scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); serial_port_out(port, SCSCR, scr_val | s->hscif_tot); if ((srr + 1 == 5) && (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) { @@ -3149,7 +3214,7 @@ static int sci_remove(struct platform_device *dev) #define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16) #define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff) -static const struct of_device_id of_sci_match[] = { +static const struct of_device_id of_sci_match[] __maybe_unused = { /* SoC-specific types */ { .compatible = "renesas,scif-r7s72100", diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index c0ae78632dda..0b65563c4e9e 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -59,6 +59,9 @@ enum { #define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */ #define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */ +/* Serial Control Register, SCI only bits */ +#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */ + /* Serial Control Register, SCIFA/SCIFB only bits */ #define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ #define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 492a3bdab5ba..b58f51296ace 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -1250,7 +1250,7 @@ static struct platform_driver sprd_platform_driver = { .remove = sprd_remove, .driver = { .name = "sprd_serial", - .of_match_table = of_match_ptr(serial_ids), + .of_match_table = serial_ids, .pm = &sprd_pm_ops, }, }; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 767ff9fdb2e5..1e38fc9b10c1 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -693,8 +693,9 @@ static void stm32_usart_transmit_chars(struct uart_port *port) int ret; if (!stm32_port->hw_flow_control && - port->rs485.flags & SER_RS485_ENABLED) { - stm32_port->txdone = false; + port->rs485.flags & SER_RS485_ENABLED && + (port->x_char || + !(uart_circ_empty(xmit) || uart_tx_stopped(port)))) { stm32_usart_tc_interrupt_disable(port); stm32_usart_rs485_rts_enable(port); } @@ -743,7 +744,6 @@ static void stm32_usart_transmit_chars(struct uart_port *port) stm32_usart_tx_interrupt_disable(port); if (!stm32_port->hw_flow_control && port->rs485.flags & SER_RS485_ENABLED) { - stm32_port->txdone = true; stm32_usart_tc_interrupt_enable(port); } } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 0ec41a732c88..903285b5aea7 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -203,7 +203,6 @@ struct stm32_port { bool hw_flow_control; bool swap; /* swap RX & TX pins */ bool fifoen; - bool txdone; int rxftcfg; /* RX FIFO threshold CFG */ int txftcfg; /* TX FIFO threshold CFG */ bool wakeup_src; diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index ccb809216e94..0fbeb3dbd843 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1403,7 +1403,7 @@ static int zs_probe(struct platform_device *op) int keyboard_mouse = 0; int err; - if (of_find_property(op->dev.of_node, "keyboard", NULL)) + if (of_property_present(op->dev.of_node, "keyboard")) keyboard_mouse = 1; /* uarts must come before keyboards/mice */ @@ -1553,7 +1553,7 @@ static int __init sunzilog_init(void) for_each_node_by_name(dp, "zs") { num_sunzilog++; - if (of_find_property(dp, "keyboard", NULL)) + if (of_property_present(dp, "keyboard")) num_keybms++; } diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 32c7a5b43f8e..404230c1ebb2 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -366,15 +366,14 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port) /* Pick next descriptor and fill from buffer */ bdp = qe_port->tx_cur; - while (!(ioread16be(&bdp->status) & BD_SC_READY) && - (xmit->tail != xmit->head)) { + while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) { count = 0; p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port); while (count < qe_port->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; uart_xmit_advance(port, 1); count++; - if (xmit->head == xmit->tail) + if (uart_circ_empty(xmit)) break; } @@ -1179,7 +1178,7 @@ static int soft_uart_init(struct platform_device *ofdev) struct qe_firmware_info *qe_fw_info; int ret; - if (of_find_property(np, "soft-uart", NULL)) { + if (of_property_read_bool(np, "soft-uart")) { dev_dbg(&ofdev->dev, "using Soft-UART mode\n"); soft_uart = 1; } else { diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 33f258d6fef9..16e469e581ec 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -287,7 +287,6 @@ struct slgt_info { unsigned char *tx_buf; int tx_count; - char *flag_buf; bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; @@ -730,7 +729,7 @@ static void set_termios(struct tty_struct *tty, /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; + tty->hw_stopped = false; tx_release(tty); } } @@ -1953,13 +1952,13 @@ static void cts_change(struct slgt_info *info, unsigned short status) if (info->port.tty) { if (info->port.tty->hw_stopped) { if (info->signals & SerialSignal_CTS) { - info->port.tty->hw_stopped = 0; + info->port.tty->hw_stopped = false; info->pending_bh |= BH_TRANSMIT; return; } } else { if (!(info->signals & SerialSignal_CTS)) - info->port.tty->hw_stopped = 1; + info->port.tty->hw_stopped = true; } } } @@ -3244,13 +3243,7 @@ static int alloc_tmp_rbuf(struct slgt_info *info) info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL); if (info->tmp_rbuf == NULL) return -ENOMEM; - /* unused flag buffer to satisfy receive_buf calling interface */ - info->flag_buf = kzalloc(info->max_frame_size + 5, GFP_KERNEL); - if (!info->flag_buf) { - kfree(info->tmp_rbuf); - info->tmp_rbuf = NULL; - return -ENOMEM; - } + return 0; } @@ -3258,8 +3251,6 @@ static void free_tmp_rbuf(struct slgt_info *info) { kfree(info->tmp_rbuf); info->tmp_rbuf = NULL; - kfree(info->flag_buf); - info->flag_buf = NULL; } /* @@ -4657,7 +4648,8 @@ check_again: hdlcdev_rx(info,info->tmp_rbuf, framesize); else #endif - ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize); + ldisc_receive_buf(tty, info->tmp_rbuf, NULL, + framesize); } } free_rbufs(info, start, end); @@ -4691,8 +4683,8 @@ static bool rx_get_buf(struct slgt_info *info) DBGDATA(info, info->rbufs[i].buf, count, "rx"); DBGINFO(("rx_get_buf size=%d\n", count)); if (count) - ldisc_receive_buf(info->port.tty, info->rbufs[i].buf, - info->flag_buf, count); + ldisc_receive_buf(info->port.tty, info->rbufs[i].buf, NULL, + count); free_rbufs(info, i, i); return true; } diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index f45cd683c02e..1e0d80e98d26 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -62,6 +62,8 @@ int __tty_check_change(struct tty_struct *tty, int sig); int tty_check_change(struct tty_struct *tty); void __stop_tty(struct tty_struct *tty); void __start_tty(struct tty_struct *tty); +void tty_write_unlock(struct tty_struct *tty); +int tty_write_lock(struct tty_struct *tty, int ndelay); void tty_vhangup_session(struct tty_struct *tty); void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty); int tty_signal_session_leader(struct tty_struct *tty, int exit_session); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 36fb945fdad4..c84be40fb8df 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -933,13 +933,13 @@ static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) return i; } -static void tty_write_unlock(struct tty_struct *tty) +void tty_write_unlock(struct tty_struct *tty) { mutex_unlock(&tty->atomic_write_lock); wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); } -static int tty_write_lock(struct tty_struct *tty, int ndelay) +int tty_write_lock(struct tty_struct *tty, int ndelay) { if (!mutex_trylock(&tty->atomic_write_lock)) { if (ndelay) @@ -3070,7 +3070,7 @@ static struct device *tty_get_device(struct tty_struct *tty) { dev_t devt = tty_devnum(tty); - return class_find_device_by_devt(tty_class, devt); + return class_find_device_by_devt(&tty_class, devt); } @@ -3143,8 +3143,6 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch) } EXPORT_SYMBOL_GPL(tty_put_char); -struct class *tty_class; - static int tty_cdev_add(struct tty_driver *driver, dev_t dev, unsigned int index, unsigned int count) { @@ -3239,7 +3237,7 @@ struct device *tty_register_device_attr(struct tty_driver *driver, return ERR_PTR(-ENOMEM); dev->devt = devt; - dev->class = tty_class; + dev->class = &tty_class; dev->parent = device; dev->release = tty_device_create_release; dev_set_name(dev, "%s", name); @@ -3294,8 +3292,7 @@ EXPORT_SYMBOL_GPL(tty_register_device_attr); */ void tty_unregister_device(struct tty_driver *driver, unsigned index) { - device_destroy(tty_class, - MKDEV(driver->major, driver->minor_start) + index); + device_destroy(&tty_class, MKDEV(driver->major, driver->minor_start) + index); if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { cdev_del(driver->cdevs[index]); driver->cdevs[index] = NULL; @@ -3510,13 +3507,14 @@ static char *tty_devnode(const struct device *dev, umode_t *mode) return NULL; } +const struct class tty_class = { + .name = "tty", + .devnode = tty_devnode, +}; + static int __init tty_class_init(void) { - tty_class = class_create(THIS_MODULE, "tty"); - if (IS_ERR(tty_class)) - return PTR_ERR(tty_class); - tty_class->devnode = tty_devnode; - return 0; + return class_register(&tty_class); } postcore_initcall(tty_class_init); @@ -3614,42 +3612,24 @@ static struct ctl_table tty_table[] = { { } }; -static struct ctl_table tty_dir_table[] = { - { - .procname = "tty", - .mode = 0555, - .child = tty_table, - }, - { } -}; - -static struct ctl_table tty_root_table[] = { - { - .procname = "dev", - .mode = 0555, - .child = tty_dir_table, - }, - { } -}; - /* * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ int __init tty_init(void) { - register_sysctl_table(tty_root_table); + register_sysctl_init("dev/tty", tty_table); cdev_init(&tty_cdev, &tty_fops); if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + device_create(&tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - consdev = device_create_with_groups(tty_class, NULL, + consdev = device_create_with_groups(&tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, cons_dev_groups, "console"); if (IS_ERR(consdev)) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 12983ce4e43e..2e88b414cf95 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -7,6 +7,7 @@ * discipline handling modules (like SLIP). */ +#include #include #include #include @@ -40,10 +41,10 @@ /* * Internal flag options for termios setting behavior */ -#define TERMIOS_FLUSH 1 -#define TERMIOS_WAIT 2 -#define TERMIOS_TERMIO 4 -#define TERMIOS_OLD 8 +#define TERMIOS_FLUSH BIT(0) +#define TERMIOS_WAIT BIT(1) +#define TERMIOS_TERMIO BIT(2) +#define TERMIOS_OLD BIT(3) /** @@ -500,22 +501,43 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); - ld = tty_ldisc_ref(tty); + if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) { +retry_write_wait: + retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty)); + if (retval < 0) + return retval; - if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); + if (tty_write_lock(tty, 0) < 0) + goto retry_write_wait; + + /* Racing writer? */ + if (tty_chars_in_buffer(tty)) { + tty_write_unlock(tty); + goto retry_write_wait; + } + + ld = tty_ldisc_ref(tty); + if (ld != NULL) { + if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); + tty_ldisc_deref(ld); + } + + if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) { + tty->ops->wait_until_sent(tty, 0); + if (signal_pending(current)) { + tty_write_unlock(tty); + return -ERESTARTSYS; + } + } + + tty_set_termios(tty, &tmp_termios); + + tty_write_unlock(tty); + } else { + tty_set_termios(tty, &tmp_termios); } - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - tty_set_termios(tty, &tmp_termios); - /* FIXME: Arguably if tmp_termios == tty->termios AND the actual requested termios was not tmp_termios then we may want to return an error as no user requested change has diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index e758f44729e7..3f68e213df1f 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -58,7 +58,6 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) { unsigned long flags; - int ret = 0; if (new_ldisc->num < N_TTY || new_ldisc->num >= NR_LDISCS) return -EINVAL; @@ -67,7 +66,7 @@ int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) tty_ldiscs[new_ldisc->num] = new_ldisc; raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); - return ret; + return 0; } EXPORT_SYMBOL(tty_register_ldisc); diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 1dc07f9214d5..829c4be66f3b 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -656,10 +656,17 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) } } - /* The vcs_size might have changed while we slept to grab - * the user buffer, so recheck. + /* The vc might have been freed or vcs_size might have changed + * while we slept to grab the user buffer, so recheck. * Return data written up to now on failure. */ + vc = vcs_vc(inode, &viewed); + if (!vc) { + if (written) + break; + ret = -ENXIO; + goto unlock_out; + } size = vcs_size(vc, attr, false); if (size < 0) { if (written) @@ -804,7 +811,7 @@ int __init vcs_init(void) if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) panic("unable to get major %d for vcs device", VCS_MAJOR); - vc_class = class_create(THIS_MODULE, "vc"); + vc_class = class_create("vc"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu"); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3c2ea9c098f7..1e8e57b45688 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -135,10 +135,9 @@ const struct consw *conswitchp; #define DEFAULT_CURSOR_BLINK_MS 200 struct vc vc_cons [MAX_NR_CONSOLES]; +EXPORT_SYMBOL(vc_cons); -#ifndef VT_SINGLE_DRIVER static const struct consw *con_driver_map[MAX_NR_CONSOLES]; -#endif static int con_open(struct tty_struct *, struct file *); static void vc_init(struct vc_data *vc, unsigned int rows, @@ -162,6 +161,7 @@ int default_utf8 = true; module_param(default_utf8, int, S_IRUGO | S_IWUSR); int global_cursor_default = -1; module_param(global_cursor_default, int, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(global_cursor_default); static int cur_default = CUR_UNDERLINE; module_param(cur_default, int, S_IRUGO | S_IWUSR); @@ -174,6 +174,7 @@ static int ignore_poke; int do_poke_blanked_console; int console_blanked; +EXPORT_SYMBOL(console_blanked); static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int vesa_off_interval; @@ -190,8 +191,10 @@ static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback); * saved_* variants are for save/restore around kernel debugger enter/leave */ int fg_console; +EXPORT_SYMBOL(fg_console); int last_console; int want_console = -1; + static int saved_fg_console; static int saved_last_console; static int saved_want_console; @@ -223,6 +226,7 @@ static int scrollback_delta; * the console on our behalf. */ int (*console_blank_hook)(int); +EXPORT_SYMBOL(console_blank_hook); static DEFINE_TIMER(console_timer, blank_screen_t); static int blank_state; @@ -639,6 +643,7 @@ void update_region(struct vc_data *vc, unsigned long start, int count) set_cursor(vc); } } +EXPORT_SYMBOL(update_region); /* Structure of attributes is hardware-dependent */ @@ -984,6 +989,7 @@ void redraw_screen(struct vc_data *vc, int is_switch) notify_update(vc); } } +EXPORT_SYMBOL(redraw_screen); /* * Allocation, freeing and resizing of VTs. @@ -1000,10 +1006,10 @@ static void visual_init(struct vc_data *vc, int num, int init) if (vc->vc_sw) module_put(vc->vc_sw->owner); vc->vc_sw = conswitchp; -#ifndef VT_SINGLE_DRIVER + if (con_driver_map[num]) vc->vc_sw = con_driver_map[num]; -#endif + __module_get(vc->vc_sw->owner); vc->vc_num = num; vc->vc_display_fg = &master_display_fg; @@ -1305,6 +1311,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) { return vc_do_resize(vc->port.tty, vc, cols, rows); } +EXPORT_SYMBOL(vc_resize); /** * vt_resize - resize a VT @@ -1368,6 +1375,7 @@ enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt}; const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; +EXPORT_SYMBOL(color_table); /* the default colour table, for VGA+ colour systems */ unsigned char default_red[] = { @@ -1375,18 +1383,21 @@ unsigned char default_red[] = { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }; module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(default_red); unsigned char default_grn[] = { 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff }; module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(default_grn); unsigned char default_blu[] = { 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff }; module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR); +EXPORT_SYMBOL(default_blu); /* * gotoxy() must verify all boundaries, because the arguments @@ -3143,93 +3154,84 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) return -EFAULT; ret = 0; - switch (type) - { - case TIOCL_SETSEL: - ret = set_selection_user((struct tiocl_selection - __user *)(p+1), tty); - break; - case TIOCL_PASTESEL: - ret = paste_selection(tty); - break; - case TIOCL_UNBLANKSCREEN: - console_lock(); - unblank_screen(); - console_unlock(); - break; - case TIOCL_SELLOADLUT: - console_lock(); - ret = sel_loadlut(p); - console_unlock(); - break; - case TIOCL_GETSHIFTSTATE: + switch (type) { + case TIOCL_SETSEL: + return set_selection_user((struct tiocl_selection + __user *)(p+1), tty); + case TIOCL_PASTESEL: + return paste_selection(tty); + case TIOCL_UNBLANKSCREEN: + console_lock(); + unblank_screen(); + console_unlock(); + break; + case TIOCL_SELLOADLUT: + console_lock(); + ret = sel_loadlut(p); + console_unlock(); + break; + case TIOCL_GETSHIFTSTATE: + /* + * Make it possible to react to Shift+Mousebutton. Note that + * 'shift_state' is an undocumented kernel-internal variable; + * programs not closely related to the kernel should not use + * this. + */ + data = vt_get_shift_state(); + return put_user(data, p); + case TIOCL_GETMOUSEREPORTING: + console_lock(); /* May be overkill */ + data = mouse_reporting(); + console_unlock(); + return put_user(data, p); + case TIOCL_SETVESABLANK: + console_lock(); + ret = set_vesa_blanking(p); + console_unlock(); + break; + case TIOCL_GETKMSGREDIRECT: + data = vt_get_kmsg_redirect(); + return put_user(data, p); + case TIOCL_SETKMSGREDIRECT: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = vt_get_shift_state(); - ret = put_user(data, p); - break; - case TIOCL_GETMOUSEREPORTING: - console_lock(); /* May be overkill */ - data = mouse_reporting(); - console_unlock(); - ret = put_user(data, p); - break; - case TIOCL_SETVESABLANK: - console_lock(); - ret = set_vesa_blanking(p); - console_unlock(); - break; - case TIOCL_GETKMSGREDIRECT: - data = vt_get_kmsg_redirect(); - ret = put_user(data, p); - break; - case TIOCL_SETKMSGREDIRECT: - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - } else { - if (get_user(data, p+1)) - ret = -EFAULT; - else - vt_kmsg_redirect(data); - } - break; - case TIOCL_GETFGCONSOLE: - /* No locking needed as this is a transiently - correct return anyway if the caller hasn't - disabled switching */ - ret = fg_console; - break; - case TIOCL_SCROLLCONSOLE: - if (get_user(lines, (s32 __user *)(p+4))) { - ret = -EFAULT; - } else { - /* Need the console lock here. Note that lots - of other calls need fixing before the lock - is actually useful ! */ - console_lock(); - scrollfront(vc_cons[fg_console].d, lines); - console_unlock(); - ret = 0; - } - break; - case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ - console_lock(); - ignore_poke = 1; - do_blank_screen(0); - console_unlock(); - break; - case TIOCL_BLANKEDSCREEN: - ret = console_blanked; - break; - default: - ret = -EINVAL; - break; + if (get_user(data, p+1)) + return -EFAULT; + + vt_kmsg_redirect(data); + + break; + case TIOCL_GETFGCONSOLE: + /* + * No locking needed as this is a transiently correct return + * anyway if the caller hasn't disabled switching. + */ + return fg_console; + case TIOCL_SCROLLCONSOLE: + if (get_user(lines, (s32 __user *)(p+4))) + return -EFAULT; + + /* + * Needs the console lock here. Note that lots of other calls + * need fixing before the lock is actually useful! + */ + console_lock(); + scrollfront(vc_cons[fg_console].d, lines); + console_unlock(); + break; + case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ + console_lock(); + ignore_poke = 1; + do_blank_screen(0); + console_unlock(); + break; + case TIOCL_BLANKEDSCREEN: + return console_blanked; + default: + return -EINVAL; } + return ret; } @@ -3539,7 +3541,7 @@ int __init vty_init(const struct file_operations *console_fops) if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - tty0dev = device_create_with_groups(tty_class, NULL, + tty0dev = device_create_with_groups(&tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, vt_dev_groups, "tty0"); if (IS_ERR(tty0dev)) @@ -3571,8 +3573,6 @@ int __init vty_init(const struct file_operations *console_fops) return 0; } -#ifndef VT_SINGLE_DRIVER - static struct class *vtconsole_class; static int do_bind_con_driver(const struct consw *csw, int first, int last, @@ -4236,12 +4236,13 @@ void give_up_console(const struct consw *csw) do_unregister_con_driver(csw); console_unlock(); } +EXPORT_SYMBOL(give_up_console); static int __init vtconsole_class_init(void) { int i; - vtconsole_class = class_create(THIS_MODULE, "vtconsole"); + vtconsole_class = class_create("vtconsole"); if (IS_ERR(vtconsole_class)) { pr_warn("Unable to create vt console class; errno = %ld\n", PTR_ERR(vtconsole_class)); @@ -4273,8 +4274,6 @@ static int __init vtconsole_class_init(void) } postcore_initcall(vtconsole_class_init); -#endif - /* * Screen blanking */ @@ -4792,23 +4791,3 @@ void vc_scrolldelta_helper(struct vc_data *c, int lines, c->vc_visible_origin = ubase + (from + from_off) % wrap; } EXPORT_SYMBOL_GPL(vc_scrolldelta_helper); - -/* - * Visible symbols for modules - */ - -EXPORT_SYMBOL(color_table); -EXPORT_SYMBOL(default_red); -EXPORT_SYMBOL(default_grn); -EXPORT_SYMBOL(default_blu); -EXPORT_SYMBOL(update_region); -EXPORT_SYMBOL(redraw_screen); -EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(fg_console); -EXPORT_SYMBOL(console_blank_hook); -EXPORT_SYMBOL(console_blanked); -EXPORT_SYMBOL(vc_cons); -EXPORT_SYMBOL(global_cursor_default); -#ifndef VT_SINGLE_DRIVER -EXPORT_SYMBOL(give_up_console); -#endif diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 31df052fbc41..51b3c6ae781d 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -150,7 +150,8 @@ static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) u32 hba_maxq, rem, tot_queues; struct Scsi_Host *host = hba->host; - hba_maxq = FIELD_GET(MAX_QUEUE_SUP, hba->mcq_capabilities); + /* maxq is 0 based value */ + hba_maxq = FIELD_GET(MAX_QUEUE_SUP, hba->mcq_capabilities) + 1; tot_queues = UFS_MCQ_NUM_DEV_CMD_QUEUES + read_queues + poll_queues + rw_queues; @@ -265,7 +266,7 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) - hba->ucdl_dma_addr; - return div_u64(addr, sizeof(struct utp_transfer_cmd_desc)); + return div_u64(addr, ufshcd_get_ucd_size(hba)); } static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, @@ -299,11 +300,11 @@ EXPORT_SYMBOL_GPL(ufshcd_mcq_poll_cqe_nolock); unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, struct ufs_hw_queue *hwq) { - unsigned long completed_reqs; + unsigned long completed_reqs, flags; - spin_lock(&hwq->cq_lock); + spin_lock_irqsave(&hwq->cq_lock, flags); completed_reqs = ufshcd_mcq_poll_cqe_nolock(hba, hwq); - spin_unlock(&hwq->cq_lock); + spin_unlock_irqrestore(&hwq->cq_lock, flags); return completed_reqs; } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 17d7bb875fee..e7e79f515e14 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2849,10 +2849,10 @@ static void ufshcd_map_queues(struct Scsi_Host *shost) static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) { struct utp_transfer_cmd_desc *cmd_descp = (void *)hba->ucdl_base_addr + - i * sizeof_utp_transfer_cmd_desc(hba); + i * ufshcd_get_ucd_size(hba); struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr + - i * sizeof_utp_transfer_cmd_desc(hba); + i * ufshcd_get_ucd_size(hba); u16 response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); @@ -3761,7 +3761,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) size_t utmrdl_size, utrdl_size, ucdl_size; /* Allocate memory for UTP command descriptors */ - ucdl_size = sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs; + ucdl_size = ufshcd_get_ucd_size(hba) * hba->nutrs; hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, ucdl_size, &hba->ucdl_dma_addr, @@ -3861,7 +3861,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); - cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba); + cmd_desc_size = ufshcd_get_ucd_size(hba); cmd_desc_dma_addr = hba->ucdl_dma_addr; for (i = 0; i < hba->nutrs; i++) { @@ -8452,7 +8452,7 @@ static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs) { size_t ucdl_size, utrdl_size; - ucdl_size = sizeof(struct utp_transfer_cmd_desc) * nutrs; + ucdl_size = ufshcd_get_ucd_size(hba) * nutrs; dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr, hba->ucdl_dma_addr); @@ -9459,8 +9459,16 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) * that performance might be impacted. */ ret = ufshcd_urgent_bkops(hba); - if (ret) + if (ret) { + /* + * If return err in suspend flow, IO will hang. + * Trigger error handler and break suspend for + * error recovery. + */ + ufshcd_force_error_recovery(hba); + ret = -EBUSY; goto enable_scaling; + } } else { /* make sure that auto bkops is disabled */ ufshcd_disable_auto_bkops(hba); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index a871a988829d..7f33bcc315f2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -133,35 +133,6 @@ comment "USB port drivers" if USB -config USB_USS720 - tristate "USS720 parport driver" - depends on PARPORT - select PARPORT_NOT_PC - help - This driver is for USB parallel port adapters that use the Lucent - Technologies USS-720 chip. These cables are plugged into your USB - port and provide USB compatibility to peripherals designed with - parallel port interfaces. - - The chip has two modes: automatic mode and manual mode. In automatic - mode, it looks to the computer like a standard USB printer. Only - printers may be connected to the USS-720 in this mode. The generic - USB printer driver ("USB Printer support", above) may be used in - that mode, and you can say N here if you want to use the chip only - in this mode. - - Manual mode is not limited to printers, any parallel port - device should work. This driver utilizes manual mode. - Note however that some operations are three orders of magnitude - slower than on a PCI/ISA Parallel Port, so timing critical - applications might not work. - - Say Y here if you own an USS-720 USB->Parport cable and intend to - connect anything other than a printer to it. - - To compile this driver as a module, choose M here: the - module will be called uss720. - source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a81e6ef293af..3a9a0dd4be70 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/ obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_ISP1362_HCD) += host/ -obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_FSL_USB2) += host/ obj-$(CONFIG_USB_FOTG210_HCD) += host/ diff --git a/drivers/usb/cdns3/cdns3-debug.h b/drivers/usb/cdns3/cdns3-debug.h index a5c6a29e1340..4618cfe85a4f 100644 --- a/drivers/usb/cdns3/cdns3-debug.h +++ b/drivers/usb/cdns3/cdns3-debug.h @@ -107,8 +107,7 @@ static inline char *cdns3_decode_ep0_irq(char *str, * Prints out all TRBs in the endpoint ring, even those after the Link TRB. *. */ -static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, - struct cdns3_trb *ring, char *str) +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str) { dma_addr_t addr = priv_ep->trb_pool_dma; struct cdns3_trb *trb; @@ -136,9 +135,6 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); - if (trb_per_sector > TRBS_PER_SEGMENT) - trb_per_sector = TRBS_PER_SEGMENT; - if (trb_per_sector > TRBS_PER_SEGMENT) { sprintf(str + ret, "\t\tTransfer ring %d too big\n", trb_per_sector); @@ -146,7 +142,7 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, } for (i = 0; i < trb_per_sector; ++i) { - trb = &ring[i]; + trb = &priv_ep->trb_pool[i]; ret += sprintf(str + ret, "\t\t@%pad %08x %08x %08x\n", &addr, le32_to_cpu(trb->buffer), diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index ccfaebca6faa..1dcadef933e3 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -2097,6 +2097,19 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) else priv_ep->trb_burst_size = 16; + /* + * In versions preceding DEV_VER_V2, for example, iMX8QM, there exit the bugs + * in the DMA. These bugs occur when the trb_burst_size exceeds 16 and the + * address is not aligned to 128 Bytes (which is a product of the 64-bit AXI + * and AXI maximum burst length of 16 or 0xF+1, dma_axi_ctrl0[3:0]). This + * results in data corruption when it crosses the 4K border. The corruption + * specifically occurs from the position (4K - (address & 0x7F)) to 4K. + * + * So force trb_burst_size to 16 at such platform. + */ + if (priv_dev->dev_ver < DEV_VER_V2) + priv_ep->trb_burst_size = 16; + mult = min_t(u8, mult, EP_CFG_MULT_MAX); buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX); maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX); diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index 7574b4a62813..40db89e3333c 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq, TP_STRUCT__entry( __field(enum usb_device_speed, speed) __field(u32, usb_ists) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->speed = cdns3_get_speed(priv_dev); __entry->usb_ists = usb_ists; ), - TP_printk("%s", cdns3_decode_usb_irq(__get_str(str), __entry->speed, + TP_printk("%s", cdns3_decode_usb_irq(__get_buf(CDNS3_MSG_MAX), __entry->speed, __entry->usb_ists)) ); @@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __field(u32, ep_traddr) __field(u32, ep_last_sid) __field(u32, use_streams) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __assign_str(ep_name, priv_ep->name); @@ -134,7 +132,7 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __entry->use_streams = priv_ep->use_streams; ), TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d", - cdns3_decode_epx_irq(__get_str(str), + cdns3_decode_epx_irq(__get_buf(CDNS3_MSG_MAX), __get_str(ep_name), __entry->ep_sts), __entry->ep_traddr, @@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq, TP_STRUCT__entry( __field(int, ep_dir) __field(u32, ep_sts) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->ep_dir = priv_dev->selected_ep; __entry->ep_sts = ep_sts; ), - TP_printk("%s", cdns3_decode_ep0_irq(__get_str(str), + TP_printk("%s", cdns3_decode_ep0_irq(__get_buf(CDNS3_MSG_MAX), __entry->ep_dir, __entry->ep_sts)) ); @@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNS3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNS3_MSG_MAX), CDNS3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) @@ -438,22 +434,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring, TP_PROTO(struct cdns3_endpoint *priv_ep), TP_ARGS(priv_ep), TP_STRUCT__entry( - __dynamic_array(u8, ring, TRB_RING_SIZE) - __dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint)) __dynamic_array(char, buffer, - (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX) + GET_TRBS_PER_SEGMENT(priv_ep->type) > TRBS_PER_SEGMENT ? + CDNS3_MSG_MAX : + (GET_TRBS_PER_SEGMENT(priv_ep->type) * 65) + CDNS3_MSG_MAX) ), TP_fast_assign( - memcpy(__get_dynamic_array(priv_ep), priv_ep, - sizeof(struct cdns3_endpoint)); - memcpy(__get_dynamic_array(ring), priv_ep->trb_pool, - TRB_RING_SIZE); + cdns3_dbg_ring(priv_ep, __get_str(buffer)); ), - TP_printk("%s", - cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep), - (struct cdns3_trb *)__get_str(ring), - __get_str(buffer))) + TP_printk("%s", __get_str(buffer)) ); DEFINE_EVENT(cdns3_log_ring, cdns3_ring, diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h index 5983dfb99653..4b51011eb00b 100644 --- a/drivers/usb/cdns3/cdnsp-trace.h +++ b/drivers/usb/cdns3/cdnsp-trace.h @@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) @@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, __field(u32, field3) __field(union cdnsp_trb *, trb) __field(dma_addr_t, trb_dma) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -359,7 +357,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, ), TP_printk("%s: %s trb: %p(%pad)", cdnsp_ring_type_string(__entry->type), - cdnsp_decode_trb(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_trb(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->field0, __entry->field1, __entry->field2, __entry->field3), __entry->trb, &__entry->trb_dma @@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -552,7 +549,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", cdnsp_decode_ep_context(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", cdnsp_decode_ep_context(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) @@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->portsc) ) ); diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6f4a3deced35..71afeab97e83 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -14,5 +14,5 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o -obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o +obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 2eeccf4ec9d6..2855ac303001 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -152,12 +152,12 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) * Check the various over current related properties. If over current * detection is disabled we're not interested in the polarity. */ - if (of_find_property(np, "disable-over-current", NULL)) { + if (of_property_read_bool(np, "disable-over-current")) { data->disable_oc = 1; - } else if (of_find_property(np, "over-current-active-high", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-high")) { data->oc_pol_active_low = 0; data->oc_pol_configured = 1; - } else if (of_find_property(np, "over-current-active-low", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-low")) { data->oc_pol_active_low = 1; data->oc_pol_configured = 1; } else { diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 281fc51720ce..798cb077867a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev, return ret; } - if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL)) + if (of_property_read_bool(dev->of_node, "non-zero-ttctrl-ttha")) platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA; ext_id = ERR_PTR(-ENODEV); @@ -1108,7 +1108,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) ret = ci_usb_phy_init(ci); if (ret) { dev_err(dev, "unable to init phy: %d\n", ret); - return ret; + goto ulpi_exit; } ci->hw_bank.phys = res->start; diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index bbc610e5bd69..e72c43615d77 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(ci_otg); -static int ci_role_show(struct seq_file *s, void *data) -{ - struct ci_hdrc *ci = s->private; - - if (ci->role != CI_ROLE_END) - seq_printf(s, "%s\n", ci_role(ci)->name); - - return 0; -} - -static ssize_t ci_role_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct ci_hdrc *ci = s->private; - enum ci_role role; - char buf[8]; - int ret; - - if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) - if (ci->roles[role] && - !strncmp(buf, ci->roles[role]->name, - strlen(ci->roles[role]->name))) - break; - - if (role == CI_ROLE_END || role == ci->role) - return -EINVAL; - - pm_runtime_get_sync(ci->dev); - disable_irq(ci->irq); - ci_role_stop(ci); - ret = ci_role_start(ci, role); - enable_irq(ci->irq); - pm_runtime_put_sync(ci->dev); - - return ret ? ret : count; -} - -static int ci_role_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_role_show, inode->i_private); -} - -static const struct file_operations ci_role_fops = { - .open = ci_role_open, - .write = ci_role_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ci_registers_show(struct seq_file *s, void *unused) { struct ci_hdrc *ci = s->private; @@ -354,7 +300,6 @@ void dbg_create_files(struct ci_hdrc *ci) if (ci_otg_is_fsm_mode(ci)) debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops); - debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops); debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops); } diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 4bb6d304eb4b..311007b1d904 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1928,6 +1928,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; + if (request.req.wLength == 0) /* Length-0 requests are never IN */ + request.req.bRequestType &= ~USB_DIR_IN; is_in = request.req.bRequestType & USB_DIR_IN; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index a98b2108376a..84d91b1c1eed 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -90,7 +90,7 @@ static void ulpi_remove(struct device *dev) drv->remove(to_ulpi_dev(dev)); } -static struct bus_type ulpi_bus = { +static const struct bus_type ulpi_bus = { .name = "ulpi", .match = ulpi_match, .uevent = ulpi_uevent, @@ -229,7 +229,7 @@ static int ulpi_read_id(struct ulpi *ulpi) request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); return 0; err: - of_device_request_module(&ulpi->dev); + of_request_module(ulpi->dev.of_node); return 0; } diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index fbb087b728dc..268ccbec88f9 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -172,3 +172,44 @@ void hcd_buffer_free( } dma_free_coherent(hcd->self.sysdev, size, addr, dma); } + +void *hcd_buffer_alloc_pages(struct usb_hcd *hcd, + size_t size, gfp_t mem_flags, dma_addr_t *dma) +{ + if (size == 0) + return NULL; + + if (hcd->localmem_pool) + return gen_pool_dma_alloc_align(hcd->localmem_pool, + size, dma, PAGE_SIZE); + + /* some USB hosts just use PIO */ + if (!hcd_uses_dma(hcd)) { + *dma = DMA_MAPPING_ERROR; + return (void *)__get_free_pages(mem_flags, + get_order(size)); + } + + return dma_alloc_coherent(hcd->self.sysdev, + size, dma, mem_flags); +} + +void hcd_buffer_free_pages(struct usb_hcd *hcd, + size_t size, void *addr, dma_addr_t dma) +{ + if (!addr) + return; + + if (hcd->localmem_pool) { + gen_pool_free(hcd->localmem_pool, + (unsigned long)addr, size); + return; + } + + if (!hcd_uses_dma(hcd)) { + free_pages((unsigned long)addr, get_order(size)); + return; + } + + dma_free_coherent(hcd->self.sysdev, size, addr, dma); +} diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e501a03d6c70..fcf68818e999 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -186,6 +186,7 @@ static int connected(struct usb_dev_state *ps) static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) { struct usb_dev_state *ps = usbm->ps; + struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus); unsigned long flags; spin_lock_irqsave(&ps->lock, flags); @@ -194,8 +195,8 @@ static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) list_del(&usbm->memlist); spin_unlock_irqrestore(&ps->lock, flags); - usb_free_coherent(ps->dev, usbm->size, usbm->mem, - usbm->dma_handle); + hcd_buffer_free_pages(hcd, usbm->size, + usbm->mem, usbm->dma_handle); usbfs_decrease_memory_usage( usbm->size + sizeof(struct usb_memory)); kfree(usbm); @@ -234,7 +235,7 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) size_t size = vma->vm_end - vma->vm_start; void *mem; unsigned long flags; - dma_addr_t dma_handle; + dma_addr_t dma_handle = DMA_MAPPING_ERROR; int ret; ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory)); @@ -247,8 +248,8 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) goto error_decrease_mem; } - mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN, - &dma_handle); + mem = hcd_buffer_alloc_pages(hcd, + size, GFP_USER | __GFP_NOWARN, &dma_handle); if (!mem) { ret = -ENOMEM; goto error_free_usbm; @@ -264,7 +265,14 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) usbm->vma_use_count = 1; INIT_LIST_HEAD(&usbm->memlist); - if (hcd->localmem_pool || !hcd_uses_dma(hcd)) { + /* + * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates + * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check + * whether we are in such cases, and then use remap_pfn_range (or + * dma_mmap_coherent) to map normal (or DMA) pages into the user + * space, respectively. + */ + if (dma_handle == DMA_MAPPING_ERROR) { if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(usbm->mem) >> PAGE_SHIFT, size, vma->vm_page_prot) < 0) { diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index a0e076c6f3a4..f58a0299fb3b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -2025,7 +2025,7 @@ int usb_disable_usb2_hardware_lpm(struct usb_device *udev) #endif /* CONFIG_PM */ -struct bus_type usb_bus_type = { +const struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index da7d88e069e6..c4ed3310e069 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -88,7 +88,7 @@ static int init_usb_class(void) } kref_init(&usb_class->kref); - usb_class->class = class_create(THIS_MODULE, "usbmisc"); + usb_class->class = class_create("usbmisc"); if (IS_ERR(usb_class->class)) { result = PTR_ERR(usb_class->class); printk(KERN_ERR "class_create failed for usb devices\n"); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 533baa85083c..a34b22537d7c 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) return -ENODEV; } - obj = acpi_evaluate_dsm(port_handle, &guid, 0, - USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL); - - if (!obj) - return -ENODEV; - - if (obj->type != ACPI_TYPE_INTEGER) { + obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0, + USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL, + ACPI_TYPE_INTEGER); + if (!obj) { dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1); - ACPI_FREE(obj); return -EINVAL; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 34742fbbd84d..901ec732321c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -206,6 +206,82 @@ int usb_find_common_endpoints_reverse(struct usb_host_interface *alt, } EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse); +/** + * usb_find_endpoint() - Given an endpoint address, search for the endpoint's + * usb_host_endpoint structure in an interface's current altsetting. + * @intf: the interface whose current altsetting should be searched + * @ep_addr: the endpoint address (number and direction) to find + * + * Search the altsetting's list of endpoints for one with the specified address. + * + * Return: Pointer to the usb_host_endpoint if found, %NULL otherwise. + */ +static const struct usb_host_endpoint *usb_find_endpoint( + const struct usb_interface *intf, unsigned int ep_addr) +{ + int n; + const struct usb_host_endpoint *ep; + + n = intf->cur_altsetting->desc.bNumEndpoints; + ep = intf->cur_altsetting->endpoint; + for (; n > 0; (--n, ++ep)) { + if (ep->desc.bEndpointAddress == ep_addr) + return ep; + } + return NULL; +} + +/** + * usb_check_bulk_endpoints - Check whether an interface's current altsetting + * contains a set of bulk endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are bulk, %false otherwise. + */ +bool usb_check_bulk_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_bulk(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_bulk_endpoints); + +/** + * usb_check_int_endpoints - Check whether an interface's current altsetting + * contains a set of interrupt endpoints with the given addresses. + * @intf: the interface whose current altsetting should be searched + * @ep_addrs: 0-terminated array of the endpoint addresses (number and + * direction) to look for + * + * Search for endpoints with the specified addresses and check their types. + * + * Return: %true if all the endpoints are found and are interrupt, + * %false otherwise. + */ +bool usb_check_int_endpoints( + const struct usb_interface *intf, const u8 *ep_addrs) +{ + const struct usb_host_endpoint *ep; + + for (; *ep_addrs; ++ep_addrs) { + ep = usb_find_endpoint(intf, *ep_addrs); + if (!ep || !usb_endpoint_xfer_int(&ep->desc)) + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(usb_check_int_endpoints); + /** * usb_find_alt_setting() - Given a configuration, find the alternate setting * for the given interface. diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 3f14e15f07f6..ffe3f6818e9c 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -141,7 +141,7 @@ static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev) #endif -extern struct bus_type usb_bus_type; +extern const struct bus_type usb_bus_type; extern struct mutex usb_port_peer_mutex; extern struct device_type usb_device_type; extern struct device_type usb_if_device_type; diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 40cf2880d7e5..0bb4c0c845bf 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1003,6 +1003,7 @@ struct dwc2_hregs_backup { * @ctrl_out_desc: EP0 OUT data phase desc chain pointer * @irq: Interrupt request line number * @clk: Pointer to otg clock + * @utmi_clk: Pointer to utmi_clk clock * @reset: Pointer to dwc2 reset controller * @reset_ecc: Pointer to dwc2 optional reset controller in Stratix10. * @regset: A pointer to a struct debugfs_regset32, which contains @@ -1065,6 +1066,7 @@ struct dwc2_hsotg { void *priv; int irq; struct clk *clk; + struct clk *utmi_clk; struct reset_control *reset; struct reset_control *reset_ecc; diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 0a1145592fc7..0d4495c6b9f7 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1078,7 +1078,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) earliest_frame = dwc2_frame_num_inc(frame_number, 1); next_active_frame = earliest_frame; - /* Get the "no microframe schduler" out of the way... */ + /* Get the "no microframe scheduler" out of the way... */ if (!hsotg->params.uframe_sched) { if (qh->do_split) /* Splits are active at microframe 0 minus 1 */ diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 9ed9fd956940..21d16533bd2f 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -508,8 +508,7 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps); } - if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) - p->oc_disable = true; + p->oc_disable = of_property_read_bool(hsotg->dev->of_node, "disable-over-current"); } static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d1589ba7d322..5aee284018c0 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -101,10 +101,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) if (ret) return ret; + if (hsotg->utmi_clk) { + ret = clk_prepare_enable(hsotg->utmi_clk); + if (ret) + goto err_dis_reg; + } + if (hsotg->clk) { ret = clk_prepare_enable(hsotg->clk); if (ret) - return ret; + goto err_dis_utmi_clk; } if (hsotg->uphy) { @@ -113,10 +119,29 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } else { ret = phy_init(hsotg->phy); - if (ret == 0) + if (ret == 0) { ret = phy_power_on(hsotg->phy); + if (ret) + phy_exit(hsotg->phy); + } } + if (ret) + goto err_dis_clk; + + return 0; + +err_dis_clk: + if (hsotg->clk) + clk_disable_unprepare(hsotg->clk); + +err_dis_utmi_clk: + if (hsotg->utmi_clk) + clk_disable_unprepare(hsotg->utmi_clk); + +err_dis_reg: + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); + return ret; } @@ -156,6 +181,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) if (hsotg->clk) clk_disable_unprepare(hsotg->clk); + if (hsotg->utmi_clk) + clk_disable_unprepare(hsotg->utmi_clk); + return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); } @@ -232,6 +260,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) if (IS_ERR(hsotg->clk)) return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->clk), "cannot get otg clock\n"); + hsotg->utmi_clk = devm_clk_get_optional(hsotg->dev, "utmi"); + if (IS_ERR(hsotg->utmi_clk)) + return dev_err_probe(hsotg->dev, PTR_ERR(hsotg->utmi_clk), + "cannot get utmi clock\n"); + /* Regulators */ for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i]; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 476b63618511..7b2ce013cc5b 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -534,90 +534,6 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); } -static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) -{ - if (!dwc->has_hibernation) - return 0; - - if (!dwc->nr_scratch) - return 0; - - dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, - DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); - if (!dwc->scratchbuf) - return -ENOMEM; - - return 0; -} - -static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) -{ - dma_addr_t scratch_addr; - u32 param; - int ret; - - if (!dwc->has_hibernation) - return 0; - - if (!dwc->nr_scratch) - return 0; - - /* should never fall here */ - if (!WARN_ON(dwc->scratchbuf)) - return 0; - - scratch_addr = dma_map_single(dwc->sysdev, dwc->scratchbuf, - dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dwc->sysdev, scratch_addr)) { - dev_err(dwc->sysdev, "failed to map scratch buffer\n"); - ret = -EFAULT; - goto err0; - } - - dwc->scratch_addr = scratch_addr; - - param = lower_32_bits(scratch_addr); - - ret = dwc3_send_gadget_generic_command(dwc, - DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); - if (ret < 0) - goto err1; - - param = upper_32_bits(scratch_addr); - - ret = dwc3_send_gadget_generic_command(dwc, - DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); - if (ret < 0) - goto err1; - - return 0; - -err1: - dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); - -err0: - return ret; -} - -static void dwc3_free_scratch_buffers(struct dwc3 *dwc) -{ - if (!dwc->has_hibernation) - return; - - if (!dwc->nr_scratch) - return; - - /* should never fall here */ - if (!WARN_ON(dwc->scratchbuf)) - return; - - dma_unmap_single(dwc->sysdev, dwc->scratch_addr, dwc->nr_scratch * - DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); - kfree(dwc->scratchbuf); -} - static void dwc3_core_num_eps(struct dwc3 *dwc) { struct dwc3_hwparams *parms = &dwc->hwparams; @@ -800,11 +716,91 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + /* + * Some ULPI USB PHY does not support internal VBUS supply, to drive + * the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL + * bit of OTG_CTRL register. Controller configures the USB2 PHY + * ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus + * with an external supply. + */ + if (dwc->ulpi_ext_vbus_drv) + reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; } +static int dwc3_phy_init(struct dwc3 *dwc) +{ + int ret; + + usb_phy_init(dwc->usb2_phy); + usb_phy_init(dwc->usb3_phy); + + ret = phy_init(dwc->usb2_generic_phy); + if (ret < 0) + goto err_shutdown_usb3_phy; + + ret = phy_init(dwc->usb3_generic_phy); + if (ret < 0) + goto err_exit_usb2_phy; + + return 0; + +err_exit_usb2_phy: + phy_exit(dwc->usb2_generic_phy); +err_shutdown_usb3_phy: + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); + + return ret; +} + +static void dwc3_phy_exit(struct dwc3 *dwc) +{ + phy_exit(dwc->usb3_generic_phy); + phy_exit(dwc->usb2_generic_phy); + + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); +} + +static int dwc3_phy_power_on(struct dwc3 *dwc) +{ + int ret; + + usb_phy_set_suspend(dwc->usb2_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy, 0); + + ret = phy_power_on(dwc->usb2_generic_phy); + if (ret < 0) + goto err_suspend_usb3_phy; + + ret = phy_power_on(dwc->usb3_generic_phy); + if (ret < 0) + goto err_power_off_usb2_phy; + + return 0; + +err_power_off_usb2_phy: + phy_power_off(dwc->usb2_generic_phy); +err_suspend_usb3_phy: + usb_phy_set_suspend(dwc->usb3_phy, 1); + usb_phy_set_suspend(dwc->usb2_phy, 1); + + return ret; +} + +static void dwc3_phy_power_off(struct dwc3 *dwc) +{ + phy_power_off(dwc->usb3_generic_phy); + phy_power_off(dwc->usb2_generic_phy); + + usb_phy_set_suspend(dwc->usb3_phy, 1); + usb_phy_set_suspend(dwc->usb2_phy, 1); +} + static int dwc3_clk_enable(struct dwc3 *dwc) { int ret; @@ -840,17 +836,8 @@ static void dwc3_clk_disable(struct dwc3 *dwc) static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); - - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + dwc3_phy_power_off(dwc); + dwc3_phy_exit(dwc); dwc3_clk_disable(dwc); reset_control_assert(dwc->reset); } @@ -877,7 +864,6 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) static void dwc3_core_setup_global_control(struct dwc3 *dwc) { - u32 hwparams4 = dwc->hwparams.hwparams4; u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -905,9 +891,6 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) reg &= ~DWC3_GCTL_DSBLCLKGTNG; break; case DWC3_GHWPARAMS1_EN_PWROPT_HIB: - /* enable hibernation here */ - dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4); - /* * REVISIT Enabling this bit so that host-mode hibernation * will work. Device-mode hibernation is not yet implemented. @@ -1096,7 +1079,7 @@ static int dwc3_core_init(struct dwc3 *dwc) ret = dwc3_phy_setup(dwc); if (ret) - goto err0; + return ret; if (!dwc->ulpi_ready) { ret = dwc3_core_ulpi_init(dwc); @@ -1105,7 +1088,7 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_core_soft_reset(dwc); ret = -EPROBE_DEFER; } - goto err0; + return ret; } dwc->ulpi_ready = true; } @@ -1113,25 +1096,17 @@ static int dwc3_core_init(struct dwc3 *dwc) if (!dwc->phys_ready) { ret = dwc3_core_get_phy(dwc); if (ret) - goto err0a; + goto err_exit_ulpi; dwc->phys_ready = true; } - usb_phy_init(dwc->usb2_phy); - usb_phy_init(dwc->usb3_phy); - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - goto err0a; - - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) { - phy_exit(dwc->usb2_generic_phy); - goto err0a; - } + ret = dwc3_phy_init(dwc); + if (ret) + goto err_exit_ulpi; ret = dwc3_core_soft_reset(dwc); if (ret) - goto err1; + goto err_exit_phy; if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) { @@ -1151,10 +1126,6 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); - ret = dwc3_setup_scratch_buffers(dwc); - if (ret) - goto err1; - /* Set power down scale of suspend_clk */ dwc3_set_power_down_clk_scale(dwc); @@ -1166,20 +1137,14 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(dwc); - usb_phy_set_suspend(dwc->usb2_phy, 0); - usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) - goto err2; - - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err3; + ret = dwc3_phy_power_on(dwc); + if (ret) + goto err_exit_phy; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err4; + goto err_power_off_phy; } /* @@ -1233,6 +1198,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->parkmode_disable_ss_quirk) reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS; + if (dwc->parkmode_disable_hs_quirk) + reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS; + if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) && (dwc->maximum_speed == USB_SPEED_HIGH || dwc->maximum_speed == USB_SPEED_FULL)) @@ -1296,26 +1264,13 @@ static int dwc3_core_init(struct dwc3 *dwc) return 0; -err4: - phy_power_off(dwc->usb3_generic_phy); - -err3: - phy_power_off(dwc->usb2_generic_phy); - -err2: - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - -err1: - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - -err0a: +err_power_off_phy: + dwc3_phy_power_off(dwc); +err_exit_phy: + dwc3_phy_exit(dwc); +err_exit_ulpi: dwc3_ulpi_exit(dwc); -err0: return ret; } @@ -1553,8 +1508,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-tx-ipgap-linecheck-quirk"); dwc->resume_hs_terminations = device_property_read_bool(dev, "snps,resume-hs-terminations"); + dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev, + "snps,ulpi-ext-vbus-drv"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); + dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev, + "snps,parkmode-disable-hs-quirk"); dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, "snps,gfladj-refclk-lpm-sel-quirk"); @@ -1750,15 +1709,71 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) return edev; } +static int dwc3_get_clocks(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + + if (!dev->of_node) + return 0; + + /* + * Clocks are optional, but new DT platforms should support all clocks + * as required by the DT-binding. + * Some devices have different clock names in legacy device trees, + * check for them to retain backwards compatibility. + */ + dwc->bus_clk = devm_clk_get_optional(dev, "bus_early"); + if (IS_ERR(dwc->bus_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + } + + if (dwc->bus_clk == NULL) { + dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk"); + if (IS_ERR(dwc->bus_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->bus_clk), + "could not get bus clock\n"); + } + } + + dwc->ref_clk = devm_clk_get_optional(dev, "ref"); + if (IS_ERR(dwc->ref_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + } + + if (dwc->ref_clk == NULL) { + dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk"); + if (IS_ERR(dwc->ref_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->ref_clk), + "could not get ref clock\n"); + } + } + + dwc->susp_clk = devm_clk_get_optional(dev, "suspend"); + if (IS_ERR(dwc->susp_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + } + + if (dwc->susp_clk == NULL) { + dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk"); + if (IS_ERR(dwc->susp_clk)) { + return dev_err_probe(dev, PTR_ERR(dwc->susp_clk), + "could not get suspend clock\n"); + } + } + + return 0; +} + static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res, dwc_res; - struct dwc3 *dwc; - - int ret; - void __iomem *regs; + struct dwc3 *dwc; + int ret; dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) @@ -1797,77 +1812,25 @@ static int dwc3_probe(struct platform_device *pdev) dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) { ret = PTR_ERR(dwc->reset); - goto put_usb_psy; + goto err_put_psy; } - if (dev->of_node) { - /* - * Clocks are optional, but new DT platforms should support all - * clocks as required by the DT-binding. - * Some devices have different clock names in legacy device trees, - * check for them to retain backwards compatibility. - */ - dwc->bus_clk = devm_clk_get_optional(dev, "bus_early"); - if (IS_ERR(dwc->bus_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); - goto put_usb_psy; - } - - if (dwc->bus_clk == NULL) { - dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk"); - if (IS_ERR(dwc->bus_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk), - "could not get bus clock\n"); - goto put_usb_psy; - } - } - - dwc->ref_clk = devm_clk_get_optional(dev, "ref"); - if (IS_ERR(dwc->ref_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); - goto put_usb_psy; - } - - if (dwc->ref_clk == NULL) { - dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk"); - if (IS_ERR(dwc->ref_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk), - "could not get ref clock\n"); - goto put_usb_psy; - } - } - - dwc->susp_clk = devm_clk_get_optional(dev, "suspend"); - if (IS_ERR(dwc->susp_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); - goto put_usb_psy; - } - - if (dwc->susp_clk == NULL) { - dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk"); - if (IS_ERR(dwc->susp_clk)) { - ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk), - "could not get suspend clock\n"); - goto put_usb_psy; - } - } - } + ret = dwc3_get_clocks(dwc); + if (ret) + goto err_put_psy; ret = reset_control_deassert(dwc->reset); if (ret) - goto put_usb_psy; + goto err_put_psy; ret = dwc3_clk_enable(dwc); if (ret) - goto assert_reset; + goto err_assert_reset; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; - goto disable_clks; + goto err_disable_clks; } platform_set_drvdata(pdev, dwc); @@ -1877,19 +1840,17 @@ static int dwc3_probe(struct platform_device *pdev) DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) { ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); if (ret) - goto disable_clks; + goto err_disable_clks; } spin_lock_init(&dwc->lock); mutex_init(&dwc->mutex); + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err1; pm_runtime_forbid(dev); @@ -1897,27 +1858,23 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; - goto err2; + goto err_allow_rpm; } dwc->edev = dwc3_get_extcon(dwc); if (IS_ERR(dwc->edev)) { ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n"); - goto err3; + goto err_free_event_buffers; } ret = dwc3_get_dr_mode(dwc); if (ret) - goto err3; - - ret = dwc3_alloc_scratch_buffers(dwc); - if (ret) - goto err3; + goto err_free_event_buffers; ret = dwc3_core_init(dwc); if (ret) { dev_err_probe(dev, ret, "failed to initialize core\n"); - goto err4; + goto err_free_event_buffers; } dwc3_check_params(dwc); @@ -1925,46 +1882,31 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init_mode(dwc); if (ret) - goto err5; + goto err_exit_debugfs; pm_runtime_put(dev); return 0; -err5: +err_exit_debugfs: dwc3_debugfs_exit(dwc); dwc3_event_buffers_cleanup(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); - - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - + dwc3_phy_power_off(dwc); + dwc3_phy_exit(dwc); dwc3_ulpi_exit(dwc); - -err4: - dwc3_free_scratch_buffers(dwc); - -err3: +err_free_event_buffers: dwc3_free_event_buffers(dwc); - -err2: - pm_runtime_allow(&pdev->dev); - -err1: - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - -disable_clks: +err_allow_rpm: + pm_runtime_allow(dev); + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); +err_disable_clks: dwc3_clk_disable(dwc); -assert_reset: +err_assert_reset: reset_control_assert(dwc->reset); -put_usb_psy: +err_put_psy: if (dwc->usb_psy) power_supply_put(dwc->usb_psy); @@ -1983,12 +1925,13 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); + pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); dwc3_free_event_buffers(dwc); - dwc3_free_scratch_buffers(dwc); if (dwc->usb_psy) power_supply_put(dwc->usb_psy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4743e918dcaf..1f043c31a096 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -263,6 +263,7 @@ #define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17) +#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16) #define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10) /* Global Status Register */ @@ -280,6 +281,7 @@ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) +#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17) #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) @@ -526,6 +528,7 @@ #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 +#define DWC3_DGCMD_DEV_NOTIFICATION 0x07 #define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F) #define DWC3_DGCMD_CMDACT BIT(10) @@ -538,6 +541,8 @@ #define DWC3_DGCMDPAR_TX_FIFO BIT(5) #define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0) #define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0) +#define DWC3_DGCMDPAR_DN_FUNC_WAKE BIT(0) +#define DWC3_DGCMDPAR_INTF_SEL(n) ((n) << 4) /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 @@ -969,12 +974,10 @@ struct dwc3_scratchpad_array { * @drd_work: workqueue used for role swapping * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer - * @scratchbuf: address of scratch buffer * @setup_buf: used while precessing STD USB requests * @ep0_trb_addr: dma address of @ep0_trb * @bounce_addr: dma address of @bounce * @ep0_usb_req: dummy req used while handling STD USB requests - * @scratch_addr: dma address of scratchbuf * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching @@ -999,7 +1002,6 @@ struct dwc3_scratchpad_array { * @current_otg_role: current role of operation while using the OTG block * @desired_otg_role: desired role of operation while using the OTG block * @otg_restart_host: flag that OTG controller needs to restart host - * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @max_ssp_rate: SuperSpeed Plus maximum signaling rate and lane count @@ -1056,7 +1058,6 @@ struct dwc3_scratchpad_array { * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer - * @has_hibernation: true when dwc3 was configured with Hibernation * @sysdev_is_parent: true when dwc3 device has a parent driver * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that * there's now way for software to detect this in runtime. @@ -1100,8 +1101,12 @@ struct dwc3_scratchpad_array { * check during HS transmit. * @resume_hs_terminations: Set if we enable quirk for fixing improper crc * generation after resume from suspend. + * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin + * VBUS with an external supply. * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed * instances in park mode. + * @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed + * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -1110,6 +1115,8 @@ struct dwc3_scratchpad_array { * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. * @dis_split_quirk: set to disable split boundary. + * @wakeup_configured: set if the device is configured for remote wakeup. + * @suspended: set to track suspend event due to U3/L2. * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @max_cfg_eps: current max number of IN eps used across all USB configs. @@ -1123,11 +1130,9 @@ struct dwc3 { struct work_struct drd_work; struct dwc3_trb *ep0_trb; void *bounce; - void *scratchbuf; u8 *setup_buf; dma_addr_t ep0_trb_addr; dma_addr_t bounce_addr; - dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; struct completion ep0_in_setup; @@ -1187,7 +1192,6 @@ struct dwc3 { u32 current_otg_role; u32 desired_otg_role; bool otg_restart_host; - u32 nr_scratch; u32 u1u2; u32 maximum_speed; u32 gadget_max_speed; @@ -1284,7 +1288,6 @@ struct dwc3 { unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; - unsigned has_hibernation:1; unsigned sysdev_is_parent:1; unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; @@ -1317,7 +1320,9 @@ struct dwc3 { unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned resume_hs_terminations:1; + unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; + unsigned parkmode_disable_hs_quirk:1; unsigned gfladj_refclk_lpm_sel:1; unsigned tx_de_emphasis_quirk:1; @@ -1327,6 +1332,8 @@ struct dwc3 { unsigned dis_split_quirk:1; unsigned async_callbacks:1; + unsigned wakeup_configured:1; + unsigned suspended:1; u16 imod_interval; diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 8bb2c9e3b9ac..09d703852a92 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd) return "Set Endpoint Prime"; case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: return "Run SoC Bus Loopback Test"; + case DWC3_DGCMD_DEV_NOTIFICATION: + return "Device Notification"; default: return "UNKNOWN"; } diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 850df0e6bcab..ebf03468fac4 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GPRTBIMAP_HS1), dump_register(GPRTBIMAP_FS0), dump_register(GPRTBIMAP_FS1), + dump_register(GUCTL2), + dump_register(VER_NUMBER), + dump_register(VER_TYPE), dump_register(GUSB2PHYCFG(0)), dump_register(GUSB2PHYCFG(1)), @@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GEVNTCOUNT(0)), dump_register(GHWPARAMS8), + dump_register(GUCTL3), + dump_register(GFLADJ), dump_register(DCFG), dump_register(DCTL), dump_register(DEVTEN), @@ -327,6 +332,11 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) unsigned int current_mode; unsigned long flags; u32 reg; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GSTS); @@ -345,6 +355,8 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) } spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -390,6 +402,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) struct dwc3 *dwc = s->private; unsigned long flags; u32 reg; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -409,6 +426,8 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); } + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -458,6 +477,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) struct dwc3 *dwc = s->private; unsigned long flags; u32 reg; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -488,6 +512,8 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) seq_printf(s, "UNKNOWN %d\n", reg); } + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -504,6 +530,7 @@ static ssize_t dwc3_testmode_write(struct file *file, unsigned long flags; u32 testmode = 0; char buf[32]; + int ret; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -521,10 +548,16 @@ static ssize_t dwc3_testmode_write(struct file *file, else testmode = 0; + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; + spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_set_test_mode(dwc, testmode); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return count; } @@ -543,12 +576,18 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) enum dwc3_link_state state; u32 reg; u8 speed; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GSTS); if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { seq_puts(s, "Not available\n"); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); return 0; } @@ -561,6 +600,8 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) dwc3_gadget_hs_link_string(state)); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -579,6 +620,7 @@ static ssize_t dwc3_link_state_write(struct file *file, char buf[32]; u32 reg; u8 speed; + int ret; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -598,10 +640,15 @@ static ssize_t dwc3_link_state_write(struct file *file, else return -EINVAL; + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; + spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GSTS); if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); return -EINVAL; } @@ -611,12 +658,15 @@ static ssize_t dwc3_link_state_write(struct file *file, if (speed < DWC3_DSTS_SUPERSPEED && state != DWC3_LINK_STATE_RECOV) { spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); return -EINVAL; } dwc3_gadget_set_link_state(dwc, state); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return count; } @@ -640,6 +690,11 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) unsigned long flags; u32 mdwidth; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXFIFO); @@ -652,6 +707,8 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -662,6 +719,11 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) unsigned long flags; u32 mdwidth; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXFIFO); @@ -674,6 +736,8 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -683,12 +747,19 @@ static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXREQQ); seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -698,12 +769,19 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -713,12 +791,19 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -728,12 +813,19 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -743,12 +835,19 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; u32 val; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); seq_printf(s, "%u\n", val); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -793,6 +892,11 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused) struct dwc3 *dwc = dep->dwc; unsigned long flags; int i; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); if (dep->number <= 1) { @@ -822,6 +926,8 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused) out: spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -834,6 +940,11 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) u32 lower_32_bits; u32 upper_32_bits; u32 reg; + int ret; + + ret = pm_runtime_resume_and_get(dwc->dev); + if (ret < 0) + return ret; spin_lock_irqsave(&dwc->lock, flags); reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number); @@ -846,6 +957,8 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) seq_printf(s, "0x%016llx\n", ep_info); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return 0; } @@ -905,6 +1018,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->regs = dwc3_regs; dwc->regset->nregs = ARRAY_SIZE(dwc3_regs); dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; + dwc->regset->dev = dwc->dev; root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root); dwc->debug_root = root; diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 173cf3579c55..cda9458c809b 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -11,12 +11,14 @@ #include #include #include -#include +#include #include #include #include #include +#include "core.h" + /* USB WRAPPER register offsets */ #define USBSS_PID 0x0 #define USBSS_OVERCURRENT_CTRL 0x4 @@ -45,6 +47,10 @@ #define USBSS_PHY_VBUS_SEL_SHIFT 1 #define USBSS_PHY_LANE_REVERSE BIT(0) +/* CORE STAT register bits */ +#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12) +#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12 + /* MODE CONTROL register bits */ #define USBSS_MODE_VALID BIT(0) @@ -54,6 +60,13 @@ #define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1) #define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0) +#define USBSS_WAKEUP_CFG_ALL (USBSS_WAKEUP_CFG_VBUSVALID_EN | \ + USBSS_WAKEUP_CFG_SESSVALID_EN | \ + USBSS_WAKEUP_CFG_LINESTATE_EN | \ + USBSS_WAKEUP_CFG_OVERCURRENT_EN) + +#define USBSS_WAKEUP_CFG_NONE 0 + /* WAKEUP STAT register bits */ #define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4) #define USBSS_WAKEUP_STAT_LINESTATE BIT(3) @@ -97,6 +110,7 @@ struct dwc3_data { struct regmap *syscon; unsigned int offset; unsigned int vbus_divider; + u32 wakeup_stat; }; static const int dwc3_ti_rate_table[] = { /* in KHZ */ @@ -233,6 +247,12 @@ static int dwc3_ti_probe(struct platform_device *pdev) reg |= USBSS_MODE_VALID; dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg); + /* Device has capability to wakeup system from sleep */ + device_set_wakeup_capable(dev, true); + ret = device_wakeup_enable(dev); + if (ret) + dev_err(dev, "couldn't enable device as a wakeup source: %d\n", ret); + /* Setting up autosuspend */ pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(dev); @@ -281,6 +301,27 @@ static int dwc3_ti_remove(struct platform_device *pdev) static int dwc3_ti_suspend_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg, current_prtcap_dir; + + if (device_may_wakeup(dev)) { + reg = dwc3_ti_readl(data, USBSS_CORE_STAT); + current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK) + >> USBSS_CORE_OPERATIONAL_MODE_SHIFT; + /* Set wakeup config enable bits */ + reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); + if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) { + reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN; + } else { + reg = USBSS_WAKEUP_CFG_VBUSVALID_EN | USBSS_WAKEUP_CFG_SESSVALID_EN; + /* + * Enable LINESTATE wake up only if connected to bus + * and in U2/L3 state else it causes spurious wake-up. + */ + } + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + /* clear wakeup status so we know what caused the wake up */ + dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR); + } clk_disable_unprepare(data->usb2_refclk); @@ -290,9 +331,18 @@ static int dwc3_ti_suspend_common(struct device *dev) static int dwc3_ti_resume_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg; clk_prepare_enable(data->usb2_refclk); + if (device_may_wakeup(dev)) { + /* Clear wakeup config enable bits */ + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE); + } + + reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT); + data->wakeup_stat = reg; + return 0; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 560793545362..44a04c9b2073 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -388,107 +388,41 @@ static void dwc3_pci_remove(struct pci_dev *pci) } static const struct pci_device_id dwc3_pci_id_table[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BYT, &dwc3_pci_intel_byt_swnode) }, + { PCI_DEVICE_DATA(INTEL, MRFLD, &dwc3_pci_intel_mrfld_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ICLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, EHL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLM, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT), - (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD), - (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB), - (kernel_ulong_t) &dwc3_pci_amd_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MR), - (kernel_ulong_t)&dwc3_pci_amd_mr_swnode, }, + { PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) }, + { PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_swnode) }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 61de693461da..953b752a5052 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -30,6 +30,8 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -356,6 +358,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->gadget->wakeup_armed << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -365,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + return dwc3_ep0_delegate_req(dwc, ctrl); case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -476,6 +481,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + if (dwc->wakeup_configured) + dwc->gadget->wakeup_armed = set; + else + ret = -EINVAL; break; /* * 9.4.1 says only for SS, in AddressState only for @@ -510,13 +519,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, switch (wValue) { case USB_INTRF_FUNC_SUSPEND: - /* - * REVISIT: Ideally we would enable some low power mode here, - * however it's unclear what we should be doing here. - * - * For now, we're not doing anything, just making sure we return - * 0 so USB Command Verifier tests pass without any errors. - */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cf5b4f49c3ed..d831f5acf7b5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -139,6 +139,24 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } +static void dwc3_ep0_reset_state(struct dwc3 *dwc) +{ + unsigned int dir; + + if (dwc->ep0state != EP0_SETUP_PHASE) { + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; + + dwc3_ep0_stall_and_restart(dwc); + } +} + /** * dwc3_ep_inc_trb - increment a trb index. * @index: Pointer to the TRB index to increment. @@ -258,7 +276,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, return ret; } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc); +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); /** * dwc3_send_gadget_ep_cmd - issue an endpoint command @@ -325,7 +343,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, fallthrough; case DWC3_LINK_STATE_U3: - ret = __dwc3_gadget_wakeup(dwc); + ret = __dwc3_gadget_wakeup(dwc, false); dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", ret); break; @@ -2273,6 +2291,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { /* -------------------------------------------------------------------------- */ +static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set) +{ + u32 reg; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + reg = dwc3_readl(dwc->regs, DWC3_DEVTEN); + if (set) + reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg &= ~DWC3_DEVTEN_ULSTCNGEN; + + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); +} + static int dwc3_gadget_get_frame(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -2280,7 +2314,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return __dwc3_gadget_get_frame(dwc); } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) { int retries; @@ -2311,9 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) return -EINVAL; } + if (async) + dwc3_gadget_enable_linksts_evts(dwc, true); + ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); + dwc3_gadget_enable_linksts_evts(dwc, false); return ret; } @@ -2325,6 +2363,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } + /* + * Since link status change events are enabled we will receive + * an U0 event when wakeup is successful. So bail out. + */ + if (async) + return 0; + /* poll until Link State changes to ON */ retries = 20000; @@ -2350,13 +2395,78 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) unsigned long flags; int ret; + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_wakeup(dwc); + if (!dwc->gadget->wakeup_armed) { + dev_err(dwc->dev, "not armed for remote wakeup\n"); + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + ret = __dwc3_gadget_wakeup(dwc, true); + spin_unlock_irqrestore(&dwc->lock, flags); return ret; } +static void dwc3_resume_gadget(struct dwc3 *dwc); + +static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; + int link_state; + + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + + spin_lock_irqsave(&dwc->lock, flags); + /* + * If the link is in U3, signal for remote wakeup and wait for the + * link to transition to U0 before sending device notification. + */ + link_state = dwc3_gadget_get_link_state(dwc); + if (link_state == DWC3_LINK_STATE_U3) { + ret = __dwc3_gadget_wakeup(dwc, false); + if (ret) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + dwc3_resume_gadget(dwc); + dwc->suspended = false; + dwc->link_state = DWC3_LINK_STATE_U0; + } + + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, + DWC3_DGCMDPAR_DN_FUNC_WAKE | + DWC3_DGCMDPAR_INTF_SEL(intf_id)); + if (ret) + dev_err(dwc->dev, "function remote wakeup failed, ret:%d\n", ret); + + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + +static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->wakeup_configured = !!set; + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { @@ -2478,7 +2588,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCFG, reg); } -static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) +static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) { u32 reg; u32 timeout = 2000; @@ -2497,17 +2607,11 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) reg &= ~DWC3_DCTL_KEEP_CONNECT; reg |= DWC3_DCTL_RUN_STOP; - if (dwc->has_hibernation) - reg |= DWC3_DCTL_KEEP_CONNECT; - __dwc3_gadget_set_speed(dwc); dwc->pullups_connected = true; } else { reg &= ~DWC3_DCTL_RUN_STOP; - if (dwc->has_hibernation && !suspend) - reg &= ~DWC3_DCTL_KEEP_CONNECT; - dwc->pullups_connected = false; } @@ -2532,29 +2636,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc); static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) { unsigned long flags; + int ret; spin_lock_irqsave(&dwc->lock, flags); dwc->connected = false; /* - * Per databook, when we want to stop the gadget, if a control transfer - * is still in process, complete it and get the core into setup phase. + * Attempt to end pending SETUP status phase, and not wait for the + * function to do so. */ - if (dwc->ep0state != EP0_SETUP_PHASE) { - int ret; - - if (dwc->delayed_status) - dwc3_ep0_send_delayed_status(dwc); - - reinit_completion(&dwc->ep0_in_setup); - - spin_unlock_irqrestore(&dwc->lock, flags); - ret = wait_for_completion_timeout(&dwc->ep0_in_setup, - msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); - spin_lock_irqsave(&dwc->lock, flags); - if (ret == 0) - dev_warn(dwc->dev, "timed out waiting for SETUP phase\n"); - } + if (dwc->delayed_status) + dwc3_ep0_send_delayed_status(dwc); /* * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a @@ -2564,9 +2656,28 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * bit. */ dwc3_stop_active_transfers(dwc); - __dwc3_gadget_stop(dwc); spin_unlock_irqrestore(&dwc->lock, flags); + /* + * Per databook, when we want to stop the gadget, if a control transfer + * is still in process, complete it and get the core into setup phase. + * In case the host is unresponsive to a SETUP transaction, forcefully + * stall the transfer, and move back to the SETUP phase, so that any + * pending endxfers can be executed. + */ + if (dwc->ep0state != EP0_SETUP_PHASE) { + reinit_completion(&dwc->ep0_in_setup); + + ret = wait_for_completion_timeout(&dwc->ep0_in_setup, + msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); + if (ret == 0) { + dev_warn(dwc->dev, "wait for SETUP phase timed out\n"); + spin_lock_irqsave(&dwc->lock, flags); + dwc3_ep0_reset_state(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + } + } + /* * Note: if the GEVNTCOUNT indicates events in the event buffer, the * driver needs to acknowledge them before the controller can halt. @@ -2574,7 +2685,34 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) * remaining event generated by the controller while polling for * DSTS.DEVCTLHLT. */ - return dwc3_gadget_run_stop(dwc, false, false); + ret = dwc3_gadget_run_stop(dwc, false); + + /* + * Stop the gadget after controller is halted, so that if needed, the + * events to update EP0 state can still occur while the run/stop + * routine polls for the halted state. DEVTEN is cleared as part of + * gadget stop. + */ + spin_lock_irqsave(&dwc->lock, flags); + __dwc3_gadget_stop(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + +static int dwc3_gadget_soft_connect(struct dwc3 *dwc) +{ + /* + * In the Synopsys DWC_usb31 1.90a programming guide section + * 4.1.9, it specifies that for a reconnect after a + * device-initiated disconnect requires a core soft reset + * (DCTL.CSftRst) before enabling the run/stop bit. + */ + dwc3_core_soft_reset(dwc); + + dwc3_event_buffers_setup(dwc); + __dwc3_gadget_start(dwc); + return dwc3_gadget_run_stop(dwc, true); } static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) @@ -2615,21 +2753,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) synchronize_irq(dwc->irq_gadget); - if (!is_on) { + if (!is_on) ret = dwc3_gadget_soft_disconnect(dwc); - } else { - /* - * In the Synopsys DWC_usb31 1.90a programming guide section - * 4.1.9, it specifies that for a reconnect after a - * device-initiated disconnect requires a core soft reset - * (DCTL.CSftRst) before enabling the run/stop bit. - */ - dwc3_core_soft_reset(dwc); - - dwc3_event_buffers_setup(dwc); - __dwc3_gadget_start(dwc); - ret = dwc3_gadget_run_stop(dwc, true, false); - } + else + ret = dwc3_gadget_soft_connect(dwc); pm_runtime_put(dwc->dev); @@ -2982,6 +3109,8 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, + .func_wakeup = dwc3_gadget_func_wakeup, + .set_remote_wakeup = dwc3_gadget_set_remote_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, @@ -3814,6 +3943,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) { int reg; + dwc->suspended = false; + dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -3827,24 +3958,19 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); - if (dwc->ep0state != EP0_SETUP_PHASE) { - unsigned int dir; - - dir = !!dwc->ep0_expect_in; - if (dwc->ep0state == EP0_DATA_PHASE) - dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); - else - dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); - dwc3_ep0_stall_and_restart(dwc); - } + dwc3_ep0_reset_state(dwc); } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; + dwc->suspended = false; + /* * Ideally, dwc3_reset_gadget() would trigger the function * drivers to stop any active transfers through ep disable. @@ -3892,20 +4018,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) * phase. So ensure that EP0 is in setup phase by issuing a stall * and restart if EP0 is not in setup phase. */ - if (dwc->ep0state != EP0_SETUP_PHASE) { - unsigned int dir; - - dir = !!dwc->ep0_expect_in; - if (dwc->ep0state == EP0_DATA_PHASE) - dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); - else - dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); - - dwc->eps[0]->trb_enqueue = 0; - dwc->eps[1]->trb_enqueue = 0; - - dwc3_ep0_stall_and_restart(dwc); - } + dwc3_ep0_reset_state(dwc); /* * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a @@ -3920,6 +4033,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_TSTCTRL_MASK; dwc3_gadget_dctl_write_safe(dwc, reg); dwc->test_mode = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); dwc3_clear_stall_all_ep(dwc); /* Reset device address to zero */ @@ -4072,8 +4187,10 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ } -static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) +static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { + dwc->suspended = false; + /* * TODO take core out of low power mode when that's * implemented. @@ -4084,6 +4201,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) dwc->gadget_driver->resume(dwc->gadget); spin_lock(&dwc->lock); } + + dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, @@ -4165,6 +4284,13 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } switch (next) { + case DWC3_LINK_STATE_U0: + if (dwc->gadget->wakeup_armed) { + dwc3_gadget_enable_linksts_evts(dwc, false); + dwc3_resume_gadget(dwc); + dwc->suspended = false; + } + break; case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) dwc3_suspend_gadget(dwc); @@ -4189,36 +4315,14 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, { enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; - if (dwc->link_state != next && next == DWC3_LINK_STATE_U3) + if (!dwc->suspended && next == DWC3_LINK_STATE_U3) { + dwc->suspended = true; dwc3_suspend_gadget(dwc); + } dwc->link_state = next; } -static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, - unsigned int evtinfo) -{ - unsigned int is_ss = evtinfo & BIT(4); - - /* - * WORKAROUND: DWC3 revision 2.20a with hibernation support - * have a known issue which can cause USB CV TD.9.23 to fail - * randomly. - * - * Because of this issue, core could generate bogus hibernation - * events which SW needs to ignore. - * - * Refers to: - * - * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 - * Device Fallback from SuperSpeed - */ - if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) - return; - - /* enter hibernation here */ -} - static void dwc3_gadget_interrupt(struct dwc3 *dwc, const struct dwc3_event_devt *event) { @@ -4233,29 +4337,18 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_conndone_interrupt(dwc); break; case DWC3_DEVICE_EVENT_WAKEUP: - dwc3_gadget_wakeup_interrupt(dwc); + dwc3_gadget_wakeup_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_HIBER_REQ: - if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, - "unexpected hibernation event\n")) - break; - - dwc3_gadget_hibernation_interrupt(dwc, event->event_info); + dev_WARN_ONCE(dwc->dev, true, "unexpected hibernation event\n"); break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_SUSPEND: /* It changed to be suspend event for version 2.30a and above */ - if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { - /* - * Ignore suspend event until the gadget enters into - * USB_STATE_CONFIGURED state. - */ - if (dwc->gadget->state >= USB_STATE_CONFIGURED) - dwc3_gadget_suspend_interrupt(dwc, - event->event_info); - } + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + dwc3_gadget_suspend_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_SOF: case DWC3_DEVICE_EVENT_ERRATIC_ERROR: @@ -4417,11 +4510,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) - goto out; - - if (!irq) - irq = -EINVAL; out: return irq; @@ -4493,6 +4581,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget->sg_supported = true; dwc->gadget->name = "dwc3-gadget"; dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; + dwc->gadget->wakeup_capable = true; /* * FIXME We might be setting max_speed to gadget_driver) return 0; - dwc3_gadget_run_stop(dwc, false, false); + ret = dwc3_gadget_soft_disconnect(dwc); + if (ret) + goto err; spin_lock_irqsave(&dwc->lock, flags); dwc3_disconnect_gadget(dwc); - __dwc3_gadget_stop(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return 0; + +err: + /* + * Attempt to reset the controller's state. Likely no + * communication can be established until the host + * performs a port reset. + */ + if (dwc->softconnect) + dwc3_gadget_soft_connect(dwc); + + return ret; } int dwc3_gadget_resume(struct dwc3 *dwc) { - int ret; - if (!dwc->gadget_driver || !dwc->softconnect) return 0; - ret = __dwc3_gadget_start(dwc); - if (ret < 0) - goto err0; - - ret = dwc3_gadget_run_stop(dwc, true, false); - if (ret < 0) - goto err1; - - return 0; - -err1: - __dwc3_gadget_stop(dwc); - -err0: - return ret; + return dwc3_gadget_soft_connect(dwc); } void dwc3_gadget_process_pending_events(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index f6f13e7f1ba1..61f57fe5bb78 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) { + if (irq > 0) dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); - goto out; - } - - if (!irq) - irq = -EINVAL; out: return irq; diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 1975aec8d36d..d2997d17cfbe 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event, TP_STRUCT__entry( __field(u32, event) __field(u32, ep0state) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->event = event; __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->event, __entry->ep0state)) ); @@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __field(__u16, wValue) __field(__u16, wIndex) __field(__u16, wLength) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5377d873c08e..1b3489149e5e 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config, } EXPORT_SYMBOL_GPL(usb_interface_id); +/** + * usb_func_wakeup - sends function wake notification to the host. + * @func: function that sends the remote wakeup notification. + * + * Applicable to devices operating at enhanced superspeed when usb + * functions are put in function suspend state and armed for function + * remote wakeup. On completion, function wake notification is sent. If + * the device is in low power state it tries to bring the device to active + * state before sending the wake notification. Since it is a synchronous + * call, caller must take care of not calling it in interrupt context. + * For devices operating at lower speeds returns negative errno. + * + * Returns zero on success, else negative errno. + */ +int usb_func_wakeup(struct usb_function *func) +{ + struct usb_gadget *gadget = func->config->cdev->gadget; + int id; + + if (!gadget->ops->func_wakeup) + return -EOPNOTSUPP; + + if (!func->func_wakeup_armed) { + ERROR(func->config->cdev, "not armed for func remote wakeup\n"); + return -EINVAL; + } + + for (id = 0; id < MAX_CONFIG_INTERFACES; id++) + if (func->config->interface[id] == func) + break; + + if (id == MAX_CONFIG_INTERFACES) { + ERROR(func->config->cdev, "Invalid function\n"); + return -EINVAL; + } + + return gadget->ops->func_wakeup(gadget, id); +} +EXPORT_SYMBOL_GPL(usb_func_wakeup); + static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { @@ -513,6 +553,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, return min(val, 900U) / 8; } +void check_remote_wakeup_config(struct usb_gadget *g, + struct usb_configuration *c) +{ + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) { + /* Reset the rw bit if gadget is not capable of it */ + if (!g->wakeup_capable && g->ops->set_remote_wakeup) { + WARN(c->cdev, "Clearing wakeup bit for config c.%d\n", + c->bConfigurationValue); + c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; + } + } +} + static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { @@ -888,6 +941,9 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) f->disable(f); + /* Section 9.1.1.6, disable remote wakeup when device is reset */ + f->func_wakeup_armed = false; + bitmap_zero(f->endpoints, 32); } cdev->config = NULL; @@ -994,6 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev, power = min(power, 500U); else power = min(power, 900U); + + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) + usb_gadget_set_remote_wakeup(gadget, 1); + else + usb_gadget_set_remote_wakeup(gadget, 0); done: if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); @@ -1948,9 +2009,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) f = cdev->config->interface[intf]; if (!f) break; - status = f->get_status ? f->get_status(f) : 0; - if (status < 0) - break; + + if (f->get_status) { + status = f->get_status(f); + if (status < 0) + break; + } else { + /* Set D0 and D1 bits based on func wakeup capability */ + if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { + status |= USB_INTRF_STAT_FUNC_RW_CAP; + if (f->func_wakeup_armed) + status |= USB_INTRF_STAT_FUNC_RW; + } + } + put_unaligned_le16(status & 0x0000ffff, req->buf); break; /* @@ -1972,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) break; value = 0; - if (f->func_suspend) + if (f->func_suspend) { value = f->func_suspend(f, w_index >> 8); + /* SetFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_SET_FEATURE) { + if (!(f->config->bmAttributes & + USB_CONFIG_ATT_WAKEUP) && + (w_index & USB_INTRF_FUNC_SUSPEND_RW)) + break; + + f->func_wakeup_armed = !!(w_index & + USB_INTRF_FUNC_SUSPEND_RW); + + if (w_index & USB_INTRF_FUNC_SUSPEND_LP) { + if (f->suspend && !f->func_suspended) { + f->suspend(f); + f->func_suspended = true; + } + /* + * Handle cases where host sends function resume + * through SetFeature(FUNCTION_SUSPEND) but low power + * bit reset + */ + } else { + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + /* ClearFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) { + f->func_wakeup_armed = false; + + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + if (value < 0) { ERROR(cdev, "func_suspend() returned error %d\n", @@ -2515,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget) cdev->driver->resume(cdev); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { - if (f->resume) + /* + * Check for func_suspended flag to see if the function is + * in USB3 FUNCTION_SUSPEND state. In this case resume is + * done via FUNCTION_SUSPEND feature selector. + */ + if (f->resume && !f->func_suspended) f->resume(f); } @@ -2530,6 +2643,10 @@ void composite_resume(struct usb_gadget *gadget) usb_gadget_clear_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); + } else { + maxpower = CONFIG_USB_GADGET_VBUS_DRAW; + maxpower = min(maxpower, 100U); + usb_gadget_vbus_draw(gadget, maxpower); } cdev->suspended = 0; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index b9f1136aa0a2..4c639e9ddedc 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, if (gadget_is_otg(gadget)) c->descriptors = otg_desc; + /* Properly configure the bmAttributes wakeup bit */ + check_remote_wakeup_config(gadget, c); + cfg = container_of(c, struct config_usb_cfg, c); if (!list_empty(&cfg->string_list)) { i = 0; diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index a7ab30e603e2..c6e63ad77a40 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void) return &opts->func_inst; } +static void ecm_suspend(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Suspend\n"); + + gether_suspend(&ecm->port); +} + +static void ecm_resume(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Resume\n"); + + gether_resume(&ecm->port); +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.setup = ecm_setup; ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; + ecm->port.func.resume = ecm_resume; return &ecm->port.func; } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 56cdfb2e4211..f41a385a5c42 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ssize_t ret; char *data; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t n; int ret; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; - ENTER(); - if (ffs->state == FFS_CLOSING) return -EBUSY; @@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file) { struct ffs_data *ffs = file->private_data; - ENTER(); - ffs_data_closed(ffs); return 0; @@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) struct usb_gadget *gadget = ffs->gadget; long ret; - ENTER(); - if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) { struct ffs_io_data *io_data = req->context; - ENTER(); if (req->status) io_data->status = req->status; else @@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct ffs_io_data *io_data = req->context; struct ffs_data *ffs = io_data->ffs; - ENTER(); - io_data->status = req->status ? req->status : req->actual; usb_ep_free_request(_ep, req); @@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb) unsigned long flags; int value; - ENTER(); - spin_lock_irqsave(&epfile->ffs->eps_lock, flags); if (io_data && io_data->ep && io_data->req) @@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); @@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, struct ffs_ep *ep; int ret; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data, { struct inode *inode; - ENTER(); - inode = new_inode(sb); if (inode) { @@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, struct dentry *dentry; struct inode *inode; - ENTER(); - dentry = d_alloc_name(sb->s_root, name); if (!dentry) return NULL; @@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc) struct inode *inode; struct ffs_data *ffs = data->ffs_data; - ENTER(); - ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; @@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param) struct fs_parse_result result; int opt; - ENTER(); - opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result); if (opt < 0) return opt; @@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc) struct ffs_data *ffs; int ret; - ENTER(); - if (!fc->source) return invalf(fc, "No source specified"); @@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) static void ffs_fs_kill_sb(struct super_block *sb) { - ENTER(); - kill_litter_super(sb); if (sb->s_fs_info) ffs_data_closed(sb->s_fs_info); @@ -1663,8 +1626,6 @@ static int functionfs_init(void) { int ret; - ENTER(); - ret = register_filesystem(&ffs_fs_type); if (!ret) pr_info("file system registered\n"); @@ -1676,8 +1637,6 @@ static int functionfs_init(void) static void functionfs_cleanup(void) { - ENTER(); - pr_info("unloading\n"); unregister_filesystem(&ffs_fs_type); } @@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs); static void ffs_data_get(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); } static void ffs_data_opened(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { @@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { - ENTER(); - if (refcount_dec_and_test(&ffs->ref)) { pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); @@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { ffs->state = FFS_DEACTIVATED; @@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name) if (!ffs) return NULL; - ENTER(); - ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); if (!ffs->io_completion_wq) { kfree(ffs); @@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - ffs_closed(ffs); BUG_ON(ffs->gadget); @@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs) static void ffs_data_reset(struct ffs_data *ffs) { - ENTER(); - ffs_data_clear(ffs); ffs->raw_descs_data = NULL; @@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) struct usb_gadget_strings **lang; int first_id; - ENTER(); - if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; @@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) static void functionfs_unbind(struct ffs_data *ffs) { - ENTER(); - if (!WARN_ON(!ffs->gadget)) { /* dequeue before freeing ep0req */ usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); @@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) struct ffs_epfile *epfile, *epfiles; unsigned i, count; - ENTER(); - count = ffs->eps_count; epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) @@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; - ENTER(); - for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { @@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, u8 length; int ret; - ENTER(); - /* At least two bytes are required: length and type */ if (len < 2) { pr_vdebug("descriptor too short\n"); @@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, unsigned long num = 0; int current_class = -1; - ENTER(); - for (;;) { int ret; @@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, struct ffs_desc_helper *helper = priv; struct usb_endpoint_descriptor *d; - ENTER(); - switch (type) { case FFS_DESCRIPTOR: break; @@ -2292,8 +2223,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, u16 bcd_version = le16_to_cpu(desc->bcdVersion); u16 w_index = le16_to_cpu(desc->wIndex); - if (bcd_version != 1) { - pr_vdebug("unsupported os descriptors version: %d", + if (bcd_version == 0x1) { + pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. " + "Userspace driver should be fixed, accepting 0x0001 for compatibility.\n"); + } else if (bcd_version != 0x100) { + pr_vdebug("unsupported os descriptors version: 0x%x\n", bcd_version); return -EINVAL; } @@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, int ret; const unsigned _len = len; - ENTER(); - /* loop over all ext compat/ext prop descriptors */ while (feature_count--) { ret = entity(type, h, data, len, priv); @@ -2349,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count, const unsigned _len = len; unsigned long num = 0; - ENTER(); - for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type; @@ -2413,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, struct ffs_data *ffs = priv; u8 length; - ENTER(); - switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; @@ -2490,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, int ret = -EINVAL, i; struct ffs_desc_helper helper; - ENTER(); - if (get_unaligned_le32(data + 4) != len) goto error; @@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, const char *data = _data; struct usb_string *s; - ENTER(); - if (len < 16 || get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len) @@ -3082,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct ffs_data *ffs_data; int ret; - ENTER(); - /* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would @@ -3160,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; - ENTER(); - /* Has descriptors only for speeds gadget does not support */ if (!(full | high | super)) return -ENOTSUPP; @@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f, unsigned long flags; int ret; - ENTER(); - pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); @@ -3441,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f, static void ffs_func_suspend(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); } static void ffs_func_resume(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); } @@ -3611,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c, unsigned count = ffs->eps_count; unsigned long flags; - ENTER(); if (ffs->func == func) { ffs_func_eps_disable(func); ffs->func = NULL; @@ -3620,6 +3535,7 @@ static void ffs_func_unbind(struct usb_configuration *c, /* Drain any pending AIO completions */ drain_workqueue(ffs->io_completion_wq); + ffs_event_add(ffs, FUNCTIONFS_UNBIND); if (!--opts->refcnt) functionfs_unbind(ffs); @@ -3644,15 +3560,12 @@ static void ffs_func_unbind(struct usb_configuration *c, func->function.ssp_descriptors = NULL; func->interfaces_nums = NULL; - ffs_event_add(ffs, FUNCTIONFS_UNBIND); } static struct usb_function *ffs_alloc(struct usb_function_instance *fi) { struct ffs_function *func; - ENTER(); - func = kzalloc(sizeof(*func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); @@ -3753,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) int ret = 0; struct ffs_dev *ffs_dev; - ENTER(); ffs_dev_lock(); ffs_dev = _ffs_find_dev(dev_name); @@ -3776,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) static void ffs_release_dev(struct ffs_dev *ffs_dev) { - ENTER(); ffs_dev_lock(); if (ffs_dev && ffs_dev->mounted) { @@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs) struct ffs_dev *ffs_obj; int ret = 0; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; @@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs) struct f_fs_opts *opts; struct config_item *ci; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index a8da3b4a2855..9f6b10134121 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -1325,7 +1325,7 @@ int ghid_setup(struct usb_gadget *g, int count) int status; dev_t dev; - hidg_class = class_create(THIS_MODULE, "hidg"); + hidg_class = class_create("hidg"); if (IS_ERR(hidg_class)) { status = PTR_ERR(hidg_class); hidg_class = NULL; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 4903d761a872..28db3e336e7d 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1512,7 +1512,7 @@ static int gprinter_setup(int count) int status; dev_t devt; - usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); + usb_gadget_class = class_create("usb_printer_gadget"); if (IS_ERR(usb_gadget_class)) { status = PTR_ERR(usb_gadget_class); usb_gadget_class = NULL; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index f259975dfba4..a366abb45623 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "u_ether.h" @@ -437,6 +438,20 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static int ether_wakeup_host(struct gether *port) +{ + int ret; + struct usb_function *func = &port->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (func->func_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + return ret; +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -456,6 +471,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, in = NULL; cdc_filter = 0; } + + if (dev->port_usb && dev->port_usb->is_suspend) { + DBG(dev, "Port suspended. Triggering wakeup\n"); + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->lock, flags); + ether_wakeup_host(dev->port_usb); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); if (!in) { @@ -942,6 +966,8 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) dev = netdev_priv(net); snprintf(host_addr, len, "%pm", dev->host_mac); + string_upper(host_addr, host_addr); + return strlen(host_addr); } EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc); @@ -1014,6 +1040,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); +void gether_suspend(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (atomic_read(&dev->tx_qlen)) { + /* + * There is a transfer in progress. So we trigger a remote + * wakeup to inform the host. + */ + ether_wakeup_host(dev->port_usb); + return; + } + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = true; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_suspend); + +void gether_resume(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (netif_queue_stopped(dev->net)) + netif_start_queue(dev->net); + + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = false; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_resume); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep @@ -1176,6 +1241,7 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; + link->is_suspend = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 40144546d1b0..851ee10d6e63 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -79,6 +79,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + bool is_suspend; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); +void gether_suspend(struct gether *link); +void gether_resume(struct gether *link); + /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); void gether_disconnect(struct gether *); diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index f102ec23f3af..4b3365f23fd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -32,8 +32,6 @@ # define ffs_dump_mem(prefix, ptr, len) do { } while (0) #endif /* VERBOSE_DEBUG */ -#define ENTER() pr_vdebug("%s()\n", __func__) - struct f_fs_opts; struct ffs_dev { diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 62b759bb7613..9bf0e985acfa 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); #undef UVCG_DEFAULT_PROCESSING_ATTR +static ssize_t uvcg_default_processing_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_processing_unit_descriptor *pd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + pd = &opts->uvc_processing; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > pd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + pd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { @@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_processing_attrs[] = { &uvcg_default_processing_attr_b_unit_id, @@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, #undef UVCG_DEFAULT_CAMERA_ATTR +static ssize_t uvcg_default_camera_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_camera_terminal_descriptor *cd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> + ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_camera_terminal; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > cd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + cd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { @@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_camera_attrs[] = { &uvcg_default_camera_attr_b_terminal_id, diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index ae6d8f7092b8..097854683e5b 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -180,8 +180,6 @@ static int __init gfs_init(void) int i; int ret = 0; - ENTER(); - if (func_num < 2) { gfs_single_func = true; func_num = 1; @@ -242,8 +240,6 @@ static void __exit gfs_exit(void) { int i; - ENTER(); - if (gfs_registered) usb_composite_unregister(&gfs_driver); gfs_registered = false; @@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev) #endif int ret, i; - ENTER(); - if (missing_funcs) return -ENODEV; #if defined CONFIG_USB_FUNCTIONFS_ETH @@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev) { int i; - ENTER(); - - #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function(f_rndis); usb_put_function_instance(fi_rndis); diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c index c80f9bd51b75..a36913ae31f9 100644 --- a/drivers/usb/gadget/udc/amd5536udc_pci.c +++ b/drivers/usb/gadget/udc/amd5536udc_pci.c @@ -170,6 +170,9 @@ static int udc_pci_probe( retval = -ENODEV; goto err_probe; } + + udc = dev; + return 0; err_probe: diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index ac3ca24f8b04..86398a04a012 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 4f3bc27c1c62..573109ca5b79 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index b4cf46249fea..e9aa74231760 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 56e55472daa1..148d7ec3ebf4 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index e2207d014620..a63e4af60a56 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 23b0629a8774..52e6d2e84e35 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -26,7 +26,7 @@ static DEFINE_IDA(gadget_id_numbers); -static struct bus_type gadget_bus_type; +static const struct bus_type gadget_bus_type; /** * struct usb_udc - describes one usb device controller @@ -513,6 +513,33 @@ out: } EXPORT_SYMBOL_GPL(usb_gadget_wakeup); +/** + * usb_gadget_set_remote_wakeup - configures the device remote wakeup feature. + * @gadget:the device being configured for remote wakeup + * @set:value to be configured. + * + * set to one to enable remote wakeup feature and zero to disable it. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set) +{ + int ret = 0; + + if (!gadget->ops->set_remote_wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_remote_wakeup(gadget, set); + +out: + trace_usb_gadget_set_remote_wakeup(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_remote_wakeup); + /** * usb_gadget_set_selfpowered - sets the device selfpowered feature. * @gadget:the device being declared as self-powered @@ -1747,7 +1774,7 @@ static int usb_udc_uevent(const struct device *dev, struct kobj_uevent_env *env) return 0; } -static struct bus_type gadget_bus_type = { +static const struct bus_type gadget_bus_type = { .name = "gadget", .probe = gadget_bind_driver, .remove = gadget_unbind_driver, @@ -1758,7 +1785,7 @@ static int __init usb_udc_init(void) { int rc; - udc_class = class_create(THIS_MODULE, "udc"); + udc_class = class_create("udc"); if (IS_ERR(udc_class)) { pr_err("failed to create udc class --> %ld\n", PTR_ERR(udc_class)); diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index ddf0ed3eb4f2..12c519f32bf7 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match); static struct spi_driver max3420_driver = { .driver = { .name = "max3420-udc", - .of_match_table = of_match_ptr(max3420_udc_of_match), + .of_match_table = max3420_udc_of_match, }, .probe = max3420_probe, .remove = max3420_remove, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index b397f3a848cf..08474c08d874 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2229,7 +2229,11 @@ static int mv_udc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&udc->status_req->queue); /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); + udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL); + if (!udc->status_req->req.buf) { + retval = -ENOMEM; + goto err_destroy_dma; + } udc->status_req->req.dma = DMA_ADDR_INVALID; udc->resume_state = USB_STATE_NOTATTACHED; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index bee6bceafc4f..aac8bc185afa 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -2661,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); + cancel_work_sync(&usb3->role_work); usb_role_switch_unregister(usb3->role_sw); usb_del_gadget_udc(&usb3->gadget); @@ -2781,13 +2781,6 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, } } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = { - .ramsize_per_ramif = SZ_16K, - .num_ramif = 2, - .ramsize_per_pipe = SZ_4K, - .workaround_for_vbus = true, -}; - static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 4, @@ -2829,14 +2822,6 @@ static const struct of_device_id usb3_of_match[] = { }; MODULE_DEVICE_TABLE(of, usb3_of_match); -static const struct soc_device_attribute renesas_usb3_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = &renesas_usb3_priv_r8a7795_es1, - }, - { /* sentinel */ } -}; - static const unsigned int renesas_usb3_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -2854,13 +2839,8 @@ static int renesas_usb3_probe(struct platform_device *pdev) struct renesas_usb3 *usb3; int irq, ret; const struct renesas_usb3_priv *priv; - const struct soc_device_attribute *attr; - attr = soc_device_match(renesas_usb3_quirks_match); - if (attr) - priv = attr->data; - else - priv = of_device_get_match_data(&pdev->dev); + priv = of_device_get_match_data(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -3039,7 +3019,7 @@ static struct platform_driver renesas_usb3_driver = { .driver = { .name = udc_name, .pm = &renesas_usb3_pm_ops, - .of_match_table = of_match_ptr(usb3_of_match), + .of_match_table = usb3_of_match, }, }; module_platform_driver(renesas_usb3_driver); diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c index cb23e62e8a87..84ac9fe4ce7f 100644 --- a/drivers/usb/gadget/udc/renesas_usbf.c +++ b/drivers/usb/gadget/udc/renesas_usbf.c @@ -545,17 +545,6 @@ static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset, usbf_ep_dma_reg_writel(ep, offset, tmp); } -static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset, - u32 clr, u32 set) -{ - u32 tmp; - - tmp = usbf_ep_dma_reg_readl(ep, offset); - tmp &= ~clr; - tmp |= set; - usbf_ep_dma_reg_writel(ep, offset, tmp); -} - static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1) { u32 set; diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c index 3c8bbf843038..589c7252e014 100644 --- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c +++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include @@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match); static struct platform_driver rzv2m_usb3drd_driver = { .driver = { .name = "rzv2m-usb3drd", - .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match), + .of_match_table = rzv2m_usb3drd_of_match, }, .probe = rzv2m_usb3drd_probe, .remove = rzv2m_usb3drd_remove, diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index 8bbb89c80348..0d3e705655b9 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -158,7 +158,7 @@ static int udc_plat_probe(struct platform_device *pdev) } /* Register for extcon if supported */ - if (of_get_property(dev->of_node, "extcon", NULL)) { + if (of_property_present(dev->of_node, "extcon")) { udc->edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(udc->edev)) { if (PTR_ERR(udc->edev) == -EPROBE_DEFER) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 2b71b33725f1..34e9c1df54c7 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2162,15 +2162,14 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget) static int tegra_xudc_gadget_vbus_draw(struct usb_gadget *gadget, unsigned int m_a) { - int ret = 0; struct tegra_xudc *xudc = to_xudc(gadget); dev_dbg(xudc->dev, "%s: %u mA\n", __func__, m_a); - if (xudc->curr_usbphy->chg_type == SDP_TYPE) - ret = usb_phy_set_power(xudc->curr_usbphy, m_a); + if (xudc->curr_usbphy && xudc->curr_usbphy->chg_type == SDP_TYPE) + return usb_phy_set_power(xudc->curr_usbphy, m_a); - return ret; + return 0; } static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on) diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index abdbcb1bacb0..a5ed26fbc2da 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -91,6 +91,11 @@ DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup, TP_ARGS(g, ret) ); +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_remote_wakeup, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered, TP_PROTO(struct usb_gadget *g, int ret), TP_ARGS(g, ret) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index eacb603ad1b2..c170672f847e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -622,33 +622,6 @@ config FHCI_DEBUG Say "y" to see some FHCI debug information and statistics through debugfs. -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB_FTDI_ELAN - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also - config USB_SL811_HCD tristate "SL811HS HCD support" depends on HAS_IOMEM diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5a13712f367d..be4e5245c52f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o -obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 62a0a193798c..b3aa464e9d2c 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -151,13 +151,13 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) of_node_put(np); } - if (of_get_property(dn, "big-endian", NULL)) { + if (of_property_read_bool(dn, "big-endian")) { ehci->big_endian_mmio = 1; ehci->big_endian_desc = 1; } - if (of_get_property(dn, "big-endian-regs", NULL)) + if (of_property_read_bool(dn, "big-endian-regs")) ehci->big_endian_mmio = 1; - if (of_get_property(dn, "big-endian-desc", NULL)) + if (of_property_read_bool(dn, "big-endian-desc")) ehci->big_endian_desc = 1; ehci->caps = hcd->regs; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 46c6a152b865..9db909d12354 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -200,19 +200,16 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) dev_data = get_dr_mode_data(np); if (of_device_is_compatible(np, "fsl-usb2-mph")) { - if (of_get_property(np, "port0", NULL)) + if (of_property_present(np, "port0")) pdata->port_enables |= FSL_USB2_PORT0_ENABLED; - if (of_get_property(np, "port1", NULL)) + if (of_property_present(np, "port1")) pdata->port_enables |= FSL_USB2_PORT1_ENABLED; pdata->operating_mode = FSL_USB2_MPH_HOST; } else { - if (of_get_property(np, "fsl,invert-drvvbus", NULL)) - pdata->invert_drvvbus = 1; - - if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) - pdata->invert_pwr_fault = 1; + pdata->invert_drvvbus = of_property_read_bool(np, "fsl,invert-drvvbus"); + pdata->invert_pwr_fault = of_property_read_bool(np, "fsl,invert-pwr-fault"); /* setup mode selected in the device tree */ pdata->operating_mode = dev_data->op_mode; diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 28d1524ee2fa..d152d72de126 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1951,7 +1951,7 @@ static struct spi_driver max3421_driver = { .remove = max3421_remove, .driver = { .name = "max3421-hcd", - .of_match_table = of_match_ptr(max3421_of_match_table), + .of_match_table = max3421_of_match_table, }, }; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 3a441310c713..f998d3f1a78a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -169,7 +169,7 @@ struct ehci_regs { #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ /* PORTSC: offset 0x44 */ - u32 port_status[0]; /* up to N_PORTS */ + u32 port_status[]; /* up to N_PORTS */ /* 31:23 reserved */ #define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index ef08d68b9714..2665832f9add 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -207,8 +207,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); static void usb_amd_find_chipset_info(void) { unsigned long flags; - struct amd_chipset_info info; - info.need_pll_quirk = false; + struct amd_chipset_info info = { }; spin_lock_irqsave(&amd_lock, flags); @@ -218,7 +217,6 @@ static void usb_amd_find_chipset_info(void) spin_unlock_irqrestore(&amd_lock, flags); return; } - memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); if (!amd_chipset_sb_type_init(&info)) { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c deleted file mode 100644 index 95240c9c45bd..000000000000 --- a/drivers/usb/host/u132-hcd.c +++ /dev/null @@ -1,3219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* -* Host Controller Driver for the Elan Digital Systems U132 adapter -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB host drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "ohci.h" -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); -MODULE_DESCRIPTION("U132 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -INT_MODULE_PARM(testing, 0); -/* Some boards misreport power switching/overcurrent*/ -static bool distrust_firmware = true; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent" - "t setup"); -static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); -/* -* u132_module_lock exists to protect access to global variables -* -*/ -static DEFINE_MUTEX(u132_module_lock); -static int u132_exiting; -static int u132_instances; -/* -* end of the global variables protected by u132_module_lock -*/ -static struct workqueue_struct *workqueue; -#define MAX_U132_PORTS 7 -#define MAX_U132_ADDRS 128 -#define MAX_U132_UDEVS 4 -#define MAX_U132_ENDPS 100 -#define MAX_U132_RINGS 4 -static const char *cc_to_text[16] = { - "No Error ", - "CRC Error ", - "Bit Stuff ", - "Data Togg ", - "Stall ", - "DevNotResp ", - "PIDCheck ", - "UnExpPID ", - "DataOver ", - "DataUnder ", - "(for hw) ", - "(for hw) ", - "BufferOver ", - "BuffUnder ", - "(for HCD) ", - "(for HCD) " -}; -struct u132_port { - struct u132 *u132; - int reset; - int enable; - int power; - int Status; -}; -struct u132_addr { - u8 address; -}; -struct u132_udev { - struct kref kref; - struct usb_device *usb_device; - u8 enumeration; - u8 udev_number; - u8 usb_addr; - u8 portnumber; - u8 endp_number_in[16]; - u8 endp_number_out[16]; -}; -#define ENDP_QUEUE_SHIFT 3 -#define ENDP_QUEUE_SIZE (1<platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -#define u132_write_pcimem(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -static inline struct u132 *udev_to_u132(struct u132_udev *udev) -{ - u8 udev_number = udev->udev_number; - return container_of(udev, struct u132, udev[udev_number]); -} - -static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) -{ - return (struct u132 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) -{ - return container_of((void *)u132, struct usb_hcd, hcd_priv); -} - -static inline void u132_disable(struct u132 *u132) -{ - u132_to_hcd(u132)->state = HC_STATE_HALT; -} - - -#define kref_to_u132(d) container_of(d, struct u132, kref) -#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) -#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) -#include "../misc/usb_u132.h" -static const char hcd_name[] = "u132_hcd"; -#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ - USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ - USB_PORT_STAT_C_RESET) << 16) -static void u132_hcd_delete(struct kref *kref) -{ - struct u132 *u132 = kref_to_u132(kref); - struct platform_device *pdev = u132->platform_dev; - struct usb_hcd *hcd = u132_to_hcd(u132); - u132->going += 1; - mutex_lock(&u132_module_lock); - u132_instances -= 1; - mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" - "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); - usb_put_hcd(hcd); -} - -static inline void u132_u132_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static inline void u132_u132_init_kref(struct u132 *u132) -{ - kref_init(&u132->kref); -} - -static void u132_udev_delete(struct kref *kref) -{ - struct u132_udev *udev = kref_to_u132_udev(kref); - udev->udev_number = 0; - udev->usb_device = NULL; - udev->usb_addr = 0; - udev->enumeration = 0; -} - -static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_put(&udev->kref, u132_udev_delete); -} - -static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_get(&udev->kref); -} - -static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) -{ - kref_init(&udev->kref); -} - -static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - if (delta > 0) { - if (queue_delayed_work(workqueue, &ring->scheduler, delta)) - return; - } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) - return; - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); -} - -static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) -{ - if (cancel_delayed_work(&ring->scheduler)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_endp_delete(struct kref *kref) -{ - struct u132_endp *endp = kref_to_u132_endp(kref); - struct u132 *u132 = endp->u132; - u8 usb_addr = endp->usb_addr; - u8 usb_endp = endp->usb_endp; - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - u8 endp_number = endp->endp_number; - struct usb_host_endpoint *hep = endp->hep; - struct u132_ring *ring = endp->ring; - struct list_head *head = &endp->endp_ring; - ring->length -= 1; - if (endp == ring->curr_endp) { - if (list_empty(head)) { - ring->curr_endp = NULL; - list_del(head); - } else { - struct u132_endp *next_endp = list_entry(head->next, - struct u132_endp, endp_ring); - ring->curr_endp = next_endp; - list_del(head); - } - } else - list_del(head); - if (endp->input) { - udev->endp_number_in[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - if (endp->output) { - udev->endp_number_out[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - u132->endp[endp_number - 1] = NULL; - hep->hcpriv = NULL; - kfree(endp); - u132_u132_put_kref(u132); -} - -static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_get(&endp->kref); -} - -static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) -{ - kref_init(&endp->kref); - kref_get(&u132->kref); -} - -static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) -{ - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); -} - -static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) -{ - if (cancel_delayed_work(&endp->scheduler)) - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_monitor_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) -{ - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_get(&u132->kref); -} - -static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) -{ - if (!queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_cancel_work(struct u132 *u132) -{ - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static int read_roothub_info(struct u132 *u132) -{ - u32 revision; - int retval; - retval = u132_read_pcimem(u132, revision, &revision); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } else if ((revision & 0xFF) == 0x10) { - } else if ((revision & 0xFF) == 0x11) { - } else { - dev_err(&u132->platform_dev->dev, "device revision is not valid" - " %08X\n", revision); - return -ENODEV; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.status, - &u132->hc_roothub_status); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.status\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.a\n", retval); - return retval; - } - { - int I = u132->num_ports; - int i = 0; - while (I-- > 0) { - retval = u132_read_pcimem(u132, roothub.portstatus[i], - &u132->hc_roothub_portstatus[i]); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d acc" - "essing device roothub.portstatus[%d]\n" - , retval, i); - return retval; - } else - i += 1; - } - } - return 0; -} - -static void u132_hcd_monitor_work(struct work_struct *work) -{ - struct u132 *u132 = container_of(work, struct u132, monitor.work); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - u132_monitor_put_kref(u132); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - u132_monitor_put_kref(u132); - return; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = read_roothub_info(u132); - if (retval) { - struct usb_hcd *hcd = u132_to_hcd(u132); - u132_disable(u132); - u132->going = 1; - mutex_unlock(&u132->sw_lock); - usb_hc_died(hcd); - ftdi_elan_gone_away(u132->platform_dev); - u132_monitor_put_kref(u132); - return; - } else { - u132_monitor_requeue_work(u132, 500); - mutex_unlock(&u132->sw_lock); - return; - } - } -} - -static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - struct u132_ring *ring; - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - u132_endp_put_kref(u132, endp); -} - -static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); -} - -static inline int edset_input(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_single(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_output(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - - -/* -* must not LOCK sw_lock -* -*/ -static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - if (urb->actual_length > 0) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - } else { - ring->in_use = 0; - endp->active = 0; - endp->jiffies = jiffies + - msecs_to_jiffies(urb->interval); - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - } - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 1 & toggle_bits); - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p givin" - "g back INTERRUPT %s\n", urb, - cc_to_text[condition_code]); - } - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - urb->actual_length += len; - endp->toggle_bits = toggle_bits; - if (urb->transfer_buffer_length > urb->actual_length) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - int retval; - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_DATAUNDERRUN) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" - ") giving back BULK IN %s\n", urb, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back B" - "ULK IN code=%d %s\n", urb, condition_code, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - if ((condition_code == TD_CC_NOERROR) || ((condition_code == - TD_DATAUNDERRUN) && ((urb->transfer_flags & - URB_SHORT_NOT_OK) == 0))) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0x3, - u132_hcd_configure_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, "giving back SETUP I" - "NPUT STALL urb %p\n", urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, "giving back SETUP IN" - "PUT %s urb %p\n", cc_to_text[condition_code], - urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - if (usb_pipein(urb->pipe)) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - u132->addr[0].address = 0; - endp->usb_addr = udev->usb_addr; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, 0, endp->usb_endp, 0, - u132_hcd_enumeration_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0x3, - u132_hcd_initial_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0, - u132_hcd_initial_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -/* -* this work function is only executed from the work queue -* -*/ -static void u132_hcd_ring_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring = - container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - mutex_lock(&u132->scheduler_lock); - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *endp, *last_endp = ring->curr_endp; - unsigned long wakeup = 0; - list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) { - if (endp->queue_next == endp->queue_last) { - } else if ((endp->delayed == 0) - || time_after_eq(jiffies, endp->jiffies)) { - ring->curr_endp = endp; - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - } - if (last_endp->queue_next == last_endp->queue_last) { - } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, - last_endp->jiffies)) { - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = last_endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - if (wakeup > 0) { - u132_ring_requeue_work(u132, ring, wakeup); - mutex_unlock(&u132->scheduler_lock); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } -} - -static void u132_hcd_endp_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring; - struct u132_endp *endp = - container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - if (endp->edset_flush) { - endp->edset_flush = 0; - if (endp->dequeueing) - usb_ftdi_elan_edset_flush(u132->platform_dev, - ring->number, endp); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->pipetype == PIPE_INTERRUPT) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else if (endp->pipetype == PIPE_CONTROL) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (address == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (endp->usb_addr == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - address = u132->addr[endp->usb_addr].address; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - if (endp->input) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_input(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } else { /* output pipe */ - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_output_sent); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } - } -} -#ifdef CONFIG_PM - -static void port_power(struct u132 *u132, int pn, int is_on) -{ - u132->port[pn].power = is_on; -} - -#endif - -static void u132_power(struct u132 *u132, int is_on) -{ - struct usb_hcd *hcd = u132_to_hcd(u132) - ; /* hub is inactive unless the port is powered */ - if (is_on) { - if (u132->power) - return; - u132->power = 1; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - } -} - -static int u132_periodic_reinit(struct u132 *u132) -{ - int retval; - u32 fi = u132->hc_fminterval & 0x03fff; - u32 fit; - u32 fminterval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - fit = fminterval & FIT; - retval = u132_write_pcimem(u132, fminterval, - (fit ^ FIT) | u132->hc_fminterval); - if (retval) - return retval; - return u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); -} - -static char *hcfs2string(int state) -{ - switch (state) { - case OHCI_USB_RESET: - return "reset"; - case OHCI_USB_RESUME: - return "resume"; - case OHCI_USB_OPER: - return "operational"; - case OHCI_USB_SUSPEND: - return "suspend"; - } - return "?"; -} - -static int u132_init(struct u132 *u132) -{ - int retval; - u32 control; - u132_disable(u132); - u132->next_statechange = jiffies; - retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (u132->num_ports == 0) { - u32 rh_a = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - u132->num_ports = rh_a & RH_A_NDP; - retval = read_roothub_info(u132); - if (retval) - return retval; - } - if (u132->num_ports > MAX_U132_PORTS) - return -EINVAL; - - return 0; -} - - -/* Start an OHCI controller, set the BUS operational -* resets USB and controller -* enable interrupts -*/ -static int u132_run(struct u132 *u132) -{ - int retval; - u32 control; - u32 status; - u32 fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int first = u132->hc_fminterval == 0; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - u132_disable(u132); - if (first) { - u32 temp; - retval = u132_read_pcimem(u132, fminterval, &temp); - if (retval) - return retval; - u132->hc_fminterval = temp & 0x3fff; - u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " - "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), - u132->hc_control); - switch (u132->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { - int temp; /* power down each port */ - for (temp = 0; temp < u132->num_ports; temp++) { - retval = u132_write_pcimem(u132, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; -retry: - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra: { - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, "USB HC reset" - " timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (u132->flags & OHCI_QUIRK_INITRESET) { - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, hcca, 0x00000000); - if (retval) - return retval; - retval = u132_periodic_reinit(u132); - if (retval) - return retval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - retval = u132_read_pcimem(u132, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(u132->flags & OHCI_QUIRK_INITRESET)) { - u132->flags |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" - "\n", fminterval, periodicstart); - } /* start controller operations */ - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrstatus, mask); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (u132->flags & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = u132_write_pcimem(u132, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - return 0; -} - -static void u132_hcd_stop(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" - "een removed %d\n", u132, hcd, u132->going); - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - } else { - mutex_lock(&u132->sw_lock); - msleep(100); - u132_power(u132, 0); - mutex_unlock(&u132->sw_lock); - } -} - -static int u132_hcd_start(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else if (hcd->self.controller) { - int retval; - struct platform_device *pdev = - to_platform_device(hcd->self.controller); - u16 vendor = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->vendor; - u16 device = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->device; - mutex_lock(&u132->sw_lock); - msleep(10); - if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { - u132->flags = OHCI_QUIRK_AMD756; - } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" - "ounds unavailable\n"); - } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) - u132->flags |= OHCI_QUIRK_ZFMICRO; - retval = u132_run(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - msleep(100); - mutex_unlock(&u132->sw_lock); - return retval; - } else { - dev_err(&u132->platform_dev->dev, "platform_device missing\n"); - return -ENODEV; - } -} - -static int u132_hcd_reset(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = u132_init(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); - return 0; -} - -static int queue_int_on_old_endpoint(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - int ring_number; - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - ring_number = 3; - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - ring_number = 2; - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - ring = endp->ring = &u132->ring[ring_number - 1]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - urb->hcpriv = u132; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; -} - -static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_control(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - u132_endp_init_kref(u132, endp); - u132_endp_get_kref(u132, endp); - if (usb_addr == 0) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_init_kref(u132, udev); - u132_udev_get_kref(u132, udev); - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_get_kref(u132, udev); - udev->enumeration = 2; - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } -} - -static int queue_control_on_old_endpoint(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp) -{ - if (usb_addr == 0) { - if (usb_pipein(urb->pipe)) { - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } else { /* usb_pipeout(urb->pipe) */ - struct u132_addr *addr = &u132->addr[usb_dev->devnum]; - int I = MAX_U132_UDEVS; - int i = 0; - while (--I > 0) { - struct u132_udev *udev = &u132->udev[++i]; - if (udev->usb_device) { - continue; - } else { - udev->enumeration = 1; - u132->addr[0].address = i; - endp->udev_number = i; - udev->udev_number = i; - udev->usb_addr = usb_dev->devnum; - u132_udev_init_kref(u132, udev); - udev->endp_number_in[usb_endp] = - endp->endp_number; - u132_udev_get_kref(u132, udev); - udev->endp_number_out[usb_endp] = - endp->endp_number; - udev->usb_device = usb_dev; - ((u8 *) (urb->setup_packet))[2] = - addr->address = i; - u132_udev_get_kref(u132, udev); - break; - } - } - if (I == 0) { - dev_err(&u132->platform_dev->dev, "run out of d" - "evice space\n"); - return -EINVAL; - } - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - urb->hcpriv = u132; - if (udev->enumeration != 2) - udev->enumeration = 2; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } -} - -static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (irqs_disabled()) { - if (gfpflags_allow_blocking(mem_flags)) { - printk(KERN_ERR "invalid context for function that might sleep\n"); - return -EINVAL; - } - } - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - return -ESHUTDOWN; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - struct usb_device *usb_dev = urb->dev; - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_int_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, - msecs_to_jiffies(urb->interval)) - ; - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { /*(endp == NULL) */ - return create_endpoint_and_queue_int(u132, udev, - urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, "the hardware does no" - "t support PIPE_ISOCHRONOUS\n"); - return -EINVAL; - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_bulk_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_bulk(u132, - udev, urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } else { - struct u132_endp *endp = urb->ep->hcpriv; - u16 urb_size = 8; - u8 *b = urb->setup_packet; - int i = 0; - char data[30 * 3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_control_on_old_endpoint( - u132, urb, usb_dev, - endp, usb_addr, - usb_endp); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_control(u132, - urb, usb_dev, usb_addr, usb_endp, - mem_flags); - } - } -} - -static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct u132_urbq *urbq; - - list_for_each_entry(urbq, &endp->urb_more, urb_more) { - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(&urbq->urb_more); - endp->queue_size -= 1; - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } - } - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" - "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" - "\n", urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - return -EINVAL; -} - -static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - int rc; - - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return rc; - } - if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" - "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } - if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { - if (endp->active) { - endp->dequeueing = 1; - endp->edset_flush = 1; - u132_endp_queue_work(u132, endp, 0); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return 0; - } else { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, status); - return 0; - } - } else { - u16 queue_list = 0; - u16 queue_size = endp->queue_size; - u16 queue_scan = endp->queue_next; - struct urb **urb_slot = NULL; - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - if (urb == endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]) { - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - break; - } - } - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]; - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - } - if (urb_slot) { - struct usb_hcd *hcd = u132_to_hcd(u132); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_size -= 1; - if (list_empty(&endp->urb_more)) { - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, - struct u132_urbq, urb_more); - list_del(next); - *urb_slot = urbq->urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - kfree(urbq); - } - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, status); - return 0; - } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in " - "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" - "=%d size=%d next=%04X last=%04X\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', - endp->output ? 'O' : ' ', endp->usb_endp, - endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } else { - int retval; - - usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); - retval = dequeue_from_overflow_chain(u132, endp, - urb); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return retval; - } - } -} - -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - if (usb_pipein(urb->pipe)) { - u8 endp_number = udev->endp_number_in[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } else { - u8 endp_number = udev->endp_number_out[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } - } -} - -static void u132_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" - ") has been removed %d\n", u132, hcd, hep, - u132->going); - } else { - struct u132_endp *endp = hep->hcpriv; - if (endp) - u132_endp_put_kref(u132, endp); - } -} - -static int u132_get_frame(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - mdelay(100); - return 0; - } -} - -static int u132_roothub_descriptor(struct u132 *u132, - struct usb_hub_descriptor *desc) -{ - int retval; - u16 temp; - u32 rh_a = -1; - u32 rh_b = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - desc->bDescriptorType = USB_DT_HUB; - desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = u132->num_ports; - temp = 1 + (u132->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM; - if (rh_a & RH_A_NPS) - temp |= HUB_CHAR_NO_LPSM; - if (rh_a & RH_A_PSM) - temp |= HUB_CHAR_INDV_PORT_LPSM; - if (rh_a & RH_A_NOCP) - temp |= HUB_CHAR_NO_OCPM; - else if (rh_a & RH_A_OCPM) - temp |= HUB_CHAR_INDV_PORT_OCPM; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else - desc->u.hs.DeviceRemovable[1] = 0xff; - return 0; -} - -static int u132_roothub_status(struct u132 *u132, __le32 *desc) -{ - u32 rh_status = -1; - int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); - *desc = cpu_to_le32(rh_status); - return ret_status; -} - -static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port = wIndex - 1; - u32 rh_portstatus = -1; - int ret_portstatus = u132_read_pcimem(u132, - roothub.portstatus[port], &rh_portstatus); - *desc = cpu_to_le32(rh_portstatus); - if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, "Port %d Status Chan" - "ge = %08X\n", port, *desc); - } - return ret_portstatus; - } -} - - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 -#define PORT_RESET_MSEC 10 -/* wrap-aware logic morphed from */ -#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -static int u132_roothub_portreset(struct u132 *u132, int port_index) -{ - int retval; - u32 fmnumber; - u16 now; - u16 reset_done; - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - reset_done = now + PORT_RESET_MSEC; - do { - u32 portstat; - do { - retval = u132_read_pcimem(u132, - roothub.portstatus[port_index], &portstat); - if (retval) - return retval; - if (RH_PS_PRS & portstat) - continue; - else - break; - } while (tick_before(now, reset_done)); - if (RH_PS_PRS & portstat) - return -ENODEV; - if (RH_PS_CCS & portstat) { - if (RH_PS_PRSC & portstat) { - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], - RH_PS_PRSC); - if (retval) - return retval; - } - } else - break; /* start the next reset, - sleep till it's probably done */ - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - RH_PS_PRS); - if (retval) - return retval; - msleep(PORT_RESET_HW_MSEC); - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - } while (tick_before(now, reset_done)); - return 0; -} - -static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - case USB_PORT_FEAT_POWER: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - case USB_PORT_FEAT_RESET: - return u132_roothub_portreset(u132, port_index); - default: - return -EPIPE; - } - } -} - -static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - u32 temp; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - if ((u132->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, "TODO resume_" - "root_hub\n"); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - return -EPIPE; - } - return u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - } -} - - -/* the virtual root hub timer IRQ checks for hub status*/ -static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" - "ed %d\n", hcd, u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - return -ESHUTDOWN; - } else { - int i, changed = 0, length = 1; - if (u132->flags & OHCI_QUIRK_AMD756) { - if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, "bogus NDP, r" - "ereads as NDP=%d\n", - u132->hc_roothub_a & RH_A_NDP); - goto done; - } - } - if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - if (u132->num_ports > 7) { - buf[1] = 0; - length++; - } - for (i = 0; i < u132->num_ports; i++) { - if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | - RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | - RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - continue; - } - if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) - continue; - - if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) - continue; - } -done: - return changed ? length : 0; - } -} - -static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - mutex_lock(&u132->sw_lock); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case ClearPortFeature:{ - retval = u132_roothub_clearportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - case GetHubDescriptor:{ - retval = u132_roothub_descriptor(u132, - (struct usb_hub_descriptor *)buf); - if (retval) - goto error; - break; - } - case GetHubStatus:{ - retval = u132_roothub_status(u132, - (__le32 *) buf); - if (retval) - goto error; - break; - } - case GetPortStatus:{ - retval = u132_roothub_portstatus(u132, - (__le32 *) buf, wIndex); - if (retval) - goto error; - break; - } - case SetPortFeature:{ - retval = u132_roothub_setportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - default: - goto stall; - error: - u132_disable(u132); - u132->going = 1; - break; - stall: - retval = -EPIPE; - break; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - - -#ifdef CONFIG_PM -static int u132_bus_suspend(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -static int u132_bus_resume(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -#else -#define u132_bus_suspend NULL -#define u132_bus_resume NULL -#endif -static const struct hc_driver u132_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct u132), - .irq = NULL, - .flags = HCD_USB11 | HCD_MEMORY, - .reset = u132_hcd_reset, - .start = u132_hcd_start, - .stop = u132_hcd_stop, - .urb_enqueue = u132_urb_enqueue, - .urb_dequeue = u132_urb_dequeue, - .endpoint_disable = u132_endpoint_disable, - .get_frame_number = u132_get_frame, - .hub_status_data = u132_hub_status_data, - .hub_control = u132_hub_control, - .bus_suspend = u132_bus_suspend, - .bus_resume = u132_bus_resume, - .start_port_reset = u132_start_port_reset, -}; - -/* -* This function may be called by the USB core whilst the "usb_all_devices_rwsem" -* is held for writing, thus this module must not call usb_remove_hcd() -* synchronously - but instead should immediately stop activity to the -* device and asynchronously call usb_remove_hcd() -*/ -static int u132_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - if (hcd) { - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, "already being remove" - "d\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, "removing device u132" - ".%d\n", u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } - while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } - } else - return 0; -} - -static void u132_initialise(struct u132 *u132, struct platform_device *pdev) -{ - int rings = MAX_U132_RINGS; - int ports = MAX_U132_PORTS; - int addrs = MAX_U132_ADDRS; - int udevs = MAX_U132_UDEVS; - int endps = MAX_U132_ENDPS; - u132->board = dev_get_platdata(&pdev->dev); - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - mutex_init(&u132->scheduler_lock); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - ring->u132 = u132; - ring->number = rings + 1; - ring->length = 0; - ring->curr_endp = NULL; - INIT_DELAYED_WORK(&ring->scheduler, - u132_hcd_ring_work_scheduler); - } - mutex_lock(&u132->sw_lock); - INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); - while (ports-- > 0) { - struct u132_port *port = &u132->port[ports]; - port->u132 = u132; - port->reset = 0; - port->enable = 0; - port->power = 0; - port->Status = 0; - } - while (addrs-- > 0) { - struct u132_addr *addr = &u132->addr[addrs]; - addr->address = 0; - } - while (udevs-- > 0) { - struct u132_udev *udev = &u132->udev[udevs]; - int i = ARRAY_SIZE(udev->endp_number_in); - int o = ARRAY_SIZE(udev->endp_number_out); - udev->usb_device = NULL; - udev->udev_number = 0; - udev->usb_addr = 0; - udev->portnumber = 0; - while (i-- > 0) - udev->endp_number_in[i] = 0; - - while (o-- > 0) - udev->endp_number_out[o] = 0; - - } - while (endps-- > 0) - u132->endp[endps] = NULL; - - mutex_unlock(&u132->sw_lock); -} - -static int u132_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - - msleep(100); - if (u132_exiting > 0) - return -ENODEV; - - retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); - if (retval) - return retval; - - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - struct u132 *u132 = hcd_to_u132(hcd); - retval = 0; - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - u132->sequence_num = ++u132_instances; - mutex_unlock(&u132_module_lock); - u132_u132_init_kref(u132); - u132_initialise(u132, pdev); - hcd->product_desc = "ELAN U132 Host Controller"; - retval = usb_add_hcd(hcd, 0, 0); - if (retval != 0) { - dev_err(&u132->platform_dev->dev, "init error %d\n", - retval); - u132_u132_put_kref(u132); - return retval; - } else { - device_wakeup_enable(hcd->self.controller); - u132_monitor_queue_work(u132, 100); - return 0; - } - } -} - - -#ifdef CONFIG_PM -/* - * for this device there's no useful distinction between the controller - * and its root hub. - */ -static int u132_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0, ports; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = u132_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 0); - } - break; - } - return retval; - } -} - -static int u132_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - if (!u132->port[0].power) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - retval = u132_bus_resume(hcd); - } - return retval; - } -} - -#else -#define u132_suspend NULL -#define u132_resume NULL -#endif -/* -* this driver is loaded explicitly by ftdi_u132 -* -* the platform_driver struct is static because it is per type of module -*/ -static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = u132_remove, - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = hcd_name, - }, -}; -static int __init u132_hcd_init(void) -{ - int retval; - u132_instances = 0; - u132_exiting = 0; - if (usb_disabled()) - return -ENODEV; - workqueue = create_singlethread_workqueue("u132"); - if (!workqueue) - return -ENOMEM; - retval = platform_driver_register(&u132_platform_driver); - if (retval) - destroy_workqueue(workqueue); - - return retval; -} - - -module_init(u132_hcd_init); -static void __exit u132_hcd_exit(void) -{ - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - destroy_workqueue(workqueue); -} - - -module_exit(u132_hcd_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:u132_hcd"); diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 3592f757fe05..7bd2fddde770 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -119,11 +119,13 @@ static int uhci_pci_init(struct usb_hcd *hcd) uhci->rh_numports = uhci_count_ports(hcd); - /* Intel controllers report the OverCurrent bit active on. - * VIA controllers report it active off, so we'll adjust the - * bit value. (It's not standardized in the UHCI spec.) + /* + * Intel controllers report the OverCurrent bit active on. VIA + * and ZHAOXIN controllers report it active off, so we'll adjust + * the bit value. (It's not standardized in the UHCI spec.) */ - if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA) + if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA || + to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_ZHAOXIN) uhci->oc_low = 1; /* HP's server management chip requires a longer port reset delay. */ diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index f1367b53b260..b40d9238d447 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -124,10 +124,10 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) /* Set DbC context and info registers: */ lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); - dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); + dev_info = (dbc->idVendor << 16) | dbc->bInterfaceProtocol; writel(dev_info, &dbc->regs->devinfo1); - dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID); + dev_info = (dbc->bcdDevice << 16) | dbc->idProduct; writel(dev_info, &dbc->regs->devinfo2); } @@ -971,7 +971,186 @@ static ssize_t dbc_store(struct device *dev, return count; } +static ssize_t dbc_idVendor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idVendor); +} + +static ssize_t dbc_idVendor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u16 value; + u32 dev_info; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idVendor = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_idProduct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idProduct); +} + +static ssize_t dbc_idProduct_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idProduct = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu)) | value; + writel(dev_info, ptr); + return size; +} + +static ssize_t dbc_bcdDevice_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->bcdDevice); +} + +static ssize_t dbc_bcdDevice_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bcdDevice = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_bInterfaceProtocol_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol); +} + +static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u8 value; + int ret; + + /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */ + ret = kstrtou8(buf, 0, &value); + if (ret || value > 1) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bInterfaceProtocol = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffu)) | value; + writel(dev_info, ptr); + + return size; +} + static DEVICE_ATTR_RW(dbc); +static DEVICE_ATTR_RW(dbc_idVendor); +static DEVICE_ATTR_RW(dbc_idProduct); +static DEVICE_ATTR_RW(dbc_bcdDevice); +static DEVICE_ATTR_RW(dbc_bInterfaceProtocol); + +static struct attribute *dbc_dev_attributes[] = { + &dev_attr_dbc.attr, + &dev_attr_dbc_idVendor.attr, + &dev_attr_dbc_idProduct.attr, + &dev_attr_dbc_bcdDevice.attr, + &dev_attr_dbc_bInterfaceProtocol.attr, + NULL +}; + +static const struct attribute_group dbc_dev_attrib_grp = { + .attrs = dbc_dev_attributes, +}; struct xhci_dbc * xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver) @@ -986,6 +1165,10 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->regs = base; dbc->dev = dev; dbc->driver = driver; + dbc->idProduct = DBC_PRODUCT_ID; + dbc->idVendor = DBC_VENDOR_ID; + dbc->bcdDevice = DBC_DEVICE_REV; + dbc->bInterfaceProtocol = DBC_PROTOCOL; if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) goto err; @@ -993,7 +1176,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); - ret = device_create_file(dev, &dev_attr_dbc); + ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp); if (ret) goto err; @@ -1012,7 +1195,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc) xhci_dbc_stop(dbc); /* remove sysfs files */ - device_remove_file(dbc->dev, &dev_attr_dbc); + sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp); kfree(dbc); } diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index ca04192fdab1..51a7ab3ba0ca 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -132,6 +132,10 @@ struct xhci_dbc { struct dbc_str_descs *string; dma_addr_t string_dma; size_t string_size; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 bInterfaceProtocol; enum dbc_state state; struct delayed_work event_work; diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 0bc7fe11f749..99baa60ef50f 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -133,6 +133,7 @@ static void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base, regset->regs = regs; regset->nregs = nregs; regset->base = hcd->regs + base; + regset->dev = hcd->self.controller; debugfs_create_regset32((const char *)rgs->name, 0444, parent, regset); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d0a9467aa5fc..7e106bd804ca 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -543,14 +544,11 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; if (size > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(dev, size, - stream_ctx, dma); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_free(xhci->small_streams_pool, - stream_ctx, dma); + dma_free_coherent(dev, size, stream_ctx, dma); + else if (size > SMALL_STREAM_ARRAY_SIZE) + dma_pool_free(xhci->medium_streams_pool, stream_ctx, dma); else - return dma_pool_free(xhci->medium_streams_pool, - stream_ctx, dma); + dma_pool_free(xhci->small_streams_pool, stream_ctx, dma); } /* @@ -568,17 +566,14 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, gfp_t mem_flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; + size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(dev, size, - dma, mem_flags); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_alloc(xhci->small_streams_pool, - mem_flags, dma); + return dma_alloc_coherent(dev, size, dma, mem_flags); + if (size > SMALL_STREAM_ARRAY_SIZE) + return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma); else - return dma_pool_alloc(xhci->medium_streams_pool, - mem_flags, dma); + return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma); } struct xhci_ring *xhci_dma_to_transfer_ring( @@ -612,8 +607,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, int ret; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - xhci_dbg(xhci, "Allocating %u streams and %u " - "stream context array entries.\n", + xhci_dbg(xhci, "Allocating %u streams and %u stream context array entries.\n", num_streams, num_stream_ctxs); if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); @@ -642,8 +636,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, mem_flags); if (!stream_info->stream_ctx_array) goto cleanup_ring_array; - memset(stream_info->stream_ctx_array, 0, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs); /* Allocate everything needed to free the stream rings later */ stream_info->free_streams_command = @@ -673,8 +665,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_ring->cycle_state; stream_info->stream_ctx_array[cur_stream].stream_ring = cpu_to_le64(addr); - xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", - cur_stream, (unsigned long long) addr); + xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr); ret = xhci_update_stream_mapping(cur_ring, mem_flags); if (ret) { @@ -984,16 +975,14 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, if (!dev->out_ctx) goto fail; - xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->out_ctx->dma); + xhci_dbg(xhci, "Slot %d output ctx = 0x%pad (dma)\n", slot_id, &dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; - xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->in_ctx->dma); + xhci_dbg(xhci, "Slot %d input ctx = 0x%pad (dma)\n", slot_id, &dev->in_ctx->dma); /* Initialize the cancellation and bandwidth list for each ep */ for (i = 0; i < 31; i++) { @@ -1400,8 +1389,9 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev, if ((udev->speed >= USB_SPEED_SUPER_PLUS) && USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ - else if (udev->speed >= USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER) return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); max_packet = usb_endpoint_maxp(&ep->desc); @@ -1660,7 +1650,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) goto fail_sp; xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - num_sp * sizeof(u64), + size_mul(sizeof(u64), num_sp), &xhci->scratchpad->sp_dma, flags); if (!xhci->scratchpad->sp_array) goto fail_sp2; @@ -1685,11 +1675,10 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) return 0; fail_sp4: - for (i = i - 1; i >= 0; i--) { + while (i--) dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_array[i]); - } kfree(xhci->scratchpad->sp_buffers); @@ -1799,7 +1788,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_segment *seg; struct xhci_erst_entry *entry; - size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; + size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs); erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, size, &erst->erst_dma_addr, flags); if (!erst->entries) @@ -1830,7 +1819,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) if (!ir) return; - erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries); + erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; if (ir->erst.entries) dma_free_coherent(dev, erst_size, ir->erst.entries, @@ -1960,8 +1949,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, ir->event_ring->dequeue); if (!deq) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; @@ -1970,8 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter */ temp &= ~ERST_EHB; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write event ring dequeue pointer, " - "preserving EHB bit"); + "// Write event ring dequeue pointer, preserving EHB bit"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &ir->ir_set->erst_dequeue); } @@ -2004,8 +1991,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { - xhci_warn(xhci, "Ignoring unknown port speed, " - "Ext Cap %p, revision = 0x%x\n", + xhci_warn(xhci, "Ignoring unknown port speed, Ext Cap %p, revision = 0x%x\n", addr, major_revision); /* Ignoring port protocol we can't understand. FIXME */ return; @@ -2020,9 +2006,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x", - addr, port_offset, port_count, major_revision); + "Ext Cap %p, port offset = %u, count = %u, revision = 0x%x", + addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ @@ -2079,10 +2064,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, struct xhci_port *hw_port = &xhci->hw_ports[i]; /* Duplicate entry. Ignore the port if the revisions differ. */ if (hw_port->rhub) { - xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," - " port %u\n", addr, i); - xhci_warn(xhci, "Port was marked as USB %u, " - "duplicated as USB %u\n", + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p, port %u\n", addr, i); + xhci_warn(xhci, "Port was marked as USB %u, duplicated as USB %u\n", hw_port->rhub->maj_rev, major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. @@ -2358,8 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci->dcbaa->dma = dma; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Device context base array address = 0x%llx (DMA), %p (virt)", - (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); + "// Device context base array address = 0x%pad (DMA), %p (virt)", + &xhci->dcbaa->dma, xhci->dcbaa); xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* @@ -2400,8 +2383,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx", - (unsigned long long)xhci->cmd_ring->first_seg->dma); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", + &xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); @@ -2421,8 +2404,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) val = readl(&xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Doorbell array is located at offset 0x%x" - " from cap regs base addr", val); + "// Doorbell array is located at offset 0x%x from cap regs base addr", + val); xhci->dba = (void __iomem *) xhci->cap_regs + val; /* Set ir_set to interrupt register set 0 */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index f7cbb08fc506..90cf40d6d0c3 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -398,6 +398,7 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) clks[2].id = "ref_ck"; clks[3].id = "mcu_ck"; clks[4].id = "dma_ck"; + clks[5].id = "frmcnt_ck"; return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks); } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 1174a510dd38..faaaf05e36ce 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -15,7 +15,7 @@ #include "xhci.h" -#define BULK_CLKS_NUM 5 +#define BULK_CLKS_NUM 6 #define BULK_VREGS_NUM 2 /* support at most 64 ep, use 32 size hash table */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 6db07ca419c3..79b3691f373f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-trace.h" @@ -78,14 +79,207 @@ static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; static int xhci_pci_setup(struct usb_hcd *hcd); +static int xhci_pci_run(struct usb_hcd *hcd); static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .reset = xhci_pci_setup, + .start = xhci_pci_run, .update_hub_device = xhci_pci_update_hub_device, }; +static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + + if (hcd->msix_enabled) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int i; + + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(pci_irq_vector(pdev, i)); + } +} + +/* Free any IRQs and disable MSI-X */ +static void xhci_cleanup_msix(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (xhci->quirks & XHCI_PLAT) + return; + + /* return if using legacy interrupt */ + if (hcd->irq > 0) + return; + + if (hcd->msix_enabled) { + int i; + + for (i = 0; i < xhci->msix_count; i++) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + } else { + free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); + } + + pci_free_irq_vectors(pdev); + hcd->msix_enabled = 0; +} + +/* + * Set up MSI + */ +static int xhci_setup_msi(struct xhci_hcd *xhci) +{ + int ret; + /* + * TODO:Check with MSI Soc for sysdev + */ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate MSI entry"); + return ret; + } + + ret = request_irq(pdev->irq, xhci_msi_irq, + 0, "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "disable MSI interrupt"); + pci_free_irq_vectors(pdev); + } + + return ret; +} + +/* + * Set up MSI-X + */ +static int xhci_setup_msix(struct xhci_hcd *xhci) +{ + int i, ret; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * calculate number of msi-x vectors supported. + * - HCS_MAX_INTRS: the max number of interrupts the host can handle, + * with max number of interrupters based on the xhci HCSPARAMS1. + * - num_online_cpus: maximum msi-x vectors per CPUs core. + * Add additional 1 vector to ensure always available interrupt. + */ + xhci->msix_count = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); + + ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, + PCI_IRQ_MSIX); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Failed to enable MSI-X"); + return ret; + } + + for (i = 0; i < xhci->msix_count; i++) { + ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, + "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) + goto disable_msix; + } + + hcd->msix_enabled = 1; + return ret; + +disable_msix: + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); + while (--i >= 0) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + pci_free_irq_vectors(pdev); + return ret; +} + +static int xhci_try_enable_msi(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev; + int ret; + + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + /* + * Some Fresco Logic host controllers advertise MSI, but fail to + * generate interrupts. Don't even try to enable MSI. + */ + if (xhci->quirks & XHCI_BROKEN_MSI) + goto legacy_irq; + + /* unregister the legacy interrupt */ + if (hcd->irq) + free_irq(hcd->irq, hcd); + hcd->irq = 0; + + ret = xhci_setup_msix(xhci); + if (ret) + /* fall back to msi*/ + ret = xhci_setup_msi(xhci); + + if (!ret) { + hcd->msi_enabled = 1; + return 0; + } + + if (!pdev->irq) { + xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); + return -EINVAL; + } + + legacy_irq: + if (!strlen(hcd->irq_descr)) + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", + hcd->driver->description, hcd->self.busnum); + + /* fall back to legacy interrupt*/ + ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, + hcd->irq_descr, hcd); + if (ret) { + xhci_err(xhci, "request interrupt %d failed\n", + pdev->irq); + return ret; + } + hcd->irq = pdev->irq; + return 0; +} + +static int xhci_pci_run(struct usb_hcd *hcd) +{ + int ret; + + if (usb_hcd_is_primary_hcd(hcd)) { + ret = xhci_try_enable_msi(hcd); + if (ret) + return ret; + } + + return xhci_run(hcd); +} + +static void xhci_pci_stop(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + xhci_stop(hcd); + + if (usb_hcd_is_primary_hcd(hcd)) + xhci_cleanup_msix(xhci); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -194,7 +388,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_RENOIR_XHCI) - xhci->quirks |= XHCI_BROKEN_D3COLD; + xhci->quirks |= XHCI_BROKEN_D3COLD_S2I; if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; @@ -535,7 +729,6 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_hcd_pci_remove(dev); } -#ifdef CONFIG_PM /* * In some Intel xHCI controllers, in order to get D3 working, * through a vendor specific SSIC CONFIG register at offset 0x883c, @@ -609,9 +802,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * Systems with the TI redriver that loses port status change events * need to have the registers polled during D3, so avoid D3cold. */ - if (xhci->quirks & (XHCI_COMP_MODE_QUIRK | XHCI_BROKEN_D3COLD)) + if (xhci->quirks & XHCI_COMP_MODE_QUIRK) pci_d3cold_disable(pdev); +#ifdef CONFIG_SUSPEND + /* d3cold is broken, but only when s2idle is used */ + if (pm_suspend_target_state == PM_SUSPEND_TO_IDLE && + xhci->quirks & (XHCI_BROKEN_D3COLD_S2I)) + pci_d3cold_disable(pdev); +#endif + if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_quirk(hcd); @@ -622,6 +822,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) xhci_sparse_control_quirk(hcd); ret = xhci_suspend(xhci, do_wakeup); + + /* synchronize irq when using MSI-X */ + xhci_msix_sync_irqs(xhci); + if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED)) xhci_ssic_port_unused_quirk(hcd, false); @@ -724,12 +928,12 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); xhci_shutdown(hcd); + xhci_cleanup_msix(xhci); /* Yet another workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) pci_set_power_state(pdev, PCI_D3hot); } -#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -771,22 +975,19 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM .driver = { - .pm = &usb_hcd_pci_pm_ops + .pm = pm_ptr(&usb_hcd_pci_pm_ops), }, -#endif }; static int __init xhci_pci_init(void) { xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides); -#ifdef CONFIG_PM - xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend; - xhci_pci_hc_driver.pci_resume = xhci_pci_resume; - xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late; - xhci_pci_hc_driver.shutdown = xhci_pci_shutdown; -#endif + xhci_pci_hc_driver.pci_suspend = pm_ptr(xhci_pci_suspend); + xhci_pci_hc_driver.pci_resume = pm_ptr(xhci_pci_resume); + xhci_pci_hc_driver.pci_poweroff_late = pm_ptr(xhci_pci_poweroff_late); + xhci_pci_hc_driver.shutdown = pm_ptr(xhci_pci_shutdown); + xhci_pci_hc_driver.stop = xhci_pci_stop; return pci_register_driver(&xhci_pci_driver); } module_init(xhci_pci_init); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b9f9625467d6..b0c8e8efc43b 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -291,6 +291,21 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s goto dealloc_usb2_hcd; } + xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, + "usb-phy", 1); + if (IS_ERR(xhci->shared_hcd->usb_phy)) { + if (PTR_ERR(xhci->shared_hcd->usb_phy) != -ENODEV) + dev_err(sysdev, "%s get usb3phy fail (ret=%d)\n", + __func__, + (int)PTR_ERR(xhci->shared_hcd->usb_phy)); + xhci->shared_hcd->usb_phy = NULL; + } else { + ret = usb_phy_init(xhci->shared_hcd->usb_phy); + if (ret) + dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", + __func__, ret); + } + xhci->shared_hcd->tpl_support = hcd->tpl_support; } @@ -362,10 +377,8 @@ static int xhci_generic_plat_probe(struct platform_device *pdev) if (is_of_node(sysdev->fwnode) || is_acpi_device_node(sysdev->fwnode)) break; -#ifdef CONFIG_PCI - else if (sysdev->bus == &pci_bus_type) + else if (dev_is_pci(sysdev)) break; -#endif } if (!sysdev) diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 7f18509a1d39..ad966b797b89 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -12,26 +12,22 @@ #include #include #include -#include #include "xhci.h" #include "xhci-plat.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" -#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem" #define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem" /* -* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x) -* - The V2 firmware is for r8a7795 ES1.x. +* - The V3 firmware is for all R-Car Gen3 * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * performance degradation. So, this driver continues to use the V1 if R-Car * Gen2. * - The V1 firmware is impossible to use on R-Car Gen3. */ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1); -MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); /*** Register Offset ***/ @@ -78,18 +74,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); #define RCAR_USB3_RX_POL_VAL BIT(21) #define RCAR_USB3_TX_POL_VAL BIT(4) -/* For soc_device_attribute */ -#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ -#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */ - -static const struct soc_device_attribute rcar_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = (void *)RCAR_XHCI_FIRMWARE_V2, - }, - { /* sentinel */ } -}; - static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ @@ -135,9 +119,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) const struct firmware *fw; int retval, index, j; u32 data, val, temp; - u32 quirks = 0; - const struct soc_device_attribute *attr; - const char *firmware_name; /* * According to the datasheet, "Upon the completion of FW Download, @@ -146,19 +127,8 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) if (readl(regs + RCAR_USB3_DL_CTRL) & RCAR_USB3_DL_CTRL_FW_SUCCESS) return 0; - attr = soc_device_match(rcar_quirks_match); - if (attr) - quirks = (uintptr_t)attr->data; - - if (quirks & RCAR_XHCI_FIRMWARE_V2) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; - else if (quirks & RCAR_XHCI_FIRMWARE_V3) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; - else - firmware_name = priv->firmware_name; - /* request R-Car USB3.0 firmware */ - retval = request_firmware(&fw, firmware_name, dev); + retval = request_firmware(&fw, priv->firmware_name, dev); if (retval) return retval; @@ -312,7 +282,7 @@ static struct platform_driver usb_xhci_renesas_driver = { .driver = { .name = "xhci-renesas-hcd", .pm = &xhci_plat_pm_ops, - .of_match_table = of_match_ptr(usb_xhci_of_match), + .of_match_table = usb_xhci_of_match, }, }; module_platform_driver(usb_xhci_renesas_driver); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index eb788c60c1c0..2bc82b3a2f98 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -276,6 +276,26 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, trace_xhci_inc_enq(ring); } +static int xhci_num_trbs_to(struct xhci_segment *start_seg, union xhci_trb *start, + struct xhci_segment *end_seg, union xhci_trb *end, + unsigned int num_segs) +{ + union xhci_trb *last_on_seg; + int num = 0; + int i = 0; + + do { + if (start_seg == end_seg && end >= start) + return num + (end - start); + last_on_seg = &start_seg->trbs[TRBS_PER_SEGMENT - 1]; + num += last_on_seg - start; + start_seg = start_seg->next; + start = start_seg->trbs; + } while (i++ <= num_segs); + + return -EINVAL; +} + /* * Check to see if there's room to enqueue num_trbs on the ring and make sure * enqueue pointer will not advance into dequeue segment. See rules above. @@ -2140,6 +2160,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, u32 trb_comp_code) { struct xhci_ep_ctx *ep_ctx; + int trbs_freed; ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); @@ -2209,9 +2230,15 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, } /* Update ring dequeue pointer */ + trbs_freed = xhci_num_trbs_to(ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb_seg, td->last_trb, + ep_ring->num_segs); + if (trbs_freed < 0) + xhci_dbg(xhci, "Failed to count freed trbs at TD finish\n"); + else + ep_ring->num_trbs_free += trbs_freed; ep_ring->dequeue = td->last_trb; ep_ring->deq_seg = td->last_trb_seg; - ep_ring->num_trbs_free += td->num_trbs - 1; inc_deq(xhci, ep_ring); return xhci_td_cleanup(xhci, td, ep_ring, td->status); @@ -3106,6 +3133,7 @@ irqreturn_t xhci_msi_irq(int irq, void *hcd) { return xhci_irq(hcd); } +EXPORT_SYMBOL_GPL(xhci_msi_irq); /**** Endpoint Ring Operations ****/ diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index a88c39e525c2..c75d93244143 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1535,7 +1535,6 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) static int tegra_xusb_probe(struct platform_device *pdev) { - struct of_phandle_args args; struct tegra_xusb *tegra; struct device_node *np; struct resource *regs; @@ -1594,15 +1593,13 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_padctl; } - /* Older device-trees don't have padctrl interrupt */ - err = of_irq_parse_one(np, 0, &args); - if (!err) { - tegra->padctl_irq = of_irq_get(np, 0); - if (tegra->padctl_irq <= 0) { - err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq; - goto put_padctl; - } - } else { + tegra->padctl_irq = of_irq_get(np, 0); + if (tegra->padctl_irq == -EPROBE_DEFER) { + err = tegra->padctl_irq; + goto put_padctl; + } else if (tegra->padctl_irq <= 0) { + /* Older device-trees don't have padctrl interrupt */ + tegra->padctl_irq = 0; dev_dbg(&pdev->dev, "%pOF is missing an interrupt, disabling PM support\n", np); } diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c index d0070814d1ea..062662d23241 100644 --- a/drivers/usb/host/xhci-trace.c +++ b/drivers/usb/host/xhci-trace.c @@ -12,3 +12,4 @@ #include "xhci-trace.h" EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks); +EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_init); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 61e93a3540a7..4286dba5b157 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -120,7 +120,6 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __field(u32, field1) __field(u32, field2) __field(u32, field3) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -130,8 +129,8 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __entry->field3 = le32_to_cpu(trb->field[3]); ), TP_printk("%s: %s", xhci_ring_type_string(__entry->type), - xhci_decode_trb(__get_str(str), XHCI_MSG_MAX, __entry->field0, __entry->field1, - __entry->field2, __entry->field3) + xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0, + __entry->field1, __entry->field2, __entry->field3) ) ); @@ -322,7 +321,6 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -330,7 +328,7 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", xhci_decode_ep_context(__get_str(str), + TP_printk("%s", xhci_decode_ep_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) ); @@ -368,7 +366,6 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __field(u32, info2) __field(u32, tt_info) __field(u32, state) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->dev_info); @@ -376,7 +373,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __entry->tt_info = le64_to_cpu(ctx->tt_info); __entry->state = le32_to_cpu(ctx->dev_state); ), - TP_printk("%s", xhci_decode_slot_context(__get_str(str), + TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->tt_info, __entry->state) ) @@ -433,13 +430,12 @@ DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx, TP_STRUCT__entry( __field(u32, drop) __field(u32, add) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags); __entry->add = le32_to_cpu(ctrl_ctx->add_flags); ), - TP_printk("%s", xhci_decode_ctrl_ctx(__get_str(str), __entry->drop, __entry->add) + TP_printk("%s", xhci_decode_ctrl_ctx(__get_buf(XHCI_MSG_MAX), __entry->drop, __entry->add) ) ); @@ -525,7 +521,6 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -533,7 +528,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - xhci_decode_portsc(__get_str(str), __entry->portsc) + xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) ) ); @@ -558,14 +553,13 @@ DECLARE_EVENT_CLASS(xhci_log_doorbell, TP_STRUCT__entry( __field(u32, slot) __field(u32, doorbell) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->slot = slot; __entry->doorbell = doorbell; ), TP_printk("Ring doorbell for %s", - xhci_decode_doorbell(__get_str(str), __entry->slot, __entry->doorbell) + xhci_decode_doorbell(__get_buf(XHCI_MSG_MAX), __entry->slot, __entry->doorbell) ) ); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6307bae9cddf..78790dc13c5f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -322,192 +322,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) return 0; } -#ifdef CONFIG_USB_PCI -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - /* - * TODO:Check with MSI Soc for sysdev - */ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "failed to allocate MSI entry"); - return ret; - } - - ret = request_irq(pdev->irq, xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "disable MSI interrupt"); - pci_free_irq_vectors(pdev); - } - - return ret; -} - -/* - * Set up MSI-X - */ -static int xhci_setup_msix(struct xhci_hcd *xhci) -{ - int i, ret; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * calculate number of msi-x vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. - * - num_online_cpus: maximum msi-x vectors per CPUs core. - * Add additional 1 vector to ensure always available interrupt. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, - PCI_IRQ_MSIX); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Failed to enable MSI-X"); - return ret; - } - - for (i = 0; i < xhci->msix_count; i++) { - ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, - "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; - } - - hcd->msix_enabled = 1; - return ret; - -disable_msix: - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); - while (--i >= 0) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - pci_free_irq_vectors(pdev); - return ret; -} - -/* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - if (xhci->quirks & XHCI_PLAT) - return; - - /* return if using legacy interrupt */ - if (hcd->irq > 0) - return; - - if (hcd->msix_enabled) { - int i; - - for (i = 0; i < xhci->msix_count; i++) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - } else { - free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); - } - - pci_free_irq_vectors(pdev); - hcd->msix_enabled = 0; -} - -static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - - if (hcd->msix_enabled) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int i; - - for (i = 0; i < xhci->msix_count; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - } -} - -static int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev; - int ret; - - /* The xhci platform device has set up IRQs through usb_add_hcd. */ - if (xhci->quirks & XHCI_PLAT) - return 0; - - pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - /* - * Some Fresco Logic host controllers advertise MSI, but fail to - * generate interrupts. Don't even try to enable MSI. - */ - if (xhci->quirks & XHCI_BROKEN_MSI) - goto legacy_irq; - - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (!ret) { - hcd->msi_enabled = 1; - return 0; - } - - if (!pdev->irq) { - xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); - return -EINVAL; - } - - legacy_irq: - if (!strlen(hcd->irq_descr)) - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", - hcd->driver->description, hcd->self.busnum); - - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return ret; - } - hcd->irq = pdev->irq; - return 0; -} - -#else - -static inline int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - return 0; -} - -static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ -} - -static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ -} - -#endif - static void compliance_mode_recovery(struct timer_list *t) { struct xhci_hcd *xhci; @@ -705,10 +519,6 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); - ret = xhci_try_enable_msi(hcd); - if (ret) - return ret; - temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -758,7 +568,7 @@ EXPORT_SYMBOL_GPL(xhci_run); * Disable device contexts, disable IRQs, and quiesce the HC. * Reset the HC, finish any completed transactions, and cleanup memory. */ -static void xhci_stop(struct usb_hcd *hcd) +void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -781,8 +591,6 @@ static void xhci_stop(struct usb_hcd *hcd) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { @@ -809,6 +617,7 @@ static void xhci_stop(struct usb_hcd *hcd) readl(&xhci->op_regs->status)); mutex_unlock(&xhci->mutex); } +EXPORT_SYMBOL_GPL(xhci_stop); /* * Shutdown HC (not bus-specific) @@ -850,8 +659,6 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_shutdown completed - status = %x", readl(&xhci->op_regs->status)); @@ -1143,10 +950,6 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) __func__); } - /* step 5: remove core well power */ - /* synchronize irq when using MSI-X */ - xhci_msix_sync_irqs(xhci); - return rc; } EXPORT_SYMBOL_GPL(xhci_suspend); @@ -1250,7 +1053,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) spin_unlock_irq(&xhci->lock); if (retval) return retval; - xhci_cleanup_msix(xhci); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 786002bb35db..6b690ec91ff3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1901,7 +1901,7 @@ struct xhci_hcd { #define XHCI_DISABLE_SPARSE BIT_ULL(38) #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39) #define XHCI_NO_SOFT_RETRY BIT_ULL(40) -#define XHCI_BROKEN_D3COLD BIT_ULL(41) +#define XHCI_BROKEN_D3COLD_S2I BIT_ULL(41) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42) #define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43) #define XHCI_RESET_TO_DEFAULT BIT_ULL(44) @@ -2125,6 +2125,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); +void xhci_stop(struct usb_hcd *hcd); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a5f7652db7da..99b15b77dfd5 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -4,6 +4,35 @@ # comment "USB Miscellaneous drivers" +config USB_USS720 + tristate "USS720 parport driver" + depends on PARPORT + select PARPORT_NOT_PC + help + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + To compile this driver as a module, choose M here: the + module will be called uss720. + config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" help @@ -108,28 +137,6 @@ config USB_IDMOUSE See also . -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - - It is safe to say M here. - config USB_APPLEDISPLAY tristate "Apple Cinema Display support" select BACKLIGHT_CLASS_DEVICE diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 93581baec3a8..1992cc284d8a 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o -obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c deleted file mode 100644 index 8ce191e3a4c0..000000000000 --- a/drivers/usb/misc/ftdi-elan.c +++ /dev/null @@ -1,2780 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * USB FTDI client driver for Elan Digital Systems's Uxxx adapters - * - * Copyright(C) 2006 Elan Digital Systems Limited - * http://www.elandigitalsystems.com - * - * Author and Maintainer - Tony Olech - Elan Digital Systems - * tony.olech@elandigitalsystems.com - * - * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) - * based on various USB client drivers in the 2.6.15 linux kernel - * with constant reference to the 3rd Edition of Linux Device Drivers - * published by O'Reilly - * - * The U132 adapter is a USB to CardBus adapter specifically designed - * for PC cards that contain an OHCI host controller. Typical PC cards - * are the Orange Mobile 3G Option GlobeTrotter Fusion card. - * - * The U132 adapter will *NOT *work with PC cards that do not contain - * an OHCI controller. A simple way to test whether a PC card has an - * OHCI controller as an interface is to insert the PC card directly - * into a laptop(or desktop) with a CardBus slot and if "lspci" shows - * a new USB controller and "lsusb -v" shows a new OHCI Host Controller - * then there is a good chance that the U132 adapter will support the - * PC card.(you also need the specific client driver for the PC card) - * - * Please inform the Author and Maintainer about any PC cards that - * contain OHCI Host Controller and work when directly connected to - * an embedded CardBus slot but do not work when they are connected - * via an ELAN U132 adapter. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -MODULE_AUTHOR("Tony Olech"); -MODULE_DESCRIPTION("FTDI ELAN driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, - "true to distrust firmware power/overcurrent setup"); -extern struct platform_driver u132_platform_driver; -/* - * ftdi_module_lock exists to protect access to global variables - * - */ -static struct mutex ftdi_module_lock; -static int ftdi_instances = 0; -static struct list_head ftdi_static_list; -/* - * end of the global variables protected by ftdi_module_lock - */ -#include "usb_u132.h" -#include -#include - -/* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "../host/ohci.h" -/* Define these values to match your devices*/ -#define USB_FTDI_ELAN_VENDOR_ID 0x0403 -#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea -/* table of devices that work with this driver*/ -static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } -}; - -MODULE_DEVICE_TABLE(usb, ftdi_elan_table); -/* only the jtag(firmware upgrade device) interface requires - * a device file and corresponding minor number, but the - * interface is created unconditionally - I suppose it could - * be configured or not according to a module parameter. - * But since we(now) require one interface per device, - * and since it unlikely that a normal installation would - * require more than a couple of elan-ftdi devices, 8 seems - * like a reasonable limit to have here, and if someone - * really requires more than 8 devices, then they can frig the - * code and recompile - */ -#define USB_FTDI_ELAN_MINOR_BASE 192 -#define COMMAND_BITS 5 -#define COMMAND_SIZE (1<udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; - kfree(ftdi); -} - -static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) -{ - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) -{ - kref_get(&ftdi->kref); -} - -static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) -{ - kref_init(&ftdi->kref); -} - -static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->status_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->status_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->command_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->command_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->respond_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->respond_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -void ftdi_elan_gone_away(struct platform_device *pdev) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); -} - - -EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -static void ftdi_release_platform_dev(struct device *dev) -{ - dev->parent = NULL; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi); -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) -{ - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - - return platform_device_register(&ftdi->platform_dev); -} - -static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) -{ - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) -{ - ftdi_command_queue_work(ftdi, 0); -} - -static void ftdi_elan_command_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, command_work.work); - - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) -{ - ftdi_respond_queue_work(ftdi, 0); -} - -static void ftdi_elan_respond_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - - -/* - * the sw_lock is initially held and will be freed - * after the FTDI has been synchronized - * - */ -static void ftdi_elan_status_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", - ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } -} - - -/* - * file_operations for the jtag interface - * - * the usage count for the device is incremented on open() - * and decremented on release() - */ -static int ftdi_elan_open(struct inode *inode, struct file *file) -{ - int subminor; - struct usb_interface *interface; - - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - pr_err("can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } -} - -static int ftdi_elan_release(struct inode *inode, struct file *file) -{ - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; -} - - -/* - * - * blocking bulk reads are used to get data from the device - * - */ -static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; -have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } -more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; -} - -static void ftdi_elan_write_bulk_callback(struct urb *urb) -{ - struct usb_ftdi *ftdi = urb->context; - int status = urb->status; - - if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, - "urb=%p write bulk status received: %d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -} - -static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; -} - -static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) -{ - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } - return total_size; -} - -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) -{ - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", - retval, urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); -} - -static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02 || ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } -} - -static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; -} - - -/* - * The engine tries to empty the FTDI fifo - * - * all responses found in the fifo data are dispatched thus - * the response buffer can only ever hold a maximum sized - * response from the Uxxx. - * - */ -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) -{ - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; -read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - goto more; - } else if (bytes_read > 0) { - dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", - bytes_read, diag); - return -ENOMEM; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - return -ENOMEM; - } - } else if (retval == -EILSEQ) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else if (retval) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } -more:{ - goto read; - } -have:if (ftdi->bulk_in_left > 0) { - u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; - bytes_read += 1; - ftdi->bulk_in_left -= 1; - if (ftdi->received == 0 && c == 0xFF) { - goto have; - } else - *b++ = c; - if (++ftdi->received < ftdi->expected) { - goto have; - } else if (ftdi->ed_found) { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ed_number]; - int payload = (ed_length >> 0) & 0x07FF; - char diag[30 *3 + 4]; - char *d = diag; - int m = payload; - u8 *c = 4 + ftdi->response; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - goto have; - } else if (ftdi->expected == 8) { - u8 buscmd; - int respond_head = ftdi->respond_head++; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & respond_head]; - u32 data = ftdi->response[7]; - data <<= 8; - data |= ftdi->response[6]; - data <<= 8; - data |= ftdi->response[5]; - data <<= 8; - data |= ftdi->response[4]; - *respond->value = data; - *respond->result = 0; - complete(&respond->wait_completion); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - buscmd = (ftdi->response[0] >> 0) & 0x0F; - if (buscmd == 0x00) { - } else if (buscmd == 0x02) { - } else if (buscmd == 0x06) { - } else if (buscmd == 0x0A) { - } else - dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n", - buscmd, data); - goto have; - } else { - if ((ftdi->response[0] & 0x80) == 0x00) { - ftdi->expected = 8; - goto have; - } else { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - int ed_type = (ftdi->response[0] >> 0) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ - ed_number]; - target->halted = (ftdi->response[0] >> 3) & - 0x01; - target->skipped = (ftdi->response[0] >> 2) & - 0x01; - target->toggle_bits = (ftdi->response[3] >> 6) - & 0x03; - target->error_count = (ftdi->response[3] >> 4) - & 0x03; - target->condition_code = (ftdi->response[ - 3] >> 0) & 0x0F; - if ((ftdi->response[0] & 0x10) == 0x00) { - b = have_ed_set_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } else { - b = have_ed_get_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } - } - } - } else - goto more; -} - - -/* - * create a urb, and a buffer for it, and copy the data to the urb - * - */ -static ssize_t ftdi_elan_write(struct file *file, - const char __user *user_buffer, size_t count, - loff_t *ppos) -{ - int retval = 0; - struct urb *urb; - char *buf; - struct usb_ftdi *ftdi = file->private_data; - - if (ftdi->disconnected > 0) { - return -ENODEV; - } - if (count == 0) { - goto exit; - } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error_1; - } - buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error_2; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error_3; - } - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, count, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, - "failed submitting write urb, error %d\n", retval); - goto error_3; - } - usb_free_urb(urb); - -exit: - return count; -error_3: - usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma); -error_2: - usb_free_urb(urb); -error_1: - return retval; -} - -static const struct file_operations ftdi_elan_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ftdi_elan_read, - .write = ftdi_elan_write, - .open = ftdi_elan_open, - .release = ftdi_elan_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver ftdi_elan_jtag_class = { - .name = "ftdi-%d-jtag", - .fops = &ftdi_elan_fops, - .minor_base = USB_FTDI_ELAN_MINOR_BASE, -}; - -/* - * the following definitions are for the - * ELAN FPGA state machgine processor that - * lies on the other side of the FTDI chip - */ -#define cPCIu132rd 0x0 -#define cPCIu132wr 0x1 -#define cPCIiord 0x2 -#define cPCIiowr 0x3 -#define cPCImemrd 0x6 -#define cPCImemwr 0x7 -#define cPCIcfgrd 0xA -#define cPCIcfgwr 0xB -#define cPCInull 0xF -#define cU132cmd_status 0x0 -#define cU132flash 0x1 -#define cPIDsetup 0x0 -#define cPIDout 0x1 -#define cPIDin 0x2 -#define cPIDinonce 0x3 -#define cCCnoerror 0x0 -#define cCCcrc 0x1 -#define cCCbitstuff 0x2 -#define cCCtoggle 0x3 -#define cCCstall 0x4 -#define cCCnoresp 0x5 -#define cCCbadpid1 0x6 -#define cCCbadpid2 0x7 -#define cCCdataoverrun 0x8 -#define cCCdataunderrun 0x9 -#define cCCbuffoverrun 0xC -#define cCCbuffunderrun 0xD -#define cCCnotaccessed 0xF -static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | cPCIu132wr; - command->length = 0x04; - command->address = 0x00; - command->width = 0x00; - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCIcfgwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCImemwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); -static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | cPCIu132rd; - command->length = 0x04; - respond->address = command->address = cU132cmd_status; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 *data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCIcfgrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 *data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCImemrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - if (ftdi->initialized == 0) { - return -ENODEV; - } else - return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); -static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed << 5); - command->length = 0x8007; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 8; - command->value = 0; - command->buffer = urb->setup_packet; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); -static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - command->header = 0x82 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); -static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->length = 0x0000; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); -static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u8 *b; - u16 urb_size; - int i = 0; - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = min_t(u32, 1024, - urb->transfer_buffer_length - - urb->actual_length); - command->value = 0; - command->buffer = urb->transfer_buffer + - urb->actual_length; - command->length = 0x8000 | (command->follows - 1); - b = command->buffer; - urb_size = command->follows; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - } else - d += sprintf(d, " .."); - } - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); -static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x83 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); -static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, - void *endp) -{ - u8 ed = ed_number - 1; - if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - struct u132_target *target = &ftdi->target[ed]; - mutex_lock(&ftdi->u132_lock); - if (target->abandoning > 0) { - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = - &ftdi->command[COMMAND_MASK & - ftdi->command_next]; - command->header = 0x80 | (ed << 5) | - 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - mutex_unlock(&ftdi->u132_lock); - return 0; - } - } -} - -int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_flush(ftdi, ed_number, endp); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); -static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 20; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 100); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", - b1); - if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return retval; - } - } - return -1; -} - - -/* - * send the long flush sequence - * - */ -static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 257; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - while (I-- > 0) - buf[i++] = 0x55; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - - -/* - * send the reset sequence - * - */ -static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 4; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - buf[i++] = 0x55; - buf[i++] = 0xAA; - buf[i++] = 0x5A; - buf[i++] = 0xA5; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) -{ - int retval; - int long_stop = 10; - int retry_on_timeout = 5; - int retry_on_empty = 10; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - ftdi->bulk_in_left = 0; - ftdi->bulk_in_last = -1; - while (long_stop-- > 0) { - int read_stop; - int read_stuck; - retval = ftdi_elan_synchronize_flush(ftdi); - if (retval) - return retval; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - reset:retval = ftdi_elan_synchronize_reset(ftdi); - if (retval) - return retval; - read_stop = 100; - read_stuck = 10; - read:{ - int packet_bytes = 0; - retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, - ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - unsigned char c = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - if (c == 0x7E) { - return 0; - } else { - if (c == 0x55) { - goto read; - } else if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 1) { - unsigned char s1 = ftdi->bulk_in_buffer[0]; - unsigned char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x00) { - if (read_stuck-- > 0) { - goto read; - } else - goto reset; - } else { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 0) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - continue; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - continue; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", - retval); - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } - } - dev_err(&ftdi->udev->dev, "failed to synchronize\n"); - return -EFAULT; -} - -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 50; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 1000); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else - return -EFAULT; - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1); - if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return -ENOMEM; - } - } - return -1; -} - -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); - if (UxxxStatus) - return UxxxStatus; - if (ftdi->controlreg & 0x00400000) { - if (ftdi->card_ejected) { - } else { - ftdi->card_ejected = 1; - dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n", - ftdi->controlreg); - } - return -ENODEV; - } else { - u8 fn = ftdi->function - 1; - int activePCIfn = fn << 8; - u32 pcidata; - u32 pciVID; - u32 pciPID; - int reg = 0; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if (pciVID == ftdi->platform_data.vendor && pciPID == - ftdi->platform_data.device) { - return 0; - } else { - dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n", - ftdi->platform_data.vendor, pciVID, - ftdi->platform_data.device, pciPID); - return -ENODEV; - } - } -} - - -#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); - -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) -{ - int devices = 0; - int retval; - u32 hc_control; - int num_ports; - u32 control; - u32 rh_a = -1; - u32 status; - u32 fminterval; - u32 hc_fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - int temp; - retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; - retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); - if (retval) - return retval; - hc_fminterval &= 0x3fff; - if (hc_fminterval != FI) { - } - hc_fminterval |= FSMP(hc_fminterval) << 16; - retval = ftdi_read_pcimem(ftdi, control, &hc_control); - if (retval) - return retval; - switch (hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { /* power down each port */ - for (temp = 0; temp < num_ports; temp++) { - retval = ftdi_write_pcimem(ftdi, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; -retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra:{ - retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (quirk & OHCI_QUIRK_INITRESET) { - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, fminterval, - ((fminterval & FIT) ^ FIT) | hc_fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, periodicstart, - ((9 *hc_fminterval) / 10) & 0x3fff); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(quirk & OHCI_QUIRK_INITRESET)) { - quirk |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", - fminterval, periodicstart); - } /* start controller operations */ - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrstatus, mask); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (quirk & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - for (temp = 0; temp < num_ports; temp++) { - u32 portstatus; - retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], - &portstatus); - if (retval) - return retval; - if (1 & portstatus) - devices += 1; - } - return devices; -} - -static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - for (reg = 0; reg <= 0x54; reg += 4) { - UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (UxxxStatus) - return UxxxStatus; - } - return 0; -} - -static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0x00000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x00); - if (UxxxStatus) - return UxxxStatus; - return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata); -} - -static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) -{ - int result; - int UxxxStatus; - UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - result = ftdi_elan_check_controller(ftdi, quirk); - UxxxStatus = ftdi_elan_close_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - return result; -} - -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) -{ - u32 controlreg; - u8 sensebits; - int UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); - if (UxxxStatus) - return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - msleep(1000); - sensebits = (controlreg >> 16) & 0x000F; - if (0x0D == sensebits) - return 0; - else - return - ENXIO; -} - -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus; - u32 pcidata; - int reg = 0; - u8 fn; - int activePCIfn = 0; - int max_devices = 0; - int controllers = 0; - int unrecognized = 0; - ftdi->function = 0; - for (fn = 0; (fn < 4); fn++) { - u32 pciVID = 0; - u32 pciPID = 0; - int devices = 0; - activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_AMD756); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_ZFMICRO); - controllers += 1; - } else if (0 == pcidata) { - } else - unrecognized += 1; - if (devices > max_devices) { - max_devices = devices; - ftdi->function = fn + 1; - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; - } - } - if (ftdi->function > 0) { - return ftdi_elan_setup_controller(ftdi, ftdi->function - 1); - } else if (controllers > 0) { - return -ENXIO; - } else if (unrecognized > 0) { - return -ENXIO; - } else { - ftdi->enumerated = 0; - return -ENXIO; - } -} - - -/* - * we use only the first bulk-in and bulk-out endpoints - */ -static int ftdi_elan_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *bulk_in, *bulk_out; - int retval; - struct usb_ftdi *ftdi; - - ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (!ftdi) - return -ENOMEM; - - mutex_lock(&ftdi_module_lock); - list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); - ftdi->sequence_num = ++ftdi_instances; - mutex_unlock(&ftdi_module_lock); - ftdi_elan_init_kref(ftdi); - sema_init(&ftdi->sw_lock, 1); - ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); - ftdi->interface = interface; - mutex_init(&ftdi->u132_lock); - ftdi->expected = 4; - - iface_desc = interface->cur_altsetting; - retval = usb_find_common_endpoints(iface_desc, - &bulk_in, &bulk_out, NULL, NULL); - if (retval) { - dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n"); - goto error; - } - - ftdi->bulk_in_size = usb_endpoint_maxp(bulk_in); - ftdi->bulk_in_endpointAddr = bulk_in->bEndpointAddress; - ftdi->bulk_in_buffer = kmalloc(ftdi->bulk_in_size, GFP_KERNEL); - if (!ftdi->bulk_in_buffer) { - retval = -ENOMEM; - goto error; - } - - ftdi->bulk_out_endpointAddr = bulk_out->bEndpointAddress; - - dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", - iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, - ftdi->bulk_out_endpointAddr); - usb_set_intfdata(interface, ftdi); - if (iface_desc->desc.bInterfaceNumber == 0 && - ftdi->bulk_in_endpointAddr == 0x81 && - ftdi->bulk_out_endpointAddr == 0x02) { - retval = usb_register_dev(interface, &ftdi_elan_jtag_class); - if (retval) { - dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n"); - usb_set_intfdata(interface, NULL); - retval = -ENOMEM; - goto error; - } else { - ftdi->class = &ftdi_elan_jtag_class; - dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n", - ftdi, iface_desc->desc.bInterfaceNumber, - interface->minor); - return 0; - } - } else if (iface_desc->desc.bInterfaceNumber == 1 && - ftdi->bulk_in_endpointAddr == 0x83 && - ftdi->bulk_out_endpointAddr == 0x04) { - ftdi->class = NULL; - dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n", - ftdi, iface_desc->desc.bInterfaceNumber); - INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); - INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); - INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); - ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); - return 0; - } else { - dev_err(&ftdi->udev->dev, - "Could not find ELAN's U132 device\n"); - retval = -ENODEV; - goto error; - } -error:if (ftdi) { - ftdi_elan_put_kref(ftdi); - } - return retval; -} - -static void ftdi_elan_disconnect(struct usb_interface *interface) -{ - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - ftdi->disconnected += 1; - if (ftdi->class) { - int minor = interface->minor; - struct usb_class_driver *class = ftdi->class; - usb_set_intfdata(interface, NULL); - usb_deregister_dev(interface, class); - dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n", - minor); - } else { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - if (ftdi->registered) { - platform_device_unregister(&ftdi->platform_dev); - ftdi->synchronized = 0; - ftdi->enumerated = 0; - ftdi->initialized = 0; - ftdi->registered = 0; - } - ftdi->disconnected += 1; - usb_set_intfdata(interface, NULL); - dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); - } - ftdi_elan_put_kref(ftdi); -} - -static struct usb_driver ftdi_elan_driver = { - .name = "ftdi-elan", - .probe = ftdi_elan_probe, - .disconnect = ftdi_elan_disconnect, - .id_table = ftdi_elan_table, -}; -static int __init ftdi_elan_init(void) -{ - int result; - pr_info("driver %s\n", ftdi_elan_driver.name); - mutex_init(&ftdi_module_lock); - INIT_LIST_HEAD(&ftdi_static_list); - result = usb_register(&ftdi_elan_driver); - if (result) { - pr_err("usb_register failed. Error number %d\n", result); - } - return result; - -} - -static void __exit ftdi_elan_exit(void) -{ - struct usb_ftdi *ftdi; - struct usb_ftdi *temp; - usb_deregister(&ftdi_elan_driver); - pr_info("ftdi_u132 driver deregistered\n"); - list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - } -} - - -module_init(ftdi_elan_init); -module_exit(ftdi_elan_exit); diff --git a/drivers/usb/misc/sisusbvga/sisusbvga.c b/drivers/usb/misc/sisusbvga/sisusbvga.c index 654a79fd3231..febf34f9f049 100644 --- a/drivers/usb/misc/sisusbvga/sisusbvga.c +++ b/drivers/usb/misc/sisusbvga/sisusbvga.c @@ -2778,6 +2778,20 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; + static const u8 ep_addresses[] = { + SISUSB_EP_GFX_IN | USB_DIR_IN, + SISUSB_EP_GFX_OUT | USB_DIR_OUT, + SISUSB_EP_GFX_BULK_OUT | USB_DIR_OUT, + SISUSB_EP_GFX_LBULK_OUT | USB_DIR_OUT, + SISUSB_EP_BRIDGE_IN | USB_DIR_IN, + SISUSB_EP_BRIDGE_OUT | USB_DIR_OUT, + 0}; + + /* Are the expected endpoints present? */ + if (!usb_check_bulk_endpoints(intf, ep_addresses)) { + dev_err(&intf->dev, "Invalid USB2VGA device\n"); + return -EINVAL; + } dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index e3abe67a155d..ce1da80d3365 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -377,7 +377,6 @@ out_err: return err; } -#ifdef CONFIG_OF static void usb251xb_get_ports_field(struct usb251xb *hub, const char *prop_name, u8 port_cnt, bool ds_only, u8 *fld) @@ -410,10 +409,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, return -ENODEV; } - if (of_get_property(np, "skip-config", NULL)) - hub->skip_config = 1; - else - hub->skip_config = 0; + hub->skip_config = of_property_read_bool(np, "skip-config"); hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->gpio_reset)) @@ -431,40 +427,40 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->device_id = USB251XB_DEF_DEVICE_ID; hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1; - if (of_get_property(np, "self-powered", NULL)) { + if (of_property_read_bool(np, "self-powered")) { hub->conf_data1 |= BIT(7); /* Configure Over-Current sens when self-powered */ hub->conf_data1 &= ~BIT(2); - if (of_get_property(np, "ganged-sensing", NULL)) + if (of_property_read_bool(np, "ganged-sensing")) hub->conf_data1 &= ~BIT(1); - else if (of_get_property(np, "individual-sensing", NULL)) + else if (of_property_read_bool(np, "individual-sensing")) hub->conf_data1 |= BIT(1); - } else if (of_get_property(np, "bus-powered", NULL)) { + } else if (of_property_read_bool(np, "bus-powered")) { hub->conf_data1 &= ~BIT(7); /* Disable Over-Current sense when bus-powered */ hub->conf_data1 |= BIT(2); } - if (of_get_property(np, "disable-hi-speed", NULL)) + if (of_property_read_bool(np, "disable-hi-speed")) hub->conf_data1 |= BIT(5); - if (of_get_property(np, "multi-tt", NULL)) + if (of_property_read_bool(np, "multi-tt")) hub->conf_data1 |= BIT(4); - else if (of_get_property(np, "single-tt", NULL)) + else if (of_property_read_bool(np, "single-tt")) hub->conf_data1 &= ~BIT(4); - if (of_get_property(np, "disable-eop", NULL)) + if (of_property_read_bool(np, "disable-eop")) hub->conf_data1 |= BIT(3); - if (of_get_property(np, "individual-port-switching", NULL)) + if (of_property_read_bool(np, "individual-port-switching")) hub->conf_data1 |= BIT(0); - else if (of_get_property(np, "ganged-port-switching", NULL)) + else if (of_property_read_bool(np, "ganged-port-switching")) hub->conf_data1 &= ~BIT(0); hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2; - if (of_get_property(np, "dynamic-power-switching", NULL)) + if (of_property_read_bool(np, "dynamic-power-switching")) hub->conf_data2 |= BIT(7); if (!of_property_read_u32(np, "oc-delay-us", &property_u32)) { @@ -487,17 +483,17 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, } } - if (of_get_property(np, "compound-device", NULL)) + if (of_property_read_bool(np, "compound-device")) hub->conf_data2 |= BIT(3); hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3; - if (of_get_property(np, "port-mapping-mode", NULL)) + if (of_property_read_bool(np, "port-mapping-mode")) hub->conf_data3 |= BIT(3); if (data->led_support && of_get_property(np, "led-usb-mode", NULL)) hub->conf_data3 &= ~BIT(1); - if (of_get_property(np, "string-support", NULL)) + if (of_property_read_bool(np, "string-support")) hub->conf_data3 |= BIT(0); hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; @@ -626,13 +622,6 @@ static const struct of_device_id usb251xb_of_match[] = { } }; MODULE_DEVICE_TABLE(of, usb251xb_of_match); -#else /* CONFIG_OF */ -static int usb251xb_get_ofdata(struct usb251xb *hub, - const struct usb251xb_data *data) -{ - return 0; -} -#endif /* CONFIG_OF */ static void usb251xb_regulator_disable_action(void *data) { @@ -754,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, usb251xb_id); static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(usb251xb_of_match), + .of_match_table = usb251xb_of_match, .pm = &usb251xb_pm_ops, }, .probe_new = usb251xb_i2c_probe, diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index bd47c4437ca4..c6cfd1edaf76 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -46,34 +46,18 @@ struct usb3503 { struct device *dev; struct clk *clk; u8 port_off_mask; + struct gpio_desc *bypass; struct gpio_desc *intn; struct gpio_desc *reset; struct gpio_desc *connect; bool secondary_ref_clk; }; -static int usb3503_reset(struct usb3503 *hub, int state) -{ - if (!state && hub->connect) - gpiod_set_value_cansleep(hub->connect, 0); - - if (hub->reset) - gpiod_set_value_cansleep(hub->reset, !state); - - /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ - if (state) - usleep_range(4000, 10000); - - return 0; -} - static int usb3503_connect(struct usb3503 *hub) { struct device *dev = hub->dev; int err; - usb3503_reset(hub, 1); - if (hub->regmap) { /* SP_ILOCK: set connect_n, config_n for config */ err = regmap_write(hub->regmap, USB3503_SP_ILOCK, @@ -126,25 +110,46 @@ static int usb3503_connect(struct usb3503 *hub) static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) { struct device *dev = hub->dev; - int err = 0; + int rst, bypass, conn; switch (mode) { case USB3503_MODE_HUB: - err = usb3503_connect(hub); + conn = 1; + rst = 0; + bypass = 0; break; - case USB3503_MODE_STANDBY: - usb3503_reset(hub, 0); + conn = 0; + rst = 1; + bypass = 1; dev_info(dev, "switched to STANDBY mode\n"); break; - + case USB3503_MODE_BYPASS: + conn = 0; + rst = 0; + bypass = 1; + break; default: dev_err(dev, "unknown mode is requested\n"); - err = -EINVAL; - break; + return -EINVAL; } - return err; + if (!conn && hub->connect) + gpiod_set_value_cansleep(hub->connect, 0); + + if (hub->reset) + gpiod_set_value_cansleep(hub->reset, rst); + + if (hub->bypass) + gpiod_set_value_cansleep(hub->bypass, bypass); + + if (conn) { + /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ + usleep_range(4000, 10000); + return usb3503_connect(hub); + } + + return 0; } static const struct regmap_config usb3503_regmap_config = { @@ -253,6 +258,14 @@ static int usb3503_probe(struct usb3503 *hub) if (hub->connect) gpiod_set_consumer_name(hub->connect, "usb3503 connect"); + hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH); + if (IS_ERR(hub->bypass)) { + err = PTR_ERR(hub->bypass); + goto err_clk; + } + if (hub->bypass) + gpiod_set_consumer_name(hub->bypass, "usb3503 bypass"); + hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->reset)) { err = PTR_ERR(hub->reset); @@ -388,6 +401,7 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id); static const struct of_device_id usb3503_of_match[] = { { .compatible = "smsc,usb3503", }, { .compatible = "smsc,usb3503a", }, + { .compatible = "smsc,usb3803", }, {}, }; MODULE_DEVICE_TABLE(of, usb3503_of_match); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index abb1cd35d8a6..952c56789258 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1379,7 +1379,7 @@ int __init mon_bin_init(void) { int rc; - mon_bin_class = class_create(THIS_MODULE, "usbmon"); + mon_bin_class = class_create("usbmon"); if (IS_ERR(mon_bin_class)) { rc = PTR_ERR(mon_bin_class); goto err_class; diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 2d7b57e07eee..b4a7662dded5 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -90,7 +90,7 @@ struct mtu3_request; */ #define EP0_RESPONSE_BUF 6 -#define BULK_CLKS_CNT 4 +#define BULK_CLKS_CNT 6 /* device operated link and speed got from DEVICE_CONF register */ enum mtu3_speed { diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 9b8aded3d95e..8191b7ed3852 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -294,6 +294,7 @@ static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx) role_sx_desc.get = ssusb_role_sw_get; role_sx_desc.fwnode = dev_fwnode(dev); role_sx_desc.driver_data = ssusb; + role_sx_desc.allow_userspace_control = true; otg_sx->role_sw = usb_role_switch_register(dev, &role_sx_desc); if (IS_ERR(otg_sx->role_sw)) return PTR_ERR(otg_sx->role_sw); diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index c0264d5426bf..ad0eeac4332d 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -23,7 +23,6 @@ __acquires(mep->mtu->lock) req->status = status; trace_mtu3_req_complete(mreq); - spin_unlock(&mtu->lock); /* ep0 makes use of PIO, needn't unmap it */ if (mep->epnum) @@ -32,6 +31,7 @@ __acquires(mep->mtu->lock) dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n", mep->name, req, req->status, req->actual, req->length); + spin_unlock(&mtu->lock); usb_gadget_giveback_request(&mep->ep, req); spin_lock(&mtu->lock); } diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index f3903367a6a0..177d2caf887c 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "mtu3.h" diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index d78ae52b4e26..6f264b129243 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -234,6 +234,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) clks[1].id = "ref_ck"; clks[2].id = "mcu_ck"; clks[3].id = "dma_ck"; + clks[4].id = "xhci_ck"; + clks[5].id = "frmcnt_ck"; ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks); if (ret) return ret; diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index a2fdab8b63b2..3d77408e3133 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c @@ -210,6 +210,7 @@ static struct qmu_gpd *advance_enq_gpd(struct mtu3_gpd_ring *ring) return ring->enqueue; } +/* @dequeue may be NULL if ring is unallocated or freed */ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring) { if (ring->dequeue < ring->end) @@ -221,7 +222,7 @@ static struct qmu_gpd *advance_deq_gpd(struct mtu3_gpd_ring *ring) } /* check if a ring is emtpy */ -static int gpd_ring_empty(struct mtu3_gpd_ring *ring) +static bool gpd_ring_empty(struct mtu3_gpd_ring *ring) { struct qmu_gpd *enq = ring->enqueue; struct qmu_gpd *next; @@ -466,6 +467,37 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) mtu3_qmu_resume(mep); } +/* + * when rx error happens (except zlperr), QMU will stop, and RQCPR saves + * the GPD encountered error, Done irq will arise after resuming QMU again. + */ +static void qmu_error_rx(struct mtu3 *mtu, u8 epnum) +{ + struct mtu3_ep *mep = mtu->out_eps + epnum; + struct mtu3_gpd_ring *ring = &mep->gpd_ring; + struct qmu_gpd *gpd_current = NULL; + struct mtu3_request *mreq; + dma_addr_t cur_gpd_dma; + + cur_gpd_dma = read_rxq_cur_addr(mtu->mac_base, epnum); + gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma); + + mreq = next_request(mep); + if (!mreq || mreq->gpd != gpd_current) { + dev_err(mtu->dev, "no correct RX req is found\n"); + return; + } + + mreq->request.status = -EAGAIN; + + /* by pass the current GDP */ + gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO); + mtu3_qmu_resume(mep); + + dev_dbg(mtu->dev, "%s EP%d, current=%p, req=%p\n", + __func__, epnum, gpd_current, mreq); +} + /* * NOTE: request list maybe is already empty as following case: * queue_tx --> qmu_interrupt(clear interrupt pending, schedule tasklet)--> @@ -491,7 +523,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum) dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", __func__, epnum, gpd, gpd_current, ring->enqueue); - while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { + while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) { mreq = next_request(mep); @@ -530,7 +562,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum) dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", __func__, epnum, gpd, gpd_current, ring->enqueue); - while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { + while (gpd && gpd != gpd_current && !GET_GPD_HWO(gpd)) { mreq = next_request(mep); @@ -571,14 +603,18 @@ static void qmu_exception_isr(struct mtu3 *mtu, u32 qmu_status) if ((qmu_status & RXQ_CSERR_INT) || (qmu_status & RXQ_LENERR_INT)) { errval = mtu3_readl(mbase, U3D_RQERRIR0); + mtu3_writel(mbase, U3D_RQERRIR0, errval); + for (i = 1; i < mtu->num_eps; i++) { if (errval & QMU_RX_CS_ERR(i)) dev_err(mtu->dev, "Rx %d CS error!\n", i); if (errval & QMU_RX_LEN_ERR(i)) dev_err(mtu->dev, "RX %d Length error\n", i); + + if (errval & (QMU_RX_CS_ERR(i) | QMU_RX_LEN_ERR(i))) + qmu_error_rx(mtu, i); } - mtu3_writel(mbase, U3D_RQERRIR0, errval); } if (qmu_status & RXQ_ZLPERR_INT) { diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 3a1f4bcea80c..9a8cf3de0617 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -113,7 +113,7 @@ config USB_MUSB_MEDIATEK config USB_MUSB_POLARFIRE_SOC tristate "Microchip PolarFire SoC platforms" - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST depends on NOP_USB_XCEIV select USB_MUSB_DUAL_ROLE help diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d47e5c94587b..912e32b78ac6 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -576,14 +576,12 @@ static int da8xx_probe(struct platform_device *pdev) return ret; } -static int da8xx_remove(struct platform_device *pdev) +static void da8xx_remove(struct platform_device *pdev) { struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->usb_phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -626,7 +624,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table); static struct platform_driver da8xx_driver = { .probe = da8xx_probe, - .remove = da8xx_remove, + .remove_new = da8xx_remove, .driver = { .name = "musb-da8xx", .pm = &da8xx_pm_ops, diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index c7b1d2a394d9..5aabdd7e2511 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -308,14 +308,12 @@ err_platform_device_put: return ret; } -static int jz4740_remove(struct platform_device *pdev) +static void jz4740_remove(struct platform_device *pdev) { struct jz4740_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->pdev); clk_disable_unprepare(glue->clk); - - return 0; } static const struct of_device_id jz4740_musb_of_match[] = { @@ -327,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); static struct platform_driver jz4740_driver = { .probe = jz4740_probe, - .remove = jz4740_remove, + .remove_new = jz4740_remove, .driver = { .name = "musb-jz4740", .of_match_table = jz4740_musb_of_match, diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c index 27b9bd258340..598ee5c0bf34 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -508,15 +508,13 @@ err_unregister_usb_phy: return ret; } -static int mtk_musb_remove(struct platform_device *pdev) +static void mtk_musb_remove(struct platform_device *pdev) { struct mtk_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } #ifdef CONFIG_OF @@ -529,7 +527,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match); static struct platform_driver mtk_musb_driver = { .probe = mtk_musb_probe, - .remove = mtk_musb_remove, + .remove_new = mtk_musb_remove, .driver = { .name = "musb-mtk", .of_match_table = of_match_ptr(mtk_musb_match), diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index cea2e8108867..24b98716f7fc 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -235,15 +235,13 @@ err_phy_release: return ret; } -static int mpfs_remove(struct platform_device *pdev) +static void mpfs_remove(struct platform_device *pdev) { struct mpfs_glue *glue = platform_get_drvdata(pdev); clk_disable_unprepare(glue->clk); platform_device_unregister(glue->musb); usb_phy_generic_unregister(pdev); - - return 0; } #ifdef CONFIG_OF @@ -256,7 +254,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table); static struct platform_driver mpfs_musb_driver = { .probe = mpfs_probe, - .remove = mpfs_remove, + .remove_new = mpfs_remove, .driver = { .name = "mpfs-musb", .of_match_table = of_match_ptr(mpfs_id_table) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 648bb6021c5e..d162afbbe19f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2621,7 +2621,7 @@ static int musb_probe(struct platform_device *pdev) return musb_init_controller(dev, irq, base); } -static int musb_remove(struct platform_device *pdev) +static void musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); @@ -2657,7 +2657,6 @@ static int musb_remove(struct platform_device *pdev) usb_phy_shutdown(musb->xceiv); musb_free(musb); device_init_wakeup(dev, 0); - return 0; } #ifdef CONFIG_PM @@ -2955,7 +2954,7 @@ static struct platform_driver musb_driver = { .dev_groups = musb_groups, }, .probe = musb_probe, - .remove = musb_remove, + .remove_new = musb_remove, }; module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index f75cde0f2b43..9119b1d51370 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -915,7 +915,7 @@ err: return ret; } -static int dsps_remove(struct platform_device *pdev) +static void dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); @@ -923,8 +923,6 @@ static int dsps_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); iounmap(glue->usbss_base); - - return 0; } static const struct dsps_musb_wrapper am33xx_driver_data = { @@ -1036,7 +1034,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, - .remove = dsps_remove, + .remove_new = dsps_remove, .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 44a21ec865fb..b4a4c1df4e0d 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -334,7 +334,7 @@ static int omap2430_probe(struct platform_device *pdev) * Legacy SoCs using omap_device get confused if node is moved * because of interconnect properties mixed into the node. */ - if (of_get_property(np, "ti,hwmods", NULL)) { + if (of_property_present(np, "ti,hwmods")) { dev_warn(&pdev->dev, "please update to probe with ti-sysc\n"); populate_irqs = true; } else { @@ -471,14 +471,12 @@ err0: return ret; } -static int omap2430_remove(struct platform_device *pdev) +static void omap2430_remove(struct platform_device *pdev) { struct omap2430_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); - - return 0; } #ifdef CONFIG_PM @@ -610,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table); static struct platform_driver omap2430_driver = { .probe = omap2430_probe, - .remove = omap2430_remove, + .remove_new = omap2430_remove, .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 9b622cd9b2bd..c5c6c4e09300 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -805,15 +805,13 @@ err_unregister_usb_phy: return ret; } -static int sunxi_musb_remove(struct platform_device *pdev) +static void sunxi_musb_remove(struct platform_device *pdev) { struct sunxi_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } static const struct sunxi_musb_cfg sun4i_a10_musb_cfg = { @@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match); static struct platform_driver sunxi_musb_driver = { .probe = sunxi_musb_probe, - .remove = sunxi_musb_remove, + .remove_new = sunxi_musb_remove, .driver = { .name = "musb-sunxi", .of_match_table = sunxi_musb_match, diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 5609b4e84d40..a1f29dbc62e6 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1258,19 +1258,17 @@ static int tusb_probe(struct platform_device *pdev) return 0; } -static int tusb_remove(struct platform_device *pdev) +static void tusb_remove(struct platform_device *pdev) { struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); - - return 0; } static struct platform_driver tusb_driver = { .probe = tusb_probe, - .remove = tusb_remove, + .remove_new = tusb_remove, .driver = { .name = "musb-tusb", }, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 8ea62c344328..c8d9d2a1d2f0 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -303,14 +303,12 @@ err0: return ret; } -static int ux500_remove(struct platform_device *pdev) +static void ux500_remove(struct platform_device *pdev) { struct ux500_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); clk_disable_unprepare(glue->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -357,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match); static struct platform_driver ux500_driver = { .probe = ux500_probe, - .remove = ux500_remove, + .remove_new = ux500_remove, .driver = { .name = "musb-ux500", .pm = &ux500_pm_ops, diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 4c52ba96f17e..408f47e39025 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -965,7 +965,7 @@ static int ab8500_usb_probe(struct platform_device *pdev) return 0; } -static int ab8500_usb_remove(struct platform_device *pdev) +static void ab8500_usb_remove(struct platform_device *pdev) { struct ab8500_usb *ab = platform_get_drvdata(pdev); @@ -977,8 +977,6 @@ static int ab8500_usb_remove(struct platform_device *pdev) ab8500_usb_host_phy_dis(ab); else if (ab->mode == USB_PERIPHERAL) ab8500_usb_peri_phy_dis(ab); - - return 0; } static const struct platform_device_id ab8500_usb_devtype[] = { @@ -989,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); static struct platform_driver ab8500_usb_driver = { .probe = ab8500_usb_probe, - .remove = ab8500_usb_remove, + .remove_new = ab8500_usb_remove, .id_table = ab8500_usb_devtype, .driver = { .name = "abx5x0-usb", diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 8524475d942d..e39665cf4b4a 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -82,12 +82,11 @@ static int am335x_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&am_phy->usb_phy_gen.phy); } -static int am335x_phy_remove(struct platform_device *pdev) +static void am335x_phy_remove(struct platform_device *pdev) { struct am335x_phy *am_phy = platform_get_drvdata(pdev); usb_remove_phy(&am_phy->usb_phy_gen.phy); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -134,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids); static struct platform_driver am335x_phy_driver = { .probe = am335x_phy_probe, - .remove = am335x_phy_remove, + .remove_new = am335x_phy_remove, .driver = { .name = "am335x-phy-driver", .pm = &am335x_pm_ops, diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 972704262b02..79617bb0a70e 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -983,7 +983,7 @@ static int fsl_otg_probe(struct platform_device *pdev) return ret; } -static int fsl_otg_remove(struct platform_device *pdev) +static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -998,13 +998,11 @@ static int fsl_otg_remove(struct platform_device *pdev) if (pdata->exit) pdata->exit(pdev); - - return 0; } struct platform_driver fsl_otg_driver = { .probe = fsl_otg_probe, - .remove = fsl_otg_remove, + .remove_new = fsl_otg_remove, .driver = { .name = driver_name, .owner = THIS_MODULE, diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index c1309ea24a52..770081b828a4 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -330,13 +330,11 @@ static int usb_phy_generic_probe(struct platform_device *pdev) return 0; } -static int usb_phy_generic_remove(struct platform_device *pdev) +static void usb_phy_generic_remove(struct platform_device *pdev) { struct usb_phy_generic *nop = platform_get_drvdata(pdev); usb_remove_phy(&nop->phy); - - return 0; } static const struct of_device_id nop_xceiv_dt_ids[] = { @@ -348,7 +346,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); static struct platform_driver usb_phy_generic_driver = { .probe = usb_phy_generic_probe, - .remove = usb_phy_generic_remove, + .remove_new = usb_phy_generic_remove, .driver = { .name = "usb_phy_generic", .of_match_table = nop_xceiv_dt_ids, diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 12dfeff7de3d..817c242a76ca 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -325,7 +325,7 @@ static int gpio_vbus_probe(struct platform_device *pdev) return 0; } -static int gpio_vbus_remove(struct platform_device *pdev) +static void gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); @@ -333,8 +333,6 @@ static int gpio_vbus_remove(struct platform_device *pdev) cancel_delayed_work_sync(&gpio_vbus->work); usb_remove_phy(&gpio_vbus->phy); - - return 0; } #ifdef CONFIG_PM @@ -386,7 +384,7 @@ static struct platform_driver gpio_vbus_driver = { .of_match_table = gpio_vbus_of_match, }, .probe = gpio_vbus_probe, - .remove = gpio_vbus_remove, + .remove_new = gpio_vbus_remove, }; module_platform_driver(gpio_vbus_driver); diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index f75912279b39..bd9a98ad1b30 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -88,13 +88,11 @@ static int keystone_usbphy_probe(struct platform_device *pdev) return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } -static int keystone_usbphy_remove(struct platform_device *pdev) +static void keystone_usbphy_remove(struct platform_device *pdev) { struct keystone_usbphy *k_phy = platform_get_drvdata(pdev); usb_remove_phy(&k_phy->usb_phy_gen.phy); - - return 0; } static const struct of_device_id keystone_usbphy_ids[] = { @@ -105,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); static struct platform_driver keystone_usbphy_driver = { .probe = keystone_usbphy_probe, - .remove = keystone_usbphy_remove, + .remove_new = keystone_usbphy_remove, .driver = { .name = "keystone-usbphy", .of_match_table = keystone_usbphy_ids, diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 86503b7d695c..df7c27474a75 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -644,7 +644,7 @@ static const struct attribute_group *mv_otg_groups[] = { NULL, }; -static int mv_otg_remove(struct platform_device *pdev) +static void mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); @@ -654,8 +654,6 @@ static int mv_otg_remove(struct platform_device *pdev) mv_otg_disable(mvotg); usb_remove_phy(&mvotg->phy); - - return 0; } static int mv_otg_probe(struct platform_device *pdev) @@ -869,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove = mv_otg_remove, + .remove_new = mv_otg_remove, .driver = { .name = driver_name, .dev_groups = mv_otg_groups, diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index d2836ef5d15c..e1a2b2ea098b 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -733,7 +733,7 @@ static int mxs_phy_probe(struct platform_device *pdev) return -ENOMEM; /* Some SoCs don't have anatop registers */ - if (of_get_property(np, "fsl,anatop", NULL)) { + if (of_property_present(np, "fsl,anatop")) { mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle (np, "fsl,anatop"); if (IS_ERR(mxs_phy->regmap_anatop)) { @@ -801,13 +801,11 @@ static int mxs_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&mxs_phy->phy); } -static int mxs_phy_remove(struct platform_device *pdev) +static void mxs_phy_remove(struct platform_device *pdev) { struct mxs_phy *mxs_phy = platform_get_drvdata(pdev); usb_remove_phy(&mxs_phy->phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -853,7 +851,7 @@ static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend, static struct platform_driver mxs_phy_driver = { .probe = mxs_phy_probe, - .remove = mxs_phy_remove, + .remove_new = mxs_phy_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mxs_phy_dt_ids, diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index f2d2cc586c5b..47562d49dfc1 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -412,7 +412,7 @@ err_disable_clk: return ret; } -static int tahvo_usb_remove(struct platform_device *pdev) +static void tahvo_usb_remove(struct platform_device *pdev) { struct tahvo_usb *tu = platform_get_drvdata(pdev); @@ -420,13 +420,11 @@ static int tahvo_usb_remove(struct platform_device *pdev) usb_remove_phy(&tu->phy); if (!IS_ERR(tu->ick)) clk_disable(tu->ick); - - return 0; } static struct platform_driver tahvo_usb_driver = { .probe = tahvo_usb_probe, - .remove = tahvo_usb_remove, + .remove_new = tahvo_usb_remove, .driver = { .name = "tahvo-usb", .dev_groups = tahvo_groups, diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index f0240107edb1..8b2ff3a8882d 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1375,7 +1375,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); - if (of_find_property(np, "dr_mode", NULL)) + if (of_property_present(np, "dr_mode")) tegra_phy->mode = usb_get_dr_mode(&pdev->dev); else tegra_phy->mode = USB_DR_MODE_HOST; @@ -1486,18 +1486,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&tegra_phy->u_phy); } -static int tegra_usb_phy_remove(struct platform_device *pdev) +static void tegra_usb_phy_remove(struct platform_device *pdev) { struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); usb_remove_phy(&tegra_phy->u_phy); - - return 0; } static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, - .remove = tegra_usb_phy_remove, + .remove_new = tegra_usb_phy_remove, .driver = { .name = "tegra-phy", .of_match_table = tegra_usb_phy_id_table, diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index ab3c38a7d8ac..c3ce6b1054f1 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -409,7 +409,7 @@ err_put_regulator: return status; } -static int twl6030_usb_remove(struct platform_device *pdev) +static void twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); @@ -422,8 +422,6 @@ static int twl6030_usb_remove(struct platform_device *pdev) free_irq(twl->irq2, twl); regulator_put(twl->usb3v3); cancel_work_sync(&twl->set_vbus_work); - - return 0; } static const struct of_device_id twl6030_usb_id_table[] = { @@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, - .remove = twl6030_usb_remove, + .remove_new = twl6030_usb_remove, .driver = { .name = "twl6030_usb", .of_match_table = of_match_ptr(twl6030_usb_id_table), diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 96f3939a65e2..fa34efabcccf 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -823,7 +823,7 @@ static struct platform_driver renesas_usbhs_driver = { .driver = { .name = "renesas_usbhs", .pm = &usbhsc_pm_ops, - .of_match_table = of_match_ptr(usbhs_of_match), + .of_match_table = usbhs_of_match, }, .probe = usbhs_probe, .remove = usbhs_remove, diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 56814ef80c24..0395bd5dbd3e 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -392,7 +392,7 @@ EXPORT_SYMBOL_GPL(usb_role_switch_get_drvdata); static int __init usb_roles_init(void) { - role_class = class_create(THIS_MODULE, "usb_role"); + role_class = class_create("usb_role"); return PTR_ERR_OR_ZERO(role_class); } subsys_initcall(usb_roles_init); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 9e38142acd38..3eb8dc3a1a8f 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -144,7 +144,7 @@ static void free_dynids(struct usb_serial_driver *drv) spin_unlock(&drv->dynids.lock); } -struct bus_type usb_serial_bus_type = { +const struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f31cc3c76329..644a55447fd7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -595,6 +595,11 @@ static void option_instat_callback(struct urb *urb); #define SIERRA_VENDOR_ID 0x1199 #define SIERRA_PRODUCT_EM9191 0x90d3 +/* UNISOC (Spreadtrum) products */ +#define UNISOC_VENDOR_ID 0x1782 +/* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */ +#define TOZED_PRODUCT_LT70C 0x4055 + /* Device flags */ /* Highest interface number which can be used with NCTRL() and RSVD() */ @@ -2225,6 +2230,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(OPPO_VENDOR_ID, OPPO_PRODUCT_R11, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 6fca40ace83a..fee581409bf6 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -176,14 +176,6 @@ static inline int qt2_control_msg(struct usb_device *dev, NULL, 0, QT2_USB_TIMEOUT); } -static inline int qt2_setdevice(struct usb_device *dev, u8 *data) -{ - u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); - - return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); -} - - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 8931df5a85fd..c54e9805da53 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -406,22 +406,25 @@ static DEF_SCSI_QCMD(queuecommand) ***********************************************************************/ /* Command timeout and abort */ -static int command_abort(struct scsi_cmnd *srb) +static int command_abort_matching(struct us_data *us, struct scsi_cmnd *srb_match) { - struct us_data *us = host_to_us(srb->device->host); - - usb_stor_dbg(us, "%s called\n", __func__); - /* * us->srb together with the TIMED_OUT, RESETTING, and ABORTING * bits are protected by the host lock. */ scsi_lock(us_to_host(us)); - /* Is this command still active? */ - if (us->srb != srb) { + /* is there any active pending command to abort ? */ + if (!us->srb) { scsi_unlock(us_to_host(us)); usb_stor_dbg(us, "-- nothing to abort\n"); + return SUCCESS; + } + + /* Does the command match the passed srb if any ? */ + if (srb_match && us->srb != srb_match) { + scsi_unlock(us_to_host(us)); + usb_stor_dbg(us, "-- pending command mismatch\n"); return FAILED; } @@ -444,6 +447,14 @@ static int command_abort(struct scsi_cmnd *srb) return SUCCESS; } +static int command_abort(struct scsi_cmnd *srb) +{ + struct us_data *us = host_to_us(srb->device->host); + + usb_stor_dbg(us, "%s called\n", __func__); + return command_abort_matching(us, srb); +} + /* * This invokes the transport reset mechanism to reset the state of the * device @@ -455,6 +466,9 @@ static int device_reset(struct scsi_cmnd *srb) usb_stor_dbg(us, "%s called\n", __func__); + /* abort any pending command before reset */ + command_abort_matching(us, NULL); + /* lock the device pointers and do the reset */ mutex_lock(&(us->dev_mutex)); result = us->transport_reset(us); diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 8f3e884222ad..66de880b28d0 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -516,6 +516,10 @@ static ssize_t pin_assignment_show(struct device *dev, mutex_unlock(&dp->lock); + /* get_current_pin_assignments can return 0 when no matching pin assignments are found */ + if (len == 0) + len++; + buf[len - 1] = '\n'; return len; } diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c index 098f0efaa58d..fe5b9a2e61f5 100644 --- a/drivers/usb/typec/bus.c +++ b/drivers/usb/typec/bus.c @@ -431,7 +431,7 @@ static void typec_remove(struct device *dev) adev->ops = NULL; } -struct bus_type typec_bus = { +const struct bus_type typec_bus = { .name = "typec", .dev_groups = typec_groups, .match = typec_match, diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h index c89168857417..643b8c81786d 100644 --- a/drivers/usb/typec/bus.h +++ b/drivers/usb/typec/bus.h @@ -28,7 +28,7 @@ struct altmode { #define to_altmode(d) container_of(d, struct altmode, adev) -extern struct bus_type typec_bus; +extern const struct bus_type typec_bus; extern const struct device_type typec_altmode_dev_type; #define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index cc3182f70673..349cc2030c90 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -22,7 +22,6 @@ static DEFINE_IDA(typec_index_ida); struct class typec_class = { .name = "typec", - .owner = THIS_MODULE, }; /* ------------------------------------------------------------------------- */ diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c index 746ef3a75b76..8bbeb9b1e439 100644 --- a/drivers/usb/typec/hd3ss3220.c +++ b/drivers/usb/typec/hd3ss3220.c @@ -290,7 +290,7 @@ MODULE_DEVICE_TABLE(of, dev_ids); static struct i2c_driver hd3ss3220_driver = { .driver = { .name = "hd3ss3220", - .of_match_table = of_match_ptr(dev_ids), + .of_match_table = dev_ids, }, .probe_new = hd3ss3220_probe, .remove = hd3ss3220_remove, diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index c7177ddd4f12..d9eaf9a0b0bf 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -514,5 +514,4 @@ EXPORT_SYMBOL_GPL(typec_mux_get_drvdata); struct class typec_mux_class = { .name = "typec_mux", - .owner = THIS_MODULE, }; diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c index 59c537a5e600..0bcde1ff4d39 100644 --- a/drivers/usb/typec/pd.c +++ b/drivers/usb/typec/pd.c @@ -15,7 +15,6 @@ static DEFINE_IDA(pd_ida); static struct class pd_class = { .name = "usb_power_delivery", - .owner = THIS_MODULE, }; #define to_pdo(o) container_of(o, struct pdo, dev) diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c index 0481e82f6bbc..4a7d1b5c4d86 100644 --- a/drivers/usb/typec/retimer.c +++ b/drivers/usb/typec/retimer.c @@ -157,5 +157,4 @@ EXPORT_SYMBOL_GPL(typec_retimer_get_drvdata); struct class retimer_class = { .name = "retimer", - .owner = THIS_MODULE, }; diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 1ffce00d94b4..62ba53357612 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -190,7 +190,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...) static int fusb302_debug_show(struct seq_file *s, void *v) { - struct fusb302_chip *chip = (struct fusb302_chip *)s->private; + struct fusb302_chip *chip = s->private; int tail; mutex_lock(&chip->logbuffer_lock); @@ -1813,7 +1813,7 @@ static int fusb302_pm_resume(struct device *dev) return 0; } -static const struct of_device_id fusb302_dt_match[] = { +static const struct of_device_id fusb302_dt_match[] __maybe_unused = { {.compatible = "fcs,fusb302"}, {}, }; diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c index 1b7c31278ebb..6fa8fd5c8041 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6360.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -43,12 +43,6 @@ struct mt6360_tcpc_info { int irq; }; -static inline int mt6360_tcpc_read16(struct regmap *regmap, - unsigned int reg, u16 *val) -{ - return regmap_raw_read(regmap, reg, val, sizeof(u16)); -} - static inline int mt6360_tcpc_write16(struct regmap *regmap, unsigned int reg, u16 val) { diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 1ee774c263f0..3c6b0c8e2d3a 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -737,7 +737,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port) static int tcpm_debug_show(struct seq_file *s, void *v) { - struct tcpm_port *port = (struct tcpm_port *)s->private; + struct tcpm_port *port = s->private; int tail; mutex_lock(&port->logbuffer_lock); @@ -1523,7 +1523,21 @@ static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt) pmdata->svids[pmdata->nsvids++] = svid; tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid); } - return true; + + /* + * PD3.0 Spec 6.4.4.3.2: The SVIDs are returned 2 per VDO (see Table + * 6-43), and can be returned maximum 6 VDOs per response (see Figure + * 6-19). If the Respondersupports 12 or more SVID then the Discover + * SVIDs Command Shall be executed multiple times until a Discover + * SVIDs VDO is returned ending either with a SVID value of 0x0000 in + * the last part of the last VDO or with a VDO containing two SVIDs + * with values of 0x0000. + * + * However, some odd dockers support SVIDs less than 12 but without + * 0x0000 in the last VDO, so we need to break the Discover SVIDs + * request and return false here. + */ + return cnt == 7; abort: tcpm_log(port, "SVID_DISCOVERY_MAX(%d) too low!", SVID_DISCOVERY_MAX); return false; @@ -6577,6 +6591,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->port_type = port->typec_caps.type; port->role_sw = usb_role_switch_get(port->dev); + if (!port->role_sw) + port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); if (IS_ERR(port->role_sw)) { err = PTR_ERR(port->role_sw); goto out_destroy_wq; diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 485b90c13078..603dbd44deba 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "tps6598x.h" #include "trace.h" @@ -97,6 +98,8 @@ struct tps6598x { int wakeup; u16 pwr_status; + struct delayed_work wq_poll; + irq_handler_t irq_handler; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -177,16 +180,6 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) return tps6598x_block_read(tps, reg, val, sizeof(u64)); } -static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u16)); -} - -static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u32)); -} - static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { return tps6598x_block_write(tps, reg, &val, sizeof(u64)); @@ -568,6 +561,18 @@ err_unlock: return IRQ_NONE; } +/* Time interval for Polling */ +#define POLL_INTERVAL 500 /* msecs */ +static void tps6598x_poll_work(struct work_struct *work) +{ + struct tps6598x *tps = container_of(to_delayed_work(work), + struct tps6598x, wq_poll); + + tps->irq_handler(0, tps); + queue_delayed_work(system_power_efficient_wq, + &tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL)); +} + static int tps6598x_check_mode(struct tps6598x *tps) { char mode[5] = { }; @@ -746,6 +751,7 @@ static int tps6598x_probe(struct i2c_client *client) TPS_REG_INT_PLUG_EVENT; } + tps->irq_handler = irq_handler; /* Make sure the controller has application firmware running */ ret = tps6598x_check_mode(tps); if (ret) @@ -837,10 +843,18 @@ static int tps6598x_probe(struct i2c_client *client) dev_err(&client->dev, "failed to register partner\n"); } - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - dev_name(&client->dev), tps); + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, + irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + dev_name(&client->dev), tps); + } else { + dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n"); + INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work); + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + } + if (ret) goto err_disconnect; @@ -848,7 +862,7 @@ static int tps6598x_probe(struct i2c_client *client) fwnode_handle_put(fwnode); tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source"); - if (tps->wakeup) { + if (tps->wakeup && client->irq) { device_init_wakeup(&client->dev, true); enable_irq_wake(client->irq); } @@ -872,6 +886,9 @@ static void tps6598x_remove(struct i2c_client *client) { struct tps6598x *tps = i2c_get_clientdata(client); + if (!client->irq) + cancel_delayed_work_sync(&tps->wq_poll); + tps6598x_disconnect(tps, 0); typec_unregister_port(tps->port); usb_role_switch_put(tps->role_sw); @@ -887,6 +904,9 @@ static int __maybe_unused tps6598x_suspend(struct device *dev) enable_irq_wake(client->irq); } + if (!client->irq) + cancel_delayed_work_sync(&tps->wq_poll); + return 0; } @@ -900,6 +920,10 @@ static int __maybe_unused tps6598x_resume(struct device *dev) enable_irq(client->irq); } + if (!client->irq) + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + return 0; } diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 8f9c4b9f31f7..b3bb0191987e 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -58,4 +58,14 @@ config UCSI_STM32G0 To compile the driver as a module, choose M here: the module will be called ucsi_stm32g0. +config UCSI_PMIC_GLINK + tristate "UCSI Qualcomm PMIC GLINK Interface Driver" + depends on QCOM_PMIC_GLINK + help + This driver enables UCSI support on platforms that expose UCSI + interface as PMIC GLINK device. + + To compile the driver as a module, choose M here: the module will be + called ucsi_glink. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 480d533d762f..77f09e136956 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -18,3 +18,4 @@ endif obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o +obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 8d1baf28df55..2b472ec01dc4 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1444,11 +1444,13 @@ static void ucsi_init_work(struct work_struct *work) ret = ucsi_init(ucsi); if (ret) - dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); + dev_err_probe(ucsi->dev, ret, "PPM init failed\n"); if (ret == -EPROBE_DEFER) { - if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) + if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) { + dev_err(ucsi->dev, "PPM init failed, stop trying\n"); return; + } queue_delayed_work(system_long_wq, &ucsi->work, UCSI_ROLE_SWITCH_INTERVAL); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 62206a6b8ea7..217355f1f9b9 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ucsi.h" @@ -23,6 +24,7 @@ struct ucsi_acpi { struct completion complete; unsigned long flags; guid_t guid; + u64 cmd; }; static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) @@ -62,6 +64,7 @@ static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); memcpy(ua->base + offset, val, val_len); + ua->cmd = *(u64 *)val; return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } @@ -93,13 +96,46 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_write = ucsi_acpi_async_write }; +static int +ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + } + + memcpy(val, ua->base + offset, val_len); + + return 0; +} + +static const struct ucsi_operations ucsi_zenbook_ops = { + .read = ucsi_zenbook_read, + .sync_write = ucsi_acpi_sync_write, + .async_write = ucsi_acpi_async_write +}; + +static const struct dmi_system_id zenbook_dmi_id[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), + }, + }, + { } +}; + static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ucsi_acpi *ua = data; u32 cci; int ret; - ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) return; @@ -114,6 +150,7 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) static int ucsi_acpi_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + const struct ucsi_operations *ops = &ucsi_acpi_ops; struct ucsi_acpi *ua; struct resource *res; acpi_status status; @@ -143,7 +180,10 @@ static int ucsi_acpi_probe(struct platform_device *pdev) init_completion(&ua->complete); ua->dev = &pdev->dev; - ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops); + if (dmi_check_system(zenbook_dmi_id)) + ops = &ucsi_zenbook_ops; + + ua->ucsi = ucsi_create(&pdev->dev, ops); if (IS_ERR(ua->ucsi)) return PTR_ERR(ua->ucsi); diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c new file mode 100644 index 000000000000..b454a5159896 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include "ucsi.h" + +#define UCSI_BUF_SIZE 48 + +#define MSG_TYPE_REQ_RESP 1 +#define UCSI_BUF_SIZE 48 + +#define UC_NOTIFY_RECEIVER_UCSI 0x0 +#define UC_UCSI_READ_BUF_REQ 0x11 +#define UC_UCSI_WRITE_BUF_REQ 0x12 +#define UC_UCSI_USBC_NOTIFY_IND 0x13 + +struct ucsi_read_buf_req_msg { + struct pmic_glink_hdr hdr; +}; + +struct ucsi_read_buf_resp_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 ret_code; +}; + +struct ucsi_write_buf_req_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 reserved; +}; + +struct ucsi_write_buf_resp_msg { + struct pmic_glink_hdr hdr; + u32 ret_code; +}; + +struct ucsi_notify_ind_msg { + struct pmic_glink_hdr hdr; + u32 notification; + u32 receiver; + u32 reserved; +}; + +struct pmic_glink_ucsi { + struct device *dev; + + struct pmic_glink_client *client; + + struct ucsi *ucsi; + struct completion read_ack; + struct completion write_ack; + struct completion sync_ack; + bool sync_pending; + struct mutex lock; /* protects concurrent access to PMIC Glink interface */ + + int sync_val; + + struct work_struct notify_work; + struct work_struct register_work; + + u8 read_buf[UCSI_BUF_SIZE]; +}; + +static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, + void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + struct ucsi_read_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_READ_BUF_REQ; + + mutex_lock(&ucsi->lock); + memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); + reinit_completion(&ucsi->read_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret); + goto out_unlock; + } + + left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI read response\n"); + ret = -ETIMEDOUT; + goto out_unlock; + } + + memcpy(val, &ucsi->read_buf[offset], val_len); + ret = 0; + +out_unlock: + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct ucsi_write_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; + memcpy(&req.buf[offset], val, val_len); + + reinit_completion(&ucsi->write_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); + return ret; + } + + left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI write response\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + int ret; + + mutex_lock(&ucsi->lock); + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + unsigned long left; + int ret; + + /* TOFIX: Downstream forces recipient to CON when UCSI_GET_ALTERNATE_MODES command */ + + mutex_lock(&ucsi->lock); + ucsi->sync_val = 0; + reinit_completion(&ucsi->sync_ack); + ucsi->sync_pending = true; + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); + ret = -ETIMEDOUT; + } else if (ucsi->sync_val) { + dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); + } + + ucsi->sync_pending = false; + + return ret; +} + +static const struct ucsi_operations pmic_glink_ucsi_ops = { + .read = pmic_glink_ucsi_read, + .sync_write = pmic_glink_ucsi_sync_write, + .async_write = pmic_glink_ucsi_async_write +}; + +static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_read_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE); + complete(&ucsi->read_ack); +} + +static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_write_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + ucsi->sync_val = resp->ret_code; + complete(&ucsi->write_ack); +} + +static void pmic_glink_ucsi_notify(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work); + unsigned int con_num; + u32 cci; + int ret; + + ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); + if (ret) { + dev_err(ucsi->dev, "failed to read CCI on notification\n"); + return; + } + + con_num = UCSI_CCI_CONNECTOR(cci); + if (con_num) + ucsi_connector_change(ucsi->ucsi, con_num); + + if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { + ucsi->sync_val = -EBUSY; + complete(&ucsi->sync_ack); + } else if (ucsi->sync_pending && + (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { + complete(&ucsi->sync_ack); + } +} + +static void pmic_glink_ucsi_register(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + + ucsi_register(ucsi->ucsi); +} + +static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) +{ + struct pmic_glink_ucsi *ucsi = priv; + const struct pmic_glink_hdr *hdr = data; + + switch (hdr->opcode) { + case UC_UCSI_READ_BUF_REQ: + pmic_glink_ucsi_read_ack(ucsi, data, len); + break; + case UC_UCSI_WRITE_BUF_REQ: + pmic_glink_ucsi_write_ack(ucsi, data, len); + break; + case UC_UCSI_USBC_NOTIFY_IND: + schedule_work(&ucsi->notify_work); + break; + }; +} + +static void pmic_glink_ucsi_pdr_notify(void *priv, int state) +{ + struct pmic_glink_ucsi *ucsi = priv; + + if (state == SERVREG_SERVICE_STATE_UP) + schedule_work(&ucsi->register_work); + else if (state == SERVREG_SERVICE_STATE_DOWN) + ucsi_unregister(ucsi->ucsi); +} + +static void pmic_glink_ucsi_destroy(void *data) +{ + struct pmic_glink_ucsi *ucsi = data; + + /* Protect to make sure we're not in a middle of a transaction from a glink callback */ + mutex_lock(&ucsi->lock); + ucsi_destroy(ucsi->ucsi); + mutex_unlock(&ucsi->lock); +} + +static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct pmic_glink_ucsi *ucsi; + struct device *dev = &adev->dev; + int ret; + + ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); + if (!ucsi) + return -ENOMEM; + + ucsi->dev = dev; + dev_set_drvdata(dev, ucsi); + + INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify); + INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); + init_completion(&ucsi->read_ack); + init_completion(&ucsi->write_ack); + init_completion(&ucsi->sync_ack); + mutex_init(&ucsi->lock); + + ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); + if (IS_ERR(ucsi->ucsi)) + return PTR_ERR(ucsi->ucsi); + + /* Make sure we destroy *after* pmic_glink unregister */ + ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi); + if (ret) + return ret; + + ucsi_set_drvdata(ucsi->ucsi, ucsi); + + ucsi->client = devm_pmic_glink_register_client(dev, + PMIC_GLINK_OWNER_USBC, + pmic_glink_ucsi_callback, + pmic_glink_ucsi_pdr_notify, + ucsi); + return PTR_ERR_OR_ZERO(ucsi->client); +} + +static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) +{ + struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); + + /* Unregister first to stop having read & writes */ + ucsi_unregister(ucsi->ucsi); +} + +static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { + { .name = "pmic_glink.ucsi", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table); + +static struct auxiliary_driver pmic_glink_ucsi_driver = { + .name = "pmic_glink_ucsi", + .probe = pmic_glink_ucsi_probe, + .remove = pmic_glink_ucsi_remove, + .id_table = pmic_glink_ucsi_id_table, +}; + +module_auxiliary_driver(pmic_glink_ucsi_driver); + +MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 195963b82b63..e29e32b306ad 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -778,12 +778,28 @@ static bool vq_is_tx(u16 idx) return idx % 2; } -static u16 get_features_12_3(u64 features) +enum { + MLX5_VIRTIO_NET_F_MRG_RXBUF = 2, + MLX5_VIRTIO_NET_F_HOST_ECN = 4, + MLX5_VIRTIO_NET_F_GUEST_ECN = 6, + MLX5_VIRTIO_NET_F_GUEST_TSO6 = 7, + MLX5_VIRTIO_NET_F_GUEST_TSO4 = 8, + MLX5_VIRTIO_NET_F_GUEST_CSUM = 9, + MLX5_VIRTIO_NET_F_CSUM = 10, + MLX5_VIRTIO_NET_F_HOST_TSO6 = 11, + MLX5_VIRTIO_NET_F_HOST_TSO4 = 12, +}; + +static u16 get_features(u64 features) { - return (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << 9) | - (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << 8) | - (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << 7) | - (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_CSUM)) << 6); + return (!!(features & BIT_ULL(VIRTIO_NET_F_MRG_RXBUF)) << MLX5_VIRTIO_NET_F_MRG_RXBUF) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_ECN)) << MLX5_VIRTIO_NET_F_HOST_ECN) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_ECN)) << MLX5_VIRTIO_NET_F_GUEST_ECN) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO6)) << MLX5_VIRTIO_NET_F_GUEST_TSO6) | + (!!(features & BIT_ULL(VIRTIO_NET_F_GUEST_TSO4)) << MLX5_VIRTIO_NET_F_GUEST_TSO4) | + (!!(features & BIT_ULL(VIRTIO_NET_F_CSUM)) << MLX5_VIRTIO_NET_F_CSUM) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO6)) << MLX5_VIRTIO_NET_F_HOST_TSO6) | + (!!(features & BIT_ULL(VIRTIO_NET_F_HOST_TSO4)) << MLX5_VIRTIO_NET_F_HOST_TSO4); } static bool counters_supported(const struct mlx5_vdpa_dev *mvdev) @@ -797,6 +813,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque int inlen = MLX5_ST_SZ_BYTES(create_virtio_net_q_in); u32 out[MLX5_ST_SZ_DW(create_virtio_net_q_out)] = {}; void *obj_context; + u16 mlx_features; void *cmd_hdr; void *vq_ctx; void *in; @@ -812,6 +829,7 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque goto err_alloc; } + mlx_features = get_features(ndev->mvdev.actual_features); cmd_hdr = MLX5_ADDR_OF(create_virtio_net_q_in, in, general_obj_in_cmd_hdr); MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); @@ -822,7 +840,9 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx); MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx); MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_12_3, - get_features_12_3(ndev->mvdev.actual_features)); + mlx_features >> 3); + MLX5_SET(virtio_net_q_object, obj_context, queue_feature_bit_mask_2_0, + mlx_features & 7); vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context); MLX5_SET(virtio_q, vq_ctx, virtio_q_type, get_queue_type(ndev)); @@ -2171,23 +2191,27 @@ static u32 mlx5_vdpa_get_vq_group(struct vdpa_device *vdev, u16 idx) return MLX5_VDPA_DATAVQ_GROUP; } -enum { MLX5_VIRTIO_NET_F_GUEST_CSUM = 1 << 9, - MLX5_VIRTIO_NET_F_CSUM = 1 << 10, - MLX5_VIRTIO_NET_F_HOST_TSO6 = 1 << 11, - MLX5_VIRTIO_NET_F_HOST_TSO4 = 1 << 12, -}; - static u64 mlx_to_vritio_features(u16 dev_features) { u64 result = 0; - if (dev_features & MLX5_VIRTIO_NET_F_GUEST_CSUM) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_MRG_RXBUF)) + result |= BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_ECN)) + result |= BIT_ULL(VIRTIO_NET_F_HOST_ECN); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_ECN)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_ECN); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO6)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO6); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_TSO4)) + result |= BIT_ULL(VIRTIO_NET_F_GUEST_TSO4); + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_GUEST_CSUM)) result |= BIT_ULL(VIRTIO_NET_F_GUEST_CSUM); - if (dev_features & MLX5_VIRTIO_NET_F_CSUM) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_CSUM)) result |= BIT_ULL(VIRTIO_NET_F_CSUM); - if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO6) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO6)) result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO6); - if (dev_features & MLX5_VIRTIO_NET_F_HOST_TSO4) + if (dev_features & BIT_ULL(MLX5_VIRTIO_NET_F_HOST_TSO4)) result |= BIT_ULL(VIRTIO_NET_F_HOST_TSO4); return result; @@ -2298,6 +2322,113 @@ static void update_cvq_info(struct mlx5_vdpa_dev *mvdev) } } +static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) +{ + u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; + int err; + + MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); + MLX5_SET(query_vport_state_in, in, op_mod, opmod); + MLX5_SET(query_vport_state_in, in, vport_number, vport); + if (vport) + MLX5_SET(query_vport_state_in, in, other_vport, 1); + + err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); + if (err) + return 0; + + return MLX5_GET(query_vport_state_out, out, state); +} + +static bool get_link_state(struct mlx5_vdpa_dev *mvdev) +{ + if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == + VPORT_STATE_UP) + return true; + + return false; +} + +static void update_carrier(struct work_struct *work) +{ + struct mlx5_vdpa_wq_ent *wqent; + struct mlx5_vdpa_dev *mvdev; + struct mlx5_vdpa_net *ndev; + + wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); + mvdev = wqent->mvdev; + ndev = to_mlx5_vdpa_ndev(mvdev); + if (get_link_state(mvdev)) + ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); + else + ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); + + if (ndev->config_cb.callback) + ndev->config_cb.callback(ndev->config_cb.private); + + kfree(wqent); +} + +static int queue_link_work(struct mlx5_vdpa_net *ndev) +{ + struct mlx5_vdpa_wq_ent *wqent; + + wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); + if (!wqent) + return -ENOMEM; + + wqent->mvdev = &ndev->mvdev; + INIT_WORK(&wqent->work, update_carrier); + queue_work(ndev->mvdev.wq, &wqent->work); + return 0; +} + +static int event_handler(struct notifier_block *nb, unsigned long event, void *param) +{ + struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); + struct mlx5_eqe *eqe = param; + int ret = NOTIFY_DONE; + + if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { + switch (eqe->sub_type) { + case MLX5_PORT_CHANGE_SUBTYPE_DOWN: + case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: + if (queue_link_work(ndev)) + return NOTIFY_DONE; + + ret = NOTIFY_OK; + break; + default: + return NOTIFY_DONE; + } + return ret; + } + return ret; +} + +static void register_link_notifier(struct mlx5_vdpa_net *ndev) +{ + if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) + return; + + ndev->nb.notifier_call = event_handler; + mlx5_notifier_register(ndev->mvdev.mdev, &ndev->nb); + ndev->nb_registered = true; + queue_link_work(ndev); +} + +static void unregister_link_notifier(struct mlx5_vdpa_net *ndev) +{ + if (!ndev->nb_registered) + return; + + ndev->nb_registered = false; + mlx5_notifier_unregister(ndev->mvdev.mdev, &ndev->nb); + if (ndev->mvdev.wq) + flush_workqueue(ndev->mvdev.wq); +} + static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); @@ -2567,10 +2698,11 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) mlx5_vdpa_warn(mvdev, "failed to setup control VQ vring\n"); goto err_setup; } + register_link_notifier(ndev); err = setup_driver(mvdev); if (err) { mlx5_vdpa_warn(mvdev, "failed to setup driver\n"); - goto err_setup; + goto err_driver; } } else { mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); @@ -2582,6 +2714,8 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) up_write(&ndev->reslock); return; +err_driver: + unregister_link_notifier(ndev); err_setup: mlx5_vdpa_destroy_mr(&ndev->mvdev); ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; @@ -2607,6 +2741,7 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev) mlx5_vdpa_info(mvdev, "performing device reset\n"); down_write(&ndev->reslock); + unregister_link_notifier(ndev); teardown_driver(ndev); clear_vqs_ready(ndev); mlx5_vdpa_destroy_mr(&ndev->mvdev); @@ -2861,9 +2996,7 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev) mlx5_vdpa_info(mvdev, "suspending device\n"); down_write(&ndev->reslock); - ndev->nb_registered = false; - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); - flush_workqueue(ndev->mvdev.wq); + unregister_link_notifier(ndev); for (i = 0; i < ndev->cur_num_vqs; i++) { mvq = &ndev->vqs[i]; suspend_vq(ndev, mvq); @@ -3000,84 +3133,6 @@ struct mlx5_vdpa_mgmtdev { struct mlx5_vdpa_net *ndev; }; -static u8 query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport) -{ - u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; - int err; - - MLX5_SET(query_vport_state_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_STATE); - MLX5_SET(query_vport_state_in, in, op_mod, opmod); - MLX5_SET(query_vport_state_in, in, vport_number, vport); - if (vport) - MLX5_SET(query_vport_state_in, in, other_vport, 1); - - err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); - if (err) - return 0; - - return MLX5_GET(query_vport_state_out, out, state); -} - -static bool get_link_state(struct mlx5_vdpa_dev *mvdev) -{ - if (query_vport_state(mvdev->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0) == - VPORT_STATE_UP) - return true; - - return false; -} - -static void update_carrier(struct work_struct *work) -{ - struct mlx5_vdpa_wq_ent *wqent; - struct mlx5_vdpa_dev *mvdev; - struct mlx5_vdpa_net *ndev; - - wqent = container_of(work, struct mlx5_vdpa_wq_ent, work); - mvdev = wqent->mvdev; - ndev = to_mlx5_vdpa_ndev(mvdev); - if (get_link_state(mvdev)) - ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP); - else - ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP); - - if (ndev->nb_registered && ndev->config_cb.callback) - ndev->config_cb.callback(ndev->config_cb.private); - - kfree(wqent); -} - -static int event_handler(struct notifier_block *nb, unsigned long event, void *param) -{ - struct mlx5_vdpa_net *ndev = container_of(nb, struct mlx5_vdpa_net, nb); - struct mlx5_eqe *eqe = param; - int ret = NOTIFY_DONE; - struct mlx5_vdpa_wq_ent *wqent; - - if (event == MLX5_EVENT_TYPE_PORT_CHANGE) { - if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS))) - return NOTIFY_DONE; - switch (eqe->sub_type) { - case MLX5_PORT_CHANGE_SUBTYPE_DOWN: - case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE: - wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); - if (!wqent) - return NOTIFY_DONE; - - wqent->mvdev = &ndev->mvdev; - INIT_WORK(&wqent->work, update_carrier); - queue_work(ndev->mvdev.wq, &wqent->work); - ret = NOTIFY_OK; - break; - default: - return NOTIFY_DONE; - } - return ret; - } - return ret; -} - static int config_func_mtu(struct mlx5_core_dev *mdev, u16 mtu) { int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); @@ -3127,6 +3182,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, return -EINVAL; } device_features &= add_config->device_features; + } else { + device_features &= ~BIT_ULL(VIRTIO_NET_F_MRG_RXBUF); } if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) && device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) { @@ -3258,9 +3315,6 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, goto err_res2; } - ndev->nb.notifier_call = event_handler; - mlx5_notifier_register(mdev, &ndev->nb); - ndev->nb_registered = true; mvdev->vdev.mdev = &mgtdev->mgtdev; err = _vdpa_register_device(&mvdev->vdev, max_vqs + 1); if (err) @@ -3294,10 +3348,7 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device * mlx5_vdpa_remove_debugfs(ndev->debugfs); ndev->debugfs = NULL; - if (ndev->nb_registered) { - ndev->nb_registered = false; - mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); - } + unregister_link_notifier(ndev); wq = mvdev->wq; mvdev->wq = NULL; destroy_workqueue(wq); diff --git a/drivers/vdpa/solidrun/Makefile b/drivers/vdpa/solidrun/Makefile index c0aa3415bf7b..9116252cd5fa 100644 --- a/drivers/vdpa/solidrun/Makefile +++ b/drivers/vdpa/solidrun/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SNET_VDPA) += snet_vdpa.o snet_vdpa-$(CONFIG_SNET_VDPA) += snet_main.o +snet_vdpa-$(CONFIG_SNET_VDPA) += snet_ctrl.o ifdef CONFIG_HWMON snet_vdpa-$(CONFIG_SNET_VDPA) += snet_hwmon.o endif diff --git a/drivers/vdpa/solidrun/snet_ctrl.c b/drivers/vdpa/solidrun/snet_ctrl.c new file mode 100644 index 000000000000..3858738643b4 --- /dev/null +++ b/drivers/vdpa/solidrun/snet_ctrl.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SolidRun DPU driver for control plane + * + * Copyright (C) 2022-2023 SolidRun + * + * Author: Alvaro Karsz + * + */ + +#include + +#include "snet_vdpa.h" + +enum snet_ctrl_opcodes { + SNET_CTRL_OP_DESTROY = 1, + SNET_CTRL_OP_READ_VQ_STATE, + SNET_CTRL_OP_SUSPEND, +}; + +#define SNET_CTRL_TIMEOUT 2000000 + +#define SNET_CTRL_DATA_SIZE_MASK 0x0000FFFF +#define SNET_CTRL_IN_PROCESS_MASK 0x00010000 +#define SNET_CTRL_CHUNK_RDY_MASK 0x00020000 +#define SNET_CTRL_ERROR_MASK 0x0FFC0000 + +#define SNET_VAL_TO_ERR(val) (-(((val) & SNET_CTRL_ERROR_MASK) >> 18)) +#define SNET_EMPTY_CTRL(val) (((val) & SNET_CTRL_ERROR_MASK) || \ + !((val) & SNET_CTRL_IN_PROCESS_MASK)) +#define SNET_DATA_READY(val) ((val) & (SNET_CTRL_ERROR_MASK | SNET_CTRL_CHUNK_RDY_MASK)) + +/* Control register used to read data from the DPU */ +struct snet_ctrl_reg_ctrl { + /* Chunk size in 4B words */ + u16 data_size; + /* We are in the middle of a command */ + u16 in_process:1; + /* A data chunk is ready and can be consumed */ + u16 chunk_ready:1; + /* Error code */ + u16 error:10; + /* Saved for future usage */ + u16 rsvd:4; +}; + +/* Opcode register */ +struct snet_ctrl_reg_op { + u16 opcode; + /* Only if VQ index is relevant for the command */ + u16 vq_idx; +}; + +struct snet_ctrl_regs { + struct snet_ctrl_reg_op op; + struct snet_ctrl_reg_ctrl ctrl; + u32 rsvd; + u32 data[]; +}; + +static struct snet_ctrl_regs __iomem *snet_get_ctrl(struct snet *snet) +{ + return snet->bar + snet->psnet->cfg.ctrl_off; +} + +static int snet_wait_for_empty_ctrl(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_EMPTY_CTRL(val), 10, + SNET_CTRL_TIMEOUT); +} + +static int snet_wait_for_empty_op(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->op, val, !val, 10, SNET_CTRL_TIMEOUT); +} + +static int snet_wait_for_data(struct snet_ctrl_regs __iomem *regs) +{ + u32 val; + + return readx_poll_timeout(ioread32, ®s->ctrl, val, SNET_DATA_READY(val), 10, + SNET_CTRL_TIMEOUT); +} + +static u32 snet_read32_word(struct snet_ctrl_regs __iomem *ctrl_regs, u16 word_idx) +{ + return ioread32(&ctrl_regs->data[word_idx]); +} + +static u32 snet_read_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs) +{ + return ioread32(&ctrl_regs->ctrl); +} + +static void snet_write_ctrl(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) +{ + iowrite32(val, &ctrl_regs->ctrl); +} + +static void snet_write_op(struct snet_ctrl_regs __iomem *ctrl_regs, u32 val) +{ + iowrite32(val, &ctrl_regs->op); +} + +static int snet_wait_for_dpu_completion(struct snet_ctrl_regs __iomem *ctrl_regs) +{ + /* Wait until the DPU finishes completely. + * It will clear the opcode register. + */ + return snet_wait_for_empty_op(ctrl_regs); +} + +/* Reading ctrl from the DPU: + * buf_size must be 4B aligned + * + * Steps: + * + * (1) Verify that the DPU is not in the middle of another operation by + * reading the in_process and error bits in the control register. + * (2) Write the request opcode and the VQ idx in the opcode register + * and write the buffer size in the control register. + * (3) Start readind chunks of data, chunk_ready bit indicates that a + * data chunk is available, we signal that we read the data by clearing the bit. + * (4) Detect that the transfer is completed when the in_process bit + * in the control register is cleared or when the an error appears. + */ +static int snet_ctrl_read_from_dpu(struct snet *snet, u16 opcode, u16 vq_idx, void *buffer, + u32 buf_size) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + u32 *bfr_ptr = (u32 *)buffer; + u32 val; + u16 buf_words; + int ret; + u16 words, i, tot_words = 0; + + /* Supported for config 2+ */ + if (!SNET_CFG_VER(snet, 2)) + return -EOPNOTSUPP; + + if (!IS_ALIGNED(buf_size, 4)) + return -EINVAL; + + mutex_lock(&snet->ctrl_lock); + + buf_words = buf_size / 4; + + /* Make sure control register is empty */ + ret = snet_wait_for_empty_ctrl(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); + goto exit; + } + + /* We need to write the buffer size in the control register, and the opcode + vq index in + * the opcode register. + * We use a spinlock to serialize the writes. + */ + spin_lock(&snet->ctrl_spinlock); + + snet_write_ctrl(regs, buf_words); + snet_write_op(regs, opcode | (vq_idx << 16)); + + spin_unlock(&snet->ctrl_spinlock); + + while (buf_words != tot_words) { + ret = snet_wait_for_data(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for control data\n"); + goto exit; + } + + val = snet_read_ctrl(regs); + + /* Error? */ + if (val & SNET_CTRL_ERROR_MASK) { + ret = SNET_VAL_TO_ERR(val); + SNET_WARN(pdev, "Error while reading control data from DPU, err %d\n", ret); + goto exit; + } + + words = min_t(u16, val & SNET_CTRL_DATA_SIZE_MASK, buf_words - tot_words); + + for (i = 0; i < words; i++) { + *bfr_ptr = snet_read32_word(regs, i); + bfr_ptr++; + } + + tot_words += words; + + /* Is the job completed? */ + if (!(val & SNET_CTRL_IN_PROCESS_MASK)) + break; + + /* Clear the chunk ready bit and continue */ + val &= ~SNET_CTRL_CHUNK_RDY_MASK; + snet_write_ctrl(regs, val); + } + + ret = snet_wait_for_dpu_completion(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for the DPU to complete a control command\n"); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +/* Send a control message to the DPU using the old mechanism + * used with config version 1. + */ +static int snet_send_ctrl_msg_old(struct snet *snet, u32 opcode) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + int ret; + + mutex_lock(&snet->ctrl_lock); + + /* Old mechanism uses just 1 register, the opcode register. + * Make sure that the opcode register is empty, and that the DPU isn't + * processing an old message. + */ + ret = snet_wait_for_empty_op(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control message to be ACKed\n"); + goto exit; + } + + /* Write the message */ + snet_write_op(regs, opcode); + + /* DPU ACKs the message by clearing the opcode register */ + ret = snet_wait_for_empty_op(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for a control message to be ACKed\n"); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +/* Send a control message to the DPU. + * A control message is a message without payload. + */ +static int snet_send_ctrl_msg(struct snet *snet, u16 opcode, u16 vq_idx) +{ + struct pci_dev *pdev = snet->pdev; + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + u32 val; + int ret; + + /* If config version is not 2+, use the old mechanism */ + if (!SNET_CFG_VER(snet, 2)) + return snet_send_ctrl_msg_old(snet, opcode); + + mutex_lock(&snet->ctrl_lock); + + /* Make sure control register is empty */ + ret = snet_wait_for_empty_ctrl(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for previous control data to be consumed\n"); + goto exit; + } + + /* We need to clear the control register and write the opcode + vq index in the opcode + * register. + * We use a spinlock to serialize the writes. + */ + spin_lock(&snet->ctrl_spinlock); + + snet_write_ctrl(regs, 0); + snet_write_op(regs, opcode | (vq_idx << 16)); + + spin_unlock(&snet->ctrl_spinlock); + + /* The DPU ACKs control messages by setting the chunk ready bit + * without data. + */ + ret = snet_wait_for_data(regs); + if (ret) { + SNET_WARN(pdev, "Timeout waiting for control message to be ACKed\n"); + goto exit; + } + + /* Check for errors */ + val = snet_read_ctrl(regs); + ret = SNET_VAL_TO_ERR(val); + + /* Clear the chunk ready bit */ + val &= ~SNET_CTRL_CHUNK_RDY_MASK; + snet_write_ctrl(regs, val); + + ret = snet_wait_for_dpu_completion(regs); + if (ret) + SNET_WARN(pdev, "Timeout waiting for DPU to complete a control command, err %d\n", + ret); + +exit: + mutex_unlock(&snet->ctrl_lock); + return ret; +} + +void snet_ctrl_clear(struct snet *snet) +{ + struct snet_ctrl_regs __iomem *regs = snet_get_ctrl(snet); + + snet_write_op(regs, 0); +} + +int snet_destroy_dev(struct snet *snet) +{ + return snet_send_ctrl_msg(snet, SNET_CTRL_OP_DESTROY, 0); +} + +int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state) +{ + return snet_ctrl_read_from_dpu(snet, SNET_CTRL_OP_READ_VQ_STATE, idx, state, + sizeof(*state)); +} + +int snet_suspend_dev(struct snet *snet) +{ + return snet_send_ctrl_msg(snet, SNET_CTRL_OP_SUSPEND, 0); +} diff --git a/drivers/vdpa/solidrun/snet_hwmon.c b/drivers/vdpa/solidrun/snet_hwmon.c index e695e36ff753..42c87387a0f1 100644 --- a/drivers/vdpa/solidrun/snet_hwmon.c +++ b/drivers/vdpa/solidrun/snet_hwmon.c @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c index 68de727398ed..cdcd84ce4f5a 100644 --- a/drivers/vdpa/solidrun/snet_main.c +++ b/drivers/vdpa/solidrun/snet_main.c @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * @@ -16,14 +16,12 @@ /* SNET signature */ #define SNET_SIGNATURE 0xD0D06363 /* Max. config version that we can work with */ -#define SNET_CFG_VERSION 0x1 +#define SNET_CFG_VERSION 0x2 /* Queue align */ #define SNET_QUEUE_ALIGNMENT PAGE_SIZE /* Kick value to notify that new data is available */ #define SNET_KICK_VAL 0x1 #define SNET_CONFIG_OFF 0x0 -/* ACK timeout for a message */ -#define SNET_ACK_TIMEOUT 2000000 /* How long we are willing to wait for a SNET device */ #define SNET_DETECT_TIMEOUT 5000000 /* How long should we wait for the DPU to read our config */ @@ -32,61 +30,16 @@ #define SNET_GENERAL_CFG_LEN 36 #define SNET_GENERAL_CFG_VQ_LEN 40 -enum snet_msg { - SNET_MSG_DESTROY = 1, -}; - static struct snet *vdpa_to_snet(struct vdpa_device *vdpa) { return container_of(vdpa, struct snet, vdpa); } -static int snet_wait_for_msg_ack(struct snet *snet) -{ - struct pci_dev *pdev = snet->pdev; - int ret; - u32 val; - - /* The DPU will clear the messages offset once messages - * are processed. - */ - ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off, - val, !val, 10, SNET_ACK_TIMEOUT); - if (ret) - SNET_WARN(pdev, "Timeout waiting for message ACK\n"); - - return ret; -} - -/* Sends a message to the DPU. - * If blocking is set, the function will return once the - * message was processed by the DPU (or timeout). - */ -static int snet_send_msg(struct snet *snet, u32 msg, bool blocking) -{ - int ret = 0; - - /* Make sure the DPU acked last message before issuing a new one */ - ret = snet_wait_for_msg_ack(snet); - if (ret) - return ret; - - /* Write the message */ - snet_write32(snet, snet->psnet->cfg.msg_off, msg); - - if (blocking) - ret = snet_wait_for_msg_ack(snet); - else /* If non-blocking, flush the write by issuing a read */ - snet_read32(snet, snet->psnet->cfg.msg_off); - - return ret; -} - static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data) { struct snet *snet = data; /* Call callback if any */ - if (snet->cb.callback) + if (likely(snet->cb.callback)) return snet->cb.callback(snet->cb.private); return IRQ_HANDLED; @@ -96,7 +49,7 @@ static irqreturn_t snet_vq_irq_hndlr(int irq, void *data) { struct snet_vq *vq = data; /* Call callback if any */ - if (vq->cb.callback) + if (likely(vq->cb.callback)) return vq->cb.callback(vq->cb.private); return IRQ_HANDLED; @@ -153,12 +106,24 @@ static void snet_kick_vq(struct vdpa_device *vdev, u16 idx) { struct snet *snet = vdpa_to_snet(vdev); /* not ready - ignore */ - if (!snet->vqs[idx]->ready) + if (unlikely(!snet->vqs[idx]->ready)) return; iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); } +static void snet_kick_vq_with_data(struct vdpa_device *vdev, u32 data) +{ + struct snet *snet = vdpa_to_snet(vdev); + u16 idx = data & 0xFFFF; + + /* not ready - ignore */ + if (unlikely(!snet->vqs[idx]->ready)) + return; + + iowrite32((data & 0xFFFF0000) | SNET_KICK_VAL, snet->vqs[idx]->kick_ptr); +} + static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb) { struct snet *snet = vdpa_to_snet(vdev); @@ -181,33 +146,48 @@ static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx) return snet->vqs[idx]->ready; } -static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +static bool snet_vq_state_is_initial(struct snet *snet, const struct vdpa_vq_state *state) { - struct snet *snet = vdpa_to_snet(vdev); - /* Setting the VQ state is not supported. - * If the asked state is the same as the initial one - * we can ignore it. - */ if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) { const struct vdpa_vq_state_packed *p = &state->packed; if (p->last_avail_counter == 1 && p->last_used_counter == 1 && p->last_avail_idx == 0 && p->last_used_idx == 0) - return 0; + return true; } else { const struct vdpa_vq_state_split *s = &state->split; if (s->avail_index == 0) - return 0; + return true; } + return false; +} + +static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state) +{ + struct snet *snet = vdpa_to_snet(vdev); + + /* We can set any state for config version 2+ */ + if (SNET_CFG_VER(snet, 2)) { + memcpy(&snet->vqs[idx]->vq_state, state, sizeof(*state)); + return 0; + } + + /* Older config - we can't set the VQ state. + * Return 0 only if this is the initial state we use in the DPU. + */ + if (snet_vq_state_is_initial(snet, state)) + return 0; + return -EOPNOTSUPP; } static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state) { - /* Not supported */ - return -EOPNOTSUPP; + struct snet *snet = vdpa_to_snet(vdev); + + return snet_read_vq_state(snet, idx, state); } static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx) @@ -232,9 +212,9 @@ static int snet_reset_dev(struct snet *snet) if (!snet->status) return 0; - /* If DPU started, send a destroy message */ + /* If DPU started, destroy it */ if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK) - ret = snet_send_msg(snet, SNET_MSG_DESTROY, true); + ret = snet_destroy_dev(snet); /* Clear VQs */ for (i = 0; i < snet->cfg->vq_num; i++) { @@ -258,7 +238,7 @@ static int snet_reset_dev(struct snet *snet) snet->dpu_ready = false; if (ret) - SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid); + SNET_WARN(pdev, "Incomplete reset to SNET[%u] device, err: %d\n", snet->sid, ret); else SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid); @@ -356,7 +336,7 @@ static int snet_write_conf(struct snet *snet) * | DESC AREA | * | DEVICE AREA | * | DRIVER AREA | - * | RESERVED | + * | VQ STATE (CFG 2+) | RSVD | * * Magic number should be written last, this is the DPU indication that the data is ready */ @@ -391,12 +371,15 @@ static int snet_write_conf(struct snet *snet) off += 8; snet_write64(snet, off, snet->vqs[i]->driver_area); off += 8; + /* Write VQ state if config version is 2+ */ + if (SNET_CFG_VER(snet, 2)) + snet_write32(snet, off, *(u32 *)&snet->vqs[i]->vq_state); + off += 4; + /* Ignore reserved */ - off += 8; + off += 4; } - /* Clear snet messages address for this device */ - snet_write32(snet, snet->psnet->cfg.msg_off, 0); /* Write magic number - data is ready */ snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE); @@ -512,10 +495,25 @@ static void snet_set_config(struct vdpa_device *vdev, unsigned int offset, iowrite8(*buf_ptr++, cfg_ptr + i); } +static int snet_suspend(struct vdpa_device *vdev) +{ + struct snet *snet = vdpa_to_snet(vdev); + int ret; + + ret = snet_suspend_dev(snet); + if (ret) + SNET_ERR(snet->pdev, "SNET[%u] suspend failed, err: %d\n", snet->sid, ret); + else + SNET_DBG(snet->pdev, "Suspend SNET[%u] device\n", snet->sid); + + return ret; +} + static const struct vdpa_config_ops snet_config_ops = { .set_vq_address = snet_set_vq_address, .set_vq_num = snet_set_vq_num, .kick_vq = snet_kick_vq, + .kick_vq_with_data = snet_kick_vq_with_data, .set_vq_cb = snet_set_vq_cb, .set_vq_ready = snet_set_vq_ready, .get_vq_ready = snet_get_vq_ready, @@ -537,6 +535,7 @@ static const struct vdpa_config_ops snet_config_ops = { .set_status = snet_set_status, .get_config = snet_get_config, .set_config = snet_set_config, + .suspend = snet_suspend, }; static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet) @@ -697,7 +696,7 @@ static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet) off += 4; cfg->hwmon_off = psnet_read32(psnet, off); off += 4; - cfg->msg_off = psnet_read32(psnet, off); + cfg->ctrl_off = psnet_read32(psnet, off); off += 4; cfg->flags = psnet_read32(psnet, off); off += 4; @@ -997,6 +996,10 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev) goto free_irqs; } + /* Init control mutex and spinlock */ + mutex_init(&snet->ctrl_lock); + spin_lock_init(&snet->ctrl_spinlock); + /* Save pci device pointer */ snet->pdev = pdev; snet->psnet = psnet; @@ -1013,6 +1016,9 @@ static int snet_vdpa_probe_vf(struct pci_dev *pdev) /* Create a VirtIO config pointer */ snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off; + /* Clear control registers */ + snet_ctrl_clear(snet); + pci_set_master(pdev); pci_set_drvdata(pdev, snet); diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h index b7f34169053f..3c78d4e7d485 100644 --- a/drivers/vdpa/solidrun/snet_vdpa.h +++ b/drivers/vdpa/solidrun/snet_vdpa.h @@ -2,7 +2,7 @@ /* * SolidRun DPU driver for control plane * - * Copyright (C) 2022 SolidRun + * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * @@ -20,10 +20,15 @@ #define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f)) +/* Check if negotiated config version is at least @ver */ +#define SNET_CFG_VER(snet, ver) ((snet)->psnet->negotiated_cfg_ver >= (ver)) + /* VQ struct */ struct snet_vq { /* VQ callback */ struct vdpa_callback cb; + /* VQ state received from bus */ + struct vdpa_vq_state vq_state; /* desc base address */ u64 desc_area; /* device base address */ @@ -51,6 +56,10 @@ struct snet { struct vdpa_device vdpa; /* Config callback */ struct vdpa_callback cb; + /* To lock the control mechanism */ + struct mutex ctrl_lock; + /* Spinlock to protect critical parts in the control mechanism */ + spinlock_t ctrl_spinlock; /* array of virqueues */ struct snet_vq **vqs; /* Used features */ @@ -117,8 +126,8 @@ struct snet_cfg { u32 kick_off; /* Offset in PCI BAR for HW monitoring */ u32 hwmon_off; - /* Offset in PCI BAR for SNET messages */ - u32 msg_off; + /* Offset in PCI BAR for Control mechanism */ + u32 ctrl_off; /* Config general flags - enum snet_cfg_flags */ u32 flags; /* Reserved for future usage */ @@ -191,4 +200,9 @@ static inline void snet_write64(struct snet *snet, u32 off, u64 val) void psnet_create_hwmon(struct pci_dev *pdev); #endif +void snet_ctrl_clear(struct snet *snet); +int snet_destroy_dev(struct snet *snet); +int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state); +int snet_suspend_dev(struct snet *snet); + #endif //_SNET_VDPA_H_ diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index eea23c630f7c..d343af4fa60e 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -35,10 +35,44 @@ module_param(max_iotlb_entries, int, 0444); MODULE_PARM_DESC(max_iotlb_entries, "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)"); +static bool use_va = true; +module_param(use_va, bool, 0444); +MODULE_PARM_DESC(use_va, "Enable/disable the device's ability to use VA"); + #define VDPASIM_QUEUE_ALIGN PAGE_SIZE #define VDPASIM_QUEUE_MAX 256 #define VDPASIM_VENDOR_ID 0 +struct vdpasim_mm_work { + struct kthread_work work; + struct vdpasim *vdpasim; + struct mm_struct *mm_to_bind; + int ret; +}; + +static void vdpasim_mm_work_fn(struct kthread_work *work) +{ + struct vdpasim_mm_work *mm_work = + container_of(work, struct vdpasim_mm_work, work); + struct vdpasim *vdpasim = mm_work->vdpasim; + + mm_work->ret = 0; + + //TODO: should we attach the cgroup of the mm owner? + vdpasim->mm_bound = mm_work->mm_to_bind; +} + +static void vdpasim_worker_change_mm_sync(struct vdpasim *vdpasim, + struct vdpasim_mm_work *mm_work) +{ + struct kthread_work *work = &mm_work->work; + + kthread_init_work(work, vdpasim_mm_work_fn); + kthread_queue_work(vdpasim->worker, work); + + kthread_flush_work(work); +} + static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa) { return container_of(vdpa, struct vdpasim, vdpa); @@ -59,13 +93,20 @@ static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx) { struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; uint16_t last_avail_idx = vq->vring.last_avail_idx; + struct vring_desc *desc = (struct vring_desc *) + (uintptr_t)vq->desc_addr; + struct vring_avail *avail = (struct vring_avail *) + (uintptr_t)vq->driver_addr; + struct vring_used *used = (struct vring_used *) + (uintptr_t)vq->device_addr; - vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, true, - (struct vring_desc *)(uintptr_t)vq->desc_addr, - (struct vring_avail *) - (uintptr_t)vq->driver_addr, - (struct vring_used *) - (uintptr_t)vq->device_addr); + if (use_va && vdpasim->mm_bound) { + vringh_init_iotlb_va(&vq->vring, vdpasim->features, vq->num, + true, desc, avail, used); + } else { + vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, + true, desc, avail, used); + } vq->vring.last_avail_idx = last_avail_idx; @@ -127,6 +168,25 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim) static const struct vdpa_config_ops vdpasim_config_ops; static const struct vdpa_config_ops vdpasim_batch_config_ops; +static void vdpasim_work_fn(struct kthread_work *work) +{ + struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); + struct mm_struct *mm = vdpasim->mm_bound; + + if (use_va && mm) { + if (!mmget_not_zero(mm)) + return; + kthread_use_mm(mm); + } + + vdpasim->dev_attr.work_fn(vdpasim); + + if (use_va && mm) { + kthread_unuse_mm(mm); + mmput(mm); + } +} + struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, const struct vdpa_dev_set_config *config) { @@ -155,7 +215,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, vdpa = __vdpa_alloc_device(NULL, ops, dev_attr->ngroups, dev_attr->nas, dev_attr->alloc_size, - dev_attr->name, false); + dev_attr->name, use_va); if (IS_ERR(vdpa)) { ret = PTR_ERR(vdpa); goto err_alloc; @@ -163,11 +223,17 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, vdpasim = vdpa_to_sim(vdpa); vdpasim->dev_attr = *dev_attr; - INIT_WORK(&vdpasim->work, dev_attr->work_fn); - spin_lock_init(&vdpasim->lock); + dev = &vdpasim->vdpa.dev; + + kthread_init_work(&vdpasim->work, vdpasim_work_fn); + vdpasim->worker = kthread_create_worker(0, "vDPA sim worker: %s", + dev_attr->name); + if (IS_ERR(vdpasim->worker)) + goto err_iommu; + + mutex_init(&vdpasim->mutex); spin_lock_init(&vdpasim->iommu_lock); - dev = &vdpasim->vdpa.dev; dev->dma_mask = &dev->coherent_dma_mask; if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) goto err_iommu; @@ -195,10 +261,6 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, for (i = 0; i < vdpasim->dev_attr.nas; i++) vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0); - vdpasim->buffer = kvmalloc(dev_attr->buffer_size, GFP_KERNEL); - if (!vdpasim->buffer) - goto err_iommu; - for (i = 0; i < dev_attr->nvqs; i++) vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0], &vdpasim->iommu_lock); @@ -214,6 +276,12 @@ err_alloc: } EXPORT_SYMBOL_GPL(vdpasim_create); +void vdpasim_schedule_work(struct vdpasim *vdpasim) +{ + kthread_queue_work(vdpasim->worker, &vdpasim->work); +} +EXPORT_SYMBOL_GPL(vdpasim_schedule_work); + static int vdpasim_set_vq_address(struct vdpa_device *vdpa, u16 idx, u64 desc_area, u64 driver_area, u64 device_area) @@ -248,7 +316,7 @@ static void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx) } if (vq->ready) - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); } static void vdpasim_set_vq_cb(struct vdpa_device *vdpa, u16 idx, @@ -267,13 +335,13 @@ static void vdpasim_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; bool old_ready; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); old_ready = vq->ready; vq->ready = ready; if (vq->ready && !old_ready) { vdpasim_queue_ready(vdpasim, idx); } - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); } static bool vdpasim_get_vq_ready(struct vdpa_device *vdpa, u16 idx) @@ -291,9 +359,9 @@ static int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx, struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; struct vringh *vrh = &vq->vring; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vrh->last_avail_idx = state->split.avail_index; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -390,9 +458,9 @@ static u8 vdpasim_get_status(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); u8 status; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); status = vdpasim->status; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return status; } @@ -401,19 +469,19 @@ static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->status = status; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); } static int vdpasim_reset(struct vdpa_device *vdpa) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->status = 0; vdpasim_do_reset(vdpasim); - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -422,9 +490,9 @@ static int vdpasim_suspend(struct vdpa_device *vdpa) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->running = false; - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -434,7 +502,7 @@ static int vdpasim_resume(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); int i; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); vdpasim->running = true; if (vdpasim->pending_kick) { @@ -445,7 +513,7 @@ static int vdpasim_resume(struct vdpa_device *vdpa) vdpasim->pending_kick = false; } - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -517,14 +585,14 @@ static int vdpasim_set_group_asid(struct vdpa_device *vdpa, unsigned int group, iommu = &vdpasim->iommu[asid]; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); for (i = 0; i < vdpasim->dev_attr.nvqs; i++) if (vdpasim_get_vq_group(vdpa, i) == group) vringh_set_iotlb(&vdpasim->vqs[i].vring, iommu, &vdpasim->iommu_lock); - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); return 0; } @@ -563,6 +631,30 @@ err: return ret; } +static int vdpasim_bind_mm(struct vdpa_device *vdpa, struct mm_struct *mm) +{ + struct vdpasim *vdpasim = vdpa_to_sim(vdpa); + struct vdpasim_mm_work mm_work; + + mm_work.vdpasim = vdpasim; + mm_work.mm_to_bind = mm; + + vdpasim_worker_change_mm_sync(vdpasim, &mm_work); + + return mm_work.ret; +} + +static void vdpasim_unbind_mm(struct vdpa_device *vdpa) +{ + struct vdpasim *vdpasim = vdpa_to_sim(vdpa); + struct vdpasim_mm_work mm_work; + + mm_work.vdpasim = vdpasim; + mm_work.mm_to_bind = NULL; + + vdpasim_worker_change_mm_sync(vdpasim, &mm_work); +} + static int vdpasim_dma_map(struct vdpa_device *vdpa, unsigned int asid, u64 iova, u64 size, u64 pa, u32 perm, void *opaque) @@ -610,14 +702,16 @@ static void vdpasim_free(struct vdpa_device *vdpa) struct vdpasim *vdpasim = vdpa_to_sim(vdpa); int i; - cancel_work_sync(&vdpasim->work); + kthread_cancel_work_sync(&vdpasim->work); + kthread_destroy_worker(vdpasim->worker); for (i = 0; i < vdpasim->dev_attr.nvqs; i++) { vringh_kiov_cleanup(&vdpasim->vqs[i].out_iov); vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov); } - kvfree(vdpasim->buffer); + vdpasim->dev_attr.free(vdpasim); + for (i = 0; i < vdpasim->dev_attr.nas; i++) vhost_iotlb_reset(&vdpasim->iommu[i]); kfree(vdpasim->iommu); @@ -658,6 +752,8 @@ static const struct vdpa_config_ops vdpasim_config_ops = { .set_group_asid = vdpasim_set_group_asid, .dma_map = vdpasim_dma_map, .dma_unmap = vdpasim_dma_unmap, + .bind_mm = vdpasim_bind_mm, + .unbind_mm = vdpasim_unbind_mm, .free = vdpasim_free, }; @@ -692,6 +788,8 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops = { .get_iova_range = vdpasim_get_iova_range, .set_group_asid = vdpasim_set_group_asid, .set_map = vdpasim_set_map, + .bind_mm = vdpasim_bind_mm, + .unbind_mm = vdpasim_unbind_mm, .free = vdpasim_free, }; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index 144858636c10..bb137e479763 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -39,33 +39,34 @@ struct vdpasim_dev_attr { u64 supported_features; size_t alloc_size; size_t config_size; - size_t buffer_size; int nvqs; u32 id; u32 ngroups; u32 nas; - work_func_t work_fn; + void (*work_fn)(struct vdpasim *vdpasim); void (*get_config)(struct vdpasim *vdpasim, void *config); void (*set_config)(struct vdpasim *vdpasim, const void *config); int (*get_stats)(struct vdpasim *vdpasim, u16 idx, struct sk_buff *msg, struct netlink_ext_ack *extack); + void (*free)(struct vdpasim *vdpasim); }; /* State of each vdpasim device */ struct vdpasim { struct vdpa_device vdpa; struct vdpasim_virtqueue *vqs; - struct work_struct work; + struct kthread_worker *worker; + struct kthread_work work; + struct mm_struct *mm_bound; struct vdpasim_dev_attr dev_attr; - /* spinlock to synchronize virtqueue state */ - spinlock_t lock; + /* mutex to synchronize virtqueue state */ + struct mutex mutex; /* virtio config according to device type */ void *config; struct vhost_iotlb *iommu; bool *iommu_pt; - void *buffer; u32 status; u32 generation; u64 features; @@ -78,6 +79,7 @@ struct vdpasim { struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *attr, const struct vdpa_dev_set_config *config); +void vdpasim_schedule_work(struct vdpasim *vdpasim); /* TODO: cross-endian support */ static inline bool vdpasim_is_little_endian(struct vdpasim *vdpasim) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c index 5117959bed8a..00d7d72713be 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -44,8 +43,39 @@ #define VDPASIM_BLK_AS_NUM 1 #define VDPASIM_BLK_GROUP_NUM 1 +struct vdpasim_blk { + struct vdpasim vdpasim; + void *buffer; + bool shared_backend; +}; + +static struct vdpasim_blk *sim_to_blk(struct vdpasim *vdpasim) +{ + return container_of(vdpasim, struct vdpasim_blk, vdpasim); +} + static char vdpasim_blk_id[VIRTIO_BLK_ID_BYTES] = "vdpa_blk_sim"; +static bool shared_backend; +module_param(shared_backend, bool, 0444); +MODULE_PARM_DESC(shared_backend, "Enable the shared backend between virtio-blk devices"); + +static void *shared_buffer; +/* mutex to synchronize shared_buffer access */ +static DEFINE_MUTEX(shared_buffer_mutex); + +static void vdpasim_blk_buffer_lock(struct vdpasim_blk *blk) +{ + if (blk->shared_backend) + mutex_lock(&shared_buffer_mutex); +} + +static void vdpasim_blk_buffer_unlock(struct vdpasim_blk *blk) +{ + if (blk->shared_backend) + mutex_unlock(&shared_buffer_mutex); +} + static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector, u64 num_sectors, u64 max_sectors) { @@ -79,6 +109,7 @@ static bool vdpasim_blk_check_range(struct vdpasim *vdpasim, u64 start_sector, static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, struct vdpasim_virtqueue *vq) { + struct vdpasim_blk *blk = sim_to_blk(vdpasim); size_t pushed = 0, to_pull, to_push; struct virtio_blk_outhdr hdr; bool handled = false; @@ -144,9 +175,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, break; } + vdpasim_blk_buffer_lock(blk); bytes = vringh_iov_push_iotlb(&vq->vring, &vq->in_iov, - vdpasim->buffer + offset, - to_push); + blk->buffer + offset, to_push); + vdpasim_blk_buffer_unlock(blk); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_push_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -166,9 +198,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, break; } + vdpasim_blk_buffer_lock(blk); bytes = vringh_iov_pull_iotlb(&vq->vring, &vq->out_iov, - vdpasim->buffer + offset, - to_pull); + blk->buffer + offset, to_pull); + vdpasim_blk_buffer_unlock(blk); if (bytes < 0) { dev_dbg(&vdpasim->vdpa.dev, "vringh_iov_pull_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n", @@ -248,8 +281,10 @@ static bool vdpasim_blk_handle_req(struct vdpasim *vdpasim, } if (type == VIRTIO_BLK_T_WRITE_ZEROES) { - memset(vdpasim->buffer + offset, 0, + vdpasim_blk_buffer_lock(blk); + memset(blk->buffer + offset, 0, num_sectors << SECTOR_SHIFT); + vdpasim_blk_buffer_unlock(blk); } break; @@ -286,13 +321,12 @@ err: return handled; } -static void vdpasim_blk_work(struct work_struct *work) +static void vdpasim_blk_work(struct vdpasim *vdpasim) { - struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); bool reschedule = false; int i; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); if (!(vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) goto out; @@ -323,10 +357,10 @@ static void vdpasim_blk_work(struct work_struct *work) } } out: - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); if (reschedule) - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); } static void vdpasim_blk_get_config(struct vdpasim *vdpasim, void *config) @@ -355,6 +389,14 @@ static void vdpasim_blk_get_config(struct vdpasim *vdpasim, void *config) } +static void vdpasim_blk_free(struct vdpasim *vdpasim) +{ + struct vdpasim_blk *blk = sim_to_blk(vdpasim); + + if (!blk->shared_backend) + kvfree(blk->buffer); +} + static void vdpasim_blk_mgmtdev_release(struct device *dev) { } @@ -368,6 +410,7 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, const struct vdpa_dev_set_config *config) { struct vdpasim_dev_attr dev_attr = {}; + struct vdpasim_blk *blk; struct vdpasim *simdev; int ret; @@ -378,16 +421,30 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, dev_attr.nvqs = VDPASIM_BLK_VQ_NUM; dev_attr.ngroups = VDPASIM_BLK_GROUP_NUM; dev_attr.nas = VDPASIM_BLK_AS_NUM; - dev_attr.alloc_size = sizeof(struct vdpasim); + dev_attr.alloc_size = sizeof(struct vdpasim_blk); dev_attr.config_size = sizeof(struct virtio_blk_config); dev_attr.get_config = vdpasim_blk_get_config; dev_attr.work_fn = vdpasim_blk_work; - dev_attr.buffer_size = VDPASIM_BLK_CAPACITY << SECTOR_SHIFT; + dev_attr.free = vdpasim_blk_free; simdev = vdpasim_create(&dev_attr, config); if (IS_ERR(simdev)) return PTR_ERR(simdev); + blk = sim_to_blk(simdev); + blk->shared_backend = shared_backend; + + if (blk->shared_backend) { + blk->buffer = shared_buffer; + } else { + blk->buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, + GFP_KERNEL); + if (!blk->buffer) { + ret = -ENOMEM; + goto put_dev; + } + } + ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_BLK_VQ_NUM); if (ret) goto put_dev; @@ -437,6 +494,15 @@ static int __init vdpasim_blk_init(void) if (ret) goto parent_err; + if (shared_backend) { + shared_buffer = kvmalloc(VDPASIM_BLK_CAPACITY << SECTOR_SHIFT, + GFP_KERNEL); + if (!shared_buffer) { + ret = -ENOMEM; + goto parent_err; + } + } + return 0; parent_err: @@ -446,6 +512,7 @@ parent_err: static void __exit vdpasim_blk_exit(void) { + kvfree(shared_buffer); vdpa_mgmtdev_unregister(&mgmt_dev); device_unregister(&vdpasim_blk_mgmtdev); } diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index dfe2ce341803..cfe962911804 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -59,6 +58,7 @@ struct vdpasim_net{ struct vdpasim_dataq_stats tx_stats; struct vdpasim_dataq_stats rx_stats; struct vdpasim_cq_stats cq_stats; + void *buffer; }; static struct vdpasim_net *sim_to_net(struct vdpasim *vdpasim) @@ -88,14 +88,15 @@ static bool receive_filter(struct vdpasim *vdpasim, size_t len) size_t hdr_len = modern ? sizeof(struct virtio_net_hdr_v1) : sizeof(struct virtio_net_hdr); struct virtio_net_config *vio_config = vdpasim->config; + struct vdpasim_net *net = sim_to_net(vdpasim); if (len < ETH_ALEN + hdr_len) return false; - if (is_broadcast_ether_addr(vdpasim->buffer + hdr_len) || - is_multicast_ether_addr(vdpasim->buffer + hdr_len)) + if (is_broadcast_ether_addr(net->buffer + hdr_len) || + is_multicast_ether_addr(net->buffer + hdr_len)) return true; - if (!strncmp(vdpasim->buffer + hdr_len, vio_config->mac, ETH_ALEN)) + if (!strncmp(net->buffer + hdr_len, vio_config->mac, ETH_ALEN)) return true; return false; @@ -192,9 +193,8 @@ static void vdpasim_handle_cvq(struct vdpasim *vdpasim) u64_stats_update_end(&net->cq_stats.syncp); } -static void vdpasim_net_work(struct work_struct *work) +static void vdpasim_net_work(struct vdpasim *vdpasim) { - struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); struct vdpasim_virtqueue *txq = &vdpasim->vqs[1]; struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0]; struct vdpasim_net *net = sim_to_net(vdpasim); @@ -203,7 +203,7 @@ static void vdpasim_net_work(struct work_struct *work) u64 rx_drops = 0, rx_overruns = 0, rx_errors = 0, tx_errors = 0; int err; - spin_lock(&vdpasim->lock); + mutex_lock(&vdpasim->mutex); if (!vdpasim->running) goto out; @@ -227,8 +227,7 @@ static void vdpasim_net_work(struct work_struct *work) ++tx_pkts; read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov, - vdpasim->buffer, - PAGE_SIZE); + net->buffer, PAGE_SIZE); tx_bytes += read; @@ -247,7 +246,7 @@ static void vdpasim_net_work(struct work_struct *work) } write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov, - vdpasim->buffer, read); + net->buffer, read); if (write <= 0) { ++rx_errors; break; @@ -260,13 +259,13 @@ static void vdpasim_net_work(struct work_struct *work) vdpasim_net_complete(rxq, write); if (tx_pkts > 4) { - schedule_work(&vdpasim->work); + vdpasim_schedule_work(vdpasim); goto out; } } out: - spin_unlock(&vdpasim->lock); + mutex_unlock(&vdpasim->mutex); u64_stats_update_begin(&net->tx_stats.syncp); net->tx_stats.pkts += tx_pkts; @@ -429,6 +428,13 @@ static void vdpasim_net_setup_config(struct vdpasim *vdpasim, vio_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); } +static void vdpasim_net_free(struct vdpasim *vdpasim) +{ + struct vdpasim_net *net = sim_to_net(vdpasim); + + kvfree(net->buffer); +} + static void vdpasim_net_mgmtdev_release(struct device *dev) { } @@ -458,7 +464,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, dev_attr.get_config = vdpasim_net_get_config; dev_attr.work_fn = vdpasim_net_work; dev_attr.get_stats = vdpasim_net_get_stats; - dev_attr.buffer_size = PAGE_SIZE; + dev_attr.free = vdpasim_net_free; simdev = vdpasim_create(&dev_attr, config); if (IS_ERR(simdev)) @@ -472,6 +478,12 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, u64_stats_init(&net->rx_stats.syncp); u64_stats_init(&net->cq_stats.syncp); + net->buffer = kvmalloc(PAGE_SIZE, GFP_KERNEL); + if (!net->buffer) { + ret = -ENOMEM; + goto reg_err; + } + /* * Initialization must be completed before this call, since it can * connect the device to the vDPA bus, so requests can arrive after diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index 0c3b48616a9f..de97e38c3b82 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -37,10 +37,15 @@ #define DRV_LICENSE "GPL v2" #define VDUSE_DEV_MAX (1U << MINORBITS) +#define VDUSE_MAX_BOUNCE_SIZE (1024 * 1024 * 1024) +#define VDUSE_MIN_BOUNCE_SIZE (1024 * 1024) #define VDUSE_BOUNCE_SIZE (64 * 1024 * 1024) -#define VDUSE_IOVA_SIZE (128 * 1024 * 1024) +/* 128 MB reserved for virtqueue creation */ +#define VDUSE_IOVA_SIZE (VDUSE_MAX_BOUNCE_SIZE + 128 * 1024 * 1024) #define VDUSE_MSG_DEFAULT_TIMEOUT 30 +#define IRQ_UNBOUND -1 + struct vduse_virtqueue { u16 index; u16 num_max; @@ -57,6 +62,9 @@ struct vduse_virtqueue { struct vdpa_callback cb; struct work_struct inject; struct work_struct kick; + int irq_effective_cpu; + struct cpumask irq_affinity; + struct kobject kobj; }; struct vduse_dev; @@ -76,7 +84,7 @@ struct vduse_umem { struct vduse_dev { struct vduse_vdpa *vdev; struct device *dev; - struct vduse_virtqueue *vqs; + struct vduse_virtqueue **vqs; struct vduse_iova_domain *domain; char *name; struct mutex lock; @@ -106,6 +114,8 @@ struct vduse_dev { u32 vq_align; struct vduse_umem *umem; struct mutex mem_lock; + unsigned int bounce_size; + struct mutex domain_lock; }; struct vduse_dev_msg { @@ -128,6 +138,7 @@ static struct class *vduse_class; static struct cdev vduse_ctrl_cdev; static struct cdev vduse_cdev; static struct workqueue_struct *vduse_irq_wq; +static struct workqueue_struct *vduse_irq_bound_wq; static u32 allowed_device_id[] = { VIRTIO_ID_BLOCK, @@ -419,7 +430,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) struct vduse_iova_domain *domain = dev->domain; /* The coherent mappings are handled in vduse_dev_free_coherent() */ - if (domain->bounce_map) + if (domain && domain->bounce_map) vduse_domain_reset_bounce_map(domain); down_write(&dev->rwsem); @@ -434,7 +445,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) flush_work(&dev->inject); for (i = 0; i < dev->vq_num; i++) { - struct vduse_virtqueue *vq = &dev->vqs[i]; + struct vduse_virtqueue *vq = dev->vqs[i]; vq->ready = false; vq->desc_addr = 0; @@ -453,6 +464,7 @@ static void vduse_dev_reset(struct vduse_dev *dev) spin_lock(&vq->irq_lock); vq->cb.callback = NULL; vq->cb.private = NULL; + vq->cb.trigger = NULL; spin_unlock(&vq->irq_lock); flush_work(&vq->inject); flush_work(&vq->kick); @@ -466,7 +478,7 @@ static int vduse_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 idx, u64 device_area) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->desc_addr = desc_area; vq->driver_addr = driver_area; @@ -500,7 +512,7 @@ static void vduse_vq_kick_work(struct work_struct *work) static void vduse_vdpa_kick_vq(struct vdpa_device *vdpa, u16 idx) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (!eventfd_signal_allowed()) { schedule_work(&vq->kick); @@ -513,18 +525,19 @@ static void vduse_vdpa_set_vq_cb(struct vdpa_device *vdpa, u16 idx, struct vdpa_callback *cb) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; spin_lock(&vq->irq_lock); vq->cb.callback = cb->callback; vq->cb.private = cb->private; + vq->cb.trigger = cb->trigger; spin_unlock(&vq->irq_lock); } static void vduse_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->num = num; } @@ -533,7 +546,7 @@ static void vduse_vdpa_set_vq_ready(struct vdpa_device *vdpa, u16 idx, bool ready) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; vq->ready = ready; } @@ -541,7 +554,7 @@ static void vduse_vdpa_set_vq_ready(struct vdpa_device *vdpa, static bool vduse_vdpa_get_vq_ready(struct vdpa_device *vdpa, u16 idx) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; return vq->ready; } @@ -550,7 +563,7 @@ static int vduse_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 idx, const struct vdpa_vq_state *state) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (dev->driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) { vq->state.packed.last_avail_counter = @@ -569,7 +582,7 @@ static int vduse_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 idx, struct vdpa_vq_state *state) { struct vduse_dev *dev = vdpa_to_vduse(vdpa); - struct vduse_virtqueue *vq = &dev->vqs[idx]; + struct vduse_virtqueue *vq = dev->vqs[idx]; if (dev->driver_features & BIT_ULL(VIRTIO_F_RING_PACKED)) return vduse_dev_get_vq_state_packed(dev, vq, &state->packed); @@ -624,8 +637,8 @@ static u16 vduse_vdpa_get_vq_num_max(struct vdpa_device *vdpa) int i; for (i = 0; i < dev->vq_num; i++) - if (num_max < dev->vqs[i].num_max) - num_max = dev->vqs[i].num_max; + if (num_max < dev->vqs[i]->num_max) + num_max = dev->vqs[i]->num_max; return num_max; } @@ -708,6 +721,23 @@ static u32 vduse_vdpa_get_generation(struct vdpa_device *vdpa) return dev->generation; } +static int vduse_vdpa_set_vq_affinity(struct vdpa_device *vdpa, u16 idx, + const struct cpumask *cpu_mask) +{ + struct vduse_dev *dev = vdpa_to_vduse(vdpa); + + cpumask_copy(&dev->vqs[idx]->irq_affinity, cpu_mask); + return 0; +} + +static const struct cpumask * +vduse_vdpa_get_vq_affinity(struct vdpa_device *vdpa, u16 idx) +{ + struct vduse_dev *dev = vdpa_to_vduse(vdpa); + + return &dev->vqs[idx]->irq_affinity; +} + static int vduse_vdpa_set_map(struct vdpa_device *vdpa, unsigned int asid, struct vhost_iotlb *iotlb) @@ -758,6 +788,8 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = { .get_config = vduse_vdpa_get_config, .set_config = vduse_vdpa_set_config, .get_generation = vduse_vdpa_get_generation, + .set_vq_affinity = vduse_vdpa_set_vq_affinity, + .get_vq_affinity = vduse_vdpa_get_vq_affinity, .reset = vduse_vdpa_reset, .set_map = vduse_vdpa_set_map, .free = vduse_vdpa_free, @@ -863,7 +895,7 @@ static int vduse_kickfd_setup(struct vduse_dev *dev, return -EINVAL; index = array_index_nospec(eventfd->index, dev->vq_num); - vq = &dev->vqs[index]; + vq = dev->vqs[index]; if (eventfd->fd >= 0) { ctx = eventfd_ctx_fdget(eventfd->fd); if (IS_ERR(ctx)) @@ -889,7 +921,7 @@ static bool vduse_dev_is_ready(struct vduse_dev *dev) int i; for (i = 0; i < dev->vq_num; i++) - if (!dev->vqs[i].num_max) + if (!dev->vqs[i]->num_max) return false; return true; @@ -916,8 +948,26 @@ static void vduse_vq_irq_inject(struct work_struct *work) spin_unlock_irq(&vq->irq_lock); } +static bool vduse_vq_signal_irqfd(struct vduse_virtqueue *vq) +{ + bool signal = false; + + if (!vq->cb.trigger) + return false; + + spin_lock_irq(&vq->irq_lock); + if (vq->ready && vq->cb.trigger) { + eventfd_signal(vq->cb.trigger, 1); + signal = true; + } + spin_unlock_irq(&vq->irq_lock); + + return signal; +} + static int vduse_dev_queue_irq_work(struct vduse_dev *dev, - struct work_struct *irq_work) + struct work_struct *irq_work, + int irq_effective_cpu) { int ret = -EINVAL; @@ -926,7 +976,11 @@ static int vduse_dev_queue_irq_work(struct vduse_dev *dev, goto unlock; ret = 0; - queue_work(vduse_irq_wq, irq_work); + if (irq_effective_cpu == IRQ_UNBOUND) + queue_work(vduse_irq_wq, irq_work); + else + queue_work_on(irq_effective_cpu, + vduse_irq_bound_wq, irq_work); unlock: up_read(&dev->rwsem); @@ -944,6 +998,9 @@ static int vduse_dev_dereg_umem(struct vduse_dev *dev, goto unlock; ret = -EINVAL; + if (!dev->domain) + goto unlock; + if (dev->umem->iova != iova || size != dev->domain->bounce_size) goto unlock; @@ -970,7 +1027,7 @@ static int vduse_dev_reg_umem(struct vduse_dev *dev, unsigned long npages, lock_limit; int ret; - if (!dev->domain->bounce_map || + if (!dev->domain || !dev->domain->bounce_map || size != dev->domain->bounce_size || iova != 0 || uaddr & ~PAGE_MASK) return -EINVAL; @@ -1029,6 +1086,22 @@ unlock: return ret; } +static void vduse_vq_update_effective_cpu(struct vduse_virtqueue *vq) +{ + int curr_cpu = vq->irq_effective_cpu; + + while (true) { + curr_cpu = cpumask_next(curr_cpu, &vq->irq_affinity); + if (cpu_online(curr_cpu)) + break; + + if (curr_cpu >= nr_cpu_ids) + curr_cpu = IRQ_UNBOUND; + } + + vq->irq_effective_cpu = curr_cpu; +} + static long vduse_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1044,7 +1117,6 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, struct vduse_iotlb_entry entry; struct vhost_iotlb_map *map; struct vdpa_map_file *map_file; - struct vduse_iova_domain *domain = dev->domain; struct file *f = NULL; ret = -EFAULT; @@ -1055,8 +1127,13 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (entry.start > entry.last) break; - spin_lock(&domain->iotlb_lock); - map = vhost_iotlb_itree_first(domain->iotlb, + mutex_lock(&dev->domain_lock); + if (!dev->domain) { + mutex_unlock(&dev->domain_lock); + break; + } + spin_lock(&dev->domain->iotlb_lock); + map = vhost_iotlb_itree_first(dev->domain->iotlb, entry.start, entry.last); if (map) { map_file = (struct vdpa_map_file *)map->opaque; @@ -1066,7 +1143,8 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, entry.last = map->last; entry.perm = map->perm; } - spin_unlock(&domain->iotlb_lock); + spin_unlock(&dev->domain->iotlb_lock); + mutex_unlock(&dev->domain_lock); ret = -EINVAL; if (!f) break; @@ -1111,7 +1189,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; } case VDUSE_DEV_INJECT_CONFIG_IRQ: - ret = vduse_dev_queue_irq_work(dev, &dev->inject); + ret = vduse_dev_queue_irq_work(dev, &dev->inject, IRQ_UNBOUND); break; case VDUSE_VQ_SETUP: { struct vduse_vq_config config; @@ -1130,7 +1208,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(config.index, dev->vq_num); - dev->vqs[index].num_max = config.max_size; + dev->vqs[index]->num_max = config.max_size; ret = 0; break; } @@ -1148,7 +1226,7 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, break; index = array_index_nospec(vq_info.index, dev->vq_num); - vq = &dev->vqs[index]; + vq = dev->vqs[index]; vq_info.desc_addr = vq->desc_addr; vq_info.driver_addr = vq->driver_addr; vq_info.device_addr = vq->device_addr; @@ -1197,8 +1275,14 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (index >= dev->vq_num) break; + ret = 0; index = array_index_nospec(index, dev->vq_num); - ret = vduse_dev_queue_irq_work(dev, &dev->vqs[index].inject); + if (!vduse_vq_signal_irqfd(dev->vqs[index])) { + vduse_vq_update_effective_cpu(dev->vqs[index]); + ret = vduse_dev_queue_irq_work(dev, + &dev->vqs[index]->inject, + dev->vqs[index]->irq_effective_cpu); + } break; } case VDUSE_IOTLB_REG_UMEM: { @@ -1213,8 +1297,10 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, sizeof(umem.reserved))) break; + mutex_lock(&dev->domain_lock); ret = vduse_dev_reg_umem(dev, umem.iova, umem.uaddr, umem.size); + mutex_unlock(&dev->domain_lock); break; } case VDUSE_IOTLB_DEREG_UMEM: { @@ -1228,15 +1314,15 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, if (!is_mem_zero((const char *)umem.reserved, sizeof(umem.reserved))) break; - + mutex_lock(&dev->domain_lock); ret = vduse_dev_dereg_umem(dev, umem.iova, umem.size); + mutex_unlock(&dev->domain_lock); break; } case VDUSE_IOTLB_GET_INFO: { struct vduse_iova_info info; struct vhost_iotlb_map *map; - struct vduse_iova_domain *domain = dev->domain; ret = -EFAULT; if (copy_from_user(&info, argp, sizeof(info))) @@ -1250,18 +1336,24 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd, sizeof(info.reserved))) break; - spin_lock(&domain->iotlb_lock); - map = vhost_iotlb_itree_first(domain->iotlb, + mutex_lock(&dev->domain_lock); + if (!dev->domain) { + mutex_unlock(&dev->domain_lock); + break; + } + spin_lock(&dev->domain->iotlb_lock); + map = vhost_iotlb_itree_first(dev->domain->iotlb, info.start, info.last); if (map) { info.start = map->start; info.last = map->last; info.capability = 0; - if (domain->bounce_map && map->start == 0 && - map->last == domain->bounce_size - 1) + if (dev->domain->bounce_map && map->start == 0 && + map->last == dev->domain->bounce_size - 1) info.capability |= VDUSE_IOVA_CAP_UMEM; } - spin_unlock(&domain->iotlb_lock); + spin_unlock(&dev->domain->iotlb_lock); + mutex_unlock(&dev->domain_lock); if (!map) break; @@ -1284,7 +1376,10 @@ static int vduse_dev_release(struct inode *inode, struct file *file) { struct vduse_dev *dev = file->private_data; - vduse_dev_dereg_umem(dev, 0, dev->domain->bounce_size); + mutex_lock(&dev->domain_lock); + if (dev->domain) + vduse_dev_dereg_umem(dev, 0, dev->domain->bounce_size); + mutex_unlock(&dev->domain_lock); spin_lock(&dev->msg_lock); /* Make sure the inflight messages can processed after reconncection */ list_splice_init(&dev->recv_list, &dev->send_list); @@ -1339,6 +1434,151 @@ static const struct file_operations vduse_dev_fops = { .llseek = noop_llseek, }; +static ssize_t irq_cb_affinity_show(struct vduse_virtqueue *vq, char *buf) +{ + return sprintf(buf, "%*pb\n", cpumask_pr_args(&vq->irq_affinity)); +} + +static ssize_t irq_cb_affinity_store(struct vduse_virtqueue *vq, + const char *buf, size_t count) +{ + cpumask_var_t new_value; + int ret; + + if (!zalloc_cpumask_var(&new_value, GFP_KERNEL)) + return -ENOMEM; + + ret = cpumask_parse(buf, new_value); + if (ret) + goto free_mask; + + ret = -EINVAL; + if (!cpumask_intersects(new_value, cpu_online_mask)) + goto free_mask; + + cpumask_copy(&vq->irq_affinity, new_value); + ret = count; +free_mask: + free_cpumask_var(new_value); + return ret; +} + +struct vq_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct vduse_virtqueue *vq, char *buf); + ssize_t (*store)(struct vduse_virtqueue *vq, const char *buf, + size_t count); +}; + +static struct vq_sysfs_entry irq_cb_affinity_attr = __ATTR_RW(irq_cb_affinity); + +static struct attribute *vq_attrs[] = { + &irq_cb_affinity_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(vq); + +static ssize_t vq_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + struct vq_sysfs_entry *entry = container_of(attr, + struct vq_sysfs_entry, attr); + + if (!entry->show) + return -EIO; + + return entry->show(vq, buf); +} + +static ssize_t vq_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + struct vq_sysfs_entry *entry = container_of(attr, + struct vq_sysfs_entry, attr); + + if (!entry->store) + return -EIO; + + return entry->store(vq, buf, count); +} + +static const struct sysfs_ops vq_sysfs_ops = { + .show = vq_attr_show, + .store = vq_attr_store, +}; + +static void vq_release(struct kobject *kobj) +{ + struct vduse_virtqueue *vq = container_of(kobj, + struct vduse_virtqueue, kobj); + kfree(vq); +} + +static const struct kobj_type vq_type = { + .release = vq_release, + .sysfs_ops = &vq_sysfs_ops, + .default_groups = vq_groups, +}; + +static void vduse_dev_deinit_vqs(struct vduse_dev *dev) +{ + int i; + + if (!dev->vqs) + return; + + for (i = 0; i < dev->vq_num; i++) + kobject_put(&dev->vqs[i]->kobj); + kfree(dev->vqs); +} + +static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num) +{ + int ret, i; + + dev->vq_align = vq_align; + dev->vq_num = vq_num; + dev->vqs = kcalloc(dev->vq_num, sizeof(*dev->vqs), GFP_KERNEL); + if (!dev->vqs) + return -ENOMEM; + + for (i = 0; i < vq_num; i++) { + dev->vqs[i] = kzalloc(sizeof(*dev->vqs[i]), GFP_KERNEL); + if (!dev->vqs[i]) { + ret = -ENOMEM; + goto err; + } + + dev->vqs[i]->index = i; + dev->vqs[i]->irq_effective_cpu = IRQ_UNBOUND; + INIT_WORK(&dev->vqs[i]->inject, vduse_vq_irq_inject); + INIT_WORK(&dev->vqs[i]->kick, vduse_vq_kick_work); + spin_lock_init(&dev->vqs[i]->kick_lock); + spin_lock_init(&dev->vqs[i]->irq_lock); + cpumask_setall(&dev->vqs[i]->irq_affinity); + + kobject_init(&dev->vqs[i]->kobj, &vq_type); + ret = kobject_add(&dev->vqs[i]->kobj, + &dev->dev->kobj, "vq%d", i); + if (ret) { + kfree(dev->vqs[i]); + goto err; + } + } + + return 0; +err: + while (i--) + kobject_put(&dev->vqs[i]->kobj); + kfree(dev->vqs); + dev->vqs = NULL; + return ret; +} + static struct vduse_dev *vduse_dev_create(void) { struct vduse_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1348,6 +1588,7 @@ static struct vduse_dev *vduse_dev_create(void) mutex_init(&dev->lock); mutex_init(&dev->mem_lock); + mutex_init(&dev->domain_lock); spin_lock_init(&dev->msg_lock); INIT_LIST_HEAD(&dev->send_list); INIT_LIST_HEAD(&dev->recv_list); @@ -1396,8 +1637,9 @@ static int vduse_destroy_dev(char *name) device_destroy(vduse_class, MKDEV(MAJOR(vduse_major), dev->minor)); idr_remove(&vduse_idr, dev->minor); kvfree(dev->config); - kfree(dev->vqs); - vduse_domain_destroy(dev->domain); + vduse_dev_deinit_vqs(dev); + if (dev->domain) + vduse_domain_destroy(dev->domain); kfree(dev->name); vduse_dev_destroy(dev); module_put(THIS_MODULE); @@ -1476,8 +1718,48 @@ static ssize_t msg_timeout_store(struct device *device, static DEVICE_ATTR_RW(msg_timeout); +static ssize_t bounce_size_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct vduse_dev *dev = dev_get_drvdata(device); + + return sysfs_emit(buf, "%u\n", dev->bounce_size); +} + +static ssize_t bounce_size_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vduse_dev *dev = dev_get_drvdata(device); + unsigned int bounce_size; + int ret; + + ret = -EPERM; + mutex_lock(&dev->domain_lock); + if (dev->domain) + goto unlock; + + ret = kstrtouint(buf, 10, &bounce_size); + if (ret < 0) + goto unlock; + + ret = -EINVAL; + if (bounce_size > VDUSE_MAX_BOUNCE_SIZE || + bounce_size < VDUSE_MIN_BOUNCE_SIZE) + goto unlock; + + dev->bounce_size = bounce_size & PAGE_MASK; + ret = count; +unlock: + mutex_unlock(&dev->domain_lock); + return ret; +} + +static DEVICE_ATTR_RW(bounce_size); + static struct attribute *vduse_dev_attrs[] = { &dev_attr_msg_timeout.attr, + &dev_attr_bounce_size.attr, NULL }; @@ -1486,7 +1768,7 @@ ATTRIBUTE_GROUPS(vduse_dev); static int vduse_create_dev(struct vduse_dev_config *config, void *config_buf, u64 api_version) { - int i, ret; + int ret; struct vduse_dev *dev; ret = -EEXIST; @@ -1506,26 +1788,9 @@ static int vduse_create_dev(struct vduse_dev_config *config, if (!dev->name) goto err_str; - dev->domain = vduse_domain_create(VDUSE_IOVA_SIZE - 1, - VDUSE_BOUNCE_SIZE); - if (!dev->domain) - goto err_domain; - + dev->bounce_size = VDUSE_BOUNCE_SIZE; dev->config = config_buf; dev->config_size = config->config_size; - dev->vq_align = config->vq_align; - dev->vq_num = config->vq_num; - dev->vqs = kcalloc(dev->vq_num, sizeof(*dev->vqs), GFP_KERNEL); - if (!dev->vqs) - goto err_vqs; - - for (i = 0; i < dev->vq_num; i++) { - dev->vqs[i].index = i; - INIT_WORK(&dev->vqs[i].inject, vduse_vq_irq_inject); - INIT_WORK(&dev->vqs[i].kick, vduse_vq_kick_work); - spin_lock_init(&dev->vqs[i].kick_lock); - spin_lock_init(&dev->vqs[i].irq_lock); - } ret = idr_alloc(&vduse_idr, dev, 1, VDUSE_DEV_MAX, GFP_KERNEL); if (ret < 0) @@ -1540,16 +1805,19 @@ static int vduse_create_dev(struct vduse_dev_config *config, ret = PTR_ERR(dev->dev); goto err_dev; } + + ret = vduse_dev_init_vqs(dev, config->vq_align, config->vq_num); + if (ret) + goto err_vqs; + __module_get(THIS_MODULE); return 0; +err_vqs: + device_destroy(vduse_class, MKDEV(MAJOR(vduse_major), dev->minor)); err_dev: idr_remove(&vduse_idr, dev->minor); err_idr: - kfree(dev->vqs); -err_vqs: - vduse_domain_destroy(dev->domain); -err_domain: kfree(dev->name); err_str: vduse_dev_destroy(dev); @@ -1716,9 +1984,23 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, if (ret) return ret; + mutex_lock(&dev->domain_lock); + if (!dev->domain) + dev->domain = vduse_domain_create(VDUSE_IOVA_SIZE - 1, + dev->bounce_size); + mutex_unlock(&dev->domain_lock); + if (!dev->domain) { + put_device(&dev->vdev->vdpa.dev); + return -ENOMEM; + } + ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num); if (ret) { put_device(&dev->vdev->vdpa.dev); + mutex_lock(&dev->domain_lock); + vduse_domain_destroy(dev->domain); + dev->domain = NULL; + mutex_unlock(&dev->domain_lock); return ret; } @@ -1793,7 +2075,7 @@ static int vduse_init(void) int ret; struct device *dev; - vduse_class = class_create(THIS_MODULE, "vduse"); + vduse_class = class_create("vduse"); if (IS_ERR(vduse_class)) return PTR_ERR(vduse_class); @@ -1824,12 +2106,15 @@ static int vduse_init(void) if (ret) goto err_cdev; + ret = -ENOMEM; vduse_irq_wq = alloc_workqueue("vduse-irq", WQ_HIGHPRI | WQ_SYSFS | WQ_UNBOUND, 0); - if (!vduse_irq_wq) { - ret = -ENOMEM; + if (!vduse_irq_wq) goto err_wq; - } + + vduse_irq_bound_wq = alloc_workqueue("vduse-irq-bound", WQ_HIGHPRI, 0); + if (!vduse_irq_bound_wq) + goto err_bound_wq; ret = vduse_domain_init(); if (ret) @@ -1843,6 +2128,8 @@ static int vduse_init(void) err_mgmtdev: vduse_domain_exit(); err_domain: + destroy_workqueue(vduse_irq_bound_wq); +err_bound_wq: destroy_workqueue(vduse_irq_wq); err_wq: cdev_del(&vduse_cdev); @@ -1862,6 +2149,7 @@ static void vduse_exit(void) { vduse_mgmtdev_exit(); vduse_domain_exit(); + destroy_workqueue(vduse_irq_bound_wq); destroy_workqueue(vduse_irq_wq); cdev_del(&vduse_cdev); device_destroy(vduse_class, vduse_major); diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c index 27d5ba7cf9dc..fc75c1000d74 100644 --- a/drivers/vfio/group.c +++ b/drivers/vfio/group.c @@ -878,7 +878,7 @@ int __init vfio_group_init(void) return ret; /* /dev/vfio/$GROUP */ - vfio.class = class_create(THIS_MODULE, "vfio"); + vfio.class = class_create("vfio"); if (IS_ERR(vfio.class)) { ret = PTR_ERR(vfio.class); goto err_group_class; diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 523e0144c86f..948cdd464f4e 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -96,6 +96,7 @@ static const u16 pci_ext_cap_length[PCI_EXT_CAP_ID_MAX + 1] = { [PCI_EXT_CAP_ID_SECPCI] = 0, /* not yet */ [PCI_EXT_CAP_ID_PMUX] = 0, /* not yet */ [PCI_EXT_CAP_ID_PASID] = 0, /* not yet */ + [PCI_EXT_CAP_ID_DVSEC] = 0xFF, }; /* @@ -1101,6 +1102,7 @@ int __init vfio_pci_init_perm_bits(void) ret |= init_pci_ext_cap_err_perm(&ecap_perms[PCI_EXT_CAP_ID_ERR]); ret |= init_pci_ext_cap_pwr_perm(&ecap_perms[PCI_EXT_CAP_ID_PWR]); ecap_perms[PCI_EXT_CAP_ID_VNDR].writefn = vfio_raw_config_write; + ecap_perms[PCI_EXT_CAP_ID_DVSEC].writefn = vfio_raw_config_write; if (ret) vfio_pci_uninit_perm_bits(); @@ -1440,6 +1442,11 @@ static int vfio_ext_cap_len(struct vfio_pci_core_device *vdev, u16 ecap, u16 epo return PCI_TPH_BASE_SIZEOF + (sts * 2) + 2; } return PCI_TPH_BASE_SIZEOF; + case PCI_EXT_CAP_ID_DVSEC: + ret = pci_read_config_dword(pdev, epos + PCI_DVSEC_HEADER1, &dword); + if (ret) + return pcibios_err_to_errno(ret); + return PCI_DVSEC_HEADER1_LEN(dword); default: pci_warn(pdev, "%s: unknown length for PCI ecap %#x@%#x\n", __func__, ecap, epos); diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 60a50ce8701e..a94ec6225d31 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -1189,52 +1189,6 @@ static long tce_iommu_ioctl(void *iommu_data, static void tce_iommu_release_ownership(struct tce_container *container, struct iommu_table_group *table_group) -{ - int i; - - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { - struct iommu_table *tbl = container->tables[i]; - - if (!tbl) - continue; - - tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); - if (tbl->it_map) - iommu_release_ownership(tbl); - - container->tables[i] = NULL; - } -} - -static int tce_iommu_take_ownership(struct tce_container *container, - struct iommu_table_group *table_group) -{ - int i, j, rc = 0; - - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { - struct iommu_table *tbl = table_group->tables[i]; - - if (!tbl || !tbl->it_map) - continue; - - rc = iommu_take_ownership(tbl); - if (rc) { - for (j = 0; j < i; ++j) - iommu_release_ownership( - table_group->tables[j]); - - return rc; - } - } - - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) - container->tables[i] = table_group->tables[i]; - - return 0; -} - -static void tce_iommu_release_ownership_ddw(struct tce_container *container, - struct iommu_table_group *table_group) { long i; @@ -1246,23 +1200,13 @@ static void tce_iommu_release_ownership_ddw(struct tce_container *container, for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) if (container->tables[i]) table_group->ops->unset_window(table_group, i); - - table_group->ops->release_ownership(table_group); } -static long tce_iommu_take_ownership_ddw(struct tce_container *container, +static long tce_iommu_take_ownership(struct tce_container *container, struct iommu_table_group *table_group) { long i, ret = 0; - if (!table_group->ops->create_table || !table_group->ops->set_window || - !table_group->ops->release_ownership) { - WARN_ON_ONCE(1); - return -EFAULT; - } - - table_group->ops->take_ownership(table_group); - /* Set all windows to the new group */ for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { struct iommu_table *tbl = container->tables[i]; @@ -1281,8 +1225,6 @@ release_exit: for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) table_group->ops->unset_window(table_group, i); - table_group->ops->release_ownership(table_group); - return ret; } @@ -1307,9 +1249,14 @@ static int tce_iommu_attach_group(void *iommu_data, goto unlock_exit; } - if (tce_groups_attached(container) && (!table_group->ops || - !table_group->ops->take_ownership || - !table_group->ops->release_ownership)) { + /* v2 requires full support of dynamic DMA windows */ + if (container->v2 && table_group->max_dynamic_windows_supported == 0) { + ret = -EINVAL; + goto unlock_exit; + } + + /* v1 reuses TCE tables and does not share them among PEs */ + if (!container->v2 && tce_groups_attached(container)) { ret = -EBUSY; goto unlock_exit; } @@ -1344,29 +1291,15 @@ static int tce_iommu_attach_group(void *iommu_data, goto unlock_exit; } - if (!table_group->ops || !table_group->ops->take_ownership || - !table_group->ops->release_ownership) { - if (container->v2) { - ret = -EPERM; - goto free_exit; - } - ret = tce_iommu_take_ownership(container, table_group); - } else { - if (!container->v2) { - ret = -EPERM; - goto free_exit; - } - ret = tce_iommu_take_ownership_ddw(container, table_group); - if (!tce_groups_attached(container) && !container->tables[0]) - container->def_window_pending = true; - } + ret = tce_iommu_take_ownership(container, table_group); + if (!tce_groups_attached(container) && !container->tables[0]) + container->def_window_pending = true; if (!ret) { tcegrp->grp = iommu_group; list_add(&tcegrp->next, &container->group_list); } -free_exit: if (ret && tcegrp) kfree(tcegrp); @@ -1405,10 +1338,7 @@ static void tce_iommu_detach_group(void *iommu_data, table_group = iommu_group_get_iommudata(iommu_group); BUG_ON(!table_group); - if (!table_group->ops || !table_group->ops->release_ownership) - tce_iommu_release_ownership(container, table_group); - else - tce_iommu_release_ownership_ddw(container, table_group); + tce_iommu_release_ownership(container, table_group); unlock_exit: mutex_unlock(&container->lock); diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 493c31de0edb..0d2f805468e1 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -580,7 +580,7 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr, goto done; } - vaddr = untagged_addr(vaddr); + vaddr = untagged_addr_remote(mm, vaddr); retry: vma = vma_lookup(mm, vaddr); @@ -860,6 +860,11 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data, if (ret) goto pin_unwind; + if (!pfn_valid(phys_pfn)) { + ret = -EINVAL; + goto pin_unwind; + } + ret = vfio_add_to_pfn_list(dma, iova, phys_pfn); if (ret) { if (put_pfn(phys_pfn, dma->prot) && do_accounting) diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 89497c933490..f0ca33b2e1df 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -1409,7 +1409,7 @@ static int __init vfio_init(void) goto err_virqfd; /* /sys/class/vfio-dev/vfioX */ - vfio.device_class = class_create(THIS_MODULE, "vfio-dev"); + vfio.device_class = class_create("vfio-dev"); if (IS_ERR(vfio.device_class)) { ret = PTR_ERR(vfio.device_class); goto err_dev_class; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 139ad52d0aa1..bb10fa4bb4f6 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -229,7 +229,10 @@ struct vhost_scsi_ctx { struct iov_iter out_iter; }; -/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ +/* + * Global mutex to protect vhost_scsi TPG list for vhost IOCTLs and LIO + * configfs management operations. + */ static DEFINE_MUTEX(vhost_scsi_mutex); static LIST_HEAD(vhost_scsi_list); @@ -1501,7 +1504,7 @@ out: * vhost_scsi_tpg with an active struct vhost_scsi_nexus * * The lock nesting rule is: - * vhost_scsi_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex + * vs->dev.mutex -> vhost_scsi_mutex -> tpg->tv_tpg_mutex -> vq->mutex */ static int vhost_scsi_set_endpoint(struct vhost_scsi *vs, @@ -1515,7 +1518,6 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, int index, ret, i, len; bool match = false; - mutex_lock(&vhost_scsi_mutex); mutex_lock(&vs->dev.mutex); /* Verify that ring has been setup correctly. */ @@ -1536,6 +1538,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (vs->vs_tpg) memcpy(vs_tpg, vs->vs_tpg, len); + mutex_lock(&vhost_scsi_mutex); list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) { mutex_lock(&tpg->tv_tpg_mutex); if (!tpg->tpg_nexus) { @@ -1551,6 +1554,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) { if (vs->vs_tpg && vs->vs_tpg[tpg->tport_tpgt]) { mutex_unlock(&tpg->tv_tpg_mutex); + mutex_unlock(&vhost_scsi_mutex); ret = -EEXIST; goto undepend; } @@ -1565,6 +1569,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, if (ret) { pr_warn("target_depend_item() failed: %d\n", ret); mutex_unlock(&tpg->tv_tpg_mutex); + mutex_unlock(&vhost_scsi_mutex); goto undepend; } tpg->tv_tpg_vhost_count++; @@ -1574,6 +1579,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, } mutex_unlock(&tpg->tv_tpg_mutex); } + mutex_unlock(&vhost_scsi_mutex); if (match) { memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn, @@ -1629,7 +1635,6 @@ undepend: kfree(vs_tpg); out: mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return ret; } @@ -1645,7 +1650,6 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, int index, ret, i; u8 target; - mutex_lock(&vhost_scsi_mutex); mutex_lock(&vs->dev.mutex); /* Verify that ring has been setup correctly. */ for (index = 0; index < vs->dev.nvqs; ++index) { @@ -1666,11 +1670,10 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, if (!tpg) continue; - mutex_lock(&tpg->tv_tpg_mutex); tv_tport = tpg->tport; if (!tv_tport) { ret = -ENODEV; - goto err_tpg; + goto err_dev; } if (strcmp(tv_tport->tport_name, t->vhost_wwpn)) { @@ -1679,35 +1682,51 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, tv_tport->tport_name, tpg->tport_tpgt, t->vhost_wwpn, t->vhost_tpgt); ret = -EINVAL; - goto err_tpg; + goto err_dev; } + match = true; + } + if (!match) + goto free_vs_tpg; + + /* Prevent new cmds from starting and accessing the tpgs/sessions */ + for (i = 0; i < vs->dev.nvqs; i++) { + vq = &vs->vqs[i].vq; + mutex_lock(&vq->mutex); + vhost_vq_set_backend(vq, NULL); + mutex_unlock(&vq->mutex); + } + /* Make sure cmds are not running before tearing them down. */ + vhost_scsi_flush(vs); + + for (i = 0; i < vs->dev.nvqs; i++) { + vq = &vs->vqs[i].vq; + vhost_scsi_destroy_vq_cmds(vq); + } + + /* + * We can now release our hold on the tpg and sessions and userspace + * can free them after this point. + */ + for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) { + target = i; + tpg = vs->vs_tpg[target]; + if (!tpg) + continue; + + mutex_lock(&tpg->tv_tpg_mutex); + tpg->tv_tpg_vhost_count--; tpg->vhost_scsi = NULL; vs->vs_tpg[target] = NULL; - match = true; + mutex_unlock(&tpg->tv_tpg_mutex); - /* - * Release se_tpg->tpg_group.cg_item configfs dependency now - * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur. - */ + se_tpg = &tpg->se_tpg; target_undepend_item(&se_tpg->tpg_group.cg_item); } - if (match) { - for (i = 0; i < vs->dev.nvqs; i++) { - vq = &vs->vqs[i].vq; - mutex_lock(&vq->mutex); - vhost_vq_set_backend(vq, NULL); - mutex_unlock(&vq->mutex); - } - /* Make sure cmds are not running before tearing them down. */ - vhost_scsi_flush(vs); - for (i = 0; i < vs->dev.nvqs; i++) { - vq = &vs->vqs[i].vq; - vhost_scsi_destroy_vq_cmds(vq); - } - } +free_vs_tpg: /* * Act as synchronize_rcu to make sure access to * old vs->vs_tpg is finished. @@ -1717,14 +1736,10 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, vs->vs_tpg = NULL; WARN_ON(vs->vs_events_nr); mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return 0; -err_tpg: - mutex_unlock(&tpg->tv_tpg_mutex); err_dev: mutex_unlock(&vs->dev.mutex); - mutex_unlock(&vhost_scsi_mutex); return ret; } @@ -1965,8 +1980,6 @@ vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg, if (!vs) return; - mutex_lock(&vs->dev.mutex); - if (plug) reason = VIRTIO_SCSI_EVT_RESET_RESCAN; else @@ -1974,11 +1987,18 @@ vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg, vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq; mutex_lock(&vq->mutex); + /* + * We can't queue events if the backend has been cleared, because + * we could end up queueing an event after the flush. + */ + if (!vhost_vq_get_backend(vq)) + goto unlock; + if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG)) vhost_scsi_send_evt(vs, tpg, lun, VIRTIO_SCSI_T_TRANSPORT_RESET, reason); +unlock: mutex_unlock(&vq->mutex); - mutex_unlock(&vs->dev.mutex); } static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun) @@ -1997,15 +2017,10 @@ static int vhost_scsi_port_link(struct se_portal_group *se_tpg, struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - mutex_lock(&vhost_scsi_mutex); - mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count++; - mutex_unlock(&tpg->tv_tpg_mutex); - vhost_scsi_hotplug(tpg, lun); - - mutex_unlock(&vhost_scsi_mutex); + mutex_unlock(&tpg->tv_tpg_mutex); return 0; } @@ -2016,15 +2031,10 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg, struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - mutex_lock(&vhost_scsi_mutex); - mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count--; - mutex_unlock(&tpg->tv_tpg_mutex); - vhost_scsi_hotunplug(tpg, lun); - - mutex_unlock(&vhost_scsi_mutex); + mutex_unlock(&tpg->tv_tpg_mutex); } static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store( diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 7be9d9d8f01c..8c1aefc865f0 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -219,6 +219,28 @@ static int vhost_vdpa_reset(struct vhost_vdpa *v) return vdpa_reset(vdpa); } +static long vhost_vdpa_bind_mm(struct vhost_vdpa *v) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + + if (!vdpa->use_va || !ops->bind_mm) + return 0; + + return ops->bind_mm(vdpa, v->vdev.mm); +} + +static void vhost_vdpa_unbind_mm(struct vhost_vdpa *v) +{ + struct vdpa_device *vdpa = v->vdpa; + const struct vdpa_config_ops *ops = vdpa->config; + + if (!vdpa->use_va || !ops->unbind_mm) + return; + + ops->unbind_mm(vdpa); +} + static long vhost_vdpa_get_device_id(struct vhost_vdpa *v, u8 __user *argp) { struct vdpa_device *vdpa = v->vdpa; @@ -599,9 +621,11 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, if (vq->call_ctx.ctx) { cb.callback = vhost_vdpa_virtqueue_cb; cb.private = vq; + cb.trigger = vq->call_ctx.ctx; } else { cb.callback = NULL; cb.private = NULL; + cb.trigger = NULL; } ops->set_vq_cb(vdpa, idx, &cb); vhost_vdpa_setup_vq_irq(v, idx); @@ -716,6 +740,17 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep, break; } + if (r) + goto out; + + switch (cmd) { + case VHOST_SET_OWNER: + r = vhost_vdpa_bind_mm(v); + if (r) + vhost_dev_reset_owner(d, NULL); + break; + } +out: mutex_unlock(&d->mutex); return r; } @@ -851,11 +886,7 @@ static void vhost_vdpa_unmap(struct vhost_vdpa *v, if (!v->in_batch) ops->set_map(vdpa, asid, iotlb); } - /* If we are in the middle of batch processing, delay the free - * of AS until BATCH_END. - */ - if (!v->in_batch && !iotlb->nmaps) - vhost_vdpa_remove_as(v, asid); + } static int vhost_vdpa_va_map(struct vhost_vdpa *v, @@ -1112,8 +1143,6 @@ static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev, u32 asid, if (v->in_batch && ops->set_map) ops->set_map(vdpa, asid, iotlb); v->in_batch = false; - if (!iotlb->nmaps) - vhost_vdpa_remove_as(v, asid); break; default: r = -EINVAL; @@ -1140,7 +1169,7 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v) struct vdpa_device *vdpa = v->vdpa; const struct vdpa_config_ops *ops = vdpa->config; struct device *dma_dev = vdpa_get_dma_dev(vdpa); - struct bus_type *bus; + const struct bus_type *bus; int ret; /* Device want to do DMA by itself */ @@ -1287,6 +1316,7 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) vhost_vdpa_clean_irq(v); vhost_vdpa_reset(v); vhost_dev_stop(&v->vdev); + vhost_vdpa_unbind_mm(v); vhost_vdpa_config_put(v); vhost_vdpa_cleanup(v); mutex_unlock(&d->mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 6d07b42833be..074273020849 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -256,7 +256,7 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work) * test_and_set_bit() implies a memory barrier. */ llist_add(&work->node, &dev->worker->work_list); - wake_up_process(dev->worker->vtsk->task); + vhost_task_wake(dev->worker->vtsk); } } EXPORT_SYMBOL_GPL(vhost_work_queue); @@ -333,40 +333,27 @@ static void vhost_vq_reset(struct vhost_dev *dev, __vhost_vq_meta_reset(vq); } -static int vhost_worker(void *data) +static bool vhost_worker(void *data) { struct vhost_worker *worker = data; struct vhost_work *work, *work_next; struct llist_node *node; - for (;;) { - /* mb paired w/ kthread_stop */ - set_current_state(TASK_INTERRUPTIBLE); - - if (vhost_task_should_stop(worker->vtsk)) { - __set_current_state(TASK_RUNNING); - break; - } - - node = llist_del_all(&worker->work_list); - if (!node) - schedule(); - + node = llist_del_all(&worker->work_list); + if (node) { node = llist_reverse_order(node); /* make sure flag is seen after deletion */ smp_wmb(); llist_for_each_entry_safe(work, work_next, node, node) { clear_bit(VHOST_WORK_QUEUED, &work->flags); - __set_current_state(TASK_RUNNING); kcov_remote_start_common(worker->kcov_handle); work->fn(work); kcov_remote_stop(); - if (need_resched()) - schedule(); + cond_resched(); } } - return 0; + return !!node; } static void vhost_vq_free_iovecs(struct vhost_virtqueue *vq) @@ -434,8 +421,7 @@ static size_t vhost_get_avail_size(struct vhost_virtqueue *vq, size_t event __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; - return sizeof(*vq->avail) + - sizeof(*vq->avail->ring) * num + event; + return size_add(struct_size(vq->avail, ring, num), event); } static size_t vhost_get_used_size(struct vhost_virtqueue *vq, @@ -444,8 +430,7 @@ static size_t vhost_get_used_size(struct vhost_virtqueue *vq, size_t event __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; - return sizeof(*vq->used) + - sizeof(*vq->used->ring) * num + event; + return size_add(struct_size(vq->used, ring, num), event); } static size_t vhost_get_desc_size(struct vhost_virtqueue *vq, diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index a1e27da54481..955d938eb663 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -636,9 +636,9 @@ static inline int xfer_to_user(const struct vringh *vrh, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid: you should check pointers * yourself! @@ -911,9 +911,9 @@ static inline int kern_xfer(const struct vringh *vrh, void *dst, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid. */ @@ -1094,10 +1094,17 @@ EXPORT_SYMBOL(vringh_need_notify_kern); #if IS_REACHABLE(CONFIG_VHOST_IOTLB) +struct iotlb_vec { + union { + struct iovec *iovec; + struct bio_vec *bvec; + } iov; + size_t count; +}; + static int iotlb_translate(const struct vringh *vrh, u64 addr, u64 len, u64 *translated, - struct bio_vec iov[], - int iov_size, u32 perm) + struct iotlb_vec *ivec, u32 perm) { struct vhost_iotlb_map *map; struct vhost_iotlb *iotlb = vrh->iotlb; @@ -1107,9 +1114,11 @@ static int iotlb_translate(const struct vringh *vrh, spin_lock(vrh->iotlb_lock); while (len > s) { - u64 size, pa, pfn; + uintptr_t io_addr; + size_t io_len; + u64 size; - if (unlikely(ret >= iov_size)) { + if (unlikely(ret >= ivec->count)) { ret = -ENOBUFS; break; } @@ -1124,10 +1133,22 @@ static int iotlb_translate(const struct vringh *vrh, } size = map->size - addr + map->start; - pa = map->addr + addr - map->start; - pfn = pa >> PAGE_SHIFT; - bvec_set_page(&iov[ret], pfn_to_page(pfn), min(len - s, size), - pa & (PAGE_SIZE - 1)); + io_len = min(len - s, size); + io_addr = map->addr - map->start + addr; + + if (vrh->use_va) { + struct iovec *iovec = ivec->iov.iovec; + + iovec[ret].iov_len = io_len; + iovec[ret].iov_base = (void __user *)io_addr; + } else { + u64 pfn = io_addr >> PAGE_SHIFT; + struct bio_vec *bvec = ivec->iov.bvec; + + bvec_set_page(&bvec[ret], pfn_to_page(pfn), io_len, + io_addr & (PAGE_SIZE - 1)); + } + s += size; addr += size; ++ret; @@ -1141,26 +1162,41 @@ static int iotlb_translate(const struct vringh *vrh, return ret; } +#define IOTLB_IOV_STRIDE 16 + static inline int copy_from_iotlb(const struct vringh *vrh, void *dst, void *src, size_t len) { + struct iotlb_vec ivec; + union { + struct iovec iovec[IOTLB_IOV_STRIDE]; + struct bio_vec bvec[IOTLB_IOV_STRIDE]; + } iov; u64 total_translated = 0; + ivec.iov.iovec = iov.iovec; + ivec.count = IOTLB_IOV_STRIDE; + while (total_translated < len) { - struct bio_vec iov[16]; struct iov_iter iter; u64 translated; int ret; ret = iotlb_translate(vrh, (u64)(uintptr_t)src, len - total_translated, &translated, - iov, ARRAY_SIZE(iov), VHOST_MAP_RO); + &ivec, VHOST_MAP_RO); if (ret == -ENOBUFS) - ret = ARRAY_SIZE(iov); + ret = IOTLB_IOV_STRIDE; else if (ret < 0) return ret; - iov_iter_bvec(&iter, ITER_SOURCE, iov, ret, translated); + if (vrh->use_va) { + iov_iter_init(&iter, ITER_SOURCE, ivec.iov.iovec, ret, + translated); + } else { + iov_iter_bvec(&iter, ITER_SOURCE, ivec.iov.bvec, ret, + translated); + } ret = copy_from_iter(dst, translated, &iter); if (ret < 0) @@ -1177,23 +1213,36 @@ static inline int copy_from_iotlb(const struct vringh *vrh, void *dst, static inline int copy_to_iotlb(const struct vringh *vrh, void *dst, void *src, size_t len) { + struct iotlb_vec ivec; + union { + struct iovec iovec[IOTLB_IOV_STRIDE]; + struct bio_vec bvec[IOTLB_IOV_STRIDE]; + } iov; u64 total_translated = 0; + ivec.iov.iovec = iov.iovec; + ivec.count = IOTLB_IOV_STRIDE; + while (total_translated < len) { - struct bio_vec iov[16]; struct iov_iter iter; u64 translated; int ret; ret = iotlb_translate(vrh, (u64)(uintptr_t)dst, len - total_translated, &translated, - iov, ARRAY_SIZE(iov), VHOST_MAP_WO); + &ivec, VHOST_MAP_WO); if (ret == -ENOBUFS) - ret = ARRAY_SIZE(iov); + ret = IOTLB_IOV_STRIDE; else if (ret < 0) return ret; - iov_iter_bvec(&iter, ITER_DEST, iov, ret, translated); + if (vrh->use_va) { + iov_iter_init(&iter, ITER_DEST, ivec.iov.iovec, ret, + translated); + } else { + iov_iter_bvec(&iter, ITER_DEST, ivec.iov.bvec, ret, + translated); + } ret = copy_to_iter(src, translated, &iter); if (ret < 0) @@ -1210,20 +1259,36 @@ static inline int copy_to_iotlb(const struct vringh *vrh, void *dst, static inline int getu16_iotlb(const struct vringh *vrh, u16 *val, const __virtio16 *p) { - struct bio_vec iov; - void *kaddr, *from; + struct iotlb_vec ivec; + union { + struct iovec iovec[1]; + struct bio_vec bvec[1]; + } iov; + __virtio16 tmp; int ret; + ivec.iov.iovec = iov.iovec; + ivec.count = 1; + /* Atomic read is needed for getu16 */ - ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL, - &iov, 1, VHOST_MAP_RO); + ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), + NULL, &ivec, VHOST_MAP_RO); if (ret < 0) return ret; - kaddr = kmap_atomic(iov.bv_page); - from = kaddr + iov.bv_offset; - *val = vringh16_to_cpu(vrh, READ_ONCE(*(__virtio16 *)from)); - kunmap_atomic(kaddr); + if (vrh->use_va) { + ret = __get_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base); + if (ret) + return ret; + } else { + void *kaddr = kmap_local_page(ivec.iov.bvec[0].bv_page); + void *from = kaddr + ivec.iov.bvec[0].bv_offset; + + tmp = READ_ONCE(*(__virtio16 *)from); + kunmap_local(kaddr); + } + + *val = vringh16_to_cpu(vrh, tmp); return 0; } @@ -1231,20 +1296,36 @@ static inline int getu16_iotlb(const struct vringh *vrh, static inline int putu16_iotlb(const struct vringh *vrh, __virtio16 *p, u16 val) { - struct bio_vec iov; - void *kaddr, *to; + struct iotlb_vec ivec; + union { + struct iovec iovec; + struct bio_vec bvec; + } iov; + __virtio16 tmp; int ret; + ivec.iov.iovec = &iov.iovec; + ivec.count = 1; + /* Atomic write is needed for putu16 */ - ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), NULL, - &iov, 1, VHOST_MAP_WO); + ret = iotlb_translate(vrh, (u64)(uintptr_t)p, sizeof(*p), + NULL, &ivec, VHOST_MAP_RO); if (ret < 0) return ret; - kaddr = kmap_atomic(iov.bv_page); - to = kaddr + iov.bv_offset; - WRITE_ONCE(*(__virtio16 *)to, cpu_to_vringh16(vrh, val)); - kunmap_atomic(kaddr); + tmp = cpu_to_vringh16(vrh, val); + + if (vrh->use_va) { + ret = __put_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base); + if (ret) + return ret; + } else { + void *kaddr = kmap_local_page(ivec.iov.bvec[0].bv_page); + void *to = kaddr + ivec.iov.bvec[0].bv_offset; + + WRITE_ONCE(*(__virtio16 *)to, tmp); + kunmap_local(kaddr); + } return 0; } @@ -1306,9 +1387,9 @@ static inline int putused_iotlb(const struct vringh *vrh, * @features: the feature bits for this ring. * @num: the number of elements. * @weak_barriers: true if we only need memory barriers, not I/O. - * @desc: the userpace descriptor pointer. - * @avail: the userpace avail pointer. - * @used: the userpace used pointer. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. * * Returns an error if num is invalid. */ @@ -1318,11 +1399,39 @@ int vringh_init_iotlb(struct vringh *vrh, u64 features, struct vring_avail *avail, struct vring_used *used) { + vrh->use_va = false; + return vringh_init_kern(vrh, features, num, weak_barriers, desc, avail, used); } EXPORT_SYMBOL(vringh_init_iotlb); +/** + * vringh_init_iotlb_va - initialize a vringh for a ring with IOTLB containing + * user VA. + * @vrh: the vringh to initialize. + * @features: the feature bits for this ring. + * @num: the number of elements. + * @weak_barriers: true if we only need memory barriers, not I/O. + * @desc: the userspace descriptor pointer. + * @avail: the userspace avail pointer. + * @used: the userspace used pointer. + * + * Returns an error if num is invalid. + */ +int vringh_init_iotlb_va(struct vringh *vrh, u64 features, + unsigned int num, bool weak_barriers, + struct vring_desc *desc, + struct vring_avail *avail, + struct vring_used *used) +{ + vrh->use_va = true; + + return vringh_init_kern(vrh, features, num, weak_barriers, + desc, avail, used); +} +EXPORT_SYMBOL(vringh_init_iotlb_va); + /** * vringh_set_iotlb - initialize a vringh for a ring with IOTLB. * @vrh: the vring diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 1cbb303e9c88..81fde3abb92c 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -178,7 +178,7 @@ out: return ret; } -static int aat2870_bl_remove(struct platform_device *pdev) +static void aat2870_bl_remove(struct platform_device *pdev) { struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev); struct backlight_device *bd = aat2870_bl->bd; @@ -186,8 +186,6 @@ static int aat2870_bl_remove(struct platform_device *pdev) bd->props.power = FB_BLANK_POWERDOWN; bd->props.brightness = 0; backlight_update_status(bd); - - return 0; } static struct platform_driver aat2870_bl_driver = { @@ -195,7 +193,7 @@ static struct platform_driver aat2870_bl_driver = { .name = "aat2870-backlight", }, .probe = aat2870_bl_probe, - .remove = aat2870_bl_remove, + .remove_new = aat2870_bl_remove, }; static int __init aat2870_bl_init(void) diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 686988c3df3a..8e0e9cfe5fe9 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -337,7 +337,7 @@ static int adp5520_bl_probe(struct platform_device *pdev) return 0; } -static int adp5520_bl_remove(struct platform_device *pdev) +static void adp5520_bl_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); struct adp5520_bl *data = bl_get_data(bl); @@ -347,8 +347,6 @@ static int adp5520_bl_remove(struct platform_device *pdev) if (data->pdata->en_ambl_sens) sysfs_remove_group(&bl->dev.kobj, &adp5520_bl_attr_group); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -377,7 +375,7 @@ static struct platform_driver adp5520_bl_driver = { .pm = &adp5520_bl_pm_ops, }, .probe = adp5520_bl_probe, - .remove = adp5520_bl_remove, + .remove_new = adp5520_bl_remove, }; module_platform_driver(adp5520_bl_driver); diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c index e610d7a1d13d..088bcca547dd 100644 --- a/drivers/video/backlight/arcxcnn_bl.c +++ b/drivers/video/backlight/arcxcnn_bl.c @@ -390,7 +390,7 @@ MODULE_DEVICE_TABLE(i2c, arcxcnn_ids); static struct i2c_driver arcxcnn_driver = { .driver = { .name = "arcxcnn_bl", - .of_match_table = of_match_ptr(arcxcnn_dt_ids), + .of_match_table = arcxcnn_dt_ids, }, .probe_new = arcxcnn_probe, .remove = arcxcnn_remove, diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 3b60019cdc2b..28437c2da0f5 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -286,23 +286,23 @@ static int as3711_backlight_parse_dt(struct device *dev) if (ret < 0) goto err_put_bl; - if (of_find_property(bl, "su2-feedback-voltage", NULL)) { + if (of_property_read_bool(bl, "su2-feedback-voltage")) { pdata->su2_feedback = AS3711_SU2_VOLTAGE; count++; } - if (of_find_property(bl, "su2-feedback-curr1", NULL)) { + if (of_property_read_bool(bl, "su2-feedback-curr1")) { pdata->su2_feedback = AS3711_SU2_CURR1; count++; } - if (of_find_property(bl, "su2-feedback-curr2", NULL)) { + if (of_property_read_bool(bl, "su2-feedback-curr2")) { pdata->su2_feedback = AS3711_SU2_CURR2; count++; } - if (of_find_property(bl, "su2-feedback-curr3", NULL)) { + if (of_property_read_bool(bl, "su2-feedback-curr3")) { pdata->su2_feedback = AS3711_SU2_CURR3; count++; } - if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) { + if (of_property_read_bool(bl, "su2-feedback-curr-auto")) { pdata->su2_feedback = AS3711_SU2_CURR_AUTO; count++; } @@ -312,19 +312,19 @@ static int as3711_backlight_parse_dt(struct device *dev) } count = 0; - if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { + if (of_property_read_bool(bl, "su2-fbprot-lx-sd4")) { pdata->su2_fbprot = AS3711_SU2_LX_SD4; count++; } - if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) { + if (of_property_read_bool(bl, "su2-fbprot-gpio2")) { pdata->su2_fbprot = AS3711_SU2_GPIO2; count++; } - if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) { + if (of_property_read_bool(bl, "su2-fbprot-gpio3")) { pdata->su2_fbprot = AS3711_SU2_GPIO3; count++; } - if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) { + if (of_property_read_bool(bl, "su2-fbprot-gpio4")) { pdata->su2_fbprot = AS3711_SU2_GPIO4; count++; } @@ -334,15 +334,15 @@ static int as3711_backlight_parse_dt(struct device *dev) } count = 0; - if (of_find_property(bl, "su2-auto-curr1", NULL)) { + if (of_property_read_bool(bl, "su2-auto-curr1")) { pdata->su2_auto_curr1 = true; count++; } - if (of_find_property(bl, "su2-auto-curr2", NULL)) { + if (of_property_read_bool(bl, "su2-auto-curr2")) { pdata->su2_auto_curr2 = true; count++; } - if (of_find_property(bl, "su2-auto-curr3", NULL)) { + if (of_property_read_bool(bl, "su2-auto-curr3")) { pdata->su2_auto_curr3 = true; count++; } diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 6eea72aa8dbf..9a885d398c22 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -751,7 +751,7 @@ static void __exit backlight_class_exit(void) static int __init backlight_class_init(void) { - backlight_class = class_create(THIS_MODULE, "backlight"); + backlight_class = class_create("backlight"); if (IS_ERR(backlight_class)) { pr_warn("Unable to create backlight class; errno = %ld\n", PTR_ERR(backlight_class)); diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 4ad0a72531fe..781aeecc451d 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -210,7 +210,7 @@ static int cr_backlight_probe(struct platform_device *pdev) return 0; } -static int cr_backlight_remove(struct platform_device *pdev) +static void cr_backlight_remove(struct platform_device *pdev) { struct cr_panel *crp = platform_get_drvdata(pdev); @@ -220,13 +220,11 @@ static int cr_backlight_remove(struct platform_device *pdev) cr_backlight_set_intensity(crp->cr_backlight_device); cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN); pci_dev_put(lpc_dev); - - return 0; } static struct platform_driver cr_backlight_driver = { .probe = cr_backlight_probe, - .remove = cr_backlight_remove, + .remove_new = cr_backlight_remove, .driver = { .name = "cr_backlight", }, diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index 882359dd288c..1cdc8543310b 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -135,7 +135,7 @@ static int da9052_backlight_probe(struct platform_device *pdev) return da9052_adjust_wled_brightness(wleds); } -static int da9052_backlight_remove(struct platform_device *pdev) +static void da9052_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); struct da9052_bl *wleds = bl_get_data(bl); @@ -143,8 +143,6 @@ static int da9052_backlight_remove(struct platform_device *pdev) wleds->brightness = 0; wleds->state = DA9052_WLEDS_OFF; da9052_adjust_wled_brightness(wleds); - - return 0; } static const struct platform_device_id da9052_wled_ids[] = { @@ -166,7 +164,7 @@ MODULE_DEVICE_TABLE(platform, da9052_wled_ids); static struct platform_driver da9052_wled_driver = { .probe = da9052_backlight_probe, - .remove = da9052_backlight_remove, + .remove_new = da9052_backlight_remove, .id_table = da9052_wled_ids, .driver = { .name = "da9052-wled", diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 9123c33def05..ddb7ab4df77e 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -119,20 +119,18 @@ static int hp680bl_probe(struct platform_device *pdev) return 0; } -static int hp680bl_remove(struct platform_device *pdev) +static void hp680bl_remove(struct platform_device *pdev) { struct backlight_device *bd = platform_get_drvdata(pdev); bd->props.brightness = 0; bd->props.power = 0; hp680bl_send_intensity(bd); - - return 0; } static struct platform_driver hp680bl_driver = { .probe = hp680bl_probe, - .remove = hp680bl_remove, + .remove_new = hp680bl_remove, .driver = { .name = "hp680-bl", .pm = &hp680bl_pm_ops, diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index 9b50bc96e00f..f76d2469d490 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -617,7 +617,7 @@ static int hx8357_probe(struct spi_device *spi) return -EINVAL; } - if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) { + if (of_property_present(spi->dev.of_node, "im-gpios")) { lcd->use_im_pins = 1; for (i = 0; i < HX8357_NUM_IM_PINS; i++) { diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index db56e465aaff..77c5cb2a44e2 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -323,7 +323,7 @@ static void __exit lcd_class_exit(void) static int __init lcd_class_init(void) { - lcd_class = class_create(THIS_MODULE, "lcd"); + lcd_class = class_create("lcd"); if (IS_ERR(lcd_class)) { pr_warn("Unable to create backlight class; errno = %ld\n", PTR_ERR(lcd_class)); diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c index f54d256e2d54..a1b6a2ad73a0 100644 --- a/drivers/video/backlight/led_bl.c +++ b/drivers/video/backlight/led_bl.c @@ -217,7 +217,7 @@ static int led_bl_probe(struct platform_device *pdev) return 0; } -static int led_bl_remove(struct platform_device *pdev) +static void led_bl_remove(struct platform_device *pdev) { struct led_bl_data *priv = platform_get_drvdata(pdev); struct backlight_device *bl = priv->bl_dev; @@ -228,8 +228,6 @@ static int led_bl_remove(struct platform_device *pdev) led_bl_power_off(priv); for (i = 0; i < priv->nb_leds; i++) led_sysfs_enable(priv->leds[i]); - - return 0; } static const struct of_device_id led_bl_of_match[] = { @@ -245,7 +243,7 @@ static struct platform_driver led_bl_driver = { .of_match_table = of_match_ptr(led_bl_of_match), }, .probe = led_bl_probe, - .remove = led_bl_remove, + .remove_new = led_bl_remove, }; module_platform_driver(led_bl_driver); diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index 1df1b6643c0b..3e10d480cb7f 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -337,7 +337,7 @@ err_sysfs_remove: return ret; } -static int lm3533_bl_remove(struct platform_device *pdev) +static void lm3533_bl_remove(struct platform_device *pdev) { struct lm3533_bl *bl = platform_get_drvdata(pdev); struct backlight_device *bd = bl->bd; @@ -349,8 +349,6 @@ static int lm3533_bl_remove(struct platform_device *pdev) lm3533_ctrlbank_disable(&bl->cb); sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -390,7 +388,7 @@ static struct platform_driver lm3533_bl_driver = { .pm = &lm3533_bl_pm_ops, }, .probe = lm3533_bl_probe, - .remove = lm3533_bl_remove, + .remove_new = lm3533_bl_remove, .shutdown = lm3533_bl_shutdown, }; module_platform_driver(lm3533_bl_driver); diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 81012bf29baf..a57c9ef3b1cc 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -548,7 +548,7 @@ static void lp855x_remove(struct i2c_client *cl) sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); } -static const struct of_device_id lp855x_dt_ids[] = { +static const struct of_device_id lp855x_dt_ids[] __maybe_unused = { { .compatible = "ti,lp8550", }, { .compatible = "ti,lp8551", }, { .compatible = "ti,lp8552", }, diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index ba42f3fe0c73..d1a14b0db265 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -298,7 +298,7 @@ err_dev: return ret; } -static int lp8788_backlight_remove(struct platform_device *pdev) +static void lp8788_backlight_remove(struct platform_device *pdev) { struct lp8788_bl *bl = platform_get_drvdata(pdev); struct backlight_device *bl_dev = bl->bl_dev; @@ -307,13 +307,11 @@ static int lp8788_backlight_remove(struct platform_device *pdev) backlight_update_status(bl_dev); sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group); lp8788_backlight_unregister(bl); - - return 0; } static struct platform_driver lp8788_bl_driver = { .probe = lp8788_backlight_probe, - .remove = lp8788_backlight_remove, + .remove_new = lp8788_backlight_remove, .driver = { .name = LP8788_DEV_BACKLIGHT, }, diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c index 623d4f2baca2..94422c956453 100644 --- a/drivers/video/backlight/mt6370-backlight.c +++ b/drivers/video/backlight/mt6370-backlight.c @@ -318,15 +318,13 @@ static int mt6370_bl_probe(struct platform_device *pdev) return 0; } -static int mt6370_bl_remove(struct platform_device *pdev) +static void mt6370_bl_remove(struct platform_device *pdev) { struct mt6370_priv *priv = platform_get_drvdata(pdev); struct backlight_device *bl_dev = priv->bl; bl_dev->props.brightness = 0; backlight_update_status(priv->bl); - - return 0; } static const struct of_device_id mt6370_bl_of_match[] = { @@ -342,7 +340,7 @@ static struct platform_driver mt6370_bl_driver = { .of_match_table = mt6370_bl_of_match, }, .probe = mt6370_bl_probe, - .remove = mt6370_bl_remove, + .remove_new = mt6370_bl_remove, }; module_platform_driver(mt6370_bl_driver); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index fb388148d98f..fce412234d10 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -625,7 +625,7 @@ err_alloc: return ret; } -static int pwm_backlight_remove(struct platform_device *pdev) +static void pwm_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); struct pwm_bl_data *pb = bl_get_data(bl); @@ -635,8 +635,6 @@ static int pwm_backlight_remove(struct platform_device *pdev) if (pb->exit) pb->exit(&pdev->dev); - - return 0; } static void pwm_backlight_shutdown(struct platform_device *pdev) @@ -690,7 +688,7 @@ static struct platform_driver pwm_backlight_driver = { .of_match_table = of_match_ptr(pwm_backlight_of_match), }, .probe = pwm_backlight_probe, - .remove = pwm_backlight_remove, + .remove_new = pwm_backlight_remove, .shutdown = pwm_backlight_shutdown, }; diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 527210e85795..c6996aa288e6 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -1717,7 +1717,7 @@ static int wled_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(bl); }; -static int wled_remove(struct platform_device *pdev) +static void wled_remove(struct platform_device *pdev) { struct wled *wled = platform_get_drvdata(pdev); @@ -1725,12 +1725,11 @@ static int wled_remove(struct platform_device *pdev) cancel_delayed_work_sync(&wled->ovp_work); disable_irq(wled->short_irq); disable_irq(wled->ovp_irq); - - return 0; } static const struct of_device_id wled_match_table[] = { { .compatible = "qcom,pm8941-wled", .data = (void *)3 }, + { .compatible = "qcom,pmi8950-wled", .data = (void *)4 }, { .compatible = "qcom,pmi8994-wled", .data = (void *)4 }, { .compatible = "qcom,pmi8998-wled", .data = (void *)4 }, { .compatible = "qcom,pm660l-wled", .data = (void *)4 }, @@ -1742,7 +1741,7 @@ MODULE_DEVICE_TABLE(of, wled_match_table); static struct platform_driver wled_driver = { .probe = wled_probe, - .remove = wled_remove, + .remove_new = wled_remove, .driver = { .name = "qcom,wled", .of_match_table = wled_match_table, diff --git a/drivers/video/backlight/rt4831-backlight.c b/drivers/video/backlight/rt4831-backlight.c index eb8c59e8713f..7d1af4c2ca67 100644 --- a/drivers/video/backlight/rt4831-backlight.c +++ b/drivers/video/backlight/rt4831-backlight.c @@ -203,15 +203,13 @@ static int rt4831_bl_probe(struct platform_device *pdev) return 0; } -static int rt4831_bl_remove(struct platform_device *pdev) +static void rt4831_bl_remove(struct platform_device *pdev) { struct rt4831_priv *priv = platform_get_drvdata(pdev); struct backlight_device *bl_dev = priv->bl; bl_dev->props.brightness = 0; backlight_update_status(priv->bl); - - return 0; } static const struct of_device_id __maybe_unused rt4831_bl_of_match[] = { @@ -226,7 +224,7 @@ static struct platform_driver rt4831_bl_driver = { .of_match_table = rt4831_bl_of_match, }, .probe = rt4831_bl_probe, - .remove = rt4831_bl_remove, + .remove_new = rt4831_bl_remove, }; module_platform_driver(rt4831_bl_driver); diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c index 0172438c38ce..eb18c6eb0ff0 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -311,7 +311,7 @@ static int sky81452_bl_probe(struct platform_device *pdev) return ret; } -static int sky81452_bl_remove(struct platform_device *pdev) +static void sky81452_bl_remove(struct platform_device *pdev) { const struct sky81452_bl_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -325,8 +325,6 @@ static int sky81452_bl_remove(struct platform_device *pdev) if (pdata->gpiod_enable) gpiod_set_value_cansleep(pdata->gpiod_enable, 0); - - return 0; } #ifdef CONFIG_OF @@ -343,7 +341,7 @@ static struct platform_driver sky81452_bl_driver = { .of_match_table = of_match_ptr(sky81452_bl_of_match), }, .probe = sky81452_bl_probe, - .remove = sky81452_bl_remove, + .remove_new = sky81452_bl_remove, }; module_platform_driver(sky81452_bl_driver); diff --git a/drivers/video/fbdev/68328fb.c b/drivers/video/fbdev/68328fb.c index 3ccf46f8ffd0..07d6e8dc686b 100644 --- a/drivers/video/fbdev/68328fb.c +++ b/drivers/video/fbdev/68328fb.c @@ -124,7 +124,7 @@ static u_long get_line_length(int xres_virtual, int bpp) * First part, xxxfb_check_var, must not write anything * to hardware, it should only verify and adjust var. * This means it doesn't alter par but it does use hardware - * data from it to check this var. + * data from it to check this var. */ static int mc68x328fb_check_var(struct fb_var_screeninfo *var, @@ -182,7 +182,7 @@ static int mc68x328fb_check_var(struct fb_var_screeninfo *var, /* * Now that we checked it we alter var. The reason being is that the video - * mode passed in might not work but slight changes to it might make it + * mode passed in might not work but slight changes to it might make it * work. This way we let the user know what is acceptable. */ switch (var->bits_per_pixel) { @@ -257,8 +257,8 @@ static int mc68x328fb_check_var(struct fb_var_screeninfo *var, } /* This routine actually sets the video mode. It's in here where we - * the hardware state info->par and fix which can be affected by the - * change in par. For this driver it doesn't do much. + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. */ static int mc68x328fb_set_par(struct fb_info *info) { @@ -295,7 +295,7 @@ static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * {hardwarespecific} contains width of RAMDAC * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) * RAMDAC[X] is programmed to (red, green, blue) - * + * * Pseudocolor: * uses offset = 0 && length = RAMDAC register width. * var->{color}.offset is 0 @@ -384,7 +384,7 @@ static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, } /* - * Most drivers don't need their own mmap function + * Most drivers don't need their own mmap function */ static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 96e91570cdd3..0fdf5f46802c 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -124,7 +124,7 @@ config FB_PROVIDE_GET_FB_UNMAPPED_AREA depends on FB help Allow generic frame-buffer to provide get_fb_unmapped_area - function. + function to provide shareable character device support on nommu. menuconfig FB_FOREIGN_ENDIAN bool "Framebuffer foreign endianness support" diff --git a/drivers/video/fbdev/arcfb.c b/drivers/video/fbdev/arcfb.c index 45e64016db32..08d15e408413 100644 --- a/drivers/video/fbdev/arcfb.c +++ b/drivers/video/fbdev/arcfb.c @@ -523,7 +523,7 @@ static int arcfb_probe(struct platform_device *dev) info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev); if (!info) - goto err; + goto err_fb_alloc; info->screen_base = (char __iomem *)videomemory; info->fbops = &arcfb_ops; @@ -535,7 +535,7 @@ static int arcfb_probe(struct platform_device *dev) if (!dio_addr || !cio_addr || !c2io_addr) { printk(KERN_WARNING "no IO addresses supplied\n"); - goto err1; + goto err_addr; } par->dio_addr = dio_addr; par->cio_addr = cio_addr; @@ -551,12 +551,12 @@ static int arcfb_probe(struct platform_device *dev) printk(KERN_INFO "arcfb: Failed req IRQ %d\n", par->irq); retval = -EBUSY; - goto err1; + goto err_addr; } } retval = register_framebuffer(info); if (retval < 0) - goto err1; + goto err_register_fb; platform_set_drvdata(dev, info); fb_info(info, "Arc frame buffer device, using %dK of video memory\n", videomemorysize >> 10); @@ -580,14 +580,17 @@ static int arcfb_probe(struct platform_device *dev) } return 0; -err1: + +err_register_fb: + free_irq(par->irq, info); +err_addr: framebuffer_release(info); -err: +err_fb_alloc: vfree(videomemory); return retval; } -static int arcfb_remove(struct platform_device *dev) +static void arcfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -598,12 +601,11 @@ static int arcfb_remove(struct platform_device *dev) vfree((void __force *)info->screen_base); framebuffer_release(info); } - return 0; } static struct platform_driver arcfb_driver = { .probe = arcfb_probe, - .remove = arcfb_remove, + .remove_new = arcfb_remove, .driver = { .name = "arcfb", }, diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 8187a7c4f910..987c5f5f0241 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -317,7 +317,7 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) /** * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory * @sinfo: the frame buffer to allocate memory for - * + * * This function is called only from the atmel_lcdfb_probe() * so no locking by fb_info->mm_lock around smem_len setting is needed. */ diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index b02e4e645035..cba2b113b28b 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3498,11 +3498,6 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, if (ret) goto atyfb_setup_generic_fail; #endif - if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN)) - par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2; - else - par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U; - /* according to ATI, we should use clock 3 for acelerated mode */ par->clk_wr_offset = 3; diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c index 519313b8bb00..648d6cac86e8 100644 --- a/drivers/video/fbdev/au1100fb.c +++ b/drivers/video/fbdev/au1100fb.c @@ -520,13 +520,10 @@ failed: return -ENODEV; } -int au1100fb_drv_remove(struct platform_device *dev) +void au1100fb_drv_remove(struct platform_device *dev) { struct au1100fb_device *fbdev = NULL; - if (!dev) - return -ENODEV; - fbdev = platform_get_drvdata(dev); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) @@ -543,8 +540,6 @@ int au1100fb_drv_remove(struct platform_device *dev) clk_disable_unprepare(fbdev->lcdclk); clk_put(fbdev->lcdclk); } - - return 0; } #ifdef CONFIG_PM @@ -593,9 +588,9 @@ static struct platform_driver au1100fb_driver = { .name = "au1100-lcd", }, .probe = au1100fb_drv_probe, - .remove = au1100fb_drv_remove, + .remove_new = au1100fb_drv_remove, .suspend = au1100fb_drv_suspend, - .resume = au1100fb_drv_resume, + .resume = au1100fb_drv_resume, }; module_platform_driver(au1100fb_driver); diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index b6b22fa4a8a0..aed88ce45bf0 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1765,7 +1765,7 @@ failed: return ret; } -static int au1200fb_drv_remove(struct platform_device *dev) +static void au1200fb_drv_remove(struct platform_device *dev) { struct au1200fb_platdata *pd = platform_get_drvdata(dev); struct fb_info *fbi; @@ -1788,8 +1788,6 @@ static int au1200fb_drv_remove(struct platform_device *dev) } free_irq(platform_get_irq(dev, 0), (void *)dev); - - return 0; } #ifdef CONFIG_PM @@ -1840,7 +1838,7 @@ static struct platform_driver au1200fb_driver = { .pm = AU1200FB_PMOPS, }, .probe = au1200fb_drv_probe, - .remove = au1200fb_drv_remove, + .remove_new = au1200fb_drv_remove, }; module_platform_driver(au1200fb_driver); diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 55e62dd96f9b..b518cacbf7cd 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -1193,7 +1193,7 @@ err: } -static int broadsheetfb_remove(struct platform_device *dev) +static void broadsheetfb_remove(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); @@ -1209,12 +1209,11 @@ static int broadsheetfb_remove(struct platform_device *dev) module_put(par->board->owner); framebuffer_release(info); } - return 0; } static struct platform_driver broadsheetfb_driver = { .probe = broadsheetfb_probe, - .remove = broadsheetfb_remove, + .remove_new = broadsheetfb_remove, .driver = { .name = "broadsheetfb", }, diff --git a/drivers/video/fbdev/bw2.c b/drivers/video/fbdev/bw2.c index 9cbadcd18b25..025d663dc6fd 100644 --- a/drivers/video/fbdev/bw2.c +++ b/drivers/video/fbdev/bw2.c @@ -352,7 +352,7 @@ out_err: return err; } -static int bw2_remove(struct platform_device *op) +static void bw2_remove(struct platform_device *op) { struct fb_info *info = dev_get_drvdata(&op->dev); struct bw2_par *par = info->par; @@ -363,8 +363,6 @@ static int bw2_remove(struct platform_device *op) of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); framebuffer_release(info); - - return 0; } static const struct of_device_id bw2_match[] = { @@ -381,7 +379,7 @@ static struct platform_driver bw2_driver = { .of_match_table = bw2_match, }, .probe = bw2_probe, - .remove = bw2_remove, + .remove_new = bw2_remove, }; static int __init bw2_init(void) diff --git a/drivers/video/fbdev/cg14.c b/drivers/video/fbdev/cg14.c index a028ede39c12..832a82f45c80 100644 --- a/drivers/video/fbdev/cg14.c +++ b/drivers/video/fbdev/cg14.c @@ -512,7 +512,7 @@ static int cg14_probe(struct platform_device *op) is_8mb = (resource_size(&op->resource[1]) == (8 * 1024 * 1024)); BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map)); - + memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map)); for (i = 0; i < CG14_MMAP_ENTRIES; i++) { diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c index 77dbf94aae5f..82eeb139c4eb 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -113,14 +113,14 @@ struct fb_info_control { struct fb_info info; struct fb_par_control par; u32 pseudo_palette[16]; - + struct cmap_regs __iomem *cmap_regs; unsigned long cmap_regs_phys; - + struct control_regs __iomem *control_regs; unsigned long control_regs_phys; unsigned long control_regs_size; - + __u8 __iomem *frame_buffer; unsigned long frame_buffer_phys; unsigned long fb_orig_base; @@ -196,7 +196,7 @@ static void set_control_clock(unsigned char *params) while (!req.complete) cuda_poll(); } -#endif +#endif } /* @@ -233,19 +233,19 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro if (p->par.xoffset != par->xoffset || p->par.yoffset != par->yoffset) set_screen_start(par->xoffset, par->yoffset, p); - + return; } - + p->par = *par; cmode = p->par.cmode; r = &par->regvals; - + /* Turn off display */ out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl); - + set_control_clock(r->clock_params); - + RADACAL_WRITE(0x20, r->radacal_ctrl); RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1); RADACAL_WRITE(0x10, 0); @@ -254,7 +254,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro rp = &p->control_regs->vswin; for (i = 0; i < 16; ++i, ++rp) out_le32(&rp->r, r->regs[i]); - + out_le32(CNTRL_REG(p,pitch), par->pitch); out_le32(CNTRL_REG(p,mode), r->mode); out_le32(CNTRL_REG(p,vram_attr), p->vram_attr); @@ -366,7 +366,7 @@ static int read_control_sense(struct fb_info_control *p) sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7; out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ - + return sense; } @@ -558,9 +558,9 @@ static int control_var_to_par(struct fb_var_screeninfo *var, static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var) { struct control_regints *rv; - + rv = (struct control_regints *) par->regvals.regs; - + memset(var, 0, sizeof(*var)); var->xres = par->xres; var->yres = par->yres; @@ -568,7 +568,7 @@ static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeni var->yres_virtual = par->vyres; var->xoffset = par->xoffset; var->yoffset = par->yoffset; - + switch(par->cmode) { default: case CMODE_8: @@ -634,7 +634,7 @@ static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *i err = control_var_to_par(var, &par, info); if (err) - return err; + return err; control_par_to_var(&par, var); return 0; @@ -655,7 +655,7 @@ static int controlfb_set_par (struct fb_info *info) " control_var_to_par: %d.\n", err); return err; } - + control_set_hardware(p, &par); info->fix.visual = (p->par.cmode == CMODE_8) ? @@ -840,7 +840,7 @@ static int __init init_control(struct fb_info_control *p) int full, sense, vmode, cmode, vyres; struct fb_var_screeninfo var; int rc; - + printk(KERN_INFO "controlfb: "); full = p->total_vram == 0x400000; diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index f98e8f298bc1..8587c9da0670 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -247,6 +247,9 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.set = 0; + if (!vc->vc_font.data) + return; + c = scr_readw((u16 *) vc->vc_pos); attribute = get_attribute(info, c); src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 3fd95a79e4c3..28739f1cb5e7 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1468,7 +1468,7 @@ __releases(&info->lock) } #if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU) -unsigned long get_fb_unmapped_area(struct file *filp, +static unsigned long get_fb_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { @@ -1751,7 +1751,7 @@ fbmem_init(void) goto err_chrdev; } - fb_class = class_create(THIS_MODULE, "graphics"); + fb_class = class_create("graphics"); if (IS_ERR(fb_class)) { ret = PTR_ERR(fb_class); pr_warn("Unable to create fb class; errno = %d\n", ret); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 23cf8eba785d..f7e019dded0f 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -257,6 +257,11 @@ static const struct fb_videomode modedb[] = { { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0, FB_VMODE_DOUBLE }, + /* 1920x1080 @ 60 Hz, 67.3 kHz hsync */ + { NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */ { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, diff --git a/drivers/video/fbdev/g364fb.c b/drivers/video/fbdev/g364fb.c index 05837a3b985c..c5b7673ddc6c 100644 --- a/drivers/video/fbdev/g364fb.c +++ b/drivers/video/fbdev/g364fb.c @@ -6,7 +6,7 @@ * * This driver is based on tgafb.c * - * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1995 Jay Estabrook * * This file is subject to the terms and conditions of the GNU General Public @@ -28,7 +28,7 @@ #include #include -/* +/* * Various defines for the G364 */ #define G364_MEM_BASE 0xe4400000 @@ -125,7 +125,7 @@ static const struct fb_ops g364fb_ops = { * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag */ -static int g364fb_pan_display(struct fb_var_screeninfo *var, +static int g364fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xoffset || diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c index 20bdab738ab7..0af58018441d 100644 --- a/drivers/video/fbdev/hgafb.c +++ b/drivers/video/fbdev/hgafb.c @@ -1,6 +1,6 @@ /* * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device - * + * * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) * Based on skeletonfb.c by Geert Uytterhoeven and * mdacon.c by Andrew Apted @@ -8,14 +8,14 @@ * History: * * - Revision 0.1.8 (23 Oct 2002): Ported to new framebuffer api. - * - * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards + * + * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards * being detected as Hercules. (Paul G.) * - Revision 0.1.6 (17 Aug 2000): new style structs * documentation * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc * minor fixes - * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for + * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for * HGA-only systems * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure * screen is cleared after rmmod @@ -143,7 +143,7 @@ static bool nologo = 0; static void write_hga_b(unsigned int val, unsigned char reg) { - outb_p(reg, HGA_INDEX_PORT); + outb_p(reg, HGA_INDEX_PORT); outb_p(val, HGA_VALUE_PORT); } @@ -155,7 +155,7 @@ static void write_hga_w(unsigned int val, unsigned char reg) static int test_hga_b(unsigned char val, unsigned char reg) { - outb_p(reg, HGA_INDEX_PORT); + outb_p(reg, HGA_INDEX_PORT); outb (val, HGA_VALUE_PORT); udelay(20); val = (inb_p(HGA_VALUE_PORT) == val); return val; @@ -244,7 +244,7 @@ static void hga_show_logo(struct fb_info *info) void __iomem *dest = hga_vram; char *logo = linux_logo_bw; int x, y; - + for (y = 134; y < 134 + 80 ; y++) * this needs some cleanup * for (x = 0; x < 10 ; x++) writeb(~*(logo++),(dest + HGA_ROWADDR(y) + x + 40)); @@ -255,7 +255,7 @@ static void hga_pan(unsigned int xoffset, unsigned int yoffset) { unsigned int base; unsigned long flags; - + base = (yoffset / 8) * 90 + xoffset; spin_lock_irqsave(&hga_reg_lock, flags); write_hga_w(base, 0x0c); /* start address */ @@ -310,7 +310,7 @@ static int hga_card_detect(void) /* Ok, there is definitely a card registering at the correct * memory location, so now we do an I/O port test. */ - + if (!test_hga_b(0x66, 0x0f)) /* cursor low register */ goto error; @@ -321,7 +321,7 @@ static int hga_card_detect(void) * bit of the status register is changing. This test lasts for * approximately 1/10th of a second. */ - + p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC; for (count=0; count < 50000 && p_save == q_save; count++) { @@ -329,7 +329,7 @@ static int hga_card_detect(void) udelay(2); } - if (p_save == q_save) + if (p_save == q_save) goto error; switch (inb_p(HGA_STATUS_PORT) & 0x70) { @@ -415,7 +415,7 @@ static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * @info:pointer to fb_info object containing info for current hga board * * This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP - * flag in @var. If input parameters are correct it calls hga_pan() to + * flag in @var. If input parameters are correct it calls hga_pan() to * program the hardware. @info->var is updated to the new values. * A zero is returned on success and %-EINVAL for failure. */ @@ -442,9 +442,9 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var, * hgafb_blank - (un)blank the screen * @blank_mode:blanking method to use * @info:unused - * - * Blank the screen if blank_mode != 0, else unblank. - * Implements VESA suspend and powerdown modes on hardware that supports + * + * Blank the screen if blank_mode != 0, else unblank. + * Implements VESA suspend and powerdown modes on hardware that supports * disabling hsync/vsync: * @blank_mode == 2 means suspend vsync, * @blank_mode == 3 means suspend hsync, @@ -539,15 +539,15 @@ static const struct fb_ops hgafb_ops = { .fb_copyarea = hgafb_copyarea, .fb_imageblit = hgafb_imageblit, }; - + /* ------------------------------------------------------------------------- * * * Functions in fb_info - * + * * ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ - + /* * Initialization */ diff --git a/drivers/video/fbdev/hpfb.c b/drivers/video/fbdev/hpfb.c index cdd44e5deafe..77fbff47b1a8 100644 --- a/drivers/video/fbdev/hpfb.c +++ b/drivers/video/fbdev/hpfb.c @@ -92,7 +92,7 @@ static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= info->cmap.len) return 1; - + while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1); out_be16(fb_regs + 0x60ba, 0xff); @@ -143,7 +143,7 @@ static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr) out_8(fb_regs + WMOVE, fb_bitmask); } -static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY); } @@ -315,7 +315,7 @@ unmap_screen_base: return ret; } -/* +/* * Check that the secondary ID indicates that we have some hope of working with this * framebuffer. The catseye boards are pretty much like topcats and we can muddle through. */ @@ -323,7 +323,7 @@ unmap_screen_base: #define topcat_sid_ok(x) (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE) \ || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT)) -/* +/* * Initialise the framebuffer */ static int hpfb_dio_probe(struct dio_dev *d, const struct dio_device_id *ent) diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index ec3f6cf05f8c..34781dec3856 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -946,7 +946,7 @@ static phys_addr_t hvfb_get_phymem(struct hv_device *hdev, if (request_size == 0) return -1; - if (order < MAX_ORDER) { + if (order <= MAX_ORDER) { /* Call alloc_pages if the size is less than 2^MAX_ORDER */ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); if (!page) @@ -977,7 +977,7 @@ static void hvfb_release_phymem(struct hv_device *hdev, { unsigned int order = get_order(size); - if (order < MAX_ORDER) + if (order <= MAX_ORDER) __free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order); else dma_free_coherent(&hdev->device, diff --git a/drivers/video/fbdev/i810/i810_dvt.c b/drivers/video/fbdev/i810/i810_dvt.c index b4b3670667ab..2082b5c92e8f 100644 --- a/drivers/video/fbdev/i810/i810_dvt.c +++ b/drivers/video/fbdev/i810/i810_dvt.c @@ -14,6 +14,7 @@ #include "i810_regs.h" #include "i810.h" +#include "i810_main.h" struct mode_registers std_modes[] = { /* 640x480 @ 60Hz */ @@ -276,7 +277,7 @@ void i810fb_fill_var_timings(struct fb_var_screeninfo *var) var->upper_margin = total - (yres + var->lower_margin + var->vsync_len); } -u32 i810_get_watermark(struct fb_var_screeninfo *var, +u32 i810_get_watermark(const struct fb_var_screeninfo *var, struct i810fb_par *par) { struct mode_registers *params = &par->regs; diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c index bea45647184e..ee7d01ad1406 100644 --- a/drivers/video/fbdev/imsttfb.c +++ b/drivers/video/fbdev/imsttfb.c @@ -1347,7 +1347,7 @@ static const struct fb_ops imsttfb_ops = { .fb_ioctl = imsttfb_ioctl, }; -static void init_imstt(struct fb_info *info) +static int init_imstt(struct fb_info *info) { struct imstt_par *par = info->par; __u32 i, tmp, *ip, *end; @@ -1420,7 +1420,7 @@ static void init_imstt(struct fb_info *info) || !(compute_imstt_regvals(par, info->var.xres, info->var.yres))) { printk("imsttfb: %ux%ux%u not supported\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); framebuffer_release(info); - return; + return -ENODEV; } sprintf(info->fix.id, "IMS TT (%s)", par->ramdac == IBM ? "IBM" : "TVP"); @@ -1452,16 +1452,21 @@ static void init_imstt(struct fb_info *info) FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_YPAN; - fb_alloc_cmap(&info->cmap, 0, 0); + if (fb_alloc_cmap(&info->cmap, 0, 0)) { + framebuffer_release(info); + return -ENODEV; + } if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); - return; + return -ENODEV; } tmp = (read_reg_le32(par->dc_regs, SSTATUS) & 0x0f00) >> 8; fb_info(info, "%s frame buffer; %uMB vram; chip version %u\n", info->fix.id, info->fix.smem_len >> 20, tmp); + return 0; } static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1529,10 +1534,12 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!par->cmap_regs) goto error; info->pseudo_palette = par->palette; - init_imstt(info); + ret = init_imstt(info); + if (ret) + goto error; pci_set_drvdata(pdev, info); - return 0; + return ret; error: if (par->dc_regs) diff --git a/drivers/video/fbdev/macfb.c b/drivers/video/fbdev/macfb.c index 312e35c9aa6c..44ff860a3f37 100644 --- a/drivers/video/fbdev/macfb.c +++ b/drivers/video/fbdev/macfb.c @@ -339,7 +339,7 @@ static int civic_setpalette(unsigned int regno, unsigned int red, { unsigned long flags; int clut_status; - + local_irq_save(flags); /* Set the register address */ @@ -439,7 +439,7 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green, * (according to the entries in the `var' structure). * Return non-zero for invalid regno. */ - + if (regno >= fb_info->cmap.len) return 1; @@ -548,7 +548,7 @@ static int __init macfb_init(void) return -ENODEV; macfb_setup(option); - if (!MACH_IS_MAC) + if (!MACH_IS_MAC) return -ENODEV; if (mac_bi_data.id == MAC_MODEL_Q630 || @@ -644,7 +644,7 @@ static int __init macfb_init(void) err = -EINVAL; goto fail_unmap; } - + /* * We take a wild guess that if the video physical address is * in nubus slot space, that the nubus card is driving video. @@ -774,7 +774,7 @@ static int __init macfb_init(void) civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000); break; - + /* * Assorted weirdos * We think this may be like the LC II diff --git a/drivers/video/fbdev/matrox/matroxfb_maven.c b/drivers/video/fbdev/matrox/matroxfb_maven.c index 727a10a59811..b15a8ad92ba7 100644 --- a/drivers/video/fbdev/matrox/matroxfb_maven.c +++ b/drivers/video/fbdev/matrox/matroxfb_maven.c @@ -1291,7 +1291,7 @@ static struct i2c_driver maven_driver={ .driver = { .name = "maven", }, - .probe_new = maven_probe, + .probe = maven_probe, .remove = maven_remove, .id_table = maven_id, }; diff --git a/drivers/video/fbdev/maxinefb.c b/drivers/video/fbdev/maxinefb.c index ae1a42bcb0ea..4e6b05232ae2 100644 --- a/drivers/video/fbdev/maxinefb.c +++ b/drivers/video/fbdev/maxinefb.c @@ -138,7 +138,7 @@ int __init maxinefb_init(void) *(volatile unsigned char *)fboff = 0x0; maxinefb_fix.smem_start = fb_start; - + /* erase hardware cursor */ for (i = 0; i < 512; i++) { maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i, diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c index 1eaa35c27835..477789cff8e0 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c @@ -491,7 +491,8 @@ static int tpo_td043_probe(struct spi_device *spi) ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc"); if (IS_ERR(ddata->vcc_reg)) { - r = dev_err_probe(&spi->dev, r, "failed to get LCD VCC regulator\n"); + r = dev_err_probe(&spi->dev, PTR_ERR(ddata->vcc_reg), + "failed to get LCD VCC regulator\n"); goto err_regulator; } diff --git a/drivers/video/fbdev/p9100.c b/drivers/video/fbdev/p9100.c index 3e44f9516318..0876962c52eb 100644 --- a/drivers/video/fbdev/p9100.c +++ b/drivers/video/fbdev/p9100.c @@ -65,7 +65,7 @@ static const struct fb_ops p9100_ops = { #define P9100_FB_OFF 0x0UL /* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */ -#define SYS_CONFIG_PIXELSIZE_SHIFT 26 +#define SYS_CONFIG_PIXELSIZE_SHIFT 26 #define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */ @@ -110,7 +110,7 @@ struct p9100_regs { u32 vram_xxx[25]; /* Registers for IBM RGB528 Palette */ - u32 ramdac_cmap_wridx; + u32 ramdac_cmap_wridx; u32 ramdac_palette_data; u32 ramdac_pixel_mask; u32 ramdac_palette_rdaddr; diff --git a/drivers/video/fbdev/platinumfb.c b/drivers/video/fbdev/platinumfb.c index 82f019f0a0d6..f8283fcd5edb 100644 --- a/drivers/video/fbdev/platinumfb.c +++ b/drivers/video/fbdev/platinumfb.c @@ -52,17 +52,17 @@ struct fb_info_platinum { __u8 red, green, blue; } palette[256]; u32 pseudo_palette[16]; - + volatile struct cmap_regs __iomem *cmap_regs; unsigned long cmap_regs_phys; - + volatile struct platinum_regs __iomem *platinum_regs; unsigned long platinum_regs_phys; - + __u8 __iomem *frame_buffer; volatile __u8 __iomem *base_frame_buffer; unsigned long frame_buffer_phys; - + unsigned long total_vram; int clktype; int dactype; @@ -133,7 +133,7 @@ static int platinumfb_set_par (struct fb_info *info) platinum_set_hardware(pinfo); init = platinum_reg_init[pinfo->vmode-1]; - + if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8)) offset = 0x10; @@ -214,7 +214,7 @@ static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, break; } } - + return 0; } @@ -269,7 +269,7 @@ static void platinum_set_hardware(struct fb_info_platinum *pinfo) struct platinum_regvals *init; int i; int vmode, cmode; - + vmode = pinfo->vmode; cmode = pinfo->cmode; @@ -436,7 +436,7 @@ static int read_platinum_sense(struct fb_info_platinum *info) * This routine takes a user-supplied var, and picks the best vmode/cmode from it. * It also updates the var structure to the actual mode data obtained */ -static int platinum_var_to_par(struct fb_var_screeninfo *var, +static int platinum_var_to_par(struct fb_var_screeninfo *var, struct fb_info_platinum *pinfo, int check_only) { @@ -478,12 +478,12 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var, pinfo->yoffset = 0; pinfo->vxres = pinfo->xres; pinfo->vyres = pinfo->yres; - + return 0; } -/* +/* * Parse user specified options (`video=platinumfb:') */ static int __init platinumfb_setup(char *options) @@ -624,7 +624,7 @@ static int platinumfb_probe(struct platform_device* odev) break; } dev_set_drvdata(&odev->dev, info); - + rc = platinum_init_fb(info); if (rc != 0) { iounmap(pinfo->frame_buffer); @@ -640,9 +640,9 @@ static void platinumfb_remove(struct platform_device* odev) { struct fb_info *info = dev_get_drvdata(&odev->dev); struct fb_info_platinum *pinfo = info->par; - + unregister_framebuffer (info); - + /* Unmap frame buffer and registers */ iounmap(pinfo->frame_buffer); iounmap(pinfo->platinum_regs); @@ -656,7 +656,7 @@ static void platinumfb_remove(struct platform_device* odev) framebuffer_release(info); } -static struct of_device_id platinumfb_match[] = +static struct of_device_id platinumfb_match[] = { { .name = "platinum", @@ -664,7 +664,7 @@ static struct of_device_id platinumfb_match[] = {}, }; -static struct platform_driver platinum_driver = +static struct platform_driver platinum_driver = { .driver = { .name = "platinumfb", diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index b1b8ccdbac4a..a2408bf00ca0 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -57,14 +57,14 @@ * - Driver appears to be working for Brutus 320x200x8bpp mode. Other * resolutions are working, but only the 8bpp mode is supported. * Changes need to be made to the palette encode and decode routines - * to support 4 and 16 bpp modes. + * to support 4 and 16 bpp modes. * Driver is not designed to be a module. The FrameBuffer is statically - * allocated since dynamic allocation of a 300k buffer cannot be - * guaranteed. + * allocated since dynamic allocation of a 300k buffer cannot be + * guaranteed. * * 1999/06/17: * - FrameBuffer memory is now allocated at run-time when the - * driver is initialized. + * driver is initialized. * * 2000/04/10: Nicolas Pitre * - Big cleanup for dynamic selection of machine type at run time. @@ -74,8 +74,8 @@ * * 2000/08/07: Tak-Shing Chan * Jeff Sutherland - * - Resolved an issue caused by a change made to the Assabet's PLD - * earlier this year which broke the framebuffer driver for newer + * - Resolved an issue caused by a change made to the Assabet's PLD + * earlier this year which broke the framebuffer driver for newer * Phase 4 Assabets. Some other parameters were changed to optimize * for the Sharp display. * @@ -102,7 +102,7 @@ * 2000/11/23: Eric Peng * - Freebird add * - * 2001/02/07: Jamey Hicks + * 2001/02/07: Jamey Hicks * Cliff Brake * - Added PM callback * @@ -500,7 +500,7 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, * the shortest recovery time * Suspend * This refers to a level of power management in which substantial power - * reduction is achieved by the display. The display can have a longer + * reduction is achieved by the display. The display can have a longer * recovery time from this state than from the Stand-by state * Off * This indicates that the display is consuming the lowest level of power @@ -522,9 +522,9 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, */ /* * sa1100fb_blank(): - * Blank the display by setting all palette values to zero. Note, the + * Blank the display by setting all palette values to zero. Note, the * 12 and 16 bpp modes don't really use the palette, so this will not - * blank the display in all modes. + * blank the display in all modes. */ static int sa1100fb_blank(int blank, struct fb_info *info) { @@ -603,8 +603,8 @@ static inline unsigned int get_pcd(struct sa1100fb_info *fbi, /* * sa1100fb_activate_var(): - * Configures LCD Controller based on entries in var parameter. Settings are - * only written to the controller if changes were made. + * Configures LCD Controller based on entries in var parameter. Settings are + * only written to the controller if changes were made. */ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) { @@ -747,7 +747,7 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) * * SA1110 spec update nr. 25 says we can and should * clear LDD15 to 12 for 4 or 8bpp modes with active - * panels. + * panels. */ if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { @@ -1020,9 +1020,9 @@ static int sa1100fb_resume(struct platform_device *dev) /* * sa1100fb_map_video_memory(): - * Allocates the DRAM memory for the frame buffer. This buffer is - * remapped into a non-cached, non-buffered, memory region to - * allow palette and pixel writes to occur without flushing the + * Allocates the DRAM memory for the frame buffer. This buffer is + * remapped into a non-cached, non-buffered, memory region to + * allow palette and pixel writes to occur without flushing the * cache. Once this area is remapped, all virtual memory * access to the video memory should occur at the new region. */ diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 046b9990d27c..132d1a205011 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -844,7 +844,7 @@ static const struct i2c_device_id ssd1307fb_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); static struct i2c_driver ssd1307fb_driver = { - .probe_new = ssd1307fb_probe, + .probe = ssd1307fb_probe, .remove = ssd1307fb_remove, .id_table = ssd1307fb_i2c_id, .driver = { diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c index ef8a4c5fc687..686a234f3899 100644 --- a/drivers/video/fbdev/stifb.c +++ b/drivers/video/fbdev/stifb.c @@ -1,11 +1,11 @@ /* - * linux/drivers/video/stifb.c - - * Low level Frame buffer driver for HP workstations with + * linux/drivers/video/stifb.c - + * Low level Frame buffer driver for HP workstations with * STI (standard text interface) video firmware. * * Copyright (C) 2001-2006 Helge Deller * Portions Copyright (C) 2001 Thomas Bogendoerfer - * + * * Based on: * - linux/drivers/video/artistfb.c -- Artist frame buffer driver * Copyright (C) 2000 Philipp Rumpf @@ -14,7 +14,7 @@ * - HP Xhp cfb-based X11 window driver for XFree86 * (c)Copyright 1992 Hewlett-Packard Co. * - * + * * The following graphics display devices (NGLE family) are supported by this driver: * * HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes @@ -30,7 +30,7 @@ * supports 1280x1024 color displays with 8 planes. * HP710G same as HP710C, 1280x1024 grayscale only * HP710L same as HP710C, 1024x768 color only - * HP712 internal graphics support on HP9000s712 SPU, supports 640x480, + * HP712 internal graphics support on HP9000s712 SPU, supports 640x480, * 1024x768 or 1280x1024 color displays on 8 planes (Artist) * * This file is subject to the terms and conditions of the GNU General Public @@ -92,7 +92,7 @@ typedef struct { __s32 misc_video_end; } video_setup_t; -typedef struct { +typedef struct { __s16 sizeof_ngle_data; __s16 x_size_visible; /* visible screen dim in pixels */ __s16 y_size_visible; @@ -177,10 +177,10 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; #endif /* DEBUG_STIFB_REGS */ -#define ENABLE 1 /* for enabling/disabling screen */ +#define ENABLE 1 /* for enabling/disabling screen */ #define DISABLE 0 -#define NGLE_LOCK(fb_info) do { } while (0) +#define NGLE_LOCK(fb_info) do { } while (0) #define NGLE_UNLOCK(fb_info) do { } while (0) static void @@ -198,9 +198,9 @@ SETUP_HW(struct stifb_info *fb) static void SETUP_FB(struct stifb_info *fb) -{ +{ unsigned int reg10_value = 0; - + SETUP_HW(fb); switch (fb->id) { @@ -210,15 +210,15 @@ SETUP_FB(struct stifb_info *fb) reg10_value = 0x13601000; break; case S9000_ID_A1439A: - if (fb->info.var.bits_per_pixel == 32) + if (fb->info.var.bits_per_pixel == 32) reg10_value = 0xBBA0A000; - else + else reg10_value = 0x13601000; break; case S9000_ID_HCRX: if (fb->info.var.bits_per_pixel == 32) reg10_value = 0xBBA0A000; - else + else reg10_value = 0x13602000; break; case S9000_ID_TIMBER: @@ -243,7 +243,7 @@ START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) } static void -WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) +WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) { SETUP_HW(fb); WRITE_WORD(((0x100+index)<<2), fb, REG_3); @@ -251,30 +251,30 @@ WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color) } static void -FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) -{ +FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb) +{ WRITE_WORD(0x400, fb, REG_2); if (fb->info.var.bits_per_pixel == 32) { WRITE_WORD(0x83000100, fb, REG_1); } else { if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG) WRITE_WORD(0x80000100, fb, REG_26); - else + else WRITE_WORD(0x80000100, fb, REG_1); } SETUP_FB(fb); } static void -SETUP_RAMDAC(struct stifb_info *fb) +SETUP_RAMDAC(struct stifb_info *fb) { SETUP_HW(fb); WRITE_WORD(0x04000000, fb, 0x1020); WRITE_WORD(0xff000000, fb, 0x1028); } -static void -CRX24_SETUP_RAMDAC(struct stifb_info *fb) +static void +CRX24_SETUP_RAMDAC(struct stifb_info *fb) { SETUP_HW(fb); WRITE_WORD(0x04000000, fb, 0x1000); @@ -286,14 +286,14 @@ CRX24_SETUP_RAMDAC(struct stifb_info *fb) } #if 0 -static void +static void HCRX_SETUP_RAMDAC(struct stifb_info *fb) { WRITE_WORD(0xffffffff, fb, REG_32); } #endif -static void +static void CRX24_SET_OVLY_MASK(struct stifb_info *fb) { SETUP_HW(fb); @@ -314,7 +314,7 @@ ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) WRITE_WORD(value, fb, 0x1038); } -static void +static void CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) { unsigned int value = enable ? 0x10000000 : 0x30000000; @@ -325,11 +325,11 @@ CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) } static void -ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) +ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) { u32 DregsMiscVideo = REG_21; u32 DregsMiscCtl = REG_27; - + SETUP_HW(fb); if (enable) { WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo); @@ -344,7 +344,7 @@ ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) (READ_BYTE(fb, REG_16b3) - 1) #define HYPER_CONFIG_PLANES_24 0x00000100 - + #define IS_24_DEVICE(fb) \ (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24) @@ -470,15 +470,15 @@ SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber) } static void -SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) +SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) { - /* REG_6 seems to have special values when run on a + /* REG_6 seems to have special values when run on a RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or INTERNAL_EG_X1024). The values are: 0x2f0: internal (LCD) & external display enabled 0x2a0: external display only 0x000: zero on standard artist graphic cards - */ + */ WRITE_WORD(0x00000000, fb, REG_6); WRITE_WORD((width<<16) | height, fb, REG_9); WRITE_WORD(0x05000000, fb, REG_6); @@ -486,7 +486,7 @@ SET_ATTR_SIZE(struct stifb_info *fb, int width, int height) } static void -FINISH_ATTR_ACCESS(struct stifb_info *fb) +FINISH_ATTR_ACCESS(struct stifb_info *fb) { SETUP_HW(fb); WRITE_WORD(0x00000000, fb, REG_12); @@ -499,7 +499,7 @@ elkSetupPlanes(struct stifb_info *fb) SETUP_FB(fb); } -static void +static void ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber) { SETUP_ATTR_ACCESS(fb, BufferNumber); @@ -519,7 +519,7 @@ rattlerSetupPlanes(struct stifb_info *fb) * read mask register for overlay planes, not image planes). */ CRX24_SETUP_RAMDAC(fb); - + /* change fb->id temporarily to fool SETUP_FB() */ saved_id = fb->id; fb->id = CRX24_OVERLAY_PLANES; @@ -565,7 +565,7 @@ setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) lutBltCtl.all = 0x80000000; lutBltCtl.fields.length = length; - switch (fb->id) + switch (fb->id) { case S9000_ID_A1439A: /* CRX24 */ if (fb->var.bits_per_pixel == 8) { @@ -576,12 +576,12 @@ setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) lutBltCtl.fields.lutOffset = 0 * 256; } break; - + case S9000_ID_ARTIST: lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; lutBltCtl.fields.lutOffset = 0 * 256; break; - + default: lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE; lutBltCtl.fields.lutOffset = 0; @@ -596,7 +596,7 @@ setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) #endif static NgleLutBltCtl -setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) +setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length) { NgleLutBltCtl lutBltCtl; @@ -633,7 +633,7 @@ static void hyperUndoITE(struct stifb_info *fb) /* Hardware setup for full-depth write to "magic" location */ GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); - NGLE_QUICK_SET_DST_BM_ACCESS(fb, + NGLE_QUICK_SET_DST_BM_ACCESS(fb, BA(IndexedDcd, Otc04, Ots08, AddrLong, BAJustPoint(0), BINovly, BAIndexBase(0))); NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, @@ -653,13 +653,13 @@ static void hyperUndoITE(struct stifb_info *fb) NGLE_UNLOCK(fb); } -static void +static void ngleDepth8_ClearImagePlanes(struct stifb_info *fb) { /* FIXME! */ } -static void +static void ngleDepth24_ClearImagePlanes(struct stifb_info *fb) { /* FIXME! */ @@ -675,7 +675,7 @@ ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg) NGLE_LOCK(fb); GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4); - NGLE_QUICK_SET_DST_BM_ACCESS(fb, + NGLE_QUICK_SET_DST_BM_ACCESS(fb, BA(IndexedDcd, Otc32, OtsIndirect, AddrLong, BAJustPoint(0), BINattr, BAIndexBase(0))); @@ -713,22 +713,22 @@ ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg) /**** Finally, set the Control Plane Register back to zero: ****/ GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1); NGLE_QUICK_SET_CTL_PLN_REG(fb, 0); - + NGLE_UNLOCK(fb); } - + static void ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data) { int nFreeFifoSlots = 0; u32 packed_dst; u32 packed_len; - + NGLE_LOCK(fb); /* Hardware setup */ GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8); - NGLE_QUICK_SET_DST_BM_ACCESS(fb, + NGLE_QUICK_SET_DST_BM_ACCESS(fb, BA(IndexedDcd, Otc04, Ots08, AddrLong, BAJustPoint(0), BINovly, BAIndexBase(0))); @@ -736,23 +736,23 @@ ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data) NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data); NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask); - + packed_dst = 0; packed_len = (fb->info.var.xres << 16) | fb->info.var.yres; NGLE_SET_DSTXY(fb, packed_dst); - - /* Write zeroes to overlay planes */ + + /* Write zeroes to overlay planes */ NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, IBOvals(RopSrc, MaskAddrOffset(0), BitmapExtent08, StaticReg(0), DataDynamic, MaskOtc, BGx(0), FGx(0))); - + SET_LENXY_START_RECFILL(fb, packed_len); NGLE_UNLOCK(fb); } -static void +static void hyperResetPlanes(struct stifb_info *fb, int enable) { unsigned int controlPlaneReg; @@ -783,7 +783,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable) ngleClearOverlayPlanes(fb, 0xff, 255); /************************************************** - ** Also need to counteract ITE settings + ** Also need to counteract ITE settings **************************************************/ hyperUndoITE(fb); break; @@ -803,13 +803,13 @@ hyperResetPlanes(struct stifb_info *fb, int enable) ngleResetAttrPlanes(fb, controlPlaneReg); break; } - + NGLE_UNLOCK(fb); } /* Return pointer to in-memory structure holding ELK device-dependent ROM values. */ -static void +static void ngleGetDeviceRomData(struct stifb_info *fb) { #if 0 @@ -821,7 +821,7 @@ XXX: FIXME: !!! char *pCard8; int i; char *mapOrigin = NULL; - + int romTableIdx; pPackedDevRomData = fb->ngle_rom; @@ -888,7 +888,7 @@ SETUP_HCRX(struct stifb_info *fb) /* Initialize Hyperbowl registers */ GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7); - + if (IS_24_DEVICE(fb)) { hyperbowl = (fb->info.var.bits_per_pixel == 32) ? HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE : @@ -897,9 +897,9 @@ SETUP_HCRX(struct stifb_info *fb) /* First write to Hyperbowl must happen twice (bug) */ WRITE_WORD(hyperbowl, fb, REG_40); WRITE_WORD(hyperbowl, fb, REG_40); - + WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39); - + WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */ WRITE_WORD(0x404c4048, fb, REG_43); WRITE_WORD(0x034c0348, fb, REG_44); @@ -990,7 +990,7 @@ stifb_setcolreg(u_int regno, u_int red, u_int green, 0, /* Offset w/i LUT */ 256); /* Load entire LUT */ NGLE_BINC_SET_SRCADDR(fb, - NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); + NGLE_LONG_FB_ADDRESS(0, 0x100, 0)); /* 0x100 is same as used in WRITE_IMAGE_COLOR() */ START_COLORMAPLOAD(fb, lutBltCtl.all); SETUP_FB(fb); @@ -1028,7 +1028,7 @@ stifb_blank(int blank_mode, struct fb_info *info) ENABLE_DISABLE_DISPLAY(fb, enable); break; } - + SETUP_FB(fb); return 0; } @@ -1114,15 +1114,15 @@ stifb_init_display(struct stifb_info *fb) /* HCRX specific initialization */ SETUP_HCRX(fb); - + /* if (id == S9000_ID_HCRX) hyperInitSprite(fb); else ngleInitSprite(fb); */ - - /* Initialize the image planes. */ + + /* Initialize the image planes. */ switch (id) { case S9000_ID_HCRX: hyperResetPlanes(fb, ENABLE); @@ -1194,7 +1194,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) fb = kzalloc(sizeof(*fb), GFP_ATOMIC); if (!fb) return -ENOMEM; - + info = &fb->info; /* set struct to a known state */ @@ -1235,7 +1235,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) dev_name, fb->id); goto out_err0; } - + /* default to 8 bpp on most graphic chips */ bpp = 8; xres = sti_onscreen_x(fb->sti); @@ -1256,7 +1256,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) fb->id = S9000_ID_A1659A; break; case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */ - if (strstr(dev_name, "GRAYSCALE") || + if (strstr(dev_name, "GRAYSCALE") || strstr(dev_name, "Grayscale") || strstr(dev_name, "grayscale")) var->grayscale = 1; @@ -1295,16 +1295,16 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) case CRT_ID_VISUALIZE_EG: case S9000_ID_ARTIST: /* Artist */ break; - default: + default: #ifdef FALLBACK_TO_1BPP - printk(KERN_WARNING + printk(KERN_WARNING "stifb: Unsupported graphics card (id=0x%08x) " "- now trying 1bpp mode instead\n", fb->id); bpp = 1; /* default to 1 bpp */ break; #else - printk(KERN_WARNING + printk(KERN_WARNING "stifb: Unsupported graphics card (id=0x%08x) " "- skipping.\n", fb->id); @@ -1320,11 +1320,11 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8; if (!fix->line_length) fix->line_length = 2048; /* default */ - + /* limit fbsize to max visible screen size */ if (fix->smem_len > yres*fix->line_length) fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024); - + fix->accel = FB_ACCEL_NONE; switch (bpp) { @@ -1350,7 +1350,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) default: break; } - + var->xres = var->xres_virtual = xres; var->yres = var->yres_virtual = yres; var->bits_per_pixel = bpp; @@ -1379,7 +1379,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) fix->smem_start, fix->smem_start+fix->smem_len); goto out_err2; } - + if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) { printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n", fix->mmio_start, fix->mmio_start+fix->mmio_len); @@ -1393,11 +1393,11 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n", fix->id, - var->xres, + var->xres, var->yres, var->bits_per_pixel, dev_name, - fb->id, + fb->id, fix->mmio_start); return 0; @@ -1413,6 +1413,7 @@ out_err1: iounmap(info->screen_base); out_err0: kfree(fb); + sti->info = NULL; return -ENXIO; } @@ -1426,7 +1427,7 @@ static int __init stifb_init(void) struct sti_struct *sti; struct sti_struct *def_sti; int i; - + #ifndef MODULE char *option = NULL; @@ -1438,7 +1439,7 @@ static int __init stifb_init(void) printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n"); return -ENXIO; } - + def_sti = sti_get_rom(0); if (def_sti) { for (i = 1; i <= MAX_STI_ROMS; i++) { @@ -1472,7 +1473,7 @@ stifb_cleanup(void) { struct sti_struct *sti; int i; - + for (i = 1; i <= MAX_STI_ROMS; i++) { sti = sti_get_rom(i); if (!sti) @@ -1495,10 +1496,10 @@ int __init stifb_setup(char *options) { int i; - + if (!options || !*options) return 1; - + if (strncmp(options, "off", 3) == 0) { stifb_disabled = 1; options += 3; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 216d49c9d47e..dabc30a09f96 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -27,6 +27,8 @@ #include